| // Copyright 2018 The Fuchsia 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 fidl_test |
| |
| import ( |
| "fmt" |
| "reflect" |
| "strings" |
| "syscall/zx" |
| "syscall/zx/fidl" |
| "syscall/zx/fidl/internal/bindingstest" |
| "testing" |
| ) |
| |
| var testCtx fidl.MarshalerContext |
| |
| func TestMarshalMessageHeader(t *testing.T) { |
| data := []byte{ |
| 0x12, 0x34, 0x56, 0x78, // txid |
| 0xAB, 0xCD, 0xEF, // flags |
| 0x01, // magic number |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // method ordinal |
| } |
| var header fidl.MessageHeader |
| hnb, _, err := fidl.Unmarshal(data, nil, &header) |
| if err != nil { |
| t.Fatalf("unmarshal failed: %s", err) |
| } |
| if hnb != 16 { |
| t.Fatalf("expected 16 bytes read, was %d", hnb) |
| } |
| if header.Magic != 0x01 { |
| t.Fatalf("expected header txid of 0x01, was %x", header.Magic) |
| } |
| } |
| |
| // TODO(https://fxbug.dev/7832): do we purposefully provide buffers too big in |
| // conformance tests to ensure the returned size is properly calculated? If |
| // not, we should keep this sort of testing, or augment the conformance tests. |
| func TestCheckUnmarshalReadSize(t *testing.T) { |
| examples := [][]byte{ |
| { |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| }, |
| |
| { |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, // these will go unread |
| }, |
| } |
| for _, data := range examples { |
| var message bindingstest.EmptyStruct |
| hnb, _, err := fidl.Unmarshal(data, nil, &message) |
| if err != nil { |
| t.Fatalf("unmarshal failed: %s", err) |
| } |
| if hnb != 8 { |
| t.Fatalf("expected 8 bytes read, was %d", hnb) |
| } |
| } |
| } |
| |
| // TODO(https://fxbug.dev/7832): We are lacking in negative tests in the conformance suite. |
| func TestEnvelopeByteCountTooLarge(t *testing.T) { |
| input := []byte{ |
| 0x21, 0xEB, 0x7E, 0x76, 0x00, 0x00, 0x00, 0x00, // ordinal + padding |
| 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, // byte + handle count |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope present |
| 0xef, 0xbe, 0xad, 0xde, 0x11, 0xba, 0x5e, 0xba, // data |
| } |
| |
| var message bindingstest.XUnion1Struct |
| _, _, err := fidl.Unmarshal(input, nil, &message) |
| if err == nil { |
| t.Fatalf("Unmarshal() returned nil error") |
| } |
| |
| errCode := err.(fidl.ValidationError).Code() |
| if errCode != fidl.ErrPayloadTooSmall { |
| t.Fatalf("Unmarshal() returned %d", errCode) |
| } |
| } |
| |
| // TODO(https://fxbug.dev/7832): We are lacking in negative tests in the conformance suite. |
| func TestEnvelopeHandleCountTooLarge(t *testing.T) { |
| input := []byte{ |
| 0x21, 0xEB, 0x7E, 0x76, 0x00, 0x00, 0x00, 0x00, // ordinal + padding |
| 0x08, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, // byte + invalid handle count |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope present |
| 0xef, 0xbe, 0xad, 0xde, 0x11, 0xba, 0x5e, 0xba, // data |
| } |
| |
| var message bindingstest.XUnion1Struct |
| _, _, err := fidl.Unmarshal(input, nil, &message) |
| if err == nil { |
| t.Fatalf("Unmarshal() returned nil error") |
| } |
| |
| errCode := err.(fidl.ValidationError).Code() |
| if errCode != fidl.ErrTooManyHandles { |
| t.Fatalf("Unmarshal() returned %d", errCode) |
| } |
| } |
| |
| // TODO(https://fxbug.dev/7832): We are lacking in negative tests in the conformance suite. |
| func TestEnvelopeInvalidPresence(t *testing.T) { |
| input := []byte{ |
| 0x21, 0xEB, 0x7E, 0x76, 0x00, 0x00, 0x00, 0x00, // ordinal + padding |
| 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // byte + handle count |
| 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, // invalid envelope presence |
| 0xef, 0xbe, 0xad, 0xde, 0x11, 0xba, 0x5e, 0xba, // data |
| } |
| |
| var message bindingstest.XUnion1Struct |
| _, _, err := fidl.Unmarshal(input, nil, &message) |
| if err == nil { |
| t.Fatalf("Unmarshal() returned nil error") |
| } |
| |
| errCode := err.(fidl.ValidationError).Code() |
| if errCode != fidl.ErrBadRefEncoding { |
| t.Fatalf("Unmarshal() returned %d", errCode) |
| } |
| } |
| |
| type example struct { |
| name string |
| input fidl.Message |
| expectSize int |
| } |
| |
| // general provides test cases used to verify correctness, and |
| // benchmark against. |
| // |
| // Keep these as a slice to preserve consistent ordering when running. |
| func general() []example { |
| vmo, err := zx.NewVMO(10, 0) |
| if err != nil { |
| panic(fmt.Sprintf("failed to create vmo: %v", err)) |
| } |
| defer vmo.Close() |
| |
| h0, h1, err := zx.NewChannel(0) |
| defer h0.Close() |
| defer h1.Close() |
| if err != nil { |
| panic(fmt.Sprintf("failed to create vmo: %v", err)) |
| } |
| |
| st1 := bindingstest.SimpleTable{} |
| st1.SetX(42) |
| st1.SetY(67) |
| |
| return []example{ |
| // TODO(https://fxbug.dev/7832): We lack coverage of floats in the conformance test suite. |
| {"float1", &bindingstest.TestFloat1{A: -36.0}, 8}, |
| {"float2", &bindingstest.TestFloat2{A: -1254918271.0}, 8}, |
| {"float3", &bindingstest.TestFloat3{A: 1241.1, B: 0.2141, C: 20, D: 0.0}, 32}, |
| |
| // TODO(https://fxbug.dev/7832): We just recently added handles in conformance suite. Are these covered? |
| {"handle1", &bindingstest.TestHandle1{ |
| A: zx.Handle(22), |
| B: zx.HandleInvalid, |
| C: vmo, |
| D: zx.VMO(zx.HandleInvalid), |
| }, 16}, |
| {"handle2", &bindingstest.TestHandle2{ |
| A: []zx.Handle{zx.Handle(vmo)}, |
| B: []zx.VMO{zx.VMO(zx.HandleInvalid)}, |
| }, 48}, |
| |
| // TODO(https://fxbug.dev/7832): Here we're checking the special logic adapting channels to |
| // `request<P>` or `P` representations. This is not supported by GIDL yet. |
| {"interface1", &bindingstest.TestInterface1{ |
| A: bindingstest.Test1WithCtxInterface(fidl.ChannelProxy{Channel: h0}), |
| B: bindingstest.Test1WithCtxInterface(fidl.ChannelProxy{Channel: zx.Channel(zx.HandleInvalid)}), |
| C: bindingstest.Test1WithCtxInterfaceRequest(fidl.InterfaceRequest{Channel: h1}), |
| D: bindingstest.Test1WithCtxInterfaceRequest(fidl.InterfaceRequest{ |
| Channel: zx.Channel(zx.HandleInvalid), |
| }), |
| }, 16}, |
| } |
| } |
| |
| func check(t *testing.T, input fidl.Message, expectSize int) { |
| t.Helper() |
| defer func() { |
| if r := recover(); r != nil { |
| // When running tests on device, this bubbles up the error |
| // on the console launching the tests, rather than having |
| // to look at the device's kernel logs. |
| t.Fatalf("panic: %s", r) |
| panic(r) |
| } |
| }() |
| var respb [zx.ChannelMaxMessageBytes]byte |
| var resphd [zx.ChannelMaxMessageHandles]zx.HandleDisposition |
| nb, nh, err := fidl.MarshalWithContext(testCtx, input, respb[:], resphd[:]) |
| if err != nil { |
| t.Fatalf("marshal: failed: %s", err) |
| } |
| if nb != expectSize { |
| t.Fatalf("marshal: expected size %d but got %d: %v", expectSize, nb, respb[:nb]) |
| } |
| var resphi [zx.ChannelMaxMessageHandles]zx.HandleInfo |
| for i := 0; i < nh; i++ { |
| resphi[i] = zx.HandleInfo{ |
| Handle: resphd[i].Handle, |
| Type: resphd[i].Type, |
| Rights: resphd[i].Rights, |
| } |
| } |
| output := makeDefault(reflect.TypeOf(input)) |
| nbActual, nhActual, err := fidl.UnmarshalWithContext2(testCtx, respb[:nb], resphi[:nh], output) |
| if err != nil { |
| t.Fatalf("unmarshal: failed: %s", err) |
| } |
| if !reflect.DeepEqual(input, output) { |
| t.Fatalf("unmarshal: expected: %v, got: %v", input, output) |
| } |
| if nb != nbActual { |
| t.Fatalf("unmarshal: num bytes, expected: %d, got: %d", nb, nbActual) |
| } |
| if nh != nhActual { |
| t.Fatalf("unmarshal: num handles, expected: %d, got: %d", nh, nhActual) |
| } |
| } |
| |
| func TestCorrectness(t *testing.T) { |
| for _, ex := range general() { |
| t.Run(ex.name, func(t *testing.T) { |
| check(t, ex.input, ex.expectSize) |
| }) |
| } |
| } |
| |
| type errorCaseUnmarshal struct { |
| name string |
| message fidl.Message |
| input []byte |
| errorCode fidl.ErrorCode |
| } |
| |
| // TODO(https://fxbug.dev/7832): We are lacking in negative tests in the conformance suite. |
| var baseErrorCasesUnmarshal = []errorCaseUnmarshal{ |
| {"empty-array-bindingstest.TestSimple", &bindingstest.TestSimple{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestSimple", &bindingstest.TestSimple{}, nil, fidl.ErrPayloadTooSmall}, |
| {"small-array-bindingstest.TestSimple", &bindingstest.TestSimple{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestSimpleBool", &bindingstest.TestSimpleBool{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestSimpleBool", &bindingstest.TestSimpleBool{}, nil, fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestAlignment1", &bindingstest.TestAlignment1{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestAlignment1", &bindingstest.TestAlignment1{}, nil, fidl.ErrPayloadTooSmall}, |
| {"small-array-bindingstest.TestAlignment1", &bindingstest.TestAlignment1{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestAlignment2", &bindingstest.TestAlignment2{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestAlignment2", &bindingstest.TestAlignment2{}, nil, fidl.ErrPayloadTooSmall}, |
| {"small-array-bindingstest.TestAlignment2", &bindingstest.TestAlignment2{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"small-array-bindingstest.TestAlignment2-2", &bindingstest.TestAlignment2{}, make([]byte, 10), fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestFloat1", &bindingstest.TestFloat1{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestFloat1", &bindingstest.TestFloat1{}, nil, fidl.ErrPayloadTooSmall}, |
| {"small-array-bindingstest.TestFloat1", &bindingstest.TestFloat1{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestFloat2", &bindingstest.TestFloat2{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestFloat2", &bindingstest.TestFloat2{}, nil, fidl.ErrPayloadTooSmall}, |
| {"small-array-bindingstest.TestFloat2", &bindingstest.TestFloat2{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestFloat3", &bindingstest.TestFloat3{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestFloat3", &bindingstest.TestFloat3{}, nil, fidl.ErrPayloadTooSmall}, |
| {"small-array-bindingstest.TestFloat3", &bindingstest.TestFloat3{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"small-array-bindingstest.TestFloat3-2", &bindingstest.TestFloat3{}, make([]byte, 6), fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestArray1", &bindingstest.TestArray1{}, nil, fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestArray1", &bindingstest.TestArray1{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"two-bytes-array-bindingstest.TestArray1", &bindingstest.TestArray1{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestArray2", &bindingstest.TestArray2{}, nil, fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestArray2", &bindingstest.TestArray2{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"two-bytes-array-bindingstest.TestArray2", &bindingstest.TestArray2{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"six-bytes-array-bindingstest.TestArray2", &bindingstest.TestArray2{}, make([]byte, 6), fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestArray3", &bindingstest.TestArray3{}, nil, fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestArray3", &bindingstest.TestArray3{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"two-bytes-array-bindingstest.TestArray3", &bindingstest.TestArray3{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"six-bytes-array-bindingstest.TestArray3", &bindingstest.TestArray3{}, make([]byte, 6), fidl.ErrPayloadTooSmall}, |
| {"thirteen-bytes-array-bindingstest.TestArray3", &bindingstest.TestArray3{}, make([]byte, 13), fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestArray4", &bindingstest.TestArray4{}, nil, fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestArray4", &bindingstest.TestArray4{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"two-bytes-array-bindingstest.TestArray4", &bindingstest.TestArray4{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestString1", &bindingstest.TestString1{}, nil, fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestString1", &bindingstest.TestString1{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"two-bytes-array-bindingstest.TestString1", &bindingstest.TestString1{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"nil-array-bindingstest.TestString2", &bindingstest.TestString2{}, nil, fidl.ErrPayloadTooSmall}, |
| {"empty-array-bindingstest.TestString2", &bindingstest.TestString2{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"two-bytes-array-bindingstest.TestString2", &bindingstest.TestString2{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"nil-array-TestStruct2", &bindingstest.TestStruct2{}, nil, fidl.ErrPayloadTooSmall}, |
| {"empty-array-TestStruct2", &bindingstest.TestStruct2{}, []byte{}, fidl.ErrPayloadTooSmall}, |
| {"two-bytes-array-TestStruct2", &bindingstest.TestStruct2{}, []byte{0x00, 0x0}, fidl.ErrPayloadTooSmall}, |
| {"six-bytes-array-TestStruct2", &bindingstest.TestStruct2{}, make([]byte, 6), fidl.ErrPayloadTooSmall}, |
| {"thirteen-bytes-array-TestStruct2", &bindingstest.TestStruct2{}, make([]byte, 13), fidl.ErrPayloadTooSmall}, |
| {"empty-struct-non-zero", &bindingstest.EmptyStruct{}, emptyStructWithOneInsteadOfZero, fidl.ErrInvalidEmptyStruct}, |
| } |
| |
| // TODO(https://fxbug.dev/7832): We are lacking in negative tests in the conformance suite. |
| var allErrorCasesUnmarshal = append(baseErrorCasesUnmarshal, []errorCaseUnmarshal{ |
| {"string-wrong-ptr-no-alloc", &bindingstest.TestStringWithBound{}, []byte{ |
| 3, 0, 0, 0, 0, 0, 0, 0, // length |
| 0, 0, 0, 0, 0, 0, 0, 0, // ptr (no alloc) |
| // no data, unmarshal should fail before |
| }, fidl.ErrUnexpectedNullRef}, |
| {"string-wrong-ptr-incorrect", &bindingstest.TestStringWithBound{}, []byte{ |
| 3, 0, 0, 0, 0, 0, 0, 0, // length |
| 0, 0, 0, 0, 0, 0, 0, 1, // ptr (no alloc) |
| // no data, unmarshal should fail before |
| }, fidl.ErrBadRefEncoding}, |
| {"string-too-long", &bindingstest.TestStringWithBound{}, []byte{ |
| 9, 0, 0, 0, 0, 0, 0, 0, // length (too long) |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // ptr |
| // no data, unmarshal should fail before |
| }, fidl.ErrStringTooLong}, |
| {"string-has-truncated-data", &bindingstest.TestStringWithBound{}, []byte{ |
| 8, 0, 0, 0, 0, 0, 0, 0, // length |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // ptr |
| 0x41, 0x72, 0x67, 0x68, 0x68, 0x68, 0x68, // only 7 bytes |
| }, fidl.ErrPayloadTooSmall}, |
| |
| {"opt-string-wrong-ptr-incorrect", &bindingstest.TestOptStringWithBound{}, []byte{ |
| 3, 0, 0, 0, 0, 0, 0, 0, // length |
| 0, 0, 0, 0, 0, 0, 0, 1, // ptr (no alloc) |
| // no data, unmarshal should fail before |
| }, fidl.ErrBadRefEncoding}, |
| {"opt-string-too-long", &bindingstest.TestOptStringWithBound{}, []byte{ |
| 9, 0, 0, 0, 0, 0, 0, 0, // length (too long) |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // ptr |
| // no data, unmarshal should fail before |
| }, fidl.ErrStringTooLong}, |
| }...) |
| |
| var simpleTableWithXY = []byte{ |
| 5, 0, 0, 0, 0, 0, 0, 0, // max ordinal |
| 255, 255, 255, 255, 255, 255, 255, 255, // alloc present |
| 8, 0, 0, 0, 0, 0, 0, 0, // envelope 1: num bytes / num handles |
| 255, 255, 255, 255, 255, 255, 255, 255, // alloc present |
| 0, 0, 0, 0, 0, 0, 0, 0, // envelope 2: num bytes / num handles |
| 0, 0, 0, 0, 0, 0, 0, 0, // no alloc |
| 0, 0, 0, 0, 0, 0, 0, 0, // envelope 3: num bytes / num handles |
| 0, 0, 0, 0, 0, 0, 0, 0, // no alloc |
| 0, 0, 0, 0, 0, 0, 0, 0, // envelope 4: num bytes / num handles |
| 0, 0, 0, 0, 0, 0, 0, 0, // no alloc |
| 8, 0, 0, 0, 0, 0, 0, 0, // envelope 5: num bytes / num handles |
| 255, 255, 255, 255, 255, 255, 255, 255, // alloc present |
| 42, 0, 0, 0, 0, 0, 0, 0, // field X |
| 67, 0, 0, 0, 0, 0, 0, 0, // field Y |
| } |
| |
| var simpleTableWithY = []byte{ |
| 5, 0, 0, 0, 0, 0, 0, 0, // max ordinal |
| 255, 255, 255, 255, 255, 255, 255, 255, // alloc present |
| 0, 0, 0, 0, 0, 0, 0, 0, // envelope 1: num bytes / num handles |
| 0, 0, 0, 0, 0, 0, 0, 0, // no alloc |
| 0, 0, 0, 0, 0, 0, 0, 0, // envelope 2: num bytes / num handles |
| 0, 0, 0, 0, 0, 0, 0, 0, // no alloc |
| 0, 0, 0, 0, 0, 0, 0, 0, // envelope 3: num bytes / num handles |
| 0, 0, 0, 0, 0, 0, 0, 0, // no alloc |
| 0, 0, 0, 0, 0, 0, 0, 0, // envelope 4: num bytes / num handles |
| 0, 0, 0, 0, 0, 0, 0, 0, // no alloc |
| 8, 0, 0, 0, 0, 0, 0, 0, // envelope 5: num bytes / num handles |
| 255, 255, 255, 255, 255, 255, 255, 255, // alloc present |
| 67, 0, 0, 0, 0, 0, 0, 0, // field Y |
| } |
| |
| var emptyStructWithOneInsteadOfZero = []byte{ |
| 1, // empty struct with invalid value of 1 (instead of zero) |
| 0, 0, 0, 0, 0, 0, 0, // 7 bytes of padding after empty struct, to align to 64 bits |
| } |
| |
| // TODO(https://fxbug.dev/7832): These should move into the conformance suite too as they captured |
| // actual regressions that occurred, which none of the other tests captured. |
| func TestAllManualSuccessCases(t *testing.T) { |
| // TODO(FIDL-635): Complete conversion. |
| var ipAddressConfig bindingstest.IpAddressConfig |
| ipAddressConfig.SetDhcp(true) |
| successCase{ |
| name: "add-ethernet-device-request", |
| context: testCtx, |
| input: &bindingstest.TestAddEthernetDeviceRequest{ |
| TopologicalPath: "@/dev/sys/pci/00:03.0/e1000/ethernet", |
| Config: bindingstest.InterfaceConfig{ |
| Name: "ethp0003", |
| IpAddressConfig: ipAddressConfig, |
| }, |
| Device: bindingstest.EthernetDeviceWithCtxInterface{Channel: zx.Channel(0xdeadbeef)}, |
| }, |
| bytes: []byte{ |
| 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // topological_path |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // topological_path |
| 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // name |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // name |
| 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subnet (dhcp variant) |
| 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subnet envelope (num bytes/handles) |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // subnet envelope (PRESENT) |
| 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // device (handle present) |
| 0x40, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x73, 0x79, // @/dev/sy |
| 0x73, 0x2f, 0x70, 0x63, 0x69, 0x2f, 0x30, 0x30, // s/pci/00 |
| 0x3a, 0x30, 0x33, 0x2e, 0x30, 0x2f, 0x65, 0x31, // :03.0/e1 |
| 0x30, 0x30, 0x30, 0x2f, 0x65, 0x74, 0x68, 0x65, // 000/ethe |
| 0x72, 0x6e, 0x65, 0x74, 0x00, 0x00, 0x00, 0x00, // rnet |
| 0x65, 0x74, 0x68, 0x70, 0x30, 0x30, 0x30, 0x33, // ethp0003 |
| 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subnet (dhcp data) |
| }, |
| handleInfos: []zx.HandleInfo{ |
| { |
| Handle: zx.Handle(0xdeadbeef), |
| Rights: fidl.ProtocolRights, |
| Type: zx.ObjectTypeChannel, |
| }, |
| }, |
| checkRights: true, |
| }.check(t) |
| |
| successCase{ |
| name: "package-resolver-resolve-request", |
| context: testCtx, |
| input: &bindingstest.TestPackageResolverResolveRequest{ |
| PackageUrl: "a", |
| Selectors: []string{"a"}, |
| UpdatePolicy: bindingstest.UpdatePolicy{ |
| FetchIfAbsent: true, |
| AllowOldVersions: true, |
| }, |
| Dir: bindingstest.EthernetDeviceWithCtxInterfaceRequest{Channel: zx.Channel(0xdeadbeef)}, |
| }, |
| bytes: []byte{ |
| 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // package url size |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // package url ptr |
| 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // selectors size |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // selectors ptr |
| 0x01, 0x01, 0x00, 0x00, // policy struct + padding |
| 0xFF, 0xFF, 0xFF, 0xFF, // request handle |
| // out of line data |
| 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| }, |
| handleInfos: []zx.HandleInfo{ |
| { |
| Handle: zx.Handle(0xdeadbeef), |
| Rights: fidl.ProtocolRights, |
| Type: zx.ObjectTypeChannel, |
| }, |
| }, |
| checkRights: true, |
| }.check(t) |
| } |
| |
| // Handle rights is not in conformance testing. |
| func TestHandleRightsMarshalUnmarshal(t *testing.T) { |
| data := make([]byte, 1024) |
| handleDispositions := make([]zx.HandleDisposition, 1) |
| input := &bindingstest.HandleRightsSubtypeTestStruct{H: []zx.VMO{5}} |
| _, nh, err := fidl.Marshal(input, data, handleDispositions) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if nh != 1 { |
| t.Fatalf("unexpected number of handles: want %d, got %d", 1, nh) |
| } |
| if handleDispositions[0].Handle != *input.H[0].Handle() { |
| t.Fatalf("expected handle to match: want %v, got %v", input.H, handleDispositions[0].Handle) |
| } |
| if handleDispositions[0].Rights != 3 { |
| t.Fatalf("incorrect rights: want %v, got %v", 3, handleDispositions[0].Rights) |
| } |
| if handleDispositions[0].Type != 3 { |
| t.Fatalf("incorrect subtype: want %v, got %v", 3, handleDispositions[0].Type) |
| } |
| |
| // normal unmarshaling |
| handleInfos := []zx.HandleInfo{ |
| { |
| Handle: handleDispositions[0].Handle, |
| Rights: handleDispositions[0].Rights, |
| Type: handleDispositions[0].Type, |
| }, |
| } |
| output := &bindingstest.HandleRightsSubtypeTestStruct{} |
| if _, _, err = fidl.Unmarshal(data, handleInfos, output); err != nil { |
| t.Fatal(err) |
| } |
| if output.H[0] != input.H[0] { |
| t.Fatalf("incorrect handle: want %v, got %v", input.H, output.H) |
| } |
| |
| // missing required rights |
| handleInfos = []zx.HandleInfo{ |
| { |
| Handle: handleDispositions[0].Handle, |
| Rights: 0x1, |
| Type: handleDispositions[0].Type, |
| }, |
| } |
| output = &bindingstest.HandleRightsSubtypeTestStruct{} |
| if _, _, err = fidl.Unmarshal(data, handleInfos, output); err == nil { |
| t.Fatalf("expected error due to missing required rights") |
| } else if err != nil && err.(fidl.ValidationError).Code() != fidl.ErrMissingRequiredHandleRights { |
| t.Fatalf("unexpected error code %v", err) |
| } |
| |
| // incorrect handle type |
| handleInfos = []zx.HandleInfo{ |
| { |
| Handle: handleDispositions[0].Handle, |
| Rights: handleDispositions[0].Rights, |
| Type: 1, |
| }, |
| } |
| output = &bindingstest.HandleRightsSubtypeTestStruct{} |
| if _, _, err = fidl.Unmarshal(data, handleInfos, output); err == nil { |
| t.Fatalf("expected error due to incorrect handle type") |
| } else if err != nil && err.(fidl.ValidationError).Code() != fidl.ErrIncorrectHandleType { |
| t.Fatalf("unexpected error code %v", err) |
| } |
| } |
| |
| // Handle rights is not in conformance testing. |
| func TestHandleUncheckedSubtypeMarshalUnmarshal(t *testing.T) { |
| data := make([]byte, 1024) |
| handleDispositions := make([]zx.HandleDisposition, 1) |
| input := &bindingstest.PlainHandleTestStruct{H: zx.Handle(5)} |
| _, nh, err := fidl.Marshal(input, data, handleDispositions) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if nh != 1 { |
| t.Fatalf("unexpected number of handles: want %d, got %d", 1, nh) |
| } |
| if handleDispositions[0].Handle != input.H { |
| t.Fatalf("expected handle to match: want %v, got %v", input.H, handleDispositions[0].Handle) |
| } |
| if handleDispositions[0].Type != 0 { |
| t.Fatalf("incorrect subtype: want %v, got %v", 0, handleDispositions[0].Type) |
| } |
| |
| // normal unmarshaling |
| handleInfos := []zx.HandleInfo{ |
| { |
| Handle: handleDispositions[0].Handle, |
| Type: handleDispositions[0].Type, |
| }, |
| } |
| output := &bindingstest.PlainHandleTestStruct{} |
| if _, _, err = fidl.Unmarshal(data, handleInfos, output); err != nil { |
| t.Fatal(err) |
| } |
| if output.H != input.H { |
| t.Fatalf("incorrect handle: want %v, got %v", input.H, output.H) |
| } |
| |
| // unchecked handle type |
| handleInfos = []zx.HandleInfo{ |
| { |
| Handle: handleDispositions[0].Handle, |
| Type: 1, |
| }, |
| } |
| output = &bindingstest.PlainHandleTestStruct{} |
| if _, _, err = fidl.Unmarshal(data, handleInfos, output); err != nil { |
| t.Fatalf("expected handle of type ZX_OBJ_TYPE_NONE to be unchecked") |
| } |
| if output.H != input.H { |
| t.Fatalf("incorrect handle: want %v, got %v", input.H, output.H) |
| } |
| } |
| |
| // This is a specific test checking that the marshaler construction properly |
| // fails with a clear error message if fed incorrect generated code. Hence, |
| // this has to stay a hand written test. |
| func TestFailureNullableTable(t *testing.T) { |
| type TestNullableTable struct { |
| _ struct{} `fidl:"s"` |
| A *bindingstest.SimpleTable `fidl:"0" fidl_offset_v1:"0"` |
| } |
| _, err := fidl.CreateMarshaler(TestNullableTable{}) |
| if err == nil { |
| t.Fatalf("expected error creating marshaler for nullable table") |
| } |
| if !strings.Contains(err.Error(), "optional field marshaler") { |
| t.Fatalf("unexpected error: %s", err.Error()) |
| } |
| } |
| |
| // TODO(https://fxbug.dev/7832): We are lacking in negative tests in the conformance suite. |
| func TestFailuresMarshal(t *testing.T) { |
| v1 := []int64{1, 2, 3} |
| cases := []struct { |
| name string |
| input fidl.Message |
| errorCode fidl.ErrorCode |
| }{ |
| {"string3-string-too-long", &bindingstest.TestString3{ |
| A: [2]string{ |
| "too long!", // limit is 4, provided is longer(tm) |
| "g", |
| }, |
| B: [2]*string{nil, nil}, |
| }, fidl.ErrStringTooLong}, |
| {"vector1-C-vector-too-long", &bindingstest.TestVector1{ |
| A: []int8{1, 2, 3, 4}, |
| B: nil, |
| C: []int32{99, 100, 101}, // limit is 2, provided is 3 |
| D: nil, |
| }, fidl.ErrVectorTooLong}, |
| {"vector1-D-vector-too-long", &bindingstest.TestVector1{ |
| A: []int8{1, 2, 3, 4}, |
| B: nil, |
| C: []int32{99}, |
| D: &v1, // limit is 2, provided is 3 |
| }, fidl.ErrVectorTooLong}, |
| } |
| for _, ex := range cases { |
| t.Run(ex.name, func(t *testing.T) { |
| var respb [zx.ChannelMaxMessageBytes]byte |
| var resphd [zx.ChannelMaxMessageHandles]zx.HandleDisposition |
| _, _, err := fidl.MarshalWithContext(testCtx, ex.input, respb[:], resphd[:]) |
| validationErr, ok := err.(fidl.ValidationError) |
| if !ok { |
| t.Fatalf("expected ValidationError, was %v", err) |
| } |
| if validationErr.Code() != ex.errorCode { |
| t.Fatalf("expected %s, was %s", ex.errorCode, validationErr.Code()) |
| } |
| }) |
| } |
| } |
| |
| // TODO(https://fxbug.dev/7832): We are lacking in negative tests in the conformance suite. |
| func TestFailuresUnmarshalNoHandles(t *testing.T) { |
| for _, ex := range allErrorCasesUnmarshal { |
| t.Run(ex.name, func(t *testing.T) { |
| _, _, err := fidl.Unmarshal(ex.input, nil, ex.message) |
| validationErr, ok := err.(fidl.ValidationError) |
| if !ok { |
| t.Fatalf("expected ValidationError, was %v", err) |
| } |
| if validationErr.Code() != ex.errorCode { |
| t.Fatalf("expected %s, was %s", ex.errorCode, validationErr.Code()) |
| } |
| }) |
| } |
| } |
| |
| // TODO(https://fxbug.dev/62647): Move to GIDL once we support protocol handles. |
| func TestConformanceClientEnd(t *testing.T) { |
| successCase{ |
| name: "handles-clientend", |
| context: testCtx, |
| input: &bindingstest.HasClientEnd{ |
| ClientEnd: bindingstest.ExampleProtocolWithCtxInterface(fidl.ChannelProxy{ |
| Channel: zx.Channel(0x44332211), |
| }), |
| }, |
| bytes: []byte{ |
| 0xff, 0xff, 0xff, 0xff, // handle present |
| 0x00, 0x00, 0x00, 0x00, // padding |
| }, |
| handleInfos: []zx.HandleInfo{ |
| { |
| Handle: zx.Handle(0x44332211), |
| Rights: fidl.ProtocolRights, |
| Type: zx.ObjectTypeChannel, |
| }, |
| }, |
| checkRights: true, |
| }.check(t) |
| } |
| |
| // TODO(https://fxbug.dev/62647): Move to GIDL once we support protocol handles. |
| func TestConformanceServerEnd(t *testing.T) { |
| successCase{ |
| name: "handles-serverend", |
| context: testCtx, |
| input: &bindingstest.HasServerEnd{ |
| ServerEnd: bindingstest.ExampleProtocolWithCtxInterfaceRequest(fidl.InterfaceRequest{ |
| Channel: zx.Channel(0x44332211), |
| }), |
| }, |
| bytes: []byte{ |
| 0xff, 0xff, 0xff, 0xff, // handle present |
| 0x00, 0x00, 0x00, 0x00, // padding |
| }, |
| handleInfos: []zx.HandleInfo{ |
| { |
| Handle: zx.Handle(0x44332211), |
| Rights: fidl.ProtocolRights, |
| Type: zx.ObjectTypeChannel, |
| }, |
| }, |
| checkRights: true, |
| }.check(t) |
| } |
| |
| func TestBitsApi(t *testing.T) { |
| raw := uint32(0b110101) |
| |
| unknownStrict := bindingstest.StrictBits(raw) |
| if !unknownStrict.HasUnknownBits() { |
| t.Error("unknown bits returned false for HasUnknownBits") |
| } |
| if unknownStrict.GetUnknownBits() != 0b110100 { |
| t.Errorf( |
| "Got wrong unknown bits: expected %b, was %b", 0b110100, unknownStrict.GetUnknownBits()) |
| } |
| if unknownStrict.InvertKnownBits() != 0b110110 { |
| t.Errorf( |
| "Got wrong InvertKnownBits: expected %b, got %b", 0b110110, unknownStrict.InvertKnownBits()) |
| } |
| if unknownStrict != unknownStrict.InvertKnownBits().InvertKnownBits() { |
| t.Errorf( |
| "Got wrong double InvertKnownBits: expected %b, got %b", unknownStrict, unknownStrict.InvertKnownBits().InvertKnownBits()) |
| } |
| if !unknownStrict.HasBits(0b1) { |
| t.Errorf("Failed to match on known bits for HasBits") |
| } |
| if !unknownStrict.HasBits(0b110000) { |
| t.Errorf("Failed to match on unknown bits for HasBits") |
| } |
| if unknownStrict.HasBits(0b10) { |
| t.Errorf("Matched on known bits for HasBits when it should not") |
| } |
| if unknownStrict.HasBits(0b1000) { |
| t.Errorf("Matched on unknown bits for HasBits when it should not") |
| } |
| if unknownStrict.ClearBits(0b1) != bindingstest.StrictBits(0b110100) { |
| t.Errorf("Failed to clear known bits for ClearBits") |
| } |
| if unknownStrict.ClearBits(0b10000) != bindingstest.StrictBits(0b100101) { |
| t.Errorf("Failed to clear unknown bits for ClearBits") |
| } |
| if unknownStrict != unknownStrict.ClearBits(0b10) { |
| t.Errorf("Cleared known bits when it should not") |
| } |
| if unknownStrict != unknownStrict.ClearBits(0b1000) { |
| t.Errorf("Cleared unknown bits when it should not") |
| } |
| |
| knownStrict := unknownStrict & bindingstest.StrictBits_Mask |
| if knownStrict != bindingstest.StrictBitsOne { |
| t.Errorf("Expected masked value: %b, got %b", bindingstest.StrictBitsOne, knownStrict) |
| } |
| |
| unknownFlexible := bindingstest.FlexibleBits(raw) |
| if !unknownFlexible.HasUnknownBits() { |
| t.Error("unknown bits returned false for HasUnknownBits") |
| } |
| if unknownFlexible.GetUnknownBits() != 0b110100 { |
| t.Errorf( |
| "Got wrong unknown bits: expected %b, was %b", 0b110100, unknownFlexible.GetUnknownBits()) |
| } |
| if unknownFlexible.InvertKnownBits() != 0b110110 { |
| t.Errorf( |
| "Got wrong InvertKnownBits: expected %b, got %b", 0b110110, unknownFlexible.InvertKnownBits()) |
| } |
| if unknownFlexible != unknownFlexible.InvertKnownBits().InvertKnownBits() { |
| t.Errorf( |
| "Got wrong double InvertKnownBits: expected %b, got %b", unknownFlexible, unknownFlexible.InvertKnownBits().InvertKnownBits()) |
| } |
| if !unknownFlexible.HasBits(0b1) { |
| t.Errorf("Failed to match on known bits for HasBits") |
| } |
| if !unknownFlexible.HasBits(0b110000) { |
| t.Errorf("Failed to match on unknown bits for HasBits") |
| } |
| if unknownFlexible.HasBits(0b10) { |
| t.Errorf("Matched on known bits for HasBits when it should not") |
| } |
| if unknownFlexible.HasBits(0b1000) { |
| t.Errorf("Matched on unknown bits for HasBits when it should not") |
| } |
| if unknownFlexible.ClearBits(0b1) != bindingstest.FlexibleBits(0b110100) { |
| t.Errorf("Failed to clear known bits for ClearBits") |
| } |
| if unknownFlexible.ClearBits(0b10000) != bindingstest.FlexibleBits(0b100101) { |
| t.Errorf("Failed to clear unknown bits for ClearBits") |
| } |
| if unknownFlexible != unknownFlexible.ClearBits(0b10) { |
| t.Errorf("Cleared known bits when it should not") |
| } |
| if unknownFlexible != unknownFlexible.ClearBits(0b1000) { |
| t.Errorf("Cleared unknown bits when it should not") |
| } |
| |
| knownFlexible := unknownFlexible & bindingstest.FlexibleBits_Mask |
| if knownFlexible != bindingstest.FlexibleBitsOne { |
| t.Errorf("Expected masked value: %b, got %b", bindingstest.FlexibleBitsOne, knownFlexible) |
| } |
| } |
| |
| func TestUnionApi(t *testing.T) { |
| union := bindingstest.XUnion1{ |
| I_xUnion1Tag: 4, |
| I_unknownData: fidl.UnknownData{ |
| Bytes: []byte{51}, |
| }, |
| } |
| if union.Which() != bindingstest.XUnion1_unknownData { |
| t.Errorf("Expected unknown union to have unknown tag") |
| } |
| |
| data := union.GetUnknownData() |
| if len(data.Bytes) != 1 || data.Bytes[0] != 51 { |
| t.Errorf("Expected unknown data to be [51], got: %v", data.Bytes) |
| } |
| if len(data.Handles) != 0 { |
| t.Errorf("Expected empty unknown handles") |
| } |
| } |
| |
| func TestTableApi(t *testing.T) { |
| var emptyTable bindingstest.SimpleTable |
| if emptyTable.HasUnknownData() { |
| t.Errorf("Expected new table to have empty unknown data") |
| } |
| |
| table := bindingstest.SimpleTable{ |
| I_unknownData: map[uint64]fidl.UnknownData{ |
| 3: { |
| Bytes: []byte{51}, |
| }, |
| }, |
| } |
| |
| table.SetX(5) |
| if !table.HasX() { |
| t.Errorf("Expected X to be set") |
| } |
| if table.GetX() != 5 { |
| t.Errorf("Expected X value 5, got: %d", table.GetX()) |
| } |
| if table.HasY() { |
| t.Errorf("Expected Y to be unset") |
| } |
| y := table.GetYWithDefault(13) |
| if y != 13 { |
| t.Errorf("Expected default Y value 13, got: %d", y) |
| } |
| if !table.HasUnknownData() { |
| t.Errorf("Expected table to have unknown data") |
| } |
| unknownData := table.GetUnknownData() |
| data, ok := unknownData[3] |
| if !ok { |
| t.Errorf("Expected table to have unknown ordinal 3") |
| } |
| if len(data.Bytes) != 1 || data.Bytes[0] != 51 { |
| t.Errorf("Expected unknown data to be [51], got: %v", data.Bytes) |
| } |
| if len(data.Handles) != 0 { |
| t.Errorf("Expected empty unknown handles") |
| } |
| } |