diff --git a/src/protocol/tests/parser_validation.rs b/src/protocol/tests/parser_validation.rs index 6b058569a03f21230018723fbe973c4f2fc982d1..5af066d56fd571d4c2f7e67ed08978014f580150 100644 --- a/src/protocol/tests/parser_validation.rs +++ b/src/protocol/tests/parser_validation.rs @@ -86,3 +86,255 @@ fn test_correct_struct_instance() { " ); } + +#[test] +fn test_incorrect_struct_instance() { + Tester::new_single_source_expect_err( + "reused field in definition", + "struct Foo{ int a, byte a }" + ).error(|e| { e + .assert_num(2) + .assert_occurs_at(0, "a }") + .assert_msg_has(0, "defined more than once") + .assert_occurs_at(1, "a, ") + .assert_msg_has(1, "other struct field"); + }); + + Tester::new_single_source_expect_err( + "reused field in instance", + " + struct Foo{ int a, int b } + int bar() { + auto foo = Foo{ a: 5, a: 3 }; + return 0; + } + " + ).error(|e| { e + .assert_occurs_at(0, "a: 3") + .assert_msg_has(0, "field is specified more than once"); + }); + + Tester::new_single_source_expect_err( + "missing field", + " + struct Foo { int a, int b } + int bar() { + auto foo = Foo{ a: 2 }; + return 0; + } + " + ).error(|e| { e + .assert_occurs_at(0, "Foo{") + .assert_msg_has(0, "'b' is missing"); + }); + + Tester::new_single_source_expect_err( + "missing fields", + " + struct Foo { int a, int b, int c } + int bar() { + auto foo = Foo{ a: 2 }; + return 0; + } + " + ).error(|e| { e + .assert_occurs_at(0, "Foo{") + .assert_msg_has(0, "[b, c] are missing"); + }); +} + +#[test] +fn test_correct_enum_instance() { + Tester::new_single_source_expect_ok( + "single variant", + " + enum Foo { A } + Foo bar() { return Foo::A; } + " + ); + + Tester::new_single_source_expect_ok( + "multiple variants", + " + enum Foo { A=15, B = 0xF } + Foo bar() { auto a = Foo::A; return Foo::B; } + " + ); + + Tester::new_single_source_expect_ok( + "explicit single polymorph", + " + enum Foo{ A } + Foo bar() { return Foo::A; } + " + ); + + Tester::new_single_source_expect_ok( + "explicit multi-polymorph", + " + enum Foo{ A, B } + Foo bar() { return Foo::B; } + " + ); +} + +#[test] +fn test_incorrect_enum_instance() { + Tester::new_single_source_expect_err( + "variant name reuse", + " + enum Foo { A, A } + Foo bar() { return Foo::A; } + " + ).error(|e| { e + .assert_num(2) + .assert_occurs_at(0, "A }") + .assert_msg_has(0, "defined more than once") + .assert_occurs_at(1, "A, ") + .assert_msg_has(1, "other enum variant is defined here"); + }); + + Tester::new_single_source_expect_err( + "undefined variant", + " + enum Foo { A } + Foo bar() { return Foo::B; } + " + ).error(|e| { e + .assert_num(1) + .assert_msg_has(0, "variant 'B' does not exist on the enum 'Foo'"); + }); +} + +#[test] +fn test_correct_union_instance() { + Tester::new_single_source_expect_ok( + "single tag", + " + union Foo { A } + Foo bar() { return Foo::A; } + " + ); + + Tester::new_single_source_expect_ok( + "multiple tags", + " + union Foo { A, B } + Foo bar() { return Foo::B; } + " + ); + + Tester::new_single_source_expect_ok( + "single embedded", + " + union Foo { A(int) } + Foo bar() { return Foo::A(5); } + " + ); + + Tester::new_single_source_expect_ok( + "multiple embedded", + " + union Foo { A(int), B(byte) } + Foo bar() { return Foo::B(2); } + " + ); + + Tester::new_single_source_expect_ok( + "multiple values in embedded", + " + union Foo { A(int, byte) } + Foo bar() { return Foo::A(0, 2); } + " + ); + + Tester::new_single_source_expect_ok( + "mixed tag/embedded", + " + union OptionInt { None, Some(int) } + OptionInt bar() { return OptionInt::Some(3); } + " + ); + + Tester::new_single_source_expect_ok( + "single polymorphic var", + " + union Option { None, Some(T) } + Option bar() { return Option::Some(3); }" + ); + + Tester::new_single_source_expect_ok( + "multiple polymorphic vars", + " + union Result { Ok(T), Err(E), } + Result bar() { return Result::Ok(3); } + " + ); + + Tester::new_single_source_expect_ok( + "multiple polymorphic in one variant", + " + union MaybePair{ None, Some(T1, T2) } + MaybePair bar() { return MaybePair::Some(1, 2); } + " + ); +} + +#[test] +fn test_incorrect_union_instance() { + Tester::new_single_source_expect_err( + "tag-variant name reuse", + " + union Foo{ A, A } + " + ).error(|e| { e + .assert_num(2) + .assert_occurs_at(0, "A }") + .assert_msg_has(0, "union variant is defined more than once") + .assert_occurs_at(1, "A, ") + .assert_msg_has(1, "other union variant"); + }); + + Tester::new_single_source_expect_err( + "embedded-variant name reuse", + " + union Foo{ A(int), A(byte) } + " + ).error(|e| { e + .assert_num(2) + .assert_occurs_at(0, "A(byte)") + .assert_msg_has(0, "union variant is defined more than once") + .assert_occurs_at(1, "A(int)") + .assert_msg_has(1, "other union variant"); + }); + + Tester::new_single_source_expect_err( + "undefined variant", + " + union Silly{ Thing(byte) } + Silly bar() { return Silly::Undefined(5); } + " + ).error(|e| { e + .assert_msg_has(0, "variant 'Undefined' does not exist on the union 'Silly'"); + }); + + Tester::new_single_source_expect_err( + "using tag instead of embedded", + " + union Foo{ A(int) } + Foo bar() { return Foo::A; } + " + ).error(|e| { e + .assert_msg_has(0, "variant 'A' of union 'Foo' expects 1 embedded values, but 0 were"); + }); + + Tester::new_single_source_expect_err( + "using embedded instead of tag", + " + union Foo{ A } + Foo bar() { return Foo::A(3); } + " + ).error(|e| { e + .assert_msg_has(0, "The variant 'A' of union 'Foo' expects 0"); + }); +} \ No newline at end of file