Skip to content

Commit

Permalink
Merge pull request #36 from mattzcarey/refactor/test/code-improvement…
Browse files Browse the repository at this point in the history
…s-for-test

refactor(test): performance and code readbility improvements
  • Loading branch information
fabienzucchet authored Jul 25, 2023
2 parents 8d07257 + 539092b commit e7867ec
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 95 deletions.
48 changes: 22 additions & 26 deletions src/review/prompt/constructPrompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,29 @@ const getSizeOfReviewFile = (file: ReviewFile): number =>
const splitFilesIntoBatches = (
files: ReviewFile[],
maxBatchSize: number
): ReviewFile[][] =>
files.reduce(
(batches: ReviewFile[][], currentFile: ReviewFile): ReviewFile[][] => {
if (batches.length === 0) {
batches.push([currentFile]);
} else {
const lastBatch = batches[batches.length - 1];

const currentBatchSize = lastBatch.reduce(
(totalSize: number, file: ReviewFile) =>
totalSize + getSizeOfReviewFile(file),
0
);

const currentFileSize = getSizeOfReviewFile(currentFile);

if (currentBatchSize + currentFileSize > maxBatchSize) {
batches.push([currentFile]);
}
): ReviewFile[][] => {
const batches: ReviewFile[][] = [];
let currentBatch: ReviewFile[] = [];
let currentBatchSize = 0;
for (const file of files) {
const currentFileSize = getSizeOfReviewFile(file);
if (currentBatchSize + currentFileSize > maxBatchSize) {
batches.push(currentBatch);
currentBatch = [file];
currentBatchSize = currentFileSize;
} else {
currentBatch.push(file);
currentBatchSize += currentFileSize;
}
}

lastBatch.push(currentFile);
}
// Add the last batch to the result
if (currentBatch.length > 0) {
batches.push(currentBatch);
}

return batches;
},
[[]] as ReviewFile[][]
);
return batches;
};

const readFiles = async (fileNames: string[]): Promise<ReviewFile[]> => {
const files: ReviewFile[] = [];
Expand All @@ -48,7 +44,7 @@ const readFiles = async (fileNames: string[]): Promise<ReviewFile[]> => {
const fileContent = await readFile(fileName, "utf8");
files.push({ fileName, fileContent });
} catch (error) {
console.error(`Failed to process file ${fileName}:`, error);
console.error(`Failed to process file ${fileName}: ${error}`);
}
}

Expand Down
133 changes: 64 additions & 69 deletions src/test/run/generateTestReport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,38 @@ export enum testResult {
FAIL = "FAIL",
}

/**
* Determine the test result based on the similarity score.
* @param similarity The similarity score.
* @returns The test result.
*/
const determineTestResult = (similarity: number): testResult => {
// If the similarity score is more than 1 - threshold, then the test is considered as passing.
// Else if the similarity score is more than 1 - 2 * threshold, then the test is considered as warn. We display a complete report for this test but do not fail the test.
// Else, the test is considered as failing. We display a complete report for this test and fail the test.
const MAX_SIMILARITY_SCORE = 1;
if (similarity > MAX_SIMILARITY_SCORE - testThreshold) {
return testResult.PASS;
} else if (similarity > MAX_SIMILARITY_SCORE - 2 * testThreshold) {
return testResult.WARN;
} else {
return testResult.FAIL;
}
};

const formatTestResult = (result: testResult, message: string): string => {
switch (result) {
case testResult.PASS:
return chalk.green(`✅ [PASS] - ${message}`);
case testResult.WARN:
return chalk.yellow(`⚠️ [WARN] - ${message}`);
case testResult.FAIL:
return chalk.red(`❌ [FAIL] - ${message}`);
default:
throw new Error(`Unknown test result: ${result}`);
}
};

