| Index: mojom/mojom_parser/parser/computed_data_test.go
|
| diff --git a/mojom/mojom_parser/parser/computed_data_test.go b/mojom/mojom_parser/parser/computed_data_test.go
|
| index 2f4bb1ff8ce3521b880b0298c0a557679d4bf84a..c00e12a8bee7e20034b4e9630f790bbf3abdb4e8 100644
|
| --- a/mojom/mojom_parser/parser/computed_data_test.go
|
| +++ b/mojom/mojom_parser/parser/computed_data_test.go
|
| @@ -5,6 +5,7 @@
|
| package parser
|
|
|
| import (
|
| + "fmt"
|
| "mojom/mojom_parser/mojom"
|
| "strings"
|
| "testing"
|
| @@ -198,3 +199,380 @@ func TestMinVersionErrors(t *testing.T) {
|
|
|
| }
|
| }
|
| +
|
| +func checkStructVersion(description string, structVersion *mojom.StructVersion,
|
| + expectedVersionNumber, expectedNumFields, expectedNumBytes uint32) error {
|
| + if structVersion.VersionNumber != expectedVersionNumber {
|
| + return fmt.Errorf("%s: VersionNumber %d != %d", description, structVersion.VersionNumber, expectedVersionNumber)
|
| + }
|
| + if structVersion.NumFields != expectedNumFields {
|
| + return fmt.Errorf("%s: for version %d: NumFields= %d != %d", description,
|
| + structVersion.VersionNumber, structVersion.NumFields, expectedNumFields)
|
| + }
|
| + if structVersion.NumBytes != expectedNumBytes {
|
| + return fmt.Errorf("%s: for version %d: NumBytes=%d != %d", description,
|
| + structVersion.VersionNumber, structVersion.NumBytes, expectedNumBytes)
|
| + }
|
| + return nil
|
| +}
|
| +
|
| +func checkStructFieldOffsets(description string, mojomStruct *mojom.MojomStruct,
|
| + expectedOrdinal, expectedOffset []uint32) error {
|
| + if len(mojomStruct.FieldsInOrdinalOrder()) != len(expectedOrdinal) {
|
| + return fmt.Errorf("%s: len(FieldsInOrdinalOrder())=%d != %d", description,
|
| + len(mojomStruct.FieldsInOrdinalOrder()), len(expectedOrdinal))
|
| + }
|
| + for i, field := range mojomStruct.FieldsInLexicalOrder {
|
| + if field != mojomStruct.FieldsInOrdinalOrder()[expectedOrdinal[i]] {
|
| + return fmt.Errorf("%s: i=%d wrong ordinal", description, i)
|
| + }
|
| + if field.Offset() != expectedOffset[i] {
|
| + return fmt.Errorf("%s: i=%d wrong offset %d != %d", description, i,
|
| + field.Offset(), expectedOffset[i])
|
| + }
|
| + }
|
| + return nil
|
| +}
|
| +
|
| +// TestStructsComputedData() iterates through a series of test cases.
|
| +// For each case we expect for parsing, resolution and final data computation to succeed.
|
| +// Then we execute a given callback test function to test that the functions
|
| +// computeFieldOffsets and computeVersionData produced the desired result.
|
| +func TestStructsComputedData(t *testing.T) {
|
| + test := singleFileSuccessTest{}
|
| +
|
| + ////////////////////////////////////////////////////////////
|
| + // Test Case: Test computeVersionInfo empty struct
|
| + // Tests that computerVersionInfo never produces an empty
|
| + // list of versions, even for empty structs.
|
| + ////////////////////////////////////////////////////////////
|
| + {
|
| + contents := `
|
| + struct MyStruct {
|
| + };`
|
| +
|
| + testFunc := func(descriptor *mojom.MojomDescriptor) error {
|
| + myStructType := descriptor.TypesByKey["TYPE_KEY:MyStruct"].(*mojom.MojomStruct)
|
| + if len(myStructType.FieldsInOrdinalOrder()) != 0 {
|
| + return fmt.Errorf("len(myStructType.FieldsInOrdinalOrder())=%d", len(myStructType.FieldsInOrdinalOrder()))
|
| + }
|
| + if len(myStructType.VersionInfo()) != 1 {
|
| + return fmt.Errorf("len(myStructType.VersionInfo() = %d", len(myStructType.VersionInfo()))
|
| + }
|
| + if err := checkStructVersion("EmptyStruct", &myStructType.VersionInfo()[0], 0, 0, 8); err != nil {
|
| + return err
|
| + }
|
| + return nil
|
| + }
|
| + test.addTestCase("", contents, testFunc)
|
| + }
|
| +
|
| + ////////////////////////////////////////////////////////////
|
| + // Test Case: Test One field
|
| + ////////////////////////////////////////////////////////////
|
| + {
|
| + contents := `
|
| + struct MyStruct {
|
| + int8 x;
|
| + };`
|
| +
|
| + testFunc := func(descriptor *mojom.MojomDescriptor) error {
|
| + myStructType := descriptor.TypesByKey["TYPE_KEY:MyStruct"].(*mojom.MojomStruct)
|
| + if err := checkStructFieldOffsets("OneField", myStructType, []uint32{0}, []uint32{0}); err != nil {
|
| + return err
|
| + }
|
| + if err := checkStructVersion("OneField", &myStructType.VersionInfo()[0], 0, 1, 16); err != nil {
|
| + return err
|
| + }
|
| + return nil
|
| + }
|
| + test.addTestCase("", contents, testFunc)
|
| + }
|
| +
|
| + ////////////////////////////////////////////////////////////
|
| + // Test Case: Test Padding, In Order
|
| + ////////////////////////////////////////////////////////////
|
| + {
|
| + contents := `
|
| + struct MyStruct {
|
| + int8 x;
|
| + uint8 y;
|
| + int32 z;
|
| + };`
|
| +
|
| + testFunc := func(descriptor *mojom.MojomDescriptor) error {
|
| + myStructType := descriptor.TypesByKey["TYPE_KEY:MyStruct"].(*mojom.MojomStruct)
|
| + if err := checkStructFieldOffsets("InOrder", myStructType, []uint32{0, 1, 2}, []uint32{0, 1, 4}); err != nil {
|
| + return err
|
| + }
|
| + if err := checkStructVersion("In order", &myStructType.VersionInfo()[0], 0, 3, 16); err != nil {
|
| + return err
|
| + }
|
| + return nil
|
| + }
|
| + test.addTestCase("", contents, testFunc)
|
| + }
|
| +
|
| + ////////////////////////////////////////////////////////////
|
| + // Test Case: Test Padding, Out of order
|
| + ////////////////////////////////////////////////////////////
|
| + {
|
| + contents := `
|
| + struct MyStruct {
|
| + int8 x;
|
| + int32 y;
|
| + uint8 z;
|
| + };`
|
| +
|
| + testFunc := func(descriptor *mojom.MojomDescriptor) error {
|
| + myStructType := descriptor.TypesByKey["TYPE_KEY:MyStruct"].(*mojom.MojomStruct)
|
| + if err := checkStructFieldOffsets("OutOfOrder", myStructType, []uint32{0, 1, 2}, []uint32{0, 4, 1}); err != nil {
|
| + return err
|
| + }
|
| + if err := checkStructVersion("OutOfOrder", &myStructType.VersionInfo()[0], 0, 3, 16); err != nil {
|
| + return err
|
| + }
|
| + return nil
|
| + }
|
| + test.addTestCase("", contents, testFunc)
|
| + }
|
| +
|
| + ////////////////////////////////////////////////////////////
|
| + // Test Case: Test Padding, Overflow
|
| + // 2 bytes should be packed together first, followed by short, then by int.
|
| + ////////////////////////////////////////////////////////////
|
| + {
|
| + contents := `
|
| + struct MyStruct {
|
| + int8 f1;
|
| + int32 f2;
|
| + int16 f3;
|
| + int8 f4;
|
| + int8 f5;
|
| + };`
|
| +
|
| + testFunc := func(descriptor *mojom.MojomDescriptor) error {
|
| + myStructType := descriptor.TypesByKey["TYPE_KEY:MyStruct"].(*mojom.MojomStruct)
|
| + if err := checkStructFieldOffsets("Overflow", myStructType, []uint32{0, 1, 2, 3, 4}, []uint32{0, 4, 2, 1, 8}); err != nil {
|
| + return err
|
| + }
|
| + if err := checkStructVersion("Overflow", &myStructType.VersionInfo()[0], 0, 5, 24); err != nil {
|
| + return err
|
| + }
|
| + return nil
|
| + }
|
| + test.addTestCase("", contents, testFunc)
|
| + }
|
| +
|
| + ////////////////////////////////////////////////////////////
|
| + // Test Case: Nullable Types
|
| + ////////////////////////////////////////////////////////////
|
| + {
|
| + contents := `
|
| + interface MyInterface{};
|
| +
|
| + struct MyStruct {
|
| + string? f1;
|
| + handle? f2;
|
| + MyStruct? f3;
|
| + handle<data_pipe_consumer>? f4;
|
| + array<int8>? f5;
|
| + handle<data_pipe_producer>? f6;
|
| + array<int8, 5>? f7;
|
| + handle<message_pipe>? f8;
|
| + MyInterface? f9;
|
| + handle<shared_buffer>? f10;
|
| + MyInterface&? f11;
|
| + };`
|
| +
|
| + testFunc := func(descriptor *mojom.MojomDescriptor) error {
|
| + myStructType := descriptor.TypesByKey["TYPE_KEY:MyStruct"].(*mojom.MojomStruct)
|
| + if err := checkStructFieldOffsets("Nullable Types", myStructType,
|
| + []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
| + []uint32{0, 8, 16, 12, 24, 32, 40, 36, 48, 56, 60}); err != nil {
|
| + return err
|
| + }
|
| + if err := checkStructVersion("Nullable Types", &myStructType.VersionInfo()[0], 0, 11, 72); err != nil {
|
| + return err
|
| + }
|
| + return nil
|
| + }
|
| + test.addTestCase("", contents, testFunc)
|
| + }
|
| +
|
| + ////////////////////////////////////////////////////////////
|
| + // Test Case: All Types
|
| + ////////////////////////////////////////////////////////////
|
| + {
|
| + contents := `
|
| + interface MyStruct2{};
|
| +
|
| + struct MyStruct {
|
| + bool f1;
|
| + int8 f2;
|
| + string f3;
|
| + uint8 f4;
|
| + int16 f5;
|
| + double f6;
|
| + uint16 f7;
|
| + int32 f8;
|
| + uint32 f9;
|
| + int64 f10;
|
| + float f11;
|
| + string f12;
|
| + handle f13;
|
| + uint64 f14;
|
| + MyStruct2 f15;
|
| + array<int32> f16;
|
| + string? f17;
|
| + };`
|
| +
|
| + testFunc := func(descriptor *mojom.MojomDescriptor) error {
|
| + myStructType := descriptor.TypesByKey["TYPE_KEY:MyStruct"].(*mojom.MojomStruct)
|
| + if err := checkStructFieldOffsets("All Types", myStructType,
|
| + []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
|
| + []uint32{0, 1, 8, 2, 4, 16, 6, 24, 28, 32, 40, 48, 44, 56, 64, 72, 80}); err != nil {
|
| + return err
|
| + }
|
| + if err := checkStructVersion("All Types", &myStructType.VersionInfo()[0], 0, 17, 96); err != nil {
|
| + return err
|
| + }
|
| + return nil
|
| + }
|
| + test.addTestCase("", contents, testFunc)
|
| + }
|
| +
|
| + ////////////////////////////////////////////////////////////
|
| + // Test Case: Bools
|
| + ////////////////////////////////////////////////////////////
|
| + {
|
| + contents := `
|
| + interface MyStruct2{};
|
| +
|
| + struct MyStruct {
|
| + bool f1;
|
| + bool f2;
|
| + int32 f3;
|
| + bool f4;
|
| + bool f5;
|
| + bool f6;
|
| + bool f7;
|
| + bool f8;
|
| + bool f9;
|
| + bool f10;
|
| + };`
|
| +
|
| + testFunc := func(descriptor *mojom.MojomDescriptor) error {
|
| + myStructType := descriptor.TypesByKey["TYPE_KEY:MyStruct"].(*mojom.MojomStruct)
|
| + if err := checkStructFieldOffsets("Bools", myStructType,
|
| + []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
|
| + []uint32{0, 0, 4, 0, 0, 0, 0, 0, 0, 1}); err != nil {
|
| + return err
|
| + }
|
| + if err := checkStructVersion("Bools", &myStructType.VersionInfo()[0], 0, 10, 16); err != nil {
|
| + return err
|
| + }
|
| + return nil
|
| + }
|
| + test.addTestCase("", contents, testFunc)
|
| + }
|
| +
|
| + ////////////////////////////////////////////////////////////
|
| + // Test Case: Test computeVersionInfo complex order
|
| + // Tests computerVersionInfo using a struct wose definition order,
|
| + // ordinal order and pack order for fields are all different.
|
| + ////////////////////////////////////////////////////////////
|
| + {
|
| + contents := `
|
| + struct MyStruct {
|
| + [MinVersion = 3]
|
| + bool field3@3;
|
| +
|
| + int32 field_0@0;
|
| +
|
| + [MinVersion = 2]
|
| + int64 field_1@1;
|
| +
|
| + [MinVersion = 3]
|
| + int64 field_2@2;
|
| + };`
|
| +
|
| + testFunc := func(descriptor *mojom.MojomDescriptor) error {
|
| + myStructType := descriptor.TypesByKey["TYPE_KEY:MyStruct"].(*mojom.MojomStruct)
|
| + if err := checkStructFieldOffsets("ComplexOrder", myStructType, []uint32{3, 0, 1, 2}, []uint32{4, 0, 8, 16}); err != nil {
|
| + return err
|
| + }
|
| + if err := checkStructVersion("ComplexOrder", &myStructType.VersionInfo()[0], 0, 1, 16); err != nil {
|
| + return err
|
| + }
|
| + if err := checkStructVersion("ComplexOrder", &myStructType.VersionInfo()[1], 2, 2, 24); err != nil {
|
| + return err
|
| + }
|
| + if err := checkStructVersion("ComplexOrder", &myStructType.VersionInfo()[2], 3, 4, 32); err != nil {
|
| + return err
|
| + }
|
| + return nil
|
| + }
|
| + test.addTestCase("", contents, testFunc)
|
| + }
|
| +
|
| + ////////////////////////////////////////////////////////////
|
| + // Test Case: Test Interface Alignment
|
| + // Tests that interfaces are aligned on 4-byte boundaries,
|
| + // although the size of an interface is 8 bytes.
|
| + ////////////////////////////////////////////////////////////
|
| + {
|
| + contents := `
|
| + interface MyInterface{};
|
| +
|
| + struct MyStruct {
|
| + int32 x;
|
| + MyInterface y;
|
| + };`
|
| +
|
| + testFunc := func(descriptor *mojom.MojomDescriptor) error {
|
| + myStructType := descriptor.TypesByKey["TYPE_KEY:MyStruct"].(*mojom.MojomStruct)
|
| + if err := checkStructFieldOffsets("InterfaceAlignment", myStructType, []uint32{0, 1}, []uint32{0, 4}); err != nil {
|
| + return err
|
| + }
|
| + if err := checkStructVersion("InterfaceAlignment",
|
| + &myStructType.VersionInfo()[0], 0, 2, 24); err != nil {
|
| + return err
|
| + }
|
| + return nil
|
| + }
|
| + test.addTestCase("", contents, testFunc)
|
| + }
|
| +
|
| + ////////////////////////////////////////////////////////////
|
| + // Execute all of the test cases.
|
| + ////////////////////////////////////////////////////////////
|
| + for i, c := range test.cases {
|
| + // Parse and resolve the mojom input.
|
| + descriptor := mojom.NewMojomDescriptor()
|
| + fileName := fmt.Sprintf("file%d", i)
|
| + parser := MakeParser(fileName, fileName, c.mojomContents, descriptor, nil)
|
| + parser.Parse()
|
| + if !parser.OK() {
|
| + t.Errorf("Parsing error for %s: %s", fileName, parser.GetError().Error())
|
| + continue
|
| + }
|
| + err := descriptor.Resolve()
|
| + if err != nil {
|
| + t.Errorf("Resolution failed for test case %d: %s", i, err.Error())
|
| + continue
|
| + }
|
| +
|
| + if err := descriptor.ComputeFinalData(); err != nil {
|
| + t.Errorf("ComputeFinalData error for test case %d: %s", i, err.Error())
|
| + continue
|
| + }
|
| +
|
| + if c.testFunc != nil {
|
| + if err := c.testFunc(descriptor); err != nil {
|
| + t.Errorf("%s:\n%s", fileName, err.Error())
|
| + continue
|
| + }
|
| + }
|
| + }
|
| +}
|
|
|