|  | // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | package parser | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "mojom/mojom_tool/lexer" | 
|  | "mojom/mojom_tool/mojom" | 
|  | "strings" | 
|  | "testing" | 
|  | ) | 
|  |  | 
|  | // TestSuccessfulParsing contains a series of test cases in which we | 
|  | // run the parser on a valid mojom input string and compare the resulting | 
|  | // MojomFile to an expected one. | 
|  | func TestSuccessfulParsing(t *testing.T) { | 
|  | type testCase struct { | 
|  | fileName      string | 
|  | mojomContents string | 
|  | expectedFile  *mojom.MojomFile | 
|  | } | 
|  | cases := make([]testCase, 0) | 
|  | testCaseNum := 0 | 
|  | var expectedFile *mojom.MojomFile | 
|  |  | 
|  | startTestCase := func(moduleNameSpace string) { | 
|  | descriptor := mojom.NewMojomDescriptor() | 
|  | fileName := fmt.Sprintf("file%d", testCaseNum) | 
|  | expectedFile = descriptor.AddMojomFile(fileName, fileName, nil, "") | 
|  | expectedFile.InitializeFileScope(mojom.NewModuleNamespace(moduleNameSpace, nil)) | 
|  | cases = append(cases, testCase{fileName, "", expectedFile}) | 
|  | } | 
|  |  | 
|  | endTestCase := func() { | 
|  | testCaseNum += 1 | 
|  | } | 
|  |  | 
|  | // Note(rudominer) The structure of this method is designed to allow | 
|  | // test cases to be rearranged and new test cases to be inserted at | 
|  | // arbitrary locations. Do not hard-code anything that refers to the | 
|  | // position of a test case in the list. | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (empty file) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = "" | 
|  | endTestCase() | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (module statement only) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("mojom.test") | 
|  | cases[testCaseNum].mojomContents = `module mojom.test;` | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (module statement with attributes) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("mojom.test") | 
|  | cases[testCaseNum].mojomContents = `[cool=true]module mojom.test;` | 
|  | expectedFile.Attributes = mojom.NewAttributes(lexer.Token{}) | 
|  | expectedFile.Attributes.List = append(expectedFile.Attributes.List, | 
|  | mojom.NewMojomAttribute("cool", nil, mojom.MakeBoolLiteralValue(true, nil))) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (import statements only) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = `import "a.file";` | 
|  | expectedFile.AddImport(mojom.NewImportedFile("a.file", nil)) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (module and import statements only) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("mojom.test") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | module mojom.test; | 
|  |  | 
|  | import "a.file";` | 
|  | { | 
|  | expectedFile.AddImport(mojom.NewImportedFile("a.file", nil)) | 
|  | endTestCase() | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (module with attributes and import statements only) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("mojom.test") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | [cool=true] | 
|  | module mojom.test; | 
|  |  | 
|  | import "a.file";` | 
|  | { | 
|  | expectedFile.Attributes = mojom.NewAttributes(lexer.Token{}) | 
|  | expectedFile.Attributes.List = append(expectedFile.Attributes.List, | 
|  | mojom.NewMojomAttribute("cool", nil, mojom.MakeBoolLiteralValue(true, nil))) | 
|  | expectedFile.AddImport(mojom.NewImportedFile("a.file", nil)) | 
|  | endTestCase() | 
|  | } | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (one empty sruct) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = `struct Foo{};` | 
|  | expectedFile.AddStruct(mojom.NewMojomStruct(mojom.DeclTestData("Foo"))) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Integer constants) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | const uint8 xu8 = 255; | 
|  | const int8 x8 = -127; | 
|  | const uint16 xu16 = 0xFFFF; | 
|  | const int16 x16 = -0x7FFF; | 
|  | const uint32 xu32 = 4294967295; | 
|  | const int32 x32 = -2147483647; | 
|  | const uint64 xu64 = 0xFFFFFFFFFFFFFFFF; | 
|  | const int64 x64 = -0x7FFFFFFFFFFFFFFF; | 
|  | const uint64 manyNines = 9999999999999999999; | 
|  | ` | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("xu8"), | 
|  | mojom.SimpleTypeUInt8, mojom.MakeUint8LiteralValue(0xFF, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("x8"), | 
|  | mojom.SimpleTypeInt8, mojom.MakeInt8LiteralValue(-0x7F, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("xu16"), | 
|  | mojom.SimpleTypeUInt16, mojom.MakeUint16LiteralValue(65535, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("x16"), | 
|  | mojom.SimpleTypeInt16, mojom.MakeInt16LiteralValue(-32767, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("xu32"), | 
|  | mojom.SimpleTypeUInt32, mojom.MakeUint32LiteralValue(0xFFFFFFFF, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("x32"), | 
|  | mojom.SimpleTypeInt32, mojom.MakeInt32LiteralValue(-0x7FFFFFFF, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("xu64"), | 
|  | mojom.SimpleTypeUInt64, mojom.MakeUint64LiteralValue(18446744073709551615, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("x64"), | 
|  | mojom.SimpleTypeInt64, mojom.MakeInt64LiteralValue(-9223372036854775807, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("manyNines"), | 
|  | mojom.SimpleTypeUInt64, mojom.MakeUint64LiteralValue(9999999999999999999, nil))) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (float and double constants) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | const float x = 123.456E7; | 
|  | const float y = 123456789.123456789; | 
|  | const float z = -0.01; | 
|  | const double w = -0.01; | 
|  | const double r = 3.14159E40; | 
|  | ` | 
|  | { | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("x"), | 
|  | mojom.SimpleTypeFloat, mojom.MakeDoubleLiteralValue(1234560000, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("y"), | 
|  | mojom.SimpleTypeFloat, mojom.MakeDoubleLiteralValue(123456789.123456789, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("z"), | 
|  | mojom.SimpleTypeFloat, mojom.MakeDoubleLiteralValue(-0.01, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("w"), | 
|  | mojom.SimpleTypeDouble, mojom.MakeDoubleLiteralValue(-0.01, nil))) | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("r"), | 
|  | mojom.SimpleTypeDouble, mojom.MakeDoubleLiteralValue(3.14159e+40, nil))) | 
|  | } | 
|  | endTestCase() | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("mojom.test") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | module mojom.test; | 
|  |  | 
|  | struct Foo{ | 
|  | int32 x; | 
|  | };` | 
|  | { | 
|  | structFoo := mojom.NewMojomStruct(mojom.DeclTestData("Foo")) | 
|  | structFoo.InitAsScope(mojom.NewTestFileScope("test.scope")) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestData("x"), mojom.SimpleTypeInt32, nil)) | 
|  | expectedFile.AddStruct(structFoo) | 
|  | } | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("mojom.test") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | module mojom.test; | 
|  |  | 
|  | import "another.file"; | 
|  | import "and.another.file"; | 
|  |  | 
|  | struct Foo{ | 
|  | [happy=true] int32 x@0; | 
|  | };` | 
|  | { | 
|  | expectedFile.AddImport(mojom.NewImportedFile("another.file", nil)) | 
|  | expectedFile.AddImport(mojom.NewImportedFile("and.another.file", nil)) | 
|  |  | 
|  | structFoo := mojom.NewMojomStruct(mojom.DeclTestData("Foo")) | 
|  | structFoo.InitAsScope(mojom.NewTestFileScope("test.scope")) | 
|  | attributes := mojom.NewAttributes(lexer.Token{}) | 
|  | attributes.List = append(attributes.List, mojom.NewMojomAttribute("happy", nil, mojom.MakeBoolLiteralValue(true, nil))) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestDataAWithOrdinal("x", attributes, 0), mojom.SimpleTypeInt32, nil)) | 
|  | expectedFile.AddStruct(structFoo) | 
|  | } | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("mojom.test") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | module mojom.test; | 
|  |  | 
|  | import "another.file"; | 
|  | import "and.another.file"; | 
|  |  | 
|  | struct Foo{ | 
|  | int32 x@0 = 42; | 
|  | [age=7, level="high"] string  y = "Howdy!"; | 
|  | string? z; | 
|  | bool w@3 = false; | 
|  | };` | 
|  | { | 
|  | expectedFile.AddImport(mojom.NewImportedFile("another.file", nil)) | 
|  | expectedFile.AddImport(mojom.NewImportedFile("and.another.file", nil)) | 
|  |  | 
|  | structFoo := mojom.NewMojomStruct(mojom.DeclTestData("Foo")) | 
|  | structFoo.InitAsScope(mojom.NewTestFileScope("test.scope")) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestDataWithOrdinal("x", 0), mojom.SimpleTypeInt32, mojom.MakeInt8LiteralValue(42, nil))) | 
|  | attributes := mojom.NewAttributes(lexer.Token{}) | 
|  | attributes.List = append(attributes.List, mojom.NewMojomAttribute("age", nil, mojom.MakeInt8LiteralValue(7, nil))) | 
|  | attributes.List = append(attributes.List, mojom.NewMojomAttribute("level", nil, mojom.MakeStringLiteralValue("high", nil))) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestDataA("y", attributes), mojom.BuiltInType("string"), mojom.MakeStringLiteralValue("Howdy!", nil))) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestData("z"), mojom.BuiltInType("string?"), nil)) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestDataWithOrdinal("w", 3), mojom.BuiltInType("bool"), mojom.MakeBoolLiteralValue(false, nil))) | 
|  | expectedFile.AddStruct(structFoo) | 
|  | } | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("mojom.test") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | module mojom.test; | 
|  |  | 
|  | import "another.file"; | 
|  | import "and.another.file"; | 
|  |  | 
|  | struct Foo{ | 
|  | int32 x; | 
|  | string  y; | 
|  | string? z; | 
|  | }; | 
|  |  | 
|  | interface Doer { | 
|  | DoIt(int8 lemon, handle<message_pipe> pipe) => (array<Foo> someFoos, Foo? anotherFoo); | 
|  | }; | 
|  |  | 
|  | ` | 
|  | { | 
|  | expectedFile.AddImport(mojom.NewImportedFile("another.file", nil)) | 
|  | expectedFile.AddImport(mojom.NewImportedFile("and.another.file", nil)) | 
|  |  | 
|  | structFoo := mojom.NewMojomStruct(mojom.DeclTestData("Foo")) | 
|  | structFoo.InitAsScope(mojom.NewTestFileScope("test.scope")) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestData("x"), mojom.SimpleTypeInt32, nil)) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestData("y"), mojom.BuiltInType("string"), nil)) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestData("z"), mojom.BuiltInType("string?"), nil)) | 
|  | expectedFile.AddStruct(structFoo) | 
|  |  | 
|  | interfaceDoer := mojom.NewMojomInterface(mojom.DeclTestData("Doer")) | 
|  | interfaceDoer.InitAsScope(mojom.NewTestFileScope("test.scope")) | 
|  |  | 
|  | // The first reference to Foo inside of interface Doer | 
|  | fooRef1 := mojom.NewUserTypeRef("Foo", false, false, interfaceDoer.Scope(), lexer.Token{}) | 
|  |  | 
|  | // The second reference to Foo inside of interface Doer. nullable=true | 
|  | fooRef2 := mojom.NewUserTypeRef("Foo", true, false, interfaceDoer.Scope(), lexer.Token{}) | 
|  |  | 
|  | params := mojom.NewMojomStruct(mojom.DeclTestData("dummy")) | 
|  | params.InitAsScope(mojom.NewTestFileScope("test.scope")) | 
|  | params.AddField(mojom.NewStructField(mojom.DeclTestData("lemon"), mojom.SimpleTypeInt8, nil)) | 
|  | params.AddField(mojom.NewStructField(mojom.DeclTestData("pipe"), mojom.BuiltInType("handle<message_pipe>"), nil)) | 
|  | responseParams := mojom.NewMojomStruct(mojom.DeclTestData("dummy")) | 
|  | responseParams.InitAsScope(mojom.NewTestFileScope("test.scope")) | 
|  | responseParams.AddField(mojom.NewStructField(mojom.DeclTestData("someFoos"), mojom.NewArrayTypeRef(fooRef1, -1, false), nil)) | 
|  | responseParams.AddField(mojom.NewStructField(mojom.DeclTestData("anotherFoo"), fooRef2, nil)) | 
|  |  | 
|  | interfaceDoer.AddMethod(mojom.NewMojomMethod(mojom.DeclTestData("DoIt"), params, responseParams)) | 
|  | expectedFile.AddInterface(interfaceDoer) | 
|  | } | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Annotation right after imports) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | import "gpu/interfaces/command_buffer.mojom"; | 
|  |  | 
|  | [ServiceName="mojo::Gpu"] | 
|  | interface Gpu { | 
|  | }; | 
|  |  | 
|  | ` | 
|  | { | 
|  | expectedFile.AddImport(mojom.NewImportedFile("gpu/interfaces/command_buffer.mojom", nil)) | 
|  |  | 
|  | attributes := mojom.NewAttributes(lexer.Token{}) | 
|  | attributes.List = append(attributes.List, mojom.NewMojomAttribute("ServiceName", nil, mojom.MakeStringLiteralValue("mojo::Gpu", nil))) | 
|  | interfaceGpu := mojom.NewMojomInterface(mojom.DeclTestDataA("Gpu", attributes)) | 
|  | expectedFile.AddInterface(interfaceGpu) | 
|  | } | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("mojom.test") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | [php_namespace="mojom.test.php"] | 
|  | module mojom.test; | 
|  |  | 
|  | import "another.file"; | 
|  | import "and.another.file"; | 
|  |  | 
|  | const int8 TOO_SMALL_VALUE = 6; | 
|  |  | 
|  | enum ErrorCodes { | 
|  | TOO_BIG = 5, | 
|  | TOO_SMALL = TOO_SMALL_VALUE, | 
|  | JUST_RIGHT, | 
|  | }; | 
|  |  | 
|  | struct Foo{ | 
|  | int32 x; | 
|  | string  y; | 
|  | string? z; | 
|  | }; | 
|  |  | 
|  | interface Doer { | 
|  | DoIt(int8 lemon, handle<message_pipe> pipe) => (array<Foo> someFoos, Foo? anotherFoo); | 
|  | }; | 
|  |  | 
|  | ` | 
|  | { | 
|  | expectedFile.Attributes = mojom.NewAttributes(lexer.Token{}) | 
|  | expectedFile.Attributes.List = append(expectedFile.Attributes.List, | 
|  | mojom.NewMojomAttribute("php_namespace", nil, mojom.MakeStringLiteralValue("mojom.test.php", nil))) | 
|  |  | 
|  | expectedFile.AddImport(mojom.NewImportedFile("another.file", nil)) | 
|  | expectedFile.AddImport(mojom.NewImportedFile("and.another.file", nil)) | 
|  |  | 
|  | expectedFile.AddConstant(mojom.NewUserDefinedConstant(mojom.DeclTestData("TOO_SMALL_VALUE"), | 
|  | mojom.SimpleTypeInt8, mojom.MakeInt8LiteralValue(6, nil))) | 
|  |  | 
|  | errorCodeEnum := mojom.NewMojomEnum(mojom.DeclTestData("ErrorCodes")) | 
|  | errorCodeEnum.InitAsScope(expectedFile.FileScope) | 
|  |  | 
|  | // The reference to TOO_SMALL_VALUE from within the ErrorCodes enum. | 
|  | assigneeType := mojom.NewResolvedUserTypeRef("ErrorCodes", errorCodeEnum) | 
|  | tooSmallValueRef := mojom.NewUserValueRef(mojom.AssigneeSpec{"assignee", assigneeType}, "TOO_SMALL_VALUE", | 
|  | expectedFile.FileScope, lexer.Token{}) | 
|  |  | 
|  | errorCodeEnum.AddEnumValue(mojom.DeclTestData("TOO_BIG"), mojom.MakeInt8LiteralValue(5, nil)) | 
|  | errorCodeEnum.AddEnumValue(mojom.DeclTestData("TOO_SMALL"), tooSmallValueRef) | 
|  | errorCodeEnum.AddEnumValue(mojom.DeclTestData("JUST_RIGHT"), nil) | 
|  | expectedFile.AddEnum(errorCodeEnum) | 
|  |  | 
|  | structFoo := mojom.NewMojomStruct(mojom.DeclTestData("Foo")) | 
|  | structFoo.InitAsScope(mojom.NewTestFileScope("test.scope")) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestData("x"), mojom.SimpleTypeInt32, nil)) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestData("y"), mojom.BuiltInType("string"), nil)) | 
|  | structFoo.AddField(mojom.NewStructField(mojom.DeclTestData("z"), mojom.BuiltInType("string?"), nil)) | 
|  | expectedFile.AddStruct(structFoo) | 
|  |  | 
|  | interfaceDoer := mojom.NewMojomInterface(mojom.DeclTestData("Doer")) | 
|  | interfaceDoer.InitAsScope(mojom.NewTestFileScope("test.scope")) | 
|  |  | 
|  | // The first reference to Foo inside of interface Doer | 
|  | fooRef1 := mojom.NewUserTypeRef("Foo", false, false, interfaceDoer.Scope(), lexer.Token{}) | 
|  |  | 
|  | // The second reference to Foo inside of interface Doer. nullable=true | 
|  | fooRef2 := mojom.NewUserTypeRef("Foo", true, false, interfaceDoer.Scope(), lexer.Token{}) | 
|  |  | 
|  | params := mojom.NewMojomStruct(mojom.DeclTestData("dummy")) | 
|  | params.InitAsScope(mojom.NewTestFileScope("test.scope")) | 
|  | params.AddField(mojom.NewStructField(mojom.DeclTestData("lemon"), mojom.SimpleTypeInt8, nil)) | 
|  | params.AddField(mojom.NewStructField(mojom.DeclTestData("pipe"), mojom.BuiltInType("handle<message_pipe>"), nil)) | 
|  | responseParams := mojom.NewMojomStruct(mojom.DeclTestData("dummy")) | 
|  | responseParams.InitAsScope(mojom.NewTestFileScope("test.scope")) | 
|  | responseParams.AddField(mojom.NewStructField(mojom.DeclTestData("someFoos"), mojom.NewArrayTypeRef(fooRef1, -1, false), nil)) | 
|  | responseParams.AddField(mojom.NewStructField(mojom.DeclTestData("anotherFoo"), fooRef2, nil)) | 
|  |  | 
|  | interfaceDoer.AddMethod(mojom.NewMojomMethod(mojom.DeclTestData("DoIt"), params, responseParams)) | 
|  | expectedFile.AddInterface(interfaceDoer) | 
|  | } | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Execute all of the test cases. | 
|  | //////////////////////////////////////////////////////////// | 
|  | for _, c := range cases { | 
|  | descriptor := mojom.NewMojomDescriptor() | 
|  | parser := MakeParser(c.fileName, c.fileName, c.mojomContents, descriptor, nil) | 
|  | parser.Parse() | 
|  | if !parser.OK() { | 
|  | t.Errorf("Parsing error for %s: %s", c.fileName, parser.GetError().Error()) | 
|  | } else { | 
|  | got := parser.GetMojomFile().String() | 
|  | expected := c.expectedFile.String() | 
|  | if got != expected { | 
|  | t.Errorf("%s:\n*****expected:\n%s\n****actual\n%s", c.fileName, expected, got) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // TestErrorParsing contains a series of test cases in which we | 
|  | // run the parser on invalid mojom input string and compare the resulting | 
|  | // error message to an expected one. | 
|  | func TestErrorParsing(t *testing.T) { | 
|  | type testCase struct { | 
|  | fileName       string | 
|  | mojomContents  string | 
|  | expectedErrors []string | 
|  | } | 
|  | cases := make([]testCase, 0) | 
|  | testCaseNum := 0 | 
|  |  | 
|  | startTestCase := func(moduleNameSpace string) { | 
|  | fileName := fmt.Sprintf("file%d", testCaseNum) | 
|  | cases = append(cases, testCase{fileName: fileName}) | 
|  | } | 
|  |  | 
|  | expectError := func(expectedError string) { | 
|  | cases[testCaseNum].expectedErrors = append(cases[testCaseNum].expectedErrors, expectedError) | 
|  | } | 
|  |  | 
|  | endTestCase := func() { | 
|  | testCaseNum += 1 | 
|  | } | 
|  |  | 
|  | // Note(rudominer) The structure of this method is designed to allow | 
|  | // test cases to be rearranged and new test cases to be inserted at | 
|  | // arbitrary locations. Do not hard-code anything that refers to the | 
|  | // position of a test case in the list. | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (naked attributes) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = "[cool=true]" | 
|  | expectError("The .mojom file contains an attributes section but nothing else.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (attributes directly before an import) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | [cool=true] | 
|  | import "another.file"; | 
|  | ` | 
|  | expectError("Attributes are not allowed before an import statement.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (two sets of initial naked attributes) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | [cool=true] | 
|  | [not-cool=false] | 
|  | ` | 
|  | expectError("Unexpected ") | 
|  | expectError("'['") | 
|  | expectError("Expecting module, import, interface, struct, union, enum or constant.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (two sets of initial attributes with a module) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | [cool=true] | 
|  | [not-cool=false] | 
|  | module mojom.test; | 
|  | ` | 
|  | expectError("Unexpected ") | 
|  | expectError("'['") | 
|  | expectError("Expecting module, import, interface, struct, union, enum or constant.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (import before module) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | import "another.file"; | 
|  |  | 
|  | module mojom.test; | 
|  | ` | 
|  | expectError("The module declaration must come before the import statements.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid struct field ordinal: empty string | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct MyStruct { | 
|  | int32 x@; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("field \"x\": Invalid ordinal string following '@'") | 
|  | expectError("Ordinals must be decimal integers between 0 and 4294967294") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid struct field ordinal: Not a number | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct MyStruct { | 
|  | int32 x@happy; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("field \"x\": Invalid ordinal string following '@'") | 
|  | expectError("Ordinals must be decimal integers between 0 and 4294967294") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid struct field ordinal: Negative | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct MyStruct { | 
|  | int32 x@-500; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("field \"x\": Invalid ordinal string following '@'") | 
|  | expectError("Ordinals must be decimal integers between 0 and 4294967294") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid struct field ordinal: too big for uint32) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct MyStruct { | 
|  | int32 x@4294967295; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("field \"x\": Invalid ordinal string following '@'") | 
|  | expectError("4294967295") | 
|  | expectError("Ordinals must be decimal integers between 0 and 4294967294") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid struct field ordinal: too big for uint64) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct MyStruct { | 
|  | int32 x@999999999999999999999999999999999999999; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("field \"x\": Invalid ordinal string following '@'") | 
|  | expectError("999999999999999999999999999999999999999") | 
|  | expectError("Ordinals must be decimal integers between 0 and 4294967294") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid struct field ordinal: too big for size of struct) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct MyStruct { | 
|  | int32 x; | 
|  | int32 y@2; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("Invalid ordinal for field y: 2.") | 
|  | expectError("A struct field ordinal must be a non-negative integer value less than the number of fields in the struct.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid struct field ordinal: implicit next value too big for size of struct) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct MyStruct { | 
|  | int32 x; | 
|  | int32 y@2; | 
|  | int32 z; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("Invalid ordinal for field z: 3.") | 
|  | expectError("A struct field ordinal must be a non-negative integer value less than the number of fields in the struct.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid struct field ordinal: Duplicate explicit) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct MyStruct { | 
|  | int32 x@0; | 
|  | int32 y; | 
|  | int32 z@0; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("Invalid ordinal for field z: 0.") | 
|  | expectError("There is already a field in struct MyStruct with that ordinal: x") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid struct field ordinal: Duplicate implicit) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct MyStruct { | 
|  | int32 x; | 
|  | int32 y; | 
|  | int32 z@1; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("Invalid ordinal for field z: 1.") | 
|  | expectError("There is already a field in struct MyStruct with that ordinal: y") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid union field ordinal: too big for uint32) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | union MyUnion { | 
|  | int8  x; | 
|  | int16 y@4294967295; | 
|  | int32 z; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("union field \"y\": Invalid ordinal string following '@'") | 
|  | expectError("4294967295") | 
|  | expectError("Ordinals must be decimal integers between 0 and 4294967294") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid union field ordinal: implicit next value too big for uint32) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | union MyUnion { | 
|  | int8  x; | 
|  | int16 y@4294967294; | 
|  | int32 z; | 
|  | }; | 
|  | ` | 
|  | expectError("Invalid tag for field z") | 
|  | expectError("4294967295") | 
|  | expectError("A union field tag must be between 0 and 4,294,967,294.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid union field ordinal: Duplicate explicit) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | union MyUnion { | 
|  | int8  x@0; | 
|  | int16 y; | 
|  | int32 z@0; | 
|  | }; | 
|  | ` | 
|  | expectError("Invalid tag for field z: 0.") | 
|  | expectError("There is already a field in union MyUnion with that tag: x") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid union field ordinal: Duplicate implicit) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | union MyUnion { | 
|  | int8  x; | 
|  | int16 y; | 
|  | int32 z@1; | 
|  | }; | 
|  | ` | 
|  | expectError("Invalid tag for field z: 1.") | 
|  | expectError("There is already a field in union MyUnion with that tag: y") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid method ordinal: too big for uint32) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | interface MyInterface { | 
|  | MethodA@4294967295(); | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("MethodA") | 
|  | expectError("4294967295") | 
|  | expectError("Invalid ordinal string") | 
|  | expectError("Ordinals must be decimal integers between 0 and 4294967294") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid method ordinal: too big for int64) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | interface MyInterface { | 
|  | MethodA@999999999999999999999999999999999999999(); | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("MethodA") | 
|  | expectError("999999999999999999999999999999999999999") | 
|  | expectError("Invalid ordinal string") | 
|  | expectError("Ordinals must be decimal integers between 0 and 4294967294") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Invalid method ordinal: negative) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | interface MyInterface { | 
|  | MethodA@-1(); | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("MethodA") | 
|  | // Note that the lexer return "@" as the ordinal token, stopping when | 
|  | // it sees the non-digit "-". | 
|  | expectError("Invalid ordinal string") | 
|  | expectError("Ordinals must be decimal integers between 0 and 4294967294") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Constant integer too big for uint64) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | const uint64 manyNines = 99999999999999999999; | 
|  | ` | 
|  | expectError("Integer literal value out of range") | 
|  | expectError("99999999999999999999") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Constant float too big for double) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | const uint64 veryBig = 3.14159E400; | 
|  | ` | 
|  | expectError("Float literal value out of range: 3.14159E400") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Use array as constant type) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | const array<uint64> Foo = 0; | 
|  | ` | 
|  | expectError("The type array<uint64> is not allowed as the type of a declared constant.") | 
|  | expectError("Only simple types, strings and enum types may be the types of constants.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Identifier ends with a dot) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | const array<my.Foo.Type.> Foo = 0; | 
|  | ` | 
|  | expectError("Invalid identifier") | 
|  | expectError("\"my.Foo.Type.\"") | 
|  | expectError("Identifiers may not end with a dot") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Unrecognized type of handle) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | handle<drawer> x; | 
|  | }; | 
|  | ` | 
|  | expectError("Unrecognized type of handle: handle<drawer>") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Nullable bool) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | bool? x; | 
|  | }; | 
|  | ` | 
|  | expectError("The type bool? is invalid because the type bool may not be made nullable") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Execute all of the test cases. | 
|  | //////////////////////////////////////////////////////////// | 
|  | for i, c := range cases { | 
|  | descriptor := mojom.NewMojomDescriptor() | 
|  | parser := MakeParser(c.fileName, c.fileName, c.mojomContents, descriptor, nil) | 
|  | parser.Parse() | 
|  | if parser.OK() { | 
|  | t.Errorf("Parsing was supposed to fail but did not for test case %d", i) | 
|  | } else { | 
|  | got := parser.GetError().Error() | 
|  | for _, expected := range c.expectedErrors { | 
|  | if !strings.Contains(got, expected) { | 
|  | t.Errorf("%s:\n*****expected to contain:\n%s\n****actual\n%s", c.fileName, expected, got) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // TestInvalidAssignmentDuringParsing contains a series of test cases in which we | 
|  | // run the parser on invalid mojom input string and compare the resulting | 
|  | // error message to an expected one. The particular type of error we are testing | 
|  | // here is invalid assignments of values to variables that may be detected during | 
|  | // parsing. | 
|  | func TestInvalidAssignmentDuringParsing(t *testing.T) { | 
|  | type testCase struct { | 
|  | fileName       string | 
|  | mojomContents  string | 
|  | expectedErrors []string | 
|  | } | 
|  | cases := make([]testCase, 0) | 
|  | testCaseNum := 0 | 
|  |  | 
|  | startTestCase := func(moduleNameSpace string) { | 
|  | fileName := fmt.Sprintf("file%d", testCaseNum) | 
|  | cases = append(cases, testCase{fileName: fileName}) | 
|  | } | 
|  |  | 
|  | expectError := func(expectedError string) { | 
|  | cases[testCaseNum].expectedErrors = append(cases[testCaseNum].expectedErrors, expectedError) | 
|  | } | 
|  |  | 
|  | endTestCase := func() { | 
|  | testCaseNum += 1 | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Group 1: Assign to struct field default value. | 
|  | //////////////////////////////////////////////////////////// | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Assign string to int32) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | int32 x = "hello"; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("Illegal assignment") | 
|  | expectError("Field x of type int32 may not be assigned the value \"hello\" of type string.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Assign int32 to string) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | string? x = 42; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("Illegal assignment") | 
|  | expectError("Field x of type string? may not be assigned the value 42 of type int8.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Assign negative number to unit8) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | uint8 x = -1; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("Illegal assignment") | 
|  | expectError("Field x of type uint8 may not be assigned the value -1 of type int8.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Assign large integer to unit8) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | uint8 x = 9999999999; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("Illegal assignment") | 
|  | expectError("Field x of type uint8 may not be assigned the value 9999999999 of type int64.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Assign large float to float32) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | float x = 3.14159E40; | 
|  | }; | 
|  | ` | 
|  | expectError("Illegal assignment") | 
|  | expectError("Field x of type float may not be assigned the value 3.14159e+40 of type double.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Assign default keyword to string) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | string x = default; | 
|  | }; | 
|  |  | 
|  | ` | 
|  | expectError("Illegal assignment") | 
|  | expectError("The 'default' keyword may not be used with the field x of type string") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Assign integer to array field) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | }; | 
|  |  | 
|  | struct Bar { | 
|  | array<Foo?, 8>? x = 7; | 
|  | }; | 
|  | ` | 
|  | expectError("Illegal assignment") | 
|  | expectError("Field x of type array<Foo?, 8>? may not be assigned the value 7 of type int8.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Assign default keyword to map field) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | }; | 
|  |  | 
|  | struct Bar { | 
|  | map<bool, Foo?>? x = default; | 
|  | }; | 
|  | ` | 
|  | expectError("Illegal assignment") | 
|  | expectError("The 'default' keyword may not be used with the field x of type map<bool, Foo?>?.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Group 2: Assign to constant. | 
|  | //////////////////////////////////////////////////////////// | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Assign boolean to int32) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | const int32 Foo = true; | 
|  | ` | 
|  | expectError("Illegal assignment") | 
|  | expectError("Constant Foo of type int32 may not be assigned the value true of type bool.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (Assign string to bool) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | const bool Foo = "true"; | 
|  | ` | 
|  | expectError("Illegal assignment") | 
|  | expectError("Constant Foo of type bool may not be assigned the value \"true\" of type string.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Execute all of the test cases. | 
|  | //////////////////////////////////////////////////////////// | 
|  | for i, c := range cases { | 
|  | descriptor := mojom.NewMojomDescriptor() | 
|  | parser := MakeParser(c.fileName, c.fileName, c.mojomContents, descriptor, nil) | 
|  | parser.Parse() | 
|  | if parser.OK() { | 
|  | t.Errorf("Parsing was supposed to fail but did not for test case %d", i) | 
|  | } else { | 
|  | got := parser.GetError().Error() | 
|  | for _, expected := range c.expectedErrors { | 
|  | if !strings.Contains(got, expected) { | 
|  | t.Errorf("%s:\n*****expected to contain:\n%s\n****actual\n%s", c.fileName, expected, got) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // TestLexerErrors contains a series of test cases in which we | 
|  | // run the parser on invalid mojom input string and compare the resulting | 
|  | // error message to an expected one. The particular type of error we are testing | 
|  | // here are cases in which the lexer detects an error and returns one of | 
|  | // its error tokens. | 
|  | func TestLexerErrors(t *testing.T) { | 
|  | type testCase struct { | 
|  | fileName       string | 
|  | mojomContents  string | 
|  | expectedErrors []string | 
|  | } | 
|  | cases := make([]testCase, 0) | 
|  | testCaseNum := 0 | 
|  |  | 
|  | startTestCase := func(moduleNameSpace string) { | 
|  | fileName := fmt.Sprintf("file%d", testCaseNum) | 
|  | cases = append(cases, testCase{fileName: fileName}) | 
|  | } | 
|  |  | 
|  | expectError := func(expectedError string) { | 
|  | cases[testCaseNum].expectedErrors = append(cases[testCaseNum].expectedErrors, expectedError) | 
|  | } | 
|  |  | 
|  | endTestCase := func() { | 
|  | testCaseNum += 1 | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Group 1: Unterminated comment | 
|  | //////////////////////////////////////////////////////////// | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case: Unterminated comment at start of file. | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | /* | 
|  | * The woods are lovely | 
|  | * dark and deep | 
|  | * but I have promises to keep. | 
|  | struct Foo { | 
|  | int32 x = "hello"; | 
|  | }; | 
|  | ` | 
|  | expectError("Error") | 
|  | expectError("unterminated comment") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case: Unterminated comment at end of file. | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | int32 x ; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * The woods are lovely | 
|  | * dark and deep | 
|  | * but I have promises to keep. | 
|  | ` | 
|  | expectError("Error") | 
|  | expectError("unterminated comment") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case: Unterminated comment in the middle. | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | int32 x ; | 
|  | /* | 
|  | * The woods are lovely | 
|  | * dark and deep | 
|  | * but I have promises to keep. | 
|  | };` | 
|  | expectError("Error") | 
|  | expectError("unterminated comment") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Group 2: Unterminated string literal | 
|  | //////////////////////////////////////////////////////////// | 
|  |  | 
|  | /// //////////////////////////////////////////////////////////// | 
|  | // Test Case: Unterminated string literal in import. | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | import "foo.bar | 
|  | struct Foo { | 
|  | int32 x = 42; | 
|  | }; | 
|  | ` | 
|  | expectError("Error") | 
|  | expectError("unterminated string literal") | 
|  | endTestCase() | 
|  |  | 
|  | /// //////////////////////////////////////////////////////////// | 
|  | // Test Case: Unterminated string literal in assignment. | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | import "foo.bar"; | 
|  | struct Foo { | 
|  | string x = "hello; | 
|  | }; | 
|  | ` | 
|  | expectError("Error") | 
|  | expectError("unterminated string literal") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Group 3: ErrorIllegalChar | 
|  | //////////////////////////////////////////////////////////// | 
|  |  | 
|  | /// //////////////////////////////////////////////////////////// | 
|  | // Test Case: ErrorIllegalChar at the beginning of  a file. | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | /? What the ?/ | 
|  | import "foo.bar" | 
|  | struct Foo { | 
|  | int32 x = 42; | 
|  | }; | 
|  | ` | 
|  | expectError("Error:") | 
|  | expectError("Unexpected \"/\"") | 
|  | endTestCase() | 
|  |  | 
|  | /// //////////////////////////////////////////////////////////// | 
|  | // Test Case: ErrorIllegalChar in the middle. | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | import "foo.bar"; | 
|  | struct Foo { | 
|  | int32 x = %42; | 
|  | }; | 
|  | ` | 
|  | expectError("Error:") | 
|  | expectError("Unexpected \"%\"") | 
|  | endTestCase() | 
|  |  | 
|  | /// //////////////////////////////////////////////////////////// | 
|  | // Test Case: ErrorIllegalChar at the end | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | import "foo.bar"; | 
|  | struct Foo { | 
|  | int32 x = 42; | 
|  | }; | 
|  | * | 
|  | ` | 
|  | expectError("Error:") | 
|  | expectError("Unexpected \"*\"") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Execute all of the test cases. | 
|  | //////////////////////////////////////////////////////////// | 
|  | for i, c := range cases { | 
|  | descriptor := mojom.NewMojomDescriptor() | 
|  | parser := MakeParser(c.fileName, c.fileName, c.mojomContents, descriptor, nil) | 
|  | parser.Parse() | 
|  | if parser.OK() { | 
|  | t.Errorf("Parsing was supposed to fail but did not for test case %d", i) | 
|  | } else { | 
|  | got := parser.GetError().Error() | 
|  | for _, expected := range c.expectedErrors { | 
|  | if !strings.Contains(got, expected) { | 
|  | t.Errorf("%s:\n*****expected to contain:\n%s\n****actual\n%s", c.fileName, expected, got) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDuplicateNameErrorsSingleFile(t *testing.T) { | 
|  | type testCase struct { | 
|  | fileName       string | 
|  | mojomContents  string | 
|  | expectedErrors []string | 
|  | } | 
|  | cases := make([]testCase, 0) | 
|  | testCaseNum := 0 | 
|  |  | 
|  | startTestCase := func(moduleNameSpace string) { | 
|  | fileName := fmt.Sprintf("file%d", testCaseNum) | 
|  | cases = append(cases, testCase{fileName: fileName}) | 
|  | } | 
|  |  | 
|  | expectError := func(expectedError string) { | 
|  | cases[testCaseNum].expectedErrors = append(cases[testCaseNum].expectedErrors, expectedError) | 
|  | } | 
|  |  | 
|  | fileName := func() string { | 
|  | return cases[testCaseNum].fileName | 
|  | } | 
|  |  | 
|  | endTestCase := func() { | 
|  | testCaseNum += 1 | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case: Duplicate struct field name. | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct Foo { | 
|  | int32 x = 3; | 
|  | string y = "hello"; | 
|  | float x = 1.7; | 
|  | }; | 
|  | ` | 
|  | expectError("Error") | 
|  | expectError("Duplicate definition of 'x'.") | 
|  | expectError("There is already a field with that name in struct Foo.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case: Duplicate union field name. | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | union Foo { | 
|  | int32 x; | 
|  | string y; | 
|  | float x ; | 
|  | }; | 
|  | ` | 
|  | expectError("Error") | 
|  | expectError("Duplicate definition of 'x'.") | 
|  | expectError("There is already a field with that name in union Foo.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case: Duplicate method request parameter name. | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | interface Foo { | 
|  | DoIt(int32 x, string y, float x); | 
|  | }; | 
|  | ` | 
|  | expectError("Error") | 
|  | expectError("Duplicate definition of 'x'.") | 
|  | expectError("There is already a request parameter with that name in method DoIt.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case: Duplicate method response parameter name. | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | interface Foo { | 
|  | DoIt() => (int32 x, string y, float x); | 
|  | }; | 
|  | ` | 
|  | expectError("Error") | 
|  | expectError("Duplicate definition of 'x'.") | 
|  | expectError("There is already a response parameter with that name in method DoIt.") | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (duplicate method names) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | interface MyInterface { | 
|  | MethodA(); | 
|  | MethodB(); | 
|  | MethodC(); | 
|  | MethodB(); | 
|  | MethodD(); | 
|  | }; | 
|  | ` | 
|  | expectError("Duplicate definition for \"MethodB\". Previous definition with the same fully-qualified name:") | 
|  | expectError("method MyInterface.MethodB at " + fileName()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (A method and an enum with the same name) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | interface MyInterface { | 
|  | Foo(); | 
|  | Bar(); | 
|  | enum Foo{ | 
|  | PLAID = 1, | 
|  | CHECKERED = 2 | 
|  | }; | 
|  | }; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Foo\". Previous definition with the same fully-qualified name:") | 
|  | expectError("method MyInterface.Foo at " + fileName()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (An enum and a method with the same name) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | interface MyInterface { | 
|  | Bar(); | 
|  | enum Foo{ | 
|  | PLAID = 1, | 
|  | CHECKERED = 2 | 
|  | }; | 
|  | Foo(); | 
|  | }; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Foo\". Previous definition with the same fully-qualified name:") | 
|  | expectError("enum MyInterface.Foo at " + fileName()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (A method and a constant with the same name) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | interface MyInterface { | 
|  | Foo(); | 
|  | Bar(); | 
|  | const int32 Foo = 7; | 
|  | }; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Foo\". Previous definition with the same fully-qualified name:") | 
|  | expectError("method MyInterface.Foo at " + fileName()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (A constant and a method with the same name) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | interface MyInterface { | 
|  | const int32 Foo = 7; | 
|  | Foo(); | 
|  | Bar(); | 
|  | }; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Foo\". Previous definition with the same fully-qualified name:") | 
|  | expectError("const MyInterface.Foo at " + fileName()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (A constant and a field with the same name) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct MyStruct { | 
|  | const int32 Bar = 7; | 
|  | string Foo; | 
|  | int32 Bar; | 
|  | }; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Bar\". Previous definition with the same fully-qualified name:") | 
|  | expectError("const MyStruct.Bar at " + fileName()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (A field and a constant with the same name) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | struct MyStruct { | 
|  | string Foo; | 
|  | int32 Bar; | 
|  | const int32 Bar = 7; | 
|  | }; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Bar\". Previous definition with the same fully-qualified name:") | 
|  | expectError("field MyStruct.Bar at " + fileName()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (two types with the same name in file scope) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | module a.b.c; | 
|  |  | 
|  | interface Foo { | 
|  | }; | 
|  |  | 
|  | struct Bar { | 
|  | }; | 
|  |  | 
|  | struct Foo { | 
|  | }; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Foo\". Previous definition with the same fully-qualified name:") | 
|  | expectError("interface a.b.c.Foo at " + fileName()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (two values with the same name in file scope) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | module a.b.c; | 
|  |  | 
|  | const int32 NUM_HATS = 6; | 
|  | const string NUM_HATS = "6"; | 
|  | ` | 
|  | expectError("Duplicate definition for \"NUM_HATS\". Previous definition with the same fully-qualified name:") | 
|  | expectError("const a.b.c.NUM_HATS at " + fileName()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (a value with the same name as a type at file scope) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | module a.b.c; | 
|  |  | 
|  | union Foo { | 
|  | }; | 
|  |  | 
|  | const int32 Foo = 42; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Foo\". Previous definition with the same fully-qualified name:") | 
|  | expectError("union a.b.c.Foo at " + fileName()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (a type with the same name as a value) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase("") | 
|  | cases[testCaseNum].mojomContents = ` | 
|  | module a.b.c; | 
|  |  | 
|  | const int32 Foo = 42; | 
|  |  | 
|  | union Foo { | 
|  | }; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Foo\". Previous definition with the same fully-qualified name:") | 
|  | expectError("const a.b.c.Foo at " + fileName()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Execute all of the test cases. | 
|  | //////////////////////////////////////////////////////////// | 
|  | for i, c := range cases { | 
|  | descriptor := mojom.NewMojomDescriptor() | 
|  | parser := MakeParser(c.fileName, c.fileName, c.mojomContents, descriptor, nil) | 
|  | parser.Parse() | 
|  | if parser.OK() { | 
|  | t.Errorf("Parsing was supposed to fail but did not for test case %d", i) | 
|  | } else { | 
|  | got := parser.GetError().Error() | 
|  | for _, expected := range c.expectedErrors { | 
|  | if !strings.Contains(got, expected) { | 
|  | t.Errorf("%s:\n*****expected to contain:\n%s\n****actual\n%s", c.fileName, expected, got) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestDuplicateNameErrorsTwoFiles(t *testing.T) { | 
|  | type testFile struct { | 
|  | fileName      string | 
|  | mojomContents string | 
|  | } | 
|  |  | 
|  | type testCase struct { | 
|  | file1, file2   testFile | 
|  | expectedErrors []string | 
|  | } | 
|  | cases := make([]testCase, 0) | 
|  | testCaseNum := 0 | 
|  |  | 
|  | startTestCase := func() { | 
|  | fileNameA := fmt.Sprintf("file%dA", testCaseNum) | 
|  | fileNameB := fmt.Sprintf("file%dB", testCaseNum) | 
|  | cases = append(cases, testCase{ | 
|  | file1: testFile{fileName: fileNameA}, | 
|  | file2: testFile{fileName: fileNameB}}) | 
|  | } | 
|  |  | 
|  | expectError := func(expectedError string) { | 
|  | cases[testCaseNum].expectedErrors = append(cases[testCaseNum].expectedErrors, expectedError) | 
|  | } | 
|  |  | 
|  | fileName1 := func() string { | 
|  | return cases[testCaseNum].file1.fileName | 
|  | } | 
|  |  | 
|  | endTestCase := func() { | 
|  | testCaseNum += 1 | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (two types with the same name in different scopes) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase() | 
|  | cases[testCaseNum].file1.mojomContents = ` | 
|  | module a.b.c; | 
|  |  | 
|  | struct Foo { | 
|  | }; | 
|  | ` | 
|  |  | 
|  | cases[testCaseNum].file2.mojomContents = ` | 
|  | module a.b; | 
|  |  | 
|  | struct c { | 
|  | enum Foo{}; | 
|  | }; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Foo\". Previous definition with the same fully-qualified name:") | 
|  | expectError("struct a.b.c.Foo at " + fileName1()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (two vales with the same name in different scopes) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase() | 
|  | cases[testCaseNum].file1.mojomContents = ` | 
|  | module a.b.c; | 
|  |  | 
|  | enum Hats { | 
|  | COWBOY = 1, | 
|  | TOP | 
|  | }; | 
|  | ` | 
|  |  | 
|  | cases[testCaseNum].file2.mojomContents = ` | 
|  | module a.b.c.Hats; | 
|  |  | 
|  | const double TOP = 4.9; | 
|  | ` | 
|  | expectError("Duplicate definition for \"TOP\". Previous definition with the same fully-qualified name:") | 
|  | expectError("enum value a.b.c.Hats.TOP at " + fileName1()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (a value with the same name as a type in a different scope) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase() | 
|  | cases[testCaseNum].file1.mojomContents = ` | 
|  | module a.b.c; | 
|  |  | 
|  | interface Hats{}; | 
|  | ` | 
|  |  | 
|  | cases[testCaseNum].file2.mojomContents = ` | 
|  | module a.b.c; | 
|  |  | 
|  | const double Hats = 4.9; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Hats\". Previous definition with the same fully-qualified name:") | 
|  | expectError("interface a.b.c.Hats at " + fileName1()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (another value with the same name as a type in a different scope) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase() | 
|  | cases[testCaseNum].file1.mojomContents = ` | 
|  | module a.b.c.Hats; | 
|  |  | 
|  | interface COWBOY{}; | 
|  | ` | 
|  |  | 
|  | cases[testCaseNum].file2.mojomContents = ` | 
|  | module a.b.c; | 
|  |  | 
|  | enum Hats { | 
|  | COWBOY = 1, | 
|  | TOP | 
|  | }; | 
|  | ` | 
|  | expectError("Duplicate definition for \"COWBOY\". Previous definition with the same fully-qualified name:") | 
|  | expectError("interface a.b.c.Hats.COWBOY at " + fileName1()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (a type with the same name as a value in a different scope) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase() | 
|  | cases[testCaseNum].file1.mojomContents = ` | 
|  | module a.b.c; | 
|  |  | 
|  | enum Hats { | 
|  | COWBOY = 1, | 
|  | TOP | 
|  | }; | 
|  | ` | 
|  |  | 
|  | cases[testCaseNum].file2.mojomContents = ` | 
|  | module a.b.c.Hats; | 
|  |  | 
|  | interface COWBOY{}; | 
|  | ` | 
|  | expectError("Duplicate definition for \"COWBOY\". Previous definition with the same fully-qualified name:") | 
|  | expectError("enum value a.b.c.Hats.COWBOY at " + fileName1()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Test Case (a value with the same name as a method in a different scope) | 
|  | //////////////////////////////////////////////////////////// | 
|  | startTestCase() | 
|  | cases[testCaseNum].file1.mojomContents = ` | 
|  | module a.b; | 
|  |  | 
|  | interface Big { | 
|  | Run(); | 
|  | }; | 
|  | ` | 
|  |  | 
|  | cases[testCaseNum].file2.mojomContents = ` | 
|  | module a.b.Big; | 
|  |  | 
|  | const int32 Run = 0; | 
|  | ` | 
|  | expectError("Duplicate definition for \"Run\". Previous definition with the same fully-qualified name:") | 
|  | expectError("method a.b.Big.Run at " + fileName1()) | 
|  | endTestCase() | 
|  |  | 
|  | //////////////////////////////////////////////////////////// | 
|  | // Execute all of the test cases. | 
|  | //////////////////////////////////////////////////////////// | 
|  | for i, c := range cases { | 
|  | descriptor := mojom.NewMojomDescriptor() | 
|  | parser := MakeParser(c.file1.fileName, c.file1.fileName, c.file1.mojomContents, descriptor, nil) | 
|  | parser.Parse() | 
|  | if !parser.OK() { | 
|  | t.Errorf("Parsing was supposed to succeed for file1 but did not for test case %d: %s", i, parser.GetError().Error()) | 
|  | } | 
|  | parser = MakeParser(c.file2.fileName, c.file2.fileName, c.file2.mojomContents, descriptor, nil) | 
|  | parser.Parse() | 
|  | if parser.OK() { | 
|  | t.Errorf("Parsing was supposed to fail for file2 but did not for test case %d", i) | 
|  | } else { | 
|  | got := parser.GetError().Error() | 
|  | for _, expected := range c.expectedErrors { | 
|  | if !strings.Contains(got, expected) { | 
|  | t.Errorf("%s:\n*****expected to contain:\n%s\n****actual\n%s", c.file2.fileName, expected, got) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // TestLexicalOrdering tests that the DeclaredObjects fields of the | 
|  | // components of the mojom file are in order of occurrence in the source. | 
|  | func TestLexicalOrdering(t *testing.T) { | 
|  | source := ` | 
|  | [Key1="SomeModule", | 
|  | Key2=10] | 
|  | module hello.world; | 
|  |  | 
|  | import "import1"; | 
|  | import "import2"; | 
|  |  | 
|  | interface InterfaceFoo { | 
|  | Method1(); | 
|  | enum InnerEnum { }; | 
|  | Method2(); | 
|  | const int8 inner_const = 10; | 
|  | Method3(); | 
|  | }; | 
|  |  | 
|  | struct StructFoo { | 
|  | int8 field1; | 
|  | enum InnerEnum { }; | 
|  | int8 field2; | 
|  | const int8 inner_const = 10; | 
|  | int8 field3; | 
|  | }; | 
|  |  | 
|  | union UnionFoo { | 
|  | int8 field1; | 
|  | int8 field2; | 
|  | }; | 
|  |  | 
|  | enum EnumFoo { | 
|  | VALUE1, | 
|  | VALUE2, | 
|  | }; | 
|  |  | 
|  | const int8 const_foo = 10; | 
|  | ` | 
|  |  | 
|  | descriptor := mojom.NewMojomDescriptor() | 
|  | parser := MakeParser("filename", "filename", source, descriptor, nil) | 
|  | parser.Parse() | 
|  |  | 
|  | if !parser.OK() { | 
|  | t.Errorf("Parser was not supposed to fail: %v", parser.GetError().Error()) | 
|  | } | 
|  |  | 
|  | checkEq := func(expected, actual interface{}) { | 
|  | if expected != actual { | 
|  | t.Fatalf("Failed check: Expected (%v), Actual (%v)", expected, actual) | 
|  | } | 
|  | } | 
|  |  | 
|  | mojomFile := parser.GetMojomFile() | 
|  |  | 
|  | checkEq("Key1", mojomFile.Attributes.List[0].Key) | 
|  | checkEq("Key1", mojomFile.Attributes.List[0].KeyToken.Text) | 
|  | checkEq("Key2", mojomFile.Attributes.List[1].Key) | 
|  | checkEq("Key2", mojomFile.Attributes.List[1].KeyToken.Text) | 
|  |  | 
|  | checkEq("import1", mojomFile.Imports[0].SpecifiedName) | 
|  | checkEq("import2", mojomFile.Imports[1].SpecifiedName) | 
|  |  | 
|  | mojomInterface := mojomFile.DeclaredObjects[0].(*mojom.MojomInterface) | 
|  | checkEq("InterfaceFoo", mojomInterface.SimpleName()) | 
|  | checkEq("Method1", mojomInterface.DeclaredObjects[0].(*mojom.MojomMethod).SimpleName()) | 
|  | checkEq("InnerEnum", mojomInterface.DeclaredObjects[1].(*mojom.MojomEnum).SimpleName()) | 
|  | checkEq("Method2", mojomInterface.DeclaredObjects[2].(*mojom.MojomMethod).SimpleName()) | 
|  | checkEq("inner_const", mojomInterface.DeclaredObjects[3].(*mojom.UserDefinedConstant).SimpleName()) | 
|  | checkEq("Method3", mojomInterface.DeclaredObjects[4].(*mojom.MojomMethod).SimpleName()) | 
|  |  | 
|  | mojomStruct := mojomFile.DeclaredObjects[1].(*mojom.MojomStruct) | 
|  | checkEq("StructFoo", mojomStruct.SimpleName()) | 
|  | checkEq("field1", mojomStruct.DeclaredObjects[0].(*mojom.StructField).SimpleName()) | 
|  | checkEq("InnerEnum", mojomStruct.DeclaredObjects[1].(*mojom.MojomEnum).SimpleName()) | 
|  | checkEq("field2", mojomStruct.DeclaredObjects[2].(*mojom.StructField).SimpleName()) | 
|  | checkEq("inner_const", mojomStruct.DeclaredObjects[3].(*mojom.UserDefinedConstant).SimpleName()) | 
|  | checkEq("field3", mojomStruct.DeclaredObjects[4].(*mojom.StructField).SimpleName()) | 
|  |  | 
|  | mojomUnion := mojomFile.DeclaredObjects[2].(*mojom.MojomUnion) | 
|  | checkEq("UnionFoo", mojomUnion.SimpleName()) | 
|  | checkEq("field1", mojomUnion.DeclaredObjects[0].(*mojom.UnionField).SimpleName()) | 
|  | checkEq("field2", mojomUnion.DeclaredObjects[1].(*mojom.UnionField).SimpleName()) | 
|  |  | 
|  | mojomEnum := mojomFile.DeclaredObjects[3].(*mojom.MojomEnum) | 
|  | checkEq("EnumFoo", mojomEnum.SimpleName()) | 
|  | checkEq("VALUE1", mojomEnum.DeclaredObjects[0].(*mojom.EnumValue).SimpleName()) | 
|  | checkEq("VALUE2", mojomEnum.DeclaredObjects[1].(*mojom.EnumValue).SimpleName()) | 
|  |  | 
|  | checkEq("const_foo", mojomFile.DeclaredObjects[4].(*mojom.UserDefinedConstant).SimpleName()) | 
|  | } |