| // Copyright 2022 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 fidlgen_cpp |
| |
| import ( |
| "testing" |
| |
| "go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgen" |
| "go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgentest" |
| ) |
| |
| func expectNames(t *testing.T, decls []fidlgen.Decl, names []string) { |
| if len(decls) != len(names) { |
| t.Errorf("expected %d decls; got %d", len(names), len(decls)) |
| } |
| for i, decl := range decls { |
| if i >= len(names) { |
| break |
| } |
| if string(decl.GetName()) != names[i] { |
| t.Errorf("expected declaration name %s; got %s", names[i], decl.GetName()) |
| } |
| } |
| } |
| |
| func TestIndependentDeclsAreSourceOrdered(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Multiple([]string{ |
| ` |
| library example; |
| |
| const A int32 = 0; |
| |
| type B = enum : int8 { |
| ZERO = 0; |
| }; |
| |
| const C bool = false; |
| `, |
| ` |
| library example; |
| |
| type D = struct { |
| value uint64; |
| }; |
| |
| type E = bits : uint8 { |
| ONE = 0b1; |
| }; |
| `, |
| ` |
| library example; |
| |
| alias F = bool; |
| `, |
| }) |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/A", |
| "example/B", |
| "example/C", |
| "example/D", |
| "example/E", |
| "example/F", |
| }) |
| } |
| |
| func TestInterdependentDeclsAreTopologicallySorted(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Multiple([]string{ |
| ` |
| library example; |
| |
| type A = enum : int32 { |
| ZERO = B; |
| }; |
| |
| const B int32 = 0; |
| `, |
| ` |
| library example; |
| |
| alias C = vector<D>; |
| |
| type D = struct { |
| value G; |
| b E; |
| }; |
| `, |
| ` |
| library example; |
| |
| type E = bits : uint8 { |
| ONE = 0b1; |
| }; |
| |
| alias F = D; |
| |
| alias G = uint64; |
| `, |
| }) |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/B", |
| "example/A", |
| "example/E", |
| "example/G", |
| "example/D", |
| "example/C", |
| "example/F", |
| }) |
| } |
| |
| func TestDirectDependency(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Multiple([]string{ |
| ` |
| library example; |
| |
| const A uint8 = B; |
| const B uint8 = C; |
| const C uint8 = 2; |
| |
| type D = enum : uint8 { |
| MEMBER1 = B; |
| MEMBER2 = 4; |
| }; |
| `, |
| ` |
| library example; |
| |
| type E = bits : uint8 { |
| MEMBER = A; |
| }; |
| |
| const F D = D.MEMBER2; |
| |
| type G = struct { |
| d D; |
| e E; |
| }; |
| `, |
| }) |
| g := NewDeclDepGraph(ir) |
| |
| directDependents := func(t *testing.T, name string) []fidlgen.Decl { |
| dependents, ok := g.GetDirectDependents(fidlgen.EncodedCompoundIdentifier(name)) |
| if !ok { |
| t.Fatalf("unexpected declaration %s", name) |
| } |
| return dependents |
| } |
| |
| expectNames(t, directDependents(t, "example/A"), []string{"example/E"}) |
| expectNames(t, directDependents(t, "example/B"), []string{"example/A", "example/D"}) |
| expectNames(t, directDependents(t, "example/C"), []string{"example/B"}) |
| expectNames(t, directDependents(t, "example/D"), []string{"example/F", "example/G"}) |
| expectNames(t, directDependents(t, "example/E"), []string{"example/G"}) |
| expectNames(t, directDependents(t, "example/G"), []string{}) |
| } |
| |
| func TestConstDeps(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| const A C = B; |
| |
| const B C = C.MEMBER; |
| |
| type C = enum : uint8 { |
| MEMBER = 0; |
| }; |
| |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/C", |
| "example/B", |
| "example/A", |
| }) |
| } |
| |
| func TestBitsDeps(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| type A = bits : uint8 { |
| ONE = B; |
| }; |
| |
| const B uint8 = 1; |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/B", |
| "example/A", |
| }) |
| } |
| |
| func TestEnumDeps(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| type A = enum : uint8 { |
| ZERO = B; |
| }; |
| |
| const B uint8 = 0; |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/B", |
| "example/A", |
| }) |
| } |
| |
| func TestResourceDeps(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| resource_definition A : uint32 { |
| properties { |
| prop1 B; |
| prop2 C; |
| // This property is required for compilation, but is not otherwise under |
| // test. |
| subtype flexible enum : uint32 {}; |
| }; |
| }; |
| |
| type B = enum : uint8 { |
| ZERO = 0; |
| }; |
| type C = bits : uint8 { |
| ONE = 1; |
| }; |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/Subtype", |
| "example/B", |
| "example/C", |
| "example/A", |
| }) |
| } |
| |
| func TestProtocolDeps(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| closed protocol A { |
| compose B; |
| }; |
| |
| closed protocol B { |
| strict Foo() -> (D); |
| |
| strict Bar(C); |
| }; |
| |
| type C = struct { |
| value uint64; |
| }; |
| |
| type D = resource struct{ |
| endpoint client_end:E; |
| }; |
| |
| closed protocol E {}; |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/C", |
| "example/D", |
| "example/B", |
| "example/A", |
| "example/E", // Appears after D since no edges drawn to protocols specified via endpoints. |
| }) |
| } |
| |
| func TestServiceDeps(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| closed protocol A {}; |
| |
| service B { |
| first client_end:A; |
| second client_end:C; |
| }; |
| |
| closed protocol C {}; |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/A", |
| "example/B", // No edges drawn to protocols specified via endpoints. |
| "example/C", |
| }) |
| } |
| |
| func TestStructDeps(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| type A = struct { |
| first uint64; |
| second B; |
| third C; |
| }; |
| |
| type B = struct { |
| value bool; |
| }; |
| |
| alias C = D; |
| |
| type D = enum : uint8 { |
| MEMBER = 0; |
| }; |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/B", |
| "example/D", |
| "example/C", |
| "example/A", |
| }) |
| } |
| |
| func TestTableDeps(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| type A = table { |
| 1: first uint64; |
| 2: second B; |
| 3: third C; |
| }; |
| |
| type B = struct { |
| value bool; |
| }; |
| |
| alias C = D; |
| |
| type D = enum : uint8 { |
| MEMBER = 0; |
| }; |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/B", |
| "example/D", |
| "example/C", |
| "example/A", |
| }) |
| } |
| |
| func TestUnionDeps(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| type A = union { |
| 1: first uint64; |
| 2: second B; |
| 3: third C; |
| }; |
| |
| type B = struct { |
| value bool; |
| }; |
| |
| alias C = D; |
| |
| type D = enum : uint8 { |
| MEMBER = 0; |
| }; |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/B", |
| "example/D", |
| "example/C", |
| "example/A", |
| }) |
| } |
| |
| // TODO(https://fxbug.dev/42057022): Test aliases of aliases too. |
| func TestAliasDeps(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| alias A = B; |
| |
| type B = struct { |
| value bool; |
| }; |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/B", |
| "example/A", |
| }) |
| } |
| |
| func TestNewTypeDeps(t *testing.T) { |
| t.Skip("TODO(https://fxbug.dev/42158155): Support new types") |
| |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| type A = B; |
| |
| alias B = bool; |
| |
| type C = D; |
| |
| type D = struct { |
| value bool; |
| }; |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/B", |
| "example/A", |
| "example/D", |
| "example/C", |
| }) |
| } |
| |
| func TestNoEdgesToNullableTypes(t *testing.T) { |
| ir := fidlgentest.EndToEndTest{T: t}.Single(` |
| library example; |
| |
| type A = struct { |
| nullable box<B>; |
| }; |
| |
| type B = struct { |
| value uint64; |
| }; |
| |
| type C = resource struct { |
| nullable server_end:<D, optional>; |
| }; |
| |
| closed protocol D {}; |
| `) |
| |
| g := NewDeclDepGraph(ir) |
| expectNames(t, g.SortedDecls(), []string{ |
| "example/A", |
| "example/B", |
| "example/C", |
| "example/D", |
| }) |
| } |