Skip to content

Commit

Permalink
fix(incremental): correctly identify removed test files (#4134)
Browse files Browse the repository at this point in the history
Remove test files that no longer exist from the incremental report.
  • Loading branch information
mkizka committed May 5, 2023
1 parent bef2f8b commit 7342ac6
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 1 deletion.
7 changes: 6 additions & 1 deletion packages/core/src/mutants/incremental-differ.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,12 @@ export class IncrementalDiffer {
Object.entries(testFiles ?? {}).forEach(([fileName, oldTestFile]) => {
const relativeFileName = toRelativeNormalizedFileName(fileName);
const currentFileSource = currentRelativeFiles.get(relativeFileName);
if (currentFileSource !== undefined && oldTestFile.source !== undefined) {
if (currentFileSource === undefined && fileName !== '') {
// An empty file name means the test runner cannot report test file locations.
// If the current file is undefined while the test runner can report test file locations, it means it has been deleted
log.debug('Test file removed: %s', relativeFileName);
testStatisticsCollector.count(relativeFileName, 'removed', oldTestFile.tests.length);
} else if (currentFileSource !== undefined && oldTestFile.source !== undefined) {
log.trace('Diffing %s', relativeFileName);
const locatedTests = closeLocations(oldTestFile);
const { results, removeCount } = performFileDiff(oldTestFile.source, currentFileSource, locatedTests);
Expand Down
36 changes: 36 additions & 0 deletions packages/core/test/unit/mutants/incremental-differ.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,10 @@ class ScenarioBuilder {
});
this.incrementalTestFiles[testAdd] = factory.mutationTestReportSchemaTestFile({
tests: [{ id: this.oldSpecId, name: 'add(2, 0) = 2' }],
source: testAddContent,
});
this.currentFiles.set(srcAdd, srcAddContent);
this.currentFiles.set(testAdd, testAddContent);
this.testCoverage.addTest(factory.testResult({ id: this.newTestId, fileName: testAdd, name: 'add(2, 0) = 2' }));

if (isStatic) {
Expand Down Expand Up @@ -252,7 +254,9 @@ class ScenarioBuilder {
this.testCoverage.addCoverage(this.mutantId, [secondTest.id]);
return this;
}

public withSecondTestInIncrementalReport({ isKillingTest = false } = {}): this {
this.currentFiles.set(testAdd, testAddContentTwoTests);
this.incrementalTestFiles[testAdd].tests.unshift(
factory.mutationTestReportSchemaTestDefinition({ id: 'spec2', name: 'add(45, -3) = 42', location: loc(7, 0) })
);
Expand Down Expand Up @@ -417,6 +421,22 @@ class ScenarioBuilder {
return this;
}

public withRemovedTestFile(): this {
this.currentFiles.delete(testAdd);
this.testCoverage.clear();
this.testCoverage.hasCoverage = false;
return this;
}

public withEmptyFileNameTestFile(): this {
this.incrementalTestFiles[''] = this.incrementalTestFiles[testAdd];
delete this.incrementalTestFiles[testAdd];
this.testCoverage.clear();
this.testCoverage.addTest(factory.testResult({ id: this.newTestId, name: 'add(2, 0) = 2' }));
this.testCoverage.addCoverage(this.mutantId, [this.newTestId]);
return this;
}

public act() {
this.sut = testInjector.injector.injectClass(IncrementalDiffer);
deepFreeze(this.mutants); // make sure mutants aren't changed at all
Expand Down Expand Up @@ -526,6 +546,11 @@ describe(IncrementalDiffer.name, () => {
expect(actualDiff[0].status).eq(MutantStatus.Killed);
});

it('should reuse the status when there is a test with empty file name', () => {
const actualDiff = new ScenarioBuilder().withMathProjectExample().withEmptyFileNameTestFile().act();
expect(actualDiff[0].status).eq(MutantStatus.Killed);
});

it('should not copy the status if the mutant came from a different mutator', () => {
const scenario = new ScenarioBuilder().withMathProjectExample().withDifferentMutator('max-replacement');
const actualDiff = scenario.act();
Expand Down Expand Up @@ -772,6 +797,17 @@ describe(IncrementalDiffer.name, () => {
expect(changes).property('removed', 0);
});

it('should collect a removed test', () => {
const scenario = new ScenarioBuilder().withMathProjectExample().withRemovedTestFile();
scenario.act();
const actualCollector = scenario.sut!.testStatisticsCollector!;
expect(actualCollector.changesByFile).lengthOf(1);
const changes = actualCollector.changesByFile.get(testAdd)!;
expect(changes).property('added', 0);
expect(changes).property('removed', 1);
sinon.assert.calledWithExactly(testInjector.logger.debug, 'Test file removed: %s', testAdd);
});

it('should collect an added and removed test when a test changes', () => {
const scenario = new ScenarioBuilder()
.withMathProjectExample()
Expand Down

0 comments on commit 7342ac6

Please sign in to comment.