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

     1  /*
     2   * Copyright 2015 The Kythe Authors. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *   http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package xrefs
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"flag"
    23  	"math"
    24  	"math/rand"
    25  	"reflect"
    26  	"sort"
    27  	"strconv"
    28  	"testing"
    29  	"testing/quick"
    30  
    31  	"bitbucket.org/creachadair/stringset"
    32  	"github.com/google/codesearch/index"
    33  	"kythe.io/kythe/go/services/xrefs"
    34  	"kythe.io/kythe/go/storage/table"
    35  	"kythe.io/kythe/go/test/testutil"
    36  	"kythe.io/kythe/go/util/compare"
    37  	"kythe.io/kythe/go/util/kytheuri"
    38  	"kythe.io/kythe/go/util/span"
    39  
    40  	"golang.org/x/text/encoding"
    41  	"golang.org/x/text/encoding/unicode"
    42  	"golang.org/x/text/transform"
    43  	"google.golang.org/protobuf/encoding/prototext"
    44  	"google.golang.org/protobuf/proto"
    45  
    46  	cpb "kythe.io/kythe/proto/common_go_proto"
    47  	srvpb "kythe.io/kythe/proto/serving_go_proto"
    48  	xpb "kythe.io/kythe/proto/xref_go_proto"
    49  )
    50  
    51  var (
    52  	ctx = context.Background()
    53  
    54  	nodes = []*srvpb.Node{
    55  		{
    56  			Ticket: "kythe://someCorpus?lang=otpl#signature",
    57  			Fact:   makeFactList("/kythe/node/kind", "testNode"),
    58  		}, {
    59  			Ticket: "kythe://someCorpus#aTicketSig",
    60  			Fact:   makeFactList("/kythe/node/kind", "testNode"),
    61  		}, {
    62  			Ticket: "kythe://someCorpus?lang=otpl#something",
    63  			Fact: makeFactList(
    64  				"/kythe/node/kind", "name",
    65  				"/some/other/fact", "value",
    66  			),
    67  		}, {
    68  			Ticket: "kythe://someCorpus?lang=otpl#sig2",
    69  			Fact:   makeFactList("/kythe/node/kind", "name"),
    70  		}, {
    71  			Ticket: "kythe://someCorpus?lang=otpl#sig3",
    72  			Fact:   makeFactList("/kythe/node/kind", "name"),
    73  		}, {
    74  			Ticket: "kythe://someCorpus?lang=otpl#sig4",
    75  			Fact:   makeFactList("/kythe/node/kind", "name"),
    76  		}, {
    77  			Ticket: "kythe://someCorpus?lang=otpl?path=/some/valid/path#a83md71",
    78  			Fact: makeFactList(
    79  				"/kythe/node/kind", "file",
    80  				"/kythe/text", "; some file content here\nfinal line\n",
    81  				"/kythe/text/encoding", "utf-8",
    82  			),
    83  		}, {
    84  			Ticket: "kythe://c?lang=otpl?path=/a/path#6-9",
    85  			Fact: makeFactList(
    86  				"/kythe/node/kind", "anchor",
    87  				"/kythe/loc/start", "6",
    88  				"/kythe/loc/end", "9",
    89  			),
    90  		}, {
    91  			Ticket: "kythe://c?lang=otpl?path=/a/path#27-33",
    92  			Fact: makeFactList(
    93  				"/kythe/node/kind", "anchor",
    94  				"/kythe/loc/start", "27",
    95  				"/kythe/loc/end", "33",
    96  			),
    97  		}, {
    98  			Ticket: "kythe://c?lang=otpl?path=/a/path#map",
    99  			Fact:   makeFactList("/kythe/node/kind", "function"),
   100  		}, {
   101  			Ticket: "kythe://core?lang=otpl#empty?",
   102  			Fact:   makeFactList("/kythe/node/kind", "function"),
   103  		}, {
   104  			Ticket: "kythe://c?lang=otpl?path=/a/path#51-55",
   105  			Fact: makeFactList(
   106  				"/kythe/node/kind", "anchor",
   107  				"/kythe/loc/start", "51",
   108  				"/kythe/loc/end", "55",
   109  			),
   110  		}, {
   111  			Ticket: "kythe://core?lang=otpl#cons",
   112  			Fact: makeFactList(
   113  				"/kythe/node/kind", "function",
   114  				// Canary to ensure we don't patch anchor facts in non-anchor nodes
   115  				"/kythe/loc/start", "51",
   116  			),
   117  		}, {
   118  			Ticket: "kythe://c?path=/a/path",
   119  			Fact: makeFactList(
   120  				"/kythe/node/kind", "file",
   121  				"/kythe/text/encoding", "utf-8",
   122  				"/kythe/text", "some random text\nhere and  \n  there\nsome random text\nhere and  \n  there\n",
   123  			),
   124  		}, {
   125  			Ticket: "kythe:?path=some/utf16/file",
   126  			Fact: []*cpb.Fact{{
   127  				Name:  "/kythe/text/encoding",
   128  				Value: []byte("utf-16le"),
   129  			}, {
   130  				Name:  "/kythe/node/kind",
   131  				Value: []byte("file"),
   132  			}, {
   133  				Name:  "/kythe/text",
   134  				Value: encodeText(utf16LE, "これはいくつかのテキストです\n"),
   135  			}},
   136  		}, {
   137  			Ticket: "kythe:?path=some/utf16/file#0-4",
   138  			Fact: makeFactList(
   139  				"/kythe/node/kind", "anchor",
   140  				"/kythe/loc/start", "0",
   141  				"/kythe/loc/end", "4",
   142  			),
   143  		}, {
   144  			Ticket: "kythe:#documented",
   145  			Fact: makeFactList(
   146  				"/kythe/node/kind", "record",
   147  			),
   148  			DefinitionLocation: &srvpb.ExpandedAnchor{
   149  				Ticket: "kythe:?path=def/location#defDoc",
   150  				Span: &cpb.Span{
   151  					Start: &cpb.Point{
   152  						ByteOffset:   1,
   153  						LineNumber:   1,
   154  						ColumnOffset: 1,
   155  					},
   156  					End: &cpb.Point{
   157  						ByteOffset:   4,
   158  						LineNumber:   1,
   159  						ColumnOffset: 4,
   160  					},
   161  				},
   162  			},
   163  		}, {
   164  			Ticket: "kythe:#documentedBy",
   165  			Fact: makeFactList(
   166  				"/kythe/node/kind", "record",
   167  			),
   168  		}, {
   169  			Ticket: "kythe:#childDoc",
   170  			Fact: makeFactList(
   171  				"/kythe/node/kind", "record",
   172  			),
   173  		}, {
   174  			Ticket: "kythe:#childDocBy",
   175  			Fact: makeFactList(
   176  				"/kythe/node/kind", "record",
   177  			),
   178  		}, {
   179  			Ticket: "kythe:#secondChildDoc",
   180  			Fact: makeFactList(
   181  				"/kythe/node/kind", "record",
   182  			),
   183  		}, {
   184  			Ticket: "kythe://someCorpus?lang=otpl#withRelated",
   185  			Fact:   makeFactList("/kythe/node/kind", "testNode"),
   186  		}, {
   187  			Ticket: "kythe://someCorpus?lang=otpl#withInfos",
   188  			Fact:   makeFactList("/kythe/node/kind", "testNode"),
   189  		}, {
   190  			Ticket: "kythe:#aliasNode",
   191  			Fact:   makeFactList("/kythe/node/kind", "talias"),
   192  		}, {
   193  			Ticket: "kythe:#indirect",
   194  			Fact:   makeFactList("/kythe/node/kind", "indirect"),
   195  		},
   196  	}
   197  
   198  	tbl = &testTable{
   199  		Nodes: nodes,
   200  		Decorations: []*srvpb.FileDecorations{
   201  			{
   202  				File: &srvpb.File{
   203  					Ticket:   "kythe://someCorpus?lang=otpl?path=/some/valid/path#a83md71",
   204  					Text:     []byte("; some file content here\nfinal line\n"),
   205  					Encoding: "utf-8",
   206  				},
   207  			},
   208  			{
   209  				File: &srvpb.File{
   210  					Ticket: "kythe://someCorpus?lang=otpl?path=/a/path#b7te37tn4",
   211  					Text: []byte(`(defn map [f coll]
   212    (if (empty? coll)
   213      []
   214      (cons (f (first coll)) (map f (rest coll)))))
   215  `),
   216  					Encoding: "utf-8",
   217  				},
   218  				Decoration: []*srvpb.FileDecorations_Decoration{
   219  					{
   220  						Anchor: &srvpb.RawAnchor{
   221  							Ticket:      "kythe://c?lang=otpl?path=/a/path#6-9",
   222  							StartOffset: 6,
   223  							EndOffset:   9,
   224  
   225  							BuildConfiguration: "test-build-config",
   226  						},
   227  						Kind:   "/kythe/edge/defines/binding",
   228  						Target: "kythe://c?lang=otpl?path=/a/path#map",
   229  					},
   230  					{
   231  						Anchor: &srvpb.RawAnchor{
   232  							Ticket:      "kythe://c?lang=otpl?path=/a/path#27-33",
   233  							StartOffset: 27,
   234  							EndOffset:   33,
   235  						},
   236  						Kind:   "/kythe/refs",
   237  						Target: "kythe://core?lang=otpl#empty?",
   238  
   239  						SemanticScope: "kythe://c?lang=otpl?path=/a/path#map",
   240  					},
   241  					{
   242  						Anchor: &srvpb.RawAnchor{
   243  							Ticket:      "kythe://c?lang=otpl?path=/a/path#51-55",
   244  							StartOffset: 51,
   245  							EndOffset:   55,
   246  						},
   247  						Kind:   "/kythe/refs",
   248  						Target: "kythe://core?lang=otpl#cons",
   249  
   250  						SemanticScope: "kythe://c?lang=otpl?path=/a/path#map",
   251  					},
   252  				},
   253  				TargetOverride: []*srvpb.FileDecorations_Override{{
   254  					Kind:                 srvpb.FileDecorations_Override_EXTENDS,
   255  					Overriding:           "kythe://c?lang=otpl?path=/a/path#map",
   256  					Overridden:           "kythe://c?lang=otpl#map",
   257  					OverriddenDefinition: "kythe://c?lang=otpl?path=/b/path#mapDef",
   258  					MarkedSource: &cpb.MarkedSource{
   259  						Kind:    cpb.MarkedSource_IDENTIFIER,
   260  						PreText: "OverrideMS",
   261  					},
   262  				}, {
   263  					Kind:                 srvpb.FileDecorations_Override_EXTENDS,
   264  					Overriding:           "kythe://c?lang=otpl?path=/a/path#map",
   265  					Overridden:           "kythe://c?lang=otpl#map",
   266  					OverriddenDefinition: "kythe://c?lang=otpl?path=/b/path#mapDefOtherConfig",
   267  					MarkedSource: &cpb.MarkedSource{
   268  						Kind:    cpb.MarkedSource_IDENTIFIER,
   269  						PreText: "OverrideMS",
   270  					},
   271  				}},
   272  				Target: getNodes("kythe://c?lang=otpl?path=/a/path#map", "kythe://core?lang=otpl#empty?", "kythe://core?lang=otpl#cons"),
   273  				TargetDefinitions: []*srvpb.ExpandedAnchor{{
   274  					Ticket:             "kythe://c?lang=otpl?path=/b/path#mapDef",
   275  					BuildConfiguration: "test-build-config",
   276  					Span: &cpb.Span{
   277  						Start: &cpb.Point{LineNumber: 1},
   278  						End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
   279  					},
   280  				}, {
   281  					Ticket:             "kythe://c?lang=otpl?path=/b/path#mapDefOtherConfig",
   282  					BuildConfiguration: "other-build-config",
   283  					Span: &cpb.Span{
   284  						Start: &cpb.Point{LineNumber: 1},
   285  						End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
   286  					},
   287  				}},
   288  				Diagnostic: []*cpb.Diagnostic{
   289  					{Message: "Test diagnostic message"},
   290  					{
   291  						Span: &cpb.Span{
   292  							Start: &cpb.Point{
   293  								ByteOffset:   6,
   294  								LineNumber:   1,
   295  								ColumnOffset: 6,
   296  							},
   297  							End: &cpb.Point{
   298  								ByteOffset:   9,
   299  								LineNumber:   1,
   300  								ColumnOffset: 9,
   301  							},
   302  						},
   303  						Message: "Test diagnostic message w/ Span",
   304  					},
   305  				},
   306  			},
   307  			{
   308  				File: &srvpb.File{
   309  					Ticket:   "kythe://corpus?path=/some/proto.proto?root=generated",
   310  					Text:     []byte("// Generated by /some/proto.proto"),
   311  					Encoding: "utf-8",
   312  				},
   313  				GeneratedBy: []string{"kythe://corpus?path=/some/proto.proto"},
   314  			},
   315  			{
   316  				File: &srvpb.File{
   317  					Ticket:   "kythe://corpus?path=file/infos",
   318  					Text:     []byte(`some file with infos`),
   319  					Encoding: "utf-8",
   320  				},
   321  				Decoration: []*srvpb.FileDecorations_Decoration{
   322  					{
   323  						Anchor: &srvpb.RawAnchor{
   324  							Ticket:      "kythe://corpus?lang=lang?path=file/infos#0-4",
   325  							StartOffset: 0,
   326  							EndOffset:   4,
   327  						},
   328  						Kind:   "/kythe/edge/includes/ref",
   329  						Target: "kythe://corpus?path=another/file",
   330  					},
   331  					{
   332  						Anchor: &srvpb.RawAnchor{
   333  							Ticket:      "kythe://corpus?lang=lang?path=file/infos#5-9",
   334  							StartOffset: 5,
   335  							EndOffset:   9,
   336  						},
   337  						Kind:             "/kythe/edge/ref",
   338  						Target:           "kythe://corpus?path=def/file#node",
   339  						TargetDefinition: "kythe://corpus?path=def/file#anchor",
   340  					},
   341  				},
   342  				TargetDefinitions: []*srvpb.ExpandedAnchor{{
   343  					Ticket: "kythe://corpus?path=def/file#anchor",
   344  					Span: &cpb.Span{
   345  						Start: &cpb.Point{LineNumber: 1},
   346  						End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
   347  					},
   348  				}},
   349  				GeneratedBy: []string{"kythe://corpus?path=some/proto.proto"},
   350  				FileInfo: []*srvpb.FileInfo{
   351  					fi(cp("corpus", "", "file/infos"), "overallFileRev"),
   352  					fi(cp("corpus", "", "some/proto.proto"), "generatedRev"),
   353  					fi(cp("corpus", "", "another/file"), "anotherFileRev"),
   354  					fi(cp("corpus", "", "def/file"), "defFileRev"),
   355  				},
   356  			},
   357  		},
   358  
   359  		RefSets: []*srvpb.PagedCrossReferences{{
   360  			SourceTicket: "kythe://someCorpus?lang=otpl#signature",
   361  			SourceNode:   getNode("kythe://someCorpus?lang=otpl#signature"),
   362  
   363  			Group: []*srvpb.PagedCrossReferences_Group{{
   364  				BuildConfig: "testConfig",
   365  				Kind:        "%/kythe/edge/defines/binding",
   366  				ScopedReference: []*srvpb.PagedCrossReferences_ScopedReference{{
   367  					SemanticScope: "kythe://someCorpus?lang=otpl#scope",
   368  					Scope: &srvpb.ExpandedAnchor{
   369  						Ticket:             "kythe://c?lang=otpl?path=/a/path#scope",
   370  						BuildConfiguration: "testConfig",
   371  						Kind:               "/kythe/edge/defines/binding",
   372  
   373  						Span: &cpb.Span{
   374  							Start: &cpb.Point{
   375  								ByteOffset:   27,
   376  								LineNumber:   2,
   377  								ColumnOffset: 10,
   378  							},
   379  							End: &cpb.Point{
   380  								ByteOffset:   33,
   381  								LineNumber:   3,
   382  								ColumnOffset: 5,
   383  							},
   384  						},
   385  
   386  						SnippetSpan: &cpb.Span{
   387  							Start: &cpb.Point{
   388  								ByteOffset: 17,
   389  								LineNumber: 2,
   390  							},
   391  							End: &cpb.Point{
   392  								ByteOffset:   27,
   393  								LineNumber:   2,
   394  								ColumnOffset: 10,
   395  							},
   396  						},
   397  						Snippet: "here and  ",
   398  					},
   399  					MarkedSource: &cpb.MarkedSource{
   400  						Kind:    cpb.MarkedSource_IDENTIFIER,
   401  						PreText: "Scope",
   402  					},
   403  					Reference: []*srvpb.ExpandedAnchor{{
   404  						Ticket:             "kythe://c?lang=otpl?path=/a/path#27-33",
   405  						BuildConfiguration: "testConfig",
   406  
   407  						Span: &cpb.Span{
   408  							Start: &cpb.Point{
   409  								ByteOffset:   27,
   410  								LineNumber:   2,
   411  								ColumnOffset: 10,
   412  							},
   413  							End: &cpb.Point{
   414  								ByteOffset:   33,
   415  								LineNumber:   3,
   416  								ColumnOffset: 5,
   417  							},
   418  						},
   419  
   420  						SnippetSpan: &cpb.Span{
   421  							Start: &cpb.Point{
   422  								ByteOffset: 17,
   423  								LineNumber: 2,
   424  							},
   425  							End: &cpb.Point{
   426  								ByteOffset:   27,
   427  								LineNumber:   2,
   428  								ColumnOffset: 10,
   429  							},
   430  						},
   431  						Snippet: "here and  ",
   432  					}},
   433  				}},
   434  			}},
   435  			PageIndex: []*srvpb.PagedCrossReferences_PageIndex{{
   436  				PageKey: "aBcDeFg",
   437  				Kind:    "%/kythe/edge/ref",
   438  				Count:   2,
   439  			}},
   440  		}, {
   441  			SourceTicket: "kythe://someCorpus?lang=otpl#withRelated",
   442  			SourceNode:   getNode("kythe://someCorpus?lang=otpl#withRelated"),
   443  			MarkedSource: &cpb.MarkedSource{
   444  				Kind:    cpb.MarkedSource_IDENTIFIER,
   445  				PreText: "id",
   446  			},
   447  
   448  			Group: []*srvpb.PagedCrossReferences_Group{{
   449  				Kind: "/kythe/edge/extends",
   450  				RelatedNode: []*srvpb.PagedCrossReferences_RelatedNode{{
   451  					Node: &srvpb.Node{
   452  						Ticket: "kythe:#someRelatedNode",
   453  					},
   454  				}},
   455  			}, {
   456  				Kind: "/kythe/edge/param",
   457  				RelatedNode: []*srvpb.PagedCrossReferences_RelatedNode{{
   458  					Ordinal: 0,
   459  					Node: &srvpb.Node{
   460  						Ticket: "kythe:#someParameter0",
   461  					},
   462  				}, {
   463  					Ordinal: 1,
   464  					Node: &srvpb.Node{
   465  						Ticket: "kythe:#someParameter1",
   466  					},
   467  				}},
   468  			}},
   469  		}, {
   470  			SourceTicket: "kythe://someCorpus?lang=otpl#withInfos",
   471  			SourceNode:   getNode("kythe://someCorpus?lang=otpl#withInfos"),
   472  
   473  			Group: []*srvpb.PagedCrossReferences_Group{{
   474  				Kind: "%/kythe/edge/ref",
   475  				Anchor: []*srvpb.ExpandedAnchor{{
   476  					Ticket: "kythe://corpus?lang=otpl?path=some/file#27-33",
   477  
   478  					Span: &cpb.Span{
   479  						Start: &cpb.Point{
   480  							ByteOffset:   27,
   481  							LineNumber:   2,
   482  							ColumnOffset: 10,
   483  						},
   484  						End: &cpb.Point{
   485  							ByteOffset:   33,
   486  							LineNumber:   3,
   487  							ColumnOffset: 5,
   488  						},
   489  					},
   490  				}},
   491  
   492  				FileInfo: []*srvpb.FileInfo{
   493  					fi(cp("corpus", "", "some/file"), "someFileRev"),
   494  				},
   495  			}},
   496  		}, {
   497  			SourceTicket: "kythe://someCorpus?lang=otpl#withMerge",
   498  			SourceNode:   getNode("kythe://someCorpus?lang=otpl#withMerge"),
   499  			MergeWith: []string{
   500  				"kythe://someCorpus?lang=otpl#withCallers",
   501  				"kythe://someCorpus?lang=otpl#withRelated",
   502  			},
   503  		}, {
   504  			SourceTicket: "kythe://someCorpus?lang=otpl#withCallers",
   505  			SourceNode:   getNode("kythe://someCorpus?lang=otpl#withCallers"),
   506  
   507  			Group: []*srvpb.PagedCrossReferences_Group{{
   508  				Kind: "#internal/ref/call/direct",
   509  				Caller: []*srvpb.PagedCrossReferences_Caller{{
   510  					Caller: &srvpb.ExpandedAnchor{
   511  						Ticket: "kythe:?path=someFile#someCallerAnchor",
   512  						Span:   arbitrarySpan,
   513  					},
   514  					MarkedSource: &cpb.MarkedSource{
   515  						Kind:    cpb.MarkedSource_IDENTIFIER,
   516  						PreText: "id",
   517  					},
   518  					SemanticCaller: "kythe:#someCaller",
   519  					Callsite: []*srvpb.ExpandedAnchor{{
   520  						Ticket: "kythe:?path=someFile#someCallsiteAnchor",
   521  					}},
   522  				}},
   523  			}, {
   524  				Kind: "#internal/ref/call/override",
   525  				Caller: []*srvpb.PagedCrossReferences_Caller{{
   526  					Caller: &srvpb.ExpandedAnchor{
   527  						Ticket: "kythe:?path=someFile#someOverrideCallerAnchor1",
   528  						Span:   arbitrarySpan,
   529  					},
   530  					Callsite: []*srvpb.ExpandedAnchor{{
   531  						Ticket: "kythe:?path=someFile#someCallsiteAnchor",
   532  						Span:   arbitrarySpan,
   533  					}},
   534  				}, {
   535  					Caller: &srvpb.ExpandedAnchor{
   536  						Ticket: "kythe:?path=someFile#someOverrideCallerAnchor2",
   537  						Span:   arbitrarySpan,
   538  					},
   539  					Callsite: []*srvpb.ExpandedAnchor{{
   540  						Ticket: "kythe:?path=someFile#someCallsiteAnchor",
   541  					}},
   542  				}},
   543  			}},
   544  		}, {
   545  			SourceTicket: "kythe:#aliasNode",
   546  			SourceNode:   getNode("kythe:#aliasNode"),
   547  			Group: []*srvpb.PagedCrossReferences_Group{{
   548  				Kind: "%/kythe/edge/aliases",
   549  				RelatedNode: []*srvpb.PagedCrossReferences_RelatedNode{{
   550  					Node: getNode("kythe://someCorpus?lang=otpl#signature"),
   551  				}},
   552  			}, {
   553  				Kind: "/kythe/edge/indirect",
   554  				RelatedNode: []*srvpb.PagedCrossReferences_RelatedNode{{
   555  					Node: getNode("kythe:#indirect"),
   556  				}},
   557  			}, {
   558  				Kind: "%/kythe/edge/ref",
   559  				Anchor: []*srvpb.ExpandedAnchor{{
   560  					Ticket: "kythe:?path=somewhere#0-9",
   561  
   562  					Span: &cpb.Span{
   563  						Start: &cpb.Point{LineNumber: 1},
   564  						End:   &cpb.Point{ByteOffset: 9, LineNumber: 1, ColumnOffset: 9},
   565  					},
   566  				}},
   567  			}},
   568  		}, {
   569  			SourceTicket: "kythe:#indirect",
   570  			SourceNode:   getNode("kythe:#indirect"),
   571  			Group: []*srvpb.PagedCrossReferences_Group{{
   572  				Kind: "%/kythe/edge/ref",
   573  				Anchor: []*srvpb.ExpandedAnchor{{
   574  					Ticket: "kythe:?path=somewhereElse#0-9",
   575  
   576  					Span: &cpb.Span{
   577  						Start: &cpb.Point{LineNumber: 1},
   578  						End:   &cpb.Point{ByteOffset: 9, LineNumber: 1, ColumnOffset: 9},
   579  					},
   580  				}},
   581  			}},
   582  			PageIndex: []*srvpb.PagedCrossReferences_PageIndex{{
   583  				PageKey: "indirectPage",
   584  				Kind:    "/kythe/edge/indirect",
   585  				Count:   1,
   586  			}},
   587  		}},
   588  		RefPages: []*srvpb.PagedCrossReferences_Page{{
   589  			PageKey: "aBcDeFg",
   590  			Group: &srvpb.PagedCrossReferences_Group{
   591  				Kind: "%/kythe/edge/ref",
   592  				Anchor: []*srvpb.ExpandedAnchor{{
   593  					Ticket: "kythe:?path=some/utf16/file#0-4",
   594  
   595  					Span: &cpb.Span{
   596  						Start: &cpb.Point{LineNumber: 1},
   597  						End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
   598  					},
   599  
   600  					SnippetSpan: &cpb.Span{
   601  						Start: &cpb.Point{
   602  							LineNumber: 1,
   603  						},
   604  						End: &cpb.Point{
   605  							ByteOffset:   28,
   606  							LineNumber:   1,
   607  							ColumnOffset: 28,
   608  						},
   609  					},
   610  					Snippet: "これはいくつかのテキストです",
   611  				}, {
   612  					Ticket: "kythe://c?lang=otpl?path=/a/path#51-55",
   613  
   614  					Span: &cpb.Span{
   615  						Start: &cpb.Point{
   616  							ByteOffset:   51,
   617  							LineNumber:   4,
   618  							ColumnOffset: 15,
   619  						},
   620  						End: &cpb.Point{
   621  							ByteOffset:   55,
   622  							LineNumber:   5,
   623  							ColumnOffset: 2,
   624  						},
   625  					},
   626  
   627  					SnippetSpan: &cpb.Span{
   628  						Start: &cpb.Point{
   629  							ByteOffset: 36,
   630  							LineNumber: 4,
   631  						},
   632  						End: &cpb.Point{
   633  							ByteOffset:   52,
   634  							LineNumber:   4,
   635  							ColumnOffset: 16,
   636  						},
   637  					},
   638  					Snippet: "some random text",
   639  				}},
   640  			},
   641  		}, {
   642  			PageKey: "indirectPage",
   643  			Group: &srvpb.PagedCrossReferences_Group{
   644  				Kind: "/kythe/edge/indirect",
   645  				RelatedNode: []*srvpb.PagedCrossReferences_RelatedNode{{
   646  					Node: getNode("kythe://someCorpus?lang=otpl#signature"),
   647  				}},
   648  			},
   649  		}},
   650  
   651  		Documents: []*srvpb.Document{{
   652  			Ticket:  "kythe:#documented",
   653  			RawText: "some documentation text",
   654  			MarkedSource: &cpb.MarkedSource{
   655  				Kind:    cpb.MarkedSource_IDENTIFIER,
   656  				PreText: "DocumentBuilderFactory",
   657  			},
   658  			Node:        getNodes("kythe:#documented"),
   659  			ChildTicket: []string{"kythe:#childDoc", "kythe:#childDocBy"},
   660  		}, {
   661  			Ticket:       "kythe:#documentedBy",
   662  			DocumentedBy: "kythe:#documented",
   663  			RawText:      "replaced documentation text",
   664  			MarkedSource: &cpb.MarkedSource{
   665  				Kind:    cpb.MarkedSource_IDENTIFIER,
   666  				PreText: "ReplacedDocumentBuilderFactory",
   667  			},
   668  			Node: getNodes("kythe:#documentedBy"),
   669  		}, {
   670  			Ticket:  "kythe:#childDoc",
   671  			RawText: "child document text",
   672  			Node:    getNodes("kythe:#childDoc"),
   673  		}, {
   674  			Ticket:       "kythe:#childDocBy",
   675  			DocumentedBy: "kythe:#secondChildDoc",
   676  			Node:         getNodes("kythe:#childDocBy"),
   677  		}, {
   678  			Ticket:  "kythe:#secondChildDoc",
   679  			RawText: "second child document text",
   680  			Node:    getNodes("kythe:#secondChildDoc"),
   681  		}},
   682  	}
   683  
   684  	arbitrarySpan = &cpb.Span{
   685  		Start: &cpb.Point{LineNumber: 1},
   686  		End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
   687  	}
   688  )
   689  
   690  func getNodes(ts ...string) []*srvpb.Node {
   691  	var res []*srvpb.Node
   692  	for _, t := range ts {
   693  		res = append(res, getNode(t))
   694  	}
   695  	return res
   696  }
   697  
   698  func getNode(t string) *srvpb.Node {
   699  	for _, n := range nodes {
   700  		if n.Ticket == t {
   701  			return n
   702  		}
   703  	}
   704  	return &srvpb.Node{Ticket: t}
   705  }
   706  
   707  var utf16LE = unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
   708  
   709  func encodeText(e encoding.Encoding, text string) []byte {
   710  	res, _, err := transform.Bytes(e.NewEncoder(), []byte(text))
   711  	if err != nil {
   712  		panic(err)
   713  	}
   714  	return res
   715  }
   716  
   717  func TestDecorationsRefs(t *testing.T) {
   718  	d := tbl.Decorations[1]
   719  
   720  	st := tbl.Construct(t)
   721  	reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
   722  		Location:   &xpb.Location{Ticket: d.File.Ticket},
   723  		References: true,
   724  		Filter:     []string{"**"},
   725  	})
   726  	testutil.Fatalf(t, "DecorationsRequest error: %v", err)
   727  
   728  	if reply.SourceText != nil {
   729  		t.Errorf("Unexpected source text: %q", string(reply.SourceText))
   730  	}
   731  	if reply.Encoding != "" {
   732  		t.Errorf("Unexpected encoding: %q", reply.Encoding)
   733  	}
   734  
   735  	expected := refs(span.NewNormalizer(d.File.Text), d.Decoration, d.FileInfo)
   736  	for _, ref := range expected {
   737  		ref.SemanticScope = "" // not requested
   738  	}
   739  	if err := testutil.DeepEqual(expected, reply.Reference); err != nil {
   740  		t.Fatal(err)
   741  	}
   742  
   743  	expectedNodes := nodeInfos(tbl.Nodes[9:11], tbl.Nodes[12:13])
   744  	if err := testutil.DeepEqual(expectedNodes, reply.Nodes); err != nil {
   745  		t.Fatal(err)
   746  	}
   747  }
   748  
   749  func TestDecorationsRefScopes(t *testing.T) {
   750  	d := tbl.Decorations[1]
   751  
   752  	st := tbl.Construct(t)
   753  	reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
   754  		Location:       &xpb.Location{Ticket: d.File.Ticket},
   755  		References:     true,
   756  		SemanticScopes: true,
   757  	})
   758  	testutil.Fatalf(t, "DecorationsRequest error: %v", err)
   759  
   760  	expected := refs(span.NewNormalizer(d.File.Text), d.Decoration, d.FileInfo)
   761  	if err := testutil.DeepEqual(expected, reply.Reference); err != nil {
   762  		t.Fatal(err)
   763  	}
   764  }
   765  
   766  func TestDecorationsExtendsOverrides(t *testing.T) {
   767  	d := tbl.Decorations[1]
   768  
   769  	st := tbl.Construct(t)
   770  	reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
   771  		Location:          &xpb.Location{Ticket: d.File.Ticket},
   772  		References:        true,
   773  		ExtendsOverrides:  true,
   774  		SemanticScopes:    true,
   775  		TargetDefinitions: true,
   776  	})
   777  	testutil.Fatalf(t, "DecorationsRequest error: %v", err)
   778  
   779  	expectedOverrides := map[string]*xpb.DecorationsReply_Overrides{
   780  		"kythe://c?lang=otpl?path=/a/path#map": &xpb.DecorationsReply_Overrides{
   781  			Override: []*xpb.DecorationsReply_Override{{
   782  				Kind:             xpb.DecorationsReply_Override_EXTENDS,
   783  				Target:           "kythe://c?lang=otpl#map",
   784  				TargetDefinition: "kythe://c?lang=otpl?path=/b/path#mapDef",
   785  				MarkedSource: &cpb.MarkedSource{
   786  					Kind:    cpb.MarkedSource_IDENTIFIER,
   787  					PreText: "OverrideMS",
   788  				},
   789  			}, {
   790  				Kind:             xpb.DecorationsReply_Override_EXTENDS,
   791  				Target:           "kythe://c?lang=otpl#map",
   792  				TargetDefinition: "kythe://c?lang=otpl?path=/b/path#mapDefOtherConfig",
   793  				MarkedSource: &cpb.MarkedSource{
   794  					Kind:    cpb.MarkedSource_IDENTIFIER,
   795  					PreText: "OverrideMS",
   796  				},
   797  			}},
   798  		},
   799  	}
   800  	if err := testutil.DeepEqual(expectedOverrides, reply.ExtendsOverrides); err != nil {
   801  		t.Fatal(err)
   802  	}
   803  
   804  	expectedDefs := map[string]*xpb.Anchor{
   805  		"kythe://c?lang=otpl?path=/b/path#mapDef": &xpb.Anchor{
   806  			Ticket:      "kythe://c?lang=otpl?path=/b/path#mapDef",
   807  			Parent:      "kythe://c?path=/b/path",
   808  			BuildConfig: "test-build-config",
   809  			Span: &cpb.Span{
   810  				Start: &cpb.Point{LineNumber: 1},
   811  				End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
   812  			},
   813  		},
   814  		"kythe://c?lang=otpl?path=/b/path#mapDefOtherConfig": &xpb.Anchor{
   815  			Ticket:      "kythe://c?lang=otpl?path=/b/path#mapDefOtherConfig",
   816  			Parent:      "kythe://c?path=/b/path",
   817  			BuildConfig: "other-build-config",
   818  			Span: &cpb.Span{
   819  				Start: &cpb.Point{LineNumber: 1},
   820  				End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
   821  			},
   822  		},
   823  	}
   824  	if err := testutil.DeepEqual(expectedDefs, reply.DefinitionLocations); err != nil {
   825  		t.Fatal(err)
   826  	}
   827  }
   828  
   829  func TestDecorationsBuildConfig(t *testing.T) {
   830  	d := tbl.Decorations[1]
   831  	st := tbl.Construct(t)
   832  
   833  	t.Run("MissingConfig", func(t *testing.T) {
   834  		reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
   835  			Location:          &xpb.Location{Ticket: d.File.Ticket},
   836  			References:        true,
   837  			BuildConfig:       []string{"missing-build-config"},
   838  			ExtendsOverrides:  true,
   839  			TargetDefinitions: true,
   840  		})
   841  		testutil.Fatalf(t, "DecorationsRequest error: %v", err)
   842  
   843  		if err := testutil.DeepEqual([]*xpb.DecorationsReply_Reference{}, reply.Reference); err != nil {
   844  			t.Fatal(err)
   845  		}
   846  	})
   847  
   848  	t.Run("FoundConfig", func(t *testing.T) {
   849  		reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
   850  			Location:          &xpb.Location{Ticket: d.File.Ticket},
   851  			References:        true,
   852  			BuildConfig:       []string{"test-build-config"},
   853  			ExtendsOverrides:  true,
   854  			TargetDefinitions: true,
   855  		})
   856  		testutil.Fatalf(t, "DecorationsRequest error: %v", err)
   857  
   858  		expected := refs(span.NewNormalizer(d.File.Text), d.Decoration[:1], d.FileInfo)
   859  		if err := testutil.DeepEqual(expected, reply.Reference); err != nil {
   860  			t.Fatal(err)
   861  		}
   862  
   863  		expectedOverrides := map[string]*xpb.DecorationsReply_Overrides{
   864  			"kythe://c?lang=otpl?path=/a/path#map": &xpb.DecorationsReply_Overrides{
   865  				Override: []*xpb.DecorationsReply_Override{{
   866  					Kind:             xpb.DecorationsReply_Override_EXTENDS,
   867  					Target:           "kythe://c?lang=otpl#map",
   868  					TargetDefinition: "kythe://c?lang=otpl?path=/b/path#mapDef",
   869  					MarkedSource: &cpb.MarkedSource{
   870  						Kind:    cpb.MarkedSource_IDENTIFIER,
   871  						PreText: "OverrideMS",
   872  					},
   873  				}},
   874  			},
   875  		}
   876  		if err := testutil.DeepEqual(expectedOverrides, reply.ExtendsOverrides); err != nil {
   877  			t.Fatal(err)
   878  		}
   879  
   880  		expectedDefs := map[string]*xpb.Anchor{
   881  			"kythe://c?lang=otpl?path=/b/path#mapDef": &xpb.Anchor{
   882  				Ticket:      "kythe://c?lang=otpl?path=/b/path#mapDef",
   883  				Parent:      "kythe://c?path=/b/path",
   884  				BuildConfig: "test-build-config",
   885  				Span: &cpb.Span{
   886  					Start: &cpb.Point{LineNumber: 1},
   887  					End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
   888  				},
   889  			},
   890  		}
   891  		if err := testutil.DeepEqual(expectedDefs, reply.DefinitionLocations); err != nil {
   892  			t.Fatal(err)
   893  		}
   894  	})
   895  }
   896  
   897  func TestDecorationsDirtyBuffer(t *testing.T) {
   898  	d := tbl.Decorations[1]
   899  
   900  	st := tbl.Construct(t)
   901  	// s/empty?/seq/
   902  	dirty := []byte(`(defn map [f coll]
   903    (if (seq coll)
   904      []
   905      (cons (f (first coll)) (map f (rest coll)))))
   906  `)
   907  	reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
   908  		Location:    &xpb.Location{Ticket: d.File.Ticket},
   909  		DirtyBuffer: dirty,
   910  		References:  true,
   911  		Filter:      []string{"**"},
   912  	})
   913  	testutil.Fatalf(t, "DecorationsRequest error: %v", err)
   914  
   915  	if reply.SourceText != nil {
   916  		t.Errorf("Unexpected source text: %q", string(reply.SourceText))
   917  	}
   918  	if reply.Encoding != "" {
   919  		t.Errorf("Unexpected encoding: %q", reply.Encoding)
   920  	}
   921  
   922  	expected := []*xpb.DecorationsReply_Reference{
   923  		{
   924  			// Unpatched anchor for "map"
   925  			TargetTicket: "kythe://c?lang=otpl?path=/a/path#map",
   926  			Kind:         "/kythe/edge/defines/binding",
   927  
   928  			Span: &cpb.Span{
   929  				Start: &cpb.Point{
   930  					ByteOffset:   6,
   931  					LineNumber:   1,
   932  					ColumnOffset: 6,
   933  				},
   934  				End: &cpb.Point{
   935  					ByteOffset:   9,
   936  					LineNumber:   1,
   937  					ColumnOffset: 9,
   938  				},
   939  			},
   940  
   941  			BuildConfig: "test-build-config",
   942  		},
   943  		// Skipped anchor for "empty?" (inside edit region)
   944  		{
   945  			// Patched anchor for "cons" (moved backwards by 3 bytes)
   946  			TargetTicket: "kythe://core?lang=otpl#cons",
   947  			Kind:         "/kythe/refs",
   948  			Span: &cpb.Span{
   949  				Start: &cpb.Point{
   950  					ByteOffset:   48,
   951  					LineNumber:   4,
   952  					ColumnOffset: 5,
   953  				},
   954  				End: &cpb.Point{
   955  					ByteOffset:   52,
   956  					LineNumber:   4,
   957  					ColumnOffset: 9,
   958  				},
   959  			},
   960  		},
   961  	}
   962  	if err := testutil.DeepEqual(expected, reply.Reference); err != nil {
   963  		t.Fatal(err)
   964  	}
   965  
   966  	// These are a subset of the anchor nodes in tbl.Decorations[1].  tbl.Nodes[10] is missing because
   967  	// it is the target of an anchor in the edited region.
   968  	expectedNodes := nodeInfos([]*srvpb.Node{tbl.Nodes[9], tbl.Nodes[12]})
   969  	if err := testutil.DeepEqual(expectedNodes, reply.Nodes); err != nil {
   970  		t.Fatal(err)
   971  	}
   972  }
   973  
   974  func TestDecorationsNotFound(t *testing.T) {
   975  	st := tbl.Construct(t)
   976  	reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
   977  		Location: &xpb.Location{
   978  			Ticket: "kythe:#someMissingFileTicket",
   979  		},
   980  	})
   981  
   982  	if err == nil {
   983  		t.Fatalf("Unexpected DecorationsReply: {%v}", reply)
   984  	} else if err != xrefs.ErrDecorationsNotFound {
   985  		t.Fatalf("Unexpected Decorations error: %v", err)
   986  	}
   987  }
   988  
   989  func TestDecorationsEmpty(t *testing.T) {
   990  	st := tbl.Construct(t)
   991  	reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
   992  		Location: &xpb.Location{
   993  			Ticket: tbl.Decorations[0].File.Ticket,
   994  		},
   995  		References: true,
   996  	})
   997  	testutil.Fatalf(t, "DecorationsRequest error: %v", err)
   998  
   999  	if len(reply.Reference) > 0 {
  1000  		t.Fatalf("Unexpected DecorationsReply: {%v}", reply)
  1001  	}
  1002  }
  1003  
  1004  func TestDecorationsSourceText(t *testing.T) {
  1005  	expected := tbl.Decorations[0]
  1006  
  1007  	st := tbl.Construct(t)
  1008  	reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
  1009  		Location:   &xpb.Location{Ticket: expected.File.Ticket},
  1010  		SourceText: true,
  1011  	})
  1012  	testutil.Fatalf(t, "DecorationsRequest error: %v", err)
  1013  
  1014  	if !bytes.Equal(reply.SourceText, expected.File.Text) {
  1015  		t.Errorf("Expected source text %q; found %q", string(expected.File.Text), string(reply.SourceText))
  1016  	}
  1017  	if reply.Encoding != expected.File.Encoding {
  1018  		t.Errorf("Expected source text %q; found %q", expected.File.Encoding, reply.Encoding)
  1019  	}
  1020  	if len(reply.Reference) > 0 {
  1021  		t.Errorf("Unexpected references in DecorationsReply %v", reply.Reference)
  1022  	}
  1023  }
  1024  
  1025  func TestDecorationsGeneratedBy(t *testing.T) {
  1026  	st := tbl.Construct(t)
  1027  	reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
  1028  		Location: &xpb.Location{Ticket: "kythe://corpus?path=/some/proto.proto?root=generated"},
  1029  	})
  1030  	testutil.Fatalf(t, "DecorationsRequest error: %v", err)
  1031  
  1032  	expected := &xpb.DecorationsReply{
  1033  		Location: &xpb.Location{Ticket: "kythe://corpus?path=/some/proto.proto?root=generated"},
  1034  		GeneratedByFile: []*xpb.File{{
  1035  			CorpusPath: &cpb.CorpusPath{
  1036  				Corpus: "corpus",
  1037  				Path:   "/some/proto.proto",
  1038  			},
  1039  		}},
  1040  	}
  1041  
  1042  	if diff := compare.ProtoDiff(expected, reply); diff != "" {
  1043  		t.Fatalf("Unexpected diff (- expected; + found):\n%s", diff)
  1044  	}
  1045  }
  1046  
  1047  func TestDecorationsRevisions(t *testing.T) {
  1048  	st := tbl.Construct(t)
  1049  
  1050  	t.Run("file/generated_by", func(t *testing.T) {
  1051  		reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
  1052  			Location: &xpb.Location{Ticket: "kythe://corpus?path=file/infos"},
  1053  		})
  1054  		testutil.Fatalf(t, "DecorationsRequest error: %v", err)
  1055  
  1056  		expected := &xpb.DecorationsReply{
  1057  			Location: &xpb.Location{Ticket: "kythe://corpus?path=file/infos"},
  1058  			Revision: "overallFileRev",
  1059  			GeneratedByFile: []*xpb.File{{
  1060  				CorpusPath: &cpb.CorpusPath{
  1061  					Corpus: "corpus",
  1062  					Path:   "some/proto.proto",
  1063  				},
  1064  				Revision: "generatedRev",
  1065  			}},
  1066  		}
  1067  
  1068  		if diff := compare.ProtoDiff(expected, reply); diff != "" {
  1069  			t.Fatalf("Unexpected diff (- expected; + found):\n%s", diff)
  1070  		}
  1071  	})
  1072  
  1073  	t.Run("target_revision", func(t *testing.T) {
  1074  		reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
  1075  			Location:   &xpb.Location{Ticket: "kythe://corpus?path=file/infos"},
  1076  			References: true,
  1077  		})
  1078  		testutil.Fatalf(t, "DecorationsRequest error: %v", err)
  1079  
  1080  		expected := &xpb.DecorationsReply{
  1081  			Location: &xpb.Location{Ticket: "kythe://corpus?path=file/infos"},
  1082  			Revision: "overallFileRev",
  1083  			GeneratedByFile: []*xpb.File{{
  1084  				CorpusPath: &cpb.CorpusPath{
  1085  					Corpus: "corpus",
  1086  					Path:   "some/proto.proto",
  1087  				},
  1088  				Revision: "generatedRev",
  1089  			}},
  1090  			Reference: []*xpb.DecorationsReply_Reference{{
  1091  				TargetTicket:   "kythe://corpus?path=another/file",
  1092  				Kind:           "/kythe/edge/includes/ref",
  1093  				TargetRevision: "anotherFileRev",
  1094  				Span: &cpb.Span{
  1095  					Start: &cpb.Point{
  1096  						ByteOffset:   0,
  1097  						LineNumber:   1,
  1098  						ColumnOffset: 0,
  1099  					},
  1100  					End: &cpb.Point{
  1101  						ByteOffset:   4,
  1102  						LineNumber:   1,
  1103  						ColumnOffset: 4,
  1104  					},
  1105  				},
  1106  			}, {
  1107  				TargetTicket: "kythe://corpus?path=def/file#node",
  1108  				Kind:         "/kythe/edge/ref",
  1109  				Span: &cpb.Span{
  1110  					Start: &cpb.Point{
  1111  						ByteOffset:   5,
  1112  						LineNumber:   1,
  1113  						ColumnOffset: 5,
  1114  					},
  1115  					End: &cpb.Point{
  1116  						ByteOffset:   9,
  1117  						LineNumber:   1,
  1118  						ColumnOffset: 9,
  1119  					},
  1120  				},
  1121  			}},
  1122  		}
  1123  
  1124  		if diff := compare.ProtoDiff(expected, reply); diff != "" {
  1125  			t.Fatalf("Unexpected diff (- expected; + found):\n%s", diff)
  1126  		}
  1127  	})
  1128  
  1129  	t.Run("target_defs", func(t *testing.T) {
  1130  		reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
  1131  			Location:          &xpb.Location{Ticket: "kythe://corpus?path=file/infos"},
  1132  			References:        true,
  1133  			TargetDefinitions: true,
  1134  		})
  1135  		testutil.Fatalf(t, "DecorationsRequest error: %v", err)
  1136  
  1137  		expected := &xpb.DecorationsReply{
  1138  			Location: &xpb.Location{Ticket: "kythe://corpus?path=file/infos"},
  1139  			Revision: "overallFileRev",
  1140  			GeneratedByFile: []*xpb.File{{
  1141  				CorpusPath: &cpb.CorpusPath{
  1142  					Corpus: "corpus",
  1143  					Path:   "some/proto.proto",
  1144  				},
  1145  				Revision: "generatedRev",
  1146  			}},
  1147  			Reference: []*xpb.DecorationsReply_Reference{{
  1148  				TargetTicket:   "kythe://corpus?path=another/file",
  1149  				Kind:           "/kythe/edge/includes/ref",
  1150  				TargetRevision: "anotherFileRev",
  1151  				Span: &cpb.Span{
  1152  					Start: &cpb.Point{
  1153  						ByteOffset:   0,
  1154  						LineNumber:   1,
  1155  						ColumnOffset: 0,
  1156  					},
  1157  					End: &cpb.Point{
  1158  						ByteOffset:   4,
  1159  						LineNumber:   1,
  1160  						ColumnOffset: 4,
  1161  					},
  1162  				},
  1163  			}, {
  1164  				TargetTicket:     "kythe://corpus?path=def/file#node",
  1165  				TargetDefinition: "kythe://corpus?path=def/file#anchor",
  1166  				Kind:             "/kythe/edge/ref",
  1167  				Span: &cpb.Span{
  1168  					Start: &cpb.Point{
  1169  						ByteOffset:   5,
  1170  						LineNumber:   1,
  1171  						ColumnOffset: 5,
  1172  					},
  1173  					End: &cpb.Point{
  1174  						ByteOffset:   9,
  1175  						LineNumber:   1,
  1176  						ColumnOffset: 9,
  1177  					},
  1178  				},
  1179  			}},
  1180  			DefinitionLocations: map[string]*xpb.Anchor{
  1181  				"kythe://corpus?path=def/file#anchor": &xpb.Anchor{
  1182  					Ticket:   "kythe://corpus?path=def/file#anchor",
  1183  					Parent:   "kythe://corpus?path=def/file",
  1184  					Revision: "defFileRev",
  1185  					Span: &cpb.Span{
  1186  						Start: &cpb.Point{LineNumber: 1},
  1187  						End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
  1188  					},
  1189  				},
  1190  			},
  1191  		}
  1192  
  1193  		if diff := compare.ProtoDiff(expected, reply); diff != "" {
  1194  			t.Fatalf("Unexpected diff (- expected; + found):\n%s", diff)
  1195  		}
  1196  	})
  1197  }
  1198  
  1199  func TestDecorationsDiagnostics(t *testing.T) {
  1200  	d := tbl.Decorations[1]
  1201  
  1202  	st := tbl.Construct(t)
  1203  	reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
  1204  		Location:    &xpb.Location{Ticket: d.File.Ticket},
  1205  		Diagnostics: true,
  1206  	})
  1207  	testutil.Fatalf(t, "DecorationsRequest error: %v", err)
  1208  
  1209  	expected := tbl.Decorations[1].Diagnostic
  1210  	if err := testutil.DeepEqual(expected, reply.Diagnostic); err != nil {
  1211  		t.Fatal(err)
  1212  	}
  1213  }
  1214  
  1215  func TestCrossReferencesNone(t *testing.T) {
  1216  	st := tbl.Construct(t)
  1217  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  1218  		Ticket:         []string{"kythe://someCorpus?lang=otpl#sig2"},
  1219  		DefinitionKind: xpb.CrossReferencesRequest_ALL_DEFINITIONS,
  1220  		ReferenceKind:  xpb.CrossReferencesRequest_ALL_REFERENCES,
  1221  	})
  1222  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  1223  
  1224  	if len(reply.CrossReferences) > 0 || len(reply.Nodes) > 0 {
  1225  		t.Fatalf("Expected empty CrossReferencesReply; found %v", reply)
  1226  	}
  1227  }
  1228  
  1229  func TestCrossReferences(t *testing.T) {
  1230  	ticket := "kythe://someCorpus?lang=otpl#signature"
  1231  
  1232  	st := tbl.Construct(t)
  1233  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  1234  		Ticket:         []string{ticket},
  1235  		DefinitionKind: xpb.CrossReferencesRequest_BINDING_DEFINITIONS,
  1236  		ReferenceKind:  xpb.CrossReferencesRequest_ALL_REFERENCES,
  1237  		Snippets:       xpb.SnippetsKind_DEFAULT,
  1238  	})
  1239  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  1240  
  1241  	expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  1242  		Ticket: ticket,
  1243  
  1244  		Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  1245  			Ticket: "kythe:?path=some/utf16/file#0-4",
  1246  			Kind:   "/kythe/edge/ref",
  1247  			Parent: "kythe:?path=some/utf16/file",
  1248  
  1249  			Span: &cpb.Span{
  1250  				Start: &cpb.Point{LineNumber: 1},
  1251  				End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
  1252  			},
  1253  
  1254  			SnippetSpan: &cpb.Span{
  1255  				Start: &cpb.Point{
  1256  					LineNumber: 1,
  1257  				},
  1258  				End: &cpb.Point{
  1259  					ByteOffset:   28,
  1260  					LineNumber:   1,
  1261  					ColumnOffset: 28,
  1262  				},
  1263  			},
  1264  			Snippet: "これはいくつかのテキストです",
  1265  		}}, {Anchor: &xpb.Anchor{
  1266  			Ticket: "kythe://c?lang=otpl?path=/a/path#51-55",
  1267  			Kind:   "/kythe/edge/ref",
  1268  			Parent: "kythe://c?path=/a/path",
  1269  
  1270  			Span: &cpb.Span{
  1271  				Start: &cpb.Point{
  1272  					ByteOffset:   51,
  1273  					LineNumber:   4,
  1274  					ColumnOffset: 15,
  1275  				},
  1276  				End: &cpb.Point{
  1277  					ByteOffset:   55,
  1278  					LineNumber:   5,
  1279  					ColumnOffset: 2,
  1280  				},
  1281  			},
  1282  
  1283  			SnippetSpan: &cpb.Span{
  1284  				Start: &cpb.Point{
  1285  					ByteOffset: 36,
  1286  					LineNumber: 4,
  1287  				},
  1288  				End: &cpb.Point{
  1289  					ByteOffset:   52,
  1290  					LineNumber:   4,
  1291  					ColumnOffset: 16,
  1292  				},
  1293  			},
  1294  			Snippet: "some random text",
  1295  		}}},
  1296  
  1297  		Definition: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  1298  			Ticket:      "kythe://c?lang=otpl?path=/a/path#27-33",
  1299  			Kind:        "/kythe/edge/defines/binding",
  1300  			Parent:      "kythe://c?path=/a/path",
  1301  			BuildConfig: "testConfig",
  1302  
  1303  			Span: &cpb.Span{
  1304  				Start: &cpb.Point{
  1305  					ByteOffset:   27,
  1306  					LineNumber:   2,
  1307  					ColumnOffset: 10,
  1308  				},
  1309  				End: &cpb.Point{
  1310  					ByteOffset:   33,
  1311  					LineNumber:   3,
  1312  					ColumnOffset: 5,
  1313  				},
  1314  			},
  1315  
  1316  			SnippetSpan: &cpb.Span{
  1317  				Start: &cpb.Point{
  1318  					ByteOffset: 17,
  1319  					LineNumber: 2,
  1320  				},
  1321  				End: &cpb.Point{
  1322  					ByteOffset:   27,
  1323  					LineNumber:   2,
  1324  					ColumnOffset: 10,
  1325  				},
  1326  			},
  1327  			Snippet: "here and  ",
  1328  		}}},
  1329  	}
  1330  
  1331  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  1332  		Definitions: 1,
  1333  		References:  2,
  1334  		RefEdgeToCount: map[string]int64{
  1335  			"/kythe/edge/ref": 2,
  1336  		},
  1337  	}, reply.Total); err != nil {
  1338  		t.Error(err)
  1339  	}
  1340  	wantFiltered := &xpb.CrossReferencesReply_Total{}
  1341  	if err := testutil.DeepEqual(wantFiltered, reply.Filtered); err != nil {
  1342  		t.Error(err)
  1343  	}
  1344  
  1345  	xr := reply.CrossReferences[ticket]
  1346  	if xr == nil {
  1347  		t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  1348  	}
  1349  	sort.Sort(byOffset(xr.Reference))
  1350  
  1351  	if err := testutil.DeepEqual(expected, xr); err != nil {
  1352  		t.Fatal(err)
  1353  	}
  1354  }
  1355  
  1356  func TestCrossReferencesScoped(t *testing.T) {
  1357  	ticket := "kythe://someCorpus?lang=otpl#signature"
  1358  
  1359  	st := tbl.Construct(t)
  1360  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  1361  		Ticket:         []string{ticket},
  1362  		DefinitionKind: xpb.CrossReferencesRequest_BINDING_DEFINITIONS,
  1363  		ReferenceKind:  xpb.CrossReferencesRequest_ALL_REFERENCES,
  1364  		Snippets:       xpb.SnippetsKind_DEFAULT,
  1365  		SemanticScopes: true,
  1366  	})
  1367  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  1368  
  1369  	expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  1370  		Ticket: ticket,
  1371  
  1372  		Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  1373  			Ticket: "kythe:?path=some/utf16/file#0-4",
  1374  			Kind:   "/kythe/edge/ref",
  1375  			Parent: "kythe:?path=some/utf16/file",
  1376  
  1377  			Span: &cpb.Span{
  1378  				Start: &cpb.Point{LineNumber: 1},
  1379  				End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
  1380  			},
  1381  
  1382  			SnippetSpan: &cpb.Span{
  1383  				Start: &cpb.Point{
  1384  					LineNumber: 1,
  1385  				},
  1386  				End: &cpb.Point{
  1387  					ByteOffset:   28,
  1388  					LineNumber:   1,
  1389  					ColumnOffset: 28,
  1390  				},
  1391  			},
  1392  			Snippet: "これはいくつかのテキストです",
  1393  		}}, {Anchor: &xpb.Anchor{
  1394  			Ticket: "kythe://c?lang=otpl?path=/a/path#51-55",
  1395  			Kind:   "/kythe/edge/ref",
  1396  			Parent: "kythe://c?path=/a/path",
  1397  
  1398  			Span: &cpb.Span{
  1399  				Start: &cpb.Point{
  1400  					ByteOffset:   51,
  1401  					LineNumber:   4,
  1402  					ColumnOffset: 15,
  1403  				},
  1404  				End: &cpb.Point{
  1405  					ByteOffset:   55,
  1406  					LineNumber:   5,
  1407  					ColumnOffset: 2,
  1408  				},
  1409  			},
  1410  
  1411  			SnippetSpan: &cpb.Span{
  1412  				Start: &cpb.Point{
  1413  					ByteOffset: 36,
  1414  					LineNumber: 4,
  1415  				},
  1416  				End: &cpb.Point{
  1417  					ByteOffset:   52,
  1418  					LineNumber:   4,
  1419  					ColumnOffset: 16,
  1420  				},
  1421  			},
  1422  			Snippet: "some random text",
  1423  		}}},
  1424  
  1425  		Definition: []*xpb.CrossReferencesReply_RelatedAnchor{{
  1426  			Ticket: "kythe://someCorpus?lang=otpl#scope",
  1427  			MarkedSource: &cpb.MarkedSource{
  1428  				Kind:    cpb.MarkedSource_IDENTIFIER,
  1429  				PreText: "Scope",
  1430  			},
  1431  			Anchor: &xpb.Anchor{
  1432  				Ticket:      "kythe://c?lang=otpl?path=/a/path#scope",
  1433  				Kind:        "/kythe/edge/defines/binding",
  1434  				Parent:      "kythe://c?path=/a/path",
  1435  				BuildConfig: "testConfig",
  1436  
  1437  				Span: &cpb.Span{
  1438  					Start: &cpb.Point{
  1439  						ByteOffset:   27,
  1440  						LineNumber:   2,
  1441  						ColumnOffset: 10,
  1442  					},
  1443  					End: &cpb.Point{
  1444  						ByteOffset:   33,
  1445  						LineNumber:   3,
  1446  						ColumnOffset: 5,
  1447  					},
  1448  				},
  1449  
  1450  				SnippetSpan: &cpb.Span{
  1451  					Start: &cpb.Point{
  1452  						ByteOffset: 17,
  1453  						LineNumber: 2,
  1454  					},
  1455  					End: &cpb.Point{
  1456  						ByteOffset:   27,
  1457  						LineNumber:   2,
  1458  						ColumnOffset: 10,
  1459  					},
  1460  				},
  1461  				Snippet: "here and  ",
  1462  			},
  1463  			Site: []*xpb.Anchor{{
  1464  				Ticket:      "kythe://c?lang=otpl?path=/a/path#27-33",
  1465  				Kind:        "/kythe/edge/defines/binding",
  1466  				Parent:      "kythe://c?path=/a/path",
  1467  				BuildConfig: "testConfig",
  1468  
  1469  				Span: &cpb.Span{
  1470  					Start: &cpb.Point{
  1471  						ByteOffset:   27,
  1472  						LineNumber:   2,
  1473  						ColumnOffset: 10,
  1474  					},
  1475  					End: &cpb.Point{
  1476  						ByteOffset:   33,
  1477  						LineNumber:   3,
  1478  						ColumnOffset: 5,
  1479  					},
  1480  				},
  1481  
  1482  				SnippetSpan: &cpb.Span{
  1483  					Start: &cpb.Point{
  1484  						ByteOffset: 17,
  1485  						LineNumber: 2,
  1486  					},
  1487  					End: &cpb.Point{
  1488  						ByteOffset:   27,
  1489  						LineNumber:   2,
  1490  						ColumnOffset: 10,
  1491  					},
  1492  				},
  1493  				Snippet: "here and  ",
  1494  			}},
  1495  		}},
  1496  	}
  1497  
  1498  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  1499  		Definitions: 1,
  1500  		References:  2,
  1501  		RefEdgeToCount: map[string]int64{
  1502  			"/kythe/edge/ref": 2,
  1503  		},
  1504  	}, reply.Total); err != nil {
  1505  		t.Error(err)
  1506  	}
  1507  	wantFiltered := &xpb.CrossReferencesReply_Total{}
  1508  	if err := testutil.DeepEqual(wantFiltered, reply.Filtered); err != nil {
  1509  		t.Error(err)
  1510  	}
  1511  
  1512  	xr := reply.CrossReferences[ticket]
  1513  	if xr == nil {
  1514  		t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  1515  	}
  1516  	sort.Sort(byOffset(xr.Reference))
  1517  
  1518  	if err := testutil.DeepEqual(expected, xr); err != nil {
  1519  		t.Fatal(err)
  1520  	}
  1521  }
  1522  
  1523  func TestCrossReferencesPaging(t *testing.T) {
  1524  	ticket := "kythe://someCorpus?lang=otpl#signature"
  1525  
  1526  	st := tbl.Construct(t)
  1527  	req := &xpb.CrossReferencesRequest{
  1528  		Ticket:         []string{ticket},
  1529  		DefinitionKind: xpb.CrossReferencesRequest_BINDING_DEFINITIONS,
  1530  		ReferenceKind:  xpb.CrossReferencesRequest_ALL_REFERENCES,
  1531  		Snippets:       xpb.SnippetsKind_DEFAULT,
  1532  		SemanticScopes: true,
  1533  		PageSize:       1,
  1534  	}
  1535  
  1536  	var anchors []*xpb.CrossReferencesReply_RelatedAnchor
  1537  	for {
  1538  		reply, err := st.CrossReferences(ctx, req)
  1539  		testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  1540  		xr := reply.GetCrossReferences()[ticket]
  1541  		anchors = append(anchors, xr.GetReference()...)
  1542  		anchors = append(anchors, xr.GetDefinition()...)
  1543  		anchors = append(anchors, xr.GetDeclaration()...)
  1544  		anchors = append(anchors, xr.GetCaller()...)
  1545  
  1546  		req.PageToken = reply.GetNextPageToken()
  1547  		if req.PageToken == "" {
  1548  			break
  1549  		}
  1550  		t.Logf("NextPageToken: %s", req.PageToken)
  1551  	}
  1552  
  1553  	expected := []*xpb.CrossReferencesReply_RelatedAnchor{
  1554  		{
  1555  			Ticket: "kythe://someCorpus?lang=otpl#scope",
  1556  			MarkedSource: &cpb.MarkedSource{
  1557  				Kind:    cpb.MarkedSource_IDENTIFIER,
  1558  				PreText: "Scope",
  1559  			},
  1560  			Anchor: &xpb.Anchor{
  1561  				Ticket:      "kythe://c?lang=otpl?path=/a/path#scope",
  1562  				Kind:        "/kythe/edge/defines/binding",
  1563  				Parent:      "kythe://c?path=/a/path",
  1564  				BuildConfig: "testConfig",
  1565  
  1566  				Span: &cpb.Span{
  1567  					Start: &cpb.Point{
  1568  						ByteOffset:   27,
  1569  						LineNumber:   2,
  1570  						ColumnOffset: 10,
  1571  					},
  1572  					End: &cpb.Point{
  1573  						ByteOffset:   33,
  1574  						LineNumber:   3,
  1575  						ColumnOffset: 5,
  1576  					},
  1577  				},
  1578  
  1579  				SnippetSpan: &cpb.Span{
  1580  					Start: &cpb.Point{
  1581  						ByteOffset: 17,
  1582  						LineNumber: 2,
  1583  					},
  1584  					End: &cpb.Point{
  1585  						ByteOffset:   27,
  1586  						LineNumber:   2,
  1587  						ColumnOffset: 10,
  1588  					},
  1589  				},
  1590  				Snippet: "here and  ",
  1591  			},
  1592  			Site: []*xpb.Anchor{{
  1593  				Ticket:      "kythe://c?lang=otpl?path=/a/path#27-33",
  1594  				Kind:        "/kythe/edge/defines/binding",
  1595  				Parent:      "kythe://c?path=/a/path",
  1596  				BuildConfig: "testConfig",
  1597  
  1598  				Span: &cpb.Span{
  1599  					Start: &cpb.Point{
  1600  						ByteOffset:   27,
  1601  						LineNumber:   2,
  1602  						ColumnOffset: 10,
  1603  					},
  1604  					End: &cpb.Point{
  1605  						ByteOffset:   33,
  1606  						LineNumber:   3,
  1607  						ColumnOffset: 5,
  1608  					},
  1609  				},
  1610  
  1611  				SnippetSpan: &cpb.Span{
  1612  					Start: &cpb.Point{
  1613  						ByteOffset: 17,
  1614  						LineNumber: 2,
  1615  					},
  1616  					End: &cpb.Point{
  1617  						ByteOffset:   27,
  1618  						LineNumber:   2,
  1619  						ColumnOffset: 10,
  1620  					},
  1621  				},
  1622  				Snippet: "here and  ",
  1623  			}},
  1624  		},
  1625  		{
  1626  			Anchor: &xpb.Anchor{
  1627  				Ticket: "kythe:?path=some/utf16/file#0-4",
  1628  				Kind:   "/kythe/edge/ref",
  1629  				Parent: "kythe:?path=some/utf16/file",
  1630  
  1631  				Span: &cpb.Span{
  1632  					Start: &cpb.Point{LineNumber: 1},
  1633  					End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
  1634  				},
  1635  
  1636  				SnippetSpan: &cpb.Span{
  1637  					Start: &cpb.Point{
  1638  						LineNumber: 1,
  1639  					},
  1640  					End: &cpb.Point{
  1641  						ByteOffset:   28,
  1642  						LineNumber:   1,
  1643  						ColumnOffset: 28,
  1644  					},
  1645  				},
  1646  				Snippet: "これはいくつかのテキストです",
  1647  			},
  1648  		},
  1649  		{
  1650  			Anchor: &xpb.Anchor{
  1651  				Ticket: "kythe://c?lang=otpl?path=/a/path#51-55",
  1652  				Kind:   "/kythe/edge/ref",
  1653  				Parent: "kythe://c?path=/a/path",
  1654  
  1655  				Span: &cpb.Span{
  1656  					Start: &cpb.Point{
  1657  						ByteOffset:   51,
  1658  						LineNumber:   4,
  1659  						ColumnOffset: 15,
  1660  					},
  1661  					End: &cpb.Point{
  1662  						ByteOffset:   55,
  1663  						LineNumber:   5,
  1664  						ColumnOffset: 2,
  1665  					},
  1666  				},
  1667  
  1668  				SnippetSpan: &cpb.Span{
  1669  					Start: &cpb.Point{
  1670  						ByteOffset: 36,
  1671  						LineNumber: 4,
  1672  					},
  1673  					End: &cpb.Point{
  1674  						ByteOffset:   52,
  1675  						LineNumber:   4,
  1676  						ColumnOffset: 16,
  1677  					},
  1678  				},
  1679  				Snippet: "some random text",
  1680  			},
  1681  		},
  1682  	}
  1683  
  1684  	if err := testutil.DeepEqual(expected, anchors); err != nil {
  1685  		t.Fatal(err)
  1686  	}
  1687  }
  1688  
  1689  func TestCrossReferencesReadAhead(t *testing.T) {
  1690  	const flagName = "page_read_ahead"
  1691  	val := flag.Lookup(flagName).Value.String()
  1692  	testutil.Fatalf(t, "flag.Set: %v", flag.Set(flagName, "4"))
  1693  	defer flag.Set(flagName, val)
  1694  
  1695  	ticket := "kythe://someCorpus?lang=otpl#signature"
  1696  
  1697  	st := tbl.Construct(t)
  1698  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  1699  		Ticket:         []string{ticket},
  1700  		DefinitionKind: xpb.CrossReferencesRequest_BINDING_DEFINITIONS,
  1701  		ReferenceKind:  xpb.CrossReferencesRequest_ALL_REFERENCES,
  1702  		Snippets:       xpb.SnippetsKind_DEFAULT,
  1703  	})
  1704  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  1705  
  1706  	expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  1707  		Ticket: ticket,
  1708  
  1709  		Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  1710  			Ticket: "kythe:?path=some/utf16/file#0-4",
  1711  			Kind:   "/kythe/edge/ref",
  1712  			Parent: "kythe:?path=some/utf16/file",
  1713  
  1714  			Span: &cpb.Span{
  1715  				Start: &cpb.Point{LineNumber: 1},
  1716  				End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
  1717  			},
  1718  
  1719  			SnippetSpan: &cpb.Span{
  1720  				Start: &cpb.Point{
  1721  					LineNumber: 1,
  1722  				},
  1723  				End: &cpb.Point{
  1724  					ByteOffset:   28,
  1725  					LineNumber:   1,
  1726  					ColumnOffset: 28,
  1727  				},
  1728  			},
  1729  			Snippet: "これはいくつかのテキストです",
  1730  		}}, {Anchor: &xpb.Anchor{
  1731  			Ticket: "kythe://c?lang=otpl?path=/a/path#51-55",
  1732  			Kind:   "/kythe/edge/ref",
  1733  			Parent: "kythe://c?path=/a/path",
  1734  
  1735  			Span: &cpb.Span{
  1736  				Start: &cpb.Point{
  1737  					ByteOffset:   51,
  1738  					LineNumber:   4,
  1739  					ColumnOffset: 15,
  1740  				},
  1741  				End: &cpb.Point{
  1742  					ByteOffset:   55,
  1743  					LineNumber:   5,
  1744  					ColumnOffset: 2,
  1745  				},
  1746  			},
  1747  
  1748  			SnippetSpan: &cpb.Span{
  1749  				Start: &cpb.Point{
  1750  					ByteOffset: 36,
  1751  					LineNumber: 4,
  1752  				},
  1753  				End: &cpb.Point{
  1754  					ByteOffset:   52,
  1755  					LineNumber:   4,
  1756  					ColumnOffset: 16,
  1757  				},
  1758  			},
  1759  			Snippet: "some random text",
  1760  		}}},
  1761  
  1762  		Definition: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  1763  			Ticket:      "kythe://c?lang=otpl?path=/a/path#27-33",
  1764  			Kind:        "/kythe/edge/defines/binding",
  1765  			Parent:      "kythe://c?path=/a/path",
  1766  			BuildConfig: "testConfig",
  1767  
  1768  			Span: &cpb.Span{
  1769  				Start: &cpb.Point{
  1770  					ByteOffset:   27,
  1771  					LineNumber:   2,
  1772  					ColumnOffset: 10,
  1773  				},
  1774  				End: &cpb.Point{
  1775  					ByteOffset:   33,
  1776  					LineNumber:   3,
  1777  					ColumnOffset: 5,
  1778  				},
  1779  			},
  1780  
  1781  			SnippetSpan: &cpb.Span{
  1782  				Start: &cpb.Point{
  1783  					ByteOffset: 17,
  1784  					LineNumber: 2,
  1785  				},
  1786  				End: &cpb.Point{
  1787  					ByteOffset:   27,
  1788  					LineNumber:   2,
  1789  					ColumnOffset: 10,
  1790  				},
  1791  			},
  1792  			Snippet: "here and  ",
  1793  		}}},
  1794  	}
  1795  
  1796  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  1797  		Definitions: 1,
  1798  		References:  2,
  1799  		RefEdgeToCount: map[string]int64{
  1800  			"/kythe/edge/ref": 2,
  1801  		},
  1802  	}, reply.Total); err != nil {
  1803  		t.Error(err)
  1804  	}
  1805  	wantFiltered := &xpb.CrossReferencesReply_Total{}
  1806  	if err := testutil.DeepEqual(wantFiltered, reply.Filtered); err != nil {
  1807  		t.Error(err)
  1808  	}
  1809  
  1810  	xr := reply.CrossReferences[ticket]
  1811  	if xr == nil {
  1812  		t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  1813  	}
  1814  	sort.Sort(byOffset(xr.Reference))
  1815  
  1816  	if err := testutil.DeepEqual(expected, xr); err != nil {
  1817  		t.Fatal(err)
  1818  	}
  1819  }
  1820  
  1821  type mockPatcher struct {
  1822  	files []*srvpb.FileInfo
  1823  }
  1824  
  1825  func (p *mockPatcher) Close() error { return nil }
  1826  func (p *mockPatcher) AddFile(ctx context.Context, f *srvpb.FileInfo) error {
  1827  	if f != nil {
  1828  		p.files = append(p.files, f)
  1829  	}
  1830  	return nil
  1831  }
  1832  func (p *mockPatcher) patchSpan(span *cpb.Span) {
  1833  	if span == nil {
  1834  		return
  1835  	}
  1836  	// Just move everything over by 1-ish
  1837  	span.Start.ByteOffset++
  1838  	span.Start.LineNumber++
  1839  	span.Start.ColumnOffset++
  1840  	span.End.ByteOffset++
  1841  	span.End.LineNumber++
  1842  	span.End.ColumnOffset++
  1843  }
  1844  func (p *mockPatcher) patchAnchor(a *xpb.Anchor) {
  1845  	p.patchSpan(a.Span)
  1846  	p.patchSpan(a.SnippetSpan)
  1847  }
  1848  
  1849  func (p *mockPatcher) PatchAnchors(ctx context.Context, as []*xpb.Anchor) ([]*xpb.Anchor, error) {
  1850  	for _, a := range as {
  1851  		p.patchAnchor(a)
  1852  	}
  1853  	return as, nil
  1854  }
  1855  func (p *mockPatcher) PatchRelatedAnchors(ctx context.Context, as []*xpb.CrossReferencesReply_RelatedAnchor) ([]*xpb.CrossReferencesReply_RelatedAnchor, error) {
  1856  	for _, a := range as {
  1857  		p.patchAnchor(a.Anchor)
  1858  		for _, site := range a.Site {
  1859  			p.patchAnchor(site)
  1860  		}
  1861  	}
  1862  	return as, nil
  1863  }
  1864  
  1865  func TestDecorationsPatching(t *testing.T) {
  1866  	st := tbl.Construct(t)
  1867  
  1868  	patcher := &mockPatcher{}
  1869  	st.MakePatcher = func(ctx context.Context, ws *xpb.Workspace) (MultiFilePatcher, error) {
  1870  		return patcher, nil
  1871  	}
  1872  
  1873  	reply, err := st.Decorations(ctx, &xpb.DecorationsRequest{
  1874  		Location:          &xpb.Location{Ticket: "kythe://corpus?path=file/infos"},
  1875  		References:        true,
  1876  		TargetDefinitions: true,
  1877  
  1878  		Workspace:             &xpb.Workspace{Uri: "test:"},
  1879  		PatchAgainstWorkspace: true,
  1880  	})
  1881  	testutil.Fatalf(t, "DecorationsRequest error: %v", err)
  1882  
  1883  	expected := &xpb.DecorationsReply{
  1884  		Location: &xpb.Location{Ticket: "kythe://corpus?path=file/infos"},
  1885  		Revision: "overallFileRev",
  1886  		GeneratedByFile: []*xpb.File{{
  1887  			CorpusPath: &cpb.CorpusPath{
  1888  				Corpus: "corpus",
  1889  				Path:   "some/proto.proto",
  1890  			},
  1891  			Revision: "generatedRev",
  1892  		}},
  1893  		Reference: []*xpb.DecorationsReply_Reference{{
  1894  			TargetTicket:   "kythe://corpus?path=another/file",
  1895  			Kind:           "/kythe/edge/includes/ref",
  1896  			TargetRevision: "anotherFileRev",
  1897  			Span: &cpb.Span{
  1898  				Start: &cpb.Point{
  1899  					ByteOffset:   0,
  1900  					LineNumber:   1,
  1901  					ColumnOffset: 0,
  1902  				},
  1903  				End: &cpb.Point{
  1904  					ByteOffset:   4,
  1905  					LineNumber:   1,
  1906  					ColumnOffset: 4,
  1907  				},
  1908  			},
  1909  		}, {
  1910  			TargetTicket:     "kythe://corpus?path=def/file#node",
  1911  			TargetDefinition: "kythe://corpus?path=def/file#anchor",
  1912  			Kind:             "/kythe/edge/ref",
  1913  			Span: &cpb.Span{
  1914  				Start: &cpb.Point{
  1915  					ByteOffset:   5,
  1916  					LineNumber:   1,
  1917  					ColumnOffset: 5,
  1918  				},
  1919  				End: &cpb.Point{
  1920  					ByteOffset:   9,
  1921  					LineNumber:   1,
  1922  					ColumnOffset: 9,
  1923  				},
  1924  			},
  1925  		}},
  1926  		DefinitionLocations: map[string]*xpb.Anchor{
  1927  			"kythe://corpus?path=def/file#anchor": &xpb.Anchor{
  1928  				Ticket:   "kythe://corpus?path=def/file#anchor",
  1929  				Parent:   "kythe://corpus?path=def/file",
  1930  				Revision: "defFileRev",
  1931  				Span: &cpb.Span{
  1932  					Start: &cpb.Point{ByteOffset: 1, LineNumber: 2, ColumnOffset: 1},
  1933  					End:   &cpb.Point{ByteOffset: 5, LineNumber: 2, ColumnOffset: 5},
  1934  				},
  1935  			},
  1936  		},
  1937  	}
  1938  
  1939  	if diff := compare.ProtoDiff(expected, reply); diff != "" {
  1940  		t.Fatalf("Unexpected diff (- expected; + found):\n%s", diff)
  1941  	}
  1942  }
  1943  
  1944  func TestPatchingError(t *testing.T) {
  1945  	st := tbl.Construct(t)
  1946  
  1947  	// An error when creating a patcher should not result in an overall error.
  1948  	st.MakePatcher = func(ctx context.Context, ws *xpb.Workspace) (MultiFilePatcher, error) {
  1949  		return nil, context.Canceled
  1950  	}
  1951  
  1952  	_, err := st.Decorations(ctx, &xpb.DecorationsRequest{
  1953  		Location:          &xpb.Location{Ticket: "kythe://corpus?path=file/infos"},
  1954  		References:        true,
  1955  		TargetDefinitions: true,
  1956  
  1957  		Workspace:             &xpb.Workspace{Uri: "test:"},
  1958  		PatchAgainstWorkspace: true,
  1959  	})
  1960  	testutil.Fatalf(t, "DecorationsRequest error: %v", err)
  1961  
  1962  	_, err = st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  1963  		Ticket:         []string{"kythe://someCorpus?lang=otpl#signature"},
  1964  		DefinitionKind: xpb.CrossReferencesRequest_BINDING_DEFINITIONS,
  1965  		ReferenceKind:  xpb.CrossReferencesRequest_ALL_REFERENCES,
  1966  		Snippets:       xpb.SnippetsKind_DEFAULT,
  1967  
  1968  		Workspace:             &xpb.Workspace{Uri: "test:"},
  1969  		PatchAgainstWorkspace: true,
  1970  	})
  1971  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  1972  
  1973  	_, err = st.Documentation(ctx, &xpb.DocumentationRequest{
  1974  		Ticket: []string{"kythe:#documented"},
  1975  
  1976  		IncludeChildren: true,
  1977  
  1978  		Workspace:             &xpb.Workspace{Uri: "test:"},
  1979  		PatchAgainstWorkspace: true,
  1980  	})
  1981  	testutil.Fatalf(t, "DocumentationRequest error: %v", err)
  1982  }
  1983  
  1984  func TestCrossReferencesPatching(t *testing.T) {
  1985  	ticket := "kythe://someCorpus?lang=otpl#signature"
  1986  
  1987  	st := tbl.Construct(t)
  1988  	patcher := &mockPatcher{}
  1989  	st.MakePatcher = func(ctx context.Context, ws *xpb.Workspace) (MultiFilePatcher, error) {
  1990  		return patcher, nil
  1991  	}
  1992  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  1993  		Ticket:         []string{ticket},
  1994  		DefinitionKind: xpb.CrossReferencesRequest_BINDING_DEFINITIONS,
  1995  		ReferenceKind:  xpb.CrossReferencesRequest_ALL_REFERENCES,
  1996  		Snippets:       xpb.SnippetsKind_DEFAULT,
  1997  
  1998  		Workspace:             &xpb.Workspace{Uri: "test:"},
  1999  		PatchAgainstWorkspace: true,
  2000  	})
  2001  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2002  
  2003  	expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2004  		Ticket: ticket,
  2005  
  2006  		Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  2007  			Ticket: "kythe:?path=some/utf16/file#0-4",
  2008  			Kind:   "/kythe/edge/ref",
  2009  			Parent: "kythe:?path=some/utf16/file",
  2010  
  2011  			Span: &cpb.Span{
  2012  				Start: &cpb.Point{ByteOffset: 1, LineNumber: 2, ColumnOffset: 1},
  2013  				End:   &cpb.Point{ByteOffset: 5, LineNumber: 2, ColumnOffset: 5},
  2014  			},
  2015  
  2016  			SnippetSpan: &cpb.Span{
  2017  				Start: &cpb.Point{
  2018  					ByteOffset:   1,
  2019  					LineNumber:   2,
  2020  					ColumnOffset: 1,
  2021  				},
  2022  				End: &cpb.Point{
  2023  					ByteOffset:   29,
  2024  					LineNumber:   2,
  2025  					ColumnOffset: 29,
  2026  				},
  2027  			},
  2028  			Snippet: "これはいくつかのテキストです",
  2029  		}}, {Anchor: &xpb.Anchor{
  2030  			Ticket: "kythe://c?lang=otpl?path=/a/path#51-55",
  2031  			Kind:   "/kythe/edge/ref",
  2032  			Parent: "kythe://c?path=/a/path",
  2033  
  2034  			Span: &cpb.Span{
  2035  				Start: &cpb.Point{
  2036  					ByteOffset:   52,
  2037  					LineNumber:   5,
  2038  					ColumnOffset: 16,
  2039  				},
  2040  				End: &cpb.Point{
  2041  					ByteOffset:   56,
  2042  					LineNumber:   6,
  2043  					ColumnOffset: 3,
  2044  				},
  2045  			},
  2046  
  2047  			SnippetSpan: &cpb.Span{
  2048  				Start: &cpb.Point{
  2049  					ByteOffset:   37,
  2050  					LineNumber:   5,
  2051  					ColumnOffset: 1,
  2052  				},
  2053  				End: &cpb.Point{
  2054  					ByteOffset:   53,
  2055  					LineNumber:   5,
  2056  					ColumnOffset: 17,
  2057  				},
  2058  			},
  2059  			Snippet: "some random text",
  2060  		}}},
  2061  
  2062  		Definition: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  2063  			Ticket:      "kythe://c?lang=otpl?path=/a/path#27-33",
  2064  			Kind:        "/kythe/edge/defines/binding",
  2065  			Parent:      "kythe://c?path=/a/path",
  2066  			BuildConfig: "testConfig",
  2067  
  2068  			Span: &cpb.Span{
  2069  				Start: &cpb.Point{
  2070  					ByteOffset:   28,
  2071  					LineNumber:   3,
  2072  					ColumnOffset: 11,
  2073  				},
  2074  				End: &cpb.Point{
  2075  					ByteOffset:   34,
  2076  					LineNumber:   4,
  2077  					ColumnOffset: 6,
  2078  				},
  2079  			},
  2080  
  2081  			SnippetSpan: &cpb.Span{
  2082  				Start: &cpb.Point{
  2083  					ByteOffset:   18,
  2084  					LineNumber:   3,
  2085  					ColumnOffset: 1,
  2086  				},
  2087  				End: &cpb.Point{
  2088  					ByteOffset:   28,
  2089  					LineNumber:   3,
  2090  					ColumnOffset: 11,
  2091  				},
  2092  			},
  2093  			Snippet: "here and  ",
  2094  		}}},
  2095  	}
  2096  	var expectedInfos []*srvpb.FileInfo
  2097  
  2098  	xr := reply.CrossReferences[ticket]
  2099  	if xr == nil {
  2100  		t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2101  	}
  2102  	sort.Sort(byOffset(xr.Reference))
  2103  
  2104  	if err := testutil.DeepEqual(expected, xr); err != nil {
  2105  		t.Fatal(err)
  2106  	}
  2107  	if err := testutil.DeepEqual(expectedInfos, patcher.files); err != nil {
  2108  		t.Fatal(err)
  2109  	}
  2110  }
  2111  
  2112  func TestCrossReferencesFiltering(t *testing.T) {
  2113  	ticket := "kythe://someCorpus?lang=otpl#signature"
  2114  
  2115  	st := tbl.Construct(t)
  2116  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2117  		Ticket:         []string{ticket},
  2118  		DefinitionKind: xpb.CrossReferencesRequest_BINDING_DEFINITIONS,
  2119  		ReferenceKind:  xpb.CrossReferencesRequest_ALL_REFERENCES,
  2120  		Snippets:       xpb.SnippetsKind_DEFAULT,
  2121  
  2122  		CorpusPathFilters: mustParseFilters(`
  2123  filter: {
  2124    type: INCLUDE_ONLY
  2125  	corpus: "^c$"
  2126  }
  2127  		`),
  2128  	})
  2129  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2130  
  2131  	expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2132  		Ticket: ticket,
  2133  
  2134  		Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  2135  			Ticket: "kythe://c?lang=otpl?path=/a/path#51-55",
  2136  			Kind:   "/kythe/edge/ref",
  2137  			Parent: "kythe://c?path=/a/path",
  2138  
  2139  			Span: &cpb.Span{
  2140  				Start: &cpb.Point{
  2141  					ByteOffset:   51,
  2142  					LineNumber:   4,
  2143  					ColumnOffset: 15,
  2144  				},
  2145  				End: &cpb.Point{
  2146  					ByteOffset:   55,
  2147  					LineNumber:   5,
  2148  					ColumnOffset: 2,
  2149  				},
  2150  			},
  2151  
  2152  			SnippetSpan: &cpb.Span{
  2153  				Start: &cpb.Point{
  2154  					ByteOffset: 36,
  2155  					LineNumber: 4,
  2156  				},
  2157  				End: &cpb.Point{
  2158  					ByteOffset:   52,
  2159  					LineNumber:   4,
  2160  					ColumnOffset: 16,
  2161  				},
  2162  			},
  2163  			Snippet: "some random text",
  2164  		}}},
  2165  
  2166  		Definition: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  2167  			Ticket:      "kythe://c?lang=otpl?path=/a/path#27-33",
  2168  			Kind:        "/kythe/edge/defines/binding",
  2169  			Parent:      "kythe://c?path=/a/path",
  2170  			BuildConfig: "testConfig",
  2171  
  2172  			Span: &cpb.Span{
  2173  				Start: &cpb.Point{
  2174  					ByteOffset:   27,
  2175  					LineNumber:   2,
  2176  					ColumnOffset: 10,
  2177  				},
  2178  				End: &cpb.Point{
  2179  					ByteOffset:   33,
  2180  					LineNumber:   3,
  2181  					ColumnOffset: 5,
  2182  				},
  2183  			},
  2184  
  2185  			SnippetSpan: &cpb.Span{
  2186  				Start: &cpb.Point{
  2187  					ByteOffset: 17,
  2188  					LineNumber: 2,
  2189  				},
  2190  				End: &cpb.Point{
  2191  					ByteOffset:   27,
  2192  					LineNumber:   2,
  2193  					ColumnOffset: 10,
  2194  				},
  2195  			},
  2196  			Snippet: "here and  ",
  2197  		}}},
  2198  	}
  2199  
  2200  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2201  		Definitions: 1,
  2202  		References:  1,
  2203  		RefEdgeToCount: map[string]int64{
  2204  			"/kythe/edge/ref": 1,
  2205  		},
  2206  	}, reply.Total); err != nil {
  2207  		t.Error(err)
  2208  	}
  2209  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2210  		References: 1,
  2211  		RefEdgeToCount: map[string]int64{
  2212  			"/kythe/edge/ref": 1,
  2213  		},
  2214  	}, reply.Filtered); err != nil {
  2215  		t.Error(err)
  2216  	}
  2217  
  2218  	xr := reply.CrossReferences[ticket]
  2219  	if xr == nil {
  2220  		t.Fatalf("Missing expected CrossReferences; found: %s", reply)
  2221  	}
  2222  	sort.Sort(byOffset(xr.Reference))
  2223  
  2224  	if diff := compare.ProtoDiff(expected, xr); diff != "" {
  2225  		t.Fatalf("(-expected; +found):\n%s", diff)
  2226  	}
  2227  }
  2228  
  2229  func TestCrossReferences_BuildConfigRefs(t *testing.T) {
  2230  	ticket := "kythe://someCorpus?lang=otpl#signature"
  2231  
  2232  	st := tbl.Construct(t)
  2233  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2234  		Ticket:         []string{ticket},
  2235  		DefinitionKind: xpb.CrossReferencesRequest_ALL_DEFINITIONS,
  2236  		ReferenceKind:  xpb.CrossReferencesRequest_ALL_REFERENCES,
  2237  		Snippets:       xpb.SnippetsKind_DEFAULT,
  2238  		BuildConfig:    []string{"testConfig"},
  2239  	})
  2240  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2241  
  2242  	expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2243  		Ticket: ticket,
  2244  
  2245  		Definition: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  2246  			Ticket:      "kythe://c?lang=otpl?path=/a/path#27-33",
  2247  			Kind:        "/kythe/edge/defines/binding",
  2248  			Parent:      "kythe://c?path=/a/path",
  2249  			BuildConfig: "testConfig",
  2250  
  2251  			Span: &cpb.Span{
  2252  				Start: &cpb.Point{
  2253  					ByteOffset:   27,
  2254  					LineNumber:   2,
  2255  					ColumnOffset: 10,
  2256  				},
  2257  				End: &cpb.Point{
  2258  					ByteOffset:   33,
  2259  					LineNumber:   3,
  2260  					ColumnOffset: 5,
  2261  				},
  2262  			},
  2263  
  2264  			SnippetSpan: &cpb.Span{
  2265  				Start: &cpb.Point{
  2266  					ByteOffset: 17,
  2267  					LineNumber: 2,
  2268  				},
  2269  				End: &cpb.Point{
  2270  					ByteOffset:   27,
  2271  					LineNumber:   2,
  2272  					ColumnOffset: 10,
  2273  				},
  2274  			},
  2275  			Snippet: "here and  ",
  2276  		}}},
  2277  	}
  2278  
  2279  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2280  		Definitions: 1,
  2281  	}, reply.Total); err != nil {
  2282  		t.Error(err)
  2283  	}
  2284  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{}, reply.Filtered); err != nil {
  2285  		t.Error(err)
  2286  	}
  2287  
  2288  	xr := reply.CrossReferences[ticket]
  2289  	if xr == nil {
  2290  		t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2291  	}
  2292  	sort.Sort(byOffset(xr.Reference))
  2293  
  2294  	if err := testutil.DeepEqual(expected, xr); err != nil {
  2295  		t.Fatal(err)
  2296  	}
  2297  }
  2298  
  2299  func TestCrossReferencesRelatedNodes(t *testing.T) {
  2300  	ticket := "kythe://someCorpus?lang=otpl#withRelated"
  2301  
  2302  	st := tbl.Construct(t)
  2303  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2304  		Ticket: []string{ticket},
  2305  		Filter: []string{"**"},
  2306  	})
  2307  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2308  
  2309  	expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2310  		Ticket: ticket,
  2311  		MarkedSource: &cpb.MarkedSource{
  2312  			Kind:    cpb.MarkedSource_IDENTIFIER,
  2313  			PreText: "id",
  2314  		},
  2315  
  2316  		RelatedNode: []*xpb.CrossReferencesReply_RelatedNode{{
  2317  			Ticket:       "kythe:#someRelatedNode",
  2318  			RelationKind: "/kythe/edge/extends",
  2319  		}, {
  2320  			Ticket:       "kythe:#someParameter0",
  2321  			RelationKind: "/kythe/edge/param",
  2322  			Ordinal:      0,
  2323  		}, {
  2324  			Ticket:       "kythe:#someParameter1",
  2325  			RelationKind: "/kythe/edge/param",
  2326  			Ordinal:      1,
  2327  		}},
  2328  	}
  2329  	expectedNodes := nodeInfos(getNodes(
  2330  		ticket,
  2331  		"kythe:#someRelatedNode",
  2332  		"kythe:#someParameter0",
  2333  		"kythe:#someParameter1"))
  2334  
  2335  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2336  		RelatedNodesByRelation: map[string]int64{
  2337  			"/kythe/edge/extends": 1,
  2338  			"/kythe/edge/param":   2,
  2339  		},
  2340  	}, reply.Total); err != nil {
  2341  		t.Error(err)
  2342  	}
  2343  
  2344  	xr := reply.CrossReferences[ticket]
  2345  	if xr == nil {
  2346  		t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2347  	} else if err := testutil.DeepEqual(expected, xr); err != nil {
  2348  		t.Fatal(err)
  2349  	} else if err := testutil.DeepEqual(expectedNodes, reply.Nodes); err != nil {
  2350  		t.Fatal(err)
  2351  	}
  2352  }
  2353  
  2354  func TestCrossReferencesMarkedSource(t *testing.T) {
  2355  	const ticket = "kythe://someCorpus?lang=otpl#withRelated"
  2356  
  2357  	st := tbl.Construct(t)
  2358  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2359  		Ticket: []string{ticket},
  2360  		Filter: []string{"**"},
  2361  	})
  2362  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2363  
  2364  	expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2365  		Ticket: ticket,
  2366  		MarkedSource: &cpb.MarkedSource{
  2367  			Kind:    cpb.MarkedSource_IDENTIFIER,
  2368  			PreText: "id",
  2369  		},
  2370  
  2371  		RelatedNode: []*xpb.CrossReferencesReply_RelatedNode{{
  2372  			Ticket:       "kythe:#someRelatedNode",
  2373  			RelationKind: "/kythe/edge/extends",
  2374  		}, {
  2375  			Ticket:       "kythe:#someParameter0",
  2376  			RelationKind: "/kythe/edge/param",
  2377  			Ordinal:      0,
  2378  		}, {
  2379  			Ticket:       "kythe:#someParameter1",
  2380  			RelationKind: "/kythe/edge/param",
  2381  			Ordinal:      1,
  2382  		}},
  2383  	}
  2384  
  2385  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2386  		RelatedNodesByRelation: map[string]int64{
  2387  			"/kythe/edge/extends": 1,
  2388  			"/kythe/edge/param":   2,
  2389  		},
  2390  	}, reply.Total); err != nil {
  2391  		t.Error(err)
  2392  	}
  2393  
  2394  	xr := reply.CrossReferences[ticket]
  2395  	if xr == nil {
  2396  		t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2397  	} else if err := testutil.DeepEqual(expected, xr); err != nil {
  2398  		t.Fatal(err)
  2399  	}
  2400  }
  2401  
  2402  func TestCrossReferencesMerge(t *testing.T) {
  2403  	ticket := "kythe://someCorpus?lang=otpl#withMerge"
  2404  
  2405  	st := tbl.Construct(t)
  2406  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2407  		Ticket:     []string{ticket},
  2408  		CallerKind: xpb.CrossReferencesRequest_DIRECT_CALLERS,
  2409  		Filter:     []string{"**"},
  2410  	})
  2411  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2412  
  2413  	expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2414  		Ticket: ticket,
  2415  		MarkedSource: &cpb.MarkedSource{
  2416  			Kind:    cpb.MarkedSource_IDENTIFIER,
  2417  			PreText: "id",
  2418  		},
  2419  
  2420  		Caller: []*xpb.CrossReferencesReply_RelatedAnchor{{
  2421  			Anchor: &xpb.Anchor{
  2422  				Ticket: "kythe:?path=someFile#someCallerAnchor",
  2423  				Parent: "kythe:?path=someFile",
  2424  				Span:   arbitrarySpan,
  2425  			},
  2426  			Ticket: "kythe:#someCaller",
  2427  			MarkedSource: &cpb.MarkedSource{
  2428  				Kind:    cpb.MarkedSource_IDENTIFIER,
  2429  				PreText: "id",
  2430  			},
  2431  			Site: []*xpb.Anchor{{
  2432  				Ticket: "kythe:?path=someFile#someCallsiteAnchor",
  2433  				Parent: "kythe:?path=someFile",
  2434  			}},
  2435  		}},
  2436  		RelatedNode: []*xpb.CrossReferencesReply_RelatedNode{{
  2437  			Ticket:       "kythe:#someRelatedNode",
  2438  			RelationKind: "/kythe/edge/extends",
  2439  		}, {
  2440  			Ticket:       "kythe:#someParameter0",
  2441  			RelationKind: "/kythe/edge/param",
  2442  			Ordinal:      0,
  2443  		}, {
  2444  			Ticket:       "kythe:#someParameter1",
  2445  			RelationKind: "/kythe/edge/param",
  2446  			Ordinal:      1,
  2447  		}},
  2448  	}
  2449  
  2450  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2451  		Callers: 1,
  2452  		RelatedNodesByRelation: map[string]int64{
  2453  			"/kythe/edge/extends": 1,
  2454  			"/kythe/edge/param":   2,
  2455  		},
  2456  	}, reply.Total); err != nil {
  2457  		t.Error(err)
  2458  	}
  2459  
  2460  	xr := reply.CrossReferences[ticket]
  2461  	if xr == nil {
  2462  		t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2463  	} else if err := testutil.DeepEqual(expected, xr); err != nil {
  2464  		t.Fatal(err)
  2465  	}
  2466  }
  2467  
  2468  func TestCrossReferencesIndirection(t *testing.T) {
  2469  	ticket := "kythe:#aliasNode"
  2470  	st := tbl.Construct(t)
  2471  
  2472  	t.Run("none", func(t *testing.T) {
  2473  		experimentalCrossReferenceIndirectionKinds = nil
  2474  
  2475  		reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2476  			Ticket:        []string{ticket},
  2477  			ReferenceKind: xpb.CrossReferencesRequest_ALL_REFERENCES,
  2478  		})
  2479  		testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2480  
  2481  		expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2482  			Ticket: ticket,
  2483  
  2484  			Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  2485  				Ticket: "kythe:?path=somewhere#0-9",
  2486  				Kind:   "/kythe/edge/ref",
  2487  				Parent: "kythe:?path=somewhere",
  2488  
  2489  				Span: &cpb.Span{
  2490  					Start: &cpb.Point{LineNumber: 1},
  2491  					End:   &cpb.Point{ByteOffset: 9, LineNumber: 1, ColumnOffset: 9},
  2492  				},
  2493  			}}},
  2494  		}
  2495  
  2496  		if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2497  			References: 1,
  2498  			RefEdgeToCount: map[string]int64{
  2499  				"/kythe/edge/ref": 1,
  2500  			},
  2501  		}, reply.Total); err != nil {
  2502  			t.Error(err)
  2503  		}
  2504  
  2505  		xr := reply.CrossReferences[ticket]
  2506  		if xr == nil {
  2507  			t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2508  		} else if err := testutil.DeepEqual(expected, xr); err != nil {
  2509  			t.Fatal(err)
  2510  		}
  2511  	})
  2512  
  2513  	t.Run("talias", func(t *testing.T) {
  2514  		// Enable indirection for talias nodes.
  2515  		experimentalCrossReferenceIndirectionKinds = nil
  2516  		experimentalCrossReferenceIndirectionKinds.Set("talias=%/kythe/edge/aliases")
  2517  
  2518  		reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2519  			Ticket:        []string{ticket},
  2520  			ReferenceKind: xpb.CrossReferencesRequest_ALL_REFERENCES,
  2521  		})
  2522  		testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2523  
  2524  		expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2525  			Ticket: ticket,
  2526  
  2527  			Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  2528  				Ticket: "kythe:?path=somewhere#0-9",
  2529  				Kind:   "/kythe/edge/ref",
  2530  				Parent: "kythe:?path=somewhere",
  2531  
  2532  				Span: &cpb.Span{
  2533  					Start: &cpb.Point{LineNumber: 1},
  2534  					End:   &cpb.Point{ByteOffset: 9, LineNumber: 1, ColumnOffset: 9},
  2535  				},
  2536  			}}, {Anchor: &xpb.Anchor{
  2537  				Ticket: "kythe:?path=some/utf16/file#0-4",
  2538  				Kind:   "/kythe/edge/ref",
  2539  				Parent: "kythe:?path=some/utf16/file",
  2540  
  2541  				Span: &cpb.Span{
  2542  					Start: &cpb.Point{LineNumber: 1},
  2543  					End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
  2544  				},
  2545  			}}, {Anchor: &xpb.Anchor{
  2546  				Ticket: "kythe://c?lang=otpl?path=/a/path#51-55",
  2547  				Kind:   "/kythe/edge/ref",
  2548  				Parent: "kythe://c?path=/a/path",
  2549  
  2550  				Span: &cpb.Span{
  2551  					Start: &cpb.Point{
  2552  						ByteOffset:   51,
  2553  						LineNumber:   4,
  2554  						ColumnOffset: 15,
  2555  					},
  2556  					End: &cpb.Point{
  2557  						ByteOffset:   55,
  2558  						LineNumber:   5,
  2559  						ColumnOffset: 2,
  2560  					},
  2561  				},
  2562  			}}},
  2563  		}
  2564  
  2565  		if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2566  			References: 3,
  2567  			RefEdgeToCount: map[string]int64{
  2568  				"/kythe/edge/ref": 3,
  2569  			},
  2570  		}, reply.Total); err != nil {
  2571  			t.Error(err)
  2572  		}
  2573  
  2574  		xr := reply.CrossReferences[ticket]
  2575  		if xr == nil {
  2576  			t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2577  		}
  2578  
  2579  		sort.Sort(byOffset(xr.Reference))
  2580  		if err := testutil.DeepEqual(expected, xr); err != nil {
  2581  			t.Fatal(err)
  2582  		}
  2583  	})
  2584  
  2585  	t.Run("wildcard", func(t *testing.T) {
  2586  		// Enable indirection for any nodes with a reverse aliases edge.
  2587  		experimentalCrossReferenceIndirectionKinds = nil
  2588  		experimentalCrossReferenceIndirectionKinds.Set("*=%/kythe/edge/aliases")
  2589  
  2590  		reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2591  			Ticket:        []string{ticket},
  2592  			ReferenceKind: xpb.CrossReferencesRequest_ALL_REFERENCES,
  2593  		})
  2594  		testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2595  
  2596  		expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2597  			Ticket: ticket,
  2598  
  2599  			Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  2600  				Ticket: "kythe:?path=somewhere#0-9",
  2601  				Kind:   "/kythe/edge/ref",
  2602  				Parent: "kythe:?path=somewhere",
  2603  
  2604  				Span: &cpb.Span{
  2605  					Start: &cpb.Point{LineNumber: 1},
  2606  					End:   &cpb.Point{ByteOffset: 9, LineNumber: 1, ColumnOffset: 9},
  2607  				},
  2608  			}}, {Anchor: &xpb.Anchor{
  2609  				Ticket: "kythe:?path=some/utf16/file#0-4",
  2610  				Kind:   "/kythe/edge/ref",
  2611  				Parent: "kythe:?path=some/utf16/file",
  2612  
  2613  				Span: &cpb.Span{
  2614  					Start: &cpb.Point{LineNumber: 1},
  2615  					End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
  2616  				},
  2617  			}}, {Anchor: &xpb.Anchor{
  2618  				Ticket: "kythe://c?lang=otpl?path=/a/path#51-55",
  2619  				Kind:   "/kythe/edge/ref",
  2620  				Parent: "kythe://c?path=/a/path",
  2621  
  2622  				Span: &cpb.Span{
  2623  					Start: &cpb.Point{
  2624  						ByteOffset:   51,
  2625  						LineNumber:   4,
  2626  						ColumnOffset: 15,
  2627  					},
  2628  					End: &cpb.Point{
  2629  						ByteOffset:   55,
  2630  						LineNumber:   5,
  2631  						ColumnOffset: 2,
  2632  					},
  2633  				},
  2634  			}}},
  2635  		}
  2636  
  2637  		if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2638  			References: 3,
  2639  			RefEdgeToCount: map[string]int64{
  2640  				"/kythe/edge/ref": 3,
  2641  			},
  2642  		}, reply.Total); err != nil {
  2643  			t.Error(err)
  2644  		}
  2645  
  2646  		xr := reply.CrossReferences[ticket]
  2647  		if xr == nil {
  2648  			t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2649  		}
  2650  
  2651  		sort.Sort(byOffset(xr.Reference))
  2652  		if err := testutil.DeepEqual(expected, xr); err != nil {
  2653  			t.Fatal(err)
  2654  		}
  2655  	})
  2656  
  2657  	t.Run("single_indirect", func(t *testing.T) {
  2658  		// Enable single indirection for talias nodes.
  2659  		experimentalCrossReferenceIndirectionKinds = nil
  2660  		experimentalCrossReferenceIndirectionKinds.Set("talias=/kythe/edge/indirect")
  2661  
  2662  		reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2663  			Ticket:        []string{ticket},
  2664  			ReferenceKind: xpb.CrossReferencesRequest_ALL_REFERENCES,
  2665  		})
  2666  		testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2667  
  2668  		expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2669  			Ticket: ticket,
  2670  
  2671  			Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  2672  				Ticket: "kythe:?path=somewhere#0-9",
  2673  				Kind:   "/kythe/edge/ref",
  2674  				Parent: "kythe:?path=somewhere",
  2675  
  2676  				Span: &cpb.Span{
  2677  					Start: &cpb.Point{LineNumber: 1},
  2678  					End:   &cpb.Point{ByteOffset: 9, LineNumber: 1, ColumnOffset: 9},
  2679  				},
  2680  			}}, {Anchor: &xpb.Anchor{
  2681  				Ticket: "kythe:?path=somewhereElse#0-9",
  2682  				Kind:   "/kythe/edge/ref",
  2683  				Parent: "kythe:?path=somewhereElse",
  2684  
  2685  				Span: &cpb.Span{
  2686  					Start: &cpb.Point{LineNumber: 1},
  2687  					End:   &cpb.Point{ByteOffset: 9, LineNumber: 1, ColumnOffset: 9},
  2688  				},
  2689  			}}},
  2690  		}
  2691  
  2692  		if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2693  			References: 2,
  2694  			RefEdgeToCount: map[string]int64{
  2695  				"/kythe/edge/ref": 2,
  2696  			},
  2697  		}, reply.Total); err != nil {
  2698  			t.Error(err)
  2699  		}
  2700  
  2701  		xr := reply.CrossReferences[ticket]
  2702  		if xr == nil {
  2703  			t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2704  		}
  2705  
  2706  		sort.Sort(byOffset(xr.Reference))
  2707  		if err := testutil.DeepEqual(expected, xr); err != nil {
  2708  			t.Fatal(err)
  2709  		}
  2710  	})
  2711  
  2712  	t.Run("double_indirect", func(t *testing.T) {
  2713  		// Enable double indirection for talias nodes.
  2714  		experimentalCrossReferenceIndirectionKinds = nil
  2715  		experimentalCrossReferenceIndirectionKinds.Set("talias=/kythe/edge/indirect,indirect=/kythe/edge/indirect")
  2716  
  2717  		reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2718  			Ticket:        []string{ticket},
  2719  			ReferenceKind: xpb.CrossReferencesRequest_ALL_REFERENCES,
  2720  		})
  2721  		testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2722  
  2723  		expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2724  			Ticket: ticket,
  2725  
  2726  			Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{Anchor: &xpb.Anchor{
  2727  				Ticket: "kythe:?path=somewhere#0-9",
  2728  				Kind:   "/kythe/edge/ref",
  2729  				Parent: "kythe:?path=somewhere",
  2730  
  2731  				Span: &cpb.Span{
  2732  					Start: &cpb.Point{LineNumber: 1},
  2733  					End:   &cpb.Point{ByteOffset: 9, LineNumber: 1, ColumnOffset: 9},
  2734  				},
  2735  			}}, {Anchor: &xpb.Anchor{
  2736  				Ticket: "kythe:?path=somewhereElse#0-9",
  2737  				Kind:   "/kythe/edge/ref",
  2738  				Parent: "kythe:?path=somewhereElse",
  2739  
  2740  				Span: &cpb.Span{
  2741  					Start: &cpb.Point{LineNumber: 1},
  2742  					End:   &cpb.Point{ByteOffset: 9, LineNumber: 1, ColumnOffset: 9},
  2743  				},
  2744  			}}, {Anchor: &xpb.Anchor{
  2745  				Ticket: "kythe:?path=some/utf16/file#0-4",
  2746  				Kind:   "/kythe/edge/ref",
  2747  				Parent: "kythe:?path=some/utf16/file",
  2748  
  2749  				Span: &cpb.Span{
  2750  					Start: &cpb.Point{LineNumber: 1},
  2751  					End:   &cpb.Point{ByteOffset: 4, LineNumber: 1, ColumnOffset: 4},
  2752  				},
  2753  			}}, {Anchor: &xpb.Anchor{
  2754  				Ticket: "kythe://c?lang=otpl?path=/a/path#51-55",
  2755  				Kind:   "/kythe/edge/ref",
  2756  				Parent: "kythe://c?path=/a/path",
  2757  
  2758  				Span: &cpb.Span{
  2759  					Start: &cpb.Point{
  2760  						ByteOffset:   51,
  2761  						LineNumber:   4,
  2762  						ColumnOffset: 15,
  2763  					},
  2764  					End: &cpb.Point{
  2765  						ByteOffset:   55,
  2766  						LineNumber:   5,
  2767  						ColumnOffset: 2,
  2768  					},
  2769  				},
  2770  			}}},
  2771  		}
  2772  
  2773  		if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2774  			References: 4,
  2775  			RefEdgeToCount: map[string]int64{
  2776  				"/kythe/edge/ref": 4,
  2777  			},
  2778  		}, reply.Total); err != nil {
  2779  			t.Error(err)
  2780  		}
  2781  
  2782  		xr := reply.CrossReferences[ticket]
  2783  		if xr == nil {
  2784  			t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2785  		}
  2786  
  2787  		sort.Sort(byOffset(xr.Reference))
  2788  		if err := testutil.DeepEqual(expected, xr); err != nil {
  2789  			t.Fatal(err)
  2790  		}
  2791  	})
  2792  }
  2793  
  2794  func TestCrossReferencesDirectCallers(t *testing.T) {
  2795  	ticket := "kythe://someCorpus?lang=otpl#withCallers"
  2796  
  2797  	st := tbl.Construct(t)
  2798  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2799  		Ticket:     []string{ticket},
  2800  		CallerKind: xpb.CrossReferencesRequest_DIRECT_CALLERS,
  2801  	})
  2802  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2803  
  2804  	expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2805  		Ticket: ticket,
  2806  
  2807  		Caller: []*xpb.CrossReferencesReply_RelatedAnchor{{
  2808  			Anchor: &xpb.Anchor{
  2809  				Ticket: "kythe:?path=someFile#someCallerAnchor",
  2810  				Parent: "kythe:?path=someFile",
  2811  				Span:   arbitrarySpan,
  2812  			},
  2813  			Ticket: "kythe:#someCaller",
  2814  			MarkedSource: &cpb.MarkedSource{
  2815  				Kind:    cpb.MarkedSource_IDENTIFIER,
  2816  				PreText: "id",
  2817  			},
  2818  			Site: []*xpb.Anchor{{
  2819  				Ticket: "kythe:?path=someFile#someCallsiteAnchor",
  2820  				Parent: "kythe:?path=someFile",
  2821  			}},
  2822  		}},
  2823  	}
  2824  
  2825  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2826  		Callers: 1,
  2827  	}, reply.Total); err != nil {
  2828  		t.Error(err)
  2829  	}
  2830  
  2831  	xr := reply.CrossReferences[ticket]
  2832  	if xr == nil {
  2833  		t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2834  	} else if err := testutil.DeepEqual(expected, xr); err != nil {
  2835  		t.Fatal(err)
  2836  	}
  2837  }
  2838  
  2839  func TestCrossReferencesOverrideCallers(t *testing.T) {
  2840  	ticket := "kythe://someCorpus?lang=otpl#withCallers"
  2841  
  2842  	st := tbl.Construct(t)
  2843  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2844  		Ticket:     []string{ticket},
  2845  		CallerKind: xpb.CrossReferencesRequest_OVERRIDE_CALLERS,
  2846  	})
  2847  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2848  
  2849  	expected := &xpb.CrossReferencesReply_CrossReferenceSet{
  2850  		Ticket: ticket,
  2851  
  2852  		Caller: []*xpb.CrossReferencesReply_RelatedAnchor{{
  2853  			Anchor: &xpb.Anchor{
  2854  				Ticket: "kythe:?path=someFile#someCallerAnchor",
  2855  				Parent: "kythe:?path=someFile",
  2856  				Span:   arbitrarySpan,
  2857  			},
  2858  			Ticket: "kythe:#someCaller",
  2859  			MarkedSource: &cpb.MarkedSource{
  2860  				Kind:    cpb.MarkedSource_IDENTIFIER,
  2861  				PreText: "id",
  2862  			},
  2863  			Site: []*xpb.Anchor{{
  2864  				Ticket: "kythe:?path=someFile#someCallsiteAnchor",
  2865  				Parent: "kythe:?path=someFile",
  2866  			}},
  2867  		}, {
  2868  			Speculative: true,
  2869  			Anchor: &xpb.Anchor{
  2870  				Ticket: "kythe:?path=someFile#someOverrideCallerAnchor1",
  2871  				Parent: "kythe:?path=someFile",
  2872  				Span:   arbitrarySpan,
  2873  			},
  2874  			Site: []*xpb.Anchor{{
  2875  				Ticket: "kythe:?path=someFile#someCallsiteAnchor",
  2876  				Parent: "kythe:?path=someFile",
  2877  				Span:   arbitrarySpan,
  2878  			}},
  2879  		}, {
  2880  			Speculative: true,
  2881  			Anchor: &xpb.Anchor{
  2882  				Ticket: "kythe:?path=someFile#someOverrideCallerAnchor2",
  2883  				Parent: "kythe:?path=someFile",
  2884  				Span:   arbitrarySpan,
  2885  			},
  2886  			Site: []*xpb.Anchor{{
  2887  				Ticket: "kythe:?path=someFile#someCallsiteAnchor",
  2888  				Parent: "kythe:?path=someFile",
  2889  			}},
  2890  		}},
  2891  	}
  2892  
  2893  	if err := testutil.DeepEqual(&xpb.CrossReferencesReply_Total{
  2894  		Callers: 3,
  2895  	}, reply.Total); err != nil {
  2896  		t.Error(err)
  2897  	}
  2898  
  2899  	xr := reply.CrossReferences[ticket]
  2900  	if xr == nil {
  2901  		t.Fatalf("Missing expected CrossReferences; found: %#v", reply)
  2902  	} else if err := testutil.DeepEqual(expected, xr); err != nil {
  2903  		t.Fatal(err)
  2904  	}
  2905  }
  2906  
  2907  func TestCrossReferencesRevisions(t *testing.T) {
  2908  	ticket := "kythe://someCorpus?lang=otpl#withInfos"
  2909  
  2910  	st := tbl.Construct(t)
  2911  	reply, err := st.CrossReferences(ctx, &xpb.CrossReferencesRequest{
  2912  		Ticket:         []string{ticket},
  2913  		DefinitionKind: xpb.CrossReferencesRequest_ALL_DEFINITIONS,
  2914  		ReferenceKind:  xpb.CrossReferencesRequest_ALL_REFERENCES,
  2915  		Snippets:       xpb.SnippetsKind_NONE,
  2916  	})
  2917  	testutil.Fatalf(t, "CrossReferencesRequest error: %v", err)
  2918  
  2919  	expected := &xpb.CrossReferencesReply{
  2920  		Total: &xpb.CrossReferencesReply_Total{
  2921  			References: 1,
  2922  			RefEdgeToCount: map[string]int64{
  2923  				"/kythe/edge/ref": 1,
  2924  			},
  2925  		},
  2926  		Filtered: &xpb.CrossReferencesReply_Total{},
  2927  		CrossReferences: map[string]*xpb.CrossReferencesReply_CrossReferenceSet{
  2928  			ticket: &xpb.CrossReferencesReply_CrossReferenceSet{
  2929  				Ticket: ticket,
  2930  
  2931  				Reference: []*xpb.CrossReferencesReply_RelatedAnchor{{
  2932  					Anchor: &xpb.Anchor{
  2933  						Ticket:   "kythe://corpus?lang=otpl?path=some/file#27-33",
  2934  						Kind:     "/kythe/edge/ref",
  2935  						Parent:   "kythe://corpus?path=some/file",
  2936  						Revision: "someFileRev", // ⟵ this is expected now
  2937  
  2938  						Span: &cpb.Span{
  2939  							Start: &cpb.Point{
  2940  								ByteOffset:   27,
  2941  								LineNumber:   2,
  2942  								ColumnOffset: 10,
  2943  							},
  2944  							End: &cpb.Point{
  2945  								ByteOffset:   33,
  2946  								LineNumber:   3,
  2947  								ColumnOffset: 5,
  2948  							},
  2949  						},
  2950  					},
  2951  				}},
  2952  			},
  2953  		},
  2954  	}
  2955  
  2956  	if diff := compare.ProtoDiff(expected, reply); diff != "" {
  2957  		t.Fatalf("(-expected; +found):\n%s", diff)
  2958  	}
  2959  }
  2960  
  2961  func nodeInfos(nss ...[]*srvpb.Node) map[string]*cpb.NodeInfo {
  2962  	m := make(map[string]*cpb.NodeInfo)
  2963  	for _, ns := range nss {
  2964  		for _, n := range ns {
  2965  			if ni := nodeInfo(n); ni != nil {
  2966  				m[n.Ticket] = ni
  2967  			}
  2968  		}
  2969  	}
  2970  	return m
  2971  }
  2972  
  2973  func TestDocumentationEmpty(t *testing.T) {
  2974  	st := tbl.Construct(t)
  2975  	reply, err := st.Documentation(ctx, &xpb.DocumentationRequest{
  2976  		Ticket: []string{"kythe:#undocumented"},
  2977  	})
  2978  
  2979  	expected := &xpb.DocumentationReply{}
  2980  
  2981  	if reply == nil || err != nil {
  2982  		t.Fatalf("Documentation call failed: (reply: %v; error: %v)", reply, err)
  2983  	} else if err := testutil.DeepEqual(expected, reply); err != nil {
  2984  		t.Fatal(err)
  2985  	}
  2986  }
  2987  
  2988  func TestDocumentation(t *testing.T) {
  2989  	st := tbl.Construct(t)
  2990  	reply, err := st.Documentation(ctx, &xpb.DocumentationRequest{
  2991  		Ticket: []string{"kythe:#documented"},
  2992  	})
  2993  
  2994  	expected := &xpb.DocumentationReply{
  2995  		Document: []*xpb.DocumentationReply_Document{{
  2996  			Ticket: "kythe:#documented",
  2997  			Text: &xpb.Printable{
  2998  				RawText: "some documentation text",
  2999  			},
  3000  			MarkedSource: &cpb.MarkedSource{
  3001  				Kind:    cpb.MarkedSource_IDENTIFIER,
  3002  				PreText: "DocumentBuilderFactory",
  3003  			},
  3004  		}},
  3005  		Nodes: nodeInfos(getNodes("kythe:#documented")),
  3006  		DefinitionLocations: map[string]*xpb.Anchor{
  3007  			"kythe:?path=def/location#defDoc": &xpb.Anchor{
  3008  				Ticket: "kythe:?path=def/location#defDoc",
  3009  				Parent: "kythe:?path=def/location",
  3010  				Span: &cpb.Span{
  3011  					Start: &cpb.Point{
  3012  						ByteOffset:   1,
  3013  						LineNumber:   1,
  3014  						ColumnOffset: 1,
  3015  					},
  3016  					End: &cpb.Point{
  3017  						ByteOffset:   4,
  3018  						LineNumber:   1,
  3019  						ColumnOffset: 4,
  3020  					},
  3021  				},
  3022  			},
  3023  		},
  3024  	}
  3025  
  3026  	if reply == nil || err != nil {
  3027  		t.Fatalf("Documentation call failed: (reply: %v; error: %v)", reply, err)
  3028  	} else if diff := compare.ProtoDiff(expected, reply); diff != "" {
  3029  		t.Fatalf("(-expected; +found):\n%s", diff)
  3030  	}
  3031  }
  3032  
  3033  func TestDocumentationChildren(t *testing.T) {
  3034  	st := tbl.Construct(t)
  3035  	reply, err := st.Documentation(ctx, &xpb.DocumentationRequest{
  3036  		Ticket: []string{"kythe:#documented"},
  3037  
  3038  		IncludeChildren: true,
  3039  	})
  3040  
  3041  	expected := &xpb.DocumentationReply{
  3042  		Document: []*xpb.DocumentationReply_Document{{
  3043  			Ticket: "kythe:#documented",
  3044  			Text: &xpb.Printable{
  3045  				RawText: "some documentation text",
  3046  			},
  3047  			MarkedSource: &cpb.MarkedSource{
  3048  				Kind:    cpb.MarkedSource_IDENTIFIER,
  3049  				PreText: "DocumentBuilderFactory",
  3050  			},
  3051  			Children: []*xpb.DocumentationReply_Document{{
  3052  				Ticket: "kythe:#childDoc",
  3053  				Text: &xpb.Printable{
  3054  					RawText: "child document text",
  3055  				},
  3056  			}, {
  3057  				Ticket: "kythe:#childDocBy",
  3058  				Text: &xpb.Printable{
  3059  					RawText: "second child document text",
  3060  				},
  3061  			}},
  3062  		}},
  3063  		Nodes: nodeInfos(getNodes(
  3064  			"kythe:#childDoc",
  3065  			"kythe:#childDocBy",
  3066  			"kythe:#documented",
  3067  			"kythe:#secondChildDoc",
  3068  		)),
  3069  		DefinitionLocations: map[string]*xpb.Anchor{
  3070  			"kythe:?path=def/location#defDoc": &xpb.Anchor{
  3071  				Ticket: "kythe:?path=def/location#defDoc",
  3072  				Parent: "kythe:?path=def/location",
  3073  				Span: &cpb.Span{
  3074  					Start: &cpb.Point{
  3075  						ByteOffset:   1,
  3076  						LineNumber:   1,
  3077  						ColumnOffset: 1,
  3078  					},
  3079  					End: &cpb.Point{
  3080  						ByteOffset:   4,
  3081  						LineNumber:   1,
  3082  						ColumnOffset: 4,
  3083  					},
  3084  				},
  3085  			},
  3086  		},
  3087  	}
  3088  
  3089  	if reply == nil || err != nil {
  3090  		t.Fatalf("Documentation call failed: (reply: %v; error: %v)", reply, err)
  3091  	} else if diff := compare.ProtoDiff(expected, reply); diff != "" {
  3092  		t.Fatalf("(-expected; +found):\n%s", diff)
  3093  	}
  3094  }
  3095  
  3096  func TestDocumentationPatching(t *testing.T) {
  3097  	st := tbl.Construct(t)
  3098  
  3099  	patcher := &mockPatcher{}
  3100  	st.MakePatcher = func(ctx context.Context, ws *xpb.Workspace) (MultiFilePatcher, error) {
  3101  		return patcher, nil
  3102  	}
  3103  
  3104  	reply, err := st.Documentation(ctx, &xpb.DocumentationRequest{
  3105  		Ticket: []string{"kythe:#documented"},
  3106  
  3107  		IncludeChildren: true,
  3108  
  3109  		Workspace:             &xpb.Workspace{Uri: "test:"},
  3110  		PatchAgainstWorkspace: true,
  3111  	})
  3112  
  3113  	expected := &xpb.DocumentationReply{
  3114  		Document: []*xpb.DocumentationReply_Document{{
  3115  			Ticket: "kythe:#documented",
  3116  			Text: &xpb.Printable{
  3117  				RawText: "some documentation text",
  3118  			},
  3119  			MarkedSource: &cpb.MarkedSource{
  3120  				Kind:    cpb.MarkedSource_IDENTIFIER,
  3121  				PreText: "DocumentBuilderFactory",
  3122  			},
  3123  			Children: []*xpb.DocumentationReply_Document{{
  3124  				Ticket: "kythe:#childDoc",
  3125  				Text: &xpb.Printable{
  3126  					RawText: "child document text",
  3127  				},
  3128  			}, {
  3129  				Ticket: "kythe:#childDocBy",
  3130  				Text: &xpb.Printable{
  3131  					RawText: "second child document text",
  3132  				},
  3133  			}},
  3134  		}},
  3135  		Nodes: nodeInfos(getNodes(
  3136  			"kythe:#childDoc",
  3137  			"kythe:#childDocBy",
  3138  			"kythe:#documented",
  3139  			"kythe:#secondChildDoc",
  3140  		)),
  3141  		DefinitionLocations: map[string]*xpb.Anchor{
  3142  			"kythe:?path=def/location#defDoc": &xpb.Anchor{
  3143  				Ticket: "kythe:?path=def/location#defDoc",
  3144  				Parent: "kythe:?path=def/location",
  3145  				Span: &cpb.Span{
  3146  					Start: &cpb.Point{
  3147  						ByteOffset:   2,
  3148  						LineNumber:   2,
  3149  						ColumnOffset: 2,
  3150  					},
  3151  					End: &cpb.Point{
  3152  						ByteOffset:   5,
  3153  						LineNumber:   2,
  3154  						ColumnOffset: 5,
  3155  					},
  3156  				},
  3157  			},
  3158  		},
  3159  	}
  3160  
  3161  	if reply == nil || err != nil {
  3162  		t.Fatalf("Documentation call failed: (reply: %v; error: %v)", reply, err)
  3163  	} else if diff := compare.ProtoDiff(expected, reply); diff != "" {
  3164  		t.Fatalf("(-expected; +found):\n%s", diff)
  3165  	}
  3166  }
  3167  
  3168  func TestDocumentationIndirection(t *testing.T) {
  3169  	st := tbl.Construct(t)
  3170  	reply, err := st.Documentation(ctx, &xpb.DocumentationRequest{
  3171  		Ticket: []string{"kythe:#documentedBy"},
  3172  	})
  3173  
  3174  	expected := &xpb.DocumentationReply{
  3175  		Document: []*xpb.DocumentationReply_Document{{
  3176  			Ticket: "kythe:#documentedBy",
  3177  			Text: &xpb.Printable{
  3178  				RawText: "some documentation text",
  3179  			},
  3180  			MarkedSource: &cpb.MarkedSource{
  3181  				Kind:    cpb.MarkedSource_IDENTIFIER,
  3182  				PreText: "DocumentBuilderFactory",
  3183  			},
  3184  		}},
  3185  		Nodes: nodeInfos(getNodes("kythe:#documented", "kythe:#documentedBy")),
  3186  		DefinitionLocations: map[string]*xpb.Anchor{
  3187  			"kythe:?path=def/location#defDoc": &xpb.Anchor{
  3188  				Ticket: "kythe:?path=def/location#defDoc",
  3189  				Parent: "kythe:?path=def/location",
  3190  				Span: &cpb.Span{
  3191  					Start: &cpb.Point{
  3192  						ByteOffset:   1,
  3193  						LineNumber:   1,
  3194  						ColumnOffset: 1,
  3195  					},
  3196  					End: &cpb.Point{
  3197  						ByteOffset:   4,
  3198  						LineNumber:   1,
  3199  						ColumnOffset: 4,
  3200  					},
  3201  				},
  3202  			},
  3203  		},
  3204  	}
  3205  
  3206  	if reply == nil || err != nil {
  3207  		t.Fatalf("Documentation call failed: (reply: %v; error: %v)", reply, err)
  3208  	} else if diff := compare.ProtoDiff(expected, reply); diff != "" {
  3209  		t.Fatalf("(-expected; +found):\n%s", diff)
  3210  	}
  3211  }
  3212  
  3213  func TestPageSearchIndex(t *testing.T) {
  3214  	set := &srvpb.PagedCrossReferences{
  3215  		PageSearchIndex: &srvpb.PagedCrossReferences_PageSearchIndex{
  3216  			ByCorpus: &srvpb.PagedCrossReferences_PageSearchIndex_Postings{
  3217  				Index: map[uint32]*srvpb.PagedCrossReferences_PageSearchIndex_Pages{
  3218  					tri("kyt"): pages(0),
  3219  					tri("the"): pages(0, 1, 2),
  3220  					tri("yth"): pages(0),
  3221  					tri("oth"): pages(1),
  3222  					tri("her"): pages(1),
  3223  					tri("Pag"): pages(math.MaxUint32), // short-hand for all pages
  3224  					tri("age"): pages(0, 1, 2),
  3225  					tri("ge_"): pages(1, 2),
  3226  				},
  3227  			},
  3228  			ByRoot: &srvpb.PagedCrossReferences_PageSearchIndex_Postings{
  3229  				Index: map[uint32]*srvpb.PagedCrossReferences_PageSearchIndex_Pages{
  3230  					tri("baz"): pages(1, 2),
  3231  					tri("aze"): pages(1, 2),
  3232  					tri("zel"): pages(1, 2),
  3233  				},
  3234  			},
  3235  			ByPath: &srvpb.PagedCrossReferences_PageSearchIndex_Postings{
  3236  				Index: map[uint32]*srvpb.PagedCrossReferences_PageSearchIndex_Pages{
  3237  					tri("kyt"): pages(0),
  3238  					tri("yth"): pages(0),
  3239  					tri("the"): pages(0),
  3240  					tri("he/"): pages(0),
  3241  					tri("e/g"): pages(0),
  3242  					tri("/go"): pages(0),
  3243  				},
  3244  			},
  3245  			ByResolvedPath: &srvpb.PagedCrossReferences_PageSearchIndex_Postings{
  3246  				Index: map[uint32]*srvpb.PagedCrossReferences_PageSearchIndex_Pages{
  3247  					tri("the"): pages(0, 2),
  3248  					tri("he/"): pages(0, 2),
  3249  					tri("e/b"): pages(0, 2),
  3250  					tri("/ba"): pages(0, 2),
  3251  				},
  3252  			},
  3253  		},
  3254  		PageIndex: []*srvpb.PagedCrossReferences_PageIndex{{
  3255  			PageKey: "kythePage",
  3256  		}, {
  3257  			PageKey: "otherPage_",
  3258  		}, {
  3259  			PageKey: "thePage_",
  3260  		}},
  3261  	}
  3262  
  3263  	// All pages are represented by nil
  3264  	var allPages stringset.Set
  3265  
  3266  	tests := []struct {
  3267  		Filter *xpb.CorpusPathFilters
  3268  		Keys   stringset.Set
  3269  	}{
  3270  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "kyt" }`), stringset.New("kythePage")},
  3271  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "kythe" }`), stringset.New("kythePage")},
  3272  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "kythe|golang" }`), stringset.New("kythePage")},
  3273  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "other" }`), stringset.New("otherPage_")},
  3274  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "kythe|other" }`), stringset.New("kythePage", "otherPage_")},
  3275  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "Page_" }`), stringset.New("thePage_", "otherPage_")},
  3276  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "the" }`), allPages},
  3277  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "Page" }`), allPages},
  3278  
  3279  		// Trigrams are separated by field
  3280  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "kythe/go" }`), stringset.New()},
  3281  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "bazel" }`), stringset.New()},
  3282  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "the/ba" }`), stringset.New()},
  3283  		{mustParseFilters(`filter: { type: INCLUDE_ONLY root: "the/ba" }`), stringset.New()},
  3284  		{mustParseFilters(`filter: { type: INCLUDE_ONLY path: "the/ba" }`), stringset.New()},
  3285  		{mustParseFilters(`filter: { type: INCLUDE_ONLY path: "kythe/go" }`), stringset.New("kythePage")},
  3286  		{mustParseFilters(`filter: { type: INCLUDE_ONLY path: "/go" }`), stringset.New("kythePage")},
  3287  		{mustParseFilters(`filter: { type: INCLUDE_ONLY root: "bazel" }`), stringset.New("otherPage_", "thePage_")},
  3288  		{mustParseFilters(`filter: { type: INCLUDE_ONLY resolved_path: "the/ba" }`), stringset.New("kythePage", "thePage_")},
  3289  
  3290  		// Merge filters
  3291  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "kythe|other" } filter: { type: INCLUDE_ONLY corpus: "other" }`), stringset.New("otherPage_")},
  3292  		{mustParseFilters(`filter: { type: INCLUDE_ONLY resolved_path: "the/ba" } filter: { type: INCLUDE_ONLY root: "bazel" }`), stringset.New("thePage_")},
  3293  
  3294  		// No trigrams; matches everything
  3295  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "ne" }`), allPages},
  3296  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "^$" }`), allPages},
  3297  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "\\.s" }`), allPages},
  3298  
  3299  		// Matches nothing
  3300  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "nope" }`), stringset.New()},
  3301  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "rip" }`), stringset.New()},
  3302  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "kyther" }`), stringset.New()},
  3303  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "kythe.+google" }`), stringset.New()},
  3304  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "golang" }`), stringset.New()},
  3305  
  3306  		// Exclusion filter are not handled by the search index; they match all pages.
  3307  		{mustParseFilters(`filter: { type: EXCLUDE corpus: "kythe" }`), allPages},
  3308  	}
  3309  
  3310  	for i, test := range tests {
  3311  		t.Run(strconv.Itoa(i), func(t *testing.T) {
  3312  			t.Logf("CorpusPathFilters: %s", test.Filter)
  3313  			filter, err := compileCorpusPathFilters(test.Filter, nil)
  3314  			testutil.Fatalf(t, "compileCorpusPathFilters: %v", err)
  3315  			found := filter.PageSet(set)
  3316  
  3317  			var expected *pageSet
  3318  			if test.Keys != nil {
  3319  				expected = &pageSet{KeySet: test.Keys}
  3320  			}
  3321  			if diff := compare.ProtoDiff(expected, found); diff != "" {
  3322  				t.Fatalf("Unexpected diff (-expected; +found):\n%s", diff)
  3323  			}
  3324  		})
  3325  	}
  3326  }
  3327  
  3328  func pages(ps ...uint32) *srvpb.PagedCrossReferences_PageSearchIndex_Pages {
  3329  	if len(ps) <= 1 {
  3330  		return &srvpb.PagedCrossReferences_PageSearchIndex_Pages{PageIndex: ps}
  3331  	}
  3332  	encoded := make([]uint32, len(ps))
  3333  	encoded[0] = ps[0]
  3334  	for i, n := range ps[1:] {
  3335  		encoded[i+1] = n - encoded[i]
  3336  	}
  3337  	return &srvpb.PagedCrossReferences_PageSearchIndex_Pages{PageIndex: encoded}
  3338  }
  3339  
  3340  func TestCorpusPathFilters(t *testing.T) {
  3341  	tests := []struct {
  3342  		filters *xpb.CorpusPathFilters
  3343  
  3344  		includes, excludes []string
  3345  	}{
  3346  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "^kythe3" }`),
  3347  			[]string{cps("kythe3", "", ""), cps("kythe3//branch", "", "")},
  3348  			[]string{cps("other", "", ""), cps("other", "kythe3", "kythe3")}},
  3349  		{mustParseFilters(`filter: { type: EXCLUDE root: ".+" }`),
  3350  			[]string{cps("kythe3", "", ""), cps("kythe3//branch", "", ""), cps("oss", "", "any/path")},
  3351  			[]string{cps("kythe3", "genfiles", ""), cps("other", "bin", "some/path")}},
  3352  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "^kythe3" root: "genfiles" }`),
  3353  			[]string{cps("kythe3", "genfiles", ""), cps("kythe3//branch", "genfiles", "")},
  3354  			[]string{cps("kythe2", "genfiles", ""), cps("kythe3", "bin", "path"), cps("other", "bin", "some/path")}},
  3355  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "kythe" } filter: { type: INCLUDE_ONLY corpus: "2|3" }`),
  3356  			[]string{cps("kythe3", "genfiles", "path"), cps("kythe2", "", "blah")},
  3357  			[]string{cps("kythe4", "", ""), cps("kythe", "kythe2", "kythe3")}},
  3358  		{mustParseFilters(`filter: { type: EXCLUDE root: ".+" } filter: { type: INCLUDE_ONLY corpus: "^kythe3"}`),
  3359  			[]string{cps("kythe3", "", "any/path"), cps("kythe3//branch", "", "some/path")},
  3360  			[]string{cps("kythe3", "genfiles", "any/path"), cps("kythe3//branch", "bin", "some/path")}},
  3361  		{mustParseFilters(`filter: { type: INCLUDE_ONLY resolved_path: "^kythe3/branch/genfiles/"}`),
  3362  			[]string{cps("kythe3//branch", "genfiles", "any/path"), cps("kythe3//branch", "genfiles/more", "any/path")},
  3363  			[]string{cps("kythe3", "bin", "any/path"), cps("kythe3", "genfiles", "some/path")}},
  3364  		// The filter should only apply when the corpus matches.
  3365  		{mustParseFilters(`filter: { type: INCLUDE_ONLY corpus: "^kythe3" path: ".*k.*" corpus_specific_filter: true}`),
  3366  			[]string{cps("kythe3", "", "k1.cc"), cps("kythe3//branch", "", "k3.cc"), cps("other", "", "file.cc")},
  3367  			[]string{cps("kythe3", "", "file.cc")}},
  3368  	}
  3369  
  3370  	for i, test := range tests {
  3371  		t.Run(strconv.Itoa(i), func(t *testing.T) {
  3372  			f, err := compileCorpusPathFilters(test.filters, nil)
  3373  			testutil.Fatalf(t, "Error: %v", err)
  3374  
  3375  			for _, include := range test.includes {
  3376  				if !f.AllowTicket(include) {
  3377  					t.Errorf("Expected %q to be included but it wasn't", include)
  3378  				}
  3379  			}
  3380  			for _, exclude := range test.excludes {
  3381  				if f.AllowTicket(exclude) {
  3382  					t.Errorf("Expected %q to be excluded but it wasn't", exclude)
  3383  				}
  3384  			}
  3385  		})
  3386  	}
  3387  }
  3388  
  3389  func randPostings(rand *rand.Rand) *srvpb.PagedCrossReferences_PageSearchIndex_Postings {
  3390  	numPages := rand.Intn(24) + 1
  3391  	p := &srvpb.PagedCrossReferences_PageSearchIndex_Postings{
  3392  		Index: make(map[uint32]*srvpb.PagedCrossReferences_PageSearchIndex_Pages, numPages),
  3393  	}
  3394  	n := rand.Intn(32) + 1
  3395  	for j := 0; j < n; j++ {
  3396  		s := randTrigram(rand)
  3397  		t := tri(s)
  3398  		ps := make([]uint32, rand.Intn(numPages))
  3399  		if len(ps) == 0 {
  3400  			ps = append([]uint32{}, allPages...)
  3401  		} else {
  3402  			for k := 0; k < len(ps); k++ {
  3403  				ps[k] = uint32(rand.Intn(numPages))
  3404  			}
  3405  
  3406  			// Sort and dedup the pages
  3407  			sort.Slice(ps, func(i, j int) bool { return ps[i] < ps[j] })
  3408  			var k int
  3409  			for l := 1; l < len(ps); l++ {
  3410  				if ps[l-1] == ps[l] {
  3411  					continue
  3412  				}
  3413  				ps[k] = ps[l]
  3414  				k++
  3415  			}
  3416  			ps = ps[:k]
  3417  		}
  3418  		p.Index[t] = pages(ps...)
  3419  	}
  3420  	return p
  3421  }
  3422  
  3423  func randQuery(rand *rand.Rand) []*index.Query {
  3424  	qs := make([]*index.Query, rand.Intn(4)+1)
  3425  	if rand.Intn(1000) == 0 {
  3426  		return nil
  3427  	}
  3428  	for j := 0; j < len(qs); j++ {
  3429  		q := &index.Query{}
  3430  		o := rand.Intn(100)
  3431  		switch {
  3432  		case o == 0:
  3433  			q.Op = index.QAll
  3434  		case o == 99:
  3435  			q.Op = index.QNone
  3436  		case o < 50:
  3437  			q.Op = index.QAnd
  3438  		default:
  3439  			q.Op = index.QOr
  3440  		}
  3441  		if q.Op == index.QAll || q.Op == index.QOr {
  3442  			n := rand.Intn(4) + 1
  3443  			for k := 0; k < n; k++ {
  3444  				q.Trigram = append(q.Trigram, randTrigram(rand))
  3445  			}
  3446  		}
  3447  		if rand.Intn(10) == 0 {
  3448  			q.Sub = randQuery(rand)
  3449  		}
  3450  		qs[j] = q
  3451  	}
  3452  	return qs
  3453  }
  3454  
  3455  func TestApplyQueries(t *testing.T) {
  3456  	testutil.Fatalf(t, "Error: %v", quick.Check(func(p *srvpb.PagedCrossReferences_PageSearchIndex_Postings, qs []*index.Query) bool {
  3457  		res := applyQueries(p, qs, nil)
  3458  		if len(res) > 1 {
  3459  			for _, x := range res {
  3460  				// Make sure the result doesn't include the allPages marker.
  3461  				if x == math.MaxUint32 {
  3462  					t.Logf("Postings: %s", p)
  3463  					t.Logf("Query: %s", qs)
  3464  					t.Logf("Result: %v", res)
  3465  					return false
  3466  				}
  3467  			}
  3468  		}
  3469  		return true
  3470  	}, &quick.Config{Values: func(args []reflect.Value, rand *rand.Rand) {
  3471  		args[0] = reflect.ValueOf(randPostings(rand))
  3472  		args[1] = reflect.ValueOf(randQuery(rand))
  3473  	}}))
  3474  }
  3475  
  3476  func randTrigram(rand *rand.Rand) string {
  3477  	return string([]rune{rune(rand.Intn(8)) + 'a', rune(rand.Intn(8)) + 'a', rune(rand.Intn(8)) + 'a'})
  3478  }
  3479  
  3480  func cps(corpus, root, path string) string {
  3481  	u := &kytheuri.URI{Corpus: corpus, Root: root, Path: path}
  3482  	return u.String()
  3483  }
  3484  
  3485  func mustParseFilters(msg string) *xpb.CorpusPathFilters {
  3486  	var f xpb.CorpusPathFilters
  3487  	if err := prototext.Unmarshal([]byte(msg), &f); err != nil {
  3488  		panic(err)
  3489  	}
  3490  	return &f
  3491  }
  3492  
  3493  // byOffset implements the sort.Interface for *xpb.CrossReferencesReply_RelatedAnchors.
  3494  type byOffset []*xpb.CrossReferencesReply_RelatedAnchor
  3495  
  3496  // Implement the sort.Interface.
  3497  func (s byOffset) Len() int      { return len(s) }
  3498  func (s byOffset) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  3499  func (s byOffset) Less(i, j int) bool {
  3500  	if s[i].Anchor.Span.Start.ByteOffset != s[j].Anchor.Span.Start.ByteOffset {
  3501  		return s[i].Anchor.Span.Start.ByteOffset < s[j].Anchor.Span.Start.ByteOffset
  3502  	} else if len(s[i].Site) == 0 || len(s[i].Site) != len(s[j].Site) {
  3503  		return len(s[i].Site) < len(s[j].Site)
  3504  	}
  3505  	return s[i].Site[0].Span.Start.ByteOffset < s[j].Site[0].Span.Start.ByteOffset
  3506  }
  3507  
  3508  func nodeInfo(n *srvpb.Node) *cpb.NodeInfo {
  3509  	ni := &cpb.NodeInfo{
  3510  		Facts:      make(map[string][]byte, len(n.Fact)),
  3511  		Definition: n.DefinitionLocation.GetTicket(),
  3512  	}
  3513  	for _, f := range n.Fact {
  3514  		ni.Facts[f.Name] = f.Value
  3515  	}
  3516  	if len(ni.Facts) == 0 && ni.Definition == "" {
  3517  		return nil
  3518  	}
  3519  	return ni
  3520  }
  3521  
  3522  func makeFactList(keyVals ...string) []*cpb.Fact {
  3523  	if len(keyVals)%2 != 0 {
  3524  		panic("makeFactList: odd number of key values")
  3525  	}
  3526  	facts := make([]*cpb.Fact, 0, len(keyVals)/2)
  3527  	for i := 0; i < len(keyVals); i += 2 {
  3528  		facts = append(facts, &cpb.Fact{
  3529  			Name:  keyVals[i],
  3530  			Value: []byte(keyVals[i+1]),
  3531  		})
  3532  	}
  3533  	return facts
  3534  }
  3535  
  3536  func refs(norm *span.Normalizer, ds []*srvpb.FileDecorations_Decoration, infos []*srvpb.FileInfo) (refs []*xpb.DecorationsReply_Reference) {
  3537  	fileInfos := makeFileInfoMap(infos)
  3538  	for _, d := range ds {
  3539  		r := decorationToReference(norm, d)
  3540  		r.TargetRevision = fileInfos[r.TargetTicket].GetRevision()
  3541  		refs = append(refs, r)
  3542  	}
  3543  	return
  3544  }
  3545  
  3546  type testTable struct {
  3547  	Nodes       []*srvpb.Node
  3548  	Decorations []*srvpb.FileDecorations
  3549  	RefSets     []*srvpb.PagedCrossReferences
  3550  	RefPages    []*srvpb.PagedCrossReferences_Page
  3551  	Documents   []*srvpb.Document
  3552  }
  3553  
  3554  func (tbl *testTable) Construct(t *testing.T) *Table {
  3555  	p := make(testProtoTable)
  3556  	for _, d := range tbl.Decorations {
  3557  		testutil.Fatalf(t, "Error writing file decorations: %v", p.Put(ctx, DecorationsKey(mustFix(t, d.File.Ticket)), d))
  3558  	}
  3559  	for _, cr := range tbl.RefSets {
  3560  		testutil.Fatalf(t, "Error writing cross-references: %v", p.Put(ctx, CrossReferencesKey(mustFix(t, cr.SourceTicket)), cr))
  3561  	}
  3562  	for _, crp := range tbl.RefPages {
  3563  		testutil.Fatalf(t, "Error writing cross-references: %v", p.Put(ctx, CrossReferencesPageKey(crp.PageKey), crp))
  3564  	}
  3565  	for _, doc := range tbl.Documents {
  3566  		testutil.Fatalf(t, "Error writing documents: %v", p.Put(ctx, DocumentationKey(doc.Ticket), doc))
  3567  	}
  3568  	return NewCombinedTable(p)
  3569  }
  3570  
  3571  func mustFix(t *testing.T, ticket string) string {
  3572  	ft, err := kytheuri.Fix(ticket)
  3573  	if err != nil {
  3574  		t.Fatalf("Error fixing ticket %q: %v", ticket, err)
  3575  	}
  3576  	return ft
  3577  }
  3578  
  3579  type testProtoTable map[string]proto.Message
  3580  
  3581  func (t testProtoTable) Put(_ context.Context, key []byte, val proto.Message) error {
  3582  	t[string(key)] = val
  3583  	return nil
  3584  }
  3585  
  3586  func (t testProtoTable) Lookup(_ context.Context, key []byte, msg proto.Message) error {
  3587  	m, ok := t[string(key)]
  3588  	if !ok {
  3589  		return table.ErrNoSuchKey
  3590  	}
  3591  	proto.Merge(msg, m)
  3592  	return nil
  3593  }
  3594  
  3595  func (t testProtoTable) LookupValues(_ context.Context, key []byte, m proto.Message, f func(proto.Message) error) error {
  3596  	val, ok := t[string(key)]
  3597  	if !ok {
  3598  		return nil
  3599  	}
  3600  	msg := m.ProtoReflect().New().Interface()
  3601  	proto.Merge(msg, val)
  3602  	if err := f(msg); err != nil && err != table.ErrStopLookup {
  3603  		return err
  3604  	}
  3605  	return nil
  3606  }
  3607  
  3608  func (t testProtoTable) Buffered() table.BufferedProto { panic("UNIMPLEMENTED") }
  3609  
  3610  func (t testProtoTable) Close(context.Context) error { return nil }
  3611  
  3612  func fi(cp *cpb.CorpusPath, rev string) *srvpb.FileInfo {
  3613  	return &srvpb.FileInfo{
  3614  		CorpusPath: cp,
  3615  		Revision:   rev,
  3616  	}
  3617  }
  3618  
  3619  func cp(corpus, root, path string) *cpb.CorpusPath {
  3620  	return &cpb.CorpusPath{
  3621  		Corpus: corpus,
  3622  		Root:   root,
  3623  		Path:   path,
  3624  	}
  3625  }