OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package serialization | |
6 | |
7 import ( | |
8 "fmt" | |
9 "mojo/public/go/bindings" | |
10 "mojom/mojom_parser/generated/mojom_files" | |
11 "mojom/mojom_parser/generated/mojom_types" | |
12 "mojom/mojom_parser/mojom" | |
13 "mojom/mojom_parser/parser" | |
14 "reflect" | |
15 "testing" | |
16 myfmt "third_party/golang/src/fmt" | |
17 ) | |
18 | |
19 // TestSingleFileSerialization uses a series of test cases in which the text of a .mojom | |
20 // file is specified and the expected MojomFileGraph is specified using Go struc t literals. | |
21 func TestSingleFileSerialization(t *testing.T) { | |
22 | |
23 type testCase struct { | |
24 fileName string | |
25 mojomContents string | |
26 lineAndcolumnNumbers bool | |
27 expectedGraph *mojom_files.MojomFileGraph | |
28 } | |
29 cases := make([]testCase, 0) | |
30 testCaseNum := 0 | |
31 var expectedGraph *mojom_files.MojomFileGraph | |
32 var expectedFile *mojom_files.MojomFile | |
33 var fileName string | |
34 | |
35 startTestCase := func(moduleNameSpace string) { | |
mattr
2015/11/10 19:26:49
I found this structure a bit confusing. You could
rudominer
2015/11/10 23:29:36
I have refactored the test to try to make it more
| |
36 fileName = fmt.Sprintf("file%d", testCaseNum) | |
37 expectedGraph = new(mojom_files.MojomFileGraph) | |
38 expectedGraph.Files = make(map[string]mojom_files.MojomFile) | |
39 expectedFile = new(mojom_files.MojomFile) | |
40 expectedFile.FileName = fileName | |
41 expectedFile.ModuleNamespace = new(string) | |
42 *expectedFile.ModuleNamespace = moduleNameSpace | |
43 expectedGraph.ResolvedTypes = make(map[string]mojom_types.UserDe finedType) | |
44 expectedGraph.ResolvedValues = make(map[string]mojom_types.UserD efinedValue) | |
45 // We don't want to bother with line and column numbers which ar e brittle. | |
46 lineAndcolumnNumbers := false | |
47 cases = append(cases, testCase{fileName, "", lineAndcolumnNumber s, expectedGraph}) | |
48 } | |
49 | |
50 endTestCase := func() { | |
51 expectedGraph.Files[fileName] = *expectedFile | |
52 testCaseNum += 1 | |
53 } | |
54 | |
55 newDeclData := func(shortName, fullIdentifier string) *mojom_types.Decla rationData { | |
56 return &mojom_types.DeclarationData{ | |
57 ShortName: newString(shortName), | |
58 FullIdentifier: newString(fullIdentifier), | |
59 DeclaredOrdinal: -1, | |
60 DeclarationOrder: -1, | |
61 SourceFileInfo: &mojom_types.SourceFileInfo{ | |
62 FileName: fileName, | |
63 }} | |
64 } | |
65 | |
66 //////////////////////////////////////////////////////////// | |
67 // Test Case | |
68 //////////////////////////////////////////////////////////// | |
69 startTestCase("mojom.test") | |
70 cases[testCaseNum].mojomContents = ` | |
71 [go_namespace="go.test", | |
72 lucky=true, | |
73 planet=EARTH] | |
74 module mojom.test; | |
75 | |
76 import "another.file"; | |
77 import "and.another.file"; | |
78 | |
79 const uint16 NUM_MAGI = 3; | |
80 | |
81 struct Foo{ | |
82 int32 x; | |
83 string y = "hello"; | |
84 string? z; | |
85 | |
86 enum Hats { | |
87 TOP, | |
88 COWBOY = NUM_MAGI | |
89 }; | |
90 };` | |
91 { | |
92 // Attributes | |
93 expectedFile.Attributes = &[]mojom_types.Attribute{ | |
94 {"go_namespace", "go.test"}, {"lucky", "true"}, {"planet ", "EARTH"}, | |
95 } | |
96 | |
97 // Imports | |
98 expectedFile.Imports = &[]string{ | |
99 "another.file.canonical", "and.another.file.canonical", | |
100 } | |
101 | |
102 // DeclaredMojomObjects | |
103 expectedFile.DeclaredMojomObjects.Structs = &[]string{"ooF.tset. mojom"} | |
104 expectedFile.DeclaredMojomObjects.TopLevelConstants = &[]string{ "IGAM_MUN.tset.mojom"} | |
105 | |
106 // Resolved Values | |
107 | |
108 // NUM_MAGI | |
109 expectedGraph.ResolvedValues["IGAM_MUN.tset.mojom"] = &mojom_typ es.UserDefinedValueDeclaredConstant{mojom_types.DeclaredConstant{ | |
110 DeclData: *newDeclData("NUM_MAGI", "mojom.test.NUM_MAGI" ), | |
111 Type: &mojom_types.TypeSimpleType{mojom_types.Simple Type_UinT16}, | |
112 Value: &mojom_types.ValueLiteralValue{&mojom_types.Li teralValueInt64Value{3}}, | |
113 }} | |
114 | |
115 // Hats.TOP | |
116 expectedGraph.ResolvedValues["POT.staH.ooF.tset.mojom"] = &mojom _types.UserDefinedValueEnumValue{mojom_types.EnumValue{ | |
117 DeclData: newDeclData("TOP", "mojom.test.Foo.Hats.TOP "), | |
118 EnumTypeKey: "staH.ooF.tset.mojom", | |
119 IntValue: -1, | |
120 }} | |
121 | |
122 // Hats.COWBOY | |
123 expectedGraph.ResolvedValues["YOBWOC.staH.ooF.tset.mojom"] = &mo jom_types.UserDefinedValueEnumValue{mojom_types.EnumValue{ | |
124 DeclData: newDeclData("COWBOY", "mojom.test.Foo.Hats. COWBOY"), | |
125 EnumTypeKey: "staH.ooF.tset.mojom", | |
126 IntValue: 3, | |
127 InitializerValue: &mojom_types.ValueUserValueReference{m ojom_types.UserValueReference{ | |
128 Identifier: "NUM_MAGI", | |
129 ValueKey: newString("IGAM_MUN.tset. mojom"), | |
130 ResolvedConcreteValue: &mojom_types.ValueLiteral Value{&mojom_types.LiteralValueInt64Value{3}}, | |
131 }}, | |
132 }} | |
133 | |
134 // ResolvedTypes | |
135 | |
136 // struct Foo | |
137 expectedGraph.ResolvedTypes["ooF.tset.mojom"] = &mojom_types.Use rDefinedTypeStructType{mojom_types.MojomStruct{ | |
138 DeclData: &mojom_types.DeclarationData{ | |
139 ShortName: newString("Foo"), | |
140 FullIdentifier: newString("mojom.test.Foo"), | |
141 DeclaredOrdinal: -1, | |
142 DeclarationOrder: -1, | |
143 SourceFileInfo: &mojom_types.SourceFileInfo{ | |
144 FileName: fileName, | |
145 }, | |
146 ContainedDeclarations: &mojom_types.ContainedDec larations{ | |
147 Enums: &[]string{"staH.ooF.tset.mojom"}} , | |
148 }, | |
149 Fields: []mojom_types.StructField{ | |
150 // field x | |
151 { | |
152 DeclData: newDeclData("x", ""), | |
153 Type: &mojom_types.TypeSimpleType{mo jom_types.SimpleType_InT32}, | |
154 }, | |
155 // field y | |
156 { | |
157 DeclData: newDeclData("y", ""), | |
158 Type: &mojom_types.TypeStringTyp e{mojom_types.StringType{false}}, | |
159 DefaultValue: &mojom_types.DefaultFieldV alueValue{&mojom_types.ValueLiteralValue{&mojom_types.LiteralValueStringValue{"h ello"}}}, | |
160 }, | |
161 // field z | |
162 { | |
163 DeclData: newDeclData("z", ""), | |
164 Type: &mojom_types.TypeStringType{mo jom_types.StringType{true}}, | |
165 }, | |
166 }, | |
167 }} | |
168 | |
169 // enum Hats | |
170 expectedGraph.ResolvedTypes["staH.ooF.tset.mojom"] = &mojom_type s.UserDefinedTypeEnumType{mojom_types.MojomEnum{ | |
171 DeclData: newDeclData("Hats", "mojom.test.Foo.Hats"), | |
172 Values: []mojom_types.EnumValue{ | |
173 // Note(rudominer) It is a bug that we need to c opy the enum values here. | |
174 // See https://github.com/domokit/mojo/issues/51 3. | |
175 // value TOP | |
176 expectedGraph.ResolvedValues["POT.staH.ooF.tset. mojom"].(*mojom_types.UserDefinedValueEnumValue).Value, | |
177 // value COWBOY | |
178 expectedGraph.ResolvedValues["YOBWOC.staH.ooF.ts et.mojom"].(*mojom_types.UserDefinedValueEnumValue).Value, | |
179 }, | |
180 }} | |
181 } | |
182 | |
183 endTestCase() | |
184 | |
185 //////////////////////////////////////////////////////////// | |
186 // Execute all of the test cases. | |
187 //////////////////////////////////////////////////////////// | |
188 for _, c := range cases { | |
189 // Parse and resolve the mojom input. | |
190 descriptor := mojom.NewMojomDescriptor() | |
191 parser := parser.MakeParser(c.fileName, c.mojomContents, descrip tor) | |
192 parser.Parse() | |
193 if !parser.OK() { | |
194 t.Errorf("Parsing error for %s: %s", c.fileName, parser. GetError().Error()) | |
195 continue | |
196 } | |
197 if err := descriptor.Resolve(); err != nil { | |
198 t.Errorf("Resolve error for %s: %s", c.fileName, err.Err or()) | |
199 continue | |
200 } | |
201 if err := descriptor.ComputeEnumValueIntegers(); err != nil { | |
202 t.Errorf("ComputeEnumValueIntegers error for %s: %s", c. fileName, err.Error()) | |
203 continue | |
204 } | |
205 if err := descriptor.ComputeDataForGenerators(); err != nil { | |
206 t.Errorf("ComputeDataForGenerators error for %s: %s", c. fileName, err.Error()) | |
207 continue | |
208 } | |
209 | |
210 // Simulate setting the canonical file name for the imported fil es. In real operation | |
211 // this step is done in parser_driver.go when each of the import ed files are parsed. | |
212 mojomFile := parser.GetMojomFile() | |
213 if mojomFile.Imports != nil { | |
214 for _, imp := range mojomFile.Imports { | |
215 imp.CanonicalFileName = fmt.Sprintf("%s.canonica l", imp.SpecifiedName) | |
216 } | |
217 } | |
218 | |
219 // Serialize | |
220 EmitLineAndColumnNumbers = c.lineAndcolumnNumbers | |
221 bytes, err := Serialize(descriptor) | |
222 if err != nil { | |
223 t.Errorf("Serialization error for %s: %s", c.fileName, e rr.Error()) | |
224 continue | |
225 } | |
226 | |
227 // Deserialize | |
228 decoder := bindings.NewDecoder(bytes, nil) | |
229 fileGraph := mojom_files.MojomFileGraph{} | |
230 fileGraph.Decode(decoder) | |
231 | |
232 // Compare | |
233 if err := compareFileGraphs(c.expectedGraph, &fileGraph); err != nil { | |
234 t.Errorf("%s:\n%s", c.fileName, err.Error()) | |
235 continue | |
236 } | |
237 } | |
238 } | |
239 | |
240 // compareFileGraphs compares |expected| and |actual| and returns a non-nil | |
241 // error if they are not deeply equal. The error message contains a human-readab le | |
242 // string containing a deep-print of expected and actual along with the substrin gs | |
243 // starting from the first character where they differ. | |
244 func compareFileGraphs(expected *mojom_files.MojomFileGraph, actual *mojom_files .MojomFileGraph) error { | |
245 if !reflect.DeepEqual(expected, actual) { | |
246 // Note(rudominer) The myfmt package is a local modification of the fmt package | |
247 // that does a deep printing that follows pointers for up to 50 levels. | |
248 // Thus expectedString and actualString should contain enough in formation to | |
249 // precisely capture the structure of expected and actual. | |
250 expectedString := myfmt.Sprintf("%+v", expected) | |
251 actualString := myfmt.Sprintf("%+v", actual) | |
252 if expectedString != actualString { | |
253 diffPos := -1 | |
254 for i := 0; i < len(expectedString) && i < len(actualStr ing); i++ { | |
255 if expectedString[i] != actualString[i] { | |
256 diffPos = i | |
257 break | |
258 } | |
259 } | |
260 mismatchExpected := "" | |
261 mismatchActual := "" | |
262 if diffPos > -1 { | |
263 mismatchExpected = expectedString[diffPos:] | |
264 mismatchActual = actualString[diffPos:] | |
265 } | |
266 return fmt.Errorf("*****\nexpected=\n*****\n%q\n*****\na ctual=\n*****\n%q\n*****\n"+ | |
267 "match failed at position %d: expected=\n*****\n %s\n******\nactual=\n*****\n%s\n******\n", | |
268 expectedString, actualString, diffPos, mismatchE xpected, mismatchActual) | |
269 } else { | |
270 return fmt.Errorf("expected != actual but the two printe d equal.") | |
271 } | |
272 } | |
273 return nil | |
274 } | |
OLD | NEW |