diff --git a/indexer.cpp b/indexer.cpp index fa2132e1..a588f0a6 100644 --- a/indexer.cpp +++ b/indexer.cpp @@ -823,14 +823,12 @@ void indexEntityReference(CXClientData client_data, const CXIdxEntityRefInfo* re } } -static bool DUMP_AST = true; - -IndexedFile Parse(IdCache* id_cache, std::string filename, std::vector args) { +IndexedFile Parse(IdCache* id_cache, std::string filename, std::vector args, bool dump_ast) { clang::Index index(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/); clang::TranslationUnit tu(index, filename, args); - if (DUMP_AST) + if (dump_ast) Dump(tu.document_cursor()); CXIndexAction index_action = clang_IndexAction_create(index.cx_index); @@ -859,165 +857,3 @@ IndexedFile Parse(IdCache* id_cache, std::string filename, std::vector -bool AreEqual(const std::vector& a, const std::vector& b) { - if (a.size() != b.size()) - return false; - - for (int i = 0; i < a.size(); ++i) { - if (a[i] != b[i]) - return false; - } - - return true; -} - -void Write(const std::vector& strs) { - for (const std::string& str : strs) { - std::cout << str << std::endl; - } -} - - -std::string ToString(const rapidjson::Document& document) { - rapidjson::StringBuffer buffer; - rapidjson::PrettyWriter writer(buffer); - writer.SetFormatOptions( - rapidjson::PrettyFormatOptions::kFormatSingleLineArray); - writer.SetIndent(' ', 2); - - buffer.Clear(); - document.Accept(writer); - return buffer.GetString(); -} - -std::vector split_string(const std::string& str, const std::string& delimiter) { - // http://stackoverflow.com/a/13172514 - std::vector 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; -} - - -void DiffDocuments(rapidjson::Document& expected, rapidjson::Document& actual) { - std::vector actual_output; - { - std::string buffer = ToString(actual); - actual_output = split_string(buffer, "\n"); - } - - std::vector expected_output; - { - std::string buffer = ToString(expected); - expected_output = split_string(buffer, "\n"); - } - - int len = std::min(actual_output.size(), expected_output.size()); - for (int i = 0; i < len; ++i) { - if (actual_output[i] != expected_output[i]) { - 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; - for (int i = len; i < actual_output.size(); ++i) - std::cout << " " << actual_output[i] << std::endl; - } - - if (expected_output.size() > len) { - std::cout << "Additional output in expected:" << std::endl; - for (int i = len; i < expected_output.size(); ++i) - std::cout << " " << expected_output[i] << std::endl; - } -} - -void WriteToFile(const std::string& filename, const std::string& content) { - std::ofstream file(filename); - file << content; -} - -int main(int argc, char** argv) { - // TODO: Assert that we need to be on clang >= 3.9.1 - - /* - ParsingDatabase db = Parse("tests/vars/function_local.cc"); - std::cout << std::endl << "== Database ==" << std::endl; - std::cout << db.ToString(); - std::cin.get(); - return 0; - */ - - DUMP_AST = false; - - for (std::string path : GetFilesInFolder("tests")) { - //if (path != "tests/usage/type_usage_declare_field.cc") continue; - //if (path != "tests/enums/enum_class_decl.cc") continue; - //if (path != "tests/constructors/constructor.cc") continue; - //if (path == "tests/constructors/destructor.cc") continue; - //if (path == "tests/usage/func_usage_call_method.cc") continue; - //if (path != "tests/usage/type_usage_as_template_parameter.cc") continue; - //if (path != "tests/usage/type_usage_as_template_parameter_complex.cc") continue; - //if (path != "tests/usage/type_usage_as_template_parameter_simple.cc") continue; - //if (path != "tests/usage/type_usage_typedef_and_using.cc") continue; - //if (path != "tests/usage/type_usage_declare_local.cc") continue; - //if (path == "tests/usage/type_usage_typedef_and_using_template.cc") continue; - //if (path != "tests/usage/func_usage_addr_method.cc") continue; - //if (path != "tests/usage/type_usage_typedef_and_using.cc") continue; - //if (path != "tests/usage/usage_inside_of_call.cc") continue; - //if (path != "tests/foobar.cc") continue; - //if (path != "tests/types/anonymous_struct.cc") continue; - - // Parse expected output from the test, parse it into JSON document. - std::string expected_output; - ParseTestExpectation(path, &expected_output); - rapidjson::Document expected; - expected.Parse(expected_output.c_str()); - - // Run test. - std::cout << "[START] " << path << std::endl; - IdCache id_cache; - IndexedFile db = Parse(&id_cache, path, {}); - std::string actual_output = db.ToString(); - - //WriteToFile("output.json", actual_output); - //break; - - rapidjson::Document actual; - actual.Parse(actual_output.c_str()); - - if (actual == expected) { - std::cout << "[PASSED] " << path << std::endl; - } - else { - std::cout << "[FAILED] " << path << std::endl; - std::cout << "Expected output for " << path << ":" << std::endl; - std::cout << expected_output; - std::cout << "Actual output for " << path << ":" << std::endl; - std::cout << actual_output; - std::cout << std::endl; - std::cout << std::endl; - DiffDocuments(expected, actual); - break; - } - } - - std::cin.get(); - return 0; -} - -// TODO: ctor/dtor, copy ctor diff --git a/indexer.h b/indexer.h index 04fae638..189b784d 100644 --- a/indexer.h +++ b/indexer.h @@ -536,4 +536,4 @@ struct IndexedFile { -IndexedFile Parse(IdCache* id_cache, std::string filename, std::vector args); \ No newline at end of file +IndexedFile Parse(IdCache* id_cache, std::string filename, std::vector args, bool dump_ast = false); \ No newline at end of file diff --git a/test.cc b/test.cc index 91f29bbe..42f96ecd 100644 --- a/test.cc +++ b/test.cc @@ -1,2 +1,160 @@ -void bar(int a, int b) {} -void foo() {} \ No newline at end of file +#include "indexer.h" + +template +bool AreEqual(const std::vector& a, const std::vector& b) { + if (a.size() != b.size()) + return false; + + for (int i = 0; i < a.size(); ++i) { + if (a[i] != b[i]) + return false; + } + + return true; +} + +void Write(const std::vector& strs) { + for (const std::string& str : strs) { + std::cout << str << std::endl; + } +} + + +std::string ToString(const rapidjson::Document& document) { + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter writer(buffer); + writer.SetFormatOptions( + rapidjson::PrettyFormatOptions::kFormatSingleLineArray); + writer.SetIndent(' ', 2); + + buffer.Clear(); + document.Accept(writer); + return buffer.GetString(); +} + +std::vector split_string(const std::string& str, const std::string& delimiter) { + // http://stackoverflow.com/a/13172514 + std::vector 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; +} + + +void DiffDocuments(rapidjson::Document& expected, rapidjson::Document& actual) { + std::vector actual_output; + { + std::string buffer = ToString(actual); + actual_output = split_string(buffer, "\n"); + } + + std::vector expected_output; + { + std::string buffer = ToString(expected); + expected_output = split_string(buffer, "\n"); + } + + int len = std::min(actual_output.size(), expected_output.size()); + for (int i = 0; i < len; ++i) { + if (actual_output[i] != expected_output[i]) { + 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; + for (int i = len; i < actual_output.size(); ++i) + std::cout << " " << actual_output[i] << std::endl; + } + + if (expected_output.size() > len) { + std::cout << "Additional output in expected:" << std::endl; + for (int i = len; i < expected_output.size(); ++i) + std::cout << " " << expected_output[i] << std::endl; + } +} + +void WriteToFile(const std::string& filename, const std::string& content) { + std::ofstream file(filename); + file << content; +} + +int main(int argc, char** argv) { + // TODO: Assert that we need to be on clang >= 3.9.1 + + /* + ParsingDatabase db = Parse("tests/vars/function_local.cc"); + std::cout << std::endl << "== Database ==" << std::endl; + std::cout << db.ToString(); + std::cin.get(); + return 0; + */ + + for (std::string path : GetFilesInFolder("tests")) { + //if (path != "tests/usage/type_usage_declare_field.cc") continue; + //if (path != "tests/enums/enum_class_decl.cc") continue; + //if (path != "tests/constructors/constructor.cc") continue; + //if (path == "tests/constructors/destructor.cc") continue; + //if (path == "tests/usage/func_usage_call_method.cc") continue; + //if (path != "tests/usage/type_usage_as_template_parameter.cc") continue; + //if (path != "tests/usage/type_usage_as_template_parameter_complex.cc") continue; + //if (path != "tests/usage/type_usage_as_template_parameter_simple.cc") continue; + //if (path != "tests/usage/type_usage_typedef_and_using.cc") continue; + //if (path != "tests/usage/type_usage_declare_local.cc") continue; + //if (path == "tests/usage/type_usage_typedef_and_using_template.cc") continue; + //if (path != "tests/usage/func_usage_addr_method.cc") continue; + //if (path != "tests/usage/type_usage_typedef_and_using.cc") continue; + //if (path != "tests/usage/usage_inside_of_call.cc") continue; + //if (path != "tests/foobar.cc") continue; + //if (path != "tests/types/anonymous_struct.cc") continue; + + // Parse expected output from the test, parse it into JSON document. + std::string expected_output; + ParseTestExpectation(path, &expected_output); + rapidjson::Document expected; + expected.Parse(expected_output.c_str()); + + // Run test. + std::cout << "[START] " << path << std::endl; + IdCache id_cache; + IndexedFile db = Parse(&id_cache, path, {}, true /*dump_ast*/); + std::string actual_output = db.ToString(); + + //WriteToFile("output.json", actual_output); + //break; + + rapidjson::Document actual; + actual.Parse(actual_output.c_str()); + + if (actual == expected) { + std::cout << "[PASSED] " << path << std::endl; + } + else { + std::cout << "[FAILED] " << path << std::endl; + std::cout << "Expected output for " << path << ":" << std::endl; + std::cout << expected_output; + std::cout << "Actual output for " << path << ":" << std::endl; + std::cout << actual_output; + std::cout << std::endl; + std::cout << std::endl; + DiffDocuments(expected, actual); + break; + } + } + + std::cin.get(); + return 0; +} + +// TODO: ctor/dtor, copy ctor