diff --git a/tools/fidl/gidl-conformance-suite/conformance.gidl b/tools/fidl/gidl-conformance-suite/conformance.gidl new file mode 100644 index 0000000000000000000000000000000000000000..6aae4d1326de55f023a776214d8a5c4555cb0735 --- /dev/null +++ b/tools/fidl/gidl-conformance-suite/conformance.gidl @@ -0,0 +1,403 @@ +// Copyright 2019 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. + +success("EmptyStruct") { + value = EmptyStruct { + } + bytes = { + 0x00, // one byte + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding + } +} + +success("EmptyStructSandwich") { + value = EmptyStructSandwich { + before: "before", + es: EmptyStruct {}, + after: "after", + } + bytes = { + 6, 0, 0, 0, 0, 0, 0, 0, // length of "before" + 255, 255, 255, 255, 255, 255, 255, 255, // "before" is present + 0, // empty struct zero field + 0, 0, 0, 0, 0, 0, 0, // 7 bytes of padding after empty struct, to align to 64 bits + 5, 0, 0, 0, 0, 0, 0, 0, // length of "after" + 255, 255, 255, 255, 255, 255, 255, 255, // "after" is present + 'b', 'e', 'f', 'o', 'r', 'e', + 0, 0, // 2 bytes of padding after "before", to align to 64 bits + 'a', 'f', 't', 'e', 'r', // "after" string + 0, 0, 0, // 3 bytes of padding after "after", to align to 64 bits + } +} + +success("Uint8Uint16Uint32Uint64") { + value = Uint8Uint16Uint32Uint64 { + f1: 0x01, + f2: 0x0203, + f3: 0x04050607, + f4: 0x08090a0b0c0d0e0f, + } + bytes = { + 0x01, // f1 + 0x00, // padding + 0x03, 0x02, // f2 + 0x07, 0x06, 0x05, 0x04, // f3 + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, // f4 + } +} + +success("Uint64Uint32Uint16Uint8") { + value = Uint64Uint32Uint16Uint8 { + f1: 0x08090a0b0c0d0e0f, + f2: 0x04050607, + f3: 0x0203, + f4: 0x01, + } + bytes = { + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, // f1 + 0x07, 0x06, 0x05, 0x04, // f2 + 0x03, 0x02, // f3 + 0x01, // f4 + 0x00, // padding + } +} + +success("SimpleTableEmpty") { + value = StructOfSimpleTable { + table: SimpleTable {}, + } + bytes = { + 0, 0, 0, 0, 0, 0, 0, 0, // max ordinal + 255, 255, 255, 255, 255, 255, 255, 255, // alloc present + } +} + +success("SimpleTableXAndY") { + value = StructOfSimpleTable { + table: SimpleTable { + x: 42, + y: 67, + }, + } + bytes = { + 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 + } +} + +success("SimpleTableJustY") { + value = StructOfSimpleTable { + table: SimpleTable { + y: 67, + }, + } + bytes = { + 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 + } +} + +success("TableWithStringAndVectorNoVectorContent") { + value = StructOfTableWithStringAndVector { + table: TableWithStringAndVector { + foo: "hello", + bar: 27, + }, + } + bytes = { + 2, 0, 0, 0, 0, 0, 0, 0, // max ordinal + 255, 255, 255, 255, 255, 255, 255, 255, // alloc present + 24, 0, 0, 0, 0, 0, 0, 0, // envelope 1: num bytes / num handles + 255, 255, 255, 255, 255, 255, 255, 255, // envelope 1: alloc present + 8, 0, 0, 0, 0, 0, 0, 0, // envelope 2: num bytes / num handles + 255, 255, 255, 255, 255, 255, 255, 255, // envelope 2: alloc present + 5, 0, 0, 0, 0, 0, 0, 0, // element 1: length + 255, 255, 255, 255, 255, 255, 255, 255, // element 1: alloc present + 104, 101, 108, 108, 111, 0, 0, 0, // element 1: hello + 27, 0, 0, 0, 0, 0, 0, 0, // element 2: value + } +} + +// TODO(FIDL-626): Create test with TableWithStringAndVectorHasVectorContent. + +success("SimpleTableThenUint64") { + value = SimpleTableThenUint64 { + table: SimpleTable { + x: 42, + y: 67, + }, + number: 0xdeadbeefdeadbeef, + } + bytes = { + 5, 0, 0, 0, 0, 0, 0, 0, // max ordinal + 255, 255, 255, 255, 255, 255, 255, 255, // alloc present + 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, // uint64 number + 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 + } +} + +success("InlineXunionInStruct") { + value = TestInlineXUnionInStruct { + before: "before", + xu: SampleXUnion { + u: 0xdeadbeef, + }, + after: "after", + } + bytes = { + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence + + 0xb2, 0x56, 0x9c, 0x38, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present + + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence + + // secondary object 1: "before" + 'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00, + + // secondary object 2: xunion content + 0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00, // xunion envelope content (0xdeadbeef) + padding + + // secondary object 3: "after" + 'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00, + } +} + +success("OptionalXunionInStructAbsent") { + value = TestOptionalXUnionInStruct { + before: "before", + // no SampleXUnion + after: "after", + } + bytes = { + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // envelope data is absent + + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence + + // secondary object 1: "before" + 'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00, + + // secondary object 2: "after" + 'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00, + } +} + +success("OptionalXunionInStructAbsent") { + value = TestOptionalXUnionInStruct { + before: "before", + xu: SampleXUnion { + u: 0xdeadbeef, + }, + after: "after", + } + bytes = { + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence + + 0xb2, 0x56, 0x9c, 0x38, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present + + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "after" presence + + // secondary object 1: "before" + 'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00, + + // secondary object 2: xunion content + 0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00, // xunion envelope content (0xdeadbeef) + padding + + // secondary object 3: "after" + 'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00, + } +} + +success("XunionInTableXunionAbsent") { + value = TestXUnionInTable { + value: XUnionInTable { + before: "before", + // no SampleXUnion + after: "after", + }, + } + bytes = { + // primary object + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // vector<envelope> element count + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // vector<envelope> present + + // secondary object 1: vector data + // vector[0]: envelope<string before> + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" is present + // vector[1]: envelope<SampleXUnion xu> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xunion is absent + // vector[2]: envelope<string after> + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "after" is present + + // secondary object 2: "before" length + pointer + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" present + + // secondary object 3: "before" + 'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00, // "before" + + // secondary object 4: "after" length + pointer + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "after" present + + // secondary object 5: "before" + 'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00, // "after" + } +} + +success("XunionInTableXunionPresent") { + value = TestXUnionInTable { + value: XUnionInTable { + before: "before", + xu: SampleXUnion { + u: 0xdeadbeef, + }, + after: "after", + }, + } + bytes = { + // primary object + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // vector<envelope> element count + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // vector<envelope> present + + // secondary object 1: vector data + // vector[0]: envelope<string before> + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" is present + // vector[1]: envelope<SampleXUnion xu> + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // xunion is present + // vector[2]: envelope<string after> + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size + handle count + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "after" is present + + // secondary object 2: "before" length + pointer + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" present + + // secondary object 3: "before" + 'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00, // "before" + + // secondary object 4: xunion + 0xb2, 0x56, 0x9c, 0x38, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present + + // secondary object 5: xunion content + 0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00, // 0xdeadbeef + padding + + // secondary object 6: "after" length + pointer + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "after" present + + // secondary object 7: "before" + 'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00, // "after" + } +} + +success("AddEthernetDeviceRequest") { + value = TestAddEthernetDeviceRequest { + topological_path: "@/dev/sys/pci/00:03.0/e1000/ethernet", + config: InterfaceConfig { + name: "ethp0003", + ip_address_config: IpAddressConfig { + dhcp: true, + }, + }, + // TODO(FIDL-625): This should be a handle. + this_should_be_a_handle: 0xffffffff, + } + bytes = { + 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 + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // subnet (dhcp variant) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding + 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 + } +} + +success("FileGetAttrResponse") { + value = FileGetAttrResponse { + s: 0x7eadbeaf, + attributes: NodeAttributes { + mode: 0x962381a4, + id: 1, + content_size: 231, + storage_size: 231, + link_count: 1, + creation_time: 0x8877665544332211, + modification_time: 0x00ffeeddccbbaa99, + }, + } + bytes = { + 0xaf, 0xbe, 0xad, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0xa4, 0x81, 0x23, 0x96, 0x00, 0x00, 0x00, 0x00, + 1, 0, 0, 0, 0, 0, 0, 0, + 231, 0, 0, 0, 0, 0, 0, 0, + 231, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, + } +} diff --git a/tools/fidl/gidl-conformance-suite/mix_and_match.test.fidl b/tools/fidl/gidl-conformance-suite/mix_and_match.test.fidl new file mode 100644 index 0000000000000000000000000000000000000000..fdf8032d2167a4ab78c588af105292b5a18f8176 --- /dev/null +++ b/tools/fidl/gidl-conformance-suite/mix_and_match.test.fidl @@ -0,0 +1,51 @@ +// Copyright 2019 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. + +library conformance; + +using zx; + +table XUnionInTable { + 1: string before; + 2: SampleXUnion xu; + 3: string after; +}; + +struct TestXUnionInTable { + XUnionInTable value; +}; + +protocol EthernetDevice {}; + +union IpAddressConfig { + array<uint32>:6 padding_size_24_align_4; + bool dhcp; +}; + +struct InterfaceConfig { + string name; + IpAddressConfig ip_address_config; +}; + +struct TestAddEthernetDeviceRequest { + string topological_path; + InterfaceConfig config; + // TODO(FIDL-625): Use 'EthernetDevice device;' instead. + uint32 this_should_be_a_handle; +}; + +struct NodeAttributes { + uint32 mode; + uint64 id; + uint64 content_size; + uint64 storage_size; + uint64 link_count; + uint64 creation_time; + uint64 modification_time; +}; + +struct FileGetAttrResponse { + zx.status s; + NodeAttributes attributes; +}; diff --git a/tools/fidl/gidl-conformance-suite/regen.sh b/tools/fidl/gidl-conformance-suite/regen.sh index 1ec3c08d09ce11d259acdbae941eb5d29db98ce7..bce7d895cc2b8bf884fda0d465f9a583e0a13942 100755 --- a/tools/fidl/gidl-conformance-suite/regen.sh +++ b/tools/fidl/gidl-conformance-suite/regen.sh @@ -2,30 +2,30 @@ set -euxo pipefail -if [[ ! -d "${FUCHSIA_DIR}" ]]; then +if [[ ! -d "${FUCHSIA_BUILD_DIR}" ]]; then echo "FUCHSIA_DIR environment variable not a directory" exit 1 fi -GOFMT="${FUCHSIA_DIR}/out/x64/tools/goroot/bin/gofmt" +GOFMT="${FUCHSIA_BUILD_DIR}/tools/goroot/bin/gofmt" if [ ! -x "${GOFMT}" ]; then echo "error: unable to find gofmt; did the path change?" 1>&2 exit 1 fi -FIDLC="${FUCHSIA_DIR}/out/x64/host_x64/fidlc" +FIDLC="${FUCHSIA_BUILD_DIR}/host_x64/fidlc" if [ ! -x "${FIDLC}" ]; then echo "error: fidlc missing; did you build?" 1>&2 exit 1 fi -FIDLGEN="${FUCHSIA_DIR}/out/x64/host_x64/fidlgen" +FIDLGEN="${FUCHSIA_BUILD_DIR}/host_x64/fidlgen" if [ ! -x "${FIDLGEN}" ]; then echo "error: fidlgen missing; did you build?" 1>&2 exit 1 fi -GIDL="${FUCHSIA_DIR}/out/default/tools/gidl" +GIDL="${FUCHSIA_BUILD_DIR}/tools/gidl" if [ ! -x "${GIDL}" ]; then echo "error: gidl missing; did you build?" 1>&2 exit 1 @@ -34,24 +34,26 @@ fi EXAMPLE_DIR="${FUCHSIA_DIR}/tools/fidl/gidl-conformance-suite" GO_LIB_DIR="${FUCHSIA_DIR}/third_party/go/src/syscall/zx/fidl/conformance" GO_TEST_DIR="${FUCHSIA_DIR}/third_party/go/src/syscall/zx/fidl/fidl_test" -for src_path in `find "${EXAMPLE_DIR}" -name '*.gidl'`; do - base=$( echo "${src_path}" | sed -e 's/\.gidl//' ) - gidl_path="${base}.gidl" - fidl_path="${base}.test.fidl" - tmpout=$( mktemp -d 2>/dev/null || mktemp -d -t 'tmpout' ) - json_path=$( mktemp ${tmpout}/tmp.XXXXXXXX ) - - # need to have all .fidl files in one conformance library - ${FIDLC} \ - --json "${json_path}" \ - --files "${fidl_path}" - - ${FIDLGEN} \ - --generators go \ - --json "${json_path}" \ - --output-base "${tmpout}" \ - --include-base "${tmpout}" - cat << EOF > "${GO_LIB_DIR}/impl.go" + +# TODO(FIDL-621): Support multiple .gidl sources. +gidl_path="${EXAMPLE_DIR}/conformance.gidl" + +tmpout=$( mktemp -d 2>/dev/null || mktemp -d -t 'tmpout' ) +trap "rm -rf ${tmpout}" EXIT +json_path=$( mktemp ${tmpout}/tmp.XXXXXXXX ) +fidlc_args="--json ${json_path} --files " +for fidl_path in `find "${EXAMPLE_DIR}" -name '*.fidl'`; do + fidlc_args="${fidlc_args} ${fidl_path}" +done + +${FIDLC} ${fidlc_args} + +${FIDLGEN} \ + --generators go \ + --json "${json_path}" \ + --output-base "${tmpout}" \ + --include-base "${tmpout}" +cat << EOF > "${GO_LIB_DIR}/impl.go" // Copyright 2019 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. @@ -61,10 +63,10 @@ for src_path in `find "${EXAMPLE_DIR}" -name '*.gidl'`; do // +build fuchsia EOF - cat "${tmpout}/impl.go" >> "${GO_LIB_DIR}/impl.go" - ${GOFMT} -s -w "${GO_LIB_DIR}/impl.go" +cat "${tmpout}/impl.go" >> "${GO_LIB_DIR}/impl.go" +${GOFMT} -s -w "${GO_LIB_DIR}/impl.go" - cat << EOF > "${GO_TEST_DIR}/conformance_test.go" +cat << EOF > "${GO_TEST_DIR}/conformance_test.go" // Copyright 2019 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. @@ -74,7 +76,6 @@ EOF // +build fuchsia EOF - ${GIDL} \ - --json "${json_path}" \ - --gidl "${gidl_path}" | ${GOFMT} >> "${GO_TEST_DIR}/conformance_test.go" -done +${GIDL} \ + --json "${json_path}" \ + --gidl "${gidl_path}" | ${GOFMT} >> "${GO_TEST_DIR}/conformance_test.go" diff --git a/tools/fidl/gidl-conformance-suite/structs.gidl b/tools/fidl/gidl-conformance-suite/structs.gidl deleted file mode 100644 index 20879e686abe7b09de5fea0828ed54ac175d40cd..0000000000000000000000000000000000000000 --- a/tools/fidl/gidl-conformance-suite/structs.gidl +++ /dev/null @@ -1,24 +0,0 @@ -success("Empty") { - value = Empty { - } - bytes = { - 0x00, // one byte - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding - } -} - -success("Uint8Uint16Uint32Uint64") { - value = Uint8Uint16Uint32Uint64 { - f1: 0x01, - f2: 0x0203, - f3: 0x04050607, - f4: 0x08090a0b0c0d0e0f, - } - bytes = { - 0x01, // f1 - 0x00, // padding - 0x03, 0x02, // f2 - 0x07, 0x06, 0x05, 0x04, // f3 - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, // f4 - } -} diff --git a/tools/fidl/gidl-conformance-suite/structs.test.fidl b/tools/fidl/gidl-conformance-suite/structs.test.fidl index 6d2f7afc793e07e5d7b238caa45ce239391c7b94..7340b14fbd476cff06ff84c79c7085bd9e9539fb 100644 --- a/tools/fidl/gidl-conformance-suite/structs.test.fidl +++ b/tools/fidl/gidl-conformance-suite/structs.test.fidl @@ -1,6 +1,16 @@ +// Copyright 2019 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. + library conformance; -struct Empty {}; +struct EmptyStruct {}; + +struct EmptyStructSandwich { + string before; + EmptyStruct es; + string after; +}; struct Uint8Uint16Uint32Uint64 { uint8 f1; @@ -8,3 +18,10 @@ struct Uint8Uint16Uint32Uint64 { uint32 f3; uint64 f4; }; + +struct Uint64Uint32Uint16Uint8 { + uint64 f1; + uint32 f2; + uint16 f3; + uint8 f4; +}; diff --git a/tools/fidl/gidl-conformance-suite/tables.test.fidl b/tools/fidl/gidl-conformance-suite/tables.test.fidl new file mode 100644 index 0000000000000000000000000000000000000000..d70b31d42fe43aa63f67f1e70323d2eec8414ac1 --- /dev/null +++ b/tools/fidl/gidl-conformance-suite/tables.test.fidl @@ -0,0 +1,32 @@ +// Copyright 2019 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. + +library conformance; + +table SimpleTable { + 1: int64 x; + 2: reserved; + 3: reserved; + 4: reserved; + 5: int64 y; +}; + +struct StructOfSimpleTable { + SimpleTable table; +}; + +struct SimpleTableThenUint64 { + SimpleTable table; + uint64 number; +}; + +table TableWithStringAndVector { + 1: string foo; + 2: int32 bar; + 3: vector<uint8> baz; +}; + +struct StructOfTableWithStringAndVector { + TableWithStringAndVector table; +}; diff --git a/tools/fidl/gidl-conformance-suite/xunion.test.fidl b/tools/fidl/gidl-conformance-suite/xunion.test.fidl new file mode 100644 index 0000000000000000000000000000000000000000..93f473238fc83648ead1f05964676828478ebe0a --- /dev/null +++ b/tools/fidl/gidl-conformance-suite/xunion.test.fidl @@ -0,0 +1,37 @@ +// Copyright 2019 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. + +library conformance; + +// TODO(FIDL-622): Do not rely on unions in xunion conformance tests. + +struct Int64Struct { + int64 x; +}; + +union SimpleUnion { + int32 i32; + int64 i64; + Int64Struct s; + Int64Struct? os; + string str; +}; + +xunion SampleXUnion { + uint32 u; + SimpleUnion su; + SimpleTable st; +}; + +struct TestInlineXUnionInStruct { + string before; + SampleXUnion xu; + string after; +}; + +struct TestOptionalXUnionInStruct { + string before; + SampleXUnion? xu; + string after; +}; diff --git a/tools/fidl/gidl/golang/golang.go b/tools/fidl/gidl/golang/golang.go index c375fe324904ebc0c8cb075dbf2aa4097cc00224..8fb0053145390b650db511a1e4fd8985a95c7e57 100644 --- a/tools/fidl/gidl/golang/golang.go +++ b/tools/fidl/gidl/golang/golang.go @@ -135,6 +135,9 @@ func (b *goValueBuilder) OnStruct(value gidlir.Object, decl *gidlmixer.StructDec fieldDecl, _ := decl.ForKey(key) gidlmixer.Visit(b, field, fieldDecl) fieldVar := b.lastVar + if decl.IsKeyNullable(key) { + fieldVar = "&" + fieldVar + } b.Builder.WriteString(fmt.Sprintf( "%s.%s = %s\n", containerVar, fidlcommon.ToUpperCamelCase(key), fieldVar)) } @@ -168,3 +171,17 @@ func (b *goValueBuilder) OnXUnion(value gidlir.Object, decl *gidlmixer.XUnionDec } b.lastVar = containerVar } + +func (b *goValueBuilder) OnUnion(value gidlir.Object, decl *gidlmixer.UnionDecl) { + containerVar := b.newVar() + b.Builder.WriteString(fmt.Sprintf( + "var %s conformance.%s\n", containerVar, value.Name)) + for key, field := range value.Fields { + fieldDecl, _ := decl.ForKey(key) + gidlmixer.Visit(b, field, fieldDecl) + fieldVar := b.lastVar + b.Builder.WriteString(fmt.Sprintf( + "%s.Set%s(%s)\n", containerVar, fidlcommon.ToUpperCamelCase(key), fieldVar)) + } + b.lastVar = containerVar +} diff --git a/tools/fidl/gidl/mixer/mixer.go b/tools/fidl/gidl/mixer/mixer.go index 5baa3ec25c2bc5a322343c78b9481249cd3abfec..33268928c19b02960c469f1884de99209f47412e 100644 --- a/tools/fidl/gidl/mixer/mixer.go +++ b/tools/fidl/gidl/mixer/mixer.go @@ -41,6 +41,7 @@ type ValueVisitor interface { OnStruct(value gidlir.Object, decl *StructDecl) OnTable(value gidlir.Object, decl *TableDecl) OnXUnion(value gidlir.Object, decl *XUnionDecl) + OnUnion(value gidlir.Object, decl *UnionDecl) } // Visit is the entry point into visiting a value, it dispatches appropriately @@ -63,6 +64,8 @@ func Visit(visitor ValueVisitor, value interface{}, decl Declaration) { visitor.OnTable(value, decl) case *XUnionDecl: visitor.OnXUnion(value, decl) + case *UnionDecl: + visitor.OnUnion(value, decl) default: panic(fmt.Sprintf("not implemented: %T", decl)) } @@ -150,7 +153,7 @@ func (decl *numberDecl) conforms(value interface{}) error { type stringDecl struct { hasNoKey - bound int + bound *int } func (decl *stringDecl) conforms(value interface{}) error { @@ -158,10 +161,13 @@ func (decl *stringDecl) conforms(value interface{}) error { default: return fmt.Errorf("expecting string, found %T (%s)", value, value) case string: - if decl.bound < len(value) { + if decl.bound == nil { + return nil + } + if bound := *decl.bound; bound < len(value) { return fmt.Errorf( "string '%s' is over bounds, expecting %d but was %d", value, - decl.bound, len(value)) + bound, len(value)) } return nil } @@ -183,6 +189,17 @@ func (decl *StructDecl) ForKey(key string) (Declaration, bool) { return nil, false } +// IsKeyNullable indicates whether this key is optional, i.e. whether it +// represents an optional field. +func (decl *StructDecl) IsKeyNullable(key string) bool { + for _, member := range decl.Members { + if string(member.Name) == key { + return member.Type.Nullable + } + } + return false +} + func (decl *StructDecl) conforms(value interface{}) error { switch value := value.(type) { default: @@ -266,6 +283,41 @@ func (decl XUnionDecl) conforms(untypedValue interface{}) error { } } +// UnionDecl describes a xunion declaration. +type UnionDecl struct { + fidlir.Union + schema schema +} + +// ForKey retrieves a declaration for a key. +func (decl UnionDecl) ForKey(key string) (Declaration, bool) { + for _, member := range decl.Members { + if string(member.Name) == key { + return decl.schema.LookupDeclByType(member.Type) + } + } + return nil, false +} + +func (decl UnionDecl) conforms(untypedValue interface{}) error { + switch value := untypedValue.(type) { + default: + return fmt.Errorf("expecting object, found %T (%v)", untypedValue, untypedValue) + case gidlir.Object: + if num := len(value.Fields); num != 1 { + return fmt.Errorf("must have one field, found %d", num) + } + for key, field := range value.Fields { + if fieldDecl, ok := decl.ForKey(key); !ok { + return fmt.Errorf("field %s: unknown", key) + } else if err := fieldDecl.conforms(field); err != nil { + return fmt.Errorf("field %s: %s", key, err) + } + } + return nil + } +} + type schema fidlir.Root // LookupDeclByName looks up a message declaration by name. @@ -294,6 +346,14 @@ func (s schema) LookupDeclByName(name string) (Declaration, bool) { }, true } } + for _, decl := range s.Unions { + if decl.Name == s.name(name) { + return &UnionDecl{ + Union: decl, + schema: s, + }, true + } + } // TODO(pascallouis): add support missing declarations (e.g. xunions) return nil, false } @@ -303,7 +363,7 @@ func (s schema) LookupDeclByType(typ fidlir.Type) (Declaration, bool) { switch typ.Kind { case fidlir.StringType: return &stringDecl{ - bound: *typ.ElementCount, + bound: typ.ElementCount, }, true case fidlir.PrimitiveType: switch typ.PrimitiveSubtype {