2017-03-10 07:06:01 +00:00
|
|
|
#include "test.h"
|
|
|
|
|
2017-02-27 07:28:33 +00:00
|
|
|
#include "indexer.h"
|
2017-03-25 20:15:00 +00:00
|
|
|
#include "platform.h"
|
2017-03-01 04:12:57 +00:00
|
|
|
#include "serializer.h"
|
2017-03-01 08:36:11 +00:00
|
|
|
#include "utils.h"
|
2017-02-27 07:28:33 +00:00
|
|
|
|
|
|
|
void Write(const std::vector<std::string>& strs) {
|
2017-03-01 04:12:57 +00:00
|
|
|
for (const std::string& str : strs)
|
2017-02-27 07:28:33 +00:00
|
|
|
std::cout << str << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string ToString(const rapidjson::Document& document) {
|
|
|
|
rapidjson::StringBuffer buffer;
|
|
|
|
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
|
|
|
|
writer.SetFormatOptions(
|
|
|
|
rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
|
|
|
|
writer.SetIndent(' ', 2);
|
|
|
|
|
|
|
|
buffer.Clear();
|
|
|
|
document.Accept(writer);
|
|
|
|
return buffer.GetString();
|
|
|
|
}
|
|
|
|
|
2017-04-03 01:34:15 +00:00
|
|
|
std::vector<std::string> SplitString(const std::string& str, const std::string& delimiter) {
|
2017-02-27 07:28:33 +00:00
|
|
|
// http://stackoverflow.com/a/13172514
|
|
|
|
std::vector<std::string> strings;
|
|
|
|
|
|
|
|
std::string::size_type pos = 0;
|
|
|
|
std::string::size_type prev = 0;
|
|
|
|
while ((pos = str.find(delimiter, prev)) != std::string::npos) {
|
|
|
|
strings.push_back(str.substr(prev, pos - prev));
|
|
|
|
prev = pos + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// To get the last substring (or only, if delimiter is not found)
|
|
|
|
strings.push_back(str.substr(prev));
|
|
|
|
|
|
|
|
return strings;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-08 22:54:36 +00:00
|
|
|
void DiffDocuments(std::string path, std::string path_section, rapidjson::Document& expected, rapidjson::Document& actual) {
|
2017-04-03 01:34:15 +00:00
|
|
|
std::string joined_actual_output = ToString(actual);
|
|
|
|
std::vector<std::string> actual_output = SplitString(joined_actual_output, "\n");
|
|
|
|
std::string joined_expected_output = ToString(expected);
|
|
|
|
std::vector<std::string> expected_output = SplitString(joined_expected_output, "\n");
|
2017-02-27 07:28:33 +00:00
|
|
|
|
2017-04-08 22:54:36 +00:00
|
|
|
std::cout << "[FAILED] " << path << " (section " << path_section << ")" << std::endl;
|
|
|
|
std::cout << "Expected output for " << path << " (section " << path_section << "):" << std::endl;
|
2017-04-03 01:34:15 +00:00
|
|
|
std::cout << joined_expected_output << std::endl;
|
2017-04-08 22:54:36 +00:00
|
|
|
std::cout << "Actual output for " << path << " (section " << path_section << "):" << std::endl;
|
2017-04-03 01:34:15 +00:00
|
|
|
std::cout << joined_actual_output << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
|
|
int max_diff = 5;
|
2017-02-27 07:28:33 +00:00
|
|
|
|
2017-04-08 07:11:57 +00:00
|
|
|
size_t len = std::min(actual_output.size(), expected_output.size());
|
2017-02-27 07:28:33 +00:00
|
|
|
for (int i = 0; i < len; ++i) {
|
|
|
|
if (actual_output[i] != expected_output[i]) {
|
2017-04-03 01:34:15 +00:00
|
|
|
if (--max_diff < 0) {
|
|
|
|
std::cout << "(... more lines may differ ...)" << std::endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-02-27 07:28:33 +00:00
|
|
|
std::cout << "Line " << i << " differs:" << std::endl;
|
|
|
|
std::cout << " expected: " << expected_output[i] << std::endl;
|
|
|
|
std::cout << " actual: " << actual_output[i] << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (actual_output.size() > len) {
|
|
|
|
std::cout << "Additional output in actual:" << std::endl;
|
2017-04-08 20:00:08 +00:00
|
|
|
for (size_t i = len; i < actual_output.size(); ++i)
|
2017-02-27 07:28:33 +00:00
|
|
|
std::cout << " " << actual_output[i] << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (expected_output.size() > len) {
|
|
|
|
std::cout << "Additional output in expected:" << std::endl;
|
2017-04-08 20:00:08 +00:00
|
|
|
for (size_t i = len; i < expected_output.size(); ++i)
|
2017-02-27 07:28:33 +00:00
|
|
|
std::cout << " " << expected_output[i] << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-08 20:00:08 +00:00
|
|
|
void VerifySerializeToFrom(IndexedFile* file) {
|
|
|
|
std::string expected = file->ToString();
|
|
|
|
std::string actual = Deserialize("--.cc", Serialize(*file)).value().ToString();
|
2017-03-01 04:12:57 +00:00
|
|
|
if (expected != actual) {
|
|
|
|
std::cerr << "Serialization failure" << std::endl;;
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-08 22:54:36 +00:00
|
|
|
std::string FindExpectedOutputForFilename(std::string filename, const std::unordered_map<std::string, std::string>& expected) {
|
|
|
|
for (const auto& entry : expected) {
|
|
|
|
if (EndsWith(entry.first, filename))
|
|
|
|
return entry.second;
|
|
|
|
}
|
2017-02-27 07:28:33 +00:00
|
|
|
|
2017-04-08 22:54:36 +00:00
|
|
|
std::cerr << "Couldn't find expected output for " << filename << std::endl;
|
|
|
|
std::cin.get();
|
2017-02-27 07:28:33 +00:00
|
|
|
std::cin.get();
|
2017-04-08 22:54:36 +00:00
|
|
|
return "{}";
|
|
|
|
}
|
|
|
|
|
|
|
|
IndexedFile* FindDbForPathEnding(const std::string& path, const std::vector<std::unique_ptr<IndexedFile>>& dbs) {
|
|
|
|
for (auto& db : dbs) {
|
|
|
|
if (EndsWith(db->path, path))
|
|
|
|
return db.get();
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RunTests() {
|
|
|
|
// TODO: Assert that we need to be on clang >= 3.9.1
|
2017-04-15 04:53:10 +00:00
|
|
|
bool update_all = false;
|
2017-02-27 07:28:33 +00:00
|
|
|
|
2017-03-11 02:24:51 +00:00
|
|
|
for (std::string path : GetFilesInFolder("tests", true /*recursive*/, true /*add_folder_to_path*/)) {
|
2017-03-06 06:23:41 +00:00
|
|
|
//if (path != "tests/templates/specialized_func_definition.cc") continue;
|
2017-03-14 04:31:53 +00:00
|
|
|
//if (path != "tests/templates/namespace_template_class_template_func_usage_folded_into_one.cc") continue;
|
2017-04-19 06:56:37 +00:00
|
|
|
//if (path != "tests/multi_file/funky_enum.cc") continue;
|
2017-04-11 05:26:27 +00:00
|
|
|
//if (path != "tests/multi_file/simple_impl.cc") continue;
|
2017-04-12 07:36:17 +00:00
|
|
|
//if (path != "tests/usage/func_called_implicit_ctor.cc") continue;
|
2017-03-14 04:31:53 +00:00
|
|
|
//if (path != "tests/templates/implicit_variable_instantiation.cc") continue;
|
2017-04-03 01:34:15 +00:00
|
|
|
//if (path != "tests/_empty_test.cc") continue;
|
2017-03-05 22:49:23 +00:00
|
|
|
|
|
|
|
//if (path != "tests/templates/template_class_type_usage_folded_into_one.cc") continue;
|
|
|
|
//path = "C:/Users/jacob/Desktop/superindex/indexer/" + path;
|
2017-02-27 07:28:33 +00:00
|
|
|
|
|
|
|
// Parse expected output from the test, parse it into JSON document.
|
2017-04-08 22:54:36 +00:00
|
|
|
std::unordered_map<std::string, std::string> all_expected_output = ParseTestExpectation(path);
|
|
|
|
|
2017-04-18 04:06:01 +00:00
|
|
|
IndexerConfig config;
|
2017-04-08 22:54:36 +00:00
|
|
|
FileConsumer::SharedState file_consumer_shared;
|
2017-02-27 07:28:33 +00:00
|
|
|
|
|
|
|
// Run test.
|
|
|
|
std::cout << "[START] " << path << std::endl;
|
2017-04-18 04:06:01 +00:00
|
|
|
std::vector<std::unique_ptr<IndexedFile>> dbs = Parse(&config, &file_consumer_shared, path, {
|
2017-04-03 01:34:15 +00:00
|
|
|
"-xc++",
|
|
|
|
"-std=c++11",
|
|
|
|
"-IC:/Users/jacob/Desktop/superindex/indexer/third_party/",
|
|
|
|
"-IC:/Users/jacob/Desktop/superindex/indexer/third_party/doctest/",
|
|
|
|
"-IC:/Users/jacob/Desktop/superindex/indexer/third_party/rapidjson/include",
|
|
|
|
"-IC:/Users/jacob/Desktop/superindex/indexer/src"
|
2017-04-11 05:26:27 +00:00
|
|
|
}, false /*dump_ast*/);
|
2017-04-08 20:00:08 +00:00
|
|
|
|
2017-04-13 07:47:47 +00:00
|
|
|
#if false
|
|
|
|
for (auto& db : dbs) {
|
|
|
|
assert(db);
|
|
|
|
if (!db) {
|
|
|
|
std::cerr << "no db!!!" << std::endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& func : db->funcs) {
|
|
|
|
if (!func.HasInterestingState())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (func.uses.size() !=
|
|
|
|
(func.callers.size() + func.declarations.size() + (func.def.definition_spelling.has_value() ? 1 : 0))) {
|
|
|
|
|
|
|
|
std::cout << "func.def.usr = " << func.def.usr << std::endl;
|
|
|
|
std::cout << "func.uses.size() = " << func.uses.size() << std::endl;
|
|
|
|
std::cout << "func.callers.size() = " << func.callers.size() << std::endl;
|
|
|
|
std::cout << "func.declarations.size() = " << func.declarations.size() << std::endl;
|
|
|
|
std::cout << "func.definition_spelling.has_value() = " << func.def.definition_spelling.has_value() << std::endl;
|
|
|
|
|
|
|
|
std::cerr << "err" << std::endl;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-04-08 22:54:36 +00:00
|
|
|
for (auto& entry : all_expected_output) {
|
|
|
|
const std::string& expected_path = entry.first;
|
|
|
|
const std::string& expected_output = entry.second;
|
2017-04-08 20:00:08 +00:00
|
|
|
|
2017-04-08 22:54:36 +00:00
|
|
|
// Get output from index operation.
|
|
|
|
IndexedFile* db = FindDbForPathEnding(expected_path, dbs);
|
|
|
|
std::string actual_output = "{}";
|
|
|
|
if (db) {
|
|
|
|
VerifySerializeToFrom(db);
|
|
|
|
actual_output = db->ToString();
|
2017-04-08 20:00:08 +00:00
|
|
|
}
|
|
|
|
|
2017-04-08 22:54:36 +00:00
|
|
|
// Compare output via rapidjson::Document to ignore any formatting
|
|
|
|
// differences.
|
|
|
|
rapidjson::Document actual;
|
|
|
|
actual.Parse(actual_output.c_str());
|
|
|
|
rapidjson::Document expected;
|
|
|
|
expected.Parse(expected_output.c_str());
|
2017-02-27 07:28:33 +00:00
|
|
|
|
2017-04-08 22:54:36 +00:00
|
|
|
if (actual == expected) {
|
|
|
|
std::cout << "[PASSED] " << path << std::endl;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DiffDocuments(path, expected_path, expected, actual);
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << std::endl;
|
2017-04-15 04:53:10 +00:00
|
|
|
std::cout << "[Enter to continue - type u to update test, a to update all]";
|
|
|
|
char c = 'u';
|
|
|
|
if (!update_all) {
|
|
|
|
c = std::cin.get();
|
|
|
|
std::cin.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == 'a')
|
|
|
|
update_all = true;
|
|
|
|
|
|
|
|
if (update_all || c == 'u') {
|
|
|
|
UpdateTestExpectation(path, expected_output, ToString(actual) + "\n");
|
|
|
|
}
|
|
|
|
|
2017-04-08 22:54:36 +00:00
|
|
|
}
|
2017-02-27 07:28:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cin.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: ctor/dtor, copy ctor
|
2017-04-08 22:54:36 +00:00
|
|
|
// TODO: Always pass IndexedFile by pointer, ie, search and remove all IndexedFile& refs.
|
|
|
|
// TODO: Rename IndexedFile to IndexFile
|
|
|
|
|