func TestNodes(t *testing.T) { st := tbl.Construct(t) for _, node := range tbl.Nodes { reply, err := st.Nodes(ctx, &xpb.NodesRequest{ Ticket: []string{node.Ticket}, }) testutil.FatalOnErrT(t, "NodesRequest error: %v", err) if len(reply.Nodes) != 1 { t.Fatalf("Expected 1 node for %q; found %d: {%v}", node.Ticket, len(reply.Nodes), reply) } else if err := testutil.DeepEqual(nodeInfo(node), reply.Nodes[node.Ticket]); err != nil { t.Fatal(err) } } var tickets []string expected := make(map[string]*xpb.NodeInfo) for _, n := range tbl.Nodes { tickets = append(tickets, n.Ticket) expected[n.Ticket] = nodeInfo(n) } reply, err := st.Nodes(ctx, &xpb.NodesRequest{Ticket: tickets}) testutil.FatalOnErrT(t, "NodesRequest error: %v", err) if err := testutil.DeepEqual(expected, reply.Nodes); err != nil { t.Fatal(err) } }
func TestDecorationsRefs(t *testing.T) { d := tbl.Decorations[1] st := tbl.Construct(t) reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{ Location: &xpb.Location{Ticket: d.File.Ticket}, References: true, Filter: []string{"**"}, }) testutil.FatalOnErrT(t, "DecorationsRequest error: %v", err) if len(reply.SourceText) != 0 { t.Errorf("Unexpected source text: %q", string(reply.SourceText)) } if reply.Encoding != "" { t.Errorf("Unexpected encoding: %q", reply.Encoding) } expected := refs(xrefs.NewNormalizer(d.File.Text), d.Decoration) if err := testutil.DeepEqual(expected, reply.Reference); err != nil { t.Fatal(err) } expectedNodes := nodeInfos(tbl.Nodes[9:11], tbl.Nodes[12:13]) if err := testutil.DeepEqual(expectedNodes, reply.Nodes); err != nil { t.Fatal(err) } }
func TestDecorations(t *testing.T) { xs := newService(t, testEntries) reply, err := xs.Decorations(ctx, &xpb.DecorationsRequest{ Location: &xpb.Location{ Ticket: kytheuri.ToString(testFileVName), }, SourceText: true, References: true, Filter: []string{"**"}, }) if err != nil { t.Fatalf("Error fetching decorations for %+v: %v", testFileVName, err) } if string(reply.SourceText) != testFileContent { t.Errorf("Incorrect file content: %q; Expected: %q", string(reply.SourceText), testFileContent) } if reply.Encoding != testFileEncoding { t.Errorf("Incorrect file encoding: %q; Expected: %q", reply.Encoding, testFileEncoding) } expectedRefs := []*xpb.DecorationsReply_Reference{ { SourceTicket: kytheuri.ToString(testAnchorVName), TargetTicket: kytheuri.ToString(testAnchorTargetVName), Kind: schema.RefEdge, AnchorStart: &xpb.Location_Point{ ByteOffset: 1, LineNumber: 1, ColumnOffset: 1, }, AnchorEnd: &xpb.Location_Point{ ByteOffset: 4, LineNumber: 1, ColumnOffset: 4, }, }, } if err := testutil.DeepEqual(sortRefs(expectedRefs), sortRefs(reply.Reference)); err != nil { t.Error(err) } expectedNodes := nodesToInfos(testNodes[4:6]) if err := testutil.DeepEqual(expectedNodes, sortInfos(reply.Node)); err != nil { t.Error(err) } }
func TestReducer_EmptySplit(t *testing.T) { expectedPivot := testNode("blah", "test", "subkind", "input") // Input for a single node (pivot header only) in := testInput([]*ipb.Path{{ Pivot: expectedPivot, }}) var found *ipb.Path_Node out, err := reduce.Sort(ctx, in, &Reducer{ Func: func(ctx context.Context, pivot *ipb.Path_Node, rio ReducerIO) error { sortKey, p, err := rio.Next() if err != io.EOF { t.Errorf("Unexpected return values: %q %v %v", sortKey, p, err) } if found != nil { t.Errorf("Already found pivot: %v", found) } found = pivot return nil }, }) if err != nil { t.Fatal(err) } if err := testutil.DeepEqual(expectedPivot, found); err != nil { t.Error(err) } if s, err := out.NextSplit(); err != io.EOF { t.Fatalf("Unexpected output/err: %v / %v", s, err) } }
func TestParseOrdinal(t *testing.T) { type ordinalTest struct { // fields exported for the comparator Input, Kind string Ordinal int HasOrdinal bool } tests := []ordinalTest{ {"/kythe/edge/defines", "/kythe/edge/defines", 0, false}, {"/kythe/edge/kind.here", "/kythe/edge/kind.here", 0, false}, {"/kythe/edge/kind1", "/kythe/edge/kind1", 0, false}, {"kind.-1", "kind.-1", 0, false}, {"kind.3", "kind", 3, true}, {"/kythe/edge/param.0", "/kythe/edge/param", 0, true}, {"/kythe/edge/param.1", "/kythe/edge/param", 1, true}, {"%/kythe/edge/param.1", "%/kythe/edge/param", 1, true}, {"/kythe/edge/kind.1930", "/kythe/edge/kind", 1930, true}, } for _, test := range tests { kind, ord, ok := ParseOrdinal(test.Input) if err := testutil.DeepEqual(test, ordinalTest{ Input: test.Input, Kind: kind, Ordinal: ord, HasOrdinal: ok, }); err != nil { t.Errorf("ParseOrdinal(%q): %v", test.Input, err) } } }
func TestEdgesMultiPage(t *testing.T) { tests := []struct { Ticket string Kinds []string EdgeSet *srvpb.PagedEdgeSet Pages []*srvpb.EdgePage }{{ Ticket: tbl.EdgeSets[1].Source.Ticket, EdgeSet: tbl.EdgeSets[1], Pages: []*srvpb.EdgePage{tbl.EdgePages[1], tbl.EdgePages[2]}, }} st := tbl.Construct(t) for _, test := range tests { reply, err := st.Edges(ctx, &xpb.EdgesRequest{ Ticket: []string{test.Ticket}, Kind: test.Kinds, }) testutil.FatalOnErrT(t, "EdgesRequest error: %v", err) if len(reply.Nodes) > 0 { t.Errorf("Received unexpected nodes in EdgesReply: {%v}", reply) } if reply.NextPageToken != "" { t.Errorf("Received unexpected next_page_token in EdgesReply: {%v}", reply) } if len(reply.EdgeSets) != 1 { t.Errorf("Expected 1 EdgeSet in EdgesReply; found %d: {%v}", len(reply.EdgeSets), reply) } expected := edgeSet(test.Kinds, test.EdgeSet, test.Pages) if err := testutil.DeepEqual(expected, reply.EdgeSets[test.Ticket]); err != nil { t.Error(err) } if err := testutil.DeepEqual(map[string]int64{ "%/kythe/edge/defines/binding": 1, "%/kythe/edge/ref": 2, "someEdgeKind": 2, "anotherEdge": 1, }, reply.TotalEdgesByKind); err != nil { t.Error(err) } } }
func TestAppendEntry(t *testing.T) { tests := []struct { entries []*spb.Entry expected *ipb.Source }{{ entries: []*spb.Entry{fact("fact", "value")}, expected: &ipb.Source{ Facts: map[string][]byte{"fact": []byte("value")}, }, }, { entries: []*spb.Entry{edge("kind", "target")}, expected: &ipb.Source{ EdgeGroups: map[string]*ipb.Source_EdgeGroup{ "kind": { Edges: []*ipb.Source_Edge{{Ticket: "kythe:#target"}}, }, }, }, }, { entries: []*spb.Entry{ fact("kind", "first"), fact("kind", "second"), edge("edgeKind", "firstTarget"), edge("edgeKind", "secondTarget"), fact("blah", "blah"), }, expected: &ipb.Source{ Facts: map[string][]byte{ "kind": []byte("second"), "blah": []byte("blah"), }, EdgeGroups: map[string]*ipb.Source_EdgeGroup{ "edgeKind": &ipb.Source_EdgeGroup{ Edges: []*ipb.Source_Edge{{ Ticket: "kythe:#firstTarget", }, { Ticket: "kythe:#secondTarget", }}, }, }, }, }} for i, test := range tests { src := &ipb.Source{ Facts: make(map[string][]byte), EdgeGroups: make(map[string]*ipb.Source_EdgeGroup), } for _, e := range test.entries { AppendEntry(src, e) } if err := testutil.DeepEqual(test.expected, src); err != nil { t.Errorf("tests[%d] error: %v", i, err) } } }
func TestEdges(t *testing.T) { xs := newService(t, testEntries) reply, err := xs.Edges(ctx, &gpb.EdgesRequest{ Ticket: nodesToTickets(testNodes), Filter: []string{"**"}, // every fact }) if err != nil { t.Fatalf("Error fetching edges for %+v: %v", nodesToTickets(testNodes), err) } expectedEdges := nodesToEdgeSets(testNodes) if err := testutil.DeepEqual(expectedEdges, sortEdgeSets(reply.EdgeSets)); err != nil { t.Error(err) } nodesWithEdges := testNodes[1:] expectedInfos := nodesToInfos(nodesWithEdges) if err := testutil.DeepEqual(expectedInfos, reply.Nodes); err != nil { t.Error(err) } }
func TestNodes(t *testing.T) { xs := newService(t, testEntries) reply, err := xs.Nodes(ctx, &xpb.NodesRequest{ Ticket: nodesToTickets(testNodes), }) if err != nil { t.Fatalf("Error fetching nodes for %+v: %v", nodesToTickets(testNodes), err) } expected := nodesToInfos(testNodes) if err := testutil.DeepEqual(expected, sortInfos(reply.Node)); err != nil { t.Fatal(err) } }
func TestDecorationsDirtyBuffer(t *testing.T) { d := tbl.Decorations[1] st := tbl.Construct(t) dirty := []byte(`(defn map [f coll] (if (seq coll) [] (cons (f (first coll)) (map f (rest coll))))) `) reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{ Location: &xpb.Location{Ticket: d.FileTicket}, DirtyBuffer: dirty, References: true, Filter: []string{"**"}, }) testutil.FatalOnErrT(t, "DecorationsRequest error: %v", err) if len(reply.SourceText) != 0 { t.Errorf("Unexpected source text: %q", string(d.SourceText)) } if reply.Encoding != "" { t.Errorf("Unexpected encoding: %q", d.Encoding) } p := xrefs.NewPatcher(d.SourceText, dirty) norm := xrefs.NewNormalizer(dirty) var expected []*xpb.DecorationsReply_Reference for _, d := range d.Decoration { if _, _, exists := p.Patch(d.Anchor.StartOffset, d.Anchor.EndOffset); exists { expected = append(expected, decorationToReference(norm, d)) } } if !reflect.DeepEqual(expected, reply.Reference) { t.Fatalf("Expected references %v; found %v", expected, reply.Reference) } // These are a subset of the anchor nodes in tbl.Decorations[1]. tbl.Nodes[10] is missing because // it is the target of an anchor in the edited region. expectedNodes := nodeInfos([]*srvpb.Node{tbl.Nodes[9], tbl.Nodes[12]}) sort.Sort(byNodeTicket(expectedNodes)) sort.Sort(byNodeTicket(reply.Node)) if err := testutil.DeepEqual(expectedNodes, reply.Node); err != nil { t.Fatal(err) } }
func TestJSONReader(t *testing.T) { r := testJSONBuffer(testEntries) var i int if err := NewJSONReader(r)(func(e *spb.Entry) error { if err := testutil.DeepEqual(testEntries[i], e); err != nil { t.Errorf("testEntries[%d]: %v", i, err) } i++ return nil }); err != nil { t.Fatal(err) } if i != len(testEntries) { t.Fatalf("Missing %d entries", len(testEntries)-i) } }
func TestParseOrdinal(t *testing.T) { tests := []OrdinalTest{ {"/kythe/edge/defines", "/kythe/edge/defines", 0, false}, {"/kythe/edge/kind.here", "/kythe/edge/kind.here", 0, false}, {"/kythe/edge/kind1", "/kythe/edge/kind1", 0, false}, {"kind.-1", "kind.-1", 0, false}, {"kind.3", "kind", 3, true}, {"/kythe/edge/param.0", "/kythe/edge/param", 0, true}, {"/kythe/edge/param.1", "/kythe/edge/param", 1, true}, {"%/kythe/edge/param.1", "%/kythe/edge/param", 1, true}, {"/kythe/edge/kind.1930", "/kythe/edge/kind", 1930, true}, } for _, test := range tests { kind, ord, ok := ParseOrdinal(test.Input) if err := testutil.DeepEqual(&test, &OrdinalTest{test.Input, kind, ord, ok}); err != nil { t.Error(err) } } }
func TestEdgesLastPage(t *testing.T) { tests := [][]string{ nil, // all kinds {"%/kythe/edge/ref"}, {"%/kythe/edge/defines/binding"}, } ticket := tbl.EdgeSets[1].Source.Ticket es := tbl.EdgeSets[1] pages := []*srvpb.EdgePage{tbl.EdgePages[1], tbl.EdgePages[2]} st := tbl.Construct(t) for _, kinds := range tests { reply, err := st.Edges(ctx, &xpb.EdgesRequest{ Ticket: []string{ticket}, Kind: kinds, }) testutil.FatalOnErrT(t, "EdgesRequest error: %v", err) if len(reply.Nodes) > 0 { t.Errorf("Received unexpected nodes in EdgesReply: {%v}", reply) } if reply.NextPageToken != "" { t.Errorf("Received unexpected next_page_token in EdgesReply: {%v}", reply) } if len(reply.EdgeSets) != 1 { t.Fatalf("Expected 1 EdgeSet in EdgesReply; found %d: {%v}", len(reply.EdgeSets), reply) } expected := edgeSet(kinds, es, pages) if err := testutil.DeepEqual(expected, reply.EdgeSets[ticket]); err != nil { t.Error(err) } } }
func TestCrossReferences(t *testing.T) { ticket := "kythe://someCorpus?lang=otpl#signature" st := tbl.Construct(t) reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{ Ticket: []string{ticket}, DefinitionKind: xpb.CrossReferencesRequest_BINDING_DEFINITIONS, ReferenceKind: xpb.CrossReferencesRequest_ALL_REFERENCES, ExperimentalSignatures: true, }) testutil.FatalOnErrT(t, "CrossReferencesRequest error: %v", err) expected := &xpb.CrossReferencesReply_CrossReferenceSet{ Ticket: ticket, DisplayName: &xpb.Printable{RawText: ""}, Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{ Ticket: "kythe:?path=some/utf16/file#0-4", Kind: "/kythe/edge/ref", Parent: "kythe://someCorpus?path=some/utf16/file#utf16FTW", Start: &xpb.Location_Point{LineNumber: 1}, End: &xpb.Location_Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4}, SnippetStart: &xpb.Location_Point{ LineNumber: 1, }, SnippetEnd: &xpb.Location_Point{ ByteOffset: 28, LineNumber: 1, ColumnOffset: 28, }, Snippet: "これはいくつかのテキストです", }}, {Anchor: &xpb.Anchor{ Ticket: "kythe://c?lang=otpl?path=/a/path#51-55", Kind: "/kythe/edge/ref", Parent: "kythe://someCorpus?path=some/path#aFileNode", Start: &xpb.Location_Point{ ByteOffset: 51, LineNumber: 4, ColumnOffset: 15, }, End: &xpb.Location_Point{ ByteOffset: 55, LineNumber: 5, ColumnOffset: 2, }, SnippetStart: &xpb.Location_Point{ ByteOffset: 36, LineNumber: 4, }, SnippetEnd: &xpb.Location_Point{ ByteOffset: 52, LineNumber: 4, ColumnOffset: 16, }, Snippet: "some random text", }}}, Definition: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{ Ticket: "kythe://c?lang=otpl?path=/a/path#27-33", Kind: "/kythe/edge/defines/binding", Parent: "kythe://someCorpus?path=some/path#aFileNode", Start: &xpb.Location_Point{ ByteOffset: 27, LineNumber: 2, ColumnOffset: 10, }, End: &xpb.Location_Point{ ByteOffset: 33, LineNumber: 3, ColumnOffset: 5, }, SnippetStart: &xpb.Location_Point{ ByteOffset: 17, LineNumber: 2, }, SnippetEnd: &xpb.Location_Point{ ByteOffset: 27, LineNumber: 2, ColumnOffset: 10, }, Snippet: "here and ", }}}, } if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{ Definitions: 1, References: 2, }, reply.Total); err != nil { t.Error(err) } xr := reply.CrossReferences[ticket] if xr == nil { t.Fatalf("Missing expected CrossReferences; found: %#v", reply) } sort.Sort(byOffset(xr.Reference)) if err := testutil.DeepEqual(expected, xr); err != nil { t.Fatal(err) } }
func TestSlowCallers(t *testing.T) { service := &mockService{ NodesFn: func(req *xpb.NodesRequest) (*xpb.NodesReply, error) { t.Fatalf("Unexpected Nodes request: %v", req) return nil, nil }, EdgesFn: func(req *xpb.EdgesRequest) (*xpb.EdgesReply, error) { if len(req.Ticket) == 1 && req.Ticket[0] == "kythe://test#f" { return &xpb.EdgesReply{}, nil } else if len(req.Ticket) == 1 && req.Ticket[0] == "kythe://test#acall" { if containsString(req.Kind, schema.ChildOfEdge) { return &xpb.EdgesReply{ EdgeSets: map[string]*xpb.EdgeSet{ req.Ticket[0]: &xpb.EdgeSet{ Groups: map[string]*xpb.EdgeSet_Group{ "": &xpb.EdgeSet_Group{ Edge: []*xpb.EdgeSet_Group_Edge{{TargetTicket: "kythe://test#g"}}, }, }, }, }, }, nil } } t.Fatalf("Unexpected Edges request: %v", req) return nil, nil }, DecorationsFn: func(req *xpb.DecorationsRequest) (*xpb.DecorationsReply, error) { t.Fatalf("Unexpected Decorations request: %v", req) return nil, nil }, CrossReferencesFn: func(req *xpb.CrossReferencesRequest) (*xpb.CrossReferencesReply, error) { if len(req.Ticket) == 1 && req.Ticket[0] == "kythe://test#f" { if req.ReferenceKind == xpb.CrossReferencesRequest_ALL_REFERENCES { return &xpb.CrossReferencesReply{ CrossReferences: map[string]*xpb.CrossReferencesReply_CrossReferenceSet{ req.Ticket[0]: &xpb.CrossReferencesReply_CrossReferenceSet{ Ticket: req.Ticket[0], Reference: []*xpb.CrossReferencesReply_RelatedAnchor{ &xpb.CrossReferencesReply_RelatedAnchor{Anchor: &xpb.Anchor{ Ticket: "kythe://test#acall", Kind: schema.RefCallEdge, }}, }, }, }, }, nil } } else if len(req.Ticket) == 2 && containsString(req.Ticket, "kythe://test#f") && containsString(req.Ticket, "kythe://test#g") { if req.DefinitionKind == xpb.CrossReferencesRequest_BINDING_DEFINITIONS { return &xpb.CrossReferencesReply{ CrossReferences: map[string]*xpb.CrossReferencesReply_CrossReferenceSet{ "kythe://test#f": &xpb.CrossReferencesReply_CrossReferenceSet{ Ticket: "kythe://test#f", Definition: []*xpb.CrossReferencesReply_RelatedAnchor{ &xpb.CrossReferencesReply_RelatedAnchor{Anchor: &xpb.Anchor{ Ticket: "kythe://test#afdef", Text: "f", }}, }, }, "kythe://test#g": &xpb.CrossReferencesReply_CrossReferenceSet{ Ticket: "kythe://test#g", Definition: []*xpb.CrossReferencesReply_RelatedAnchor{ &xpb.CrossReferencesReply_RelatedAnchor{Anchor: &xpb.Anchor{ Ticket: "kythe://test#agdef", Text: "g", }}, }, }, }, }, nil } } t.Fatalf("Unexpected CrossReferences request: %v", req) return nil, nil }, CallersFn: func(req *xpb.CallersRequest) (*xpb.CallersReply, error) { t.Fatalf("Unexpected Callers request: %v", req) return nil, nil }, } creq := &xpb.CallersRequest{ IncludeOverrides: true, SemanticObject: []string{"kythe://test#f"}, } creply, err := SlowCallers(nil, service, creq) if err != nil { t.Fatalf("SlowCallers error: %v", err) } if creply == nil { t.Fatalf("SlowCallers returned nil response") } expected := &xpb.CallersReply{ Callee: []*xpb.CallersReply_CallableDetail{ &xpb.CallersReply_CallableDetail{ SemanticObject: "kythe://test#f", Definition: &xpb.Anchor{ Ticket: "kythe://test#afdef", Text: "f", }, Identifier: "f", DisplayName: "f", }, }, Caller: []*xpb.CallersReply_Caller{ &xpb.CallersReply_Caller{ Detail: &xpb.CallersReply_CallableDetail{ SemanticObject: "kythe://test#g", Definition: &xpb.Anchor{ Ticket: "kythe://test#agdef", Text: "g", }, Identifier: "g", DisplayName: "g", }, CallSite: []*xpb.CallersReply_Caller_CallSite{ &xpb.CallersReply_Caller_CallSite{ Anchor: &xpb.Anchor{ Ticket: "kythe://test#acall", Kind: "/kythe/edge/ref/call", }, }, }, }, }, } if err := testutil.DeepEqual(expected, creply); err != nil { t.Fatal(err) } }
func TestSlowSignature(t *testing.T) { db := []struct { ticket, format, kind, typed, childof string params []string }{ {ticket: "kythe://test#ident", format: "IDENT", kind: "etc"}, {ticket: "kythe:?lang=b#etc%23meta", format: "META", kind: "meta"}, {ticket: "kythe://test?lang=b#meta", kind: "etc"}, {ticket: "kythe://test#escparen", format: "%%", kind: "etc"}, {ticket: "kythe://test#escparentext", format: "a%%b%%c", kind: "etc"}, {ticket: "kythe://test#p0", format: "P0", kind: "etc"}, {ticket: "kythe://test#p1", format: "P1", kind: "etc"}, {ticket: "kythe://test#p2", format: "P2", kind: "etc"}, {ticket: "kythe://test#pselect", format: "%0.%1.", kind: "etc", params: []string{"kythe://test#p0", "kythe://test#p1"}}, {ticket: "kythe://test#parent", format: "%^::C", kind: "etc", childof: "kythe://test#p0"}, {ticket: "kythe://test#parents", format: "%^::D", kind: "etc", childof: "kythe://test#parent"}, {ticket: "kythe://test#recurse", format: "%^", kind: "etc", childof: "kythe://test#recurse"}, {ticket: "kythe://test#list", format: "%0,", kind: "etc", params: []string{"kythe://test#p0", "kythe://test#p1", "kythe://test#p2"}}, {ticket: "kythe://test#listofs1", format: "%1,", kind: "etc", params: []string{"kythe://test#p0", "kythe://test#p1", "kythe://test#p2"}}, {ticket: "kythe://test#listofs2", format: "%2,", kind: "etc", params: []string{"kythe://test#p0", "kythe://test#p1", "kythe://test#p2"}}, {ticket: "kythe://test#listofs3", format: "%3,", kind: "etc", params: []string{"kythe://test#p0", "kythe://test#p1", "kythe://test#p2"}}, {ticket: "kythe://test#typeselect", format: "%1`", kind: "etc", typed: "kythe://test#list"}, {ticket: "kythe:?lang=b#tapp%23meta", format: "m%2.m", kind: "meta"}, {ticket: "kythe://test#lhs", format: "l%1.l", kind: "tapp"}, {ticket: "kythe://test?lang=b#tappmeta", kind: "tapp", params: []string{"kythe://test#missing", "kythe://test#p0", "kythe://test#p1"}}, {ticket: "kythe://test?lang=b#tapplhs", kind: "tapp", params: []string{"kythe://test#lhs", "kythe://test#p0"}}, } tests := []struct{ ticket, reply string }{ {ticket: "kythe://test#ident", reply: "IDENT"}, {ticket: "kythe://test?lang=b#meta", reply: "META"}, {ticket: "kythe://test#escparen", reply: "%"}, {ticket: "kythe://test#escparentext", reply: "a%b%c"}, {ticket: "kythe://test#pselect", reply: "P0P1"}, {ticket: "kythe://test#recurse", reply: "..."}, {ticket: "kythe://test#parent", reply: "P0::C"}, {ticket: "kythe://test#parents", reply: "P0::C::D"}, {ticket: "kythe://test#list", reply: "P0, P1, P2"}, {ticket: "kythe://test#listofs1", reply: "P1, P2"}, {ticket: "kythe://test#listofs2", reply: "P2"}, {ticket: "kythe://test#listofs3", reply: ""}, {ticket: "kythe://test#typeselect", reply: "P1"}, {ticket: "kythe://test?lang=b#tappmeta", reply: "mP1m"}, {ticket: "kythe://test?lang=b#tapplhs", reply: "lP0l"}, } nodes := make(map[string]*xpb.NodeInfo) edges := make(map[string]*xpb.EdgeSet) for _, node := range db { nodes[node.ticket] = &xpb.NodeInfo{ Facts: map[string][]byte{ schema.NodeKindFact: []byte(node.kind), schema.FormatFact: []byte(node.format), }, } set := &xpb.EdgeSet{Groups: make(map[string]*xpb.EdgeSet_Group)} if node.typed != "" { set.Groups[schema.TypedEdge] = &xpb.EdgeSet_Group{ Edge: []*xpb.EdgeSet_Group_Edge{{TargetTicket: node.typed}}, } } if node.childof != "" { set.Groups[schema.ChildOfEdge] = &xpb.EdgeSet_Group{ Edge: []*xpb.EdgeSet_Group_Edge{{TargetTicket: node.childof}}, } } if node.params != nil { var edges []*xpb.EdgeSet_Group_Edge for i, p := range node.params { edges = append(edges, &xpb.EdgeSet_Group_Edge{TargetTicket: p, Ordinal: int32(i)}) } set.Groups[schema.ParamEdge] = &xpb.EdgeSet_Group{Edge: edges} } edges[node.ticket] = set } getNode := func(ticket string, facts []string) *xpb.NodeInfo { data, found := nodes[ticket] if !found { return nil } info := &xpb.NodeInfo{Facts: make(map[string][]byte)} for _, fact := range facts { info.Facts[fact] = data.Facts[fact] } return info } service := &mockService{ NodesFn: func(req *xpb.NodesRequest) (*xpb.NodesReply, error) { log.Printf("NodesFn: %v", req) if len(req.Ticket) != 1 { t.Fatalf("Unexpected Nodes request: %v", req) return nil, nil } reply := &xpb.NodesReply{Nodes: make(map[string]*xpb.NodeInfo)} if info := getNode(req.Ticket[0], req.Filter); info != nil { reply.Nodes[req.Ticket[0]] = info } return reply, nil }, EdgesFn: func(req *xpb.EdgesRequest) (*xpb.EdgesReply, error) { log.Printf("EdgesFn: %v", req) if len(req.Ticket) != 1 { t.Fatalf("Unexpected Edges request: %v", req) return nil, nil } reply := &xpb.EdgesReply{ EdgeSets: make(map[string]*xpb.EdgeSet), Nodes: make(map[string]*xpb.NodeInfo), } if data, found := edges[req.Ticket[0]]; found { set := &xpb.EdgeSet{Groups: make(map[string]*xpb.EdgeSet_Group)} reply.EdgeSets[req.Ticket[0]] = set nodes := make(map[string]bool) for groupKind, group := range data.Groups { for _, kind := range req.Kind { if groupKind == kind { set.Groups[kind] = group for _, edge := range group.Edge { if !nodes[edge.TargetTicket] { nodes[edge.TargetTicket] = true if node := getNode(edge.TargetTicket, req.Filter); node != nil { reply.Nodes[edge.TargetTicket] = node } } } break } } } } log.Printf(" => %v", reply) return reply, nil }, } _, err := SlowSignature(nil, service, "kythe://test#missing") if err == nil { t.Fatal("SlowSignature should return an error for a missing ticket") } for _, test := range tests { reply, err := SlowSignature(nil, service, test.ticket) if err != nil { t.Fatalf("SlowSignature error for %s: %v", test.ticket, err) } if err := testutil.DeepEqual(&xpb.Printable{RawText: test.reply}, reply); err != nil { t.Fatal(err) } } }
func TestReducer_Output(t *testing.T) { in := testInput([]*ipb.Path{{ Pivot: testNode("blah", "UNKNOWN"), Edges: testEdges("edgeKind", "target"), }, { Pivot: testNode("blah", "UNKNOWN2"), Edges: testEdges("e1", "t1", "e2", "t2"), }, { Pivot: testNode("blah", "test", "subkind", "input"), }, { Pivot: testNode("blah", "still UNKNOWN"), Edges: testEdges("e0", "t3"), }}) out, err := reduce.Sort(ctx, in, &Reducer{ OutputSort: func(p *ipb.Path) string { if len(p.Edges) == 0 { return "" } // Order by first edge's kind return p.Edges[0].Kind }, Func: func(ctx context.Context, pivot *ipb.Path_Node, rio ReducerIO) error { // Pass-through the pivot node if err := rio.Emit(ctx, &ipb.Path{Pivot: pivot}); err != nil { t.Fatal(err) } for { _, p, err := rio.Next() if err == io.EOF { return nil } else if err != nil { t.Fatal(err) } // Pass-through each Path if err := rio.Emit(ctx, p); err != nil { t.Fatal(err) } } }, }) if err != nil { t.Fatal(err) } var found []*ipb.Path empty, err := reduce.Sort(ctx, out, &Reducer{ Func: func(ctx context.Context, pivot *ipb.Path_Node, rio ReducerIO) error { if len(found) > 0 { t.Fatalf("Already read paths: %v", found) } for { _, p, err := rio.Next() if err == io.EOF { return nil } else if err != nil { t.Fatal(err) } found = append(found, p) } }, }) expectedPivot := testNode("blah", "test", "subkind", "input") // Ordered by first edge's kind expectedPaths := []*ipb.Path{{ Pivot: expectedPivot, Edges: testEdges("e0", "t3"), }, { Pivot: expectedPivot, Edges: testEdges("e1", "t1", "e2", "t2"), }, { Pivot: expectedPivot, Edges: testEdges("edgeKind", "target"), }} if err := testutil.DeepEqual(expectedPaths, found); err != nil { t.Error(err) } if s, err := empty.NextSplit(); err != io.EOF { t.Fatalf("Unexpected output/err: %v / %v", s, err) } }
func TestPager(t *testing.T) { var outputSets, expectedSets []*testSet var outputPages, expectedPages []*testPage p := &SetPager{ MaxPageSize: 4, OutputSet: func(_ context.Context, total int, s Set, grps []Group) error { ts := s.(*testSet) ts.Total = total for _, g := range grps { ts.Groups = append(ts.Groups, g.(*testGroup)) } outputSets = append(outputSets, ts) return nil }, OutputPage: func(_ context.Context, s Set, g Group) error { ts := s.(*testSet) outputPages = append(outputPages, &testPage{ Index: ts.Pages, Group: g.(*testGroup), }) ts.Pages++ return nil }, NewSet: func(h Head) Set { return &testSet{Head: h.(string)} }, Combine: func(l, r Group) Group { lg, rg := l.(*testGroup), r.(*testGroup) if lg.Key != rg.Key { return nil } lg.Vals = append(lg.Vals, rg.Vals...) return lg }, Split: func(total int, g Group) (Group, Group) { tg := g.(*testGroup) ng := &testGroup{ Key: tg.Key, Vals: tg.Vals[:total], } tg.Vals = tg.Vals[total:] return ng, tg }, Size: func(g Group) int { return len(g.(*testGroup).Vals) }, } ctx := context.Background() testutil.FatalOnErrT(t, "StartSet error: %v", p.StartSet(ctx, "head key")) testutil.FatalOnErrT(t, "AddGroup error: %v", p.AddGroup(ctx, &testGroup{ Key: "key1", Vals: []int{11, 12, 13}, })) testutil.FatalOnErrT(t, "AddGroup error: %v", p.AddGroup(ctx, &testGroup{ Key: "key1", Vals: []int{14, 15, 16}, })) expectedPages = append(expectedPages, &testPage{ Index: 0, Group: &testGroup{ Key: "key1", Vals: []int{11, 12, 13, 14}, }, }) if err := testutil.DeepEqual(expectedSets, outputSets); err != nil { t.Fatalf("error checking Sets: %v", err) } if err := testutil.DeepEqual(expectedPages, outputPages); err != nil { t.Fatalf("error checking Pages: %v", err) } testutil.FatalOnErrT(t, "AddGroup error: %v", p.AddGroup(ctx, &testGroup{ Key: "key2", Vals: []int{21}, })) testutil.FatalOnErrT(t, "AddGroup error: %v", p.AddGroup(ctx, &testGroup{ Key: "key2", Vals: []int{22, 23}, })) expectedPages = append(expectedPages, &testPage{ Index: 1, Group: &testGroup{ Key: "key2", Vals: []int{21, 22, 23}, }, }) if err := testutil.DeepEqual(expectedSets, outputSets); err != nil { t.Fatalf("error checking Sets: %v", err) } if err := testutil.DeepEqual(expectedPages, outputPages); err != nil { t.Fatalf("error checking Pages: %v", err) } testutil.FatalOnErrT(t, "StartSet error: %v", p.StartSet(ctx, "next set")) expectedSets = append(expectedSets, &testSet{ Head: "head key", Total: 9, Groups: []*testGroup{{ Key: "key1", Vals: []int{15, 16}, }}, Pages: len(expectedPages), }) if err := testutil.DeepEqual(expectedSets, outputSets); err != nil { t.Fatalf("error checking Sets: %v", err) } if err := testutil.DeepEqual(expectedPages, outputPages); err != nil { t.Fatalf("error checking Pages: %v", err) } testutil.FatalOnErrT(t, "StartSet error: %v", p.StartSet(ctx, "final set")) expectedSets = append(expectedSets, &testSet{ Head: "next set", }) if err := testutil.DeepEqual(expectedSets, outputSets); err != nil { t.Fatalf("error checking Sets: %v", err) } if err := testutil.DeepEqual(expectedPages, outputPages); err != nil { t.Fatalf("error checking Pages: %v", err) } testutil.FatalOnErrT(t, "AddGroup error: %v", p.AddGroup(ctx, &testGroup{ Key: "key0", Vals: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, })) expectedPages = append(expectedPages, &testPage{ Index: 0, Group: &testGroup{ Key: "key0", Vals: []int{1, 2, 3, 4}, }, }) expectedPages = append(expectedPages, &testPage{ Index: 1, Group: &testGroup{ Key: "key0", Vals: []int{5, 6, 7, 8}, }, }) if err := testutil.DeepEqual(expectedSets, outputSets); err != nil { t.Fatalf("error checking Sets: %v", err) } if err := testutil.DeepEqual(expectedPages, outputPages); err != nil { t.Fatalf("error checking Pages: %v", err) } testutil.FatalOnErrT(t, "Flush error: %v", p.Flush(ctx)) expectedSets = append(expectedSets, &testSet{ Head: "final set", Total: 12, Groups: []*testGroup{{ Key: "key0", Vals: []int{9, 10, 11, 12}, }}, Pages: 2, }) if err := testutil.DeepEqual(expectedSets, outputSets); err != nil { t.Fatalf("error checking Sets: %v", err) } if err := testutil.DeepEqual(expectedPages, outputPages); err != nil { t.Fatalf("error checking Pages: %v", err) } }
func TestDecorationsDirtyBuffer(t *testing.T) { d := tbl.Decorations[1] st := tbl.Construct(t) // s/empty?/seq/ dirty := []byte(`(defn map [f coll] (if (seq coll) [] (cons (f (first coll)) (map f (rest coll))))) `) reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{ Location: &xpb.Location{Ticket: d.File.Ticket}, DirtyBuffer: dirty, References: true, Filter: []string{"**"}, }) testutil.FatalOnErrT(t, "DecorationsRequest error: %v", err) if len(reply.SourceText) != 0 { t.Errorf("Unexpected source text: %q", string(reply.SourceText)) } if reply.Encoding != "" { t.Errorf("Unexpected encoding: %q", reply.Encoding) } expected := []*xpb.DecorationsReply_Reference{ { // Unpatched anchor for "map" SourceTicket: "kythe://c?lang=otpl?path=/a/path#6-9", TargetTicket: "kythe://c?lang=otpl?path=/a/path#map", Kind: "/kythe/defines/binding", AnchorStart: &xpb.Location_Point{ ByteOffset: 6, LineNumber: 1, ColumnOffset: 6, }, AnchorEnd: &xpb.Location_Point{ ByteOffset: 9, LineNumber: 1, ColumnOffset: 9, }, }, // Skipped anchor for "empty?" (inside edit region) { // Patched anchor for "cons" (moved backwards by 3 bytes) SourceTicket: "kythe://c?lang=otpl?path=/a/path#51-55", TargetTicket: "kythe://core?lang=otpl#cons", Kind: "/kythe/refs", AnchorStart: &xpb.Location_Point{ ByteOffset: 48, LineNumber: 4, ColumnOffset: 5, }, AnchorEnd: &xpb.Location_Point{ ByteOffset: 52, LineNumber: 4, ColumnOffset: 9, }, }, } if err := testutil.DeepEqual(expected, reply.Reference); err != nil { t.Fatal(err) } // These are a subset of the anchor nodes in tbl.Decorations[1]. tbl.Nodes[10] is missing because // it is the target of an anchor in the edited region. expectedNodes := nodeInfos([]*srvpb.Node{tbl.Nodes[9], tbl.Nodes[12]}) sort.Sort(byNodeTicket(expectedNodes)) sort.Sort(byNodeTicket(reply.Node)) if err := testutil.DeepEqual(expectedNodes, reply.Node); err != nil { t.Fatal(err) } }
func TestEdgeSetBuilder(t *testing.T) { tests := []struct { src *srvpb.Node grp *srvpb.EdgeGroup edgeSet *srvpb.PagedEdgeSet edgePages []*srvpb.EdgePage }{{ src: getNode("someSource"), }, { grp: &srvpb.EdgeGroup{ Kind: "someEdgeKind", Edge: getEdgeTargets("kythe:#aTarget"), }, }, { // flush edgeSet: &srvpb.PagedEdgeSet{ Source: getNode("someSource"), Group: []*srvpb.EdgeGroup{{ Kind: "someEdgeKind", Edge: getEdgeTargets("kythe:#aTarget"), }}, TotalEdges: 1, }, }, { src: getNode("someOtherSource"), }, { grp: &srvpb.EdgeGroup{ Kind: "someEdgeKind", Edge: getEdgeTargets( "kythe:#aTarget", "kythe:#anotherTarget", ), }, }, { grp: &srvpb.EdgeGroup{ Kind: "someEdgeKind", Edge: getEdgeTargets( "kythe:#onceMoreWithFeeling", ), }, }, { src: getNode("aThirdSource"), // forced flush due to new source edgeSet: &srvpb.PagedEdgeSet{ Source: getNode("someOtherSource"), Group: []*srvpb.EdgeGroup{{ Kind: "someEdgeKind", Edge: getEdgeTargets( "kythe:#aTarget", "kythe:#anotherTarget", "kythe:#onceMoreWithFeeling", ), }}, TotalEdges: 3, // fits exactly MaxEdgePageSize }, }, { grp: &srvpb.EdgeGroup{ Kind: "edgeKind123", Edge: getEdgeTargets("kythe:#aTarget"), }, }, { grp: &srvpb.EdgeGroup{ Kind: "edgeKind123", Edge: getEdgeTargets( "kythe:#bTarget", "kythe:#anotherTarget", "kythe:#threeTarget", "kythe:#fourTarget", ), }, edgePages: []*srvpb.EdgePage{{ SourceTicket: "aThirdSource", PageKey: "aThirdSource.0000000000", EdgesGroup: &srvpb.EdgeGroup{ Kind: "edgeKind123", Edge: getEdgeTargets( "kythe:#aTarget", "kythe:#bTarget", "kythe:#anotherTarget", ), }, }}, }, { grp: &srvpb.EdgeGroup{ Kind: "edgeKind123", Edge: getEdgeTargets( "kythe:#five", "kythe:#six", "kythe:#seven", "kythe:#eight", "kythe:#nine", ), }, edgePages: []*srvpb.EdgePage{{ SourceTicket: "aThirdSource", PageKey: "aThirdSource.0000000001", EdgesGroup: &srvpb.EdgeGroup{ Kind: "edgeKind123", Edge: getEdgeTargets( "kythe:#threeTarget", "kythe:#fourTarget", "kythe:#five", ), }, }, { SourceTicket: "aThirdSource", PageKey: "aThirdSource.0000000002", EdgesGroup: &srvpb.EdgeGroup{ Kind: "edgeKind123", Edge: getEdgeTargets( "kythe:#six", "kythe:#seven", "kythe:#eight", ), }, }}, }, { grp: &srvpb.EdgeGroup{ Kind: "edgeKind123", Edge: getEdgeTargets( "kythe:#ten", "kythe:#eleven", ), }, }, { grp: &srvpb.EdgeGroup{ Kind: "edgeKindFinal", Edge: getEdgeTargets( "kythe:#ten", ), }, edgePages: []*srvpb.EdgePage{{ SourceTicket: "aThirdSource", PageKey: "aThirdSource.0000000003", EdgesGroup: &srvpb.EdgeGroup{ Kind: "edgeKind123", Edge: getEdgeTargets( "kythe:#nine", "kythe:#ten", "kythe:#eleven", ), }, }}, }, { grp: &srvpb.EdgeGroup{ Kind: "edgeKindFinal", Edge: getEdgeTargets( "kythe:#two", "kythe:#three", ), }, }, { // flush edgeSet: &srvpb.PagedEdgeSet{ TotalEdges: 15, Source: getNode("aThirdSource"), Group: []*srvpb.EdgeGroup{{ Kind: "edgeKindFinal", Edge: getEdgeTargets( "kythe:#ten", "kythe:#two", "kythe:#three", ), }}, PageIndex: []*srvpb.PageIndex{{ PageKey: "aThirdSource.0000000000", EdgeKind: "edgeKind123", EdgeCount: 3, }, { PageKey: "aThirdSource.0000000001", EdgeKind: "edgeKind123", EdgeCount: 3, }, { PageKey: "aThirdSource.0000000002", EdgeKind: "edgeKind123", EdgeCount: 3, }, { PageKey: "aThirdSource.0000000003", EdgeKind: "edgeKind123", EdgeCount: 3, }}, }, }} tESB := newTestESB(&EdgeSetBuilder{ MaxEdgePageSize: 3, }) var edgeSets, edgePages int for _, test := range tests { if test.src != nil { testutil.FatalOnErrT(t, "Failure to StartEdgeSet: %v", tESB.StartEdgeSet(ctx, test.src)) } else if test.grp != nil { testutil.FatalOnErrT(t, "Failure to AddGroup: %v", tESB.AddGroup(ctx, test.grp)) } else { testutil.FatalOnErrT(t, "Failure to Flush: %v", tESB.Flush(ctx)) } if test.edgeSet != nil { // Expected a new PagedEdgeSet if edgeSets+1 != len(tESB.PagedEdgeSets) { t.Fatalf("Missing expected PagedEdgeSet: %v", test.edgeSet) } else if found := tESB.PagedEdgeSets[len(tESB.PagedEdgeSets)-1]; !reflect.DeepEqual(test.edgeSet, found) { t.Errorf("Expected PagedEdgeSet: %v; found: %v", test.edgeSet, found) } edgeSets++ } else if edgeSets != len(tESB.PagedEdgeSets) { t.Fatalf("Unexpected PagedEdgeSet: %v", tESB.PagedEdgeSets[len(tESB.PagedEdgeSets)-1]) } // Expected new EdgePage(s) for i := 0; i < len(test.edgePages); i++ { if edgePages >= len(tESB.EdgePages) { t.Fatalf("Missing expected EdgePages: %v", test.edgePages[i]) } else if err := testutil.DeepEqual(test.edgePages[i], tESB.EdgePages[edgePages]); err != nil { t.Error(err) } edgePages++ } if edgePages != len(tESB.EdgePages) { t.Fatalf("Unexpected EdgePage(s): %v", tESB.EdgePages[edgePages:]) } } }
func TestSlowDocumentation(t *testing.T) { db := []struct { ticket, kind, documented, defines, completes, completed, childof, typed, text, format string params, definitionText []string }{ {ticket: "kythe://test#a", kind: "etc", documented: "kythe://test#adoc", format: "asig"}, {ticket: "kythe://test#adoc", kind: "doc", text: "atext"}, {ticket: "kythe://test#fdoc", kind: "doc", text: "ftext"}, {ticket: "kythe://test#fdecl", kind: "function", documented: "kythe://test#fdoc", format: "fsig"}, {ticket: "kythe://test#fdefn", kind: "function", completed: "kythe://test#fbind", format: "fsig"}, {ticket: "kythe://test#fbind", kind: "anchor", defines: "kythe://test#fdefn", completes: "kythe://test#fdecl"}, {ticket: "kythe://test#l", kind: "etc", documented: "kythe://test#ldoc"}, {ticket: "kythe://test#ldoc", kind: "doc", text: "ltext", params: []string{"kythe://test#l1", "kythe://test#l2"}}, {ticket: "kythe://test#l1", kind: "etc", definitionText: []string{"deftext1"}}, {ticket: "kythe://test#l2", kind: "etc", definitionText: []string{"deftext2"}}, {ticket: "kythe://test#l", kind: "etc", documented: "kythe://test#ldoc", format: "lsig"}, } mkPr := func(text string, linkTicket ...string) *xpb.Printable { links := make([]*xpb.Link, len(linkTicket)) for i, link := range linkTicket { links[i] = &xpb.Link{Definition: []*xpb.Anchor{{Text: link}}} } return &xpb.Printable{RawText: text, Link: links} } tests := []struct { ticket string reply *xpb.DocumentationReply_Document }{ {ticket: "kythe://test#a", reply: &xpb.DocumentationReply_Document{Signature: mkPr("asig"), Kind: "etc", Text: mkPr("atext")}}, {ticket: "kythe://test#fdecl", reply: &xpb.DocumentationReply_Document{Signature: mkPr("fsig"), Kind: "function", Text: mkPr("ftext")}}, {ticket: "kythe://test#fdefn", reply: &xpb.DocumentationReply_Document{Signature: mkPr("fsig"), Kind: "function", Text: mkPr("ftext")}}, {ticket: "kythe://test#l", reply: &xpb.DocumentationReply_Document{Signature: mkPr("lsig"), Kind: "etc", Text: mkPr("ltext", "deftext1", "deftext2")}}, } nodes := make(map[string]*xpb.NodeInfo) edges := make(map[string]*xpb.EdgeSet) xrefs := make(map[string]*xpb.CrossReferencesReply_CrossReferenceSet) for _, node := range db { nodes[node.ticket] = &xpb.NodeInfo{ Facts: map[string][]byte{ schema.NodeKindFact: []byte(node.kind), schema.TextFact: []byte(node.text), schema.FormatFact: []byte(node.format), }, } if node.definitionText != nil { set := &xpb.CrossReferencesReply_CrossReferenceSet{Ticket: node.ticket} for _, text := range node.definitionText { set.Definition = append(set.Definition, &xpb.CrossReferencesReply_RelatedAnchor{Anchor: &xpb.Anchor{Text: text}}) } xrefs[node.ticket] = set } set := &xpb.EdgeSet{Groups: make(map[string]*xpb.EdgeSet_Group)} if node.typed != "" { set.Groups[schema.TypedEdge] = &xpb.EdgeSet_Group{ Edge: []*xpb.EdgeSet_Group_Edge{&xpb.EdgeSet_Group_Edge{TargetTicket: node.typed}}, } } if node.childof != "" { set.Groups[schema.ChildOfEdge] = &xpb.EdgeSet_Group{ Edge: []*xpb.EdgeSet_Group_Edge{&xpb.EdgeSet_Group_Edge{TargetTicket: node.childof}}, } } if node.documented != "" { set.Groups[schema.MirrorEdge(schema.DocumentsEdge)] = &xpb.EdgeSet_Group{ Edge: []*xpb.EdgeSet_Group_Edge{&xpb.EdgeSet_Group_Edge{TargetTicket: node.documented}}, } } if node.completes != "" { set.Groups[schema.CompletesEdge] = &xpb.EdgeSet_Group{ Edge: []*xpb.EdgeSet_Group_Edge{&xpb.EdgeSet_Group_Edge{TargetTicket: node.completes}}, } } if node.completed != "" { set.Groups[schema.MirrorEdge(schema.CompletesEdge)] = &xpb.EdgeSet_Group{ Edge: []*xpb.EdgeSet_Group_Edge{&xpb.EdgeSet_Group_Edge{TargetTicket: node.completed}}, } } if node.defines != "" { set.Groups[schema.DefinesBindingEdge] = &xpb.EdgeSet_Group{ Edge: []*xpb.EdgeSet_Group_Edge{&xpb.EdgeSet_Group_Edge{TargetTicket: node.defines}}, } } if node.params != nil { var edges []*xpb.EdgeSet_Group_Edge for i, p := range node.params { edges = append(edges, &xpb.EdgeSet_Group_Edge{TargetTicket: p, Ordinal: int32(i)}) } set.Groups[schema.ParamEdge] = &xpb.EdgeSet_Group{ Edge: edges, } } edges[node.ticket] = set } getNode := func(ticket string, facts []string) *xpb.NodeInfo { data, found := nodes[ticket] if !found { return nil } info := &xpb.NodeInfo{Facts: make(map[string][]byte)} for _, fact := range facts { info.Facts[fact] = data.Facts[fact] } return info } service := &mockService{ NodesFn: func(req *xpb.NodesRequest) (*xpb.NodesReply, error) { if len(req.Ticket) != 1 { t.Fatalf("Unexpected Nodes request: %v", req) return nil, nil } reply := &xpb.NodesReply{Nodes: make(map[string]*xpb.NodeInfo)} for _, ticket := range req.Ticket { if info := getNode(ticket, req.Filter); info != nil { reply.Nodes[ticket] = info } } return reply, nil }, EdgesFn: func(req *xpb.EdgesRequest) (*xpb.EdgesReply, error) { reply := &xpb.EdgesReply{ EdgeSets: make(map[string]*xpb.EdgeSet), Nodes: make(map[string]*xpb.NodeInfo), } for _, ticket := range req.Ticket { if data, found := edges[ticket]; found { set := &xpb.EdgeSet{Groups: make(map[string]*xpb.EdgeSet_Group)} reply.EdgeSets[ticket] = set nodes := make(map[string]bool) for groupKind, group := range data.Groups { for _, kind := range req.Kind { if groupKind == kind { set.Groups[kind] = group for _, edge := range group.Edge { if !nodes[edge.TargetTicket] { nodes[edge.TargetTicket] = true if node := getNode(edge.TargetTicket, req.Filter); node != nil { reply.Nodes[edge.TargetTicket] = node } } } break } } } } } return reply, nil }, CrossReferencesFn: func(req *xpb.CrossReferencesRequest) (*xpb.CrossReferencesReply, error) { if req.DefinitionKind != xpb.CrossReferencesRequest_ALL_DEFINITIONS || req.ReferenceKind != xpb.CrossReferencesRequest_NO_REFERENCES || req.DocumentationKind != xpb.CrossReferencesRequest_NO_DOCUMENTATION || req.AnchorText { t.Fatalf("Unexpected CrossReferences request: %v", req) } reply := &xpb.CrossReferencesReply{ CrossReferences: make(map[string]*xpb.CrossReferencesReply_CrossReferenceSet), } for _, ticket := range req.Ticket { if set, found := xrefs[ticket]; found { reply.CrossReferences[ticket] = set } } return reply, nil }, } for _, test := range tests { reply, err := SlowDocumentation(nil, service, &xpb.DocumentationRequest{Ticket: []string{test.ticket}}) if err != nil { t.Fatalf("SlowDocumentation error for %s: %v", test.ticket, err) } test.reply.Ticket = test.ticket if err := testutil.DeepEqual(&xpb.DocumentationReply{Document: []*xpb.DocumentationReply_Document{test.reply}}, reply); err != nil { t.Fatal(err) } } }
func TestCrossReferences(t *testing.T) { ticket := "kythe://someCorpus?lang=otpl#signature" st := tbl.Construct(t) reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{ Ticket: []string{ticket}, DefinitionKind: xpb.CrossReferencesRequest_BINDING_DEFINITIONS, ReferenceKind: xpb.CrossReferencesRequest_ALL_REFERENCES, }) testutil.FatalOnErrT(t, "CrossReferencesRequest error: %v", err) expected := &xpb.CrossReferencesReply_CrossReferenceSet{ Ticket: ticket, Reference: []*xpb.Anchor{{ Ticket: "kythe://c?lang=otpl?path=/a/path#51-55", Kind: "/kythe/edge/ref", Parent: "kythe://someCorpus?path=some/path#aFileNode", Start: &xpb.Location_Point{ ByteOffset: 51, LineNumber: 4, ColumnOffset: 15, }, End: &xpb.Location_Point{ ByteOffset: 55, LineNumber: 5, ColumnOffset: 2, }, Snippet: "some random text", }}, Definition: []*xpb.Anchor{{ Ticket: "kythe://c?lang=otpl?path=/a/path#27-33", Kind: "/kythe/edge/defines/binding", Parent: "kythe://someCorpus?path=some/path#aFileNode", Start: &xpb.Location_Point{ ByteOffset: 27, LineNumber: 2, ColumnOffset: 10, }, End: &xpb.Location_Point{ ByteOffset: 33, LineNumber: 3, ColumnOffset: 5, }, Snippet: "here and ", }}, } xr := reply.CrossReferences[ticket] if xr == nil { log.Fatal("Missing expected CrossReferences") } if err := testutil.DeepEqual(expected, xr); err != nil { t.Fatal(err) } }
func TestReducer_Input(t *testing.T) { in := testInput([]*ipb.Path{{ Pivot: testNode("blah", "UNKNOWN"), // will be replaced by expectedPivot (below) Edges: testEdges("edgeKind", "target"), }, { Pivot: testNode("blah", "UNKNOWN2"), // will also be replaced Edges: testEdges("e1", "t1", "e2", "t2"), }, { // pivot-only edge will be sorted before anything else Pivot: testNode("blah", "test", "subkind", "input"), }, { Pivot: testNode("blah", "still UNKNOWN"), // replaced Edges: testEdges("e0", "t3"), }}) var found []*ipb.Path empty, err := reduce.Sort(ctx, in, &Reducer{ Func: func(ctx context.Context, pivot *ipb.Path_Node, rio ReducerIO) error { if len(found) > 0 { t.Fatalf("Already read paths: %v", found) } for { sortKey, p, err := rio.Next() if err == io.EOF { return nil } else if err != nil { t.Fatal(err) } else if sortKey != "" { t.Errorf("Unexpected sort key: %q", sortKey) } else if err := testutil.DeepEqual(pivot, p.Pivot); err != nil { t.Errorf("mismatched pivot: %v", err) } found = append(found, p) } }, }) if err != nil { t.Fatal(err) } expectedPivot := testNode("blah", "test", "subkind", "input") // Ordered the same as input expectedPaths := []*ipb.Path{{ Pivot: expectedPivot, Edges: testEdges("edgeKind", "target"), }, { Pivot: expectedPivot, Edges: testEdges("e1", "t1", "e2", "t2"), }, { Pivot: expectedPivot, Edges: testEdges("e0", "t3"), }} if err := testutil.DeepEqual(expectedPaths, found); err != nil { t.Error(err) } if s, err := empty.NextSplit(); err != io.EOF { t.Fatalf("Unexpected output/err: %v / %v", s, err) } }