@ai-dev-tools/csharp-copilot-core 0.0.34 → 0.0.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -42,15 +42,16 @@ const getCodeCoverageSetting_1 = require("../codeCoverage/getCodeCoverageSetting
|
|
|
42
42
|
/**
|
|
43
43
|
* Process a single source file to get all related paths.
|
|
44
44
|
* @param sourceFile - The changed file entry (filepath should be absolute path from CI)
|
|
45
|
+
* @param changedTestFiles - List of changed test file paths from the config
|
|
45
46
|
*/
|
|
46
|
-
function processSourceFile(sourceFile) {
|
|
47
|
+
function processSourceFile(sourceFile, changedTestFiles) {
|
|
47
48
|
const fullSourcePath = path.normalize(sourceFile.filepath);
|
|
48
49
|
// Find solution file
|
|
49
50
|
const solutionFilePath = (0, getCodeStructurePath_1.findSolutionFile)(fullSourcePath);
|
|
50
51
|
// Get test file path
|
|
51
52
|
let testFilePath = null;
|
|
52
53
|
try {
|
|
53
|
-
const result = (0, getTestFile_1.getOrCreatTestFile)(fullSourcePath, undefined);
|
|
54
|
+
const result = (0, getTestFile_1.getOrCreatTestFile)(fullSourcePath, undefined, changedTestFiles);
|
|
54
55
|
testFilePath = result.testFilePath;
|
|
55
56
|
}
|
|
56
57
|
catch (error) {
|
|
@@ -106,9 +107,10 @@ async function processChangedFiles(changedFilesConfigPath, options) {
|
|
|
106
107
|
console.log('Test files:', testFiles.map(f => f.filepath));
|
|
107
108
|
console.log('Source files:', sourceFiles.map(f => f.filepath));
|
|
108
109
|
// Process each source file
|
|
110
|
+
const changedTestFilePaths = testFiles.map(f => f.filepath);
|
|
109
111
|
const processedFiles = [];
|
|
110
112
|
for (const sourceFile of sourceFiles) {
|
|
111
|
-
const processed = processSourceFile(sourceFile);
|
|
113
|
+
const processed = processSourceFile(sourceFile, changedTestFilePaths);
|
|
112
114
|
processedFiles.push(processed);
|
|
113
115
|
console.log(`Processed: ${sourceFile.filepath}`);
|
|
114
116
|
console.log(` Solution: ${processed.solutionFilePath || 'not found'}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processChangedFiles.js","sourceRoot":"","sources":["../../src/changedFilesProcessor/processChangedFiles.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport { getOrCreatTestFile, isTestFile } from '../utils/getTestFile';\r\nimport { getCodeRepoRoot, findSolutionFile } from '../utils/getCodeStructurePath';\r\nimport { getCodeCoverageSetting } from '../codeCoverage/getCodeCoverageSetting';\r\nimport { ChangedFileEntry, CategorizedFiles, ProcessedSourceFile, ChangedFileResult, ProcessChangedFilesResult } from '../types/changedFilesResult';\r\n\r\nexport type { CategorizedFiles, ProcessedSourceFile, ChangedFileResult, ProcessChangedFilesResult };\r\n\r\n/**\r\n * Process a single source file to get all related paths.\r\n * @param sourceFile - The changed file entry (filepath should be absolute path from CI)\r\n */\r\nfunction processSourceFile(sourceFile: ChangedFileEntry): ProcessedSourceFile {\r\n const fullSourcePath = path.normalize(sourceFile.filepath);\r\n\r\n // Find solution file\r\n const solutionFilePath = findSolutionFile(fullSourcePath);\r\n\r\n // Get test file path\r\n let testFilePath: string | null = null;\r\n try {\r\n const result = getOrCreatTestFile(fullSourcePath, undefined);\r\n testFilePath = result.testFilePath;\r\n } catch (error) {\r\n console.warn(`Failed to get test file for ${sourceFile.filepath}: ${error}`);\r\n }\r\n\r\n // Find runsettings file from test project path\r\n const runsettingsFilePath = testFilePath ? getCodeCoverageSetting(testFilePath) : null;\r\n\r\n return {\r\n sourceFile,\r\n testFilePath,\r\n runsettingsFilePath,\r\n solutionFilePath\r\n };\r\n}\r\n\r\n/**\r\n * Read and parse the changed files config, filter CS files, and categorize them.\r\n */\r\nfunction readAndCategorizeChangedFiles(configPath: string): CategorizedFiles {\r\n const configContent = fs.readFileSync(configPath, 'utf-8');\r\n const parsed: unknown = JSON.parse(configContent);\r\n\r\n if (!Array.isArray(parsed)) {\r\n throw new Error(`Changed files config is not an array: ${configPath}`);\r\n }\r\n\r\n const allFiles: ChangedFileEntry[] = parsed.filter(\r\n (entry): entry is ChangedFileEntry =>\r\n entry != null &&\r\n typeof entry === 'object' &&\r\n typeof (entry as any).filepath === 'string'\r\n );\r\n\r\n // Filter only .cs files\r\n const csFiles = allFiles.filter(entry => entry.filepath.toLowerCase().endsWith('.cs'));\r\n\r\n // Categorize into test files and source files\r\n const testFiles: ChangedFileEntry[] = [];\r\n const sourceFiles: ChangedFileEntry[] = [];\r\n\r\n for (const file of csFiles) {\r\n if (isTestFile(file.filepath)) {\r\n testFiles.push(file);\r\n } else {\r\n sourceFiles.push(file);\r\n }\r\n }\r\n\r\n console.log(`Found ${csFiles.length} CS files: ${testFiles.length} test files, ${sourceFiles.length} source files`);\r\n\r\n return { testFiles, sourceFiles };\r\n}\r\n\r\n/**\r\n * Process changed files from a config file path.\r\n * @param changedFilesConfigPath - Path to the JSON config file containing changed files array\r\n * @param options - Additional command line options\r\n * @returns Result with most common solution, its runsettings, and changed files with test paths\r\n */\r\nexport async function processChangedFiles(changedFilesConfigPath: string, options: Record<string, unknown>): Promise<ProcessChangedFilesResult> {\r\n console.log(`Processing changed files from config: ${changedFilesConfigPath}`);\r\n\r\n // Read and categorize files\r\n const { testFiles, sourceFiles } = readAndCategorizeChangedFiles(changedFilesConfigPath);\r\n\r\n console.log('Test files:', testFiles.map(f => f.filepath));\r\n console.log('Source files:', sourceFiles.map(f => f.filepath));\r\n\r\n // Process each source file\r\n const processedFiles: ProcessedSourceFile[] = [];\r\n for (const sourceFile of sourceFiles) {\r\n const processed = processSourceFile(sourceFile);\r\n processedFiles.push(processed);\r\n console.log(`Processed: ${sourceFile.filepath}`);\r\n console.log(` Solution: ${processed.solutionFilePath || 'not found'}`);\r\n console.log(` Runsettings: ${processed.runsettingsFilePath || 'not found'}`);\r\n console.log(` Test file: ${processed.testFilePath || 'not found'}`);\r\n }\r\n\r\n // solutionPath -> {file count, runsettings}\r\n const solutionCounts = new Map<string, { count: number; runsettingsFilePath: string | null }>();\r\n for (const file of processedFiles) {\r\n if (file.solutionFilePath) {\r\n const existing = solutionCounts.get(file.solutionFilePath);\r\n if (existing) {\r\n existing.count++;\r\n } else {\r\n solutionCounts.set(file.solutionFilePath, { \r\n count: 1, \r\n runsettingsFilePath: file.runsettingsFilePath \r\n });\r\n }\r\n }\r\n }\r\n\r\n // Get the solution with the highest count\r\n let mostCommonSolution: string | null = null;\r\n let mostCommonRunsettings: string | null = null;\r\n if (solutionCounts.size > 0) {\r\n const [solution, data] = [...solutionCounts.entries()]\r\n .reduce((a, b) => a[1].count > b[1].count ? a : b);\r\n mostCommonSolution = solution;\r\n mostCommonRunsettings = data.runsettingsFilePath;\r\n }\r\n\r\n // Build the changed file array\r\n const changedFiles: ChangedFileResult[] = processedFiles.map(file => ({\r\n filepath: file.sourceFile.filepath,\r\n testfilepath: file.testFilePath\r\n }));\r\n\r\n const result: ProcessChangedFilesResult = {\r\n solutionFilePath: mostCommonSolution,\r\n runsettingsFilePath: mostCommonRunsettings,\r\n changedFiles\r\n };\r\n\r\n console.log(`Result: Solution=${mostCommonSolution}, Runsettings=${mostCommonRunsettings}, ChangedFiles=${changedFiles.length}`);\r\n\r\n return result;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"processChangedFiles.js","sourceRoot":"","sources":["../../src/changedFilesProcessor/processChangedFiles.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport { getOrCreatTestFile, isTestFile } from '../utils/getTestFile';\r\nimport { getCodeRepoRoot, findSolutionFile } from '../utils/getCodeStructurePath';\r\nimport { getCodeCoverageSetting } from '../codeCoverage/getCodeCoverageSetting';\r\nimport { ChangedFileEntry, CategorizedFiles, ProcessedSourceFile, ChangedFileResult, ProcessChangedFilesResult } from '../types/changedFilesResult';\r\n\r\nexport type { CategorizedFiles, ProcessedSourceFile, ChangedFileResult, ProcessChangedFilesResult };\r\n\r\n/**\r\n * Process a single source file to get all related paths.\r\n * @param sourceFile - The changed file entry (filepath should be absolute path from CI)\r\n * @param changedTestFiles - List of changed test file paths from the config\r\n */\r\nfunction processSourceFile(sourceFile: ChangedFileEntry, changedTestFiles: string[]): ProcessedSourceFile {\r\n const fullSourcePath = path.normalize(sourceFile.filepath);\r\n\r\n // Find solution file\r\n const solutionFilePath = findSolutionFile(fullSourcePath);\r\n\r\n // Get test file path\r\n let testFilePath: string | null = null;\r\n try {\r\n const result = getOrCreatTestFile(fullSourcePath, undefined, changedTestFiles);\r\n testFilePath = result.testFilePath;\r\n } catch (error) {\r\n console.warn(`Failed to get test file for ${sourceFile.filepath}: ${error}`);\r\n }\r\n\r\n // Find runsettings file from test project path\r\n const runsettingsFilePath = testFilePath ? getCodeCoverageSetting(testFilePath) : null;\r\n\r\n return {\r\n sourceFile,\r\n testFilePath,\r\n runsettingsFilePath,\r\n solutionFilePath\r\n };\r\n}\r\n\r\n/**\r\n * Read and parse the changed files config, filter CS files, and categorize them.\r\n */\r\nfunction readAndCategorizeChangedFiles(configPath: string): CategorizedFiles {\r\n const configContent = fs.readFileSync(configPath, 'utf-8');\r\n const parsed: unknown = JSON.parse(configContent);\r\n\r\n if (!Array.isArray(parsed)) {\r\n throw new Error(`Changed files config is not an array: ${configPath}`);\r\n }\r\n\r\n const allFiles: ChangedFileEntry[] = parsed.filter(\r\n (entry): entry is ChangedFileEntry =>\r\n entry != null &&\r\n typeof entry === 'object' &&\r\n typeof (entry as any).filepath === 'string'\r\n );\r\n\r\n // Filter only .cs files\r\n const csFiles = allFiles.filter(entry => entry.filepath.toLowerCase().endsWith('.cs'));\r\n\r\n // Categorize into test files and source files\r\n const testFiles: ChangedFileEntry[] = [];\r\n const sourceFiles: ChangedFileEntry[] = [];\r\n\r\n for (const file of csFiles) {\r\n if (isTestFile(file.filepath)) {\r\n testFiles.push(file);\r\n } else {\r\n sourceFiles.push(file);\r\n }\r\n }\r\n\r\n console.log(`Found ${csFiles.length} CS files: ${testFiles.length} test files, ${sourceFiles.length} source files`);\r\n\r\n return { testFiles, sourceFiles };\r\n}\r\n\r\n/**\r\n * Process changed files from a config file path.\r\n * @param changedFilesConfigPath - Path to the JSON config file containing changed files array\r\n * @param options - Additional command line options\r\n * @returns Result with most common solution, its runsettings, and changed files with test paths\r\n */\r\nexport async function processChangedFiles(changedFilesConfigPath: string, options: Record<string, unknown>): Promise<ProcessChangedFilesResult> {\r\n console.log(`Processing changed files from config: ${changedFilesConfigPath}`);\r\n\r\n // Read and categorize files\r\n const { testFiles, sourceFiles } = readAndCategorizeChangedFiles(changedFilesConfigPath);\r\n\r\n console.log('Test files:', testFiles.map(f => f.filepath));\r\n console.log('Source files:', sourceFiles.map(f => f.filepath));\r\n\r\n // Process each source file\r\n const changedTestFilePaths = testFiles.map(f => f.filepath);\r\n const processedFiles: ProcessedSourceFile[] = [];\r\n for (const sourceFile of sourceFiles) {\r\n const processed = processSourceFile(sourceFile, changedTestFilePaths);\r\n processedFiles.push(processed);\r\n console.log(`Processed: ${sourceFile.filepath}`);\r\n console.log(` Solution: ${processed.solutionFilePath || 'not found'}`);\r\n console.log(` Runsettings: ${processed.runsettingsFilePath || 'not found'}`);\r\n console.log(` Test file: ${processed.testFilePath || 'not found'}`);\r\n }\r\n\r\n // solutionPath -> {file count, runsettings}\r\n const solutionCounts = new Map<string, { count: number; runsettingsFilePath: string | null }>();\r\n for (const file of processedFiles) {\r\n if (file.solutionFilePath) {\r\n const existing = solutionCounts.get(file.solutionFilePath);\r\n if (existing) {\r\n existing.count++;\r\n } else {\r\n solutionCounts.set(file.solutionFilePath, { \r\n count: 1, \r\n runsettingsFilePath: file.runsettingsFilePath \r\n });\r\n }\r\n }\r\n }\r\n\r\n // Get the solution with the highest count\r\n let mostCommonSolution: string | null = null;\r\n let mostCommonRunsettings: string | null = null;\r\n if (solutionCounts.size > 0) {\r\n const [solution, data] = [...solutionCounts.entries()]\r\n .reduce((a, b) => a[1].count > b[1].count ? a : b);\r\n mostCommonSolution = solution;\r\n mostCommonRunsettings = data.runsettingsFilePath;\r\n }\r\n\r\n // Build the changed file array\r\n const changedFiles: ChangedFileResult[] = processedFiles.map(file => ({\r\n filepath: file.sourceFile.filepath,\r\n testfilepath: file.testFilePath\r\n }));\r\n\r\n const result: ProcessChangedFilesResult = {\r\n solutionFilePath: mostCommonSolution,\r\n runsettingsFilePath: mostCommonRunsettings,\r\n changedFiles\r\n };\r\n\r\n console.log(`Result: Solution=${mostCommonSolution}, Runsettings=${mostCommonRunsettings}, ChangedFiles=${changedFiles.length}`);\r\n\r\n return result;\r\n}\r\n"]}
|
package/out/utils/getTestFile.js
CHANGED
|
@@ -755,6 +755,7 @@ function getTestFileFromChangedFiles(sourceCodePath, changedTestFiles) {
|
|
|
755
755
|
if (!changedTestFiles || changedTestFiles.length === 0) {
|
|
756
756
|
return { testFilePath: null, testProjectPath: null };
|
|
757
757
|
}
|
|
758
|
+
console.log(`Searching test file from ${changedTestFiles.length} changed test files for source: ${sourceCodePath}`);
|
|
758
759
|
// Get the csproj of the source code
|
|
759
760
|
const sourceCsprojPath = (0, getCodeStructurePath_1.getSourceFileCsprojFilePath)(sourceCodePath);
|
|
760
761
|
if (!sourceCsprojPath) {
|
|
@@ -802,55 +803,53 @@ function getOrCreatTestFile(sourceCodePath, testFilePath, changedTestFiles) {
|
|
|
802
803
|
let finalTestFilePath = testFilePath;
|
|
803
804
|
let finalTestProjectPath;
|
|
804
805
|
let testFileExist = !!testFilePath && fs.existsSync(testFilePath);
|
|
805
|
-
// If
|
|
806
|
-
if (
|
|
806
|
+
// If testFilePath is provided, get its project path and return directly
|
|
807
|
+
if (testFilePath && testFilePath.trim() !== '') {
|
|
807
808
|
finalTestProjectPath = (0, getCodeStructurePath_1.getSourceFileCsprojFilePath)(testFilePath);
|
|
808
809
|
return { testFilePath: finalTestFilePath, testProjectPath: finalTestProjectPath, testFileExist };
|
|
809
810
|
}
|
|
810
811
|
// if outputPath param is not provided, try to find an existing test file
|
|
811
812
|
// if no existing test file found, create a new one in test project
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
(0, getOrCreateDir_1.getOrCreateDir)(path.dirname(finalTestFilePath));
|
|
853
|
-
}
|
|
813
|
+
console.log(' Output path is missing. outputPath:', testFilePath, ', start looking for existing test project');
|
|
814
|
+
// Try to find test file from changed files first
|
|
815
|
+
let resultFromChangedFiles = getTestFileFromChangedFiles(sourceCodePath, changedTestFiles);
|
|
816
|
+
if (resultFromChangedFiles.testFilePath) {
|
|
817
|
+
return { testFilePath: resultFromChangedFiles.testFilePath, testProjectPath: resultFromChangedFiles.testProjectPath, testFileExist: true };
|
|
818
|
+
}
|
|
819
|
+
// Fallback: try to find existing test file
|
|
820
|
+
const possibleCSProjPaths = findPossibleTestProjectsFromCsFile(sourceCodePath);
|
|
821
|
+
if (!possibleCSProjPaths || possibleCSProjPaths.length === 0) {
|
|
822
|
+
console.error(` No test project found for source code: ${sourceCodePath}`);
|
|
823
|
+
return { testFilePath: null, testProjectPath: null, testFileExist: false };
|
|
824
|
+
}
|
|
825
|
+
// Get the source csproj path for matching
|
|
826
|
+
const sourceCsprojPath = (0, getCodeStructurePath_1.getSourceFileCsprojFilePath)(sourceCodePath);
|
|
827
|
+
if (!sourceCsprojPath) {
|
|
828
|
+
console.error(` Cannot find source csproj for: ${sourceCodePath}`);
|
|
829
|
+
return { testFilePath: null, testProjectPath: null, testFileExist: false };
|
|
830
|
+
}
|
|
831
|
+
// Try to find existing test file in each possible test project
|
|
832
|
+
for (const testCsprojPath of possibleCSProjPaths) {
|
|
833
|
+
const result = findMatchingTestFileInProject(testCsprojPath, sourceCodePath, sourceCsprojPath);
|
|
834
|
+
if (result.testFilePath) {
|
|
835
|
+
testFileExist = true;
|
|
836
|
+
finalTestFilePath = result.testFilePath;
|
|
837
|
+
finalTestProjectPath = result.testProjectPath;
|
|
838
|
+
return { testFilePath: finalTestFilePath, testProjectPath: finalTestProjectPath, testFileExist };
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
// No existing test file found, determine test file path (may find existing)
|
|
842
|
+
const result = determineTestFilePath(sourceCodePath, possibleCSProjPaths[0]);
|
|
843
|
+
if (!result.testFilePath || !result.testProjectPath) {
|
|
844
|
+
console.error(`Failed to determine test file path for ${sourceCodePath}`);
|
|
845
|
+
return { testFilePath: null, testProjectPath: null, testFileExist: false };
|
|
846
|
+
}
|
|
847
|
+
finalTestFilePath = result.testFilePath;
|
|
848
|
+
finalTestProjectPath = result.testProjectPath;
|
|
849
|
+
testFileExist = result.testFileExist ?? false;
|
|
850
|
+
// Create directory if test file doesn't exist
|
|
851
|
+
if (!testFileExist) {
|
|
852
|
+
(0, getOrCreateDir_1.getOrCreateDir)(path.dirname(finalTestFilePath));
|
|
854
853
|
}
|
|
855
854
|
return { testFilePath: finalTestFilePath, testProjectPath: finalTestProjectPath, testFileExist };
|
|
856
855
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getTestFile.js","sourceRoot":"","sources":["../../src/utils/getTestFile.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\r\nimport * as path from 'path';\r\n\r\nimport { getAssemblyName, getCodeRepoRoot, getSourceFileCsprojFilePath, getSourceFileProjectDir } from './getCodeStructurePath';\r\nimport { getOrCreateDir } from './getOrCreateDir';\r\n\r\nimport { XMLParser } from 'fast-xml-parser';\r\n\r\nconst TEST_NAME_REGEX = /(Test|Tests)/i;\r\nconst TEST_ATTR_REGEX = /\\[(Fact|Theory|TestClass|TestMethod|Test)\\]/;\r\n\r\n/**\r\n * Check if a file path is a test file based on common naming conventions.\r\n * Checks if the file name (without .cs extension) ends with test, tests, unittest, or unittests.\r\n */\r\nexport function isTestFile(filepath: string): boolean {\r\n const fileName = path.basename(filepath).toLowerCase();\r\n const fileNameWithoutExt = fileName.replace(/\\.cs$/, '');\r\n \r\n return fileNameWithoutExt.endsWith('test') || \r\n fileNameWithoutExt.endsWith('tests') ||\r\n fileNameWithoutExt.endsWith('unittest') ||\r\n fileNameWithoutExt.endsWith('unittests');\r\n}\r\n\r\n// Modifier pattern for C# type declarations (sealed, abstract, static, partial)\r\nconst MODIFIER_PATTERN = `(?:sealed|abstract|static|partial)?\\\\s*`;\r\n\r\n// Helper function to create test file name pattern\r\nfunction getTestFileNamePattern(sourceFileName: string): RegExp {\r\n return new RegExp(`^${sourceFileName}(Unit)?(\\\\.)?(Test|Tests)$`);\r\n}\r\n\r\n/**\r\n * Extract words from a name string (e.g., project name, file name)\r\n * Splits by camelCase and special characters, returns lowercase words\r\n * \r\n * @param name - The name string to extract words from\r\n * @returns Array of lowercase words\r\n */\r\nfunction extractWordsFromName(name: string): string[] {\r\n return name\r\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\r\n .split(/[^a-zA-Z0-9]+/)\r\n .filter(Boolean)\r\n .map(w => w.toLowerCase());\r\n}\r\n\r\n/**\r\n * Calculate word-level matching score between two names\r\n * Returns the count of matching words\r\n * \r\n * @param name1 - First name to compare\r\n * @param name2 - Second name to compare\r\n * @returns Number of matching words\r\n */\r\nfunction calculateWordMatchCount(name1: string, name2: string): number {\r\n const words1 = extractWordsFromName(name1);\r\n const words2 = extractWordsFromName(name2);\r\n \r\n const words1Set = new Set(words1);\r\n return words2.filter(w => words1Set.has(w)).length;\r\n}\r\n\r\n/**\r\n * Get all subfolder names under a directory (recursive)\r\n * Skips: bin, obj, .vs directories\r\n * \r\n * @param dirPath - Path to directory\r\n * @returns Set of lowercase folder names\r\n */\r\nfunction getSubfolderNamesRecursive(dirPath: string): Set<string> {\r\n const subfolders = new Set<string>();\r\n try {\r\n const entries = fs.readdirSync(dirPath, { withFileTypes: true });\r\n for (const entry of entries) {\r\n if (entry.isDirectory() && entry.name !== 'bin' && entry.name !== 'obj' && entry.name !== '.vs') {\r\n subfolders.add(entry.name.toLowerCase());\r\n // Recursively get subfolders\r\n const subPath = path.join(dirPath, entry.name);\r\n const deepSubfolders = getSubfolderNamesRecursive(subPath);\r\n deepSubfolders.forEach(f => subfolders.add(f));\r\n }\r\n }\r\n } catch (err) {\r\n // Ignore errors for inaccessible directories\r\n }\r\n return subfolders;\r\n}\r\n\r\n/**\r\n * Get all .cs file names under a directory (recursive)\r\n * Skips: bin, obj, .vs directories\r\n * \r\n * @param dirPath - Path to directory\r\n * @returns Set of lowercase file names (without .cs extension)\r\n */\r\nfunction getFileNamesRecursive(dirPath: string): Set<string> {\r\n const fileNames = new Set<string>();\r\n try {\r\n const entries = fs.readdirSync(dirPath, { withFileTypes: true });\r\n for (const entry of entries) {\r\n if (entry.name === 'bin' || entry.name === 'obj' || entry.name === '.vs') {\r\n continue;\r\n }\r\n const fullPath = path.join(dirPath, entry.name);\r\n if (entry.isDirectory()) {\r\n // Recursively get file names from subdirectories\r\n const subFileNames = getFileNamesRecursive(fullPath);\r\n subFileNames.forEach(f => fileNames.add(f));\r\n } else if (entry.isFile() && entry.name.endsWith('.cs')) {\r\n // Add file name without .cs extension\r\n fileNames.add(entry.name.slice(0, -3).toLowerCase());\r\n }\r\n }\r\n } catch (err) {\r\n // Ignore errors for inaccessible directories\r\n }\r\n return fileNames;\r\n}\r\n\r\nfunction findAllCsprojFiles(dir: string, excludedPaths: string[]): string[] {\r\n const results: string[] = [];\r\n const entries = fs.readdirSync(dir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dir, entry.name);\r\n if (entry.name === \".vs\" || excludedPaths.includes(fullPath)) {\r\n continue; // Skip excluded paths\r\n }\r\n\r\n if (entry.isDirectory()) {\r\n results.push(...findAllCsprojFiles(fullPath, excludedPaths));\r\n } else if (entry.isFile() && entry.name.endsWith('.csproj')) {\r\n results.push(fullPath);\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\nfunction isXapTestProject(csprojPath: string): boolean {\r\n try {\r\n const content = fs.readFileSync(csprojPath, 'utf-8');\r\n const parser = new XMLParser({ ignoreAttributes: false, ignoreDeclaration: true });\r\n const json = parser.parse(content);\r\n const project = json.Project;\r\n\r\n const propertyGroups = Array.isArray(project.PropertyGroup)\r\n ? project.PropertyGroup\r\n : [project.PropertyGroup];\r\n\r\n for (const group of propertyGroups) {\r\n if (group.XapProjectType === 'TestProject') {\r\n return true;\r\n }\r\n }\r\n } catch (err: any) {\r\n console.error(`Failed to parse ${csprojPath}: ${err.message}`);\r\n }\r\n return false;\r\n}\r\n\r\nfunction isGeneralTestProject(csprojPath: string): boolean {\r\n try {\r\n const content = fs.readFileSync(csprojPath, 'utf-8');\r\n\r\n // 1. package reference (test framework)\r\n const referencesTestFramework = /<PackageReference\\s+Include=\"(xunit|nunit|MSTest\\.TestFramework|Microsoft\\.NET\\.Test\\.Sdk)\"/i.test(content);\r\n\r\n // 2. file name *.Tests.csproj\r\n const fileNameHasTests = (/\\.Tests\\.csproj$/i.test(path.basename(csprojPath))) || (/\\.Test\\.csproj$/i.test(path.basename(csprojPath)));\r\n\r\n // 3. path contains Tests\r\n const pathHasTests = /[\\\\/](Tests?|UnitTests?|IntegrationTests?)[\\\\/]/i.test(csprojPath);\r\n\r\n // 4. Project SDK is test type (optional)\r\n const sdkIsTestSdk = /<Project\\s+Sdk=\"Microsoft\\.NET\\.Test\\.Sdk\"/i.test(content);\r\n\r\n // 组合判断\r\n return referencesTestFramework || sdkIsTestSdk || fileNameHasTests || pathHasTests;\r\n } catch (err) {\r\n console.error(`can't read csproj file: ${csprojPath}`);\r\n return false;\r\n }\r\n}\r\n\r\nfunction isFalconUnitTestProject(csprojPath: string): boolean {\r\n const xmlContent = fs.readFileSync(csprojPath, 'utf-8');\r\n\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n attributeNamePrefix: ''\r\n });\r\n const parsed = parser.parse(xmlContent);\r\n\r\n // get PackageReference node\r\n const project = parsed.Project;\r\n const itemGroups = Array.isArray(project.ItemGroup) ? project.ItemGroup : [project.ItemGroup];\r\n\r\n let isFalconUnitTestProject = false;\r\n\r\n for (const group of itemGroups) {\r\n if(!group) continue;\r\n const refs = group.PackageReference;\r\n if (!refs) continue;\r\n\r\n // PackageReference\r\n const refList = Array.isArray(refs) ? refs : [refs];\r\n\r\n for (const ref of refList) {\r\n if (ref.Include === 'Microsoft.Falcon.CodeAnalyzers') {\r\n isFalconUnitTestProject = true;\r\n console.log('Found Microsoft.Falcon.CodeAnalyzers');\r\n break;\r\n }\r\n }\r\n\r\n if (isFalconUnitTestProject) break;\r\n }\r\n\r\n // if (!isFalconUnitTestProject) {\r\n // console.log('Microsoft.Falcon.CodeAnalyzers not found');\r\n // }\r\n\r\n return isFalconUnitTestProject;\r\n}\r\n\r\nfunction isProjectNameMatchedTestProject(csprojPath: string, projectAssemblyName: string, projectName: string) {\r\n const testProjectName = path.basename(csprojPath, '.csproj').toLowerCase();\r\n const projectNameLower = projectName.toLowerCase();\r\n \r\n // Check if test project name exactly matches: projectName + suffix\r\n const suffixes = ['.tests', '.test', '.unittest', '.unittests', 'tests', 'test'];\r\n const exactMatch = suffixes.some(suffix => testProjectName === projectNameLower + suffix);\r\n \r\n if (exactMatch) {\r\n return true;\r\n }\r\n \r\n // Fallback: check assembly name with exact match\r\n const testProjectAssemblyName = getAssemblyName(csprojPath);\r\n if (testProjectAssemblyName) {\r\n const assemblyNameLower = testProjectAssemblyName.toLowerCase();\r\n const projectAssemblyNameLower = projectAssemblyName.toLowerCase();\r\n return suffixes.some(suffix => assemblyNameLower === projectAssemblyNameLower + suffix);\r\n }\r\n \r\n return false;\r\n}\r\n\r\n/**\r\n * Search for test projects in repository directories\r\n * Walks up from source file directory and collects all test projects that reference the source project\r\n * \r\n * @param csFilePath - Path to the source .cs file\r\n * @param repoRoot - Repository root directory\r\n * @param projectFilePath - Path to source project's .csproj\r\n * @param normalizedProjectPath - Normalized path to source project\r\n * @returns Array of test project paths that reference the source project\r\n */\r\nfunction searchTestProjectsInRepositories(\r\n csFilePath: string,\r\n repoRoot: string,\r\n projectFilePath: string,\r\n normalizedProjectPath: string\r\n): string[] {\r\n let currentDir = path.dirname(csFilePath);\r\n const possibleTestProjects: string[] = [];\r\n const excludedPaths: string[] = [currentDir];\r\n const repoRootParentPath = path.dirname(repoRoot);\r\n \r\n currentDir = path.dirname(currentDir);\r\n while (currentDir !== repoRootParentPath) {\r\n const csprojFiles = findAllCsprojFiles(currentDir, excludedPaths);\r\n \r\n // Filter csproj files by standard test project naming patterns\r\n const testProjectCandidates = csprojFiles.filter(csproj => {\r\n const rawName = path.basename(csproj, '.csproj');\r\n const csprojName = rawName.toLowerCase();\r\n // Standard test naming: ends with .tests, .test, .unittests, .unittest, Tests, or Test\r\n if (\r\n csprojName.endsWith('.tests') || \r\n csprojName.endsWith('.test') || \r\n csprojName.endsWith('.unittests') || \r\n csprojName.endsWith('.unittest') ||\r\n csprojName.endsWith('tests') ||\r\n csprojName.endsWith('test')\r\n ) {\r\n return true;\r\n }\r\n\r\n // Word-level match: any word ends with \"test\" or \"tests\"\r\n const words = extractWordsFromName(rawName);\r\n return words.some(w => w.endsWith('test') || w.endsWith('tests'));\r\n });\r\n \r\n for (const csproj of testProjectCandidates) {\r\n // Check if this csproj references the source project\r\n const projectReferences = getProjectReferencesFromCsproj(csproj);\r\n const referencesSourceProject = checkTestProjectReferencesSourceProject(csproj, normalizedProjectPath, projectReferences);\r\n \r\n if (!referencesSourceProject) {\r\n continue;\r\n }\r\n \r\n const projectName = path.basename(projectFilePath, '.csproj');\r\n const projectAssemblyName = getAssemblyName(projectFilePath);\r\n if (isProjectNameMatchedTestProject(csproj, projectAssemblyName, projectName)) {\r\n return [csproj];\r\n }\r\n \r\n // Collect all test projects that reference the source project\r\n possibleTestProjects.push(csproj);\r\n }\r\n \r\n excludedPaths.push(currentDir);\r\n currentDir = path.dirname(currentDir);\r\n }\r\n \r\n return possibleTestProjects;\r\n}\r\n\r\n/**\r\n * Filter test projects by subfolder matching\r\n * Returns projects sorted by match count, or proceeds to file name matching if all zero\r\n * \r\n * @param possibleTestProjects - List of test project paths\r\n * @param projectFilePath - Path to source project's .csproj\r\n * @returns Filtered projects with scores, or null if needs file name matching\r\n */\r\nfunction filterBySubfolderMatching(\r\n possibleTestProjects: string[],\r\n projectFilePath: string\r\n): Array<{ csproj: string, matchCount: number }> | null {\r\n const sourceProjectDir = path.dirname(projectFilePath);\r\n const sourceSubfolders = getSubfolderNamesRecursive(sourceProjectDir);\r\n\r\n const projectsWithScores = possibleTestProjects.map(csproj => {\r\n const testProjectDir = path.dirname(csproj);\r\n const testSubfolders = getSubfolderNamesRecursive(testProjectDir);\r\n \r\n let matchCount = 0;\r\n testSubfolders.forEach(folderName => {\r\n if (sourceSubfolders.has(folderName)) {\r\n matchCount++;\r\n }\r\n });\r\n \r\n return { csproj, matchCount };\r\n });\r\n\r\n projectsWithScores.sort((a, b) => b.matchCount - a.matchCount);\r\n\r\n const allZero = projectsWithScores.every(p => p.matchCount === 0);\r\n return allZero ? null : projectsWithScores;\r\n}\r\n\r\n/**\r\n * Filter test projects by file name matching with test suffixes\r\n * Returns filtered projects if any matches found\r\n * \r\n * @param projectsWithScores - Projects with scores\r\n * @param projectFilePath - Path to source project's .csproj\r\n * @returns Filtered projects by file name, or null if no matches\r\n */\r\nfunction filterByFileNameMatching(\r\n projectsWithScores: Array<{ csproj: string, matchCount: number }>,\r\n projectFilePath: string\r\n): Array<{ csproj: string, matchCount: number }> | null {\r\n const sourceProjectDir = path.dirname(projectFilePath);\r\n const sourceFileNames = getFileNamesRecursive(sourceProjectDir);\r\n const testSuffixes = ['.tests', '.test', '.unittests', '.unittest', 'tests', 'test'];\r\n\r\n const filteredProjectsWithScores = projectsWithScores.filter(projectScore => {\r\n const testProjectDir = path.dirname(projectScore.csproj);\r\n const testFileNames = getFileNamesRecursive(testProjectDir);\r\n\r\n for (const sourceFileName of sourceFileNames) {\r\n for (const suffix of testSuffixes) {\r\n const expectedTestFileName = (sourceFileName + suffix).toLowerCase();\r\n if (testFileNames.has(expectedTestFileName)) {\r\n return true;\r\n }\r\n }\r\n }\r\n return false;\r\n });\r\n\r\n return filteredProjectsWithScores.length > 0 ? filteredProjectsWithScores : null;\r\n}\r\n\r\n/**\r\n * Filter test projects by word-level matching\r\n * Returns top 2 projects with highest word match count\r\n * \r\n * @param projectsWithScores - Projects with scores\r\n * @param projectName - Name of source project\r\n * @returns Top 2 projects by word match count, or empty array if no matches\r\n */\r\nfunction filterByWordLevelMatching(\r\n projectsWithScores: Array<{ csproj: string, matchCount: number }>,\r\n projectName: string\r\n): string[] {\r\n const projectsWithWordScores = projectsWithScores.map(projectScore => {\r\n const testProjectName = path.basename(projectScore.csproj, '.csproj');\r\n const wordMatchCount = calculateWordMatchCount(projectName, testProjectName);\r\n return { ...projectScore, wordMatchCount };\r\n });\r\n\r\n const projectsWithMatches = projectsWithWordScores.filter(p => p.wordMatchCount > 0);\r\n\r\n if (projectsWithMatches.length === 0) {\r\n return [];\r\n }\r\n\r\n projectsWithMatches.sort((a, b) => b.wordMatchCount - a.wordMatchCount);\r\n\r\n const countToReturn = Math.min(2, projectsWithMatches.length);\r\n return projectsWithMatches.slice(0, countToReturn).map(p => p.csproj);\r\n}\r\n\r\n/**\r\n * Select top projects by score percentage or minimum count\r\n * \r\n * @param projectsWithScores - Projects with scores\r\n * @param minCount - Minimum projects to return (default 2)\r\n * @returns Array of selected project paths\r\n */\r\nfunction selectTopProjectsByScore(\r\n projectsWithScores: Array<{ csproj: string, [key: string]: any }>,\r\n minCount: number = 2\r\n): string[] {\r\n const countToReturn = Math.max(minCount, Math.ceil(projectsWithScores.length * 0.3));\r\n return projectsWithScores.slice(0, countToReturn).map(p => p.csproj);\r\n}\r\n\r\n/**\r\n * Find possible test projects for a C# source file\r\n * Uses multi-level matching: folder names -> file names -> word-level matching\r\n * \r\n * @param csFilePath - Path to the source .cs file\r\n * @returns Array of possible test project paths\r\n */\r\nfunction findPossibleTestProjectsFromCsFile(csFilePath: string): string[] {\r\n const repoRoot = getCodeRepoRoot(csFilePath);\r\n const projectFilePath = getSourceFileCsprojFilePath(csFilePath);\r\n const projectName = path.basename(projectFilePath, '.csproj');\r\n const normalizedProjectPath = path.normalize(projectFilePath);\r\n\r\n // Search for test projects in repository\r\n const possibleTestProjects = searchTestProjectsInRepositories(\r\n csFilePath,\r\n repoRoot,\r\n projectFilePath,\r\n normalizedProjectPath\r\n );\r\n\r\n if (possibleTestProjects.length === 0) {\r\n return [];\r\n }\r\n\r\n if (possibleTestProjects.length === 1) {\r\n return possibleTestProjects;\r\n }\r\n\r\n // Try subfolder-level matching\r\n const subfolderMatchResults = filterBySubfolderMatching(possibleTestProjects, projectFilePath);\r\n if (subfolderMatchResults !== null) {\r\n return selectTopProjectsByScore(subfolderMatchResults);\r\n }\r\n\r\n // If subfolder matching is all zero, try file name matching\r\n const projectsWithScores = possibleTestProjects.map(csproj => ({ csproj, matchCount: 0 }));\r\n const fileNameMatchResults = filterByFileNameMatching(projectsWithScores, projectFilePath);\r\n if (fileNameMatchResults !== null) {\r\n return selectTopProjectsByScore(fileNameMatchResults);\r\n }\r\n\r\n // If file name matching fails, try word-level matching\r\n const wordLevelResults = filterByWordLevelMatching(projectsWithScores, projectName);\r\n return wordLevelResults.length > 0 ? wordLevelResults : [];\r\n}\r\n\r\nfunction findPossibleTestFiles(testProjectDir: string, className: string): string[] {\r\n const results: string[] = [];\r\n const stack: string[] = [testProjectDir];\r\n\r\n while (stack.length > 0) {\r\n const currentDir = stack.pop()!;\r\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n if (entry.name === \"bin\" || entry.name === \"obj\") {\r\n continue;\r\n }\r\n const fullPath = path.join(currentDir, entry.name);\r\n if (entry.isDirectory()) {\r\n stack.push(fullPath);\r\n } else if (entry.isFile() && entry.name.endsWith('.cs') && entry.name.includes(className)) {\r\n results.push(fullPath);\r\n }\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\nfunction fileContainsTestAttributes(filePath: string): boolean {\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n return TEST_ATTR_REGEX.test(content);\r\n}\r\n\r\n/**\r\n * Check if a test project references a source project.\r\n * \r\n * @param testCsprojPath - Path to the test project's csproj file\r\n * @param sourceCsprojPath - Path to the source project's csproj file\r\n * @param projectReferences - Project references from the test csproj\r\n * @returns True if test project references the source project, false otherwise\r\n */\r\nfunction checkTestProjectReferencesSourceProject(\r\n testCsprojPath: string,\r\n sourceCsprojPath: string,\r\n projectReferences: string[]\r\n): boolean {\r\n const normalizedSourceCsprojPath = path.normalize(sourceCsprojPath).toLowerCase();\r\n return projectReferences.some(ref => {\r\n const resolvedRefPath = path.normalize(path.resolve(path.dirname(testCsprojPath), ref)).toLowerCase();\r\n return resolvedRefPath === normalizedSourceCsprojPath;\r\n });\r\n}\r\n\r\nfunction getProjectReferencesFromCsproj(csprojPath: string): string[] {\r\n const projectReferences: string[] = [];\r\n try {\r\n const xmlContent = fs.readFileSync(csprojPath, 'utf-8');\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n attributeNamePrefix: ''\r\n });\r\n const projectData = parser.parse(xmlContent);\r\n \r\n const project = projectData.Project;\r\n const itemGroups = Array.isArray(project.ItemGroup) ? project.ItemGroup : [project.ItemGroup];\r\n \r\n for (const group of itemGroups) {\r\n if (!group) continue;\r\n const projectRefs = group.ProjectReference;\r\n if (!projectRefs) continue;\r\n\r\n const refList = Array.isArray(projectRefs) ? projectRefs : [projectRefs];\r\n for (const ref of refList) {\r\n if (ref.Include) {\r\n projectReferences.push(ref.Include);\r\n }\r\n }\r\n }\r\n } catch (err) {\r\n console.error(`Failed to parse csproj: ${csprojPath}`, err);\r\n }\r\n return projectReferences;\r\n}\r\n\r\n/**\r\n * Calculate matching score between test file path and source file path based on directory structure.\r\n * Returns two scores: continuous matching folders from end, and total matching folders.\r\n * \r\n * @param testRelativePath - Relative path of test file from test project root\r\n * @param sourceRelativePath - Relative path of source file from source project root\r\n * @returns Object with 'continuous' (right-to-left consecutive matches) and 'total' (all matches)\r\n */\r\nfunction calculateMatchingScore(testRelativePath: string, sourceRelativePath: string): { continuous: number, total: number } {\r\n // Extract directory paths (remove file names)\r\n const testDir = path.dirname(testRelativePath);\r\n const sourceDir = path.dirname(sourceRelativePath);\r\n \r\n // If both files are in root directory (no subdirectories), give highest priority\r\n if ((testDir === '.' || testDir === '') && (sourceDir === '.' || sourceDir === '')) {\r\n return { continuous: 1000, total: 1000 };\r\n }\r\n \r\n // Split paths into folder arrays (case-insensitive)\r\n const testFolders = testDir === '.' || testDir === '' ? [] : testDir.split(path.sep).map(f => f.toLowerCase());\r\n const sourceFolders = sourceDir === '.' || sourceDir === '' ? [] : sourceDir.split(path.sep).map(f => f.toLowerCase());\r\n \r\n // 1. Calculate continuous matching folders from end (right to left)\r\n let continuous = 0;\r\n const minLength = Math.min(testFolders.length, sourceFolders.length);\r\n \r\n for (let i = 1; i <= minLength; i++) {\r\n if (testFolders[testFolders.length - i] === sourceFolders[sourceFolders.length - i]) {\r\n continuous++;\r\n } else {\r\n // Stop at first mismatch\r\n break;\r\n }\r\n }\r\n \r\n // 2. Calculate total matching folders (not required to be continuous)\r\n const sourceSet = new Set(sourceFolders);\r\n const total = testFolders.filter(f => sourceSet.has(f)).length;\r\n \r\n return { continuous, total };\r\n}\r\n\r\nfunction isTestFileForSourceFile(testFilePath: string, sourceCodePath: string): boolean {\r\n const sourceFileName = path.basename(sourceCodePath, '.cs');\r\n const testFileName = path.basename(testFilePath, '.cs');\r\n \r\n // First check: test file name should match common test patterns\r\n // Patterns: SourceFile + (Unit)? + (.)? + (Test|Tests)\r\n // Examples: SourceFileTests, SourceFileTest, SourceFile.Tests, SourceFile.Test, SourceFileUnitTests, SourceFileUnit.Tests\r\n const testPattern = getTestFileNamePattern(sourceFileName);\r\n const matchesPattern = testPattern.test(testFileName);\r\n if (!matchesPattern) {\r\n return false;\r\n }\r\n \r\n try {\r\n // Read both files content\r\n const testContent = fs.readFileSync(testFilePath, 'utf-8');\r\n const sourceContent = fs.readFileSync(sourceCodePath, 'utf-8');\r\n \r\n // First check: Extract namespace from source file and verify test file references it\r\n const sourceNamespaceMatch = sourceContent.match(/namespace\\s+([\\w.]+)/);\r\n if (!sourceNamespaceMatch || !sourceNamespaceMatch[1]) {\r\n // No namespace found in source file, fall back to name-based matching\r\n return true;\r\n }\r\n \r\n const sourceNamespace = sourceNamespaceMatch[1];\r\n // Check if test file has using statement for source namespace\r\n const usingRegex = new RegExp(`using\\\\s+${sourceNamespace.replace(/\\./g, '\\\\.')};`);\r\n if (!usingRegex.test(testContent)) {\r\n // Test file doesn't reference source namespace\r\n return false;\r\n }\r\n \r\n // Second check: Extract the main type name from source file (public or internal)\r\n // Supports: class, interface, struct, record (but not nested private/protected types)\r\n // Priority: public > internal; match first public, fallback to first internal\r\n // Handles modifiers: sealed, abstract, static, partial\r\n const publicTypeMatch = sourceContent.match(new RegExp(`\\\\bpublic\\\\s+${MODIFIER_PATTERN}(?:class|interface|struct|record)\\\\s+(\\\\w+)`));\r\n const internalTypeMatch = sourceContent.match(new RegExp(`\\\\binternal\\\\s+${MODIFIER_PATTERN}(?:class|interface|struct|record)\\\\s+(\\\\w+)`));\r\n \r\n const sourceTypeMatch = publicTypeMatch || internalTypeMatch;\r\n if (!sourceTypeMatch || !sourceTypeMatch[1]) {\r\n // No public or internal type found - this file might be a utility/helper file\r\n // without testable classes, so it shouldn't have a test file\r\n return false;\r\n }\r\n \r\n const sourceTypeName = sourceTypeMatch[1];\r\n // Check if test file references the source type name or its interface\r\n // If source is an interface (direct interface definition), only match itself\r\n // If source is a class/struct/record, also match interface (ITypeName)\r\n const isSourceInterface = new RegExp(`\\\\b(?:public|internal)\\\\s+${MODIFIER_PATTERN}interface\\\\s+(?:\\\\w+)`).test(sourceContent);\r\n let sourceCodeTypeReferenceRegex: RegExp;\r\n if (isSourceInterface) {\r\n // Source is an interface, match only itself\r\n sourceCodeTypeReferenceRegex = new RegExp(`\\\\b${sourceTypeName}\\\\b`, 'g');\r\n } else {\r\n // Source is a class/struct/record, match both TypeName and ITypeName\r\n sourceCodeTypeReferenceRegex = new RegExp(`\\\\b(I)?${sourceTypeName}\\\\b`, 'g');\r\n }\r\n \r\n if (sourceCodeTypeReferenceRegex.test(testContent)) {\r\n return true;\r\n }\r\n \r\n // Namespace matches but class name not found in test file\r\n return false;\r\n \r\n } catch (err) {\r\n console.error(`Failed to read file content for matching: ${err}`);\r\n // Strict mode: if we can't verify the content, treat as non-matching\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Find an existing test file from sibling source files in the same or parent directories.\r\n * This helps determine the best location for a new test file by looking at where\r\n * existing test files are located for nearby source files.\r\n * \r\n * @param sourceCodePath - Path to the source file\r\n * @param testCsprojPath - Path to the test project's csproj file\r\n * @param sourceCsprojPath - Path to the source project's csproj file\r\n * @returns Object with siblingTestFilePath and sourceRelativeDepth if found, otherwise null\r\n */\r\nfunction findSiblingTestFile(\r\n sourceCodePath: string,\r\n testCsprojPath: string,\r\n sourceCsprojPath: string\r\n): { siblingTestFilePath: string, sourceRelativeDepth: number } | null {\r\n const sourceProjectDir = path.dirname(sourceCsprojPath);\r\n let currentDir = path.dirname(sourceCodePath);\r\n let depth = 0;\r\n \r\n // Search from current directory up to source project root\r\n while (currentDir.toLowerCase().startsWith(sourceProjectDir.toLowerCase()) && currentDir.length >= sourceProjectDir.length) {\r\n try {\r\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\r\n const csFiles = entries\r\n .filter(e => e.isFile() && e.name.endsWith('.cs') && path.join(currentDir, e.name) !== sourceCodePath)\r\n .map(e => path.join(currentDir, e.name));\r\n \r\n for (const csFile of csFiles) {\r\n // Try to find test file for this sibling source file\r\n const result = findMatchingTestFileInProject(testCsprojPath, csFile, sourceCsprojPath);\r\n if (result.testFilePath) {\r\n return { siblingTestFilePath: result.testFilePath, sourceRelativeDepth: depth };\r\n }\r\n }\r\n } catch (err) {\r\n // Ignore errors for inaccessible directories\r\n }\r\n \r\n // Move to parent directory\r\n const parentDir = path.dirname(currentDir);\r\n if (parentDir === currentDir) {\r\n break;\r\n }\r\n currentDir = parentDir;\r\n depth++;\r\n }\r\n \r\n return null;\r\n}\r\n\r\n/**\r\n * Determine the best test file path for a source file.\r\n * This function only calculates the path, it does not create any directories.\r\n * \r\n * @param sourceCodePath - Path to the source file\r\n * @param testCsprojPath - Path to the test project's csproj file (optional)\r\n * @returns Object with testFilePath, testProjectPath, and testFileExist flag\r\n */\r\nexport function determineTestFilePath(sourceCodePath: string, testCsprojPath?: string): { testFilePath: string | null, testProjectPath: string | null, testFileExist?: boolean } {\r\n let testProjectPath = testCsprojPath;\r\n if (!testProjectPath) {\r\n console.error(`No test project found for ${sourceCodePath}`);\r\n return { testFilePath: null, testProjectPath: null };\r\n }\r\n \r\n const sourceFileName = path.basename(sourceCodePath, '.cs');\r\n const testFileName = `${sourceFileName}Tests.cs`;\r\n const sourceFileProjectPath = getSourceFileProjectDir(sourceCodePath);\r\n const sourceCsprojPath = getSourceFileCsprojFilePath(sourceCodePath);\r\n \r\n // Try to find sibling test file to determine the best location\r\n const siblingResult = findSiblingTestFile(sourceCodePath, testProjectPath, sourceCsprojPath);\r\n \r\n let testFilePath: string;\r\n if (siblingResult) {\r\n // Found sibling test file, calculate new test file path based on it\r\n const siblingTestDir = path.dirname(siblingResult.siblingTestFilePath);\r\n const sourceFileDir = path.dirname(sourceCodePath);\r\n \r\n if (siblingResult.sourceRelativeDepth === 0) {\r\n // Sibling is in the same directory, put test file in the same test directory\r\n testFilePath = path.join(siblingTestDir, testFileName);\r\n } else {\r\n // Sibling is in a parent directory, calculate the relative path from sibling source to current source\r\n let relativeParts: string[] = [];\r\n let tempDir = sourceFileDir;\r\n \r\n for (let i = 0; i < siblingResult.sourceRelativeDepth; i++) {\r\n relativeParts.unshift(path.basename(tempDir));\r\n tempDir = path.dirname(tempDir);\r\n }\r\n \r\n // The relative path from the found sibling source dir to our source file\r\n const relativePath = relativeParts.join(path.sep);\r\n testFilePath = path.join(siblingTestDir, relativePath, testFileName);\r\n }\r\n } else {\r\n // No sibling test file found, use original logic\r\n const sourceFileDir = path.dirname(sourceCodePath);\r\n const testFileRelativePath = sourceFileDir.replace(sourceFileProjectPath, \"\");\r\n const testProjecDir = path.dirname(testProjectPath);\r\n testFilePath = path.join(testProjecDir, testFileRelativePath, testFileName);\r\n }\r\n \r\n // Check if the test file already exists\r\n const testFileExist = fs.existsSync(testFilePath);\r\n if (testFileExist) {\r\n console.log(`Test file already exists at ${testFilePath}`);\r\n }\r\n \r\n return { testFilePath, testProjectPath, testFileExist };\r\n}\r\n\r\n/**\r\n * Search for matching test file in a specific test project.\r\n * Uses directory structure matching and file content analysis to find the best match.\r\n * \r\n * @param testCsprojPath - Path to the test project's csproj file\r\n * @param sourceCodePath - Path to the source file\r\n * @param sourceCsprojPath - Path to the source project's csproj file\r\n * @returns Object with testFilePath and testProjectPath if found, otherwise both null\r\n */\r\nfunction findMatchingTestFileInProject(\r\n testCsprojPath: string,\r\n sourceCodePath: string,\r\n sourceCsprojPath: string\r\n): { testFilePath: string | null, testProjectPath: string | null } {\r\n const testProjectDir = path.dirname(testCsprojPath);\r\n \r\n // Get source file's csproj directory\r\n const sourceCsprojDir = path.dirname(sourceCsprojPath);\r\n // Calculate relative path of source file from its csproj directory\r\n const sourceRelativePath = path.relative(sourceCsprojDir, sourceCodePath);\r\n \r\n // Get source file name for filtering\r\n const sourceFileName = path.basename(sourceCodePath, '.cs');\r\n \r\n // Find .cs files containing source file name (optimization to reduce file count)\r\n const allTestFiles = findPossibleTestFiles(testProjectDir, sourceFileName);\r\n \r\n // Filter by file name pattern first to reduce unnecessary file reads\r\n const testPattern = getTestFileNamePattern(sourceFileName);\r\n \r\n // Create list of candidates with their matching scores\r\n const candidatesWithScores = allTestFiles\r\n .filter(file => {\r\n const testFileName = path.basename(file, '.cs');\r\n return testPattern.test(testFileName);\r\n })\r\n .map(file => {\r\n const testRelativePath = path.relative(testProjectDir, file);\r\n const score = calculateMatchingScore(testRelativePath, sourceRelativePath);\r\n return {\r\n filePath: file,\r\n relativePath: testRelativePath,\r\n score: score\r\n };\r\n })\r\n // Sort by continuous match first, then by total match\r\n .sort((a, b) => {\r\n if (b.score.continuous !== a.score.continuous) {\r\n return b.score.continuous - a.score.continuous;\r\n }\r\n return b.score.total - a.score.total;\r\n });\r\n \r\n for (const candidate of candidatesWithScores) {\r\n if (isTestFileForSourceFile(candidate.filePath, sourceCodePath)) {\r\n return { testFilePath: candidate.filePath, testProjectPath: testCsprojPath };\r\n }\r\n }\r\n \r\n return { testFilePath: null, testProjectPath: null };\r\n}\r\n\r\nfunction getTestFileFromChangedFiles(sourceCodePath: string, changedTestFiles?: string[]): { testFilePath: string | null, testProjectPath: string | null } {\r\n if (!changedTestFiles || changedTestFiles.length === 0) {\r\n return { testFilePath: null, testProjectPath: null };\r\n }\r\n\r\n // Get the csproj of the source code\r\n const sourceCsprojPath = getSourceFileCsprojFilePath(sourceCodePath);\r\n if (!sourceCsprojPath) {\r\n return { testFilePath: null, testProjectPath: null };\r\n }\r\n\r\n // Cache to store project references from csproj to avoid re-parsing\r\n const csprojCache = new Map<string, string[]>();\r\n // Store test projects that reference the source project\r\n const referencingTestProjects = new Set<string>();\r\n\r\n for (const testFilePath of changedTestFiles) {\r\n if (!fs.existsSync(testFilePath)) {\r\n continue;\r\n }\r\n\r\n // Get the csproj of the test file\r\n const testCsprojPath = getSourceFileCsprojFilePath(testFilePath);\r\n if (!testCsprojPath) {\r\n continue;\r\n }\r\n\r\n // Check cache first\r\n let projectReferences = csprojCache.get(testCsprojPath);\r\n if (!projectReferences) {\r\n projectReferences = getProjectReferencesFromCsproj(testCsprojPath);\r\n csprojCache.set(testCsprojPath, projectReferences);\r\n }\r\n\r\n // Check if test project references the source project\r\n const normalizedSourceCsprojPath = path.normalize(sourceCsprojPath);\r\n if (checkTestProjectReferencesSourceProject(testCsprojPath, normalizedSourceCsprojPath, projectReferences)) {\r\n referencingTestProjects.add(testCsprojPath);\r\n // Check if this test file is for the source file\r\n if (isTestFileForSourceFile(testFilePath, sourceCodePath)) {\r\n return { testFilePath, testProjectPath: testCsprojPath };\r\n }\r\n }\r\n }\r\n\r\n // Fallback: search all test files in projects that reference the source project\r\n for (const testCsprojPath of referencingTestProjects) {\r\n const result = findMatchingTestFileInProject(testCsprojPath, sourceCodePath, sourceCsprojPath);\r\n if (result.testFilePath) {\r\n return result;\r\n }\r\n }\r\n\r\n return { testFilePath: null, testProjectPath: null };\r\n}\r\n\r\nexport function getOrCreatTestFile(sourceCodePath: string, testFilePath: string, changedTestFiles?: string[]) {\r\n let finalTestFilePath = testFilePath;\r\n let finalTestProjectPath;\r\n let testFileExist = !!testFilePath && fs.existsSync(testFilePath);\r\n \r\n // If test file exists, get its project path and return directly\r\n if (testFileExist) {\r\n finalTestProjectPath = getSourceFileCsprojFilePath(testFilePath);\r\n return { testFilePath: finalTestFilePath, testProjectPath: finalTestProjectPath, testFileExist };\r\n }\r\n \r\n // if outputPath param is not provided, try to find an existing test file\r\n // if no existing test file found, create a new one in test project\r\n if (!testFilePath || testFilePath.trim() === '') {\r\n console.log(' Output path is missing. outputPath:', testFilePath, ', start looking for existing test project');\r\n\r\n // Try to find test file from changed files first\r\n let resultFromChangedFiles = getTestFileFromChangedFiles(sourceCodePath, changedTestFiles);\r\n if (resultFromChangedFiles.testFilePath) {\r\n return { testFilePath: resultFromChangedFiles.testFilePath, testProjectPath: resultFromChangedFiles.testProjectPath, testFileExist: true };\r\n }\r\n\r\n // Fallback: try to find existing test file\r\n const possibleCSProjPaths = findPossibleTestProjectsFromCsFile(sourceCodePath);\r\n if (!possibleCSProjPaths || possibleCSProjPaths.length === 0) {\r\n console.error(` No test project found for source code: ${sourceCodePath}`);\r\n return { testFilePath: null, testProjectPath: null, testFileExist: false };\r\n }\r\n\r\n // Get the source csproj path for matching\r\n const sourceCsprojPath = getSourceFileCsprojFilePath(sourceCodePath);\r\n if (!sourceCsprojPath) {\r\n console.error(` Cannot find source csproj for: ${sourceCodePath}`);\r\n return { testFilePath: null, testProjectPath: null, testFileExist: false };\r\n }\r\n\r\n // Try to find existing test file in each possible test project\r\n for (const testCsprojPath of possibleCSProjPaths) {\r\n const result = findMatchingTestFileInProject(testCsprojPath, sourceCodePath, sourceCsprojPath);\r\n if (result.testFilePath) {\r\n testFileExist = true;\r\n finalTestFilePath = result.testFilePath;\r\n finalTestProjectPath = result.testProjectPath;\r\n return { testFilePath: finalTestFilePath, testProjectPath: finalTestProjectPath, testFileExist };\r\n }\r\n }\r\n\r\n // No existing test file found, determine test file path (may find existing)\r\n const result = determineTestFilePath(sourceCodePath, possibleCSProjPaths[0]);\r\n if (!result.testFilePath || !result.testProjectPath) {\r\n console.error(`Failed to determine test file path for ${sourceCodePath}`);\r\n return { testFilePath: null, testProjectPath: null, testFileExist: false };\r\n }\r\n finalTestFilePath = result.testFilePath;\r\n finalTestProjectPath = result.testProjectPath;\r\n testFileExist = result.testFileExist ?? false;\r\n \r\n // Create directory if test file doesn't exist\r\n if (!testFileExist) {\r\n getOrCreateDir(path.dirname(finalTestFilePath));\r\n }\r\n }\r\n\r\n return { testFilePath: finalTestFilePath, testProjectPath: finalTestProjectPath, testFileExist };\r\n\r\n}\r\n\r\n// // Verify test file paths for all projects\r\n// function verifyTestFilePaths(): void {\r\n// const baseFolder = 'Q:\\\\src\\\\Microsoft.News.OneService';\r\n// const outputFile = 'q:\\\\verifyTestFilePaths_results.txt';\r\n// const results: string[] = [];\r\n\r\n// try {\r\n// // Recursively find all non test csproj files \r\n// const getAllCsprojFiles = (dir: string): string[] => {\r\n// const csprojFiles: string[] = [];\r\n// try {\r\n// const entries = fs.readdirSync(dir, { withFileTypes: true });\r\n// for (const entry of entries) {\r\n// const fullPath = path.join(dir, entry.name);\r\n// if (entry.isDirectory() && entry.name !== 'bin' && entry.name !== 'obj' && entry.name !== '.vs') {\r\n// csprojFiles.push(...getAllCsprojFiles(fullPath));\r\n// } else if (entry.isFile() && entry.name.endsWith('.csproj')) {\r\n// // Filter by test project naming patterns\r\n// const rawName = path.basename(fullPath, '.csproj');\r\n// const words = rawName\r\n// .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\r\n// .split(/[^a-zA-Z0-9]+/)\r\n// .filter(Boolean)\r\n// .map(w => w.toLowerCase());\r\n \r\n// if (words.every(w => !w.endsWith('test') && !w.endsWith('tests'))) {\r\n// csprojFiles.push(fullPath);\r\n// }\r\n// }\r\n// }\r\n// } catch (err) {\r\n// // Skip inaccessible directories\r\n// }\r\n// return csprojFiles;\r\n// };\r\n\r\n// // Get first .cs file in a directory (recursive search)\r\n// const getFirstCsFile = (dir: string): string | null => {\r\n// try {\r\n// const entries = fs.readdirSync(dir, { withFileTypes: true });\r\n// // First pass: look for .cs files in current directory\r\n// for (const entry of entries) {\r\n// if (entry.isFile() && entry.name.endsWith('.cs')) {\r\n// return path.join(dir, entry.name);\r\n// }\r\n// }\r\n// // Second pass: recurse into subdirectories\r\n// for (const entry of entries) {\r\n// if (entry.isDirectory() && entry.name !== 'bin' && entry.name !== 'obj' && entry.name !== '.vs') {\r\n// const fullPath = path.join(dir, entry.name);\r\n// const result = getFirstCsFile(fullPath);\r\n// if (result) {\r\n// return result;\r\n// }\r\n// }\r\n// }\r\n// } catch (err) {\r\n// // Skip if directory can't be read\r\n// }\r\n// return null;\r\n// };\r\n\r\n// // Find all csproj files\r\n// const csprojFiles = getAllCsprojFiles(baseFolder);\r\n\r\n// // Process each csproj\r\n// for (const csprojPath of csprojFiles) {\r\n// const csprojDir = path.dirname(csprojPath);\r\n// const csFile = getFirstCsFile(csprojDir);\r\n\r\n// if (csFile) {\r\n// const result = getOrCreatTestFile(csFile, undefined);\r\n// const testFilePath = result.testFilePath || 'NOT_FOUND';\r\n// const testProjectPath = result.testProjectPath || 'NOT_FOUND';\r\n// results.push(`${csprojPath}\\t${csFile}\\t${testFilePath}\\t${testProjectPath}\\t${result.testFileExist}`);\r\n// console.log(`Processed: ${csprojPath}`);\r\n// }\r\n// }\r\n\r\n// // Write results to file\r\n// fs.writeFileSync(outputFile, results.join('\\n'), 'utf-8');\r\n// console.log(`Results written to ${outputFile}`);\r\n// } catch (err) {\r\n// console.error(`Error during verification: ${err}`);\r\n// }\r\n// }\r\n\r\n// // Uncomment to run verification\r\n// verifyTestFilePaths();\r\n\r\n// getOrCreatTestFile(\"Q:\\\\src\\\\Microsoft.News.OneService\\\\Libraries\\\\Tests\\\\MockStrategies\\\\MockDataException.cs\", undefined);\r\n\r\n\r\n// Example usage\r\n// const csFilePath = \"D:\\\\code\\\\CS.Service.Fundamental\\\\SharedSegments\\\\SharedSegments\\\\SharedSegments.Plugins\\\\Workflows\\\\LocationDetection\\\\AudienceResponseParser.cs\";\r\n// const csFilePath = \"D:\\\\code\\\\msnews-experiences\\\\experiences\\\\weather-right-rail\\\\src\\\\WeatherRightRail.connector.ts\";\r\n// const testProjectPath = \"D:\\\\code\\\\CS.Service.Fundamental\\\\SharedSegments\\\\SharedSegments\\\\SharedSegments.Tests\\\\SharedSegments.Tests.csproj\";\r\n// if (!csFilePath) {\r\n// console.error('Usage: ts-node findTestFile.ts path/to/your/file.cs');\r\n// process.exit(1);\r\n// }\r\n\r\n// const start = Date.now();\r\n// const testFilePath = getExistingTestFile(csFilePath);\r\n// console.log(`Test file for ${csFilePath}:`, testFilePath ?? 'No test file found');\r\n// console.log(`Search completed in ${(Date.now() - start) / 1000} seconds`);\r\n// createXapTestFile(csFilePath);\r\n\r\n// const repoDir = getCodeRepoRoot(\"D:\\\\code\\\\CS.Service.Fundamental\\\\SharedSegments\\\\SharedSegments\\\\SharedSegments.Plugins\\\\Workflows\\\\LocationDetection\\\\AudienceResponseParser.cs\");\r\n// console.log(`Code repository root directory: ${repoDir}`);\r\n\r\n// const result = getExistingTestFile(\"D:\\\\code\\\\CS.Service.Fundamental\\\\SharedSegments\\\\SharedSegments\\\\SharedSegments.Plugins\\\\Workflows\\\\Eplant\\\\EplantConfigManager.cs\");\r\n// console.log(`Test file path: ${result.testFilePath}`);\r\n// console.log(`Test project path: ${result.testProjectPath}`);\r\n\r\n\r\n// falcon test project\r\n// const isFlaconUt = isFalconUnitTestProject(\"D:\\\\code\\\\WeatherNotification\\\\services\\\\WeatherUserInterest\\\\tests\\\\UnitTests\\\\Microsoft.Falcon.WeatherUserInterest.UnitTests.csproj\");\r\n// console.log(`Is Falcon Unit Test Project: ${isFlaconUt}`);\r\n// const testProject = findTestProjectFromCsFile(\"D:\\\\code\\\\WeatherNotification\\\\services\\\\WeatherUserInterest\\\\src\\\\Service\\\\Microsoft.Falcon.WeatherUserInterest.csproj\");\r\n// console.log(`Test project path: ${testProject}`);\r\n// const testFilePath = getOrCreatTestFile(\"D:\\\\code\\\\WeatherNotification\\\\services\\\\WeatherUserInterest\\\\src\\\\Service\\\\Components\\\\IUserInterestTable.cs\", undefined, false);\r\n// console.log(`Test file path: ${testFilePath.testFilePath}`);\r\n\r\n// ads projects\r\n// const testProjectPath = findTestProjectFromCsFile(\"D:\\\\code\\\\UCMDynamics\\\\private\\\\DynamicCode\\\\Plugin\\\\UCMDynamics.AppointmentPlugin\\\\AppointmentOperation.cs\");\r\n// console.log(`Test project path: ${testProjectPath}`);\r\n// const isValid = isGeneralTestProject(\"D:\\\\code\\\\UCMDynamics\\\\private\\\\DynamicCode\\\\Plugin\\\\UcmDynamics.AppointmentPlugin\\\\UcmDynamics.AppointmentPlugin.csproj\");\r\n// // const isValid = isGeneralTestProject(\"D:\\\\code\\\\UCMDynamics\\\\private\\\\DynamicCode\\\\Plugin\\\\UcmDynamics.AppointmentPlugin.Tests\\\\UcmDynamics.AppointmentPlugin.Tests.csproj\");\r\n// console.log(`Is General Test Project: ${isValid}`);\r\n\r\n// const testProjectPath = findTestProjectFromCsFile(\"D:\\\\code\\\\AIUnitTestExample\\\\src\\\\ToListinator.Analyzers\\\\ToListCountAnalyzer.cs\");\r\n// console.log(`Test project path: ${testProjectPath}`);"]}
|
|
1
|
+
{"version":3,"file":"getTestFile.js","sourceRoot":"","sources":["../../src/utils/getTestFile.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\r\nimport * as path from 'path';\r\n\r\nimport { getAssemblyName, getCodeRepoRoot, getSourceFileCsprojFilePath, getSourceFileProjectDir } from './getCodeStructurePath';\r\nimport { getOrCreateDir } from './getOrCreateDir';\r\n\r\nimport { XMLParser } from 'fast-xml-parser';\r\n\r\nconst TEST_NAME_REGEX = /(Test|Tests)/i;\r\nconst TEST_ATTR_REGEX = /\\[(Fact|Theory|TestClass|TestMethod|Test)\\]/;\r\n\r\n/**\r\n * Check if a file path is a test file based on common naming conventions.\r\n * Checks if the file name (without .cs extension) ends with test, tests, unittest, or unittests.\r\n */\r\nexport function isTestFile(filepath: string): boolean {\r\n const fileName = path.basename(filepath).toLowerCase();\r\n const fileNameWithoutExt = fileName.replace(/\\.cs$/, '');\r\n \r\n return fileNameWithoutExt.endsWith('test') || \r\n fileNameWithoutExt.endsWith('tests') ||\r\n fileNameWithoutExt.endsWith('unittest') ||\r\n fileNameWithoutExt.endsWith('unittests');\r\n}\r\n\r\n// Modifier pattern for C# type declarations (sealed, abstract, static, partial)\r\nconst MODIFIER_PATTERN = `(?:sealed|abstract|static|partial)?\\\\s*`;\r\n\r\n// Helper function to create test file name pattern\r\nfunction getTestFileNamePattern(sourceFileName: string): RegExp {\r\n return new RegExp(`^${sourceFileName}(Unit)?(\\\\.)?(Test|Tests)$`);\r\n}\r\n\r\n/**\r\n * Extract words from a name string (e.g., project name, file name)\r\n * Splits by camelCase and special characters, returns lowercase words\r\n * \r\n * @param name - The name string to extract words from\r\n * @returns Array of lowercase words\r\n */\r\nfunction extractWordsFromName(name: string): string[] {\r\n return name\r\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\r\n .split(/[^a-zA-Z0-9]+/)\r\n .filter(Boolean)\r\n .map(w => w.toLowerCase());\r\n}\r\n\r\n/**\r\n * Calculate word-level matching score between two names\r\n * Returns the count of matching words\r\n * \r\n * @param name1 - First name to compare\r\n * @param name2 - Second name to compare\r\n * @returns Number of matching words\r\n */\r\nfunction calculateWordMatchCount(name1: string, name2: string): number {\r\n const words1 = extractWordsFromName(name1);\r\n const words2 = extractWordsFromName(name2);\r\n \r\n const words1Set = new Set(words1);\r\n return words2.filter(w => words1Set.has(w)).length;\r\n}\r\n\r\n/**\r\n * Get all subfolder names under a directory (recursive)\r\n * Skips: bin, obj, .vs directories\r\n * \r\n * @param dirPath - Path to directory\r\n * @returns Set of lowercase folder names\r\n */\r\nfunction getSubfolderNamesRecursive(dirPath: string): Set<string> {\r\n const subfolders = new Set<string>();\r\n try {\r\n const entries = fs.readdirSync(dirPath, { withFileTypes: true });\r\n for (const entry of entries) {\r\n if (entry.isDirectory() && entry.name !== 'bin' && entry.name !== 'obj' && entry.name !== '.vs') {\r\n subfolders.add(entry.name.toLowerCase());\r\n // Recursively get subfolders\r\n const subPath = path.join(dirPath, entry.name);\r\n const deepSubfolders = getSubfolderNamesRecursive(subPath);\r\n deepSubfolders.forEach(f => subfolders.add(f));\r\n }\r\n }\r\n } catch (err) {\r\n // Ignore errors for inaccessible directories\r\n }\r\n return subfolders;\r\n}\r\n\r\n/**\r\n * Get all .cs file names under a directory (recursive)\r\n * Skips: bin, obj, .vs directories\r\n * \r\n * @param dirPath - Path to directory\r\n * @returns Set of lowercase file names (without .cs extension)\r\n */\r\nfunction getFileNamesRecursive(dirPath: string): Set<string> {\r\n const fileNames = new Set<string>();\r\n try {\r\n const entries = fs.readdirSync(dirPath, { withFileTypes: true });\r\n for (const entry of entries) {\r\n if (entry.name === 'bin' || entry.name === 'obj' || entry.name === '.vs') {\r\n continue;\r\n }\r\n const fullPath = path.join(dirPath, entry.name);\r\n if (entry.isDirectory()) {\r\n // Recursively get file names from subdirectories\r\n const subFileNames = getFileNamesRecursive(fullPath);\r\n subFileNames.forEach(f => fileNames.add(f));\r\n } else if (entry.isFile() && entry.name.endsWith('.cs')) {\r\n // Add file name without .cs extension\r\n fileNames.add(entry.name.slice(0, -3).toLowerCase());\r\n }\r\n }\r\n } catch (err) {\r\n // Ignore errors for inaccessible directories\r\n }\r\n return fileNames;\r\n}\r\n\r\nfunction findAllCsprojFiles(dir: string, excludedPaths: string[]): string[] {\r\n const results: string[] = [];\r\n const entries = fs.readdirSync(dir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dir, entry.name);\r\n if (entry.name === \".vs\" || excludedPaths.includes(fullPath)) {\r\n continue; // Skip excluded paths\r\n }\r\n\r\n if (entry.isDirectory()) {\r\n results.push(...findAllCsprojFiles(fullPath, excludedPaths));\r\n } else if (entry.isFile() && entry.name.endsWith('.csproj')) {\r\n results.push(fullPath);\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\nfunction isXapTestProject(csprojPath: string): boolean {\r\n try {\r\n const content = fs.readFileSync(csprojPath, 'utf-8');\r\n const parser = new XMLParser({ ignoreAttributes: false, ignoreDeclaration: true });\r\n const json = parser.parse(content);\r\n const project = json.Project;\r\n\r\n const propertyGroups = Array.isArray(project.PropertyGroup)\r\n ? project.PropertyGroup\r\n : [project.PropertyGroup];\r\n\r\n for (const group of propertyGroups) {\r\n if (group.XapProjectType === 'TestProject') {\r\n return true;\r\n }\r\n }\r\n } catch (err: any) {\r\n console.error(`Failed to parse ${csprojPath}: ${err.message}`);\r\n }\r\n return false;\r\n}\r\n\r\nfunction isGeneralTestProject(csprojPath: string): boolean {\r\n try {\r\n const content = fs.readFileSync(csprojPath, 'utf-8');\r\n\r\n // 1. package reference (test framework)\r\n const referencesTestFramework = /<PackageReference\\s+Include=\"(xunit|nunit|MSTest\\.TestFramework|Microsoft\\.NET\\.Test\\.Sdk)\"/i.test(content);\r\n\r\n // 2. file name *.Tests.csproj\r\n const fileNameHasTests = (/\\.Tests\\.csproj$/i.test(path.basename(csprojPath))) || (/\\.Test\\.csproj$/i.test(path.basename(csprojPath)));\r\n\r\n // 3. path contains Tests\r\n const pathHasTests = /[\\\\/](Tests?|UnitTests?|IntegrationTests?)[\\\\/]/i.test(csprojPath);\r\n\r\n // 4. Project SDK is test type (optional)\r\n const sdkIsTestSdk = /<Project\\s+Sdk=\"Microsoft\\.NET\\.Test\\.Sdk\"/i.test(content);\r\n\r\n // 组合判断\r\n return referencesTestFramework || sdkIsTestSdk || fileNameHasTests || pathHasTests;\r\n } catch (err) {\r\n console.error(`can't read csproj file: ${csprojPath}`);\r\n return false;\r\n }\r\n}\r\n\r\nfunction isFalconUnitTestProject(csprojPath: string): boolean {\r\n const xmlContent = fs.readFileSync(csprojPath, 'utf-8');\r\n\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n attributeNamePrefix: ''\r\n });\r\n const parsed = parser.parse(xmlContent);\r\n\r\n // get PackageReference node\r\n const project = parsed.Project;\r\n const itemGroups = Array.isArray(project.ItemGroup) ? project.ItemGroup : [project.ItemGroup];\r\n\r\n let isFalconUnitTestProject = false;\r\n\r\n for (const group of itemGroups) {\r\n if(!group) continue;\r\n const refs = group.PackageReference;\r\n if (!refs) continue;\r\n\r\n // PackageReference\r\n const refList = Array.isArray(refs) ? refs : [refs];\r\n\r\n for (const ref of refList) {\r\n if (ref.Include === 'Microsoft.Falcon.CodeAnalyzers') {\r\n isFalconUnitTestProject = true;\r\n console.log('Found Microsoft.Falcon.CodeAnalyzers');\r\n break;\r\n }\r\n }\r\n\r\n if (isFalconUnitTestProject) break;\r\n }\r\n\r\n // if (!isFalconUnitTestProject) {\r\n // console.log('Microsoft.Falcon.CodeAnalyzers not found');\r\n // }\r\n\r\n return isFalconUnitTestProject;\r\n}\r\n\r\nfunction isProjectNameMatchedTestProject(csprojPath: string, projectAssemblyName: string, projectName: string) {\r\n const testProjectName = path.basename(csprojPath, '.csproj').toLowerCase();\r\n const projectNameLower = projectName.toLowerCase();\r\n \r\n // Check if test project name exactly matches: projectName + suffix\r\n const suffixes = ['.tests', '.test', '.unittest', '.unittests', 'tests', 'test'];\r\n const exactMatch = suffixes.some(suffix => testProjectName === projectNameLower + suffix);\r\n \r\n if (exactMatch) {\r\n return true;\r\n }\r\n \r\n // Fallback: check assembly name with exact match\r\n const testProjectAssemblyName = getAssemblyName(csprojPath);\r\n if (testProjectAssemblyName) {\r\n const assemblyNameLower = testProjectAssemblyName.toLowerCase();\r\n const projectAssemblyNameLower = projectAssemblyName.toLowerCase();\r\n return suffixes.some(suffix => assemblyNameLower === projectAssemblyNameLower + suffix);\r\n }\r\n \r\n return false;\r\n}\r\n\r\n/**\r\n * Search for test projects in repository directories\r\n * Walks up from source file directory and collects all test projects that reference the source project\r\n * \r\n * @param csFilePath - Path to the source .cs file\r\n * @param repoRoot - Repository root directory\r\n * @param projectFilePath - Path to source project's .csproj\r\n * @param normalizedProjectPath - Normalized path to source project\r\n * @returns Array of test project paths that reference the source project\r\n */\r\nfunction searchTestProjectsInRepositories(\r\n csFilePath: string,\r\n repoRoot: string,\r\n projectFilePath: string,\r\n normalizedProjectPath: string\r\n): string[] {\r\n let currentDir = path.dirname(csFilePath);\r\n const possibleTestProjects: string[] = [];\r\n const excludedPaths: string[] = [currentDir];\r\n const repoRootParentPath = path.dirname(repoRoot);\r\n \r\n currentDir = path.dirname(currentDir);\r\n while (currentDir !== repoRootParentPath) {\r\n const csprojFiles = findAllCsprojFiles(currentDir, excludedPaths);\r\n \r\n // Filter csproj files by standard test project naming patterns\r\n const testProjectCandidates = csprojFiles.filter(csproj => {\r\n const rawName = path.basename(csproj, '.csproj');\r\n const csprojName = rawName.toLowerCase();\r\n // Standard test naming: ends with .tests, .test, .unittests, .unittest, Tests, or Test\r\n if (\r\n csprojName.endsWith('.tests') || \r\n csprojName.endsWith('.test') || \r\n csprojName.endsWith('.unittests') || \r\n csprojName.endsWith('.unittest') ||\r\n csprojName.endsWith('tests') ||\r\n csprojName.endsWith('test')\r\n ) {\r\n return true;\r\n }\r\n\r\n // Word-level match: any word ends with \"test\" or \"tests\"\r\n const words = extractWordsFromName(rawName);\r\n return words.some(w => w.endsWith('test') || w.endsWith('tests'));\r\n });\r\n \r\n for (const csproj of testProjectCandidates) {\r\n // Check if this csproj references the source project\r\n const projectReferences = getProjectReferencesFromCsproj(csproj);\r\n const referencesSourceProject = checkTestProjectReferencesSourceProject(csproj, normalizedProjectPath, projectReferences);\r\n \r\n if (!referencesSourceProject) {\r\n continue;\r\n }\r\n \r\n const projectName = path.basename(projectFilePath, '.csproj');\r\n const projectAssemblyName = getAssemblyName(projectFilePath);\r\n if (isProjectNameMatchedTestProject(csproj, projectAssemblyName, projectName)) {\r\n return [csproj];\r\n }\r\n \r\n // Collect all test projects that reference the source project\r\n possibleTestProjects.push(csproj);\r\n }\r\n \r\n excludedPaths.push(currentDir);\r\n currentDir = path.dirname(currentDir);\r\n }\r\n \r\n return possibleTestProjects;\r\n}\r\n\r\n/**\r\n * Filter test projects by subfolder matching\r\n * Returns projects sorted by match count, or proceeds to file name matching if all zero\r\n * \r\n * @param possibleTestProjects - List of test project paths\r\n * @param projectFilePath - Path to source project's .csproj\r\n * @returns Filtered projects with scores, or null if needs file name matching\r\n */\r\nfunction filterBySubfolderMatching(\r\n possibleTestProjects: string[],\r\n projectFilePath: string\r\n): Array<{ csproj: string, matchCount: number }> | null {\r\n const sourceProjectDir = path.dirname(projectFilePath);\r\n const sourceSubfolders = getSubfolderNamesRecursive(sourceProjectDir);\r\n\r\n const projectsWithScores = possibleTestProjects.map(csproj => {\r\n const testProjectDir = path.dirname(csproj);\r\n const testSubfolders = getSubfolderNamesRecursive(testProjectDir);\r\n \r\n let matchCount = 0;\r\n testSubfolders.forEach(folderName => {\r\n if (sourceSubfolders.has(folderName)) {\r\n matchCount++;\r\n }\r\n });\r\n \r\n return { csproj, matchCount };\r\n });\r\n\r\n projectsWithScores.sort((a, b) => b.matchCount - a.matchCount);\r\n\r\n const allZero = projectsWithScores.every(p => p.matchCount === 0);\r\n return allZero ? null : projectsWithScores;\r\n}\r\n\r\n/**\r\n * Filter test projects by file name matching with test suffixes\r\n * Returns filtered projects if any matches found\r\n * \r\n * @param projectsWithScores - Projects with scores\r\n * @param projectFilePath - Path to source project's .csproj\r\n * @returns Filtered projects by file name, or null if no matches\r\n */\r\nfunction filterByFileNameMatching(\r\n projectsWithScores: Array<{ csproj: string, matchCount: number }>,\r\n projectFilePath: string\r\n): Array<{ csproj: string, matchCount: number }> | null {\r\n const sourceProjectDir = path.dirname(projectFilePath);\r\n const sourceFileNames = getFileNamesRecursive(sourceProjectDir);\r\n const testSuffixes = ['.tests', '.test', '.unittests', '.unittest', 'tests', 'test'];\r\n\r\n const filteredProjectsWithScores = projectsWithScores.filter(projectScore => {\r\n const testProjectDir = path.dirname(projectScore.csproj);\r\n const testFileNames = getFileNamesRecursive(testProjectDir);\r\n\r\n for (const sourceFileName of sourceFileNames) {\r\n for (const suffix of testSuffixes) {\r\n const expectedTestFileName = (sourceFileName + suffix).toLowerCase();\r\n if (testFileNames.has(expectedTestFileName)) {\r\n return true;\r\n }\r\n }\r\n }\r\n return false;\r\n });\r\n\r\n return filteredProjectsWithScores.length > 0 ? filteredProjectsWithScores : null;\r\n}\r\n\r\n/**\r\n * Filter test projects by word-level matching\r\n * Returns top 2 projects with highest word match count\r\n * \r\n * @param projectsWithScores - Projects with scores\r\n * @param projectName - Name of source project\r\n * @returns Top 2 projects by word match count, or empty array if no matches\r\n */\r\nfunction filterByWordLevelMatching(\r\n projectsWithScores: Array<{ csproj: string, matchCount: number }>,\r\n projectName: string\r\n): string[] {\r\n const projectsWithWordScores = projectsWithScores.map(projectScore => {\r\n const testProjectName = path.basename(projectScore.csproj, '.csproj');\r\n const wordMatchCount = calculateWordMatchCount(projectName, testProjectName);\r\n return { ...projectScore, wordMatchCount };\r\n });\r\n\r\n const projectsWithMatches = projectsWithWordScores.filter(p => p.wordMatchCount > 0);\r\n\r\n if (projectsWithMatches.length === 0) {\r\n return [];\r\n }\r\n\r\n projectsWithMatches.sort((a, b) => b.wordMatchCount - a.wordMatchCount);\r\n\r\n const countToReturn = Math.min(2, projectsWithMatches.length);\r\n return projectsWithMatches.slice(0, countToReturn).map(p => p.csproj);\r\n}\r\n\r\n/**\r\n * Select top projects by score percentage or minimum count\r\n * \r\n * @param projectsWithScores - Projects with scores\r\n * @param minCount - Minimum projects to return (default 2)\r\n * @returns Array of selected project paths\r\n */\r\nfunction selectTopProjectsByScore(\r\n projectsWithScores: Array<{ csproj: string, [key: string]: any }>,\r\n minCount: number = 2\r\n): string[] {\r\n const countToReturn = Math.max(minCount, Math.ceil(projectsWithScores.length * 0.3));\r\n return projectsWithScores.slice(0, countToReturn).map(p => p.csproj);\r\n}\r\n\r\n/**\r\n * Find possible test projects for a C# source file\r\n * Uses multi-level matching: folder names -> file names -> word-level matching\r\n * \r\n * @param csFilePath - Path to the source .cs file\r\n * @returns Array of possible test project paths\r\n */\r\nfunction findPossibleTestProjectsFromCsFile(csFilePath: string): string[] {\r\n const repoRoot = getCodeRepoRoot(csFilePath);\r\n const projectFilePath = getSourceFileCsprojFilePath(csFilePath);\r\n const projectName = path.basename(projectFilePath, '.csproj');\r\n const normalizedProjectPath = path.normalize(projectFilePath);\r\n\r\n // Search for test projects in repository\r\n const possibleTestProjects = searchTestProjectsInRepositories(\r\n csFilePath,\r\n repoRoot,\r\n projectFilePath,\r\n normalizedProjectPath\r\n );\r\n\r\n if (possibleTestProjects.length === 0) {\r\n return [];\r\n }\r\n\r\n if (possibleTestProjects.length === 1) {\r\n return possibleTestProjects;\r\n }\r\n\r\n // Try subfolder-level matching\r\n const subfolderMatchResults = filterBySubfolderMatching(possibleTestProjects, projectFilePath);\r\n if (subfolderMatchResults !== null) {\r\n return selectTopProjectsByScore(subfolderMatchResults);\r\n }\r\n\r\n // If subfolder matching is all zero, try file name matching\r\n const projectsWithScores = possibleTestProjects.map(csproj => ({ csproj, matchCount: 0 }));\r\n const fileNameMatchResults = filterByFileNameMatching(projectsWithScores, projectFilePath);\r\n if (fileNameMatchResults !== null) {\r\n return selectTopProjectsByScore(fileNameMatchResults);\r\n }\r\n\r\n // If file name matching fails, try word-level matching\r\n const wordLevelResults = filterByWordLevelMatching(projectsWithScores, projectName);\r\n return wordLevelResults.length > 0 ? wordLevelResults : [];\r\n}\r\n\r\nfunction findPossibleTestFiles(testProjectDir: string, className: string): string[] {\r\n const results: string[] = [];\r\n const stack: string[] = [testProjectDir];\r\n\r\n while (stack.length > 0) {\r\n const currentDir = stack.pop()!;\r\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n if (entry.name === \"bin\" || entry.name === \"obj\") {\r\n continue;\r\n }\r\n const fullPath = path.join(currentDir, entry.name);\r\n if (entry.isDirectory()) {\r\n stack.push(fullPath);\r\n } else if (entry.isFile() && entry.name.endsWith('.cs') && entry.name.includes(className)) {\r\n results.push(fullPath);\r\n }\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\nfunction fileContainsTestAttributes(filePath: string): boolean {\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n return TEST_ATTR_REGEX.test(content);\r\n}\r\n\r\n/**\r\n * Check if a test project references a source project.\r\n * \r\n * @param testCsprojPath - Path to the test project's csproj file\r\n * @param sourceCsprojPath - Path to the source project's csproj file\r\n * @param projectReferences - Project references from the test csproj\r\n * @returns True if test project references the source project, false otherwise\r\n */\r\nfunction checkTestProjectReferencesSourceProject(\r\n testCsprojPath: string,\r\n sourceCsprojPath: string,\r\n projectReferences: string[]\r\n): boolean {\r\n const normalizedSourceCsprojPath = path.normalize(sourceCsprojPath).toLowerCase();\r\n return projectReferences.some(ref => {\r\n const resolvedRefPath = path.normalize(path.resolve(path.dirname(testCsprojPath), ref)).toLowerCase();\r\n return resolvedRefPath === normalizedSourceCsprojPath;\r\n });\r\n}\r\n\r\nfunction getProjectReferencesFromCsproj(csprojPath: string): string[] {\r\n const projectReferences: string[] = [];\r\n try {\r\n const xmlContent = fs.readFileSync(csprojPath, 'utf-8');\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n attributeNamePrefix: ''\r\n });\r\n const projectData = parser.parse(xmlContent);\r\n \r\n const project = projectData.Project;\r\n const itemGroups = Array.isArray(project.ItemGroup) ? project.ItemGroup : [project.ItemGroup];\r\n \r\n for (const group of itemGroups) {\r\n if (!group) continue;\r\n const projectRefs = group.ProjectReference;\r\n if (!projectRefs) continue;\r\n\r\n const refList = Array.isArray(projectRefs) ? projectRefs : [projectRefs];\r\n for (const ref of refList) {\r\n if (ref.Include) {\r\n projectReferences.push(ref.Include);\r\n }\r\n }\r\n }\r\n } catch (err) {\r\n console.error(`Failed to parse csproj: ${csprojPath}`, err);\r\n }\r\n return projectReferences;\r\n}\r\n\r\n/**\r\n * Calculate matching score between test file path and source file path based on directory structure.\r\n * Returns two scores: continuous matching folders from end, and total matching folders.\r\n * \r\n * @param testRelativePath - Relative path of test file from test project root\r\n * @param sourceRelativePath - Relative path of source file from source project root\r\n * @returns Object with 'continuous' (right-to-left consecutive matches) and 'total' (all matches)\r\n */\r\nfunction calculateMatchingScore(testRelativePath: string, sourceRelativePath: string): { continuous: number, total: number } {\r\n // Extract directory paths (remove file names)\r\n const testDir = path.dirname(testRelativePath);\r\n const sourceDir = path.dirname(sourceRelativePath);\r\n \r\n // If both files are in root directory (no subdirectories), give highest priority\r\n if ((testDir === '.' || testDir === '') && (sourceDir === '.' || sourceDir === '')) {\r\n return { continuous: 1000, total: 1000 };\r\n }\r\n \r\n // Split paths into folder arrays (case-insensitive)\r\n const testFolders = testDir === '.' || testDir === '' ? [] : testDir.split(path.sep).map(f => f.toLowerCase());\r\n const sourceFolders = sourceDir === '.' || sourceDir === '' ? [] : sourceDir.split(path.sep).map(f => f.toLowerCase());\r\n \r\n // 1. Calculate continuous matching folders from end (right to left)\r\n let continuous = 0;\r\n const minLength = Math.min(testFolders.length, sourceFolders.length);\r\n \r\n for (let i = 1; i <= minLength; i++) {\r\n if (testFolders[testFolders.length - i] === sourceFolders[sourceFolders.length - i]) {\r\n continuous++;\r\n } else {\r\n // Stop at first mismatch\r\n break;\r\n }\r\n }\r\n \r\n // 2. Calculate total matching folders (not required to be continuous)\r\n const sourceSet = new Set(sourceFolders);\r\n const total = testFolders.filter(f => sourceSet.has(f)).length;\r\n \r\n return { continuous, total };\r\n}\r\n\r\nfunction isTestFileForSourceFile(testFilePath: string, sourceCodePath: string): boolean {\r\n const sourceFileName = path.basename(sourceCodePath, '.cs');\r\n const testFileName = path.basename(testFilePath, '.cs');\r\n \r\n // First check: test file name should match common test patterns\r\n // Patterns: SourceFile + (Unit)? + (.)? + (Test|Tests)\r\n // Examples: SourceFileTests, SourceFileTest, SourceFile.Tests, SourceFile.Test, SourceFileUnitTests, SourceFileUnit.Tests\r\n const testPattern = getTestFileNamePattern(sourceFileName);\r\n const matchesPattern = testPattern.test(testFileName);\r\n if (!matchesPattern) {\r\n return false;\r\n }\r\n \r\n try {\r\n // Read both files content\r\n const testContent = fs.readFileSync(testFilePath, 'utf-8');\r\n const sourceContent = fs.readFileSync(sourceCodePath, 'utf-8');\r\n \r\n // First check: Extract namespace from source file and verify test file references it\r\n const sourceNamespaceMatch = sourceContent.match(/namespace\\s+([\\w.]+)/);\r\n if (!sourceNamespaceMatch || !sourceNamespaceMatch[1]) {\r\n // No namespace found in source file, fall back to name-based matching\r\n return true;\r\n }\r\n \r\n const sourceNamespace = sourceNamespaceMatch[1];\r\n // Check if test file has using statement for source namespace\r\n const usingRegex = new RegExp(`using\\\\s+${sourceNamespace.replace(/\\./g, '\\\\.')};`);\r\n if (!usingRegex.test(testContent)) {\r\n // Test file doesn't reference source namespace\r\n return false;\r\n }\r\n \r\n // Second check: Extract the main type name from source file (public or internal)\r\n // Supports: class, interface, struct, record (but not nested private/protected types)\r\n // Priority: public > internal; match first public, fallback to first internal\r\n // Handles modifiers: sealed, abstract, static, partial\r\n const publicTypeMatch = sourceContent.match(new RegExp(`\\\\bpublic\\\\s+${MODIFIER_PATTERN}(?:class|interface|struct|record)\\\\s+(\\\\w+)`));\r\n const internalTypeMatch = sourceContent.match(new RegExp(`\\\\binternal\\\\s+${MODIFIER_PATTERN}(?:class|interface|struct|record)\\\\s+(\\\\w+)`));\r\n \r\n const sourceTypeMatch = publicTypeMatch || internalTypeMatch;\r\n if (!sourceTypeMatch || !sourceTypeMatch[1]) {\r\n // No public or internal type found - this file might be a utility/helper file\r\n // without testable classes, so it shouldn't have a test file\r\n return false;\r\n }\r\n \r\n const sourceTypeName = sourceTypeMatch[1];\r\n // Check if test file references the source type name or its interface\r\n // If source is an interface (direct interface definition), only match itself\r\n // If source is a class/struct/record, also match interface (ITypeName)\r\n const isSourceInterface = new RegExp(`\\\\b(?:public|internal)\\\\s+${MODIFIER_PATTERN}interface\\\\s+(?:\\\\w+)`).test(sourceContent);\r\n let sourceCodeTypeReferenceRegex: RegExp;\r\n if (isSourceInterface) {\r\n // Source is an interface, match only itself\r\n sourceCodeTypeReferenceRegex = new RegExp(`\\\\b${sourceTypeName}\\\\b`, 'g');\r\n } else {\r\n // Source is a class/struct/record, match both TypeName and ITypeName\r\n sourceCodeTypeReferenceRegex = new RegExp(`\\\\b(I)?${sourceTypeName}\\\\b`, 'g');\r\n }\r\n \r\n if (sourceCodeTypeReferenceRegex.test(testContent)) {\r\n return true;\r\n }\r\n \r\n // Namespace matches but class name not found in test file\r\n return false;\r\n \r\n } catch (err) {\r\n console.error(`Failed to read file content for matching: ${err}`);\r\n // Strict mode: if we can't verify the content, treat as non-matching\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Find an existing test file from sibling source files in the same or parent directories.\r\n * This helps determine the best location for a new test file by looking at where\r\n * existing test files are located for nearby source files.\r\n * \r\n * @param sourceCodePath - Path to the source file\r\n * @param testCsprojPath - Path to the test project's csproj file\r\n * @param sourceCsprojPath - Path to the source project's csproj file\r\n * @returns Object with siblingTestFilePath and sourceRelativeDepth if found, otherwise null\r\n */\r\nfunction findSiblingTestFile(\r\n sourceCodePath: string,\r\n testCsprojPath: string,\r\n sourceCsprojPath: string\r\n): { siblingTestFilePath: string, sourceRelativeDepth: number } | null {\r\n const sourceProjectDir = path.dirname(sourceCsprojPath);\r\n let currentDir = path.dirname(sourceCodePath);\r\n let depth = 0;\r\n \r\n // Search from current directory up to source project root\r\n while (currentDir.toLowerCase().startsWith(sourceProjectDir.toLowerCase()) && currentDir.length >= sourceProjectDir.length) {\r\n try {\r\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\r\n const csFiles = entries\r\n .filter(e => e.isFile() && e.name.endsWith('.cs') && path.join(currentDir, e.name) !== sourceCodePath)\r\n .map(e => path.join(currentDir, e.name));\r\n \r\n for (const csFile of csFiles) {\r\n // Try to find test file for this sibling source file\r\n const result = findMatchingTestFileInProject(testCsprojPath, csFile, sourceCsprojPath);\r\n if (result.testFilePath) {\r\n return { siblingTestFilePath: result.testFilePath, sourceRelativeDepth: depth };\r\n }\r\n }\r\n } catch (err) {\r\n // Ignore errors for inaccessible directories\r\n }\r\n \r\n // Move to parent directory\r\n const parentDir = path.dirname(currentDir);\r\n if (parentDir === currentDir) {\r\n break;\r\n }\r\n currentDir = parentDir;\r\n depth++;\r\n }\r\n \r\n return null;\r\n}\r\n\r\n/**\r\n * Determine the best test file path for a source file.\r\n * This function only calculates the path, it does not create any directories.\r\n * \r\n * @param sourceCodePath - Path to the source file\r\n * @param testCsprojPath - Path to the test project's csproj file (optional)\r\n * @returns Object with testFilePath, testProjectPath, and testFileExist flag\r\n */\r\nexport function determineTestFilePath(sourceCodePath: string, testCsprojPath?: string): { testFilePath: string | null, testProjectPath: string | null, testFileExist?: boolean } {\r\n let testProjectPath = testCsprojPath;\r\n if (!testProjectPath) {\r\n console.error(`No test project found for ${sourceCodePath}`);\r\n return { testFilePath: null, testProjectPath: null };\r\n }\r\n \r\n const sourceFileName = path.basename(sourceCodePath, '.cs');\r\n const testFileName = `${sourceFileName}Tests.cs`;\r\n const sourceFileProjectPath = getSourceFileProjectDir(sourceCodePath);\r\n const sourceCsprojPath = getSourceFileCsprojFilePath(sourceCodePath);\r\n \r\n // Try to find sibling test file to determine the best location\r\n const siblingResult = findSiblingTestFile(sourceCodePath, testProjectPath, sourceCsprojPath);\r\n \r\n let testFilePath: string;\r\n if (siblingResult) {\r\n // Found sibling test file, calculate new test file path based on it\r\n const siblingTestDir = path.dirname(siblingResult.siblingTestFilePath);\r\n const sourceFileDir = path.dirname(sourceCodePath);\r\n \r\n if (siblingResult.sourceRelativeDepth === 0) {\r\n // Sibling is in the same directory, put test file in the same test directory\r\n testFilePath = path.join(siblingTestDir, testFileName);\r\n } else {\r\n // Sibling is in a parent directory, calculate the relative path from sibling source to current source\r\n let relativeParts: string[] = [];\r\n let tempDir = sourceFileDir;\r\n \r\n for (let i = 0; i < siblingResult.sourceRelativeDepth; i++) {\r\n relativeParts.unshift(path.basename(tempDir));\r\n tempDir = path.dirname(tempDir);\r\n }\r\n \r\n // The relative path from the found sibling source dir to our source file\r\n const relativePath = relativeParts.join(path.sep);\r\n testFilePath = path.join(siblingTestDir, relativePath, testFileName);\r\n }\r\n } else {\r\n // No sibling test file found, use original logic\r\n const sourceFileDir = path.dirname(sourceCodePath);\r\n const testFileRelativePath = sourceFileDir.replace(sourceFileProjectPath, \"\");\r\n const testProjecDir = path.dirname(testProjectPath);\r\n testFilePath = path.join(testProjecDir, testFileRelativePath, testFileName);\r\n }\r\n \r\n // Check if the test file already exists\r\n const testFileExist = fs.existsSync(testFilePath);\r\n if (testFileExist) {\r\n console.log(`Test file already exists at ${testFilePath}`);\r\n }\r\n \r\n return { testFilePath, testProjectPath, testFileExist };\r\n}\r\n\r\n/**\r\n * Search for matching test file in a specific test project.\r\n * Uses directory structure matching and file content analysis to find the best match.\r\n * \r\n * @param testCsprojPath - Path to the test project's csproj file\r\n * @param sourceCodePath - Path to the source file\r\n * @param sourceCsprojPath - Path to the source project's csproj file\r\n * @returns Object with testFilePath and testProjectPath if found, otherwise both null\r\n */\r\nfunction findMatchingTestFileInProject(\r\n testCsprojPath: string,\r\n sourceCodePath: string,\r\n sourceCsprojPath: string\r\n): { testFilePath: string | null, testProjectPath: string | null } {\r\n const testProjectDir = path.dirname(testCsprojPath);\r\n \r\n // Get source file's csproj directory\r\n const sourceCsprojDir = path.dirname(sourceCsprojPath);\r\n // Calculate relative path of source file from its csproj directory\r\n const sourceRelativePath = path.relative(sourceCsprojDir, sourceCodePath);\r\n \r\n // Get source file name for filtering\r\n const sourceFileName = path.basename(sourceCodePath, '.cs');\r\n \r\n // Find .cs files containing source file name (optimization to reduce file count)\r\n const allTestFiles = findPossibleTestFiles(testProjectDir, sourceFileName);\r\n \r\n // Filter by file name pattern first to reduce unnecessary file reads\r\n const testPattern = getTestFileNamePattern(sourceFileName);\r\n \r\n // Create list of candidates with their matching scores\r\n const candidatesWithScores = allTestFiles\r\n .filter(file => {\r\n const testFileName = path.basename(file, '.cs');\r\n return testPattern.test(testFileName);\r\n })\r\n .map(file => {\r\n const testRelativePath = path.relative(testProjectDir, file);\r\n const score = calculateMatchingScore(testRelativePath, sourceRelativePath);\r\n return {\r\n filePath: file,\r\n relativePath: testRelativePath,\r\n score: score\r\n };\r\n })\r\n // Sort by continuous match first, then by total match\r\n .sort((a, b) => {\r\n if (b.score.continuous !== a.score.continuous) {\r\n return b.score.continuous - a.score.continuous;\r\n }\r\n return b.score.total - a.score.total;\r\n });\r\n \r\n for (const candidate of candidatesWithScores) {\r\n if (isTestFileForSourceFile(candidate.filePath, sourceCodePath)) {\r\n return { testFilePath: candidate.filePath, testProjectPath: testCsprojPath };\r\n }\r\n }\r\n \r\n return { testFilePath: null, testProjectPath: null };\r\n}\r\n\r\nfunction getTestFileFromChangedFiles(sourceCodePath: string, changedTestFiles?: string[]): { testFilePath: string | null, testProjectPath: string | null } {\r\n if (!changedTestFiles || changedTestFiles.length === 0) {\r\n return { testFilePath: null, testProjectPath: null };\r\n }\r\n\r\n console.log(`Searching test file from ${changedTestFiles.length} changed test files for source: ${sourceCodePath}`);\r\n\r\n // Get the csproj of the source code\r\n const sourceCsprojPath = getSourceFileCsprojFilePath(sourceCodePath);\r\n if (!sourceCsprojPath) {\r\n return { testFilePath: null, testProjectPath: null };\r\n }\r\n\r\n // Cache to store project references from csproj to avoid re-parsing\r\n const csprojCache = new Map<string, string[]>();\r\n // Store test projects that reference the source project\r\n const referencingTestProjects = new Set<string>();\r\n\r\n for (const testFilePath of changedTestFiles) {\r\n if (!fs.existsSync(testFilePath)) {\r\n continue;\r\n }\r\n\r\n // Get the csproj of the test file\r\n const testCsprojPath = getSourceFileCsprojFilePath(testFilePath);\r\n if (!testCsprojPath) {\r\n continue;\r\n }\r\n\r\n // Check cache first\r\n let projectReferences = csprojCache.get(testCsprojPath);\r\n if (!projectReferences) {\r\n projectReferences = getProjectReferencesFromCsproj(testCsprojPath);\r\n csprojCache.set(testCsprojPath, projectReferences);\r\n }\r\n\r\n // Check if test project references the source project\r\n const normalizedSourceCsprojPath = path.normalize(sourceCsprojPath);\r\n if (checkTestProjectReferencesSourceProject(testCsprojPath, normalizedSourceCsprojPath, projectReferences)) {\r\n referencingTestProjects.add(testCsprojPath);\r\n // Check if this test file is for the source file\r\n if (isTestFileForSourceFile(testFilePath, sourceCodePath)) {\r\n return { testFilePath, testProjectPath: testCsprojPath };\r\n }\r\n }\r\n }\r\n\r\n // Fallback: search all test files in projects that reference the source project\r\n for (const testCsprojPath of referencingTestProjects) {\r\n const result = findMatchingTestFileInProject(testCsprojPath, sourceCodePath, sourceCsprojPath);\r\n if (result.testFilePath) {\r\n return result;\r\n }\r\n }\r\n\r\n return { testFilePath: null, testProjectPath: null };\r\n}\r\n\r\nexport function getOrCreatTestFile(sourceCodePath: string, testFilePath: string, changedTestFiles?: string[]) {\r\n let finalTestFilePath = testFilePath;\r\n let finalTestProjectPath;\r\n let testFileExist = !!testFilePath && fs.existsSync(testFilePath);\r\n \r\n // If testFilePath is provided, get its project path and return directly\r\n if (testFilePath && testFilePath.trim() !== '') {\r\n finalTestProjectPath = getSourceFileCsprojFilePath(testFilePath);\r\n return { testFilePath: finalTestFilePath, testProjectPath: finalTestProjectPath, testFileExist };\r\n }\r\n \r\n // if outputPath param is not provided, try to find an existing test file\r\n // if no existing test file found, create a new one in test project\r\n console.log(' Output path is missing. outputPath:', testFilePath, ', start looking for existing test project');\r\n\r\n // Try to find test file from changed files first\r\n let resultFromChangedFiles = getTestFileFromChangedFiles(sourceCodePath, changedTestFiles);\r\n if (resultFromChangedFiles.testFilePath) {\r\n return { testFilePath: resultFromChangedFiles.testFilePath, testProjectPath: resultFromChangedFiles.testProjectPath, testFileExist: true };\r\n }\r\n\r\n // Fallback: try to find existing test file\r\n const possibleCSProjPaths = findPossibleTestProjectsFromCsFile(sourceCodePath);\r\n if (!possibleCSProjPaths || possibleCSProjPaths.length === 0) {\r\n console.error(` No test project found for source code: ${sourceCodePath}`);\r\n return { testFilePath: null, testProjectPath: null, testFileExist: false };\r\n }\r\n\r\n // Get the source csproj path for matching\r\n const sourceCsprojPath = getSourceFileCsprojFilePath(sourceCodePath);\r\n if (!sourceCsprojPath) {\r\n console.error(` Cannot find source csproj for: ${sourceCodePath}`);\r\n return { testFilePath: null, testProjectPath: null, testFileExist: false };\r\n }\r\n\r\n // Try to find existing test file in each possible test project\r\n for (const testCsprojPath of possibleCSProjPaths) {\r\n const result = findMatchingTestFileInProject(testCsprojPath, sourceCodePath, sourceCsprojPath);\r\n if (result.testFilePath) {\r\n testFileExist = true;\r\n finalTestFilePath = result.testFilePath;\r\n finalTestProjectPath = result.testProjectPath;\r\n return { testFilePath: finalTestFilePath, testProjectPath: finalTestProjectPath, testFileExist };\r\n }\r\n }\r\n\r\n // No existing test file found, determine test file path (may find existing)\r\n const result = determineTestFilePath(sourceCodePath, possibleCSProjPaths[0]);\r\n if (!result.testFilePath || !result.testProjectPath) {\r\n console.error(`Failed to determine test file path for ${sourceCodePath}`);\r\n return { testFilePath: null, testProjectPath: null, testFileExist: false };\r\n }\r\n finalTestFilePath = result.testFilePath;\r\n finalTestProjectPath = result.testProjectPath;\r\n testFileExist = result.testFileExist ?? false;\r\n \r\n // Create directory if test file doesn't exist\r\n if (!testFileExist) {\r\n getOrCreateDir(path.dirname(finalTestFilePath));\r\n }\r\n\r\n return { testFilePath: finalTestFilePath, testProjectPath: finalTestProjectPath, testFileExist };\r\n\r\n}\r\n\r\n// // Verify test file paths for all projects\r\n// function verifyTestFilePaths(): void {\r\n// const baseFolder = 'Q:\\\\src\\\\Microsoft.News.OneService';\r\n// const outputFile = 'q:\\\\verifyTestFilePaths_results.txt';\r\n// const results: string[] = [];\r\n\r\n// try {\r\n// // Recursively find all non test csproj files \r\n// const getAllCsprojFiles = (dir: string): string[] => {\r\n// const csprojFiles: string[] = [];\r\n// try {\r\n// const entries = fs.readdirSync(dir, { withFileTypes: true });\r\n// for (const entry of entries) {\r\n// const fullPath = path.join(dir, entry.name);\r\n// if (entry.isDirectory() && entry.name !== 'bin' && entry.name !== 'obj' && entry.name !== '.vs') {\r\n// csprojFiles.push(...getAllCsprojFiles(fullPath));\r\n// } else if (entry.isFile() && entry.name.endsWith('.csproj')) {\r\n// // Filter by test project naming patterns\r\n// const rawName = path.basename(fullPath, '.csproj');\r\n// const words = rawName\r\n// .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\r\n// .split(/[^a-zA-Z0-9]+/)\r\n// .filter(Boolean)\r\n// .map(w => w.toLowerCase());\r\n \r\n// if (words.every(w => !w.endsWith('test') && !w.endsWith('tests'))) {\r\n// csprojFiles.push(fullPath);\r\n// }\r\n// }\r\n// }\r\n// } catch (err) {\r\n// // Skip inaccessible directories\r\n// }\r\n// return csprojFiles;\r\n// };\r\n\r\n// // Get first .cs file in a directory (recursive search)\r\n// const getFirstCsFile = (dir: string): string | null => {\r\n// try {\r\n// const entries = fs.readdirSync(dir, { withFileTypes: true });\r\n// // First pass: look for .cs files in current directory\r\n// for (const entry of entries) {\r\n// if (entry.isFile() && entry.name.endsWith('.cs')) {\r\n// return path.join(dir, entry.name);\r\n// }\r\n// }\r\n// // Second pass: recurse into subdirectories\r\n// for (const entry of entries) {\r\n// if (entry.isDirectory() && entry.name !== 'bin' && entry.name !== 'obj' && entry.name !== '.vs') {\r\n// const fullPath = path.join(dir, entry.name);\r\n// const result = getFirstCsFile(fullPath);\r\n// if (result) {\r\n// return result;\r\n// }\r\n// }\r\n// }\r\n// } catch (err) {\r\n// // Skip if directory can't be read\r\n// }\r\n// return null;\r\n// };\r\n\r\n// // Find all csproj files\r\n// const csprojFiles = getAllCsprojFiles(baseFolder);\r\n\r\n// // Process each csproj\r\n// for (const csprojPath of csprojFiles) {\r\n// const csprojDir = path.dirname(csprojPath);\r\n// const csFile = getFirstCsFile(csprojDir);\r\n\r\n// if (csFile) {\r\n// const result = getOrCreatTestFile(csFile, undefined);\r\n// const testFilePath = result.testFilePath || 'NOT_FOUND';\r\n// const testProjectPath = result.testProjectPath || 'NOT_FOUND';\r\n// results.push(`${csprojPath}\\t${csFile}\\t${testFilePath}\\t${testProjectPath}\\t${result.testFileExist}`);\r\n// console.log(`Processed: ${csprojPath}`);\r\n// }\r\n// }\r\n\r\n// // Write results to file\r\n// fs.writeFileSync(outputFile, results.join('\\n'), 'utf-8');\r\n// console.log(`Results written to ${outputFile}`);\r\n// } catch (err) {\r\n// console.error(`Error during verification: ${err}`);\r\n// }\r\n// }\r\n\r\n// // Uncomment to run verification\r\n// verifyTestFilePaths();\r\n\r\n// getOrCreatTestFile(\"Q:\\\\src\\\\Microsoft.News.OneService\\\\Libraries\\\\Tests\\\\MockStrategies\\\\MockDataException.cs\", undefined);\r\n\r\n\r\n// Example usage\r\n// const csFilePath = \"D:\\\\code\\\\CS.Service.Fundamental\\\\SharedSegments\\\\SharedSegments\\\\SharedSegments.Plugins\\\\Workflows\\\\LocationDetection\\\\AudienceResponseParser.cs\";\r\n// const csFilePath = \"D:\\\\code\\\\msnews-experiences\\\\experiences\\\\weather-right-rail\\\\src\\\\WeatherRightRail.connector.ts\";\r\n// const testProjectPath = \"D:\\\\code\\\\CS.Service.Fundamental\\\\SharedSegments\\\\SharedSegments\\\\SharedSegments.Tests\\\\SharedSegments.Tests.csproj\";\r\n// if (!csFilePath) {\r\n// console.error('Usage: ts-node findTestFile.ts path/to/your/file.cs');\r\n// process.exit(1);\r\n// }\r\n\r\n// const start = Date.now();\r\n// const testFilePath = getExistingTestFile(csFilePath);\r\n// console.log(`Test file for ${csFilePath}:`, testFilePath ?? 'No test file found');\r\n// console.log(`Search completed in ${(Date.now() - start) / 1000} seconds`);\r\n// createXapTestFile(csFilePath);\r\n\r\n// const repoDir = getCodeRepoRoot(\"D:\\\\code\\\\CS.Service.Fundamental\\\\SharedSegments\\\\SharedSegments\\\\SharedSegments.Plugins\\\\Workflows\\\\LocationDetection\\\\AudienceResponseParser.cs\");\r\n// console.log(`Code repository root directory: ${repoDir}`);\r\n\r\n// const result = getExistingTestFile(\"D:\\\\code\\\\CS.Service.Fundamental\\\\SharedSegments\\\\SharedSegments\\\\SharedSegments.Plugins\\\\Workflows\\\\Eplant\\\\EplantConfigManager.cs\");\r\n// console.log(`Test file path: ${result.testFilePath}`);\r\n// console.log(`Test project path: ${result.testProjectPath}`);\r\n\r\n\r\n// falcon test project\r\n// const isFlaconUt = isFalconUnitTestProject(\"D:\\\\code\\\\WeatherNotification\\\\services\\\\WeatherUserInterest\\\\tests\\\\UnitTests\\\\Microsoft.Falcon.WeatherUserInterest.UnitTests.csproj\");\r\n// console.log(`Is Falcon Unit Test Project: ${isFlaconUt}`);\r\n// const testProject = findTestProjectFromCsFile(\"D:\\\\code\\\\WeatherNotification\\\\services\\\\WeatherUserInterest\\\\src\\\\Service\\\\Microsoft.Falcon.WeatherUserInterest.csproj\");\r\n// console.log(`Test project path: ${testProject}`);\r\n// const testFilePath = getOrCreatTestFile(\"D:\\\\code\\\\WeatherNotification\\\\services\\\\WeatherUserInterest\\\\src\\\\Service\\\\Components\\\\IUserInterestTable.cs\", undefined, false);\r\n// console.log(`Test file path: ${testFilePath.testFilePath}`);\r\n\r\n// ads projects\r\n// const testProjectPath = findTestProjectFromCsFile(\"D:\\\\code\\\\UCMDynamics\\\\private\\\\DynamicCode\\\\Plugin\\\\UCMDynamics.AppointmentPlugin\\\\AppointmentOperation.cs\");\r\n// console.log(`Test project path: ${testProjectPath}`);\r\n// const isValid = isGeneralTestProject(\"D:\\\\code\\\\UCMDynamics\\\\private\\\\DynamicCode\\\\Plugin\\\\UcmDynamics.AppointmentPlugin\\\\UcmDynamics.AppointmentPlugin.csproj\");\r\n// // const isValid = isGeneralTestProject(\"D:\\\\code\\\\UCMDynamics\\\\private\\\\DynamicCode\\\\Plugin\\\\UcmDynamics.AppointmentPlugin.Tests\\\\UcmDynamics.AppointmentPlugin.Tests.csproj\");\r\n// console.log(`Is General Test Project: ${isValid}`);\r\n\r\n// const testProjectPath = findTestProjectFromCsFile(\"D:\\\\code\\\\AIUnitTestExample\\\\src\\\\ToListinator.Analyzers\\\\ToListCountAnalyzer.cs\");\r\n// console.log(`Test project path: ${testProjectPath}`);"]}
|