| // 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 langserver |
| |
| import ( |
| "testing" |
| |
| "github.com/sourcegraph/go-lsp" |
| |
| "fidl-lsp/analysis" |
| ) |
| |
| func TestHover(t *testing.T) { |
| var elementCount uint = 10 |
| |
| cases := []struct { |
| symName string |
| symType analysis.Type |
| hoverText []lsp.MarkedString |
| }{ |
| { |
| symName: "fuchsia.test", |
| symType: analysis.Type{ |
| IsLib: true, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("library fuchsia.test")}, |
| }, |
| { |
| symName: "array_value", |
| symType: analysis.Type{ |
| Kind: analysis.ArrayType, |
| Array: &analysis.ArrayTypeInfo{ |
| ElementType: analysis.Type{ |
| Kind: analysis.PrimitiveType, |
| Primitive: &analysis.PrimitiveTypeInfo{ |
| Subtype: analysis.Uint32, |
| }, |
| }, |
| ElementCount: 10, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("array<uint32>:10")}, |
| }, |
| { |
| symName: "vector_without_size_constraint", |
| symType: analysis.Type{ |
| Kind: analysis.VectorType, |
| Vector: &analysis.VectorTypeInfo{ |
| ElementType: analysis.Type{ |
| Kind: analysis.PrimitiveType, |
| Primitive: &analysis.PrimitiveTypeInfo{ |
| Subtype: analysis.Uint32, |
| }, |
| }, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("vector<uint32>")}, |
| }, |
| { |
| symName: "nullable_vector_with_size_constraint", |
| symType: analysis.Type{ |
| Kind: analysis.VectorType, |
| Vector: &analysis.VectorTypeInfo{ |
| ElementType: analysis.Type{ |
| Kind: analysis.PrimitiveType, |
| Primitive: &analysis.PrimitiveTypeInfo{ |
| Subtype: analysis.Uint32, |
| }, |
| }, |
| ElementCount: &elementCount, |
| Nullable: true, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("vector<uint32>:10?")}, |
| }, |
| { |
| symName: "nullable_string_without_size_constraint", |
| symType: analysis.Type{ |
| Kind: analysis.StringType, |
| String: &analysis.StringTypeInfo{ |
| Nullable: true, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("string?")}, |
| }, |
| { |
| symName: "string_with_size_constraint", |
| symType: analysis.Type{ |
| Kind: analysis.StringType, |
| String: &analysis.StringTypeInfo{ |
| ElementCount: &elementCount, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("string:10")}, |
| }, |
| { |
| symName: "handle", |
| symType: analysis.Type{ |
| Kind: analysis.HandleType, |
| Handle: &analysis.HandleTypeInfo{ |
| Subtype: analysis.Vmo, |
| Nullable: true, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("handle<vmo>?")}, |
| }, |
| { |
| symName: "request", |
| symType: analysis.Type{ |
| Kind: analysis.RequestType, |
| Request: &analysis.RequestTypeInfo{ |
| Subtype: "File", |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("request<File>")}, |
| }, |
| { |
| symName: "primitive_bool", |
| symType: analysis.Type{ |
| Kind: analysis.PrimitiveType, |
| Primitive: &analysis.PrimitiveTypeInfo{ |
| Subtype: analysis.Bool, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("bool")}, |
| }, |
| { |
| symName: "primitive_uint64", |
| symType: analysis.Type{ |
| Kind: analysis.PrimitiveType, |
| Primitive: &analysis.PrimitiveTypeInfo{ |
| Subtype: analysis.Uint64, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("uint64")}, |
| }, |
| { |
| symName: "bits_decl", |
| symType: analysis.Type{ |
| Kind: analysis.IdentifierType, |
| Identifier: &analysis.IdentifierTypeInfo{ |
| IsDecl: true, |
| Name: "fuchsia.test/MyBits", |
| Kind: analysis.BitsKind, |
| Bits: &analysis.BitsTypeInfo{ |
| Type: analysis.Type{ |
| Kind: analysis.PrimitiveType, |
| Primitive: &analysis.PrimitiveTypeInfo{ |
| Subtype: analysis.Uint32, |
| }, |
| }, |
| }, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("bits fuchsia.test/MyBits: uint32")}, |
| }, |
| { |
| symName: "enum_decl", |
| symType: analysis.Type{ |
| Kind: analysis.IdentifierType, |
| Identifier: &analysis.IdentifierTypeInfo{ |
| IsDecl: true, |
| Name: "fuchsia.test/MyEnum", |
| Kind: analysis.EnumKind, |
| Enum: &analysis.EnumTypeInfo{ |
| Type: "string", |
| }, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("enum fuchsia.test/MyEnum: string")}, |
| }, |
| { |
| symName: "const_decl", |
| symType: analysis.Type{ |
| Kind: analysis.IdentifierType, |
| Identifier: &analysis.IdentifierTypeInfo{ |
| IsDecl: true, |
| Name: "fuchsia.test/MyConst", |
| Kind: analysis.ConstKind, |
| Const: &analysis.ConstTypeInfo{ |
| Type: analysis.Type{ |
| Kind: analysis.StringType, |
| String: &analysis.StringTypeInfo{}, |
| }, |
| Value: "hello, world!", |
| }, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("const string fuchsia.test/MyConst = `hello, world!`")}, |
| }, |
| { |
| symName: "protocol_decl", |
| symType: analysis.Type{ |
| Kind: analysis.IdentifierType, |
| Identifier: &analysis.IdentifierTypeInfo{ |
| IsDecl: true, |
| Name: "fuchsia.test/MyProtocol", |
| Kind: analysis.ProtocolKind, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("protocol fuchsia.test/MyProtocol")}, |
| }, |
| { |
| symName: "service_decl", |
| symType: analysis.Type{ |
| Kind: analysis.IdentifierType, |
| Identifier: &analysis.IdentifierTypeInfo{ |
| IsDecl: true, |
| Name: "fuchsia.test/MyService", |
| Kind: analysis.ServiceKind, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("service fuchsia.test/MyService")}, |
| }, |
| { |
| symName: "struct_decl", |
| symType: analysis.Type{ |
| Kind: analysis.IdentifierType, |
| Identifier: &analysis.IdentifierTypeInfo{ |
| IsDecl: true, |
| Name: "fuchsia.test/MyStruct", |
| Kind: analysis.StructKind, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("struct fuchsia.test/MyStruct")}, |
| }, |
| { |
| symName: "table_decl", |
| symType: analysis.Type{ |
| Kind: analysis.IdentifierType, |
| Identifier: &analysis.IdentifierTypeInfo{ |
| IsDecl: true, |
| Name: "fuchsia.test/MyTable", |
| Kind: analysis.TableKind, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("table fuchsia.test/MyTable")}, |
| }, |
| { |
| symName: "union_decl", |
| symType: analysis.Type{ |
| Kind: analysis.IdentifierType, |
| Identifier: &analysis.IdentifierTypeInfo{ |
| IsDecl: true, |
| Name: "fuchsia.test/MyUnion", |
| Kind: analysis.UnionKind, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("union fuchsia.test/MyUnion")}, |
| }, |
| { |
| symName: "type_alias_decl", |
| symType: analysis.Type{ |
| Kind: analysis.IdentifierType, |
| Identifier: &analysis.IdentifierTypeInfo{ |
| IsDecl: true, |
| Name: "fuchsia.test/AliasToVectorOfBools", |
| Kind: analysis.TypeAliasKind, |
| TypeAlias: &analysis.TypeAliasTypeInfo{ |
| Type: analysis.Type{ |
| Kind: analysis.VectorType, |
| Vector: &analysis.VectorTypeInfo{ |
| ElementType: analysis.Type{ |
| Kind: analysis.PrimitiveType, |
| Primitive: &analysis.PrimitiveTypeInfo{ |
| Subtype: analysis.Bool, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("fuchsia.test/AliasToVectorOfBools: alias to vector<bool>")}, |
| }, |
| { |
| symName: "nullable_struct_param", |
| symType: analysis.Type{ |
| Kind: analysis.IdentifierType, |
| Identifier: &analysis.IdentifierTypeInfo{ |
| IsDecl: false, |
| Identifier: "fuchsia.test/MyStruct", |
| Nullable: true, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{newFIDLString("fuchsia.test/MyStruct?")}, |
| }, |
| { |
| symName: "type_with_attributes", |
| symType: analysis.Type{ |
| Kind: analysis.IdentifierType, |
| Identifier: &analysis.IdentifierTypeInfo{ |
| IsDecl: true, |
| Name: "fuchsia.test/MyProtocol", |
| Kind: analysis.ProtocolKind, |
| }, |
| Attrs: []analysis.Attribute{ |
| { |
| Name: "Doc", |
| Value: "Example doc comments on MyProtocol", |
| }, |
| {Name: "Transitional"}, |
| { |
| Name: "OtherAttribute", |
| Value: "AttributeValue", |
| }, |
| }, |
| }, |
| hoverText: []lsp.MarkedString{ |
| lsp.RawMarkedString(`Example doc comments on MyProtocol`), |
| newFIDLString(`[Transitional, OtherAttribute = "AttributeValue"]`), |
| newFIDLString(`protocol fuchsia.test/MyProtocol`), |
| }, |
| }, |
| } |
| |
| for _, ex := range cases { |
| hoverText, err := symbolTypeToMarkedStrings(ex.symName, ex.symType) |
| if err != nil { |
| t.Errorf("could not get hover text for symbol `%s`: %s", ex.symName, err) |
| continue |
| } |
| if len(hoverText) != len(ex.hoverText) { |
| t.Errorf( |
| "incorrect number of marked strings for symbol `%s`: expected %d, got %d", |
| ex.symName, |
| len(ex.hoverText), |
| len(hoverText), |
| ) |
| continue |
| } |
| for i, expMarkedString := range ex.hoverText { |
| if hoverText[i] != expMarkedString { |
| t.Errorf( |
| "incorrect hoverText for symbol `%s`: expected %v, got %v", |
| ex.symName, |
| expMarkedString, |
| hoverText[i], |
| ) |
| } |
| } |
| } |
| } |
| |
| func TestHoverInvalidType(t *testing.T) { |
| _, err := symbolTypeToMarkedStrings( |
| "invalid_type", |
| analysis.Type{ |
| Kind: analysis.PrimitiveType, |
| Array: &analysis.ArrayTypeInfo{ |
| ElementType: analysis.Type{ |
| Kind: analysis.PrimitiveType, |
| Primitive: &analysis.PrimitiveTypeInfo{ |
| Subtype: analysis.Uint64, |
| }, |
| }, |
| ElementCount: 255, |
| }, |
| }, |
| ) |
| if err == nil { |
| t.Errorf("expect error for hover text on invalid type") |
| } |
| } |