@noldova/context.testing 0.0.0-stage → 0.0.2

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.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/api/index.d.ts +2015 -0
  3. package/api/index.js +42 -0
  4. package/api/index.js.map +1 -0
  5. package/decorators/category.js +23 -0
  6. package/decorators/category.js.map +1 -0
  7. package/decorators/skip.js +17 -0
  8. package/decorators/skip.js.map +1 -0
  9. package/decorators/test-class.js +12 -0
  10. package/decorators/test-class.js.map +1 -0
  11. package/decorators/test-data.js +23 -0
  12. package/decorators/test-data.js.map +1 -0
  13. package/decorators/test-method.js +12 -0
  14. package/decorators/test-method.js.map +1 -0
  15. package/enums/test-outcome.js +14 -0
  16. package/enums/test-outcome.js.map +1 -0
  17. package/enums/test-worker-message-kind.js +17 -0
  18. package/enums/test-worker-message-kind.js.map +1 -0
  19. package/enums/test-worker-value-kind.js +16 -0
  20. package/enums/test-worker-value-kind.js.map +1 -0
  21. package/exceptions/assert-failed.exception.js +19 -0
  22. package/exceptions/assert-failed.exception.js.map +1 -0
  23. package/exceptions/test-timeout.exception.js +20 -0
  24. package/exceptions/test-timeout.exception.js.map +1 -0
  25. package/exceptions/testing.exception.js +14 -0
  26. package/exceptions/testing.exception.js.map +1 -0
  27. package/interfaces/i-clock.js +9 -0
  28. package/interfaces/i-clock.js.map +1 -0
  29. package/interfaces/i-coverage-range.js +9 -0
  30. package/interfaces/i-coverage-range.js.map +1 -0
  31. package/interfaces/i-coverage-report.js +9 -0
  32. package/interfaces/i-coverage-report.js.map +1 -0
  33. package/interfaces/i-function-coverage.js +9 -0
  34. package/interfaces/i-function-coverage.js.map +1 -0
  35. package/interfaces/i-script-coverage.js +9 -0
  36. package/interfaces/i-script-coverage.js.map +1 -0
  37. package/interfaces/i-source-map-data.js +9 -0
  38. package/interfaces/i-source-map-data.js.map +1 -0
  39. package/interfaces/i-test-progress-listener.js +9 -0
  40. package/interfaces/i-test-progress-listener.js.map +1 -0
  41. package/models/coverage/block-coverage.js +21 -0
  42. package/models/coverage/block-coverage.js.map +1 -0
  43. package/models/coverage/coverage-project.js +23 -0
  44. package/models/coverage/coverage-project.js.map +1 -0
  45. package/models/coverage/coverage-range.js +18 -0
  46. package/models/coverage/coverage-range.js.map +1 -0
  47. package/models/coverage/coverage-result.js +28 -0
  48. package/models/coverage/coverage-result.js.map +1 -0
  49. package/models/coverage/file-coverage.js +45 -0
  50. package/models/coverage/file-coverage.js.map +1 -0
  51. package/models/coverage/function-coverage.js +14 -0
  52. package/models/coverage/function-coverage.js.map +1 -0
  53. package/models/coverage/line-range.js +25 -0
  54. package/models/coverage/line-range.js.map +1 -0
  55. package/models/coverage/mapped-source-line.js +22 -0
  56. package/models/coverage/mapped-source-line.js.map +1 -0
  57. package/models/coverage/source-map-segment.js +18 -0
  58. package/models/coverage/source-map-segment.js.map +1 -0
  59. package/models/decorators/test-data-entry.js +17 -0
  60. package/models/decorators/test-data-entry.js.map +1 -0
  61. package/models/decorators/test-marks.js +16 -0
  62. package/models/decorators/test-marks.js.map +1 -0
  63. package/models/discovery/discovered-test-class.js +36 -0
  64. package/models/discovery/discovered-test-class.js.map +1 -0
  65. package/models/discovery/discovered-test-method.js +42 -0
  66. package/models/discovery/discovered-test-method.js.map +1 -0
  67. package/models/discovery/test-project.js +20 -0
  68. package/models/discovery/test-project.js.map +1 -0
  69. package/models/execution/test-worker-message.js +76 -0
  70. package/models/execution/test-worker-message.js.map +1 -0
  71. package/models/execution/test-worker-record.js +75 -0
  72. package/models/execution/test-worker-record.js.map +1 -0
  73. package/models/execution/test-worker-result.js +45 -0
  74. package/models/execution/test-worker-result.js.map +1 -0
  75. package/models/execution/test-worker-run.js +31 -0
  76. package/models/execution/test-worker-run.js.map +1 -0
  77. package/models/execution/test-worker-start.js +33 -0
  78. package/models/execution/test-worker-start.js.map +1 -0
  79. package/models/execution/test-worker-text.js +17 -0
  80. package/models/execution/test-worker-text.js.map +1 -0
  81. package/models/execution/test-worker-value.js +104 -0
  82. package/models/execution/test-worker-value.js.map +1 -0
  83. package/models/reporting/coverage-report-row.js +22 -0
  84. package/models/reporting/coverage-report-row.js.map +1 -0
  85. package/models/results/test-class-result.js +29 -0
  86. package/models/results/test-class-result.js.map +1 -0
  87. package/models/results/test-method-result.js +59 -0
  88. package/models/results/test-method-result.js.map +1 -0
  89. package/models/results/test-run-result.js +34 -0
  90. package/models/results/test-run-result.js.map +1 -0
  91. package/models/results/test-run-totals.js +36 -0
  92. package/models/results/test-run-totals.js.map +1 -0
  93. package/models/results/test-selection.js +33 -0
  94. package/models/results/test-selection.js.map +1 -0
  95. package/package.json +25 -4
  96. package/resources.js +309 -0
  97. package/resources.js.map +1 -0
  98. package/services/assert.js +92 -0
  99. package/services/assert.js.map +1 -0
  100. package/services/coverage/coverage-analyzer.js +52 -0
  101. package/services/coverage/coverage-analyzer.js.map +1 -0
  102. package/services/coverage/coverage-report.reader.js +126 -0
  103. package/services/coverage/coverage-report.reader.js.map +1 -0
  104. package/services/coverage/file-coverage-analyzer.js +206 -0
  105. package/services/coverage/file-coverage-analyzer.js.map +1 -0
  106. package/services/coverage/source-map.js +135 -0
  107. package/services/coverage/source-map.js.map +1 -0
  108. package/services/discovery/test-discovery.js +198 -0
  109. package/services/discovery/test-discovery.js.map +1 -0
  110. package/services/execution/parallel-test-runner.js +24 -0
  111. package/services/execution/parallel-test-runner.js.map +1 -0
  112. package/services/execution/test-executor.js +116 -0
  113. package/services/execution/test-executor.js.map +1 -0
  114. package/services/execution/test-run-entry-point.js +89 -0
  115. package/services/execution/test-run-entry-point.js.map +1 -0
  116. package/services/execution/test-run-supervisor.js +251 -0
  117. package/services/execution/test-run-supervisor.js.map +1 -0
  118. package/services/execution/test-run-worker-entry-point.js +18 -0
  119. package/services/execution/test-run-worker-entry-point.js.map +1 -0
  120. package/services/execution/test-run-worker.js +116 -0
  121. package/services/execution/test-run-worker.js.map +1 -0
  122. package/services/execution/test-runner.js +58 -0
  123. package/services/execution/test-runner.js.map +1 -0
  124. package/services/reporting/coverage-report-writer.js +81 -0
  125. package/services/reporting/coverage-report-writer.js.map +1 -0
  126. package/services/reporting/test-console-reporter.js +72 -0
  127. package/services/reporting/test-console-reporter.js.map +1 -0
  128. package/services/reporting/test-report-writer.js +111 -0
  129. package/services/reporting/test-report-writer.js.map +1 -0
  130. package/services/timing/system-clock.js +26 -0
  131. package/services/timing/system-clock.js.map +1 -0
  132. 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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"}