@nahisaho/musubix-core 1.0.0
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/bin/musubix.js +18 -0
- package/dist/__tests__/index.test.d.ts +2 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.js +27 -0
- package/dist/__tests__/index.test.js.map +1 -0
- package/dist/auth/auth-manager.d.ts +320 -0
- package/dist/auth/auth-manager.d.ts.map +1 -0
- package/dist/auth/auth-manager.js +580 -0
- package/dist/auth/auth-manager.js.map +1 -0
- package/dist/cli/base.d.ts +58 -0
- package/dist/cli/base.d.ts.map +1 -0
- package/dist/cli/base.js +93 -0
- package/dist/cli/base.js.map +1 -0
- package/dist/cli/commands/help.d.ts +17 -0
- package/dist/cli/commands/help.d.ts.map +1 -0
- package/dist/cli/commands/help.js +228 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/index.d.ts +14 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +25 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/init.d.ts +38 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +258 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +9 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/codegen/coding-standards.d.ts +250 -0
- package/dist/codegen/coding-standards.d.ts.map +1 -0
- package/dist/codegen/coding-standards.js +976 -0
- package/dist/codegen/coding-standards.js.map +1 -0
- package/dist/codegen/coverage-reporter.d.ts +264 -0
- package/dist/codegen/coverage-reporter.d.ts.map +1 -0
- package/dist/codegen/coverage-reporter.js +697 -0
- package/dist/codegen/coverage-reporter.js.map +1 -0
- package/dist/codegen/dependency-analyzer.d.ts +271 -0
- package/dist/codegen/dependency-analyzer.d.ts.map +1 -0
- package/dist/codegen/dependency-analyzer.js +661 -0
- package/dist/codegen/dependency-analyzer.js.map +1 -0
- package/dist/codegen/generator.d.ts +275 -0
- package/dist/codegen/generator.d.ts.map +1 -0
- package/dist/codegen/generator.js +781 -0
- package/dist/codegen/generator.js.map +1 -0
- package/dist/codegen/index.d.ts +18 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/index.js +27 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/codegen/integration-test-generator.d.ts +312 -0
- package/dist/codegen/integration-test-generator.d.ts.map +1 -0
- package/dist/codegen/integration-test-generator.js +765 -0
- package/dist/codegen/integration-test-generator.js.map +1 -0
- package/dist/codegen/pattern-conformance.d.ts +309 -0
- package/dist/codegen/pattern-conformance.d.ts.map +1 -0
- package/dist/codegen/pattern-conformance.js +590 -0
- package/dist/codegen/pattern-conformance.js.map +1 -0
- package/dist/codegen/quality-metrics.d.ts +235 -0
- package/dist/codegen/quality-metrics.d.ts.map +1 -0
- package/dist/codegen/quality-metrics.js +439 -0
- package/dist/codegen/quality-metrics.js.map +1 -0
- package/dist/codegen/security-scanner.d.ts +179 -0
- package/dist/codegen/security-scanner.d.ts.map +1 -0
- package/dist/codegen/security-scanner.js +495 -0
- package/dist/codegen/security-scanner.js.map +1 -0
- package/dist/codegen/static-analyzer.d.ts +188 -0
- package/dist/codegen/static-analyzer.d.ts.map +1 -0
- package/dist/codegen/static-analyzer.js +490 -0
- package/dist/codegen/static-analyzer.js.map +1 -0
- package/dist/codegen/unit-test-generator.d.ts +289 -0
- package/dist/codegen/unit-test-generator.d.ts.map +1 -0
- package/dist/codegen/unit-test-generator.js +634 -0
- package/dist/codegen/unit-test-generator.js.map +1 -0
- package/dist/design/adr-generator.d.ts +227 -0
- package/dist/design/adr-generator.d.ts.map +1 -0
- package/dist/design/adr-generator.js +423 -0
- package/dist/design/adr-generator.js.map +1 -0
- package/dist/design/c4-generator.d.ts +267 -0
- package/dist/design/c4-generator.d.ts.map +1 -0
- package/dist/design/c4-generator.js +453 -0
- package/dist/design/c4-generator.js.map +1 -0
- package/dist/design/framework-optimizer.d.ts +190 -0
- package/dist/design/framework-optimizer.d.ts.map +1 -0
- package/dist/design/framework-optimizer.js +589 -0
- package/dist/design/framework-optimizer.js.map +1 -0
- package/dist/design/index.d.ts +12 -0
- package/dist/design/index.d.ts.map +1 -0
- package/dist/design/index.js +13 -0
- package/dist/design/index.js.map +1 -0
- package/dist/design/pattern-detector.d.ts +270 -0
- package/dist/design/pattern-detector.d.ts.map +1 -0
- package/dist/design/pattern-detector.js +621 -0
- package/dist/design/pattern-detector.js.map +1 -0
- package/dist/design/solid-validator.d.ts +188 -0
- package/dist/design/solid-validator.d.ts.map +1 -0
- package/dist/design/solid-validator.js +579 -0
- package/dist/design/solid-validator.js.map +1 -0
- package/dist/error/data-persistence.d.ts +311 -0
- package/dist/error/data-persistence.d.ts.map +1 -0
- package/dist/error/data-persistence.js +586 -0
- package/dist/error/data-persistence.js.map +1 -0
- package/dist/error/graceful-degradation.d.ts +309 -0
- package/dist/error/graceful-degradation.d.ts.map +1 -0
- package/dist/error/graceful-degradation.js +510 -0
- package/dist/error/graceful-degradation.js.map +1 -0
- package/dist/error/index.d.ts +11 -0
- package/dist/error/index.d.ts.map +1 -0
- package/dist/error/index.js +19 -0
- package/dist/error/index.js.map +1 -0
- package/dist/explanation/explanation-generator.d.ts +228 -0
- package/dist/explanation/explanation-generator.d.ts.map +1 -0
- package/dist/explanation/explanation-generator.js +662 -0
- package/dist/explanation/explanation-generator.js.map +1 -0
- package/dist/explanation/index.d.ts +11 -0
- package/dist/explanation/index.d.ts.map +1 -0
- package/dist/explanation/index.js +19 -0
- package/dist/explanation/index.js.map +1 -0
- package/dist/explanation/reasoning-chain.d.ts +314 -0
- package/dist/explanation/reasoning-chain.d.ts.map +1 -0
- package/dist/explanation/reasoning-chain.js +414 -0
- package/dist/explanation/reasoning-chain.js.map +1 -0
- package/dist/explanation/visual-explanation.d.ts +315 -0
- package/dist/explanation/visual-explanation.d.ts.map +1 -0
- package/dist/explanation/visual-explanation.js +667 -0
- package/dist/explanation/visual-explanation.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/requirements/decomposer.d.ts +235 -0
- package/dist/requirements/decomposer.d.ts.map +1 -0
- package/dist/requirements/decomposer.js +587 -0
- package/dist/requirements/decomposer.js.map +1 -0
- package/dist/requirements/related-finder.d.ts +261 -0
- package/dist/requirements/related-finder.d.ts.map +1 -0
- package/dist/requirements/related-finder.js +629 -0
- package/dist/requirements/related-finder.js.map +1 -0
- package/dist/traceability/impact.d.ts +196 -0
- package/dist/traceability/impact.d.ts.map +1 -0
- package/dist/traceability/impact.js +438 -0
- package/dist/traceability/impact.js.map +1 -0
- package/dist/traceability/index.d.ts +9 -0
- package/dist/traceability/index.d.ts.map +1 -0
- package/dist/traceability/index.js +10 -0
- package/dist/traceability/index.js.map +1 -0
- package/dist/traceability/manager.d.ts +266 -0
- package/dist/traceability/manager.d.ts.map +1 -0
- package/dist/traceability/manager.js +412 -0
- package/dist/traceability/manager.js.map +1 -0
- package/dist/types/common.d.ts +294 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +15 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/ears.d.ts +158 -0
- package/dist/types/ears.d.ts.map +1 -0
- package/dist/types/ears.js +33 -0
- package/dist/types/ears.js.map +1 -0
- package/dist/types/errors.d.ts +176 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +55 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/data-protector.d.ts +122 -0
- package/dist/utils/data-protector.d.ts.map +1 -0
- package/dist/utils/data-protector.js +275 -0
- package/dist/utils/data-protector.js.map +1 -0
- package/dist/utils/error-handler.d.ts +101 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +324 -0
- package/dist/utils/error-handler.js.map +1 -0
- package/dist/utils/i18n-manager.d.ts +259 -0
- package/dist/utils/i18n-manager.d.ts.map +1 -0
- package/dist/utils/i18n-manager.js +554 -0
- package/dist/utils/i18n-manager.js.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +120 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +237 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/performance-profiler.d.ts +251 -0
- package/dist/utils/performance-profiler.d.ts.map +1 -0
- package/dist/utils/performance-profiler.js +458 -0
- package/dist/utils/performance-profiler.js.map +1 -0
- package/dist/utils/scalability-optimizer.d.ts +294 -0
- package/dist/utils/scalability-optimizer.d.ts.map +1 -0
- package/dist/utils/scalability-optimizer.js +606 -0
- package/dist/utils/scalability-optimizer.js.map +1 -0
- package/dist/utils/structured-logger.d.ts +294 -0
- package/dist/utils/structured-logger.d.ts.map +1 -0
- package/dist/utils/structured-logger.js +630 -0
- package/dist/utils/structured-logger.js.map +1 -0
- package/dist/utils/version-compatibility.d.ts +217 -0
- package/dist/utils/version-compatibility.d.ts.map +1 -0
- package/dist/utils/version-compatibility.js +443 -0
- package/dist/utils/version-compatibility.js.map +1 -0
- package/dist/validators/ears-validator.d.ts +182 -0
- package/dist/validators/ears-validator.d.ts.map +1 -0
- package/dist/validators/ears-validator.js +357 -0
- package/dist/validators/ears-validator.js.map +1 -0
- package/dist/validators/index.d.ts +8 -0
- package/dist/validators/index.d.ts.map +1 -0
- package/dist/validators/index.js +9 -0
- package/dist/validators/index.js.map +1 -0
- package/dist/version.d.ts +8 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/package.json +100 -0
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit Test Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates unit tests from code and specifications
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
* @module codegen/unit-test-generator
|
|
8
|
+
*
|
|
9
|
+
* @see REQ-TST-001 - Unit Test Generation
|
|
10
|
+
* @see Article VII - Quality Assurance Standards
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Default configuration
|
|
14
|
+
*/
|
|
15
|
+
export const DEFAULT_TEST_GENERATOR_CONFIG = {
|
|
16
|
+
framework: 'jest',
|
|
17
|
+
assertionStyle: 'expect',
|
|
18
|
+
generateEdgeCases: true,
|
|
19
|
+
generateErrorCases: true,
|
|
20
|
+
generateNullCases: true,
|
|
21
|
+
maxTestCasesPerFunction: 10,
|
|
22
|
+
includeSetupTeardown: true,
|
|
23
|
+
generateMocks: true,
|
|
24
|
+
testFileSuffix: '.test',
|
|
25
|
+
testDirectory: '__tests__',
|
|
26
|
+
verboseDescriptions: true,
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Framework templates
|
|
30
|
+
*/
|
|
31
|
+
const FRAMEWORK_TEMPLATES = {
|
|
32
|
+
jest: {
|
|
33
|
+
imports: '',
|
|
34
|
+
describe: (name, body) => `describe('${name}', () => {\n${body}\n});`,
|
|
35
|
+
it: (name, body, isAsync) => ` it('${name}', ${isAsync ? 'async ' : ''}() => {\n${body}\n });`,
|
|
36
|
+
beforeAll: (body) => ` beforeAll(() => {\n${body}\n });`,
|
|
37
|
+
afterAll: (body) => ` afterAll(() => {\n${body}\n });`,
|
|
38
|
+
beforeEach: (body) => ` beforeEach(() => {\n${body}\n });`,
|
|
39
|
+
afterEach: (body) => ` afterEach(() => {\n${body}\n });`,
|
|
40
|
+
expect: (value) => `expect(${value})`,
|
|
41
|
+
mockFn: () => 'jest.fn()',
|
|
42
|
+
mockModule: (module) => `jest.mock('${module}')`,
|
|
43
|
+
},
|
|
44
|
+
vitest: {
|
|
45
|
+
imports: "import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach, vi } from 'vitest';",
|
|
46
|
+
describe: (name, body) => `describe('${name}', () => {\n${body}\n});`,
|
|
47
|
+
it: (name, body, isAsync) => ` it('${name}', ${isAsync ? 'async ' : ''}() => {\n${body}\n });`,
|
|
48
|
+
beforeAll: (body) => ` beforeAll(() => {\n${body}\n });`,
|
|
49
|
+
afterAll: (body) => ` afterAll(() => {\n${body}\n });`,
|
|
50
|
+
beforeEach: (body) => ` beforeEach(() => {\n${body}\n });`,
|
|
51
|
+
afterEach: (body) => ` afterEach(() => {\n${body}\n });`,
|
|
52
|
+
expect: (value) => `expect(${value})`,
|
|
53
|
+
mockFn: () => 'vi.fn()',
|
|
54
|
+
mockModule: (module) => `vi.mock('${module}')`,
|
|
55
|
+
},
|
|
56
|
+
mocha: {
|
|
57
|
+
imports: "import { expect } from 'chai';",
|
|
58
|
+
describe: (name, body) => `describe('${name}', () => {\n${body}\n});`,
|
|
59
|
+
it: (name, body, isAsync) => ` it('${name}', ${isAsync ? 'async ' : ''}() => {\n${body}\n });`,
|
|
60
|
+
beforeAll: (body) => ` before(() => {\n${body}\n });`,
|
|
61
|
+
afterAll: (body) => ` after(() => {\n${body}\n });`,
|
|
62
|
+
beforeEach: (body) => ` beforeEach(() => {\n${body}\n });`,
|
|
63
|
+
afterEach: (body) => ` afterEach(() => {\n${body}\n });`,
|
|
64
|
+
expect: (value) => `expect(${value})`,
|
|
65
|
+
mockFn: () => "sinon.stub()",
|
|
66
|
+
mockModule: (module) => `// Mock ${module} with sinon or proxyquire`,
|
|
67
|
+
},
|
|
68
|
+
ava: {
|
|
69
|
+
imports: "import test from 'ava';",
|
|
70
|
+
describe: (name, body) => `// ${name}\n${body}`,
|
|
71
|
+
it: (name, body, isAsync) => `test('${name}', ${isAsync ? 'async ' : ''}(t) => {\n${body.replace(/expect\(/g, 't.is(')}\n});`,
|
|
72
|
+
beforeAll: (body) => `test.before(() => {\n${body}\n});`,
|
|
73
|
+
afterAll: (body) => `test.after(() => {\n${body}\n});`,
|
|
74
|
+
beforeEach: (body) => `test.beforeEach(() => {\n${body}\n});`,
|
|
75
|
+
afterEach: (body) => `test.afterEach(() => {\n${body}\n});`,
|
|
76
|
+
expect: (value) => `t.is(${value}`,
|
|
77
|
+
mockFn: () => "sinon.stub()",
|
|
78
|
+
mockModule: (module) => `// Mock ${module} with proxyquire`,
|
|
79
|
+
},
|
|
80
|
+
tap: {
|
|
81
|
+
imports: "import tap from 'tap';",
|
|
82
|
+
describe: (name, body) => `tap.test('${name}', (t) => {\n${body}\n t.end();\n});`,
|
|
83
|
+
it: (name, body, isAsync) => ` t.test('${name}', ${isAsync ? 'async ' : ''}(t) => {\n${body}\n t.end();\n });`,
|
|
84
|
+
beforeAll: (body) => ` t.before(() => {\n${body}\n });`,
|
|
85
|
+
afterAll: (body) => ` t.after(() => {\n${body}\n });`,
|
|
86
|
+
beforeEach: (body) => ` t.beforeEach(() => {\n${body}\n });`,
|
|
87
|
+
afterEach: (body) => ` t.afterEach(() => {\n${body}\n });`,
|
|
88
|
+
expect: (value) => `t.equal(${value}`,
|
|
89
|
+
mockFn: () => "sinon.stub()",
|
|
90
|
+
mockModule: (module) => `// Mock ${module}`,
|
|
91
|
+
},
|
|
92
|
+
pytest: {
|
|
93
|
+
imports: 'import pytest\nfrom unittest.mock import Mock, patch',
|
|
94
|
+
describe: (name, body) => `class Test${name.replace(/\s+/g, '')}:\n${body}`,
|
|
95
|
+
it: (name, body, isAsync) => ` ${isAsync ? 'async ' : ''}def test_${name.replace(/\s+/g, '_').toLowerCase()}(self):\n${body}`,
|
|
96
|
+
beforeAll: (body) => ` @classmethod\n def setup_class(cls):\n${body}`,
|
|
97
|
+
afterAll: (body) => ` @classmethod\n def teardown_class(cls):\n${body}`,
|
|
98
|
+
beforeEach: (body) => ` def setup_method(self):\n${body}`,
|
|
99
|
+
afterEach: (body) => ` def teardown_method(self):\n${body}`,
|
|
100
|
+
expect: (value) => `assert ${value}`,
|
|
101
|
+
mockFn: () => 'Mock()',
|
|
102
|
+
mockModule: (module) => `@patch('${module}')`,
|
|
103
|
+
},
|
|
104
|
+
unittest: {
|
|
105
|
+
imports: 'import unittest\nfrom unittest.mock import Mock, patch',
|
|
106
|
+
describe: (name, body) => `class Test${name.replace(/\s+/g, '')}(unittest.TestCase):\n${body}`,
|
|
107
|
+
it: (name, body, _isAsync) => ` def test_${name.replace(/\s+/g, '_').toLowerCase()}(self):\n${body}`,
|
|
108
|
+
beforeAll: (body) => ` @classmethod\n def setUpClass(cls):\n${body}`,
|
|
109
|
+
afterAll: (body) => ` @classmethod\n def tearDownClass(cls):\n${body}`,
|
|
110
|
+
beforeEach: (body) => ` def setUp(self):\n${body}`,
|
|
111
|
+
afterEach: (body) => ` def tearDown(self):\n${body}`,
|
|
112
|
+
expect: (value) => `self.assertEqual(${value}`,
|
|
113
|
+
mockFn: () => 'Mock()',
|
|
114
|
+
mockModule: (module) => `@patch('${module}')`,
|
|
115
|
+
},
|
|
116
|
+
junit: {
|
|
117
|
+
imports: 'import org.junit.jupiter.api.*;\nimport static org.junit.jupiter.api.Assertions.*;',
|
|
118
|
+
describe: (name, body) => `class ${name.replace(/\s+/g, '')}Test {\n${body}\n}`,
|
|
119
|
+
it: (name, body, _isAsync) => ` @Test\n void test${name.replace(/\s+/g, '')}() {\n${body}\n }`,
|
|
120
|
+
beforeAll: (body) => ` @BeforeAll\n static void setUpAll() {\n${body}\n }`,
|
|
121
|
+
afterAll: (body) => ` @AfterAll\n static void tearDownAll() {\n${body}\n }`,
|
|
122
|
+
beforeEach: (body) => ` @BeforeEach\n void setUp() {\n${body}\n }`,
|
|
123
|
+
afterEach: (body) => ` @AfterEach\n void tearDown() {\n${body}\n }`,
|
|
124
|
+
expect: (value) => `assertEquals(${value}`,
|
|
125
|
+
mockFn: () => 'mock()',
|
|
126
|
+
mockModule: (module) => `// Mock ${module} with Mockito`,
|
|
127
|
+
},
|
|
128
|
+
nunit: {
|
|
129
|
+
imports: 'using NUnit.Framework;\nusing Moq;',
|
|
130
|
+
describe: (name, body) => `[TestFixture]\npublic class ${name.replace(/\s+/g, '')}Tests\n{\n${body}\n}`,
|
|
131
|
+
it: (name, body, _isAsync) => ` [Test]\n public void Test${name.replace(/\s+/g, '')}()\n {\n${body}\n }`,
|
|
132
|
+
beforeAll: (body) => ` [OneTimeSetUp]\n public void SetUpFixture()\n {\n${body}\n }`,
|
|
133
|
+
afterAll: (body) => ` [OneTimeTearDown]\n public void TearDownFixture()\n {\n${body}\n }`,
|
|
134
|
+
beforeEach: (body) => ` [SetUp]\n public void SetUp()\n {\n${body}\n }`,
|
|
135
|
+
afterEach: (body) => ` [TearDown]\n public void TearDown()\n {\n${body}\n }`,
|
|
136
|
+
expect: (value) => `Assert.That(${value}`,
|
|
137
|
+
mockFn: () => 'new Mock<T>()',
|
|
138
|
+
mockModule: (module) => `// Mock ${module} with Moq`,
|
|
139
|
+
},
|
|
140
|
+
xunit: {
|
|
141
|
+
imports: 'using Xunit;\nusing Moq;',
|
|
142
|
+
describe: (name, body) => `public class ${name.replace(/\s+/g, '')}Tests\n{\n${body}\n}`,
|
|
143
|
+
it: (name, body, _isAsync) => ` [Fact]\n public void Test${name.replace(/\s+/g, '')}()\n {\n${body}\n }`,
|
|
144
|
+
beforeAll: (body) => ` public XunitTests()\n {\n${body}\n }`,
|
|
145
|
+
afterAll: (body) => ` public void Dispose()\n {\n${body}\n }`,
|
|
146
|
+
beforeEach: (body) => ` // Setup: ${body}`,
|
|
147
|
+
afterEach: (body) => ` // Teardown: ${body}`,
|
|
148
|
+
expect: (value) => `Assert.Equal(${value}`,
|
|
149
|
+
mockFn: () => 'new Mock<T>()',
|
|
150
|
+
mockModule: (module) => `// Mock ${module} with Moq`,
|
|
151
|
+
},
|
|
152
|
+
'go-test': {
|
|
153
|
+
imports: 'import (\n "testing"\n)',
|
|
154
|
+
describe: (name, body) => `// ${name}\n${body}`,
|
|
155
|
+
it: (name, body, _isAsync) => `func Test${name.replace(/\s+/g, '')}(t *testing.T) {\n${body}\n}`,
|
|
156
|
+
beforeAll: (body) => `func TestMain(m *testing.M) {\n${body}\n os.Exit(m.Run())\n}`,
|
|
157
|
+
afterAll: (body) => `// Teardown in TestMain: ${body}`,
|
|
158
|
+
beforeEach: (body) => ` // Setup: ${body}`,
|
|
159
|
+
afterEach: (body) => ` // Teardown: ${body}`,
|
|
160
|
+
expect: (value) => `if ${value}`,
|
|
161
|
+
mockFn: () => '// mock function',
|
|
162
|
+
mockModule: (module) => `// Mock ${module}`,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Unit Test Generator
|
|
167
|
+
*/
|
|
168
|
+
export class UnitTestGenerator {
|
|
169
|
+
config;
|
|
170
|
+
template;
|
|
171
|
+
constructor(config) {
|
|
172
|
+
this.config = { ...DEFAULT_TEST_GENERATOR_CONFIG, ...config };
|
|
173
|
+
this.template = FRAMEWORK_TEMPLATES[this.config.framework];
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Generate tests for a function
|
|
177
|
+
*/
|
|
178
|
+
generateForFunction(func, targetFile) {
|
|
179
|
+
const testCases = this.generateTestCases(func);
|
|
180
|
+
const content = this.generateTestFile(func, testCases, targetFile);
|
|
181
|
+
const testFilePath = this.getTestFilePath(targetFile);
|
|
182
|
+
const coverageEstimate = this.estimateCoverage(func, testCases);
|
|
183
|
+
return {
|
|
184
|
+
content,
|
|
185
|
+
filePath: testFilePath,
|
|
186
|
+
testCount: testCases.length,
|
|
187
|
+
coverageEstimate,
|
|
188
|
+
warnings: this.generateWarnings(func, testCases),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Generate tests for multiple functions
|
|
193
|
+
*/
|
|
194
|
+
generateForModule(functions, targetFile) {
|
|
195
|
+
const allTestCases = [];
|
|
196
|
+
const warnings = [];
|
|
197
|
+
for (const func of functions) {
|
|
198
|
+
const testCases = this.generateTestCases(func);
|
|
199
|
+
allTestCases.push(...testCases);
|
|
200
|
+
warnings.push(...this.generateWarnings(func, testCases));
|
|
201
|
+
}
|
|
202
|
+
const content = this.generateModuleTestFile(functions, allTestCases, targetFile);
|
|
203
|
+
const testFilePath = this.getTestFilePath(targetFile);
|
|
204
|
+
return {
|
|
205
|
+
content,
|
|
206
|
+
filePath: testFilePath,
|
|
207
|
+
testCount: allTestCases.length,
|
|
208
|
+
coverageEstimate: this.estimateModuleCoverage(functions, allTestCases),
|
|
209
|
+
warnings,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Generate test cases for a function
|
|
214
|
+
*/
|
|
215
|
+
generateTestCases(func) {
|
|
216
|
+
const testCases = [];
|
|
217
|
+
// Basic happy path test
|
|
218
|
+
testCases.push(this.generateHappyPathTest(func));
|
|
219
|
+
// Edge cases
|
|
220
|
+
if (this.config.generateEdgeCases) {
|
|
221
|
+
testCases.push(...this.generateEdgeCaseTests(func));
|
|
222
|
+
}
|
|
223
|
+
// Error cases
|
|
224
|
+
if (this.config.generateErrorCases) {
|
|
225
|
+
testCases.push(...this.generateErrorTests(func));
|
|
226
|
+
}
|
|
227
|
+
// Null/undefined cases
|
|
228
|
+
if (this.config.generateNullCases) {
|
|
229
|
+
testCases.push(...this.generateNullTests(func));
|
|
230
|
+
}
|
|
231
|
+
// Limit test cases
|
|
232
|
+
return testCases.slice(0, this.config.maxTestCasesPerFunction);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Generate happy path test
|
|
236
|
+
*/
|
|
237
|
+
generateHappyPathTest(func) {
|
|
238
|
+
return {
|
|
239
|
+
name: `should ${this.generateTestName(func)} with valid input`,
|
|
240
|
+
description: `Tests ${func.name} with typical valid input`,
|
|
241
|
+
type: 'unit',
|
|
242
|
+
inputs: func.parameters.map((p) => ({
|
|
243
|
+
name: p.name,
|
|
244
|
+
value: this.generateSampleValue(p.type),
|
|
245
|
+
type: p.type,
|
|
246
|
+
})),
|
|
247
|
+
expectedOutput: {
|
|
248
|
+
type: func.returnType,
|
|
249
|
+
value: this.generateExpectedValue(func.returnType),
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Generate edge case tests
|
|
255
|
+
*/
|
|
256
|
+
generateEdgeCaseTests(func) {
|
|
257
|
+
const tests = [];
|
|
258
|
+
for (const param of func.parameters) {
|
|
259
|
+
const edgeValues = this.getEdgeValues(param.type);
|
|
260
|
+
for (const edge of edgeValues) {
|
|
261
|
+
tests.push({
|
|
262
|
+
name: `should handle ${param.name} with ${edge.description}`,
|
|
263
|
+
description: `Edge case test for ${param.name}`,
|
|
264
|
+
type: 'edge',
|
|
265
|
+
inputs: func.parameters.map((p) => ({
|
|
266
|
+
name: p.name,
|
|
267
|
+
value: p.name === param.name ? edge.value : this.generateSampleValue(p.type),
|
|
268
|
+
type: p.type,
|
|
269
|
+
})),
|
|
270
|
+
expectedOutput: {
|
|
271
|
+
type: func.returnType,
|
|
272
|
+
},
|
|
273
|
+
tags: ['edge-case'],
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return tests;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Generate error tests
|
|
281
|
+
*/
|
|
282
|
+
generateErrorTests(func) {
|
|
283
|
+
const tests = [];
|
|
284
|
+
// Invalid type tests
|
|
285
|
+
for (const param of func.parameters) {
|
|
286
|
+
if (!param.optional) {
|
|
287
|
+
tests.push({
|
|
288
|
+
name: `should throw error when ${param.name} is invalid`,
|
|
289
|
+
description: `Error handling test for invalid ${param.name}`,
|
|
290
|
+
type: 'error',
|
|
291
|
+
inputs: func.parameters.map((p) => ({
|
|
292
|
+
name: p.name,
|
|
293
|
+
value: p.name === param.name ? this.generateInvalidValue(p.type) : this.generateSampleValue(p.type),
|
|
294
|
+
type: p.type,
|
|
295
|
+
})),
|
|
296
|
+
expectedOutput: {
|
|
297
|
+
error: {
|
|
298
|
+
type: 'Error',
|
|
299
|
+
message: `Invalid ${param.name}`,
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
tags: ['error-handling'],
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return tests;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Generate null/undefined tests
|
|
310
|
+
*/
|
|
311
|
+
generateNullTests(func) {
|
|
312
|
+
const tests = [];
|
|
313
|
+
for (const param of func.parameters) {
|
|
314
|
+
if (!param.optional) {
|
|
315
|
+
// Null test
|
|
316
|
+
tests.push({
|
|
317
|
+
name: `should handle null ${param.name}`,
|
|
318
|
+
description: `Null handling test for ${param.name}`,
|
|
319
|
+
type: 'null',
|
|
320
|
+
inputs: func.parameters.map((p) => ({
|
|
321
|
+
name: p.name,
|
|
322
|
+
value: p.name === param.name ? null : this.generateSampleValue(p.type),
|
|
323
|
+
type: p.type,
|
|
324
|
+
})),
|
|
325
|
+
expectedOutput: {
|
|
326
|
+
error: {
|
|
327
|
+
type: 'TypeError',
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
tags: ['null-check'],
|
|
331
|
+
});
|
|
332
|
+
// Undefined test
|
|
333
|
+
tests.push({
|
|
334
|
+
name: `should handle undefined ${param.name}`,
|
|
335
|
+
description: `Undefined handling test for ${param.name}`,
|
|
336
|
+
type: 'null',
|
|
337
|
+
inputs: func.parameters.map((p) => ({
|
|
338
|
+
name: p.name,
|
|
339
|
+
value: p.name === param.name ? undefined : this.generateSampleValue(p.type),
|
|
340
|
+
type: p.type,
|
|
341
|
+
})),
|
|
342
|
+
expectedOutput: {
|
|
343
|
+
error: {
|
|
344
|
+
type: 'TypeError',
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
tags: ['undefined-check'],
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return tests;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Generate test file content
|
|
355
|
+
*/
|
|
356
|
+
generateTestFile(func, testCases, targetFile) {
|
|
357
|
+
const lines = [];
|
|
358
|
+
// Framework imports
|
|
359
|
+
if (this.template.imports) {
|
|
360
|
+
lines.push(this.template.imports);
|
|
361
|
+
}
|
|
362
|
+
// Import target
|
|
363
|
+
const importPath = this.getImportPath(targetFile);
|
|
364
|
+
lines.push(`import { ${func.name} } from '${importPath}';`);
|
|
365
|
+
lines.push('');
|
|
366
|
+
// Generate describe block
|
|
367
|
+
const testBody = this.generateDescribeBody(func, testCases);
|
|
368
|
+
lines.push(this.template.describe(func.name, testBody));
|
|
369
|
+
return lines.join('\n');
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Generate module test file
|
|
373
|
+
*/
|
|
374
|
+
generateModuleTestFile(functions, testCases, targetFile) {
|
|
375
|
+
const lines = [];
|
|
376
|
+
// Framework imports
|
|
377
|
+
if (this.template.imports) {
|
|
378
|
+
lines.push(this.template.imports);
|
|
379
|
+
}
|
|
380
|
+
// Import targets
|
|
381
|
+
const importPath = this.getImportPath(targetFile);
|
|
382
|
+
const imports = functions.map((f) => f.name).join(', ');
|
|
383
|
+
lines.push(`import { ${imports} } from '${importPath}';`);
|
|
384
|
+
lines.push('');
|
|
385
|
+
// Generate describe blocks for each function
|
|
386
|
+
for (const func of functions) {
|
|
387
|
+
const funcTests = testCases.filter((t) => t.name.includes(func.name) || t.description.includes(func.name));
|
|
388
|
+
const testBody = this.generateDescribeBody(func, funcTests);
|
|
389
|
+
lines.push(this.template.describe(func.name, testBody));
|
|
390
|
+
lines.push('');
|
|
391
|
+
}
|
|
392
|
+
return lines.join('\n');
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Generate describe block body
|
|
396
|
+
*/
|
|
397
|
+
generateDescribeBody(func, testCases) {
|
|
398
|
+
const lines = [];
|
|
399
|
+
// Setup/teardown
|
|
400
|
+
if (this.config.includeSetupTeardown) {
|
|
401
|
+
lines.push(this.template.beforeEach(' // Setup'));
|
|
402
|
+
lines.push('');
|
|
403
|
+
}
|
|
404
|
+
// Test cases
|
|
405
|
+
for (const testCase of testCases) {
|
|
406
|
+
const testBody = this.generateTestBody(func, testCase);
|
|
407
|
+
lines.push(this.template.it(testCase.name, testBody, func.isAsync));
|
|
408
|
+
lines.push('');
|
|
409
|
+
}
|
|
410
|
+
return lines.join('\n');
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Generate test body
|
|
414
|
+
*/
|
|
415
|
+
generateTestBody(func, testCase) {
|
|
416
|
+
const lines = [];
|
|
417
|
+
const indent = ' ';
|
|
418
|
+
// Setup mocks
|
|
419
|
+
if (testCase.mocks) {
|
|
420
|
+
for (const mock of testCase.mocks) {
|
|
421
|
+
lines.push(`${indent}const ${mock.target}Mock = ${this.template.mockFn()};`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
// Arrange: prepare inputs
|
|
425
|
+
const inputVars = [];
|
|
426
|
+
for (const input of testCase.inputs) {
|
|
427
|
+
const varName = input.name;
|
|
428
|
+
const value = JSON.stringify(input.value);
|
|
429
|
+
lines.push(`${indent}const ${varName} = ${value};`);
|
|
430
|
+
inputVars.push(varName);
|
|
431
|
+
}
|
|
432
|
+
lines.push('');
|
|
433
|
+
// Act: call function
|
|
434
|
+
const funcCall = func.className
|
|
435
|
+
? `new ${func.className}().${func.name}(${inputVars.join(', ')})`
|
|
436
|
+
: `${func.name}(${inputVars.join(', ')})`;
|
|
437
|
+
if (testCase.expectedOutput.error) {
|
|
438
|
+
// Expect error
|
|
439
|
+
if (func.isAsync) {
|
|
440
|
+
lines.push(`${indent}await ${this.template.expect(`${funcCall}`)}.rejects.toThrow();`);
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
lines.push(`${indent}${this.template.expect(`() => ${funcCall}`)}.toThrow();`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
// Expect result
|
|
448
|
+
const resultVar = func.isAsync
|
|
449
|
+
? `await ${funcCall}`
|
|
450
|
+
: funcCall;
|
|
451
|
+
lines.push(`${indent}const result = ${resultVar};`);
|
|
452
|
+
lines.push('');
|
|
453
|
+
// Assert
|
|
454
|
+
if (testCase.expectedOutput.value !== undefined) {
|
|
455
|
+
const expected = JSON.stringify(testCase.expectedOutput.value);
|
|
456
|
+
lines.push(`${indent}${this.template.expect('result')}.toEqual(${expected});`);
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
lines.push(`${indent}${this.template.expect('result')}.toBeDefined();`);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return lines.join('\n');
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Generate test name from function
|
|
466
|
+
*/
|
|
467
|
+
generateTestName(func) {
|
|
468
|
+
// Convert camelCase to words
|
|
469
|
+
const words = func.name
|
|
470
|
+
.replace(/([A-Z])/g, ' $1')
|
|
471
|
+
.toLowerCase()
|
|
472
|
+
.trim();
|
|
473
|
+
return words;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Generate sample value for type
|
|
477
|
+
*/
|
|
478
|
+
generateSampleValue(type) {
|
|
479
|
+
const normalized = type.toLowerCase().replace(/\s+/g, '');
|
|
480
|
+
if (normalized.includes('string'))
|
|
481
|
+
return 'test';
|
|
482
|
+
if (normalized.includes('number') || normalized.includes('int') || normalized.includes('float'))
|
|
483
|
+
return 42;
|
|
484
|
+
if (normalized.includes('boolean') || normalized.includes('bool'))
|
|
485
|
+
return true;
|
|
486
|
+
if (normalized.includes('array') || normalized.includes('[]'))
|
|
487
|
+
return [];
|
|
488
|
+
if (normalized.includes('object') || normalized.includes('record'))
|
|
489
|
+
return {};
|
|
490
|
+
if (normalized.includes('date'))
|
|
491
|
+
return new Date().toISOString();
|
|
492
|
+
if (normalized.includes('null'))
|
|
493
|
+
return null;
|
|
494
|
+
if (normalized.includes('undefined'))
|
|
495
|
+
return undefined;
|
|
496
|
+
return {};
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Generate expected value for return type
|
|
500
|
+
*/
|
|
501
|
+
generateExpectedValue(type) {
|
|
502
|
+
const normalized = type.toLowerCase().replace(/\s+/g, '');
|
|
503
|
+
if (normalized === 'void' || normalized === 'undefined')
|
|
504
|
+
return undefined;
|
|
505
|
+
if (normalized.includes('promise')) {
|
|
506
|
+
const inner = type.match(/<(.+)>/)?.[1] ?? 'unknown';
|
|
507
|
+
return this.generateSampleValue(inner);
|
|
508
|
+
}
|
|
509
|
+
return this.generateSampleValue(type);
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Generate invalid value for type
|
|
513
|
+
*/
|
|
514
|
+
generateInvalidValue(type) {
|
|
515
|
+
const normalized = type.toLowerCase().replace(/\s+/g, '');
|
|
516
|
+
if (normalized.includes('string'))
|
|
517
|
+
return 123;
|
|
518
|
+
if (normalized.includes('number'))
|
|
519
|
+
return 'not a number';
|
|
520
|
+
if (normalized.includes('boolean'))
|
|
521
|
+
return 'not boolean';
|
|
522
|
+
if (normalized.includes('array'))
|
|
523
|
+
return 'not array';
|
|
524
|
+
if (normalized.includes('object'))
|
|
525
|
+
return 'not object';
|
|
526
|
+
return Symbol('invalid');
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Get edge values for type
|
|
530
|
+
*/
|
|
531
|
+
getEdgeValues(type) {
|
|
532
|
+
const normalized = type.toLowerCase().replace(/\s+/g, '');
|
|
533
|
+
const edges = [];
|
|
534
|
+
if (normalized.includes('string')) {
|
|
535
|
+
edges.push({ value: '', description: 'empty string' });
|
|
536
|
+
edges.push({ value: ' ', description: 'whitespace' });
|
|
537
|
+
edges.push({ value: 'a'.repeat(1000), description: 'very long string' });
|
|
538
|
+
}
|
|
539
|
+
if (normalized.includes('number')) {
|
|
540
|
+
edges.push({ value: 0, description: 'zero' });
|
|
541
|
+
edges.push({ value: -1, description: 'negative' });
|
|
542
|
+
edges.push({ value: Number.MAX_SAFE_INTEGER, description: 'max safe integer' });
|
|
543
|
+
edges.push({ value: Number.MIN_SAFE_INTEGER, description: 'min safe integer' });
|
|
544
|
+
edges.push({ value: Infinity, description: 'infinity' });
|
|
545
|
+
edges.push({ value: NaN, description: 'NaN' });
|
|
546
|
+
}
|
|
547
|
+
if (normalized.includes('array')) {
|
|
548
|
+
edges.push({ value: [], description: 'empty array' });
|
|
549
|
+
edges.push({ value: new Array(1000).fill(0), description: 'large array' });
|
|
550
|
+
}
|
|
551
|
+
return edges;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Get test file path
|
|
555
|
+
*/
|
|
556
|
+
getTestFilePath(targetFile) {
|
|
557
|
+
const parts = targetFile.split('/');
|
|
558
|
+
const filename = parts.pop();
|
|
559
|
+
const ext = filename.split('.').pop();
|
|
560
|
+
const baseName = filename.replace(`.${ext}`, '');
|
|
561
|
+
return [...parts, this.config.testDirectory, `${baseName}${this.config.testFileSuffix}.${ext}`].join('/');
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Get import path
|
|
565
|
+
*/
|
|
566
|
+
getImportPath(targetFile) {
|
|
567
|
+
// Convert absolute to relative import
|
|
568
|
+
const parts = targetFile.split('/');
|
|
569
|
+
const filename = parts.pop();
|
|
570
|
+
const ext = filename.split('.').pop();
|
|
571
|
+
const baseName = filename.replace(`.${ext}`, '');
|
|
572
|
+
return `../${baseName}`;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Estimate coverage
|
|
576
|
+
*/
|
|
577
|
+
estimateCoverage(_func, testCases) {
|
|
578
|
+
const hasHappyPath = testCases.some((t) => t.type === 'unit');
|
|
579
|
+
const hasEdgeCases = testCases.some((t) => t.type === 'edge');
|
|
580
|
+
const hasErrorCases = testCases.some((t) => t.type === 'error');
|
|
581
|
+
const hasNullCases = testCases.some((t) => t.type === 'null');
|
|
582
|
+
let base = hasHappyPath ? 50 : 0;
|
|
583
|
+
if (hasEdgeCases)
|
|
584
|
+
base += 15;
|
|
585
|
+
if (hasErrorCases)
|
|
586
|
+
base += 20;
|
|
587
|
+
if (hasNullCases)
|
|
588
|
+
base += 15;
|
|
589
|
+
return {
|
|
590
|
+
statements: Math.min(base + 10, 100),
|
|
591
|
+
branches: Math.min(base, 100),
|
|
592
|
+
functions: hasHappyPath ? 100 : 0,
|
|
593
|
+
lines: Math.min(base + 10, 100),
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Estimate module coverage
|
|
598
|
+
*/
|
|
599
|
+
estimateModuleCoverage(functions, testCases) {
|
|
600
|
+
const functionsCovered = functions.filter((f) => testCases.some((t) => t.name.includes(f.name) || t.description.includes(f.name))).length;
|
|
601
|
+
const functionCoverage = functions.length > 0
|
|
602
|
+
? (functionsCovered / functions.length) * 100
|
|
603
|
+
: 0;
|
|
604
|
+
return {
|
|
605
|
+
statements: Math.round(functionCoverage * 0.9),
|
|
606
|
+
branches: Math.round(functionCoverage * 0.7),
|
|
607
|
+
functions: Math.round(functionCoverage),
|
|
608
|
+
lines: Math.round(functionCoverage * 0.9),
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Generate warnings
|
|
613
|
+
*/
|
|
614
|
+
generateWarnings(func, testCases) {
|
|
615
|
+
const warnings = [];
|
|
616
|
+
if (testCases.length < 3) {
|
|
617
|
+
warnings.push(`Low test count for ${func.name}: consider adding more test cases`);
|
|
618
|
+
}
|
|
619
|
+
if (func.parameters.length > 5) {
|
|
620
|
+
warnings.push(`${func.name} has many parameters: consider refactoring`);
|
|
621
|
+
}
|
|
622
|
+
if (!testCases.some((t) => t.type === 'error')) {
|
|
623
|
+
warnings.push(`No error handling tests for ${func.name}`);
|
|
624
|
+
}
|
|
625
|
+
return warnings;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Create unit test generator instance
|
|
630
|
+
*/
|
|
631
|
+
export function createUnitTestGenerator(config) {
|
|
632
|
+
return new UnitTestGenerator(config);
|
|
633
|
+
}
|
|
634
|
+
//# sourceMappingURL=unit-test-generator.js.map
|