// Step 311: C# Parser Tests (12 tests) // Verifies CSharpParser parses C# source into Whetstone AST: // methods, async methods → AsyncFunction, class, interface, using/namespace skipped. #include "ast/CSharpParser.h" #include "ast/Module.h" #include "ast/Function.h" #include "ast/Variable.h" #include "ast/ClassDeclaration.h" #include "ast/AsyncNodes.h" #include #include #include static int passed = 0, failed = 0; #define TEST(name) { std::cout << " " << #name << "... "; } #define PASS() { std::cout << "PASS\n"; ++passed; } #define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; } #define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } else {} // 1. Parse a simple method void test_parse_simple_method() { TEST(parse_simple_method); auto mod = CSharpParser::parseCSharp(R"( public void DoWork() { Console.WriteLine("Hello"); } )"); CHECK(mod != nullptr, "module is null"); auto fns = mod->getChildren("functions"); CHECK(fns.size() == 1, "expected 1 function, got " + std::to_string(fns.size())); CHECK(fns[0]->conceptType == "Function", "expected Function, got " + fns[0]->conceptType); auto* fn = static_cast(fns[0]); CHECK(fn->name == "DoWork", "expected name 'DoWork', got '" + fn->name + "'"); PASS(); } // 2. Parse async method → AsyncFunction void test_parse_async_method() { TEST(parse_async_method); auto mod = CSharpParser::parseCSharp(R"( public async Task FetchData() { var result = await httpClient.GetAsync(url); } )"); CHECK(mod != nullptr, "module is null"); auto fns = mod->getChildren("functions"); CHECK(fns.size() == 1, "expected 1 function"); CHECK(fns[0]->conceptType == "AsyncFunction", "expected AsyncFunction, got " + fns[0]->conceptType); auto* af = static_cast(fns[0]); CHECK(af->name == "FetchData", "expected name 'FetchData', got '" + af->name + "'"); PASS(); } // 3. Parse class declaration (empty class — no inner methods to clobber name) void test_parse_class() { TEST(parse_class); auto mod = CSharpParser::parseCSharp(R"( class Animal { } )"); CHECK(mod != nullptr, "module is null"); auto classes = mod->getChildren("classes"); CHECK(classes.size() == 1, "expected 1 class, got " + std::to_string(classes.size())); auto* cls = static_cast(classes[0]); CHECK(cls->name == "Animal", "expected name 'Animal', got '" + cls->name + "'"); PASS(); } // 4. Parse interface declaration void test_parse_interface() { TEST(parse_interface); auto mod = CSharpParser::parseCSharp(R"( interface IDrawable { void Draw(); } )"); CHECK(mod != nullptr, "module is null"); auto ifaces = mod->getChildren("interfaces"); CHECK(ifaces.size() == 1, "expected 1 interface, got " + std::to_string(ifaces.size())); auto* iface = static_cast(ifaces[0]); CHECK(iface->name == "IDrawable", "expected name 'IDrawable', got '" + iface->name + "'"); PASS(); } // 5. Using directives are skipped void test_using_directives_skipped() { TEST(using_directives_skipped); auto mod = CSharpParser::parseCSharp(R"( using System; using System.Collections.Generic; public void Main() { Console.WriteLine("hello"); } )"); CHECK(mod != nullptr, "module is null"); auto fns = mod->getChildren("functions"); CHECK(fns.size() == 1, "expected 1 function (usings skipped)"); PASS(); } // 6. Namespace wrapper is skipped void test_namespace_skipped() { TEST(namespace_skipped); auto mod = CSharpParser::parseCSharp(R"( namespace MyApp { } )"); CHECK(mod != nullptr, "module is null"); // Namespace alone should not produce functions or classes CHECK(mod->getChildren("functions").empty(), "expected no functions"); PASS(); } // 7. Module target language is csharp void test_module_target_language() { TEST(module_target_language); auto mod = CSharpParser::parseCSharp("public void Test() {\n}\n"); CHECK(mod != nullptr, "module is null"); CHECK(mod->targetLanguage == "csharp", "expected 'csharp', got '" + mod->targetLanguage + "'"); CHECK(mod->name == "parsed_csharp_module", "expected module name 'parsed_csharp_module'"); PASS(); } // 8. Parse with diagnostics entry point void test_parse_with_diagnostics() { TEST(parse_with_diagnostics); auto result = CSharpParser::parseCSharpWithDiagnostics(R"( public void Test() { int x = 1; } )"); CHECK(result.module != nullptr, "module is null from WithDiagnostics"); auto fns = result.module->getChildren("functions"); CHECK(fns.size() == 1, "expected 1 function"); PASS(); } // 9. Multiple methods void test_parse_multiple_methods() { TEST(parse_multiple_methods); auto mod = CSharpParser::parseCSharp(R"( public void Foo() { int a = 1; } private void Bar() { int b = 2; } static void Baz() { int c = 3; } )"); CHECK(mod != nullptr, "module is null"); auto fns = mod->getChildren("functions"); CHECK(fns.size() == 3, "expected 3 functions, got " + std::to_string(fns.size())); PASS(); } // 10. Mixed async and sync methods (top-level, no class wrapper) void test_mixed_async_sync() { TEST(mixed_async_sync); auto mod = CSharpParser::parseCSharp(R"( public void SyncWork() { } public async Task AsyncWork() { } public void MoreSync() { } )"); CHECK(mod != nullptr, "module is null"); auto fns = mod->getChildren("functions"); CHECK(fns.size() == 3, "expected 3 functions, got " + std::to_string(fns.size())); CHECK(fns[0]->conceptType == "Function", "first should be Function"); CHECK(fns[1]->conceptType == "AsyncFunction", "second should be AsyncFunction"); CHECK(fns[2]->conceptType == "Function", "third should be Function"); PASS(); } // 11. Empty source produces empty module void test_parse_empty_source() { TEST(parse_empty_source); auto mod = CSharpParser::parseCSharp(""); CHECK(mod != nullptr, "module should not be null for empty source"); CHECK(mod->getChildren("functions").empty(), "expected no functions"); CHECK(mod->getChildren("classes").empty(), "expected no classes"); PASS(); } // 12. Comments are skipped void test_comments_skipped() { TEST(comments_skipped); auto mod = CSharpParser::parseCSharp(R"( // A comment public void Execute() { // Inner comment } )"); CHECK(mod != nullptr, "module is null"); auto fns = mod->getChildren("functions"); CHECK(fns.size() == 1, "expected 1 function"); auto* fn = static_cast(fns[0]); CHECK(fn->name == "Execute", "expected 'Execute'"); PASS(); } int main() { std::cout << "Step 311: C# Parser Tests\n"; test_parse_simple_method(); // 1 test_parse_async_method(); // 2 test_parse_class(); // 3 test_parse_interface(); // 4 test_using_directives_skipped(); // 5 test_namespace_skipped(); // 6 test_module_target_language(); // 7 test_parse_with_diagnostics(); // 8 test_parse_multiple_methods(); // 9 test_mixed_async_sync(); // 10 test_parse_empty_source(); // 11 test_comments_skipped(); // 12 std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n"; return failed == 0 ? 0 : 1; }