@noldova/context.testing 0.0.0-stage → 0.0.1
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.
- package/LICENSE +21 -0
- package/api/index.d.ts +2015 -0
- package/api/index.js +42 -0
- package/api/index.js.map +1 -0
- package/decorators/category.js +23 -0
- package/decorators/category.js.map +1 -0
- package/decorators/skip.js +17 -0
- package/decorators/skip.js.map +1 -0
- package/decorators/test-class.js +12 -0
- package/decorators/test-class.js.map +1 -0
- package/decorators/test-data.js +23 -0
- package/decorators/test-data.js.map +1 -0
- package/decorators/test-method.js +12 -0
- package/decorators/test-method.js.map +1 -0
- package/enums/test-outcome.js +14 -0
- package/enums/test-outcome.js.map +1 -0
- package/enums/test-worker-message-kind.js +17 -0
- package/enums/test-worker-message-kind.js.map +1 -0
- package/enums/test-worker-value-kind.js +16 -0
- package/enums/test-worker-value-kind.js.map +1 -0
- package/exceptions/assert-failed.exception.js +19 -0
- package/exceptions/assert-failed.exception.js.map +1 -0
- package/exceptions/test-timeout.exception.js +20 -0
- package/exceptions/test-timeout.exception.js.map +1 -0
- package/exceptions/testing.exception.js +14 -0
- package/exceptions/testing.exception.js.map +1 -0
- package/interfaces/i-clock.js +9 -0
- package/interfaces/i-clock.js.map +1 -0
- package/interfaces/i-coverage-range.js +9 -0
- package/interfaces/i-coverage-range.js.map +1 -0
- package/interfaces/i-coverage-report.js +9 -0
- package/interfaces/i-coverage-report.js.map +1 -0
- package/interfaces/i-function-coverage.js +9 -0
- package/interfaces/i-function-coverage.js.map +1 -0
- package/interfaces/i-script-coverage.js +9 -0
- package/interfaces/i-script-coverage.js.map +1 -0
- package/interfaces/i-source-map-data.js +9 -0
- package/interfaces/i-source-map-data.js.map +1 -0
- package/interfaces/i-test-progress-listener.js +9 -0
- package/interfaces/i-test-progress-listener.js.map +1 -0
- package/models/coverage/block-coverage.js +21 -0
- package/models/coverage/block-coverage.js.map +1 -0
- package/models/coverage/coverage-project.js +23 -0
- package/models/coverage/coverage-project.js.map +1 -0
- package/models/coverage/coverage-range.js +18 -0
- package/models/coverage/coverage-range.js.map +1 -0
- package/models/coverage/coverage-result.js +28 -0
- package/models/coverage/coverage-result.js.map +1 -0
- package/models/coverage/file-coverage.js +45 -0
- package/models/coverage/file-coverage.js.map +1 -0
- package/models/coverage/function-coverage.js +14 -0
- package/models/coverage/function-coverage.js.map +1 -0
- package/models/coverage/line-range.js +25 -0
- package/models/coverage/line-range.js.map +1 -0
- package/models/coverage/mapped-source-line.js +22 -0
- package/models/coverage/mapped-source-line.js.map +1 -0
- package/models/coverage/source-map-segment.js +18 -0
- package/models/coverage/source-map-segment.js.map +1 -0
- package/models/decorators/test-data-entry.js +17 -0
- package/models/decorators/test-data-entry.js.map +1 -0
- package/models/decorators/test-marks.js +16 -0
- package/models/decorators/test-marks.js.map +1 -0
- package/models/discovery/discovered-test-class.js +36 -0
- package/models/discovery/discovered-test-class.js.map +1 -0
- package/models/discovery/discovered-test-method.js +42 -0
- package/models/discovery/discovered-test-method.js.map +1 -0
- package/models/discovery/test-project.js +20 -0
- package/models/discovery/test-project.js.map +1 -0
- package/models/execution/test-worker-message.js +76 -0
- package/models/execution/test-worker-message.js.map +1 -0
- package/models/execution/test-worker-record.js +75 -0
- package/models/execution/test-worker-record.js.map +1 -0
- package/models/execution/test-worker-result.js +45 -0
- package/models/execution/test-worker-result.js.map +1 -0
- package/models/execution/test-worker-run.js +31 -0
- package/models/execution/test-worker-run.js.map +1 -0
- package/models/execution/test-worker-start.js +33 -0
- package/models/execution/test-worker-start.js.map +1 -0
- package/models/execution/test-worker-text.js +17 -0
- package/models/execution/test-worker-text.js.map +1 -0
- package/models/execution/test-worker-value.js +104 -0
- package/models/execution/test-worker-value.js.map +1 -0
- package/models/reporting/coverage-report-row.js +22 -0
- package/models/reporting/coverage-report-row.js.map +1 -0
- package/models/results/test-class-result.js +29 -0
- package/models/results/test-class-result.js.map +1 -0
- package/models/results/test-method-result.js +59 -0
- package/models/results/test-method-result.js.map +1 -0
- package/models/results/test-run-result.js +34 -0
- package/models/results/test-run-result.js.map +1 -0
- package/models/results/test-run-totals.js +36 -0
- package/models/results/test-run-totals.js.map +1 -0
- package/models/results/test-selection.js +33 -0
- package/models/results/test-selection.js.map +1 -0
- package/package.json +25 -4
- package/resources.js +309 -0
- package/resources.js.map +1 -0
- package/services/assert.js +92 -0
- package/services/assert.js.map +1 -0
- package/services/coverage/coverage-analyzer.js +52 -0
- package/services/coverage/coverage-analyzer.js.map +1 -0
- package/services/coverage/coverage-report.reader.js +126 -0
- package/services/coverage/coverage-report.reader.js.map +1 -0
- package/services/coverage/file-coverage-analyzer.js +206 -0
- package/services/coverage/file-coverage-analyzer.js.map +1 -0
- package/services/coverage/source-map.js +135 -0
- package/services/coverage/source-map.js.map +1 -0
- package/services/discovery/test-discovery.js +198 -0
- package/services/discovery/test-discovery.js.map +1 -0
- package/services/execution/parallel-test-runner.js +24 -0
- package/services/execution/parallel-test-runner.js.map +1 -0
- package/services/execution/test-executor.js +116 -0
- package/services/execution/test-executor.js.map +1 -0
- package/services/execution/test-run-entry-point.js +89 -0
- package/services/execution/test-run-entry-point.js.map +1 -0
- package/services/execution/test-run-supervisor.js +251 -0
- package/services/execution/test-run-supervisor.js.map +1 -0
- package/services/execution/test-run-worker-entry-point.js +18 -0
- package/services/execution/test-run-worker-entry-point.js.map +1 -0
- package/services/execution/test-run-worker.js +116 -0
- package/services/execution/test-run-worker.js.map +1 -0
- package/services/execution/test-runner.js +58 -0
- package/services/execution/test-runner.js.map +1 -0
- package/services/reporting/coverage-report-writer.js +81 -0
- package/services/reporting/coverage-report-writer.js.map +1 -0
- package/services/reporting/test-console-reporter.js +72 -0
- package/services/reporting/test-console-reporter.js.map +1 -0
- package/services/reporting/test-report-writer.js +111 -0
- package/services/reporting/test-report-writer.js.map +1 -0
- package/services/timing/system-clock.js +26 -0
- package/services/timing/system-clock.js.map +1 -0
- package/README.md +0 -3
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) Noldova.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
// This file uses Node APIs and will change when we replace Node.
|
|
9
|
+
import { resolve } from "node:path";
|
|
10
|
+
import { ArgumentException, ArgumentOutOfRangeException } from "@noldova/context.exceptions";
|
|
11
|
+
import { TestingException } from "../../exceptions/testing.exception.js";
|
|
12
|
+
import { MappedSourceLine } from "../../models/coverage/mapped-source-line.js";
|
|
13
|
+
import { SourceMapSegment } from "../../models/coverage/source-map-segment.js";
|
|
14
|
+
import { Resources } from "../../resources.js";
|
|
15
|
+
export class SourceMap {
|
|
16
|
+
sourcePaths;
|
|
17
|
+
nameCount;
|
|
18
|
+
segmentsByGeneratedLine;
|
|
19
|
+
constructor(data, mapDirectory) {
|
|
20
|
+
ArgumentException.throwIfNullOrWhitespace(mapDirectory, Resources.mapDirectoryParameter);
|
|
21
|
+
if (data.version !== Resources.sourceMapVersion)
|
|
22
|
+
throw new TestingException(Resources.sourceMapVersionInvalid(Resources.sourceMapVersion));
|
|
23
|
+
this.sourcePaths = data.sources.map(t => resolve(mapDirectory, data.sourceRoot ?? String.empty, t)
|
|
24
|
+
.replaceAll(Resources.windowsDirectorySeparator, Resources.directorySeparator));
|
|
25
|
+
this.nameCount = data.names?.length ?? 0;
|
|
26
|
+
this.segmentsByGeneratedLine = this.decodeMappings(data.mappings);
|
|
27
|
+
}
|
|
28
|
+
mapToSource(generatedLine, generatedColumn) {
|
|
29
|
+
if (!Number.isInteger(generatedLine) || generatedLine < 1)
|
|
30
|
+
throw new ArgumentOutOfRangeException(Resources.generatedLineParameter, generatedLine, Resources.generatedLineInvalid);
|
|
31
|
+
if (!Number.isInteger(generatedColumn) || generatedColumn < 0)
|
|
32
|
+
throw new ArgumentOutOfRangeException(Resources.generatedColumnParameter, generatedColumn, Resources.generatedColumnInvalid);
|
|
33
|
+
const segment = this.findSegment(generatedLine, generatedColumn);
|
|
34
|
+
if (Object.isUndefined(segment?.sourcePath) || Object.isUndefined(segment.sourceLine))
|
|
35
|
+
return undefined;
|
|
36
|
+
return new MappedSourceLine(segment.sourcePath, segment.sourceLine + 1);
|
|
37
|
+
}
|
|
38
|
+
findSegment(generatedLine, generatedColumn) {
|
|
39
|
+
const segments = this.segmentsByGeneratedLine[generatedLine - 1];
|
|
40
|
+
if (Object.isUndefined(segments))
|
|
41
|
+
return undefined;
|
|
42
|
+
let found;
|
|
43
|
+
for (const segment of segments) {
|
|
44
|
+
if (segment.generatedColumn > generatedColumn)
|
|
45
|
+
break;
|
|
46
|
+
found = segment;
|
|
47
|
+
}
|
|
48
|
+
return found;
|
|
49
|
+
}
|
|
50
|
+
decodeMappings(mappings) {
|
|
51
|
+
const segmentsByGeneratedLine = [];
|
|
52
|
+
let sourceIndex = 0;
|
|
53
|
+
let sourceLine = 0;
|
|
54
|
+
let sourceColumn = 0;
|
|
55
|
+
let nameIndex = 0;
|
|
56
|
+
for (const lineText of mappings.split(Resources.sourceMapLineSeparator)) {
|
|
57
|
+
const segments = [];
|
|
58
|
+
let generatedColumn = 0;
|
|
59
|
+
let previousGeneratedColumn = -1;
|
|
60
|
+
for (const segmentText of lineText.split(Resources.sourceMapSegmentSeparator)) {
|
|
61
|
+
if (segmentText === String.empty)
|
|
62
|
+
continue;
|
|
63
|
+
const values = this.decodeVlqValues(segmentText);
|
|
64
|
+
if (values.length !== 1 && values.length !== 4 && values.length !== 5)
|
|
65
|
+
throw new TestingException(Resources.sourceMapSegmentFieldCountInvalid);
|
|
66
|
+
for (const [fieldIndex, fieldValue] of values.entries()) {
|
|
67
|
+
switch (fieldIndex) {
|
|
68
|
+
case 0:
|
|
69
|
+
generatedColumn += fieldValue;
|
|
70
|
+
break;
|
|
71
|
+
case 1:
|
|
72
|
+
sourceIndex += fieldValue;
|
|
73
|
+
break;
|
|
74
|
+
case 2:
|
|
75
|
+
sourceLine += fieldValue;
|
|
76
|
+
break;
|
|
77
|
+
case 3:
|
|
78
|
+
sourceColumn += fieldValue;
|
|
79
|
+
break;
|
|
80
|
+
case 4:
|
|
81
|
+
nameIndex += fieldValue;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (generatedColumn < 0)
|
|
86
|
+
throw new TestingException(Resources.sourceMapGeneratedColumnInvalid);
|
|
87
|
+
if (generatedColumn < previousGeneratedColumn)
|
|
88
|
+
throw new TestingException(Resources.sourceMapGeneratedColumnOrderInvalid);
|
|
89
|
+
previousGeneratedColumn = generatedColumn;
|
|
90
|
+
if (values.length === 1) {
|
|
91
|
+
segments.push(new SourceMapSegment(generatedColumn));
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const sourcePath = this.sourcePaths[sourceIndex];
|
|
95
|
+
if (Object.isUndefined(sourcePath) || sourceLine < 0 || sourceColumn < 0)
|
|
96
|
+
throw new TestingException(Resources.sourceMapOriginalPositionInvalid);
|
|
97
|
+
if (values.length === 5) {
|
|
98
|
+
if (nameIndex < 0 || nameIndex >= this.nameCount)
|
|
99
|
+
throw new TestingException(Resources.sourceMapNameIndexInvalid);
|
|
100
|
+
}
|
|
101
|
+
segments.push(new SourceMapSegment(generatedColumn, sourcePath, sourceLine));
|
|
102
|
+
}
|
|
103
|
+
segmentsByGeneratedLine.push(segments);
|
|
104
|
+
}
|
|
105
|
+
return segmentsByGeneratedLine;
|
|
106
|
+
}
|
|
107
|
+
decodeVlqValues(segmentText) {
|
|
108
|
+
const values = [];
|
|
109
|
+
let value = 0;
|
|
110
|
+
let multiplier = 1;
|
|
111
|
+
let isContinued = false;
|
|
112
|
+
for (const character of segmentText) {
|
|
113
|
+
const digit = Resources.sourceMapBase64Alphabet.indexOf(character);
|
|
114
|
+
if (digit === -1)
|
|
115
|
+
throw new TestingException(Resources.sourceMapCharacterInvalid(character));
|
|
116
|
+
value += (digit & Resources.sourceMapValueMask) * multiplier;
|
|
117
|
+
if (!Number.isSafeInteger(value))
|
|
118
|
+
throw new TestingException(Resources.sourceMapIntegerUnsupported);
|
|
119
|
+
isContinued = (digit & Resources.sourceMapContinuationBit) !== 0;
|
|
120
|
+
if (isContinued) {
|
|
121
|
+
multiplier *= 32;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const isNegative = value % 2 === 1;
|
|
125
|
+
const magnitude = Math.floor(value / 2);
|
|
126
|
+
values.push(isNegative ? -magnitude : magnitude);
|
|
127
|
+
value = 0;
|
|
128
|
+
multiplier = 1;
|
|
129
|
+
}
|
|
130
|
+
if (isContinued)
|
|
131
|
+
throw new TestingException(Resources.sourceMapMappingTruncated);
|
|
132
|
+
return values;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=source-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-map.js","sourceRoot":"","sources":["../../../../../src/noldova.context.testing/src/services/coverage/source-map.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) Noldova.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
// This file uses Node APIs and will change when we replace Node.
|
|
9
|
+
import { readdir } from "node:fs/promises";
|
|
10
|
+
import { join, relative } from "node:path";
|
|
11
|
+
import { pathToFileURL } from "node:url";
|
|
12
|
+
import { isGeneratorFunction } from "node:util/types";
|
|
13
|
+
import { nameof } from "@noldova/context.core";
|
|
14
|
+
import { ArgumentException } from "@noldova/context.exceptions";
|
|
15
|
+
import { TestingException } from "../../exceptions/testing.exception.js";
|
|
16
|
+
import { TestDataEntry } from "../../models/decorators/test-data-entry.js";
|
|
17
|
+
import { TestMarks } from "../../models/decorators/test-marks.js";
|
|
18
|
+
import { DiscoveredTestClass } from "../../models/discovery/discovered-test-class.js";
|
|
19
|
+
import { DiscoveredTestMethod } from "../../models/discovery/discovered-test-method.js";
|
|
20
|
+
import { Resources } from "../../resources.js";
|
|
21
|
+
export class TestDiscovery {
|
|
22
|
+
async discoverAsync(testProjects, onFileImported = () => undefined) {
|
|
23
|
+
const testClasses = [];
|
|
24
|
+
const sortedProjects = [...testProjects]
|
|
25
|
+
.sort((first, second) => this.compareProjects(first, second));
|
|
26
|
+
for (const testProject of sortedProjects) {
|
|
27
|
+
for (const testFile of await this.findTestFilesAsync(testProject.rootDirectory)) {
|
|
28
|
+
const filePath = relative(testProject.rootDirectory, testFile).replaceAll(Resources.windowsDirectorySeparator, Resources.directorySeparator);
|
|
29
|
+
const moduleExports = await import(pathToFileURL(testFile).href);
|
|
30
|
+
onFileImported(filePath);
|
|
31
|
+
testClasses.push(...this.discoverModuleExports(moduleExports, filePath, testProject.packageName));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return testClasses;
|
|
35
|
+
}
|
|
36
|
+
discoverModuleExports(moduleExports, filePath, packageName) {
|
|
37
|
+
ArgumentException.throwIfNullOrWhitespace(filePath, Resources.filePathParameter);
|
|
38
|
+
ArgumentException.throwIfNullOrWhitespace(packageName, Resources.packageNameParameter);
|
|
39
|
+
const testClasses = [];
|
|
40
|
+
for (const exportName of Object.keys(moduleExports).sort()) {
|
|
41
|
+
const exportedValue = this.getOwnDataProperty(moduleExports, exportName);
|
|
42
|
+
const isNamed = exportName.endsWith(Resources.testClassSuffix);
|
|
43
|
+
if (!this.isMarkedTestClass(exportedValue)) {
|
|
44
|
+
if (this.hasCategories(exportedValue))
|
|
45
|
+
throw new TestingException(Resources.categoryWithoutTestClass(exportName, filePath));
|
|
46
|
+
if (Object.isFunction(exportedValue) && Object.hasOwn(exportedValue, TestMarks.SKIP))
|
|
47
|
+
throw new TestingException(Resources.skipWithoutTestClass(exportName, filePath));
|
|
48
|
+
if (isNamed)
|
|
49
|
+
throw new TestingException(Resources.unmarkedNamedTestClass(exportName, filePath));
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (!isNamed)
|
|
53
|
+
throw new TestingException(Resources.markedTestClassWithoutRequiredName(exportName, filePath, Resources.testClassSuffix));
|
|
54
|
+
testClasses.push(this.discoverTestClass(exportName, exportedValue, filePath, packageName));
|
|
55
|
+
}
|
|
56
|
+
if (testClasses.length === 0)
|
|
57
|
+
throw new TestingException(Resources.testFileWithoutTestClass(filePath));
|
|
58
|
+
return testClasses;
|
|
59
|
+
}
|
|
60
|
+
discoverTestClass(className, testClassConstructor, filePath, packageName) {
|
|
61
|
+
const prototype = testClassConstructor.prototype;
|
|
62
|
+
if (!Object.isObject(prototype) || Object.isFunction(prototype))
|
|
63
|
+
throw new TestingException(Resources.testClassWithoutPrototype(className, filePath));
|
|
64
|
+
const classCategories = this.getCategories(testClassConstructor);
|
|
65
|
+
for (const memberName of [...Object.getOwnPropertyNames(testClassConstructor).sort(), ...Object.getOwnPropertySymbols(testClassConstructor)]) {
|
|
66
|
+
const descriptor = Object.getOwnPropertyDescriptor(testClassConstructor, memberName);
|
|
67
|
+
if (this.descriptorHasTestMetadata(descriptor))
|
|
68
|
+
throw new TestingException(Resources.staticTestMetadataInvalid(String(memberName), className, filePath));
|
|
69
|
+
}
|
|
70
|
+
const methods = [];
|
|
71
|
+
for (const memberName of [...Object.getOwnPropertyNames(prototype).sort(), ...Object.getOwnPropertySymbols(prototype)]) {
|
|
72
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, memberName);
|
|
73
|
+
if (Object.isSymbol(memberName)) {
|
|
74
|
+
if (this.descriptorHasTestMetadata(descriptor))
|
|
75
|
+
throw new TestingException(Resources.symbolTestMetadataInvalid(className, filePath));
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (memberName === nameof(t => t.constructor))
|
|
79
|
+
continue;
|
|
80
|
+
if (!Object.isUndefined(descriptor.get) || !Object.isUndefined(descriptor.set)) {
|
|
81
|
+
if (this.descriptorHasTestMetadata(descriptor))
|
|
82
|
+
throw new TestingException(Resources.accessorTestMetadataInvalid(memberName, className, filePath));
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const member = this.getOwnDataProperty(prototype, memberName);
|
|
86
|
+
const testDataEntries = this.getTestDataEntries(member);
|
|
87
|
+
const methodCategories = this.getCategories(member);
|
|
88
|
+
if (!this.isMarkedTestMethod(member)) {
|
|
89
|
+
if (!Object.isUndefined(testDataEntries))
|
|
90
|
+
throw new TestingException(Resources.testDataWithoutTestMethod(memberName, className, filePath));
|
|
91
|
+
if (methodCategories.length > 0)
|
|
92
|
+
throw new TestingException(Resources.categoryWithoutTestMethod(memberName, className, filePath));
|
|
93
|
+
if (Object.isFunction(member) && Object.hasOwn(member, TestMarks.SKIP))
|
|
94
|
+
throw new TestingException(Resources.skipWithoutTestMethod(memberName, className, filePath));
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (isGeneratorFunction(member))
|
|
98
|
+
throw new TestingException(Resources.generatorTestMethodInvalid(memberName, className, filePath));
|
|
99
|
+
const skipReason = this.getSkipReason(member);
|
|
100
|
+
const categories = [...classCategories, ...methodCategories];
|
|
101
|
+
if (Object.isUndefined(testDataEntries)) {
|
|
102
|
+
if (member.length > 0)
|
|
103
|
+
throw new TestingException(Resources.testMethodRequiresData(memberName, className, filePath));
|
|
104
|
+
methods.push(new DiscoveredTestMethod(memberName, undefined, [], skipReason, categories));
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
for (let index = 0; index < testDataEntries.length; index++) {
|
|
108
|
+
const testDataEntry = testDataEntries[index];
|
|
109
|
+
if (Object.isUndefined(testDataEntry))
|
|
110
|
+
throw new TestingException(Resources.testDataMarkInvalid);
|
|
111
|
+
if (testDataEntry.values.length !== member.length)
|
|
112
|
+
throw new TestingException(Resources.testDataParameterCountMismatch(memberName, className, filePath, member.length, testDataEntry.values.length));
|
|
113
|
+
methods.push(new DiscoveredTestMethod(memberName, index, testDataEntry.values, skipReason, categories));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (methods.length === 0)
|
|
117
|
+
throw new TestingException(Resources.testClassWithoutTestMethod(className, filePath));
|
|
118
|
+
return new DiscoveredTestClass(packageName, className, filePath, testClassConstructor, this.getSkipReason(testClassConstructor), methods, classCategories);
|
|
119
|
+
}
|
|
120
|
+
async findTestFilesAsync(rootDirectory) {
|
|
121
|
+
ArgumentException.throwIfNullOrWhitespace(rootDirectory, Resources.rootDirectoryParameter);
|
|
122
|
+
const entries = await readdir(rootDirectory, { recursive: true, withFileTypes: true });
|
|
123
|
+
const testFiles = [];
|
|
124
|
+
for (const entry of entries)
|
|
125
|
+
if (entry.isFile() && entry.name.endsWith(Resources.testFileSuffix))
|
|
126
|
+
testFiles.push(join(entry.parentPath, entry.name));
|
|
127
|
+
return testFiles.sort();
|
|
128
|
+
}
|
|
129
|
+
isMarkedTestClass(value) {
|
|
130
|
+
if (!Object.isFunction(value) || !Object.hasOwn(value, TestMarks.TEST_CLASS))
|
|
131
|
+
return false;
|
|
132
|
+
if (this.getOwnDataProperty(value, TestMarks.TEST_CLASS) !== true)
|
|
133
|
+
throw new TestingException(Resources.testClassMarkInvalid);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
isMarkedTestMethod(value) {
|
|
137
|
+
if (!Object.isFunction(value) || !Object.hasOwn(value, TestMarks.TEST_METHOD))
|
|
138
|
+
return false;
|
|
139
|
+
if (this.getOwnDataProperty(value, TestMarks.TEST_METHOD) !== true)
|
|
140
|
+
throw new TestingException(Resources.testMethodMarkInvalid);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
hasTestData(value) {
|
|
144
|
+
return Object.isFunction(value) && Object.hasOwn(value, TestMarks.TEST_DATA);
|
|
145
|
+
}
|
|
146
|
+
hasCategories(value) {
|
|
147
|
+
return Object.isFunction(value) && Object.hasOwn(value, TestMarks.CATEGORY);
|
|
148
|
+
}
|
|
149
|
+
getCategories(value) {
|
|
150
|
+
if (!this.hasCategories(value))
|
|
151
|
+
return [];
|
|
152
|
+
const markedCategories = this.getOwnDataProperty(value, TestMarks.CATEGORY);
|
|
153
|
+
if (!Array.isArray(markedCategories) || markedCategories.length === 0)
|
|
154
|
+
throw new TestingException(Resources.categoryMarkInvalid);
|
|
155
|
+
const categories = [];
|
|
156
|
+
for (const category of markedCategories) {
|
|
157
|
+
if (!Object.isString(category) || String.isNullOrWhitespace(category))
|
|
158
|
+
throw new TestingException(Resources.categoryMarkInvalid);
|
|
159
|
+
categories.push(category);
|
|
160
|
+
}
|
|
161
|
+
return [...new Set(categories)];
|
|
162
|
+
}
|
|
163
|
+
getTestDataEntries(value) {
|
|
164
|
+
if (!this.hasTestData(value))
|
|
165
|
+
return undefined;
|
|
166
|
+
const entries = this.getOwnDataProperty(value, TestMarks.TEST_DATA);
|
|
167
|
+
if (!Array.isArray(entries) || entries.length === 0 || entries.some(t => !(t instanceof TestDataEntry)))
|
|
168
|
+
throw new TestingException(Resources.testDataMarkInvalid);
|
|
169
|
+
return entries;
|
|
170
|
+
}
|
|
171
|
+
getSkipReason(value) {
|
|
172
|
+
if (!Object.hasOwn(value, TestMarks.SKIP))
|
|
173
|
+
return undefined;
|
|
174
|
+
const reason = this.getOwnDataProperty(value, TestMarks.SKIP);
|
|
175
|
+
if (!Object.isString(reason) || String.isNullOrWhitespace(reason))
|
|
176
|
+
throw new TestingException(Resources.skipReasonInvalid);
|
|
177
|
+
return reason;
|
|
178
|
+
}
|
|
179
|
+
descriptorHasTestMetadata(descriptor) {
|
|
180
|
+
return this.hasTestMetadata(descriptor.value)
|
|
181
|
+
|| this.hasTestMetadata(descriptor.get)
|
|
182
|
+
|| this.hasTestMetadata(descriptor.set);
|
|
183
|
+
}
|
|
184
|
+
hasTestMetadata(value) {
|
|
185
|
+
return Object.isFunction(value)
|
|
186
|
+
&& (this.isMarkedTestMethod(value) || this.hasTestData(value) || this.hasCategories(value) || Object.hasOwn(value, TestMarks.SKIP));
|
|
187
|
+
}
|
|
188
|
+
getOwnDataProperty(value, propertyKey) {
|
|
189
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, propertyKey);
|
|
190
|
+
return !Object.isUndefined(descriptor) && Object.hasOwn(descriptor, nameof(t => t.value)) ? descriptor.value : undefined;
|
|
191
|
+
}
|
|
192
|
+
compareProjects(first, second) {
|
|
193
|
+
if (first.packageName !== second.packageName)
|
|
194
|
+
return first.packageName < second.packageName ? -1 : 1;
|
|
195
|
+
return first.rootDirectory === second.rootDirectory ? 0 : first.rootDirectory < second.rootDirectory ? -1 : 1;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=test-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-discovery.js","sourceRoot":"","sources":["../../../../../src/noldova.context.testing/src/services/discovery/test-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) Noldova.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import { SystemClock } from "../timing/system-clock.js";
|
|
9
|
+
import { TestRunSupervisor } from "./test-run-supervisor.js";
|
|
10
|
+
export class ParallelTestRunner {
|
|
11
|
+
timeoutMilliseconds;
|
|
12
|
+
workerCount;
|
|
13
|
+
clock;
|
|
14
|
+
constructor(timeoutMilliseconds, workerCount = TestRunSupervisor.defaultWorkerCount(), clock = new SystemClock()) {
|
|
15
|
+
TestRunSupervisor.throwIfLimitsInvalid(timeoutMilliseconds, workerCount);
|
|
16
|
+
this.timeoutMilliseconds = timeoutMilliseconds;
|
|
17
|
+
this.workerCount = workerCount;
|
|
18
|
+
this.clock = clock;
|
|
19
|
+
}
|
|
20
|
+
runAsync(testProjects, filters = [], progressListener) {
|
|
21
|
+
return new TestRunSupervisor(this.timeoutMilliseconds, testProjects, filters, progressListener, undefined, this.workerCount, undefined, undefined, this.clock).runAsync();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=parallel-test-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallel-test-runner.js","sourceRoot":"","sources":["../../../../../src/noldova.context.testing/src/services/execution/parallel-test-runner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,OAAO,kBAAkB;IACZ,mBAAmB,CAAS;IAC5B,WAAW,CAAS;IACpB,KAAK,CAAS;IAE/B,YAAmB,mBAA2B,EAAE,WAAW,GAAW,iBAAiB,CAAC,kBAAkB,EAAE,EAAE,KAAK,GAAW,IAAI,WAAW,EAAE;QAC7I,iBAAiB,CAAC,oBAAoB,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;QAEzE,IAAI,CAAC,mBAAmB,GAAG,mBAAmB,CAAC;QAC/C,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAEM,QAAQ,CAAC,YAAoC,EAAE,OAAO,GAAsB,EAAE,EAAE,gBAAwC;QAC7H,OAAO,IAAI,iBAAiB,CAAC,IAAI,CAAC,mBAAmB,EAAE,YAAY,EAAE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,SAAS,EAC/I,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) Noldova.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
// This file uses Node APIs and will change when we replace Node.
|
|
9
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
|
+
import { ArgumentOutOfRangeException } from "@noldova/context.exceptions";
|
|
11
|
+
import { TestOutcome } from "../../enums/test-outcome.js";
|
|
12
|
+
import { TestTimeoutException } from "../../exceptions/test-timeout.exception.js";
|
|
13
|
+
import { TestingException } from "../../exceptions/testing.exception.js";
|
|
14
|
+
import { TestClassResult } from "../../models/results/test-class-result.js";
|
|
15
|
+
import { TestMethodResult } from "../../models/results/test-method-result.js";
|
|
16
|
+
import { Resources } from "../../resources.js";
|
|
17
|
+
import { SystemClock } from "../timing/system-clock.js";
|
|
18
|
+
export class TestExecutor {
|
|
19
|
+
static REJECTION_STORAGE = new AsyncLocalStorage();
|
|
20
|
+
static ON_UNHANDLED_REJECTION = (t) => {
|
|
21
|
+
const rejections = TestExecutor.REJECTION_STORAGE.getStore();
|
|
22
|
+
if (Object.isUndefined(rejections))
|
|
23
|
+
throw t;
|
|
24
|
+
rejections.push(t);
|
|
25
|
+
};
|
|
26
|
+
timeoutMilliseconds;
|
|
27
|
+
clock;
|
|
28
|
+
constructor(timeoutMilliseconds, clock = new SystemClock()) {
|
|
29
|
+
ArgumentOutOfRangeException.throwIfNotPositiveInteger(timeoutMilliseconds, Resources.timeoutMillisecondsParameter, Resources.timeoutInvalid);
|
|
30
|
+
if (timeoutMilliseconds > Resources.maximumTimeoutMilliseconds)
|
|
31
|
+
throw new ArgumentOutOfRangeException(Resources.timeoutMillisecondsParameter, timeoutMilliseconds, Resources.timeoutTooLarge);
|
|
32
|
+
this.timeoutMilliseconds = timeoutMilliseconds;
|
|
33
|
+
this.clock = clock;
|
|
34
|
+
}
|
|
35
|
+
async executeAsync(testClasses, progressListener, stoppedMethods = new Set(), isStopping) {
|
|
36
|
+
const ownsRejectionListener = !process.listeners(Resources.unhandledRejectionEvent).includes(TestExecutor.ON_UNHANDLED_REJECTION);
|
|
37
|
+
if (ownsRejectionListener)
|
|
38
|
+
process.on(Resources.unhandledRejectionEvent, TestExecutor.ON_UNHANDLED_REJECTION);
|
|
39
|
+
try {
|
|
40
|
+
const classResults = [];
|
|
41
|
+
for (const testClass of testClasses) {
|
|
42
|
+
const methodResults = [];
|
|
43
|
+
for (const method of testClass.methods) {
|
|
44
|
+
if (isStopping?.() === true)
|
|
45
|
+
return classResults;
|
|
46
|
+
progressListener?.onMethodStarted?.(testClass, method);
|
|
47
|
+
const methodResult = stoppedMethods.has(method) ? this.createStoppedResult(testClass, method) : await this.executeMethodAsync(testClass, method);
|
|
48
|
+
methodResults.push(methodResult);
|
|
49
|
+
progressListener?.onMethodCompleted?.(methodResult);
|
|
50
|
+
}
|
|
51
|
+
const classResult = new TestClassResult(testClass.packageName, testClass.className, testClass.filePath, methodResults);
|
|
52
|
+
classResults.push(classResult);
|
|
53
|
+
progressListener?.onClassCompleted(classResult);
|
|
54
|
+
}
|
|
55
|
+
return classResults;
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
if (ownsRejectionListener)
|
|
59
|
+
process.off(Resources.unhandledRejectionEvent, TestExecutor.ON_UNHANDLED_REJECTION);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
createStoppedResult(testClass, method) {
|
|
63
|
+
return new TestMethodResult(testClass.packageName, testClass.className, method.methodName, method.testDataIndex, method.testData, TestOutcome.Failed, this.timeoutMilliseconds, new TestTimeoutException(this.timeoutMilliseconds), undefined);
|
|
64
|
+
}
|
|
65
|
+
async executeMethodAsync(testClass, method) {
|
|
66
|
+
const skipReason = method.skipReason ?? testClass.skipReason;
|
|
67
|
+
if (!Object.isUndefined(skipReason))
|
|
68
|
+
return new TestMethodResult(testClass.packageName, testClass.className, method.methodName, method.testDataIndex, method.testData, TestOutcome.Skipped, 0, undefined, skipReason);
|
|
69
|
+
const start = this.clock.now();
|
|
70
|
+
const unhandledRejections = [];
|
|
71
|
+
let didFail = false;
|
|
72
|
+
let failure;
|
|
73
|
+
try {
|
|
74
|
+
await TestExecutor.REJECTION_STORAGE.run(unhandledRejections, async () => {
|
|
75
|
+
try {
|
|
76
|
+
await this.invokeWithTimeoutAsync(testClass, method);
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
await this.drainPendingRejectionsAsync();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
if (unhandledRejections.length > 0) {
|
|
83
|
+
didFail = true;
|
|
84
|
+
failure = unhandledRejections[0];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
didFail = true;
|
|
89
|
+
failure = error;
|
|
90
|
+
}
|
|
91
|
+
const durationMilliseconds = this.clock.now() - start;
|
|
92
|
+
if (didFail)
|
|
93
|
+
return new TestMethodResult(testClass.packageName, testClass.className, method.methodName, method.testDataIndex, method.testData, TestOutcome.Failed, durationMilliseconds, failure, undefined);
|
|
94
|
+
return new TestMethodResult(testClass.packageName, testClass.className, method.methodName, method.testDataIndex, method.testData, TestOutcome.Passed, durationMilliseconds, undefined, undefined);
|
|
95
|
+
}
|
|
96
|
+
async invokeWithTimeoutAsync(testClass, method) {
|
|
97
|
+
const instance = new testClass.testClassConstructor();
|
|
98
|
+
const testMethod = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(instance), method.methodName)?.value;
|
|
99
|
+
if (!Object.isFunction(testMethod))
|
|
100
|
+
throw new TestingException(Resources.methodNotCallable(method.methodName, testClass.className));
|
|
101
|
+
let timeoutHandle;
|
|
102
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
103
|
+
timeoutHandle = this.clock.setTimeout(() => reject(new TestTimeoutException(this.timeoutMilliseconds)), this.timeoutMilliseconds);
|
|
104
|
+
});
|
|
105
|
+
try {
|
|
106
|
+
await Promise.race([Promise.resolve(testMethod.call(instance, ...method.testData)), timeoutPromise]);
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
this.clock.clearTimeout(timeoutHandle);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async drainPendingRejectionsAsync() {
|
|
113
|
+
await new Promise(t => setImmediate(t));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=test-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-executor.js","sourceRoot":"","sources":["../../../../../src/noldova.context.testing/src/services/execution/test-executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) Noldova.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
// This file uses Node APIs and will change when we replace Node.
|
|
9
|
+
import { mkdtemp, readdir, rm } from "node:fs/promises";
|
|
10
|
+
import { tmpdir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import "@noldova/context.core";
|
|
13
|
+
import { ExceptionOptions } from "@noldova/context.exceptions";
|
|
14
|
+
import { TestingException } from "../../exceptions/testing.exception.js";
|
|
15
|
+
import { TestProject } from "../../models/discovery/test-project.js";
|
|
16
|
+
import { TestRunTotals } from "../../models/results/test-run-totals.js";
|
|
17
|
+
import { Resources } from "../../resources.js";
|
|
18
|
+
import { TestConsoleReporter } from "../reporting/test-console-reporter.js";
|
|
19
|
+
import { TestRunSupervisor } from "./test-run-supervisor.js";
|
|
20
|
+
export class TestRunEntryPoint {
|
|
21
|
+
async runAsync() {
|
|
22
|
+
const testProjectArguments = process.argv.slice(2);
|
|
23
|
+
const skipPassingDetails = !Object.isUndefined(process.env[Resources.skipTestDetailsVariable]);
|
|
24
|
+
const reporter = new TestConsoleReporter(t => process.stdout.write(t), process.stdout.isTTY === true, skipPassingDetails);
|
|
25
|
+
const temporaryDirectory = await this.isolateTemporaryFilesAsync();
|
|
26
|
+
try {
|
|
27
|
+
const filters = this.parseFilters(process.env[Resources.filtersVariable]);
|
|
28
|
+
const testProjects = [];
|
|
29
|
+
for (let index = 0; index < testProjectArguments.length; index += 2) {
|
|
30
|
+
const packageName = testProjectArguments[index];
|
|
31
|
+
const rootDirectory = testProjectArguments[index + 1];
|
|
32
|
+
if (Object.isUndefined(packageName) || Object.isUndefined(rootDirectory))
|
|
33
|
+
throw new TestingException(Resources.testProjectPairRequired);
|
|
34
|
+
testProjects.push(new TestProject(packageName, rootDirectory));
|
|
35
|
+
}
|
|
36
|
+
const supervisor = new TestRunSupervisor(Resources.defaultTimeoutMilliseconds, testProjects, filters, reporter);
|
|
37
|
+
reporter.start();
|
|
38
|
+
const result = await supervisor.runAsync();
|
|
39
|
+
const totals = new TestRunTotals(result.passed, result.failed, result.skipped, supervisor.elapsedMilliseconds);
|
|
40
|
+
reporter.writeSummary(totals, supervisor.selection);
|
|
41
|
+
if (supervisor.selection.isFiltered && supervisor.selection.selected === 0)
|
|
42
|
+
console.error(Resources.noTestMatchedFilters);
|
|
43
|
+
process.exitCode = Math.min(totals.failed + Number(totals.total === 0), 1);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
reporter.stop();
|
|
47
|
+
console.error(String(error));
|
|
48
|
+
process.exitCode = 1;
|
|
49
|
+
}
|
|
50
|
+
const leftovers = await this.removeTemporaryFilesAsync(temporaryDirectory);
|
|
51
|
+
if (leftovers.length > 0) {
|
|
52
|
+
console.error(Resources.formatTemporaryLeftovers(leftovers));
|
|
53
|
+
process.exitCode = 1;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async isolateTemporaryFilesAsync() {
|
|
57
|
+
const directory = await mkdtemp(join(tmpdir(), Resources.temporaryDirectoryPrefix));
|
|
58
|
+
for (const variable of Resources.temporaryDirectoryVariables)
|
|
59
|
+
process.env[variable] = directory;
|
|
60
|
+
return directory;
|
|
61
|
+
}
|
|
62
|
+
async removeTemporaryFilesAsync(directory) {
|
|
63
|
+
const leftovers = (await readdir(directory)).sort();
|
|
64
|
+
await rm(directory, { recursive: true, force: true, maxRetries: Resources.temporaryRemovalRetries });
|
|
65
|
+
return leftovers;
|
|
66
|
+
}
|
|
67
|
+
parseFilters(text) {
|
|
68
|
+
if (Object.isUndefined(text))
|
|
69
|
+
throw new TestingException(Resources.testFiltersInvalid);
|
|
70
|
+
let value;
|
|
71
|
+
try {
|
|
72
|
+
value = JSON.parse(text);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
throw new TestingException(Resources.testFiltersInvalid, new ExceptionOptions(error));
|
|
76
|
+
}
|
|
77
|
+
if (!Array.isArray(value))
|
|
78
|
+
throw new TestingException(Resources.testFiltersInvalid);
|
|
79
|
+
const filters = [];
|
|
80
|
+
for (const filter of value) {
|
|
81
|
+
if (!Object.isString(filter))
|
|
82
|
+
throw new TestingException(Resources.testFiltersInvalid);
|
|
83
|
+
filters.push(filter);
|
|
84
|
+
}
|
|
85
|
+
return filters;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
await new TestRunEntryPoint().runAsync();
|
|
89
|
+
//# sourceMappingURL=test-run-entry-point.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-run-entry-point.js","sourceRoot":"","sources":["../../../../../src/noldova.context.testing/src/services/execution/test-run-entry-point.ts"],"names":[],"mappings":"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"}
|