blob: 5f97e6775be80946980fda9199736425b62fa960 [file] [log] [blame]
// Copyright 2021 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 summarize
import (
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgentest"
)
const (
// zxLibrary is a shortened version of zx_common.fidl, for tests.
zxLibrary = `
library zx;
type ObjType = enum : uint32 {
CHANNEL = 4;
};
resource_definition Handle : uint32 {
properties {
subtype ObjType;
};
};
`
// l2Library is a sample dependency taken in by some tests.
l2Library = `
library l2;
type T = struct {};
type UnaryArg = struct {
num int32;
};
closed protocol Inverter {
strict Invert(UnaryArg) -> (UnaryArg);
};
closed protocol TableResponse {
strict Foo() -> (table {});
};
closed protocol ErrorSyntax {
strict Foo() -> () error uint32;
};
`
)
type summaryTestCase struct {
name string
fidl string
dep string
expected string
}
func TestJSONSummaryFormat(t *testing.T) {
tests := []summaryTestCase{
{
name: "library only",
fidl: `library l;`,
expected: `[
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "primitives 1",
fidl: `
library l;
const OFFSET int8 = -33;
const ENABLED_FLAG bool = true;
`,
expected: `[
{
"kind": "const",
"name": "l/ENABLED_FLAG",
"type": "bool",
"value": "true"
},
{
"kind": "const",
"name": "l/OFFSET",
"type": "int8",
"value": "-33"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
// Same as above, except reordered.
name: "primitives 2",
fidl: `
library l;
const ENABLED_FLAG bool = true;
const OFFSET int8 = -33;
`,
expected: `[
{
"kind": "const",
"name": "l/ENABLED_FLAG",
"type": "bool",
"value": "true"
},
{
"kind": "const",
"name": "l/OFFSET",
"type": "int8",
"value": "-33"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "primitives 3",
fidl: `
library l;
const ANSWER uint16 = 42;
const ANSWER_IN_BINARY uint16 = 0b101010;
`,
expected: `[
{
"kind": "const",
"name": "l/ANSWER",
"type": "uint16",
"value": "42"
},
{
"kind": "const",
"name": "l/ANSWER_IN_BINARY",
"type": "uint16",
"value": "42"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "primitives 4",
fidl: `
library l;
const ENABLED_FLAG bool = true;
const OFFSET int8 = -33;
const ANSWER uint16 = 42;
const ANSWER_IN_BINARY uint16 = 0b101010;
const POPULATION_USA_2018 uint32 = 330000000;
const DIAMOND uint64 = 0x183c7effff7e3c18;
const FUCHSIA uint64 = 4054509061583223046;
const USERNAME string = "squeenze";
const MIN_TEMP float32 = -273.15;
const CONVERSION_FACTOR float64 = 1.41421358;
`,
expected: `[
{
"kind": "const",
"name": "l/ANSWER",
"type": "uint16",
"value": "42"
},
{
"kind": "const",
"name": "l/ANSWER_IN_BINARY",
"type": "uint16",
"value": "42"
},
{
"kind": "const",
"name": "l/CONVERSION_FACTOR",
"type": "float64",
"value": "1.41421"
},
{
"kind": "const",
"name": "l/DIAMOND",
"type": "uint64",
"value": "1746410393481133080"
},
{
"kind": "const",
"name": "l/ENABLED_FLAG",
"type": "bool",
"value": "true"
},
{
"kind": "const",
"name": "l/FUCHSIA",
"type": "uint64",
"value": "4054509061583223046"
},
{
"kind": "const",
"name": "l/MIN_TEMP",
"type": "float32",
"value": "-273.15"
},
{
"kind": "const",
"name": "l/OFFSET",
"type": "int8",
"value": "-33"
},
{
"kind": "const",
"name": "l/POPULATION_USA_2018",
"type": "uint32",
"value": "330000000"
},
{
"kind": "const",
"name": "l/USERNAME",
"type": "string",
"value": "squeenze"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "primitives 5, binary operator",
fidl: `
library l;
const FOO uint8 = 1;
const BAR uint8 = 2;
const BAZ uint8 = FOO | BAR;
`,
expected: `[
{
"kind": "const",
"name": "l/BAR",
"type": "uint8",
"value": "2"
},
{
"kind": "const",
"name": "l/BAZ",
"type": "uint8",
"value": "3"
},
{
"kind": "const",
"name": "l/FOO",
"type": "uint8",
"value": "1"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "bits",
fidl: `
library l;
type Bits1 = strict bits {
BIT1 = 0x01;
BIT2 = 0x02;
};
`,
expected: `[
{
"kind": "bits/member",
"name": "l/Bits1.BIT1",
"value": "1"
},
{
"kind": "bits/member",
"name": "l/Bits1.BIT2",
"value": "2"
},
{
"kind": "bits",
"name": "l/Bits1",
"strictness": "strict",
"type": "uint32"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "bits 2",
fidl: `
library l;
type Bits1 = strict bits {
BIT1 = 0x01;
BIT2 = 0x02;
};
type Bits2 = strict bits {
BIT1 = 0x01;
BIT2 = 0x02;
};
`,
expected: `[
{
"kind": "bits/member",
"name": "l/Bits1.BIT1",
"value": "1"
},
{
"kind": "bits/member",
"name": "l/Bits1.BIT2",
"value": "2"
},
{
"kind": "bits",
"name": "l/Bits1",
"strictness": "strict",
"type": "uint32"
},
{
"kind": "bits/member",
"name": "l/Bits2.BIT1",
"value": "1"
},
{
"kind": "bits/member",
"name": "l/Bits2.BIT2",
"value": "2"
},
{
"kind": "bits",
"name": "l/Bits2",
"strictness": "strict",
"type": "uint32"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "bits 3",
fidl: `
library l;
type Bits = flexible bits : uint8 {
BIT1 = 0x01;
BIT2 = 0x02;
};
`,
expected: `[
{
"kind": "bits/member",
"name": "l/Bits.BIT1",
"value": "1"
},
{
"kind": "bits/member",
"name": "l/Bits.BIT2",
"value": "2"
},
{
"kind": "bits",
"name": "l/Bits",
"strictness": "flexible",
"type": "uint8"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "enums",
fidl: `
library l;
type Beverage = flexible enum : uint8 {
WATER = 0;
COFFEE = 1;
TEA = 2;
WHISKEY = 3;
};
// Underlying type is assumed to be uint32.
type Vessel = strict enum {
CUP = 0;
BOWL = 1;
TUREEN = 2;
JUG = 3;
};
`,
expected: `[
{
"kind": "enum/member",
"name": "l/Beverage.COFFEE",
"value": "1"
},
{
"kind": "enum/member",
"name": "l/Beverage.TEA",
"value": "2"
},
{
"kind": "enum/member",
"name": "l/Beverage.WATER",
"value": "0"
},
{
"kind": "enum/member",
"name": "l/Beverage.WHISKEY",
"value": "3"
},
{
"kind": "enum",
"name": "l/Beverage",
"strictness": "flexible",
"type": "uint8"
},
{
"kind": "enum/member",
"name": "l/Vessel.BOWL",
"value": "1"
},
{
"kind": "enum/member",
"name": "l/Vessel.CUP",
"value": "0"
},
{
"kind": "enum/member",
"name": "l/Vessel.JUG",
"value": "3"
},
{
"kind": "enum/member",
"name": "l/Vessel.TUREEN",
"value": "2"
},
{
"kind": "enum",
"name": "l/Vessel",
"strictness": "strict",
"type": "uint32"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "struct as precondition for arrays",
fidl: `
library l;
type S = struct {
x float32;
};
`,
expected: `[
{
"kind": "struct/member",
"name": "l/S.x",
"ordinal": "1",
"type": "float32"
},
{
"kind": "struct",
"name": "l/S"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "struct with an element with default value",
fidl: `
library l;
const VALUE string = "booyah!";
type S = struct {
@allow_deprecated_struct_defaults
x float32 = 0.314159;
@allow_deprecated_struct_defaults
foo string = "huzzah";
@allow_deprecated_struct_defaults
bar bool = true;
@allow_deprecated_struct_defaults
baz string = VALUE;
};
`,
expected: `[
{
"kind": "struct/member",
"name": "l/S.bar",
"ordinal": "3",
"type": "bool",
"value": "true"
},
{
"kind": "struct/member",
"name": "l/S.baz",
"ordinal": "4",
"type": "string",
"value": "booyah!"
},
{
"kind": "struct/member",
"name": "l/S.foo",
"ordinal": "2",
"type": "string",
"value": "huzzah"
},
{
"kind": "struct/member",
"name": "l/S.x",
"ordinal": "1",
"type": "float32",
"value": "0.314159"
},
{
"kind": "struct",
"name": "l/S"
},
{
"kind": "const",
"name": "l/VALUE",
"type": "string",
"value": "booyah!"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "arrays",
fidl: `
library l;
type Arrays = struct {
form array<float32, 16>;
matrix array<array<string, 4>, 10>;
};
`,
expected: `[
{
"kind": "struct/member",
"name": "l/Arrays.form",
"ordinal": "1",
"type": "array<float32,16>"
},
{
"kind": "struct/member",
"name": "l/Arrays.matrix",
"ordinal": "2",
"type": "array<array<string,4>,10>"
},
{
"kind": "struct",
"name": "l/Arrays"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "strings",
fidl: `
library l;
type Document = struct {
title string:40;
description string:optional;
};
`,
expected: `[
{
"kind": "struct/member",
"name": "l/Document.description",
"ordinal": "2",
"type": "string:optional"
},
{
"kind": "struct/member",
"name": "l/Document.title",
"ordinal": "1",
"type": "string:40"
},
{
"kind": "struct",
"name": "l/Document"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "vectors",
fidl: `
library l;
type Vectors = struct {
params vector<int32>:10;
blob vector<uint8>;
nullable_vector_of_strings vector<string>:<24, optional>;
vector_of_nullable_strings vector<string:optional>;
complex vector<vector<array<float32, 16>>>;
};
`,
expected: `[
{
"kind": "struct/member",
"name": "l/Vectors.blob",
"ordinal": "2",
"type": "vector<uint8>"
},
{
"kind": "struct/member",
"name": "l/Vectors.complex",
"ordinal": "5",
"type": "vector<vector<array<float32,16>>>"
},
{
"kind": "struct/member",
"name": "l/Vectors.nullable_vector_of_strings",
"ordinal": "3",
"type": "vector<string>:<24,optional>"
},
{
"kind": "struct/member",
"name": "l/Vectors.params",
"ordinal": "1",
"type": "vector<int32>:10"
},
{
"kind": "struct/member",
"name": "l/Vectors.vector_of_nullable_strings",
"ordinal": "4",
"type": "vector<string:optional>"
},
{
"kind": "struct",
"name": "l/Vectors"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "handles",
dep: zxLibrary,
fidl: `
library l;
using zx;
type Handles = resource struct {
h zx.Handle;
c zx.Handle:<CHANNEL, optional>;
};
`,
expected: `[
{
"kind": "struct/member",
"name": "l/Handles.c",
"ordinal": "2",
"type": "zx/Handle:<CHANNEL,optional>"
},
{
"kind": "struct/member",
"name": "l/Handles.h",
"ordinal": "1",
"type": "zx/Handle"
},
{
"kind": "struct",
"name": "l/Handles",
"resourceness": "resource"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "struct local type reference",
fidl: `
library l;
type A = struct {};
type B = struct {
a A;
};
`,
expected: `[
{
"kind": "struct",
"name": "l/A"
},
{
"kind": "struct/member",
"name": "l/B.a",
"ordinal": "1",
"type": "l/A"
},
{
"kind": "struct",
"name": "l/B"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "structs 2",
fidl: `
library l;
type CirclePoint = struct {
x float32;
y float32;
};
type Color = struct {
r float32;
g float32;
b float32;
};
type Circle = struct {
filled bool;
center CirclePoint;
radius float32;
color box<Color>;
dashed bool;
};
`,
expected: `[
{
"kind": "struct/member",
"name": "l/Circle.center",
"ordinal": "2",
"type": "l/CirclePoint"
},
{
"kind": "struct/member",
"name": "l/Circle.color",
"ordinal": "4",
"type": "box<l/Color>"
},
{
"kind": "struct/member",
"name": "l/Circle.dashed",
"ordinal": "5",
"type": "bool"
},
{
"kind": "struct/member",
"name": "l/Circle.filled",
"ordinal": "1",
"type": "bool"
},
{
"kind": "struct/member",
"name": "l/Circle.radius",
"ordinal": "3",
"type": "float32"
},
{
"kind": "struct",
"name": "l/Circle"
},
{
"kind": "struct/member",
"name": "l/CirclePoint.x",
"ordinal": "1",
"type": "float32"
},
{
"kind": "struct/member",
"name": "l/CirclePoint.y",
"ordinal": "2",
"type": "float32"
},
{
"kind": "struct",
"name": "l/CirclePoint"
},
{
"kind": "struct/member",
"name": "l/Color.b",
"ordinal": "3",
"type": "float32"
},
{
"kind": "struct/member",
"name": "l/Color.g",
"ordinal": "2",
"type": "float32"
},
{
"kind": "struct/member",
"name": "l/Color.r",
"ordinal": "1",
"type": "float32"
},
{
"kind": "struct",
"name": "l/Color"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "tables",
fidl: `
library l;
type Profile = table {
1: locales vector<string>;
2: calendars vector<string>;
3: time_zones vector<string>;
};
`,
expected: `[
{
"kind": "table/member",
"name": "l/Profile.calendars",
"ordinal": "2",
"type": "vector<string>"
},
{
"kind": "table/member",
"name": "l/Profile.locales",
"ordinal": "1",
"type": "vector<string>"
},
{
"kind": "table/member",
"name": "l/Profile.time_zones",
"ordinal": "3",
"type": "vector<string>"
},
{
"kind": "table",
"name": "l/Profile"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "unions",
fidl: `
library l;
type Left = struct {};
type Right = struct {};
type Either = strict union {
1: left Left;
2: right Right;
};
`,
expected: `[
{
"kind": "union/member",
"name": "l/Either.left",
"ordinal": "1",
"type": "l/Left"
},
{
"kind": "union/member",
"name": "l/Either.right",
"ordinal": "2",
"type": "l/Right"
},
{
"kind": "union",
"name": "l/Either",
"strictness": "strict"
},
{
"kind": "struct",
"name": "l/Left"
},
{
"kind": "struct",
"name": "l/Right"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "protocols 1",
fidl: `
library l;
closed protocol Calculator {
strict Add(struct { a int32; b int32; }) -> (struct { sum int32; });
};
`,
expected: `[
{
"kind": "protocol/member",
"name": "l/Calculator.Add",
"strictness": "strict",
"ordinal": "250442423443911233",
"direction": "two_way",
"request": "l/CalculatorAddRequest",
"response": "l/CalculatorAddResponse"
},
{
"kind": "protocol",
"name": "l/Calculator",
"openness": "closed",
"transport": "channel"
},
{
"kind": "struct/member",
"name": "l/CalculatorAddRequest.a",
"ordinal": "1",
"type": "int32"
},
{
"kind": "struct/member",
"name": "l/CalculatorAddRequest.b",
"ordinal": "2",
"type": "int32"
},
{
"kind": "struct",
"name": "l/CalculatorAddRequest"
},
{
"kind": "struct/member",
"name": "l/CalculatorAddResponse.sum",
"ordinal": "1",
"type": "int32"
},
{
"kind": "struct",
"name": "l/CalculatorAddResponse"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "protocols 2",
fidl: `
library l;
type Foo = struct {};
type Bar = struct {};
open protocol P {
flexible M(struct { b box<Bar>; }) -> (struct { c Foo; });
};
`,
expected: `[
{
"kind": "struct",
"name": "l/Bar"
},
{
"kind": "struct",
"name": "l/Foo"
},
{
"kind": "protocol/member",
"name": "l/P.M",
"strictness": "flexible",
"ordinal": "1416054259560567967",
"direction": "two_way",
"request": "l/PMRequest",
"response": "l/P_M_Response"
},
{
"kind": "protocol",
"name": "l/P",
"openness": "open",
"transport": "channel"
},
{
"kind": "struct/member",
"name": "l/PMRequest.b",
"ordinal": "1",
"type": "box<l/Bar>"
},
{
"kind": "struct",
"name": "l/PMRequest"
},
{
"kind": "struct/member",
"name": "l/P_M_Response.c",
"ordinal": "1",
"type": "l/Foo"
},
{
"kind": "struct",
"name": "l/P_M_Response"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "protocols 3",
fidl: `
library l;
type Bar = struct {};
closed protocol P {};
closed protocol P2 {
strict M1(resource struct { a client_end:P; });
strict M2(resource struct { a client_end:<P, optional>; });
strict M3(resource struct { a server_end:<P>; });
strict M4(resource struct { a server_end:<P, optional>; });
};
`,
expected: `[
{
"kind": "struct",
"name": "l/Bar"
},
{
"kind": "protocol",
"name": "l/P",
"openness": "closed",
"transport": "channel"
},
{
"kind": "protocol/member",
"name": "l/P2.M1",
"strictness": "strict",
"ordinal": "837411832102395320",
"direction": "one_way",
"request": "l/P2M1Request"
},
{
"kind": "protocol/member",
"name": "l/P2.M2",
"strictness": "strict",
"ordinal": "7643406716745546297",
"direction": "one_way",
"request": "l/P2M2Request"
},
{
"kind": "protocol/member",
"name": "l/P2.M3",
"strictness": "strict",
"ordinal": "2712856865629095774",
"direction": "one_way",
"request": "l/P2M3Request"
},
{
"kind": "protocol/member",
"name": "l/P2.M4",
"strictness": "strict",
"ordinal": "8900715097515580538",
"direction": "one_way",
"request": "l/P2M4Request"
},
{
"kind": "protocol",
"name": "l/P2",
"openness": "closed",
"transport": "channel"
},
{
"kind": "struct/member",
"name": "l/P2M1Request.a",
"ordinal": "1",
"type": "client_end:l/P"
},
{
"kind": "struct",
"name": "l/P2M1Request",
"resourceness": "resource"
},
{
"kind": "struct/member",
"name": "l/P2M2Request.a",
"ordinal": "1",
"type": "client_end:<l/P,optional>"
},
{
"kind": "struct",
"name": "l/P2M2Request",
"resourceness": "resource"
},
{
"kind": "struct/member",
"name": "l/P2M3Request.a",
"ordinal": "1",
"type": "server_end:l/P"
},
{
"kind": "struct",
"name": "l/P2M3Request",
"resourceness": "resource"
},
{
"kind": "struct/member",
"name": "l/P2M4Request.a",
"ordinal": "1",
"type": "server_end:<l/P,optional>"
},
{
"kind": "struct",
"name": "l/P2M4Request",
"resourceness": "resource"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "protocols 4",
fidl: `
library l;
closed protocol P {
strict -> F1(struct { a int32; });
strict F2() -> (struct { a int32; });
strict F3() -> () error int32;
strict F4();
};
`,
expected: `[
{
"kind": "protocol/member",
"name": "l/P.F1",
"strictness": "strict",
"ordinal": "5135084091202286418",
"direction": "event",
"request": "l/PF1Request"
},
{
"kind": "protocol/member",
"name": "l/P.F2",
"strictness": "strict",
"ordinal": "2448214607574469420",
"direction": "two_way",
"response": "l/PF2Response"
},
{
"kind": "protocol/member",
"name": "l/P.F3",
"strictness": "strict",
"ordinal": "542295173779636617",
"direction": "two_way",
"response": "l/P_F3_Response",
"error": "int32"
},
{
"kind": "protocol/member",
"name": "l/P.F4",
"strictness": "strict",
"ordinal": "7474367752247153959",
"direction": "one_way"
},
{
"kind": "protocol",
"name": "l/P",
"openness": "closed",
"transport": "channel"
},
{
"kind": "struct/member",
"name": "l/PF1Request.a",
"ordinal": "1",
"type": "int32"
},
{
"kind": "struct",
"name": "l/PF1Request"
},
{
"kind": "struct/member",
"name": "l/PF2Response.a",
"ordinal": "1",
"type": "int32"
},
{
"kind": "struct",
"name": "l/PF2Response"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "protocols with named payloads",
fidl: `
library l;
type Payload = struct {
a bool;
};
closed protocol P {
strict -> M1(Payload);
strict M2() -> (Payload) error uint32;
};
`,
expected: `[
{
"kind": "protocol/member",
"name": "l/P.M1",
"strictness": "strict",
"ordinal": "6412048159635322006",
"direction": "event",
"request": "l/Payload"
},
{
"kind": "protocol/member",
"name": "l/P.M2",
"strictness": "strict",
"ordinal": "4975997396601956357",
"direction": "two_way",
"response": "l/Payload",
"error": "uint32"
},
{
"kind": "protocol",
"name": "l/P",
"openness": "closed",
"transport": "channel"
},
{
"kind": "struct/member",
"name": "l/Payload.a",
"ordinal": "1",
"type": "bool"
},
{
"kind": "struct",
"name": "l/Payload"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "protocols with non-struct payloads",
fidl: `
library l;
type U = flexible union {
1: a uint64;
};
type T = table {
1: b int32;
};
closed protocol P {
strict M1(U)-> (T);
strict M2(table {1: c bool; })-> (strict union {1: d uint32; });
};
`,
expected: `[
{
"kind": "protocol/member",
"name": "l/P.M1",
"strictness": "strict",
"ordinal": "6412048159635322006",
"direction": "two_way",
"request": "l/U",
"response": "l/T"
},
{
"kind": "protocol/member",
"name": "l/P.M2",
"strictness": "strict",
"ordinal": "4975997396601956357",
"direction": "two_way",
"request": "l/PM2Request",
"response": "l/PM2Response"
},
{
"kind": "protocol",
"name": "l/P",
"openness": "closed",
"transport": "channel"
},
{
"kind": "table/member",
"name": "l/PM2Request.c",
"ordinal": "1",
"type": "bool"
},
{
"kind": "table",
"name": "l/PM2Request"
},
{
"kind": "union/member",
"name": "l/PM2Response.d",
"ordinal": "1",
"type": "uint32"
},
{
"kind": "union",
"name": "l/PM2Response",
"strictness": "strict"
},
{
"kind": "table/member",
"name": "l/T.b",
"ordinal": "1",
"type": "int32"
},
{
"kind": "table",
"name": "l/T"
},
{
"kind": "union/member",
"name": "l/U.a",
"ordinal": "1",
"type": "uint64"
},
{
"kind": "union",
"name": "l/U",
"strictness": "flexible"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "protocols with errorable non-struct payloads",
fidl: `
library l;
type T = table {
1: b string;
};
closed protocol P {
strict M1() -> (flexible union { 1: a bool; }) error uint32;
strict M2() -> (T) error int32;
};
`,
expected: `[
{
"kind": "protocol/member",
"name": "l/P.M1",
"strictness": "strict",
"ordinal": "6412048159635322006",
"direction": "two_way",
"response": "l/P_M1_Response",
"error": "uint32"
},
{
"kind": "protocol/member",
"name": "l/P.M2",
"strictness": "strict",
"ordinal": "4975997396601956357",
"direction": "two_way",
"response": "l/T",
"error": "int32"
},
{
"kind": "protocol",
"name": "l/P",
"openness": "closed",
"transport": "channel"
},
{
"kind": "union/member",
"name": "l/P_M1_Response.a",
"ordinal": "1",
"type": "bool"
},
{
"kind": "union",
"name": "l/P_M1_Response",
"strictness": "flexible"
},
{
"kind": "table/member",
"name": "l/T.b",
"ordinal": "1",
"type": "string"
},
{
"kind": "table",
"name": "l/T"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "check types",
fidl: `
library l;
type S = struct {
f1 string;
f2 string:4;
f3 string:<4, optional>;
};
`,
expected: `[
{
"kind": "struct/member",
"name": "l/S.f1",
"ordinal": "1",
"type": "string"
},
{
"kind": "struct/member",
"name": "l/S.f2",
"ordinal": "2",
"type": "string:4"
},
{
"kind": "struct/member",
"name": "l/S.f3",
"ordinal": "3",
"type": "string:<4,optional>"
},
{
"kind": "struct",
"name": "l/S"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "with foreign library",
dep: l2Library,
fidl: `
library l;
using l2;
type A = struct {
a l2.T;
};
`,
expected: `[
{
"kind": "struct/member",
"name": "l/A.a",
"ordinal": "1",
"type": "l2/T"
},
{
"kind": "struct",
"name": "l/A"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "protocol with foreign library",
dep: l2Library,
fidl: `
library l;
using l2;
type Foo = struct {};
type Bar = struct {};
closed protocol Calculator {
compose l2.Inverter;
strict Halve(l2.UnaryArg) -> (l2.UnaryArg);
strict Add(struct { a l2.T; b Bar; }) -> (struct { c Foo; });
};
`,
expected: `[
{
"kind": "struct",
"name": "l/Bar"
},
{
"kind": "protocol/member",
"name": "l/Calculator.Add",
"strictness": "strict",
"ordinal": "250442423443911233",
"direction": "two_way",
"request": "l/CalculatorAddRequest",
"response": "l/CalculatorAddResponse"
},
{
"kind": "protocol/member",
"name": "l/Calculator.Halve",
"strictness": "strict",
"ordinal": "7372493581703395840",
"direction": "two_way",
"request": "l2/UnaryArg",
"response": "l2/UnaryArg"
},
{
"kind": "protocol/member",
"name": "l/Calculator.Invert",
"strictness": "strict",
"ordinal": "2134776808183153853",
"direction": "two_way",
"request": "l2/UnaryArg",
"response": "l2/UnaryArg"
},
{
"kind": "protocol",
"name": "l/Calculator",
"openness": "closed",
"transport": "channel"
},
{
"kind": "struct/member",
"name": "l/CalculatorAddRequest.a",
"ordinal": "1",
"type": "l2/T"
},
{
"kind": "struct/member",
"name": "l/CalculatorAddRequest.b",
"ordinal": "2",
"type": "l/Bar"
},
{
"kind": "struct",
"name": "l/CalculatorAddRequest"
},
{
"kind": "struct/member",
"name": "l/CalculatorAddResponse.c",
"ordinal": "1",
"type": "l/Foo"
},
{
"kind": "struct",
"name": "l/CalculatorAddResponse"
},
{
"kind": "struct",
"name": "l/Foo"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "compose foreign method with table response",
dep: l2Library,
fidl: `
library l;
using l2;
closed protocol P {
compose l2.TableResponse;
};
`,
expected: `[
{
"kind": "protocol/member",
"name": "l/P.Foo",
"strictness": "strict",
"ordinal": "3518338923794038768",
"direction": "two_way",
"response": "l2/TableResponseFooResponse"
},
{
"kind": "protocol",
"name": "l/P",
"openness": "closed",
"transport": "channel"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
{
name: "compose foreign method with error syntax",
dep: l2Library,
fidl: `
library l;
using l2;
closed protocol P {
compose l2.ErrorSyntax;
};
`,
expected: `[
{
"kind": "protocol/member",
"name": "l/P.Foo",
"strictness": "strict",
"ordinal": "1974636303379855936",
"direction": "two_way",
"response": "l2/ErrorSyntax_Foo_Response",
"error": "uint32"
},
{
"kind": "protocol",
"name": "l/P",
"openness": "closed",
"transport": "channel"
},
{
"kind": "library",
"name": "l"
}
]
`,
},
}
runGenerateSummaryTests(t, tests)
}
func runGenerateSummaryTests(t *testing.T, tests []summaryTestCase) {
t.Helper()
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
c := fidlgentest.EndToEndTest{T: t}
if test.dep != "" {
c = c.WithDependency(test.dep)
}
r := c.Single(test.fidl)
s := Summarize(r)
var b strings.Builder
if err := s.WriteJSON(&b); err != nil {
t.Fatalf("while writing JOSN: %v", err)
}
actual := strings.Split(b.String(), "\n")
expected := strings.Split(test.expected, "\n")
if diff := cmp.Diff(expected, actual); diff != "" {
t.Errorf("got summary diff (-want, +got):\n%s\n", diff)
}
})
}
}
func TestLoadSummariesJSON(t *testing.T) {
tests := []struct {
name string
json string
want [][]ElementStr
}{
{
name: "eof",
json: "",
want: [][]ElementStr{{}},
}, {
name: "empty list",
json: "[]",
want: [][]ElementStr{{}},
}, {
name: "library only",
json: `[{"kind": "library", "name": "l"}]`,
want: [][]ElementStr{
{{Kind: libraryKind, Name: "l"}},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
summaries, err := LoadSummariesJSON(strings.NewReader(tt.json))
if err != nil {
t.Fatalf("LoadSummariesJSON(%q) got unexpected error: %v", tt.json, err)
}
if diff := cmp.Diff(tt.want, summaries); diff != "" {
t.Fatalf("LoadSummariesJSON(%q) got diff (-want,+got):\n%s", tt.json, diff)
}
})
}
}
func TestIsEmptyLibrary(t *testing.T) {
tests := []struct {
name string
fidl string
expected bool
}{
{
name: "empty library",
fidl: `
library l;
`,
expected: true,
},
{
name: "empty library with comments",
fidl: `
// Regular comment
/// Doc comment
library l;
`,
expected: true,
},
{
name: "empty library with attribute",
fidl: `
@some_attribute
library l;
`,
expected: true,
},
{
name: "nonempty library removed before HEAD",
fidl: `
@available(platform="example", added=1, removed=2)
library l;
const FOO string = "foo";
`,
expected: true,
},
{
name: "nonempty library",
fidl: `
library l;
const FOO string = "foo";
`,
expected: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
c := fidlgentest.EndToEndTest{T: t}.WithAvailable("example", "HEAD")
r := c.Single(test.fidl)
s := Summarize(r)
actual := s.IsEmptyLibrary()
if actual != test.expected {
t.Errorf("got %v, want %v for IsEmptyLibrary() on FIDL:\n%s\nWith summary:\n%+v", actual, test.expected, test.fidl, s)
}
})
}
}