Пример #1
0
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)
	}
}
Пример #2
0
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)
	}
}
Пример #3
0
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)
	}
}
Пример #4
0
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)
	}
}
Пример #5
0
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)
		}
	}
}
Пример #6
0
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)
		}
	}
}
Пример #7
0
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)
		}
	}
}
Пример #8
0
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)
	}
}
Пример #9
0
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)
	}
}
Пример #10
0
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)
	}
}
Пример #11
0
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)
	}
}
Пример #12
0
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)
		}
	}
}
Пример #13
0
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)
		}
	}
}
Пример #14
0
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)
	}
}
Пример #15
0
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)
	}
}
Пример #16
0
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)
		}
	}
}
Пример #17
0
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)
	}
}
Пример #18
0
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)
	}
}
Пример #19
0
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)
	}
}
Пример #20
0
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:])
		}
	}
}
Пример #21
0
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)
		}
	}
}
Пример #22
0
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)
	}
}
Пример #23
0
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)
	}
}