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) { |
| 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 |