Repository: kythe/kythe
Pull request #5841 (2023-09-14 14:44:04)

test(typescript_indexer): add MarkedSource rendering tests


Patch:
diff --git a/kythe/go/util/markedsource/BUILD b/kythe/go/util/markedsource/BUILD
index 9fd4be87a..52d5bd29f 100644
--- a/kythe/go/util/markedsource/BUILD
+++ b/kythe/go/util/markedsource/BUILD
@@ -17,6 +17,7 @@ go_library(
         "//kythe/proto:common_go_proto",
         "//kythe/proto:storage_go_proto",
         "@com_github_html2markdown//escape",
+        "@org_golang_google_protobuf//encoding/protojson",
         "@org_golang_google_protobuf//proto",
     ],
 )
diff --git a/kythe/go/util/markedsource/resolve.go b/kythe/go/util/markedsource/resolve.go
index ef8016dc7..edb192124 100644
--- a/kythe/go/util/markedsource/resolve.go
+++ b/kythe/go/util/markedsource/resolve.go
@@ -23,6 +23,7 @@ import (
 	"kythe.io/kythe/go/util/schema/edges"
 	"kythe.io/kythe/go/util/schema/facts"
 
+	"google.golang.org/protobuf/encoding/protojson"
 	"google.golang.org/protobuf/proto"
 
 	cpb "kythe.io/kythe/proto/common_go_proto"
@@ -54,6 +55,13 @@ func NewResolver(entries []*spb.Entry) (*Resolver, error) {
 				return nil, fmt.Errorf("error unmarshalling code for %s: %v", ticket, err)
 			}
 			r.nodes[ticket] = &ms
+		} else if e.GetFactName() == facts.Code+"/json" {
+			ticket := kytheuri.ToString(e.GetSource())
+			var ms cpb.MarkedSource
+			if err := protojson.Unmarshal(e.GetFactValue(), &ms); err != nil {
+				return nil, fmt.Errorf("error unmarshalling code/json for %s: %v", ticket, err)
+			}
+			r.nodes[ticket] = &ms
 		} else if e.GetEdgeKind() != "" {
 			ticket := kytheuri.ToString(e.GetSource())
 			kind, ord, _ := edges.ParseOrdinal(e.GetEdgeKind())
diff --git a/kythe/go/util/tools/markedsource/markedsource.go b/kythe/go/util/tools/markedsource/markedsource.go
index de3167282..9ca2256f3 100644
--- a/kythe/go/util/tools/markedsource/markedsource.go
+++ b/kythe/go/util/tools/markedsource/markedsource.go
@@ -73,9 +73,10 @@ func main() {
 		out := bufio.NewWriter(os.Stdout)
 		wr := delimited.NewWriter(out)
 		for _, e := range entries {
-			if e.GetFactName() == facts.Code {
+			if e.GetFactName() == facts.Code || e.GetFactName() == facts.Code+"/json" {
 				resolved := r.Resolve(e.GetSource())
 				e = proto.Clone(e).(*spb.Entry)
+				e.FactName = facts.Code
 				rec, err := proto.Marshal(resolved)
 				exitOnErrf("Error marshalling resolved MarkedSource: %v", err)
 				e.FactValue = rec
diff --git a/kythe/typescript/BUILD b/kythe/typescript/BUILD
index fa2ba5273..a92bfdf9c 100644
--- a/kythe/typescript/BUILD
+++ b/kythe/typescript/BUILD
@@ -91,6 +91,7 @@ js_test(
     ) + [
         "//kythe/cxx/verifier",
         "//kythe/go/platform/tools/entrystream",
+        "//kythe/go/util/tools/markedsource",
     ],
     entry_point = ":test.js",
 )


Test patch:
diff --git a/kythe/typescript/test.ts b/kythe/typescript/test.ts
index 5052d1687..b05e05cab 100644
--- a/kythe/typescript/test.ts
+++ b/kythe/typescript/test.ts
@@ -36,13 +36,15 @@ import {CompilationUnit, IndexerHost, Plugin} from './plugin_api';
 const KYTHE_PATH = process.env['KYTHE'] || '/opt/kythe';
 const RUNFILES = process.env['TEST_SRCDIR'];
 
-
-
-const ENTRYSTREAM = RUNFILES ?
-    path.resolve('kythe/go/platform/tools/entrystream/entrystream') :
-    path.resolve(KYTHE_PATH, 'tools/entrystream');
-const VERIFIER = RUNFILES ? path.resolve('kythe/cxx/verifier/verifier') :
-                            path.resolve(KYTHE_PATH, 'tools/verifier');
+const ENTRYSTREAM = RUNFILES
+  ? path.resolve('kythe/go/platform/tools/entrystream/entrystream')
+  : path.resolve(KYTHE_PATH, 'tools/entrystream');
+const VERIFIER = RUNFILES
+  ? path.resolve('kythe/cxx/verifier/verifier')
+  : path.resolve(KYTHE_PATH, 'tools/verifier');
+const MARKEDSOURCE = RUNFILES
+  ? path.resolve('kythe/go/util/tools/markedsource/markedsource')
+  : path.resolve(KYTHE_PATH, 'tools/markedsource');
 
 /** Record representing a single test case to run. */
 interface TestCase {
@@ -55,7 +57,6 @@ interface TestCase {
   readonly files: string[];
 }
 
-
 /**
  * createTestCompilerHost creates a ts.CompilerHost that caches the default
  * libraries.  This prevents re-parsing the (big) TypeScript standard library
@@ -65,20 +66,22 @@ function createTestCompilerHost(options: ts.CompilerOptions): ts.CompilerHost {
   const compilerHost = ts.createCompilerHost(options);
 
   // Map of path to parsed SourceFile for all TS builtin libraries.
-  const libs = new Map<string, ts.SourceFile|undefined>();
+  const libs = new Map<string, ts.SourceFile | undefined>();
   const libDir = compilerHost.getDefaultLibLocation!();
 
   const hostGetSourceFile = compilerHost.getSourceFile;
-  compilerHost.getSourceFile =
-      (fileName: string, languageVersion: ts.ScriptTarget,
-       onError?: (message: string) => void): ts.SourceFile|undefined => {
-        let sourceFile = libs.get(fileName);
-        if (!sourceFile) {
-          sourceFile = hostGetSourceFile(fileName, languageVersion, onError);
-          if (path.dirname(fileName) === libDir) libs.set(fileName, sourceFile);
-        }
-        return sourceFile;
-      };
+  compilerHost.getSourceFile = (
+    fileName: string,
+    languageVersion: ts.ScriptTarget,
+    onError?: (message: string) => void,
+  ): ts.SourceFile | undefined => {
+    let sourceFile = libs.get(fileName);
+    if (!sourceFile) {
+      sourceFile = hostGetSourceFile(fileName, languageVersion, onError);
+      if (path.dirname(fileName) === libDir) libs.set(fileName, sourceFile);
+    }
+    return sourceFile;
+  };
   return compilerHost;
 }
 
@@ -92,8 +95,13 @@ function isTsFile(filename: string): boolean {
  * be run async; if there's an error, it will reject the promise.
  */
 function verify(
-    host: ts.CompilerHost, options: ts.CompilerOptions, testCase: TestCase,
-    plugins?: Plugin[], emitRefCallOverIdentifier?: boolean): Promise<void> {
+  host: ts.CompilerHost,
+  options: ts.CompilerOptions,
+  testCase: TestCase,
+  plugins?: Plugin[],
+  emitRefCallOverIdentifier?: boolean,
+  resolveCodeFacts?: boolean,
+): Promise<void> {
   const rootVName: kythe.VName = {
     corpus: 'testcorpus',
     root: '',
@@ -104,12 +112,17 @@ function verify(
   const testFiles = testCase.files;
 
   const verifier = child_process.spawn(
-      `${ENTRYSTREAM} --read_format=json | ` +
-          `${VERIFIER} --convert_marked_source ${testFiles.join(' ')}`,
-      [], {
-        stdio: ['pipe', process.stdout, process.stderr],
-        shell: true,
-      });
+    `${ENTRYSTREAM} --read_format=json | ` +
+      (resolveCodeFacts
+        ? `${MARKEDSOURCE} --rewrite --render_callsite_signatures --render_qualified_names --render_signatures | `
+        : '') +
+      `${VERIFIER} --convert_marked_source ${testFiles.join(' ')}`,
+    [],
+    {
+      stdio: ['pipe', process.stdout, process.stderr],
+      shell: true,
+    },
+  );
   const fileVNames = new Map<string, kythe.VName>();
   for (const file of testFiles) {
     fileVNames.set(file, {...rootVName, path: file});
@@ -150,7 +163,9 @@ function verify(
 
 function testLoadTsConfig() {
   const config = indexer.loadTsConfig(
-      'testdata/tsconfig-files.for.tests.json', 'testdata');
+    'testdata/tsconfig-files.for.tests.json',
+    'testdata',
+  );
   // We expect the paths that were loaded to be absolute.
   assert.deepEqual(config.fileNames, [path.resolve('testdata/alt.ts')]);
 }
@@ -208,9 +223,9 @@ function getTestCases(options: ts.CompilerOptions, dir: string): TestCase[] {
  * Matching is done by simply checking for substring.
  */
 function filterTestCases(testCases: TestCase[], filters: string[]): TestCase[] {
-  return testCases.filter(testCase => {
+  return testCases.filter((testCase) => {
     for (const file of testCase.files) {
-      if (filters.some(filter => file.includes(filter))) {
+      if (filters.some((filter) => file.includes(filter))) {
         return true;
       }
     }
@@ -219,8 +234,10 @@ function filterTestCases(testCases: TestCase[], filters: string[]): TestCase[] {
 }
 
 async function testIndexer(filters: string[], plugins?: Plugin[]) {
-  const config =
-      indexer.loadTsConfig('testdata/tsconfig.for.tests.json', 'testdata');
+  const config = indexer.loadTsConfig(
+    'testdata/tsconfig.for.tests.json',
+    'testdata',
+  );
   let testCases = getTestCases(config.options, 'testdata');
   if (filters.length !== 0) {
     testCases = filterTestCases(testCases, filters);
@@ -233,10 +250,20 @@ async function testIndexer(filters: string[], plugins?: Plugin[]) {
       continue;
     }
     const emitRefCallOverIdentifier = testCase.name.endsWith('_id.ts');
+    const resolveCodeFacts = testCase.name.startsWith(
+      'testdata/marked_source/rendered/',
+    );
     const start = new Date().valueOf();
     process.stdout.write(`${testCase.name}: `);
     try {
-      await verify(host, config.options, testCase, plugins, emitRefCallOverIdentifier);
+      await verify(
+        host,
+        config.options,
+        testCase,
+        plugins,
+        emitRefCallOverIdentifier,
+        resolveCodeFacts,
+      );
     } catch (e) {
       console.log('FAIL');
       throw e;
@@ -278,10 +305,10 @@ async function testMain(args: string[]) {
 }
 
 testMain(process.argv.slice(2))
-    .then(() => {
-      process.exitCode = 0;
-    })
-    .catch((e) => {
-      console.error(e);
-      process.exitCode = 1;
-    });
+  .then(() => {
+    process.exitCode = 0;
+  })
+  .catch((e) => {
+    console.error(e);
+    process.exitCode = 1;
+  });
diff --git a/kythe/typescript/testdata/marked_source/rendered/class.ts b/kythe/typescript/testdata/marked_source/rendered/class.ts
new file mode 100644
index 000000000..e101f2787
--- /dev/null
+++ b/kythe/typescript/testdata/marked_source/rendered/class.ts
@@ -0,0 +1,12 @@
+
+//- @MyClass defines/binding MyClass
+//- MyClass.code/rendered/qualified_name "MyClass"
+class MyClass {
+    //- @myMethod defines/binding MyMethod
+    //- MyMethod.code/rendered/callsite_signature "myMethod(arg)"
+    //- MyMethod.code/rendered/signature "myMethod(arg: number): MyClass"
+    //- MyMethod.code/rendered/qualified_name "MyClass.myMethod"
+    myMethod(arg: number): MyClass {
+        return this;
+    }
+}