| // Copyright 2020 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 analysis_test |
| |
| import ( |
| "testing" |
| |
| "fidl-lsp/analysis" |
| "fidl-lsp/state" |
| ) |
| |
| func indexOf(slice []string, elem string) int { |
| for i, v := range slice { |
| if v == elem { |
| return i |
| } |
| } |
| return -1 |
| } |
| |
| func TestFindDepsNoDeps(t *testing.T) { |
| analyzer := analysis.NewAnalyzer(analysis.CompiledLibraries{}) |
| fs := state.NewFileSystem() |
| fs.OpenFile( |
| "file.fidl", |
| `library test;`, |
| ) |
| |
| analyzer.Analyze(fs, "file.fidl") |
| fidlcArgs, err := analyzer.FindDeps(fs, "file.fidl") |
| if err != nil { |
| t.Error(err) |
| } |
| if len(fidlcArgs) != 2 { |
| t.Fatalf("incorrect number of fidlc --files args %d: expected %d", len(fidlcArgs), 2) |
| } |
| } |
| |
| func TestFindDepsDirectImports(t *testing.T) { |
| analyzer := analysis.NewAnalyzer(analysis.CompiledLibraries{ |
| analysis.LibraryName("fuchsia.import1"): analysis.CompiledLibrary{ |
| Files: []string{"import1.fidl"}, |
| }, |
| analysis.LibraryName("fuchsia.import2"): analysis.CompiledLibrary{ |
| Files: []string{"import2.fidl"}, |
| }, |
| }) |
| |
| fs := state.NewFileSystem() |
| fs.OpenFile( |
| "test.fidl", |
| ` |
| library test; |
| using fuchsia.import1; |
| using fuchsia.import2; |
| `, |
| ) |
| |
| analyzer.Analyze(fs, "test.fidl") |
| fidlcArgs, err := analyzer.FindDeps(fs, "test.fidl") |
| if err != nil { |
| t.Error(err) |
| } |
| expArgs := []string{ |
| "--files", "import1.fidl", |
| "--files", "import2.fidl", |
| "--files", |
| } |
| // FindDeps returns the required --files args to fidlc, including the library |
| // itself, which we don't check. So there should be (# of dependencies + 1) |
| // total --files args. |
| if len(fidlcArgs) != len(expArgs)+1 { |
| t.Fatalf("incorrect number of fidlc --files args %d: expected %d", len(fidlcArgs), len(expArgs)+len(fs.Files())) |
| } |
| for _, expArg := range expArgs { |
| if indexOf(fidlcArgs, expArg) == -1 { |
| t.Errorf("missing expected fidlc --files arg %s", expArg) |
| } |
| } |
| } |
| |
| func TestFindDepsIndirectImports(t *testing.T) { |
| analyzer := analysis.NewAnalyzer(analysis.CompiledLibraries{ |
| analysis.LibraryName("fuchsia.import1"): analysis.CompiledLibrary{ |
| Files: []string{"import1.fidl"}, |
| Deps: []analysis.LibraryName{analysis.LibraryName("fuchsia.import2"), analysis.LibraryName("fuchsia.import3")}, |
| }, |
| analysis.LibraryName("fuchsia.import2"): analysis.CompiledLibrary{ |
| Files: []string{"import2.fidl"}, |
| Deps: []analysis.LibraryName{analysis.LibraryName("fuchsia.import4")}, |
| }, |
| analysis.LibraryName("fuchsia.import3"): analysis.CompiledLibrary{ |
| Files: []string{"import3.fidl"}, |
| }, |
| analysis.LibraryName("fuchsia.import4"): analysis.CompiledLibrary{ |
| Files: []string{"import4.fidl"}, |
| }, |
| }) |
| |
| fs := state.NewFileSystem() |
| fs.OpenFile( |
| "test.fidl", |
| ` |
| library test; |
| using fuchsia.import1; // depends on import2, import3 |
| using fuchsia.import2; // depends on import 4 |
| `, |
| ) |
| |
| analyzer.Analyze(fs, "test.fidl") |
| fidlcArgs, err := analyzer.FindDeps(fs, "test.fidl") |
| if err != nil { |
| t.Error(err) |
| } |
| expArgs := []string{ |
| "--files", "import4.fidl", |
| "--files", "import3.fidl", |
| "--files", "import2.fidl", |
| "--files", "import1.fidl", |
| "--files", |
| } |
| if len(fidlcArgs) != len(expArgs)+1 { |
| t.Fatalf("incorrect number of fidlc --files args %d: expected %d", len(fidlcArgs), len(expArgs)+len(fs.Files())) |
| } |
| for _, expArg := range expArgs { |
| if indexOf(fidlcArgs, expArg) == -1 { |
| t.Errorf("missing expected fidlc --files arg %s", expArg) |
| } |
| } |
| if indexOf(fidlcArgs, "import4.fidl") > indexOf(fidlcArgs, "import2.fidl") || |
| indexOf(fidlcArgs, "import3.fidl") > indexOf(fidlcArgs, "import1.fidl") || |
| indexOf(fidlcArgs, "import2.fidl") > indexOf(fidlcArgs, "import1.fidl") { |
| t.Errorf("fidlc --files are not in correct dependency order") |
| } |
| } |
| |
| func TestFindDepsMultiFileLibraries(t *testing.T) { |
| analyzer := analysis.NewAnalyzer(analysis.CompiledLibraries{ |
| analysis.LibraryName("fuchsia.import1"): analysis.CompiledLibrary{ |
| Files: []string{"import1_1.fidl", "import1_2.fidl"}, |
| Deps: []analysis.LibraryName{analysis.LibraryName("fuchsia.import3"), analysis.LibraryName("fuchsia.import4")}, |
| }, |
| analysis.LibraryName("fuchsia.import2"): analysis.CompiledLibrary{ |
| Files: []string{"import2_1.fidl", "import2_2.fidl"}, |
| Deps: []analysis.LibraryName{analysis.LibraryName("fuchsia.import4")}, |
| }, |
| analysis.LibraryName("fuchsia.import3"): analysis.CompiledLibrary{ |
| Files: []string{"import3.fidl"}, |
| }, |
| analysis.LibraryName("fuchsia.import4"): analysis.CompiledLibrary{ |
| Files: []string{"import4_1.fidl", "import4_2.fidl", "import4_3.fidl"}, |
| }, |
| }) |
| |
| fs := state.NewFileSystem() |
| fs.OpenFile( |
| "test1.fidl", |
| ` |
| library test; |
| using fuchsia.import1; // depends on import2, import3 |
| `, |
| ) |
| fs.OpenFile( |
| "test2.fidl", |
| ` |
| library test; |
| using fuchsia.import2; // depends on import 4 |
| `, |
| ) |
| |
| analyzer.Analyze(fs, "test1.fidl") |
| analyzer.Analyze(fs, "test2.fidl") |
| fidlcArgs, err := analyzer.FindDeps(fs, "test1.fidl") |
| if err != nil { |
| t.Error(err) |
| } |
| expArgs := []string{ |
| "--files", "import4_1.fidl", "import4_2.fidl", "import4_3.fidl", |
| "--files", "import3.fidl", |
| "--files", "import2_1.fidl", "import2_2.fidl", |
| "--files", "import1_1.fidl", "import1_2.fidl", |
| "--files", |
| } |
| if len(fidlcArgs) != len(expArgs)+2 { |
| t.Errorf("args: %v\n", fidlcArgs) |
| t.Fatalf("incorrect number of fidlc --files args %d: expected %d", len(fidlcArgs), len(expArgs)+len(fs.Files())) |
| } |
| // We don't test the topological sort, just that all the required files are present. |
| for _, expArg := range expArgs { |
| if indexOf(fidlcArgs, expArg) == -1 { |
| t.Errorf("missing expected fidlc --files arg %s", expArg) |
| } |
| } |
| } |
| |
| func TestFindDepsNoLibraryInFile(t *testing.T) { |
| analyzer := analysis.NewAnalyzer(analysis.CompiledLibraries{}) |
| fs := state.NewFileSystem() |
| fs.OpenFile( |
| "test1.fidl", |
| `const FOO = 0;`, |
| ) |
| |
| analyzer.Analyze(fs, "test1.fidl") |
| if _, err := analyzer.FindDeps(fs, "test1.fidl"); err == nil { |
| t.Errorf("expect error on file with no library") |
| } |
| } |
| |
| func TestFindDepsImportNotInFidlProject(t *testing.T) { |
| analyzer := analysis.NewAnalyzer(analysis.CompiledLibraries{}) |
| fs := state.NewFileSystem() |
| fs.OpenFile( |
| "foo.fidl", |
| ` |
| library foo; |
| using fuchsia.bar; |
| `, |
| ) |
| |
| analyzer.Analyze(fs, "foo.fidl") |
| if _, err := analyzer.FindDeps(fs, "foo.fidl"); err == nil { |
| t.Errorf("expect error on unknown import") |
| } |
| } |
| |
| func TestFindDepsImportCycle(t *testing.T) { |
| analyzer := analysis.NewAnalyzer(analysis.CompiledLibraries{ |
| analysis.LibraryName("fuchsia.foo"): analysis.CompiledLibrary{ |
| Files: []string{"foo.fidl"}, |
| Deps: []analysis.LibraryName{analysis.LibraryName("fuchsia.bar")}, |
| }, |
| analysis.LibraryName("fuchsia.bar"): analysis.CompiledLibrary{ |
| Files: []string{"bar.fidl"}, |
| Deps: []analysis.LibraryName{analysis.LibraryName("fuchsia.foo")}, |
| }, |
| }) |
| |
| fs := state.NewFileSystem() |
| fs.OpenFile( |
| "foo.fidl", |
| ` |
| library fuchsia.foo; |
| using fuchsia.bar; |
| `, |
| ) |
| fs.OpenFile( |
| "bar.fidl", |
| ` |
| library fuchsia.bar; |
| using fuchsia.foo; |
| `, |
| ) |
| |
| analyzer.Analyze(fs, "foo.fidl") |
| analyzer.Analyze(fs, "bar.fidl") |
| if _, err := analyzer.FindDeps(fs, "foo.fidl"); err == nil { |
| t.Errorf("expect error on import cycle") |
| } |
| } |