/**
* Generate a test report for a test case.
* @param testCase The test case.
Expand All @@ -25,33 +57,23 @@ export const generateTestReport = (
similarReview: string,
similarity: number
): { report: string; result: testResult } => {
// If the similarity score is more than 1 - threshold, then the test is considered as passing.
// Else if the similarity score is more than 1 - 2 * threshold, then the test is considered as warn. We display a complete report for this test but do not fail the test.
// Else, the test is considered as failing. We display a complete report for this test and fail the test.
if (similarity > 1 - testThreshold) {
return {
result: testResult.PASS,
report: chalk.green(
`[PASS] - Test case: ${testCase.name} - Similarity score: ${similarity}\n`
),
};
} else if (similarity > 1 - 2 * testThreshold) {
return {
result: testResult.WARN,
report:
chalk.yellow(
`[WARN] - Test case: ${testCase.name} - Similarity score: ${similarity}\n`
) + testReportTemplate(testCase, review, similarReview, similarity),
};
} else {
return {
result: testResult.FAIL,
report:
chalk.red(
`[FAIL] - Test case: ${testCase.name} - Similarity score: ${similarity}\n`
) + testReportTemplate(testCase, review, similarReview, similarity),
};
}
const result = determineTestResult(similarity);

const shouldDisplayDetailedReport = result !== testResult.PASS;

const report =
formatTestResult(
result,
`Test case: ${testCase.name} - Similarity score: ${similarity}\n`
) +
(shouldDisplayDetailedReport
? displayDetailedReport(testCase, review, similarReview)
: "");

return {
result,
report,
};
};

/**
Expand All @@ -62,14 +84,11 @@ export const generateTestReport = (
* @param similarity The similarity score between the review and the most similar review found in the vector store.
* @returns The test report template.
*/
const testReportTemplate = (
const displayDetailedReport = (
testCase: TestCase,
review: string,
similarReview: string,
similarity: number
similarReview: string
) => `
> Test case description: ${testCase.description}
> Test case snippet: ${testCase.snippet}
===============================================================================
Expand All @@ -80,29 +99,9 @@ ${review}
> Similar review:
${similarReview}
===============================================================================
> Similarity score: ${similarity}
`;

/**
* Generate a summary line for a test result.
* @param testName The name of the test case.
* @param result The test result.
* @returns The summary line.
*/
const summaryLineForTestResult = (testName: string, result: testResult) => {
switch (result) {
case testResult.PASS:
return chalk.green(`[PASS] - Test case: ${testName}`);
case testResult.WARN:
return chalk.yellow(`[WARN] - Test case: ${testName}`);
case testResult.FAIL:
return chalk.red(`[FAIL] - Test case: ${testName}`);
}
};

/**
* Generate a summary of the test results.
* @param testResults The test results.
Expand All @@ -111,28 +110,24 @@ const summaryLineForTestResult = (testName: string, result: testResult) => {
export const generateTestResultsSummary = (testResults: {
[key: string]: testResult;
}): string => {
const { detailedSummary: detailedSummary, counts } = Object.entries(
testResults
).reduce(
const summary = Object.entries(testResults).reduce(
(summary, [testCaseName, result]) => {
return {
detailedSummary:
summary.detailedSummary +
summaryLineForTestResult(testCaseName, result) +
"\n",
counts: { ...summary.counts, [result]: summary.counts[result] + 1 },
};
return (
summary + formatTestResult(result, `Test case: ${testCaseName}`) + "\n"
);
},
{
detailedSummary: chalk.blue(`\n### Test results summary:\n`),
counts: { PASS: 0, WARN: 0, FAIL: 0 },
}
chalk.blue(`\n### Test results summary:\n`)
);

const counts = Object.values(testResults).reduce((counts, result) => {
counts[result]++;
return counts;
}, Object.fromEntries(Object.values(testResult).map((result) => [result, 0])));

return (
detailedSummary +
`\n**SUMMARY: ${chalk.green(`✅ PASS: ${counts.PASS}`)}, ${chalk.yellow(
summary +
`\n**SUMMARY: ${chalk.green(`✅ PASS: ${counts.PASS}`)} - ${chalk.yellow(
`⚠️ WARN: ${counts.WARN}`
)}, ${chalk.red(`❌ FAIL: ${counts.FAIL}`)}**\n`
)} - ${chalk.red(`❌ FAIL: ${counts.FAIL}`)}**\n`
);
};

0 comments on commit e7867ec

Please sign in to comment.