func (tbl *testTable) Construct(t *testing.T) xrefs.Service { p := make(testProtoTable) tickets := stringset.New() for _, n := range tbl.Nodes { tickets.Add(n.Ticket) } for _, es := range tbl.EdgeSets { tickets.Remove(es.EdgeSet.Source.Ticket) testutil.FatalOnErrT(t, "Error writing edge set: %v", p.Put(ctx, EdgeSetKey(mustFix(t, es.EdgeSet.Source.Ticket)), es)) } // Fill in EdgeSets for zero-degree nodes for ticket := range tickets { es := &srvpb.PagedEdgeSet{ EdgeSet: &srvpb.EdgeSet{ Source: getNode(ticket), }, } testutil.FatalOnErrT(t, "Error writing edge set: %v", p.Put(ctx, EdgeSetKey(mustFix(t, es.EdgeSet.Source.Ticket)), es)) } for _, ep := range tbl.EdgePages { testutil.FatalOnErrT(t, "Error writing edge page: %v", p.Put(ctx, []byte(edgePagesTablePrefix+ep.PageKey), ep)) } for _, d := range tbl.Decorations { testutil.FatalOnErrT(t, "Error writing file decorations: %v", p.Put(ctx, DecorationsKey(mustFix(t, d.FileTicket)), d)) } return NewCombinedTable(table.ProtoBatchParallel{p}) }
func TestAsyncNilCallbacks(t *testing.T) { done := make(chan struct{}, 1) err := StartAsync(exec.Command(find(t, "true")), &Callbacks{ OnExit: func(state *os.ProcessState, err error) { done <- struct{}{} }, }) testutil.FatalOnErrT(t, "Error starting async: %v", err) err = StartAsync(exec.Command(find(t, "false")), &Callbacks{ OnExit: func(state *os.ProcessState, err error) { done <- struct{}{} }, }) testutil.FatalOnErrT(t, "Error starting async: %v", err) err = StartAsync(exec.Command(find(t, "true")), &Callbacks{ OnSuccess: func(state *os.ProcessState) { done <- struct{}{} }, }) testutil.FatalOnErrT(t, "Error starting async: %v", err) timeout := time.After(5 * time.Second) for i := 0; i < 3; i++ { select { case <-done: case <-timeout: t.Fatal("Process did not finish before timeout") } } }
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.Node) != 1 { t.Fatalf("Expected 1 node for %q; found %d: {%v}", node.Ticket, len(reply.Node), reply) } else if expected := nodeInfo(node); !reflect.DeepEqual(reply.Node[0], expected) { t.Fatalf("Expected {%v}; received {%v}", expected, reply.Node[0]) } } var tickets []string var expected []*xpb.NodeInfo for _, n := range tbl.Nodes { tickets = append(tickets, n.Ticket) expected = append(expected, nodeInfo(n)) } reply, err := st.Nodes(ctx, &xpb.NodesRequest{Ticket: tickets}) testutil.FatalOnErrT(t, "NodesRequest error: %v", err) sort.Sort(byNodeTicket(expected)) sort.Sort(byNodeTicket(reply.Node)) if !reflect.DeepEqual(expected, reply.Node) { t.Fatalf("Expected {%v}; received {%v}", expected, reply.Node) } }
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) } }
// OrderTest tests the ordering of the streamed entries while reading from the // CreateFunc created graphstore.Service. func OrderTest(t *testing.T, create CreateFunc, batchSize int) { gs, destroy, err := create() testutil.FatalOnErrT(t, "CreateFunc error: %v", err) defer func() { testutil.FatalOnErrT(t, "gs close error: %v", gs.Close(ctx)) testutil.FatalOnErrT(t, "DestroyFunc error: %v", destroy()) }() updates := make([]spb.WriteRequest_Update, batchSize) req := &spb.WriteRequest{ Source: &spb.VName{}, Update: make([]*spb.WriteRequest_Update, batchSize), } for i := 0; i < 1024; i++ { randVName(req.Source, keySize) for j := 0; j < batchSize; j++ { randUpdate(&updates[j], keySize) req.Update[j] = &updates[j] } testutil.FatalOnErrT(t, "write error: %v", gs.Write(ctx, req)) } var lastEntry *spb.Entry testutil.FatalOnErrT(t, "entryLess error: %v", gs.Scan(ctx, new(spb.ScanRequest), func(entry *spb.Entry) error { if compare.Entries(lastEntry, entry) != compare.LT { return fmt.Errorf("expected {%v} < {%v}", lastEntry, entry) } return nil })) }
func TestParse(t *testing.T) { tests := []struct { str string sz Size }{ {"0", 0}, {"1024", 1024 * Byte}, {"100", 100 * Byte}, {"0tb", 0}, {"1b", Byte}, {"1kb", Kilobyte}, {"1mb", Megabyte}, {"1Gb", Gigabyte}, {"1tb", Terabyte}, {"1Pb", Petabyte}, {"1KiB", Kibibyte}, {"1mib", Mebibyte}, {"1gib", Gibibyte}, {"1tib", Tebibyte}, {"1PiB", Pebibyte}, {"4TB", 4 * Terabyte}, {"43.5MB", Size(43.5 * float64(Megabyte))}, } for _, test := range tests { found, err := Parse(test.str) testutil.FatalOnErrT(t, "Unexpected error: %v", err) if found != test.sz { t.Errorf("Parse(%q): expected: %s; found: %s", test.str, test.sz, found) } } }
func (tbl *testTable) Construct(t *testing.T) xrefs.Service { p := make(testProtoTable) for _, n := range tbl.Nodes { testutil.FatalOnErrT(t, "Error writing node: %v", p.Put(ctx, NodeKey(mustFix(t, n.Ticket)), n)) } for _, es := range tbl.EdgeSets { testutil.FatalOnErrT(t, "Error writing edge set: %v", p.Put(ctx, EdgeSetKey(mustFix(t, es.EdgeSet.SourceTicket)), es)) } for _, ep := range tbl.EdgePages { testutil.FatalOnErrT(t, "Error writing edge page: %v", p.Put(ctx, []byte(edgePagesTablePrefix+ep.PageKey), ep)) } for _, d := range tbl.Decorations { testutil.FatalOnErrT(t, "Error writing file decorations: %v", p.Put(ctx, DecorationsKey(mustFix(t, d.FileTicket)), d)) } return NewCombinedTable(table.ProtoBatchParallel{p}) }
func TestDriverErrorHandler(t *testing.T) { m := &mock{ t: t, Outputs: outs("a", "b", "c"), Compilations: comps("target1", "target2"), AnalyzeError: errFromAnalysis, } var analysisErr error d := &Driver{ Analyzer: m, Compilations: m, Output: m.out(), AnalysisError: func(_ context.Context, cu *apb.CompilationUnit, err error) error { analysisErr = err return nil // don't return err }, } testutil.FatalOnErrT(t, "Driver error: %v", d.Run(context.Background())) if len(m.Requests) != len(m.Compilations) { t.Errorf("Expected %d AnalysisRequests; found %v", len(m.Compilations), m.Requests) } if analysisErr != errFromAnalysis { t.Errorf("Expected AnalysisError: %v; found: %v", errFromAnalysis, analysisErr) } }
func TestDriver(t *testing.T) { m := &mock{ t: t, Outputs: outs("a", "b", "c"), Compilations: comps("target1", "target2"), } var setupIdx, teardownIdx int d := &Driver{ Analyzer: m, Compilations: m, Output: m.out(), Setup: func(_ context.Context, cu *apb.CompilationUnit) error { setupIdx++ return nil }, Teardown: func(_ context.Context, cu *apb.CompilationUnit) error { if setupIdx != teardownIdx+1 { t.Error("Teardown was not called directly after Setup/Analyze") } teardownIdx++ return nil }, } testutil.FatalOnErrT(t, "Driver error: %v", d.Run(context.Background())) if len(m.Requests) != len(m.Compilations) { t.Errorf("Expected %d AnalysisRequests; found %v", len(m.Compilations), m.Requests) } if setupIdx != len(m.Compilations) { t.Errorf("Expected %d calls to Setup; found %d", len(m.Compilations), setupIdx) } if teardownIdx != len(m.Compilations) { t.Errorf("Expected %d calls to Teardown; found %d", len(m.Compilations), teardownIdx) } }
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.FileTicket}, 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) } expected := refs(xrefs.NewNormalizer(d.SourceText), d.Decoration) if !reflect.DeepEqual(expected, reply.Reference) { t.Fatalf("Expected references %v; found %v", expected, reply.Reference) } expectedNodes := nodeInfos(tbl.Nodes[7:13]) sort.Sort(byNodeTicket(expectedNodes)) sort.Sort(byNodeTicket(reply.Node)) if err := testutil.DeepEqual(expectedNodes, 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[8] // and tbl.Nodes[10] are missing because [8] was an anchor in the edited // region and [10] was its target. expectedNodes := nodeInfos([]*srvpb.Node{ tbl.Nodes[7], tbl.Nodes[9], tbl.Nodes[11], tbl.Nodes[12], }) // Ensure patching affects the anchor node facts mapFacts(expectedNodes[2], map[string]string{ "/kythe/loc/start": "48", "/kythe/loc/end": "52", }) sort.Sort(byNodeTicket(expectedNodes)) sort.Sort(byNodeTicket(reply.Node)) if !reflect.DeepEqual(expectedNodes, reply.Node) { t.Fatalf("Expected nodes %v; found %v", expected, reply.Node) } }
func TestEdgesMissing(t *testing.T) { st := tbl.Construct(t) reply, err := st.Edges(ctx, &xpb.EdgesRequest{ Ticket: []string{"kythe:#someMissingTicket"}, }) testutil.FatalOnErrT(t, "EdgesRequest error: %v", err) if len(reply.EdgeSet) > 0 || len(reply.Node) > 0 || reply.NextPageToken != "" { t.Fatalf("Received unexpected reply for missing edges: {%v}", reply) } }
func TestNodesMissing(t *testing.T) { st := tbl.Construct(t) reply, err := st.Nodes(ctx, &xpb.NodesRequest{ Ticket: []string{"kythe:#someMissingTicket"}, }) testutil.FatalOnErrT(t, "NodesRequest error: %v", err) if len(reply.Node) > 0 { t.Fatalf("Received unexpected reply for missing node: {%v}", reply) } }
func TestDriverEmpty(t *testing.T) { m := &mock{t: t} d := &Driver{ Analyzer: m, Compilations: m, Output: m.out(), } testutil.FatalOnErrT(t, "Driver error: %v", d.Run(context.Background())) if len(m.Requests) != 0 { t.Fatalf("Unexpected AnalysisRequests: %v", m.Requests) } }
func (tbl *testTable) Construct(t *testing.T) *Table { p := make(testProtoTable) var tickets stringset.Set for _, n := range tbl.Nodes { tickets.Add(n.Ticket) } for _, es := range tbl.EdgeSets { tickets.Discard(es.Source.Ticket) testutil.FatalOnErrT(t, "Error writing edge set: %v", p.Put(ctx, EdgeSetKey(mustFix(t, es.Source.Ticket)), es)) } // Fill in EdgeSets for zero-degree nodes for ticket := range tickets { es := &srvpb.PagedEdgeSet{ Source: getNode(ticket), } testutil.FatalOnErrT(t, "Error writing edge set: %v", p.Put(ctx, EdgeSetKey(mustFix(t, es.Source.Ticket)), es)) } for _, ep := range tbl.EdgePages { testutil.FatalOnErrT(t, "Error writing edge page: %v", p.Put(ctx, EdgePageKey(ep.PageKey), ep)) } for _, d := range tbl.Decorations { testutil.FatalOnErrT(t, "Error writing file decorations: %v", p.Put(ctx, DecorationsKey(mustFix(t, d.File.Ticket)), d)) } for _, cr := range tbl.RefSets { testutil.FatalOnErrT(t, "Error writing cross-references: %v", p.Put(ctx, CrossReferencesKey(mustFix(t, cr.SourceTicket)), cr)) } for _, crp := range tbl.RefPages { testutil.FatalOnErrT(t, "Error writing cross-references: %v", p.Put(ctx, CrossReferencesPageKey(crp.PageKey), crp)) } return NewCombinedTable(table.ProtoBatchParallel{p}) }
func TestDecorationsEmpty(t *testing.T) { st := tbl.Construct(t) reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{ Location: &xpb.Location{ Ticket: tbl.Decorations[0].FileTicket, }, References: true, }) testutil.FatalOnErrT(t, "DecorationsRequest error: %v", err) if len(reply.Reference) > 0 { t.Fatalf("Unexpected DecorationsReply: {%v}", reply) } }
func TestCrossReferencesNone(t *testing.T) { st := tbl.Construct(t) reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{ Ticket: []string{"kythe://someCorpus?lang=otpl#sig2"}, DocumentationKind: xpb.CrossReferencesRequest_ALL_DOCUMENTATION, DefinitionKind: xpb.CrossReferencesRequest_ALL_DEFINITIONS, ReferenceKind: xpb.CrossReferencesRequest_ALL_REFERENCES, }) testutil.FatalOnErrT(t, "CrossReferencesRequest error: %v", err) if len(reply.CrossReferences) > 0 || len(reply.Nodes) > 0 { t.Fatalf("Expected empty CrossReferencesReply; found %v", reply) } }
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 TestIsUnique(t *testing.T) { d, err := New(HashSize * 2) testutil.FatalOnErrT(t, "Error creating Deduper: %v", err) tests := []struct { val string uniq bool }{ {"a", true}, {"a", false}, {"a", false}, {"b", true}, {"a", false}, {"b", false}, {"c", true}, // cache size exceeded (impl-specific behavior below) {"c", false}, {"b", false}, {"a", true}, // cache size exceeded {"c", false}, {"b", true}, } var unique, duplicates uint64 for _, test := range tests { uniq := d.IsUnique([]byte(test.val)) if uniq != test.uniq { t.Fatalf("Expected IsUnique(%v) to be %s; found it wasn't", test.uniq, test.val) } if uniq { unique++ } else { duplicates++ } if found := d.Unique(); unique != found { t.Fatalf("Expected Unique() == %d; found %d", unique, found) } if found := d.Duplicates(); duplicates != found { t.Fatalf("Expected Duplicates() == %d; found %d", unique, found) } } }
func TestDecorationsSourceText(t *testing.T) { expected := tbl.Decorations[0] st := tbl.Construct(t) reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{ Location: &xpb.Location{Ticket: expected.FileTicket}, SourceText: true, }) testutil.FatalOnErrT(t, "DecorationsRequest error: %v", err) if !bytes.Equal(reply.SourceText, expected.SourceText) { t.Errorf("Expected source text %q; found %q", string(expected.SourceText), string(reply.SourceText)) } if reply.Encoding != expected.Encoding { t.Errorf("Expected source text %q; found %q", expected.Encoding, reply.Encoding) } if len(reply.Reference) > 0 { t.Errorf("Unexpected references in DecorationsReply %v", reply.Reference) } }
func TestEdgesSinglePage(t *testing.T) { tests := []struct { Tickets []string Kinds []string EdgeSet *srvpb.PagedEdgeSet }{{ Tickets: []string{tbl.EdgeSets[0].EdgeSet.SourceTicket}, EdgeSet: tbl.EdgeSets[0], }, { Tickets: []string{tbl.EdgeSets[0].EdgeSet.SourceTicket}, Kinds: []string{"someEdgeKind", "anotherEdge"}, EdgeSet: tbl.EdgeSets[0], }} st := tbl.Construct(t) for _, test := range tests { reply, err := st.Edges(ctx, &xpb.EdgesRequest{ Ticket: test.Tickets, Kind: test.Kinds, }) testutil.FatalOnErrT(t, "EdgesRequest error: %v", err) if len(reply.Node) > 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.EdgeSet) != 1 { t.Errorf("Expected 1 EdgeSet in EdgesReply; found %d: {%v}", len(reply.EdgeSet), reply) } expected := edgeSet(test.Kinds, test.EdgeSet, nil) if !reflect.DeepEqual(reply.EdgeSet[0], expected) { t.Errorf("Expected {%v}; found {%v}", expected, reply.EdgeSet) } } }
func TestAsyncError(t *testing.T) { done := make(chan struct{}, 1) err := StartAsync(exec.Command(find(t, "false")), &Callbacks{ OnStart: func(p *os.Process) { if p == nil { t.Error("Process was nil") } done <- struct{}{} }, OnExit: func(state *os.ProcessState, err error) { if err == nil { t.Errorf("Process exited with no error: %v", state) } done <- struct{}{} }, OnSuccess: func(state *os.ProcessState) { t.Errorf("Process was unexpectedly successful: %v", state) }, OnError: func(state *os.ProcessState, err error) { if state.Success() { t.Errorf("Process was unexpectedly successful: %v", state) } if !state.Exited() { t.Errorf("Process did not exit: %v", state) } done <- struct{}{} }, }) testutil.FatalOnErrT(t, "Error starting async: %v", err) timeout := time.After(5 * time.Second) for i := 0; i < 3; i++ { select { case <-done: case <-timeout: t.Fatal("Process did not finish before timeout") } } }
func TestEdgesLastPage(t *testing.T) { tests := [][]string{ nil, // all kinds {"%/kythe/edge/ref"}, {"%/kythe/edge/defines/binding"}, } tickets := []string{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: tickets, Kind: kinds, }) testutil.FatalOnErrT(t, "EdgesRequest error: %v", err) if len(reply.Node) > 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.EdgeSet) != 1 { t.Fatalf("Expected 1 EdgeSet in EdgesReply; found %d: {%v}", len(reply.EdgeSet), reply) } expected := edgeSet(kinds, es, pages) if !reflect.DeepEqual(reply.EdgeSet[0], expected) { t.Errorf("Expected {%v}; found {%v}", expected, reply.EdgeSet) } } }
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 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 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 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 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) } }