/** * Regression coverage for the generated-file detector that drives * symbol-disambiguation down-ranking. Locked here because the suffix * list is a contract: if a future edit drops `.pb.go`, the cosmos-sdk * trace endpoint regresses to the gRPC stub (see * `project_go_multi_module_audit` memory + the audit in #N/A). * * The content-header half (#1500) is a second contract: the marker table is * precision-first, because a false positive silently demotes hand-written code * in EVERY ranking path. Measured on a shallow clone of kubernetes/client-go * (2,453 Go files): the path check flags 0, the content check flags 2,001 — * exactly the set that greps to the canonical banner, no false positives and * no misses. Every one of those files has an ordinary name. */ import { describe, it, expect } from 'vitest'; import * as fs from 'fs'; import * as path from 'path'; import { isGeneratedFile, hasGeneratedHeader, detectGeneratedFile, } from '../src/extraction/generated-detection'; describe('isGeneratedFile', () => { it('classifies Go protobuf / gRPC / pulsar / mock outputs as generated', () => { expect(isGeneratedFile('api/cosmos/bank/v1beta1/tx_grpc.pb.go')).toBe(true); expect(isGeneratedFile('x/bank/types/tx.pb.go')).toBe(true); expect(isGeneratedFile('api/cosmos/bank/v1beta1/tx.pulsar.go')).toBe(true); // cosmos-sdk uses `_mocks.go`; mockgen's default is `mock_.go`; // many projects use `_mock.go`. All three are mockgen output. expect(isGeneratedFile('x/auth/testutil/expected_keepers_mocks.go')).toBe(true); expect(isGeneratedFile('internal/foo_mock.go')).toBe(true); expect(isGeneratedFile('mock_keeper.go')).toBe(true); }); it('does not flag the hand-written keeper as generated', () => { expect(isGeneratedFile('x/bank/keeper/msg_server.go')).toBe(false); expect(isGeneratedFile('x/bank/keeper/send.go')).toBe(false); }); it('catches common cross-language codegen suffixes', () => { expect(isGeneratedFile('app/foo.generated.ts')).toBe(true); expect(isGeneratedFile('app/foo.generated.tsx')).toBe(true); expect(isGeneratedFile('proto/bar_pb2.py')).toBe(true); expect(isGeneratedFile('proto/bar_pb2_grpc.py')).toBe(true); expect(isGeneratedFile('lib/baz.pb.cc')).toBe(true); expect(isGeneratedFile('lib/baz.pb.h')).toBe(true); expect(isGeneratedFile('lib/quux.g.dart')).toBe(true); expect(isGeneratedFile('lib/quux.freezed.dart')).toBe(true); }); it('leaves ordinary source files alone', () => { expect(isGeneratedFile('src/index.ts')).toBe(false); expect(isGeneratedFile('src/components/Foo.tsx')).toBe(false); expect(isGeneratedFile('lib/main.dart')).toBe(false); expect(isGeneratedFile('cmd/server/main.go')).toBe(false); expect(isGeneratedFile('app/db.py')).toBe(false); }); }); describe('hasGeneratedHeader — per-marker coverage (#1500)', () => { // One case per banner the marker table claims to recognize. Each string is // the real thing a generator emits, not a paraphrase — if a regex is // narrowed, the case that motivated it fails by name. const GENERATED: ReadonlyArray<[string, string]> = [ [ 'Go — the #1500 case: ordinary filename, banner below the package clause', 'package payroll\n\n// Code generated by fkit. DO NOT EDIT.\n\nimport "context"\n\nfunc CreatePayroll(ctx context.Context) error { return nil }\n', ], [ 'Go — protoc-gen-go', '// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// protoc-gen-go v1.28.0\n\npackage pb\n', ], [ 'Go — banner under build tags', '//go:build !windows\n// +build !windows\n\n// Code generated by MockGen. DO NOT EDIT.\npackage mocks\n', ], [ 'Go — banner under an Apache-2.0 license preamble', '// Copyright 2021 The Foo Authors.\n// Licensed under the Apache License, Version 2.0 (the "License");\n// you may not use this file except in compliance with the License.\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an "AS IS" BASIS.\n\n// Code generated by sqlc. DO NOT EDIT.\n// source: query.sql\n\npackage db\n', ], [ 'protoc — Java banner ("DO NOT EDIT!")', '// Generated by the protocol buffer compiler. DO NOT EDIT!\n// source: foo.proto\n\npackage com.example;\n', ], [ 'protoc — Python banner behind a coding cookie', '# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler. DO NOT EDIT!\n# source: foo.proto\n', ], [ 'C# — Roslyn / designer block', '//------------------------------------------------------------------------------\n// \n// This code was generated by a tool.\n// \n//------------------------------------------------------------------------------\n', ], ['C# — EF self-closing ', '// \nusing System;\n'], [ 'JS — Meta/Relay @generated with a SignedSource', '/**\n * @generated SignedSource<<0123456789abcdef0123456789abcdef>>\n * @flow\n */\n', ], [ 'TS — protobuf-es / Buf @generated', '// @generated by protoc-gen-es v1.2.0 with parameter "target=ts"\n// @generated from file foo.proto (package example, syntax proto3)\n', ], [ 'Thrift — "Autogenerated by Thrift Compiler"', '/**\n * Autogenerated by Thrift Compiler (0.14.1)\n *\n * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n */\n', ], [ 'OpenAPI Generator — "This class is auto generated by"', '/*\n * Pet Store API\n *\n * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).\n * Do not edit the class manually.\n */\n', ], [ 'FlatBuffers — "automatically generated by … do not modify"', '// automatically generated by the FlatBuffers compiler, do not modify\n\npackage MyGame;\n', ], [ 'Rust — bindgen block comment', '/* automatically generated by rust-bindgen 0.59.2 */\n\npub const FOO: u32 = 1;\n', ], ['ANTLR — "Generated from … -- DO NOT EDIT"', '// Generated from Expr.g4 by ANTLR 4.9.2 -- DO NOT EDIT\npackage parser;\n'], [ 'banner on an unprefixed line INSIDE a block comment', '/*\n Code generated by ent. DO NOT EDIT.\n*/\npackage ent\n', ], [ 'Python — banner inside a module docstring', '"""Generated by the protocol buffer compiler. DO NOT EDIT!"""\nimport sys\n', ], ['YAML/shell — "#" comment leader', '# This file is generated by kustomize. Do not edit.\napiVersion: v1\n'], ['SQL — "--" comment leader', '-- Code generated by sqlc. DO NOT EDIT.\nCREATE TABLE foo (id INT);\n'], ['HTML/XML — "\n\n'], ]; it.each(GENERATED)('flags: %s', (_label, source) => { expect(hasGeneratedHeader(source)).toBe(true); }); // Precision cases. Each is a shape that a looser marker table WOULD flag. const HAND_WRITTEN: ReadonlyArray<[string, string]> = [ [ 'ordinary Go source', 'package keeper\n\nimport "context"\n\n// SendCoins moves coins between accounts.\nfunc (k Keeper) SendCoins(ctx context.Context) error { return nil }\n', ], [ 'a generator\'s own source, which merely talks about generating', '// This package generates SQL migrations from the schema.\n// The generated output lives under db/migrations.\npackage gen\n', ], [ 'prose using "automatically generated" without naming a tool', '"""Report builder.\n\nThe summary table is automatically generated at runtime from the\nrows below; callers should not edit it in place.\n"""\n', ], [ 'a generator holding the banner as a string constant in its BODY', 'package main\n\n// Package main implements the fkit CRUD generator.\n\nimport "fmt"\n\nfunc header() string {\n\treturn "// Code generated by fkit. DO NOT EDIT."\n}\n', ], ['an email address that happens to contain "@generated"', '// Contact: build@generated.example.com for issues.\npackage main\n'], ['"DO NOT EDIT" with no generation claim', '// DO NOT EDIT THIS FILE BY HAND — run `make fmt` instead.\npackage main\n'], ['empty file', ''], ]; it.each(HAND_WRITTEN)('does not flag: %s', (_label, source) => { expect(hasGeneratedHeader(source)).toBe(false); }); it('only looks at the header — a banner buried 80 lines down is not a banner', () => { const filler = Array.from({ length: 80 }, (_, i) => `// filler line ${i}`).join('\n'); expect(hasGeneratedHeader(`${filler}\n// Code generated by foo. DO NOT EDIT.\npackage main\n`)).toBe(false); // …but the same banner within the window is caught. const shortFiller = Array.from({ length: 20 }, (_, i) => `// filler line ${i}`).join('\n'); expect(hasGeneratedHeader(`${shortFiller}\n// Code generated by foo. DO NOT EDIT.\npackage main\n`)).toBe(true); }); it('requires a comment line — the same words in executable code are not a banner', () => { // No comment leader, no open block: this is a bare statement. expect(hasGeneratedHeader('const banner = "Code generated by tool. DO NOT EDIT.";\n')).toBe(false); }); it('does not classify the detector module itself (the pattern table must stay below the header window)', () => { const self = fs.readFileSync( path.join(__dirname, '..', 'src', 'extraction', 'generated-detection.ts'), 'utf-8' ); expect(hasGeneratedHeader(self)).toBe(false); }); }); describe('detectGeneratedFile — the union the indexer persists', () => { it('is true when only the PATH says so', () => { expect(detectGeneratedFile('x/bank/types/tx.pb.go', 'package types\n')).toBe(true); }); it('is true when only the CONTENT says so — the #1500 acceptance case', () => { // A Go file named `payroll.go` sitting beside hand-written workflow // use-cases. Nothing in the path gives it away. expect( detectGeneratedFile('internal/payroll/payroll.go', 'package payroll\n\n// Code generated by fkit. DO NOT EDIT.\n\nfunc Create() {}\n') ).toBe(true); expect(isGeneratedFile('internal/payroll/payroll.go')).toBe(false); }); it('is false for a hand-written file with an ordinary name', () => { expect( detectGeneratedFile('internal/payroll/workflow.go', 'package payroll\n\n// RunPayrollWorkflow drives the monthly run.\nfunc RunPayrollWorkflow() {}\n') ).toBe(false); }); });