kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/serving/identifiers/identifiers_test.go (about)

     1  /*
     2   * Copyright 2017 The Kythe Authors. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *   http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package identifiers
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"kythe.io/kythe/go/storage/table"
    24  	"kythe.io/kythe/go/test/testutil"
    25  
    26  	"google.golang.org/protobuf/proto"
    27  
    28  	ipb "kythe.io/kythe/proto/identifier_go_proto"
    29  	srvpb "kythe.io/kythe/proto/serving_go_proto"
    30  )
    31  
    32  var matchTable = Table{testProtoTable{
    33  	"foo::bar": []proto.Message{
    34  		&srvpb.IdentifierMatch{
    35  			Node: []*srvpb.IdentifierMatch_Node{
    36  				node("kythe://corpus?lang=c++", "", "record", "class"),
    37  			},
    38  			BaseName:      "bar",
    39  			QualifiedName: "foo::bar",
    40  		},
    41  		&srvpb.IdentifierMatch{
    42  			Node: []*srvpb.IdentifierMatch_Node{
    43  				node("kythe://corpus?lang=c++#decl", "kythe://corpus?lang=c++", "record", "class"),
    44  			},
    45  			BaseName:      "bar",
    46  			QualifiedName: "foo::bar",
    47  		},
    48  		&srvpb.IdentifierMatch{
    49  			Node: []*srvpb.IdentifierMatch_Node{
    50  				node("kythe://corpus?lang=rust", "", "record", "struct"),
    51  			},
    52  			BaseName:      "bar",
    53  			QualifiedName: "foo::bar",
    54  		},
    55  	},
    56  
    57  	"foo.bar": []proto.Message{
    58  		&srvpb.IdentifierMatch{
    59  			Node: []*srvpb.IdentifierMatch_Node{
    60  				node("kythe://corpus?lang=java", "kythe://corpus?lang=c++", "record", "interface"),
    61  			},
    62  			BaseName:      "bar",
    63  			QualifiedName: "foo.bar",
    64  		},
    65  	},
    66  
    67  	"com.java.package.Interface": []proto.Message{
    68  		&srvpb.IdentifierMatch{
    69  			Node: []*srvpb.IdentifierMatch_Node{
    70  				node("kythe://habeas?lang=java", "", "record", "interface"),
    71  			},
    72  			BaseName:      "Interface",
    73  			QualifiedName: "com.java.package.Interface",
    74  		},
    75  	},
    76  }}
    77  
    78  var tests = []testCase{
    79  	{
    80  		"Qualified name across languages",
    81  		findRequest("foo::bar", nil, nil, false),
    82  		[]*ipb.FindReply_Match{
    83  			match("kythe://corpus?lang=c++", "record", "class", "bar", "foo::bar"),
    84  			match("kythe://corpus?lang=c++#decl", "record", "class", "bar", "foo::bar"),
    85  			match("kythe://corpus?lang=rust", "record", "struct", "bar", "foo::bar"),
    86  		},
    87  	},
    88  	{
    89  		"Canonical node for Qualified name across languages",
    90  		findRequest("foo::bar", nil, nil, true),
    91  		[]*ipb.FindReply_Match{
    92  			match("kythe://corpus?lang=c++", "record", "class", "bar", "foo::bar"),
    93  			match("kythe://corpus?lang=rust", "record", "struct", "bar", "foo::bar"),
    94  		},
    95  	},
    96  	{
    97  		"Java qualified name",
    98  		findRequest("foo.bar", nil, nil, false),
    99  		[]*ipb.FindReply_Match{
   100  			match("kythe://corpus?lang=java", "record", "interface", "bar", "foo.bar"),
   101  		},
   102  	},
   103  	{
   104  		"Java qualified name with canonical node with a different qualified name",
   105  		findRequest("foo.bar", nil, nil, true),
   106  		[]*ipb.FindReply_Match{
   107  			match("kythe://corpus?lang=java", "record", "interface", "bar", "foo.bar"),
   108  		},
   109  	},
   110  	{
   111  		"Rust only",
   112  		findRequest("foo::bar", nil, []string{"rust"}, false),
   113  		[]*ipb.FindReply_Match{
   114  			match("kythe://corpus?lang=rust", "record", "struct", "bar", "foo::bar"),
   115  		},
   116  	},
   117  	{
   118  		"Corpus filter matches",
   119  		findRequest("com.java.package.Interface", []string{"habeas"}, nil, false),
   120  		[]*ipb.FindReply_Match{
   121  			match("kythe://habeas?lang=java", "record", "interface", "Interface", "com.java.package.Interface"),
   122  		},
   123  	},
   124  	{
   125  		"Corpus filter does not match",
   126  		findRequest("com.java.package.Interface", []string{"corpus"}, nil, false),
   127  		nil,
   128  	},
   129  }
   130  
   131  func TestFind(t *testing.T) {
   132  	for _, test := range tests {
   133  		reply, err := matchTable.Find(context.TODO(), test.Request)
   134  		if err != nil {
   135  			t.Errorf("unexpected error for request %v: %v", test.Request, err)
   136  		}
   137  
   138  		if err := testutil.DeepEqual(test.Matches, reply.Matches); err != nil {
   139  			t.Errorf("Failed %s\n%v", test.Name, err)
   140  		}
   141  	}
   142  }
   143  
   144  func findRequest(qname string, corpora, langs []string, canonicalOnly bool) *ipb.FindRequest {
   145  	return &ipb.FindRequest{
   146  		Identifier:         qname,
   147  		PickCanonicalNodes: canonicalOnly,
   148  		Corpus:             corpora,
   149  		Languages:          langs,
   150  	}
   151  }
   152  
   153  func node(ticket, canonicalNodeTicket, kind, subkind string) *srvpb.IdentifierMatch_Node {
   154  	return &srvpb.IdentifierMatch_Node{
   155  		Ticket:              ticket,
   156  		CanonicalNodeTicket: canonicalNodeTicket,
   157  		NodeKind:            kind,
   158  		NodeSubkind:         subkind,
   159  	}
   160  }
   161  
   162  func match(ticket, kind, subkind, bname, qname string) *ipb.FindReply_Match {
   163  	return &ipb.FindReply_Match{
   164  		Ticket:        ticket,
   165  		NodeKind:      kind,
   166  		NodeSubkind:   subkind,
   167  		BaseName:      bname,
   168  		QualifiedName: qname,
   169  	}
   170  }
   171  
   172  type testCase struct {
   173  	Name    string
   174  	Request *ipb.FindRequest
   175  	Matches []*ipb.FindReply_Match
   176  }
   177  
   178  type testProtoTable map[string][]proto.Message
   179  
   180  func (t testProtoTable) Put(_ context.Context, key []byte, val proto.Message) error {
   181  	t[string(key)] = []proto.Message{val}
   182  	return nil
   183  }
   184  
   185  func (t testProtoTable) Lookup(_ context.Context, key []byte, msg proto.Message) error {
   186  	m, ok := t[string(key)]
   187  	if !ok || len(m) == 0 {
   188  		return table.ErrNoSuchKey
   189  	}
   190  	proto.Merge(msg, m[0])
   191  	return nil
   192  }
   193  
   194  func (t testProtoTable) LookupValues(_ context.Context, key []byte, m proto.Message, f func(proto.Message) error) error {
   195  	for _, val := range t[string(key)] {
   196  		msg := m.ProtoReflect().New().Interface()
   197  		proto.Merge(msg, val)
   198  		if err := f(msg); err == table.ErrStopLookup {
   199  			return nil
   200  		} else if err != nil {
   201  			return err
   202  		}
   203  	}
   204  	return nil
   205  }
   206  
   207  func (t testProtoTable) Buffered() table.BufferedProto { panic("UNIMPLEMENTED") }
   208  
   209  func (t testProtoTable) Close(context.Context) error { return nil }