blob: 6e32a0de424e60a42eca296a2ff26cf5dea1dca5 [file] [log] [blame]
// 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 state_test
import (
"testing"
fidlcommon "fidl-lsp/third_party/common"
"fidl-lsp/state"
)
func TestLibraryOfFile(t *testing.T) {
library, err := state.LibraryOfFile(`library example;`)
if err != nil {
t.Errorf("error getting library of file: %s", err)
}
expLibrary := "example"
if library.FullyQualifiedName() != expLibrary {
t.Errorf("expected library `%s`, got `%s`", expLibrary, library)
}
library, err = state.LibraryOfFile(`
/// Doc comments
library fuchsia.foo.bar;
struct S {};
`)
if err != nil {
t.Errorf("error getting library of file: %s", err)
}
expLibrary = "fuchsia.foo.bar"
if library.FullyQualifiedName() != expLibrary {
t.Errorf("expected library `%s`, got `%s`", expLibrary, library)
}
library, err = state.LibraryOfFile(`library .invalid.name;`)
if err == nil {
t.Error("expect error getting library of file")
}
library, err = state.LibraryOfFile(`library exampl // Missing semicolon`)
if err == nil {
t.Error("expect error getting library of file")
}
}
func TestParseLibraryMatch(t *testing.T) {
library, ok := state.ParseLibraryMatch(`
library example;
// ~~~~~~~ expected range
`)
if !ok {
t.Errorf("error getting library of file")
}
expLibrary := state.LibraryMatch{
Lib: fidlcommon.MustReadLibraryName("example"),
Range: state.Range{
Start: state.Position{Line: 1, Character: 8},
End: state.Position{Line: 1, Character: 15},
},
}
if library != expLibrary {
t.Errorf("expected library `%v`, got `%v`", expLibrary, library)
}
library, ok = state.ParseLibraryMatch(`
/// Doc comments
library fuchsia.foo.bar;
// ~~~~~~~~~~~~~~~ expected range
struct S {};
`)
if !ok {
t.Errorf("error getting library of file")
}
expLibrary = state.LibraryMatch{
Lib: fidlcommon.MustReadLibraryName("fuchsia.foo.bar"),
Range: state.Range{
Start: state.Position{Line: 2, Character: 8},
End: state.Position{Line: 2, Character: 23},
},
}
if library != expLibrary {
t.Errorf("expected library `%v`, got `%v`", expLibrary, library)
}
library, ok = state.ParseLibraryMatch(`library .invalid.name;`)
if ok {
t.Error("expect error getting library of file")
}
library, ok = state.ParseLibraryMatch(`library exampl // Missing semicolon`)
if ok {
t.Error("expect error getting library of file")
}
}
func TestParsePlatformImportsMatch(t *testing.T) {
imports := state.ParsePlatformImportsMatch(`
library example;
using fuchsia.foo.bar;
using fuchsia.baz.qux;
using non.platform.import;
using TypeAlias = uint8;
`)
expImports := []state.LibraryMatch{
{
Lib: fidlcommon.MustReadLibraryName("fuchsia.foo.bar"),
Range: state.Range{
Start: state.Position{Line: 2, Character: 6},
End: state.Position{Line: 2, Character: 21},
},
},
{
Lib: fidlcommon.MustReadLibraryName("fuchsia.baz.qux"),
Range: state.Range{
Start: state.Position{Line: 3, Character: 6},
End: state.Position{Line: 3, Character: 21},
},
},
}
if len(imports) != len(expImports) {
t.Errorf("expected %d imports, found %d", len(expImports), len(imports))
}
for i, expImport := range expImports {
if imports[i] != expImport {
t.Errorf("unexpected import `%v`, expected `%v`", imports[i], expImport)
}
}
}
func TestSymbolAtPos(t *testing.T) {
fs := state.NewFileSystem()
fs.NewFile("test.fidl", `
library example;
using test.import;
struct Foo {
uint8 bar_baz;
};
`)
cases := []struct {
pos state.Position
sym state.Symbol
}{
{
pos: state.Position{Line: 1, Character: 0},
sym: state.Symbol{
Name: "library",
Location: state.Location{
FileID: state.FileID("test.fidl"),
Range: state.Range{
Start: state.Position{Line: 1, Character: 0},
End: state.Position{Line: 1, Character: 7},
},
},
},
},
{
pos: state.Position{Line: 1, Character: 15},
sym: state.Symbol{
Name: "example",
Location: state.Location{
FileID: state.FileID("test.fidl"),
Range: state.Range{
Start: state.Position{Line: 1, Character: 8},
End: state.Position{Line: 1, Character: 15},
},
},
},
},
{
pos: state.Position{Line: 2, Character: 11},
sym: state.Symbol{
Name: "test.import",
Location: state.Location{
FileID: state.FileID("test.fidl"),
Range: state.Range{
Start: state.Position{Line: 2, Character: 6},
End: state.Position{Line: 2, Character: 17},
},
},
},
},
{
pos: state.Position{Line: 4, Character: 10},
sym: state.Symbol{
Name: "Foo",
Location: state.Location{
FileID: state.FileID("test.fidl"),
Range: state.Range{
Start: state.Position{Line: 4, Character: 7},
End: state.Position{Line: 4, Character: 10},
},
},
},
},
{
pos: state.Position{Line: 5, Character: 13},
sym: state.Symbol{
Name: "bar_baz",
Location: state.Location{
FileID: state.FileID("test.fidl"),
Range: state.Range{
Start: state.Position{Line: 5, Character: 10},
End: state.Position{Line: 5, Character: 17},
},
},
},
},
}
for _, ex := range cases {
sym, err := fs.SymbolAtPos(
state.FileID("test.fidl"),
ex.pos,
)
if err != nil {
t.Fatalf("error finding symbol: %s", err)
}
if sym.Name != ex.sym.Name {
t.Fatalf("did not find correct symbol; expected %s, found %s", ex.sym.Name, sym.Name)
}
if sym.Location.FileID != ex.sym.Location.FileID {
t.Fatalf(
"incorrect file; expected %s, found %s",
ex.sym.Location.FileID,
sym.Location.FileID,
)
}
if sym.Location.Range != ex.sym.Location.Range {
t.Fatalf(
"incorrect range; expected %#v, found %#v",
ex.sym.Location.Range,
sym.Location.Range,
)
}
}
}
func TestNoSymbolAtPos(t *testing.T) {
fs := state.NewFileSystem()
fs.NewFile("test.fidl", `
// ^ should not be a symbol
library example;
// ^ should not be a symbol
struct Foo {
// ^ should not be a symbol
uint8 foo;
//^ should not be a symbol
};
.prepended.dot
^ should not be a symbol ('prepended.dot' is a valid symbol)
trailing.dot.
^ should not be a symbol ('trailing.dot' is a valid symbol)
0starts_with_a_number
^ should not be a symbol
ends_with_a_semicolon_
^ should not be a symbol
`)
cases := []state.Position{
{Line: 0, Character: 0},
{Line: 2, Character: 16},
{Line: 5, Character: 11},
{Line: 7, Character: 2},
{Line: 11, Character: 0},
{Line: 13, Character: 13},
{Line: 15, Character: 3},
{Line: 17, Character: 3},
}
for _, ex := range cases {
sym, err := fs.SymbolAtPos(
state.FileID("test.fidl"),
ex,
)
if err == nil {
t.Errorf("expected not to find symbol at position %v, but found %s", ex, sym.Name)
}
}
}