agentic-qe 3.2.3 → 3.3.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/.claude/agents/v3/qe-accessibility-auditor.md +90 -0
- package/README.md +49 -7
- package/package.json +8 -2
- package/scripts/cloud-db-config.json +37 -0
- package/scripts/cloud-db-connect.sh +37 -0
- package/scripts/cloud-db-tunnel.sh +23 -0
- package/v3/CHANGELOG.md +253 -0
- package/v3/README.md +59 -1
- package/v3/assets/agents/v3/qe-accessibility-auditor.md +90 -0
- package/v3/dist/adapters/claude-flow/index.d.ts +54 -0
- package/v3/dist/adapters/claude-flow/index.d.ts.map +1 -0
- package/v3/dist/adapters/claude-flow/index.js +79 -0
- package/v3/dist/adapters/claude-flow/index.js.map +1 -0
- package/v3/dist/adapters/claude-flow/model-router-bridge.d.ts +70 -0
- package/v3/dist/adapters/claude-flow/model-router-bridge.d.ts.map +1 -0
- package/v3/dist/adapters/claude-flow/model-router-bridge.js +203 -0
- package/v3/dist/adapters/claude-flow/model-router-bridge.js.map +1 -0
- package/v3/dist/adapters/claude-flow/pretrain-bridge.d.ts +73 -0
- package/v3/dist/adapters/claude-flow/pretrain-bridge.d.ts.map +1 -0
- package/v3/dist/adapters/claude-flow/pretrain-bridge.js +276 -0
- package/v3/dist/adapters/claude-flow/pretrain-bridge.js.map +1 -0
- package/v3/dist/adapters/claude-flow/trajectory-bridge.d.ts +70 -0
- package/v3/dist/adapters/claude-flow/trajectory-bridge.d.ts.map +1 -0
- package/v3/dist/adapters/claude-flow/trajectory-bridge.js +205 -0
- package/v3/dist/adapters/claude-flow/trajectory-bridge.js.map +1 -0
- package/v3/dist/adapters/claude-flow/types.d.ts +99 -0
- package/v3/dist/adapters/claude-flow/types.d.ts.map +1 -0
- package/v3/dist/adapters/claude-flow/types.js +6 -0
- package/v3/dist/adapters/claude-flow/types.js.map +1 -0
- package/v3/dist/causal-discovery/causal-graph.d.ts +80 -1
- package/v3/dist/causal-discovery/causal-graph.d.ts.map +1 -1
- package/v3/dist/causal-discovery/causal-graph.js +111 -1
- package/v3/dist/causal-discovery/causal-graph.js.map +1 -1
- package/v3/dist/cli/bundle.js +25321 -15378
- package/v3/dist/cli/command-registry.d.ts +55 -0
- package/v3/dist/cli/command-registry.d.ts.map +1 -0
- package/v3/dist/cli/command-registry.js +103 -0
- package/v3/dist/cli/command-registry.js.map +1 -0
- package/v3/dist/cli/commands/claude-flow-setup.d.ts +82 -0
- package/v3/dist/cli/commands/claude-flow-setup.d.ts.map +1 -0
- package/v3/dist/cli/commands/claude-flow-setup.js +334 -0
- package/v3/dist/cli/commands/claude-flow-setup.js.map +1 -0
- package/v3/dist/cli/commands/code.d.ts +9 -0
- package/v3/dist/cli/commands/code.d.ts.map +1 -0
- package/v3/dist/cli/commands/code.js +254 -0
- package/v3/dist/cli/commands/code.js.map +1 -0
- package/v3/dist/cli/commands/completions.d.ts +8 -0
- package/v3/dist/cli/commands/completions.d.ts.map +1 -0
- package/v3/dist/cli/commands/completions.js +99 -0
- package/v3/dist/cli/commands/completions.js.map +1 -0
- package/v3/dist/cli/commands/coverage.d.ts +9 -0
- package/v3/dist/cli/commands/coverage.d.ts.map +1 -0
- package/v3/dist/cli/commands/coverage.js +208 -0
- package/v3/dist/cli/commands/coverage.js.map +1 -0
- package/v3/dist/cli/commands/fleet.d.ts +11 -0
- package/v3/dist/cli/commands/fleet.d.ts.map +1 -0
- package/v3/dist/cli/commands/fleet.js +338 -0
- package/v3/dist/cli/commands/fleet.js.map +1 -0
- package/v3/dist/cli/commands/hooks.d.ts +2 -0
- package/v3/dist/cli/commands/hooks.d.ts.map +1 -1
- package/v3/dist/cli/commands/hooks.js +13 -2
- package/v3/dist/cli/commands/hooks.js.map +1 -1
- package/v3/dist/cli/commands/init.d.ts +19 -0
- package/v3/dist/cli/commands/init.d.ts.map +1 -0
- package/v3/dist/cli/commands/init.js +345 -0
- package/v3/dist/cli/commands/init.js.map +1 -0
- package/v3/dist/cli/commands/migrate.d.ts +9 -0
- package/v3/dist/cli/commands/migrate.d.ts.map +1 -0
- package/v3/dist/cli/commands/migrate.js +566 -0
- package/v3/dist/cli/commands/migrate.js.map +1 -0
- package/v3/dist/cli/commands/quality.d.ts +9 -0
- package/v3/dist/cli/commands/quality.d.ts.map +1 -0
- package/v3/dist/cli/commands/quality.js +40 -0
- package/v3/dist/cli/commands/quality.js.map +1 -0
- package/v3/dist/cli/commands/security.d.ts +9 -0
- package/v3/dist/cli/commands/security.d.ts.map +1 -0
- package/v3/dist/cli/commands/security.js +124 -0
- package/v3/dist/cli/commands/security.js.map +1 -0
- package/v3/dist/cli/commands/sync.d.ts +19 -0
- package/v3/dist/cli/commands/sync.d.ts.map +1 -0
- package/v3/dist/cli/commands/sync.js +283 -0
- package/v3/dist/cli/commands/sync.js.map +1 -0
- package/v3/dist/cli/commands/test.d.ts +9 -0
- package/v3/dist/cli/commands/test.d.ts.map +1 -0
- package/v3/dist/cli/commands/test.js +166 -0
- package/v3/dist/cli/commands/test.js.map +1 -0
- package/v3/dist/cli/handlers/agent-handler.d.ts +20 -0
- package/v3/dist/cli/handlers/agent-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/agent-handler.js +158 -0
- package/v3/dist/cli/handlers/agent-handler.js.map +1 -0
- package/v3/dist/cli/handlers/domain-handler.d.ts +20 -0
- package/v3/dist/cli/handlers/domain-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/domain-handler.js +115 -0
- package/v3/dist/cli/handlers/domain-handler.js.map +1 -0
- package/v3/dist/cli/handlers/index.d.ts +13 -0
- package/v3/dist/cli/handlers/index.d.ts.map +1 -0
- package/v3/dist/cli/handlers/index.js +15 -0
- package/v3/dist/cli/handlers/index.js.map +1 -0
- package/v3/dist/cli/handlers/init-handler.d.ts +38 -0
- package/v3/dist/cli/handlers/init-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/init-handler.js +288 -0
- package/v3/dist/cli/handlers/init-handler.js.map +1 -0
- package/v3/dist/cli/handlers/interfaces.d.ts +104 -0
- package/v3/dist/cli/handlers/interfaces.d.ts.map +1 -0
- package/v3/dist/cli/handlers/interfaces.js +109 -0
- package/v3/dist/cli/handlers/interfaces.js.map +1 -0
- package/v3/dist/cli/handlers/protocol-handler.d.ts +19 -0
- package/v3/dist/cli/handlers/protocol-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/protocol-handler.js +79 -0
- package/v3/dist/cli/handlers/protocol-handler.js.map +1 -0
- package/v3/dist/cli/handlers/status-handler.d.ts +30 -0
- package/v3/dist/cli/handlers/status-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/status-handler.js +218 -0
- package/v3/dist/cli/handlers/status-handler.js.map +1 -0
- package/v3/dist/cli/handlers/task-handler.d.ts +22 -0
- package/v3/dist/cli/handlers/task-handler.d.ts.map +1 -0
- package/v3/dist/cli/handlers/task-handler.js +271 -0
- package/v3/dist/cli/handlers/task-handler.js.map +1 -0
- package/v3/dist/cli/index.d.ts +4 -0
- package/v3/dist/cli/index.d.ts.map +1 -1
- package/v3/dist/cli/index.js +62 -2583
- package/v3/dist/cli/index.js.map +1 -1
- package/v3/dist/cli/wizards/core/index.d.ts +11 -0
- package/v3/dist/cli/wizards/core/index.d.ts.map +1 -0
- package/v3/dist/cli/wizards/core/index.js +15 -0
- package/v3/dist/cli/wizards/core/index.js.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-base.d.ts +87 -0
- package/v3/dist/cli/wizards/core/wizard-base.d.ts.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-base.js +120 -0
- package/v3/dist/cli/wizards/core/wizard-base.js.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-command.d.ts +182 -0
- package/v3/dist/cli/wizards/core/wizard-command.d.ts.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-command.js +45 -0
- package/v3/dist/cli/wizards/core/wizard-command.js.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-step.d.ts +109 -0
- package/v3/dist/cli/wizards/core/wizard-step.d.ts.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-step.js +384 -0
- package/v3/dist/cli/wizards/core/wizard-step.js.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-utils.d.ts +117 -0
- package/v3/dist/cli/wizards/core/wizard-utils.d.ts.map +1 -0
- package/v3/dist/cli/wizards/core/wizard-utils.js +291 -0
- package/v3/dist/cli/wizards/core/wizard-utils.js.map +1 -0
- package/v3/dist/cli/wizards/coverage-wizard.d.ts +13 -68
- package/v3/dist/cli/wizards/coverage-wizard.d.ts.map +1 -1
- package/v3/dist/cli/wizards/coverage-wizard.js +127 -391
- package/v3/dist/cli/wizards/coverage-wizard.js.map +1 -1
- package/v3/dist/cli/wizards/fleet-wizard.d.ts +13 -64
- package/v3/dist/cli/wizards/fleet-wizard.d.ts.map +1 -1
- package/v3/dist/cli/wizards/fleet-wizard.js +150 -363
- package/v3/dist/cli/wizards/fleet-wizard.js.map +1 -1
- package/v3/dist/cli/wizards/index.d.ts +2 -0
- package/v3/dist/cli/wizards/index.d.ts.map +1 -1
- package/v3/dist/cli/wizards/index.js +3 -0
- package/v3/dist/cli/wizards/index.js.map +1 -1
- package/v3/dist/cli/wizards/security-wizard.d.ts +13 -64
- package/v3/dist/cli/wizards/security-wizard.d.ts.map +1 -1
- package/v3/dist/cli/wizards/security-wizard.js +152 -395
- package/v3/dist/cli/wizards/security-wizard.js.map +1 -1
- package/v3/dist/cli/wizards/test-wizard.d.ts +13 -77
- package/v3/dist/cli/wizards/test-wizard.d.ts.map +1 -1
- package/v3/dist/cli/wizards/test-wizard.js +196 -328
- package/v3/dist/cli/wizards/test-wizard.js.map +1 -1
- package/v3/dist/coordination/mincut/interfaces.d.ts +8 -2
- package/v3/dist/coordination/mincut/interfaces.d.ts.map +1 -1
- package/v3/dist/coordination/mincut/interfaces.js.map +1 -1
- package/v3/dist/coordination/mincut/mincut-health-monitor.d.ts +8 -0
- package/v3/dist/coordination/mincut/mincut-health-monitor.d.ts.map +1 -1
- package/v3/dist/coordination/mincut/mincut-health-monitor.js +26 -4
- package/v3/dist/coordination/mincut/mincut-health-monitor.js.map +1 -1
- package/v3/dist/coordination/mincut/queen-integration.d.ts +7 -0
- package/v3/dist/coordination/mincut/queen-integration.d.ts.map +1 -1
- package/v3/dist/coordination/mincut/queen-integration.js +19 -1
- package/v3/dist/coordination/mincut/queen-integration.js.map +1 -1
- package/v3/dist/coordination/queen-coordinator.d.ts +5 -0
- package/v3/dist/coordination/queen-coordinator.d.ts.map +1 -1
- package/v3/dist/coordination/queen-coordinator.js +45 -7
- package/v3/dist/coordination/queen-coordinator.js.map +1 -1
- package/v3/dist/coordination/task-executor.js +2 -2
- package/v3/dist/coordination/task-executor.js.map +1 -1
- package/v3/dist/domains/chaos-resilience/plugin.js +2 -2
- package/v3/dist/domains/chaos-resilience/plugin.js.map +1 -1
- package/v3/dist/domains/code-intelligence/plugin.js +2 -2
- package/v3/dist/domains/code-intelligence/plugin.js.map +1 -1
- package/v3/dist/domains/contract-testing/plugin.js +2 -2
- package/v3/dist/domains/contract-testing/plugin.js.map +1 -1
- package/v3/dist/domains/coverage-analysis/plugin.d.ts.map +1 -1
- package/v3/dist/domains/coverage-analysis/plugin.js +2 -1
- package/v3/dist/domains/coverage-analysis/plugin.js.map +1 -1
- package/v3/dist/domains/defect-intelligence/plugin.js +2 -2
- package/v3/dist/domains/defect-intelligence/plugin.js.map +1 -1
- package/v3/dist/domains/domain-interface.d.ts.map +1 -1
- package/v3/dist/domains/domain-interface.js +3 -1
- package/v3/dist/domains/domain-interface.js.map +1 -1
- package/v3/dist/domains/learning-optimization/coordinator.d.ts +5 -0
- package/v3/dist/domains/learning-optimization/coordinator.d.ts.map +1 -1
- package/v3/dist/domains/learning-optimization/coordinator.js +79 -0
- package/v3/dist/domains/learning-optimization/coordinator.js.map +1 -1
- package/v3/dist/domains/learning-optimization/plugin.js +2 -2
- package/v3/dist/domains/learning-optimization/plugin.js.map +1 -1
- package/v3/dist/domains/quality-assessment/plugin.js +2 -2
- package/v3/dist/domains/quality-assessment/plugin.js.map +1 -1
- package/v3/dist/domains/requirements-validation/plugin.js +2 -2
- package/v3/dist/domains/requirements-validation/plugin.js.map +1 -1
- package/v3/dist/domains/security-compliance/plugin.js +2 -2
- package/v3/dist/domains/security-compliance/plugin.js.map +1 -1
- package/v3/dist/domains/test-execution/index.d.ts +2 -1
- package/v3/dist/domains/test-execution/index.d.ts.map +1 -1
- package/v3/dist/domains/test-execution/index.js +0 -2
- package/v3/dist/domains/test-execution/index.js.map +1 -1
- package/v3/dist/domains/test-execution/interfaces.d.ts +222 -25
- package/v3/dist/domains/test-execution/interfaces.d.ts.map +1 -1
- package/v3/dist/domains/test-execution/interfaces.js +130 -3
- package/v3/dist/domains/test-execution/interfaces.js.map +1 -1
- package/v3/dist/domains/test-execution/plugin.d.ts.map +1 -1
- package/v3/dist/domains/test-execution/plugin.js +2 -1
- package/v3/dist/domains/test-execution/plugin.js.map +1 -1
- package/v3/dist/domains/test-execution/test-prioritization-types.d.ts +5 -172
- package/v3/dist/domains/test-execution/test-prioritization-types.d.ts.map +1 -1
- package/v3/dist/domains/test-execution/test-prioritization-types.js +6 -129
- package/v3/dist/domains/test-execution/test-prioritization-types.js.map +1 -1
- package/v3/dist/domains/test-execution/types/index.d.ts +7 -3
- package/v3/dist/domains/test-execution/types/index.d.ts.map +1 -1
- package/v3/dist/domains/test-execution/types/index.js +7 -17
- package/v3/dist/domains/test-execution/types/index.js.map +1 -1
- package/v3/dist/domains/test-generation/coordinator.d.ts +32 -1
- package/v3/dist/domains/test-generation/coordinator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/coordinator.js +72 -3
- package/v3/dist/domains/test-generation/coordinator.js.map +1 -1
- package/v3/dist/domains/test-generation/factories/index.d.ts +8 -0
- package/v3/dist/domains/test-generation/factories/index.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/factories/index.js +8 -0
- package/v3/dist/domains/test-generation/factories/index.js.map +1 -0
- package/v3/dist/domains/test-generation/factories/test-generator-factory.d.ts +108 -0
- package/v3/dist/domains/test-generation/factories/test-generator-factory.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/factories/test-generator-factory.js +158 -0
- package/v3/dist/domains/test-generation/factories/test-generator-factory.js.map +1 -0
- package/v3/dist/domains/test-generation/generators/base-test-generator.d.ts +79 -0
- package/v3/dist/domains/test-generation/generators/base-test-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/generators/base-test-generator.js +252 -0
- package/v3/dist/domains/test-generation/generators/base-test-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/generators/index.d.ts +11 -0
- package/v3/dist/domains/test-generation/generators/index.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/generators/index.js +13 -0
- package/v3/dist/domains/test-generation/generators/index.js.map +1 -0
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.d.ts +77 -0
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js +365 -0
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/generators/mocha-generator.d.ts +56 -0
- package/v3/dist/domains/test-generation/generators/mocha-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/generators/mocha-generator.js +197 -0
- package/v3/dist/domains/test-generation/generators/mocha-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/generators/pytest-generator.d.ts +66 -0
- package/v3/dist/domains/test-generation/generators/pytest-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/generators/pytest-generator.js +240 -0
- package/v3/dist/domains/test-generation/generators/pytest-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/index.d.ts +2 -1
- package/v3/dist/domains/test-generation/index.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/index.js +5 -1
- package/v3/dist/domains/test-generation/index.js.map +1 -1
- package/v3/dist/domains/test-generation/interfaces/index.d.ts +9 -0
- package/v3/dist/domains/test-generation/interfaces/index.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/interfaces/index.js +9 -0
- package/v3/dist/domains/test-generation/interfaces/index.js.map +1 -0
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts +166 -0
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.js +8 -0
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.js.map +1 -0
- package/v3/dist/domains/test-generation/interfaces.d.ts +163 -24
- package/v3/dist/domains/test-generation/interfaces.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/interfaces.js +2 -2
- package/v3/dist/domains/test-generation/plugin.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/plugin.js +6 -5
- package/v3/dist/domains/test-generation/plugin.js.map +1 -1
- package/v3/dist/domains/test-generation/services/coherence-gate-service.d.ts +245 -0
- package/v3/dist/domains/test-generation/services/coherence-gate-service.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/services/coherence-gate-service.js +454 -0
- package/v3/dist/domains/test-generation/services/coherence-gate-service.js.map +1 -0
- package/v3/dist/domains/test-generation/services/index.d.ts +8 -1
- package/v3/dist/domains/test-generation/services/index.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/services/index.js +10 -1
- package/v3/dist/domains/test-generation/services/index.js.map +1 -1
- package/v3/dist/domains/test-generation/services/property-test-generator.d.ts +34 -0
- package/v3/dist/domains/test-generation/services/property-test-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/services/property-test-generator.js +306 -0
- package/v3/dist/domains/test-generation/services/property-test-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/services/tdd-generator.d.ts +33 -0
- package/v3/dist/domains/test-generation/services/tdd-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/services/tdd-generator.js +342 -0
- package/v3/dist/domains/test-generation/services/tdd-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/services/test-data-generator.d.ts +34 -0
- package/v3/dist/domains/test-generation/services/test-data-generator.d.ts.map +1 -0
- package/v3/dist/domains/test-generation/services/test-data-generator.js +245 -0
- package/v3/dist/domains/test-generation/services/test-data-generator.js.map +1 -0
- package/v3/dist/domains/test-generation/services/test-generator.d.ts +51 -160
- package/v3/dist/domains/test-generation/services/test-generator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/services/test-generator.js +101 -1858
- package/v3/dist/domains/test-generation/services/test-generator.js.map +1 -1
- package/v3/dist/domains/visual-accessibility/index.d.ts +2 -1
- package/v3/dist/domains/visual-accessibility/index.d.ts.map +1 -1
- package/v3/dist/domains/visual-accessibility/index.js +1 -0
- package/v3/dist/domains/visual-accessibility/index.js.map +1 -1
- package/v3/dist/domains/visual-accessibility/interfaces.d.ts +131 -0
- package/v3/dist/domains/visual-accessibility/interfaces.d.ts.map +1 -1
- package/v3/dist/domains/visual-accessibility/plugin.d.ts +26 -0
- package/v3/dist/domains/visual-accessibility/plugin.d.ts.map +1 -1
- package/v3/dist/domains/visual-accessibility/plugin.js +153 -2
- package/v3/dist/domains/visual-accessibility/plugin.js.map +1 -1
- package/v3/dist/domains/visual-accessibility/services/accessibility-tester.d.ts +42 -1
- package/v3/dist/domains/visual-accessibility/services/accessibility-tester.d.ts.map +1 -1
- package/v3/dist/domains/visual-accessibility/services/accessibility-tester.js +69 -0
- package/v3/dist/domains/visual-accessibility/services/accessibility-tester.js.map +1 -1
- package/v3/dist/domains/visual-accessibility/services/eu-compliance.d.ts +138 -0
- package/v3/dist/domains/visual-accessibility/services/eu-compliance.d.ts.map +1 -0
- package/v3/dist/domains/visual-accessibility/services/eu-compliance.js +830 -0
- package/v3/dist/domains/visual-accessibility/services/eu-compliance.js.map +1 -0
- package/v3/dist/domains/visual-accessibility/services/index.d.ts +1 -0
- package/v3/dist/domains/visual-accessibility/services/index.d.ts.map +1 -1
- package/v3/dist/domains/visual-accessibility/services/index.js +1 -0
- package/v3/dist/domains/visual-accessibility/services/index.js.map +1 -1
- package/v3/dist/init/enhancements/claude-flow-adapter.d.ts +84 -0
- package/v3/dist/init/enhancements/claude-flow-adapter.d.ts.map +1 -0
- package/v3/dist/init/enhancements/claude-flow-adapter.js +250 -0
- package/v3/dist/init/enhancements/claude-flow-adapter.js.map +1 -0
- package/v3/dist/init/enhancements/detector.d.ts +10 -0
- package/v3/dist/init/enhancements/detector.d.ts.map +1 -0
- package/v3/dist/init/enhancements/detector.js +87 -0
- package/v3/dist/init/enhancements/detector.js.map +1 -0
- package/v3/dist/init/enhancements/index.d.ts +13 -0
- package/v3/dist/init/enhancements/index.d.ts.map +1 -0
- package/v3/dist/init/enhancements/index.js +25 -0
- package/v3/dist/init/enhancements/index.js.map +1 -0
- package/v3/dist/init/enhancements/types.d.ts +93 -0
- package/v3/dist/init/enhancements/types.d.ts.map +1 -0
- package/v3/dist/init/enhancements/types.js +6 -0
- package/v3/dist/init/enhancements/types.js.map +1 -0
- package/v3/dist/init/index.d.ts +8 -0
- package/v3/dist/init/index.d.ts.map +1 -1
- package/v3/dist/init/index.js +4 -0
- package/v3/dist/init/index.js.map +1 -1
- package/v3/dist/init/migration/config-migrator.d.ts +31 -0
- package/v3/dist/init/migration/config-migrator.d.ts.map +1 -0
- package/v3/dist/init/migration/config-migrator.js +133 -0
- package/v3/dist/init/migration/config-migrator.js.map +1 -0
- package/v3/dist/init/migration/data-migrator.d.ts +72 -0
- package/v3/dist/init/migration/data-migrator.d.ts.map +1 -0
- package/v3/dist/init/migration/data-migrator.js +233 -0
- package/v3/dist/init/migration/data-migrator.js.map +1 -0
- package/v3/dist/init/migration/detector.d.ts +44 -0
- package/v3/dist/init/migration/detector.d.ts.map +1 -0
- package/v3/dist/init/migration/detector.js +106 -0
- package/v3/dist/init/migration/detector.js.map +1 -0
- package/v3/dist/init/migration/index.d.ts +8 -0
- package/v3/dist/init/migration/index.d.ts.map +1 -0
- package/v3/dist/init/migration/index.js +8 -0
- package/v3/dist/init/migration/index.js.map +1 -0
- package/v3/dist/init/orchestrator.d.ts +68 -0
- package/v3/dist/init/orchestrator.d.ts.map +1 -0
- package/v3/dist/init/orchestrator.js +239 -0
- package/v3/dist/init/orchestrator.js.map +1 -0
- package/v3/dist/init/phases/01-detection.d.ts +30 -0
- package/v3/dist/init/phases/01-detection.d.ts.map +1 -0
- package/v3/dist/init/phases/01-detection.js +143 -0
- package/v3/dist/init/phases/01-detection.js.map +1 -0
- package/v3/dist/init/phases/02-analysis.d.ts +18 -0
- package/v3/dist/init/phases/02-analysis.d.ts.map +1 -0
- package/v3/dist/init/phases/02-analysis.js +28 -0
- package/v3/dist/init/phases/02-analysis.js.map +1 -0
- package/v3/dist/init/phases/03-configuration.d.ts +26 -0
- package/v3/dist/init/phases/03-configuration.d.ts.map +1 -0
- package/v3/dist/init/phases/03-configuration.js +98 -0
- package/v3/dist/init/phases/03-configuration.js.map +1 -0
- package/v3/dist/init/phases/04-database.d.ts +22 -0
- package/v3/dist/init/phases/04-database.d.ts.map +1 -0
- package/v3/dist/init/phases/04-database.js +88 -0
- package/v3/dist/init/phases/04-database.js.map +1 -0
- package/v3/dist/init/phases/05-learning.d.ts +28 -0
- package/v3/dist/init/phases/05-learning.d.ts.map +1 -0
- package/v3/dist/init/phases/05-learning.js +98 -0
- package/v3/dist/init/phases/05-learning.js.map +1 -0
- package/v3/dist/init/phases/06-code-intelligence.d.ts +33 -0
- package/v3/dist/init/phases/06-code-intelligence.d.ts.map +1 -0
- package/v3/dist/init/phases/06-code-intelligence.js +115 -0
- package/v3/dist/init/phases/06-code-intelligence.js.map +1 -0
- package/v3/dist/init/phases/07-hooks.d.ts +27 -0
- package/v3/dist/init/phases/07-hooks.d.ts.map +1 -0
- package/v3/dist/init/phases/07-hooks.js +209 -0
- package/v3/dist/init/phases/07-hooks.js.map +1 -0
- package/v3/dist/init/phases/08-mcp.d.ts +22 -0
- package/v3/dist/init/phases/08-mcp.d.ts.map +1 -0
- package/v3/dist/init/phases/08-mcp.js +62 -0
- package/v3/dist/init/phases/08-mcp.js.map +1 -0
- package/v3/dist/init/phases/09-assets.d.ts +23 -0
- package/v3/dist/init/phases/09-assets.d.ts.map +1 -0
- package/v3/dist/init/phases/09-assets.js +82 -0
- package/v3/dist/init/phases/09-assets.js.map +1 -0
- package/v3/dist/init/phases/10-workers.d.ts +23 -0
- package/v3/dist/init/phases/10-workers.d.ts.map +1 -0
- package/v3/dist/init/phases/10-workers.js +111 -0
- package/v3/dist/init/phases/10-workers.js.map +1 -0
- package/v3/dist/init/phases/11-claude-md.d.ts +26 -0
- package/v3/dist/init/phases/11-claude-md.d.ts.map +1 -0
- package/v3/dist/init/phases/11-claude-md.js +121 -0
- package/v3/dist/init/phases/11-claude-md.js.map +1 -0
- package/v3/dist/init/phases/12-verification.d.ts +61 -0
- package/v3/dist/init/phases/12-verification.d.ts.map +1 -0
- package/v3/dist/init/phases/12-verification.js +370 -0
- package/v3/dist/init/phases/12-verification.js.map +1 -0
- package/v3/dist/init/phases/index.d.ts +46 -0
- package/v3/dist/init/phases/index.d.ts.map +1 -0
- package/v3/dist/init/phases/index.js +64 -0
- package/v3/dist/init/phases/index.js.map +1 -0
- package/v3/dist/init/phases/phase-interface.d.ts +193 -0
- package/v3/dist/init/phases/phase-interface.d.ts.map +1 -0
- package/v3/dist/init/phases/phase-interface.js +119 -0
- package/v3/dist/init/phases/phase-interface.js.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.d.ts +24 -62
- package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.d.ts.map +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.js +45 -497
- package/v3/dist/integrations/agentic-flow/model-router/complexity-analyzer.js.map +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/router.js +2 -2
- package/v3/dist/integrations/agentic-flow/model-router/router.js.map +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/score-calculator.d.ts +98 -0
- package/v3/dist/integrations/agentic-flow/model-router/score-calculator.d.ts.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/score-calculator.js +197 -0
- package/v3/dist/integrations/agentic-flow/model-router/score-calculator.js.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.d.ts +102 -0
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.d.ts.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.js +372 -0
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.js.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.d.ts +64 -0
- package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.d.ts.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.js +120 -0
- package/v3/dist/integrations/agentic-flow/model-router/tier-recommender.js.map +1 -0
- package/v3/dist/integrations/coherence/coherence-service.d.ts +323 -0
- package/v3/dist/integrations/coherence/coherence-service.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/coherence-service.js +856 -0
- package/v3/dist/integrations/coherence/coherence-service.js.map +1 -0
- package/v3/dist/integrations/coherence/engines/category-adapter.d.ts +170 -0
- package/v3/dist/integrations/coherence/engines/category-adapter.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/engines/category-adapter.js +403 -0
- package/v3/dist/integrations/coherence/engines/category-adapter.js.map +1 -0
- package/v3/dist/integrations/coherence/engines/causal-adapter.d.ts +159 -0
- package/v3/dist/integrations/coherence/engines/causal-adapter.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/engines/causal-adapter.js +348 -0
- package/v3/dist/integrations/coherence/engines/causal-adapter.js.map +1 -0
- package/v3/dist/integrations/coherence/engines/cohomology-adapter.d.ts +174 -0
- package/v3/dist/integrations/coherence/engines/cohomology-adapter.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/engines/cohomology-adapter.js +401 -0
- package/v3/dist/integrations/coherence/engines/cohomology-adapter.js.map +1 -0
- package/v3/dist/integrations/coherence/engines/homotopy-adapter.d.ts +201 -0
- package/v3/dist/integrations/coherence/engines/homotopy-adapter.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/engines/homotopy-adapter.js +324 -0
- package/v3/dist/integrations/coherence/engines/homotopy-adapter.js.map +1 -0
- package/v3/dist/integrations/coherence/engines/index.d.ts +20 -0
- package/v3/dist/integrations/coherence/engines/index.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/engines/index.js +26 -0
- package/v3/dist/integrations/coherence/engines/index.js.map +1 -0
- package/v3/dist/integrations/coherence/engines/spectral-adapter.d.ts +193 -0
- package/v3/dist/integrations/coherence/engines/spectral-adapter.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/engines/spectral-adapter.js +565 -0
- package/v3/dist/integrations/coherence/engines/spectral-adapter.js.map +1 -0
- package/v3/dist/integrations/coherence/engines/witness-adapter.d.ts +175 -0
- package/v3/dist/integrations/coherence/engines/witness-adapter.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/engines/witness-adapter.js +377 -0
- package/v3/dist/integrations/coherence/engines/witness-adapter.js.map +1 -0
- package/v3/dist/integrations/coherence/index.d.ts +84 -0
- package/v3/dist/integrations/coherence/index.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/index.js +114 -0
- package/v3/dist/integrations/coherence/index.js.map +1 -0
- package/v3/dist/integrations/coherence/threshold-tuner.d.ts +396 -0
- package/v3/dist/integrations/coherence/threshold-tuner.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/threshold-tuner.js +538 -0
- package/v3/dist/integrations/coherence/threshold-tuner.js.map +1 -0
- package/v3/dist/integrations/coherence/types.d.ts +879 -0
- package/v3/dist/integrations/coherence/types.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/types.js +134 -0
- package/v3/dist/integrations/coherence/types.js.map +1 -0
- package/v3/dist/integrations/coherence/wasm-loader.d.ts +351 -0
- package/v3/dist/integrations/coherence/wasm-loader.d.ts.map +1 -0
- package/v3/dist/integrations/coherence/wasm-loader.js +842 -0
- package/v3/dist/integrations/coherence/wasm-loader.js.map +1 -0
- package/v3/dist/integrations/embeddings/index/HNSWIndex.d.ts.map +1 -1
- package/v3/dist/integrations/embeddings/index/HNSWIndex.js +4 -1
- package/v3/dist/integrations/embeddings/index/HNSWIndex.js.map +1 -1
- package/v3/dist/kernel/interfaces.d.ts +8 -1
- package/v3/dist/kernel/interfaces.d.ts.map +1 -1
- package/v3/dist/learning/aqe-learning-engine.d.ts +272 -0
- package/v3/dist/learning/aqe-learning-engine.d.ts.map +1 -0
- package/v3/dist/learning/aqe-learning-engine.js +708 -0
- package/v3/dist/learning/aqe-learning-engine.js.map +1 -0
- package/v3/dist/learning/causal-verifier.d.ts +244 -0
- package/v3/dist/learning/causal-verifier.d.ts.map +1 -0
- package/v3/dist/learning/causal-verifier.js +300 -0
- package/v3/dist/learning/causal-verifier.js.map +1 -0
- package/v3/dist/learning/experience-capture.d.ts +266 -0
- package/v3/dist/learning/experience-capture.d.ts.map +1 -0
- package/v3/dist/learning/experience-capture.js +647 -0
- package/v3/dist/learning/experience-capture.js.map +1 -0
- package/v3/dist/learning/index.d.ts +8 -0
- package/v3/dist/learning/index.d.ts.map +1 -1
- package/v3/dist/learning/index.js +16 -0
- package/v3/dist/learning/index.js.map +1 -1
- package/v3/dist/learning/memory-auditor.d.ts +235 -0
- package/v3/dist/learning/memory-auditor.d.ts.map +1 -0
- package/v3/dist/learning/memory-auditor.js +480 -0
- package/v3/dist/learning/memory-auditor.js.map +1 -0
- package/v3/dist/learning/pattern-store.d.ts.map +1 -1
- package/v3/dist/learning/pattern-store.js +27 -6
- package/v3/dist/learning/pattern-store.js.map +1 -1
- package/v3/dist/learning/qe-patterns.d.ts +15 -1
- package/v3/dist/learning/qe-patterns.d.ts.map +1 -1
- package/v3/dist/learning/qe-patterns.js +26 -5
- package/v3/dist/learning/qe-patterns.js.map +1 -1
- package/v3/dist/learning/qe-reasoning-bank.d.ts +38 -2
- package/v3/dist/learning/qe-reasoning-bank.d.ts.map +1 -1
- package/v3/dist/learning/qe-reasoning-bank.js +86 -4
- package/v3/dist/learning/qe-reasoning-bank.js.map +1 -1
- package/v3/dist/learning/real-qe-reasoning-bank.d.ts +32 -2
- package/v3/dist/learning/real-qe-reasoning-bank.d.ts.map +1 -1
- package/v3/dist/learning/real-qe-reasoning-bank.js +61 -6
- package/v3/dist/learning/real-qe-reasoning-bank.js.map +1 -1
- package/v3/dist/mcp/bundle.js +8786 -1737
- package/v3/dist/mcp/security/cve-prevention.d.ts +31 -134
- package/v3/dist/mcp/security/cve-prevention.d.ts.map +1 -1
- package/v3/dist/mcp/security/cve-prevention.js +37 -562
- package/v3/dist/mcp/security/cve-prevention.js.map +1 -1
- package/v3/dist/mcp/security/index.d.ts +5 -1
- package/v3/dist/mcp/security/index.d.ts.map +1 -1
- package/v3/dist/mcp/security/validators/command-validator.d.ts +41 -0
- package/v3/dist/mcp/security/validators/command-validator.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/command-validator.js +123 -0
- package/v3/dist/mcp/security/validators/command-validator.js.map +1 -0
- package/v3/dist/mcp/security/validators/crypto-validator.d.ts +40 -0
- package/v3/dist/mcp/security/validators/crypto-validator.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/crypto-validator.js +72 -0
- package/v3/dist/mcp/security/validators/crypto-validator.js.map +1 -0
- package/v3/dist/mcp/security/validators/index.d.ts +12 -0
- package/v3/dist/mcp/security/validators/index.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/index.js +22 -0
- package/v3/dist/mcp/security/validators/index.js.map +1 -0
- package/v3/dist/mcp/security/validators/input-sanitizer.d.ts +56 -0
- package/v3/dist/mcp/security/validators/input-sanitizer.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/input-sanitizer.js +157 -0
- package/v3/dist/mcp/security/validators/input-sanitizer.js.map +1 -0
- package/v3/dist/mcp/security/validators/interfaces.d.ts +164 -0
- package/v3/dist/mcp/security/validators/interfaces.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/interfaces.js +6 -0
- package/v3/dist/mcp/security/validators/interfaces.js.map +1 -0
- package/v3/dist/mcp/security/validators/path-traversal-validator.d.ts +50 -0
- package/v3/dist/mcp/security/validators/path-traversal-validator.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/path-traversal-validator.js +242 -0
- package/v3/dist/mcp/security/validators/path-traversal-validator.js.map +1 -0
- package/v3/dist/mcp/security/validators/regex-safety-validator.d.ts +50 -0
- package/v3/dist/mcp/security/validators/regex-safety-validator.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/regex-safety-validator.js +183 -0
- package/v3/dist/mcp/security/validators/regex-safety-validator.js.map +1 -0
- package/v3/dist/mcp/security/validators/validation-orchestrator.d.ts +66 -0
- package/v3/dist/mcp/security/validators/validation-orchestrator.d.ts.map +1 -0
- package/v3/dist/mcp/security/validators/validation-orchestrator.js +146 -0
- package/v3/dist/mcp/security/validators/validation-orchestrator.js.map +1 -0
- package/v3/dist/mcp/server.d.ts.map +1 -1
- package/v3/dist/mcp/server.js +1 -0
- package/v3/dist/mcp/server.js.map +1 -1
- package/v3/dist/mcp/tool-registry.d.ts +3 -1
- package/v3/dist/mcp/tool-registry.d.ts.map +1 -1
- package/v3/dist/mcp/tool-registry.js +155 -2
- package/v3/dist/mcp/tool-registry.js.map +1 -1
- package/v3/dist/mcp/tools/coherence/audit.d.ts +107 -0
- package/v3/dist/mcp/tools/coherence/audit.d.ts.map +1 -0
- package/v3/dist/mcp/tools/coherence/audit.js +236 -0
- package/v3/dist/mcp/tools/coherence/audit.js.map +1 -0
- package/v3/dist/mcp/tools/coherence/check.d.ts +106 -0
- package/v3/dist/mcp/tools/coherence/check.d.ts.map +1 -0
- package/v3/dist/mcp/tools/coherence/check.js +205 -0
- package/v3/dist/mcp/tools/coherence/check.js.map +1 -0
- package/v3/dist/mcp/tools/coherence/collapse.d.ts +123 -0
- package/v3/dist/mcp/tools/coherence/collapse.d.ts.map +1 -0
- package/v3/dist/mcp/tools/coherence/collapse.js +279 -0
- package/v3/dist/mcp/tools/coherence/collapse.js.map +1 -0
- package/v3/dist/mcp/tools/coherence/consensus.d.ts +100 -0
- package/v3/dist/mcp/tools/coherence/consensus.d.ts.map +1 -0
- package/v3/dist/mcp/tools/coherence/consensus.js +201 -0
- package/v3/dist/mcp/tools/coherence/consensus.js.map +1 -0
- package/v3/dist/mcp/tools/coherence/index.d.ts +31 -0
- package/v3/dist/mcp/tools/coherence/index.d.ts.map +1 -0
- package/v3/dist/mcp/tools/coherence/index.js +42 -0
- package/v3/dist/mcp/tools/coherence/index.js.map +1 -0
- package/v3/dist/mcp/tools/index.d.ts +6 -1
- package/v3/dist/mcp/tools/index.d.ts.map +1 -1
- package/v3/dist/mcp/tools/index.js +9 -1
- package/v3/dist/mcp/tools/index.js.map +1 -1
- package/v3/dist/mcp/tools/mincut/index.d.ts +1 -1
- package/v3/dist/mcp/tools/mincut/index.d.ts.map +1 -1
- package/v3/dist/mcp/tools/mincut/index.js.map +1 -1
- package/v3/dist/mcp/tools/registry.d.ts +4 -0
- package/v3/dist/mcp/tools/registry.d.ts.map +1 -1
- package/v3/dist/mcp/tools/registry.js +5 -0
- package/v3/dist/mcp/tools/registry.js.map +1 -1
- package/v3/dist/mcp/tools/test-generation/generate.d.ts +1 -0
- package/v3/dist/mcp/tools/test-generation/generate.d.ts.map +1 -1
- package/v3/dist/mcp/tools/test-generation/generate.js +3 -2
- package/v3/dist/mcp/tools/test-generation/generate.js.map +1 -1
- package/v3/dist/mcp/types.d.ts +1 -1
- package/v3/dist/mcp/types.d.ts.map +1 -1
- package/v3/dist/strange-loop/belief-reconciler.d.ts +357 -0
- package/v3/dist/strange-loop/belief-reconciler.d.ts.map +1 -0
- package/v3/dist/strange-loop/belief-reconciler.js +696 -0
- package/v3/dist/strange-loop/belief-reconciler.js.map +1 -0
- package/v3/dist/strange-loop/index.d.ts +1 -0
- package/v3/dist/strange-loop/index.d.ts.map +1 -1
- package/v3/dist/strange-loop/index.js +2 -0
- package/v3/dist/strange-loop/index.js.map +1 -1
- package/v3/dist/strange-loop/strange-loop.d.ts +177 -5
- package/v3/dist/strange-loop/strange-loop.d.ts.map +1 -1
- package/v3/dist/strange-loop/strange-loop.js +452 -9
- package/v3/dist/strange-loop/strange-loop.js.map +1 -1
- package/v3/dist/strange-loop/types.d.ts +205 -1
- package/v3/dist/strange-loop/types.d.ts.map +1 -1
- package/v3/dist/strange-loop/types.js +5 -0
- package/v3/dist/strange-loop/types.js.map +1 -1
- package/v3/dist/sync/cloud/index.d.ts +8 -0
- package/v3/dist/sync/cloud/index.d.ts.map +1 -0
- package/v3/dist/sync/cloud/index.js +8 -0
- package/v3/dist/sync/cloud/index.js.map +1 -0
- package/v3/dist/sync/cloud/postgres-writer.d.ts +88 -0
- package/v3/dist/sync/cloud/postgres-writer.d.ts.map +1 -0
- package/v3/dist/sync/cloud/postgres-writer.js +319 -0
- package/v3/dist/sync/cloud/postgres-writer.js.map +1 -0
- package/v3/dist/sync/cloud/tunnel-manager.d.ts +75 -0
- package/v3/dist/sync/cloud/tunnel-manager.d.ts.map +1 -0
- package/v3/dist/sync/cloud/tunnel-manager.js +221 -0
- package/v3/dist/sync/cloud/tunnel-manager.js.map +1 -0
- package/v3/dist/sync/index.d.ts +35 -0
- package/v3/dist/sync/index.d.ts.map +1 -0
- package/v3/dist/sync/index.js +35 -0
- package/v3/dist/sync/index.js.map +1 -0
- package/v3/dist/sync/interfaces.d.ts +245 -0
- package/v3/dist/sync/interfaces.d.ts.map +1 -0
- package/v3/dist/sync/interfaces.js +160 -0
- package/v3/dist/sync/interfaces.js.map +1 -0
- package/v3/dist/sync/readers/index.d.ts +8 -0
- package/v3/dist/sync/readers/index.d.ts.map +1 -0
- package/v3/dist/sync/readers/index.js +8 -0
- package/v3/dist/sync/readers/index.js.map +1 -0
- package/v3/dist/sync/readers/json-reader.d.ts +95 -0
- package/v3/dist/sync/readers/json-reader.d.ts.map +1 -0
- package/v3/dist/sync/readers/json-reader.js +306 -0
- package/v3/dist/sync/readers/json-reader.js.map +1 -0
- package/v3/dist/sync/readers/sqlite-reader.d.ts +88 -0
- package/v3/dist/sync/readers/sqlite-reader.d.ts.map +1 -0
- package/v3/dist/sync/readers/sqlite-reader.js +255 -0
- package/v3/dist/sync/readers/sqlite-reader.js.map +1 -0
- package/v3/dist/sync/sync-agent.d.ts +116 -0
- package/v3/dist/sync/sync-agent.d.ts.map +1 -0
- package/v3/dist/sync/sync-agent.js +416 -0
- package/v3/dist/sync/sync-agent.js.map +1 -0
- package/v3/package.json +17 -2
|
@@ -2,32 +2,46 @@
|
|
|
2
2
|
* Agentic QE v3 - Test Generation Service
|
|
3
3
|
* Implements ITestGenerationService for AI-powered test generation
|
|
4
4
|
*
|
|
5
|
-
* Uses
|
|
5
|
+
* Uses Strategy Pattern generators for framework-specific code generation
|
|
6
6
|
* Uses TypeScript AST parser for code analysis
|
|
7
|
+
* Delegates to specialized services for TDD, property tests, and test data
|
|
7
8
|
*/
|
|
8
9
|
import { v4 as uuidv4 } from 'uuid';
|
|
9
10
|
import * as fs from 'fs';
|
|
10
11
|
import * as path from 'path';
|
|
11
12
|
import * as ts from 'typescript';
|
|
12
|
-
import { faker } from '@faker-js/faker';
|
|
13
13
|
import { ok, err } from '../../../shared/types';
|
|
14
|
+
import { TestGeneratorFactory } from '../factories/test-generator-factory';
|
|
15
|
+
import { TDDGeneratorService } from './tdd-generator';
|
|
16
|
+
import { PropertyTestGeneratorService } from './property-test-generator';
|
|
17
|
+
import { TestDataGeneratorService } from './test-data-generator';
|
|
14
18
|
const DEFAULT_CONFIG = {
|
|
15
|
-
defaultFramework: '
|
|
19
|
+
defaultFramework: 'vitest',
|
|
16
20
|
maxTestsPerFile: 50,
|
|
17
21
|
coverageTargetDefault: 80,
|
|
18
22
|
enableAIGeneration: true,
|
|
19
23
|
};
|
|
20
24
|
/**
|
|
21
25
|
* Test Generation Service Implementation
|
|
22
|
-
* Uses
|
|
23
|
-
*
|
|
26
|
+
* Uses Strategy Pattern generators for framework-specific test generation
|
|
27
|
+
* Delegates TDD, property testing, and test data to specialized services
|
|
28
|
+
*
|
|
29
|
+
* ADR-XXX: Refactored to use Dependency Injection for better testability and flexibility
|
|
24
30
|
*/
|
|
25
31
|
export class TestGeneratorService {
|
|
26
|
-
memory;
|
|
27
32
|
config;
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
memory;
|
|
34
|
+
generatorFactory;
|
|
35
|
+
tddGenerator;
|
|
36
|
+
propertyTestGenerator;
|
|
37
|
+
testDataGenerator;
|
|
38
|
+
constructor(dependencies, config = {}) {
|
|
30
39
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
40
|
+
this.memory = dependencies.memory;
|
|
41
|
+
this.generatorFactory = dependencies.generatorFactory || new TestGeneratorFactory();
|
|
42
|
+
this.tddGenerator = dependencies.tddGenerator || new TDDGeneratorService();
|
|
43
|
+
this.propertyTestGenerator = dependencies.propertyTestGenerator || new PropertyTestGeneratorService();
|
|
44
|
+
this.testDataGenerator = dependencies.testDataGenerator || new TestDataGeneratorService();
|
|
31
45
|
}
|
|
32
46
|
/**
|
|
33
47
|
* Generate tests for given source files
|
|
@@ -40,7 +54,6 @@ export class TestGeneratorService {
|
|
|
40
54
|
}
|
|
41
55
|
const tests = [];
|
|
42
56
|
const patternsUsed = [];
|
|
43
|
-
// Process each source file
|
|
44
57
|
for (const sourceFile of sourceFiles) {
|
|
45
58
|
const fileTests = await this.generateTestsForFile(sourceFile, testType, framework, patterns);
|
|
46
59
|
if (fileTests.success) {
|
|
@@ -48,14 +61,12 @@ export class TestGeneratorService {
|
|
|
48
61
|
patternsUsed.push(...fileTests.value.patternsUsed);
|
|
49
62
|
}
|
|
50
63
|
}
|
|
51
|
-
// Calculate coverage estimate based on test count and complexity
|
|
52
64
|
const coverageEstimate = this.estimateCoverage(tests, coverageTarget);
|
|
53
|
-
// Store generation metadata in memory
|
|
54
65
|
await this.storeGenerationMetadata(tests, patternsUsed);
|
|
55
66
|
return ok({
|
|
56
67
|
tests,
|
|
57
68
|
coverageEstimate,
|
|
58
|
-
patternsUsed:
|
|
69
|
+
patternsUsed: Array.from(new Set(patternsUsed)),
|
|
59
70
|
});
|
|
60
71
|
}
|
|
61
72
|
catch (error) {
|
|
@@ -70,13 +81,13 @@ export class TestGeneratorService {
|
|
|
70
81
|
if (uncoveredLines.length === 0) {
|
|
71
82
|
return ok([]);
|
|
72
83
|
}
|
|
73
|
-
// Analyze uncovered lines and generate targeted tests
|
|
74
|
-
// Groups consecutive lines and generates tests for each block
|
|
75
84
|
const tests = [];
|
|
76
|
-
// Group uncovered lines into logical blocks
|
|
77
85
|
const lineGroups = this.groupConsecutiveLines(uncoveredLines);
|
|
86
|
+
const frameworkType = this.generatorFactory.supports(framework)
|
|
87
|
+
? framework
|
|
88
|
+
: this.config.defaultFramework;
|
|
78
89
|
for (const group of lineGroups) {
|
|
79
|
-
const test = await this.generateTestForLines(file, group,
|
|
90
|
+
const test = await this.generateTestForLines(file, group, frameworkType);
|
|
80
91
|
if (test) {
|
|
81
92
|
tests.push(test);
|
|
82
93
|
}
|
|
@@ -88,87 +99,49 @@ export class TestGeneratorService {
|
|
|
88
99
|
}
|
|
89
100
|
}
|
|
90
101
|
/**
|
|
91
|
-
* Generate tests following TDD workflow
|
|
102
|
+
* Generate tests following TDD workflow - delegates to TDDGeneratorService
|
|
92
103
|
*/
|
|
93
104
|
async generateTDDTests(request) {
|
|
94
105
|
try {
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
case 'red':
|
|
98
|
-
// Generate failing test first
|
|
99
|
-
return ok(await this.generateRedPhaseTest(feature, behavior, framework));
|
|
100
|
-
case 'green':
|
|
101
|
-
// Generate minimal implementation to make test pass
|
|
102
|
-
return ok(await this.generateGreenPhaseCode(feature, behavior, framework));
|
|
103
|
-
case 'refactor':
|
|
104
|
-
// Suggest refactoring improvements
|
|
105
|
-
return ok(await this.generateRefactoringSuggestions(feature, behavior));
|
|
106
|
-
default:
|
|
107
|
-
return err(new Error(`Unknown TDD phase: ${phase}`));
|
|
108
|
-
}
|
|
106
|
+
const result = await this.tddGenerator.generateTDDTests(request);
|
|
107
|
+
return ok(result);
|
|
109
108
|
}
|
|
110
109
|
catch (error) {
|
|
111
110
|
return err(error instanceof Error ? error : new Error(String(error)));
|
|
112
111
|
}
|
|
113
112
|
}
|
|
114
113
|
/**
|
|
115
|
-
* Generate property-based tests
|
|
114
|
+
* Generate property-based tests - delegates to PropertyTestGeneratorService
|
|
116
115
|
*/
|
|
117
116
|
async generatePropertyTests(request) {
|
|
118
117
|
try {
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
const tests = properties.map((property) => ({
|
|
122
|
-
property,
|
|
123
|
-
testCode: this.generatePropertyTestCode(funcName, property, constraints),
|
|
124
|
-
generators: this.inferGenerators(property, constraints),
|
|
125
|
-
}));
|
|
126
|
-
return ok({
|
|
127
|
-
tests,
|
|
128
|
-
arbitraries: this.collectArbitraries(tests),
|
|
129
|
-
});
|
|
118
|
+
const result = await this.propertyTestGenerator.generatePropertyTests(request);
|
|
119
|
+
return ok(result);
|
|
130
120
|
}
|
|
131
121
|
catch (error) {
|
|
132
122
|
return err(error instanceof Error ? error : new Error(String(error)));
|
|
133
123
|
}
|
|
134
124
|
}
|
|
135
125
|
/**
|
|
136
|
-
* Generate test data based on schema
|
|
126
|
+
* Generate test data based on schema - delegates to TestDataGeneratorService
|
|
137
127
|
*/
|
|
138
128
|
async generateTestData(request) {
|
|
139
129
|
try {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
const seed = Date.now();
|
|
143
|
-
const records = [];
|
|
144
|
-
for (let i = 0; i < count; i++) {
|
|
145
|
-
const record = this.generateRecordFromSchema(schema, seed + i, locale);
|
|
146
|
-
records.push(record);
|
|
147
|
-
}
|
|
148
|
-
// Handle relationships if needed
|
|
149
|
-
if (preserveRelationships) {
|
|
150
|
-
this.linkRelatedRecords(records, schema);
|
|
151
|
-
}
|
|
152
|
-
return ok({
|
|
153
|
-
records,
|
|
154
|
-
schema,
|
|
155
|
-
seed,
|
|
156
|
-
});
|
|
130
|
+
const result = await this.testDataGenerator.generateTestData(request);
|
|
131
|
+
return ok(result);
|
|
157
132
|
}
|
|
158
133
|
catch (error) {
|
|
159
134
|
return err(error instanceof Error ? error : new Error(String(error)));
|
|
160
135
|
}
|
|
161
136
|
}
|
|
162
137
|
// ============================================================================
|
|
163
|
-
// Private Helper Methods
|
|
138
|
+
// Private Helper Methods - Core Test Generation
|
|
164
139
|
// ============================================================================
|
|
165
140
|
async generateTestsForFile(sourceFile, testType, framework, patterns) {
|
|
166
141
|
const testFile = this.getTestFilePath(sourceFile, framework);
|
|
167
142
|
const patternsUsed = [];
|
|
168
|
-
// Look for applicable patterns from memory
|
|
169
143
|
const applicablePatterns = await this.findApplicablePatterns(sourceFile, patterns);
|
|
170
144
|
patternsUsed.push(...applicablePatterns.map((p) => p.name));
|
|
171
|
-
// Try to read and parse the source file for real AST analysis
|
|
172
145
|
let codeAnalysis = null;
|
|
173
146
|
try {
|
|
174
147
|
const content = fs.readFileSync(sourceFile, 'utf-8');
|
|
@@ -177,17 +150,20 @@ export class TestGeneratorService {
|
|
|
177
150
|
catch {
|
|
178
151
|
// File doesn't exist or can't be read - use stub generation
|
|
179
152
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
153
|
+
const generator = this.generatorFactory.create(framework);
|
|
154
|
+
const moduleName = this.extractModuleName(sourceFile);
|
|
155
|
+
const importPath = this.getImportPath(sourceFile);
|
|
156
|
+
const context = {
|
|
157
|
+
moduleName,
|
|
158
|
+
importPath,
|
|
159
|
+
testType,
|
|
160
|
+
patterns: applicablePatterns,
|
|
161
|
+
analysis: codeAnalysis ?? undefined,
|
|
162
|
+
};
|
|
163
|
+
const testCode = generator.generateTests(context);
|
|
188
164
|
const test = {
|
|
189
165
|
id: uuidv4(),
|
|
190
|
-
name: `${
|
|
166
|
+
name: `${moduleName} tests`,
|
|
191
167
|
sourceFile,
|
|
192
168
|
testFile,
|
|
193
169
|
testCode,
|
|
@@ -196,19 +172,36 @@ export class TestGeneratorService {
|
|
|
196
172
|
};
|
|
197
173
|
return ok({ tests: [test], patternsUsed });
|
|
198
174
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
175
|
+
async generateTestForLines(file, lines, framework) {
|
|
176
|
+
if (lines.length === 0)
|
|
177
|
+
return null;
|
|
178
|
+
const testId = uuidv4();
|
|
179
|
+
const testFile = this.getTestFilePath(file, framework);
|
|
180
|
+
const moduleName = this.extractModuleName(file);
|
|
181
|
+
const importPath = this.getImportPath(file);
|
|
182
|
+
const generator = this.generatorFactory.create(framework);
|
|
183
|
+
const testCode = generator.generateCoverageTests(moduleName, importPath, lines);
|
|
184
|
+
return {
|
|
185
|
+
id: testId,
|
|
186
|
+
name: `Coverage test for lines ${lines[0]}-${lines[lines.length - 1]}`,
|
|
187
|
+
sourceFile: file,
|
|
188
|
+
testFile,
|
|
189
|
+
testCode,
|
|
190
|
+
type: 'unit',
|
|
191
|
+
assertions: this.countAssertions(testCode),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
// ============================================================================
|
|
195
|
+
// Private Helper Methods - AST Analysis
|
|
196
|
+
// ============================================================================
|
|
202
197
|
analyzeSourceCode(content, fileName) {
|
|
203
198
|
const sourceFile = ts.createSourceFile(path.basename(fileName), content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
204
199
|
const functions = [];
|
|
205
200
|
const classes = [];
|
|
206
201
|
const visit = (node) => {
|
|
207
|
-
// Extract function declarations
|
|
208
202
|
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
209
203
|
functions.push(this.extractFunctionInfo(node, sourceFile));
|
|
210
204
|
}
|
|
211
|
-
// Extract arrow functions assigned to variables
|
|
212
205
|
else if (ts.isVariableStatement(node)) {
|
|
213
206
|
for (const declaration of node.declarationList.declarations) {
|
|
214
207
|
if (ts.isVariableDeclaration(declaration) &&
|
|
@@ -220,7 +213,6 @@ export class TestGeneratorService {
|
|
|
220
213
|
}
|
|
221
214
|
}
|
|
222
215
|
}
|
|
223
|
-
// Extract class declarations
|
|
224
216
|
else if (ts.isClassDeclaration(node) && node.name) {
|
|
225
217
|
classes.push(this.extractClassInfo(node, sourceFile));
|
|
226
218
|
}
|
|
@@ -229,9 +221,6 @@ export class TestGeneratorService {
|
|
|
229
221
|
ts.forEachChild(sourceFile, visit);
|
|
230
222
|
return { functions, classes };
|
|
231
223
|
}
|
|
232
|
-
/**
|
|
233
|
-
* Extract function information from AST
|
|
234
|
-
*/
|
|
235
224
|
extractFunctionInfo(node, sourceFile) {
|
|
236
225
|
const name = node.name?.getText(sourceFile) || 'anonymous';
|
|
237
226
|
const parameters = this.extractParameters(node.parameters, sourceFile);
|
|
@@ -252,9 +241,6 @@ export class TestGeneratorService {
|
|
|
252
241
|
body: node.body?.getText(sourceFile),
|
|
253
242
|
};
|
|
254
243
|
}
|
|
255
|
-
/**
|
|
256
|
-
* Extract arrow function information from AST
|
|
257
|
-
*/
|
|
258
244
|
extractArrowFunctionInfo(name, node, sourceFile, parentNode) {
|
|
259
245
|
const parameters = this.extractParameters(node.parameters, sourceFile);
|
|
260
246
|
const returnType = node.type?.getText(sourceFile);
|
|
@@ -275,9 +261,6 @@ export class TestGeneratorService {
|
|
|
275
261
|
body: node.body?.getText(sourceFile),
|
|
276
262
|
};
|
|
277
263
|
}
|
|
278
|
-
/**
|
|
279
|
-
* Extract class information from AST
|
|
280
|
-
*/
|
|
281
264
|
extractClassInfo(node, sourceFile) {
|
|
282
265
|
const name = node.name?.getText(sourceFile) || 'AnonymousClass';
|
|
283
266
|
const methods = [];
|
|
@@ -331,9 +314,6 @@ export class TestGeneratorService {
|
|
|
331
314
|
constructorParams,
|
|
332
315
|
};
|
|
333
316
|
}
|
|
334
|
-
/**
|
|
335
|
-
* Extract parameters from a function
|
|
336
|
-
*/
|
|
337
317
|
extractParameters(params, sourceFile) {
|
|
338
318
|
return params.map((param) => ({
|
|
339
319
|
name: param.name.getText(sourceFile),
|
|
@@ -342,9 +322,6 @@ export class TestGeneratorService {
|
|
|
342
322
|
defaultValue: param.initializer?.getText(sourceFile),
|
|
343
323
|
}));
|
|
344
324
|
}
|
|
345
|
-
/**
|
|
346
|
-
* Calculate cyclomatic complexity of a node
|
|
347
|
-
*/
|
|
348
325
|
calculateComplexity(node) {
|
|
349
326
|
let complexity = 1;
|
|
350
327
|
const visit = (n) => {
|
|
@@ -374,452 +351,17 @@ export class TestGeneratorService {
|
|
|
374
351
|
ts.forEachChild(node, visit);
|
|
375
352
|
return complexity;
|
|
376
353
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
generateRealTestCode(sourceFile, testType, framework, analysis, patterns) {
|
|
381
|
-
const moduleName = this.extractModuleName(sourceFile);
|
|
382
|
-
const importPath = this.getImportPath(sourceFile);
|
|
383
|
-
switch (framework) {
|
|
384
|
-
case 'jest':
|
|
385
|
-
case 'vitest':
|
|
386
|
-
return this.generateRealJestVitestTest(moduleName, importPath, testType, analysis, patterns, framework);
|
|
387
|
-
case 'mocha':
|
|
388
|
-
return this.generateRealMochaTest(moduleName, importPath, testType, analysis, patterns);
|
|
389
|
-
case 'pytest':
|
|
390
|
-
return this.generateRealPytestTest(moduleName, importPath, testType, analysis, patterns);
|
|
391
|
-
default:
|
|
392
|
-
return this.generateRealJestVitestTest(moduleName, importPath, testType, analysis, patterns, 'vitest');
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
/**
|
|
396
|
-
* Generate real Jest/Vitest test code
|
|
397
|
-
*/
|
|
398
|
-
generateRealJestVitestTest(moduleName, importPath, testType, analysis, patterns, framework) {
|
|
399
|
-
const patternComment = patterns.length > 0
|
|
400
|
-
? `// Applied patterns: ${patterns.map((p) => p.name).join(', ')}\n`
|
|
401
|
-
: '';
|
|
402
|
-
// Collect all exports to import
|
|
403
|
-
const exports = [];
|
|
404
|
-
for (const fn of analysis.functions) {
|
|
405
|
-
if (fn.isExported)
|
|
406
|
-
exports.push(fn.name);
|
|
407
|
-
}
|
|
408
|
-
for (const cls of analysis.classes) {
|
|
409
|
-
if (cls.isExported)
|
|
410
|
-
exports.push(cls.name);
|
|
411
|
-
}
|
|
412
|
-
const importStatement = exports.length > 0
|
|
413
|
-
? `import { ${exports.join(', ')} } from '${importPath}';`
|
|
414
|
-
: `import * as ${moduleName} from '${importPath}';`;
|
|
415
|
-
let testCode = `${patternComment}import { describe, it, expect, beforeEach${framework === 'vitest' ? ', vi' : ''} } from '${framework}';
|
|
416
|
-
${importStatement}
|
|
417
|
-
|
|
418
|
-
`;
|
|
419
|
-
// Generate tests for each function
|
|
420
|
-
for (const fn of analysis.functions) {
|
|
421
|
-
testCode += this.generateFunctionTests(fn, testType);
|
|
422
|
-
}
|
|
423
|
-
// Generate tests for each class
|
|
424
|
-
for (const cls of analysis.classes) {
|
|
425
|
-
testCode += this.generateClassTests(cls, testType);
|
|
426
|
-
}
|
|
427
|
-
return testCode;
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Generate tests for a function
|
|
431
|
-
*/
|
|
432
|
-
generateFunctionTests(fn, _testType) {
|
|
433
|
-
const testCases = this.generateTestCasesForFunction(fn);
|
|
434
|
-
let code = `describe('${fn.name}', () => {\n`;
|
|
435
|
-
for (const testCase of testCases) {
|
|
436
|
-
if (testCase.setup) {
|
|
437
|
-
code += ` ${testCase.setup}\n\n`;
|
|
438
|
-
}
|
|
439
|
-
const asyncPrefix = fn.isAsync ? 'async ' : '';
|
|
440
|
-
code += ` it('${testCase.description}', ${asyncPrefix}() => {\n`;
|
|
441
|
-
code += ` ${testCase.action}\n`;
|
|
442
|
-
code += ` ${testCase.assertion}\n`;
|
|
443
|
-
code += ` });\n\n`;
|
|
444
|
-
}
|
|
445
|
-
code += `});\n\n`;
|
|
446
|
-
return code;
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* Generate test cases for a function
|
|
450
|
-
*/
|
|
451
|
-
generateTestCasesForFunction(fn) {
|
|
452
|
-
const testCases = [];
|
|
453
|
-
// Generate valid input test
|
|
454
|
-
const validParams = fn.parameters.map((p) => this.generateTestValue(p)).join(', ');
|
|
455
|
-
const fnCall = fn.isAsync ? `await ${fn.name}(${validParams})` : `${fn.name}(${validParams})`;
|
|
456
|
-
testCases.push({
|
|
457
|
-
description: 'should handle valid input correctly',
|
|
458
|
-
type: 'happy-path',
|
|
459
|
-
action: `const result = ${fnCall};`,
|
|
460
|
-
assertion: 'expect(result).toBeDefined();',
|
|
461
|
-
});
|
|
462
|
-
// Generate tests for each parameter
|
|
463
|
-
for (const param of fn.parameters) {
|
|
464
|
-
if (!param.optional) {
|
|
465
|
-
// Test with undefined
|
|
466
|
-
const paramsWithUndefined = fn.parameters
|
|
467
|
-
.map((p) => (p.name === param.name ? 'undefined' : this.generateTestValue(p)))
|
|
468
|
-
.join(', ');
|
|
469
|
-
testCases.push({
|
|
470
|
-
description: `should handle undefined ${param.name}`,
|
|
471
|
-
type: 'error-handling',
|
|
472
|
-
action: fn.isAsync
|
|
473
|
-
? `const action = async () => await ${fn.name}(${paramsWithUndefined});`
|
|
474
|
-
: `const action = () => ${fn.name}(${paramsWithUndefined});`,
|
|
475
|
-
assertion: 'expect(action).toThrow();',
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
// Type-specific boundary tests
|
|
479
|
-
if (param.type?.includes('string')) {
|
|
480
|
-
const paramsWithEmpty = fn.parameters
|
|
481
|
-
.map((p) => (p.name === param.name ? "''" : this.generateTestValue(p)))
|
|
482
|
-
.join(', ');
|
|
483
|
-
const emptyCall = fn.isAsync
|
|
484
|
-
? `await ${fn.name}(${paramsWithEmpty})`
|
|
485
|
-
: `${fn.name}(${paramsWithEmpty})`;
|
|
486
|
-
testCases.push({
|
|
487
|
-
description: `should handle empty string for ${param.name}`,
|
|
488
|
-
type: 'boundary',
|
|
489
|
-
action: `const result = ${emptyCall};`,
|
|
490
|
-
assertion: 'expect(result).toBeDefined();',
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
if (param.type?.includes('number')) {
|
|
494
|
-
const paramsWithZero = fn.parameters
|
|
495
|
-
.map((p) => (p.name === param.name ? '0' : this.generateTestValue(p)))
|
|
496
|
-
.join(', ');
|
|
497
|
-
const zeroCall = fn.isAsync
|
|
498
|
-
? `await ${fn.name}(${paramsWithZero})`
|
|
499
|
-
: `${fn.name}(${paramsWithZero})`;
|
|
500
|
-
testCases.push({
|
|
501
|
-
description: `should handle zero for ${param.name}`,
|
|
502
|
-
type: 'boundary',
|
|
503
|
-
action: `const result = ${zeroCall};`,
|
|
504
|
-
assertion: 'expect(result).toBeDefined();',
|
|
505
|
-
});
|
|
506
|
-
const paramsWithNegative = fn.parameters
|
|
507
|
-
.map((p) => (p.name === param.name ? '-1' : this.generateTestValue(p)))
|
|
508
|
-
.join(', ');
|
|
509
|
-
const negativeCall = fn.isAsync
|
|
510
|
-
? `await ${fn.name}(${paramsWithNegative})`
|
|
511
|
-
: `${fn.name}(${paramsWithNegative})`;
|
|
512
|
-
testCases.push({
|
|
513
|
-
description: `should handle negative value for ${param.name}`,
|
|
514
|
-
type: 'edge-case',
|
|
515
|
-
action: `const result = ${negativeCall};`,
|
|
516
|
-
assertion: 'expect(result).toBeDefined();',
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
if (param.type?.includes('[]') || param.type?.includes('Array')) {
|
|
520
|
-
const paramsWithEmpty = fn.parameters
|
|
521
|
-
.map((p) => (p.name === param.name ? '[]' : this.generateTestValue(p)))
|
|
522
|
-
.join(', ');
|
|
523
|
-
const emptyCall = fn.isAsync
|
|
524
|
-
? `await ${fn.name}(${paramsWithEmpty})`
|
|
525
|
-
: `${fn.name}(${paramsWithEmpty})`;
|
|
526
|
-
testCases.push({
|
|
527
|
-
description: `should handle empty array for ${param.name}`,
|
|
528
|
-
type: 'boundary',
|
|
529
|
-
action: `const result = ${emptyCall};`,
|
|
530
|
-
assertion: 'expect(result).toBeDefined();',
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
// Async rejection test
|
|
535
|
-
if (fn.isAsync) {
|
|
536
|
-
testCases.push({
|
|
537
|
-
description: 'should handle async rejection gracefully',
|
|
538
|
-
type: 'error-handling',
|
|
539
|
-
action: `// Mock or setup to cause rejection`,
|
|
540
|
-
assertion: `// await expect(${fn.name}(invalidParams)).rejects.toThrow();`,
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
return testCases;
|
|
544
|
-
}
|
|
545
|
-
/**
|
|
546
|
-
* Generate tests for a class
|
|
547
|
-
*/
|
|
548
|
-
generateClassTests(cls, testType) {
|
|
549
|
-
let code = `describe('${cls.name}', () => {\n`;
|
|
550
|
-
code += ` let instance: ${cls.name};\n\n`;
|
|
551
|
-
// Setup
|
|
552
|
-
if (cls.hasConstructor && cls.constructorParams) {
|
|
553
|
-
const constructorArgs = cls.constructorParams
|
|
554
|
-
.map((p) => this.generateTestValue(p))
|
|
555
|
-
.join(', ');
|
|
556
|
-
code += ` beforeEach(() => {\n`;
|
|
557
|
-
code += ` instance = new ${cls.name}(${constructorArgs});\n`;
|
|
558
|
-
code += ` });\n\n`;
|
|
559
|
-
}
|
|
560
|
-
else {
|
|
561
|
-
code += ` beforeEach(() => {\n`;
|
|
562
|
-
code += ` instance = new ${cls.name}();\n`;
|
|
563
|
-
code += ` });\n\n`;
|
|
564
|
-
}
|
|
565
|
-
// Constructor test
|
|
566
|
-
code += ` it('should instantiate correctly', () => {\n`;
|
|
567
|
-
code += ` expect(instance).toBeInstanceOf(${cls.name});\n`;
|
|
568
|
-
code += ` });\n\n`;
|
|
569
|
-
// Generate tests for each public method
|
|
570
|
-
for (const method of cls.methods) {
|
|
571
|
-
if (!method.name.startsWith('_') && !method.name.startsWith('#')) {
|
|
572
|
-
code += this.generateMethodTests(method, cls.name, testType);
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
code += `});\n\n`;
|
|
576
|
-
return code;
|
|
577
|
-
}
|
|
578
|
-
/**
|
|
579
|
-
* Generate tests for a class method
|
|
580
|
-
*/
|
|
581
|
-
generateMethodTests(method, _className, _testType) {
|
|
582
|
-
let code = ` describe('${method.name}', () => {\n`;
|
|
583
|
-
const validParams = method.parameters.map((p) => this.generateTestValue(p)).join(', ');
|
|
584
|
-
const methodCall = method.isAsync
|
|
585
|
-
? `await instance.${method.name}(${validParams})`
|
|
586
|
-
: `instance.${method.name}(${validParams})`;
|
|
587
|
-
// Happy path
|
|
588
|
-
const asyncPrefix = method.isAsync ? 'async ' : '';
|
|
589
|
-
code += ` it('should execute successfully', ${asyncPrefix}() => {\n`;
|
|
590
|
-
code += ` const result = ${methodCall};\n`;
|
|
591
|
-
code += ` expect(result).toBeDefined();\n`;
|
|
592
|
-
code += ` });\n`;
|
|
593
|
-
// Error handling for non-optional params
|
|
594
|
-
for (const param of method.parameters) {
|
|
595
|
-
if (!param.optional) {
|
|
596
|
-
const paramsWithUndefined = method.parameters
|
|
597
|
-
.map((p) => (p.name === param.name ? 'undefined as any' : this.generateTestValue(p)))
|
|
598
|
-
.join(', ');
|
|
599
|
-
code += `\n it('should handle invalid ${param.name}', () => {\n`;
|
|
600
|
-
code += ` expect(() => instance.${method.name}(${paramsWithUndefined})).toThrow();\n`;
|
|
601
|
-
code += ` });\n`;
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
code += ` });\n\n`;
|
|
605
|
-
return code;
|
|
606
|
-
}
|
|
607
|
-
/**
|
|
608
|
-
* Generate a test value for a parameter
|
|
609
|
-
*/
|
|
610
|
-
generateTestValue(param) {
|
|
611
|
-
if (param.defaultValue) {
|
|
612
|
-
return param.defaultValue;
|
|
613
|
-
}
|
|
614
|
-
const type = param.type?.toLowerCase() || 'unknown';
|
|
615
|
-
const name = param.name.toLowerCase();
|
|
616
|
-
// Infer from param name first
|
|
617
|
-
if (name.includes('id'))
|
|
618
|
-
return `'${faker.string.uuid()}'`;
|
|
619
|
-
if (name.includes('email'))
|
|
620
|
-
return `'${faker.internet.email()}'`;
|
|
621
|
-
if (name.includes('name'))
|
|
622
|
-
return `'${faker.person.fullName()}'`;
|
|
623
|
-
if (name.includes('url'))
|
|
624
|
-
return `'${faker.internet.url()}'`;
|
|
625
|
-
if (name.includes('date'))
|
|
626
|
-
return `new Date('${faker.date.recent().toISOString()}')`;
|
|
627
|
-
// Then by type
|
|
628
|
-
if (type.includes('string'))
|
|
629
|
-
return `'${faker.lorem.word()}'`;
|
|
630
|
-
if (type.includes('number'))
|
|
631
|
-
return String(faker.number.int({ min: 1, max: 100 }));
|
|
632
|
-
if (type.includes('boolean'))
|
|
633
|
-
return 'true';
|
|
634
|
-
if (type.includes('[]') || type.includes('array'))
|
|
635
|
-
return '[]';
|
|
636
|
-
if (type.includes('object') || type.includes('{'))
|
|
637
|
-
return '{}';
|
|
638
|
-
if (type.includes('function'))
|
|
639
|
-
return '() => {}';
|
|
640
|
-
if (type.includes('promise'))
|
|
641
|
-
return 'Promise.resolve()';
|
|
642
|
-
if (type.includes('date'))
|
|
643
|
-
return 'new Date()';
|
|
644
|
-
// Default
|
|
645
|
-
return `mock${param.name.charAt(0).toUpperCase() + param.name.slice(1)}`;
|
|
646
|
-
}
|
|
647
|
-
/**
|
|
648
|
-
* Generate real Mocha test code
|
|
649
|
-
*/
|
|
650
|
-
generateRealMochaTest(moduleName, importPath, testType, analysis, patterns) {
|
|
651
|
-
const patternComment = patterns.length > 0
|
|
652
|
-
? `// Applied patterns: ${patterns.map((p) => p.name).join(', ')}\n`
|
|
653
|
-
: '';
|
|
654
|
-
const exports = [];
|
|
655
|
-
for (const fn of analysis.functions) {
|
|
656
|
-
if (fn.isExported)
|
|
657
|
-
exports.push(fn.name);
|
|
658
|
-
}
|
|
659
|
-
for (const cls of analysis.classes) {
|
|
660
|
-
if (cls.isExported)
|
|
661
|
-
exports.push(cls.name);
|
|
662
|
-
}
|
|
663
|
-
const importStatement = exports.length > 0
|
|
664
|
-
? `import { ${exports.join(', ')} } from '${importPath}';`
|
|
665
|
-
: `import * as ${moduleName} from '${importPath}';`;
|
|
666
|
-
let code = `${patternComment}import { expect } from 'chai';
|
|
667
|
-
${importStatement}
|
|
668
|
-
|
|
669
|
-
describe('${moduleName} - ${testType} tests', function() {
|
|
670
|
-
`;
|
|
671
|
-
for (const fn of analysis.functions) {
|
|
672
|
-
code += this.generateMochaFunctionTests(fn);
|
|
673
|
-
}
|
|
674
|
-
for (const cls of analysis.classes) {
|
|
675
|
-
code += this.generateMochaClassTests(cls);
|
|
676
|
-
}
|
|
677
|
-
code += `});\n`;
|
|
678
|
-
return code;
|
|
679
|
-
}
|
|
680
|
-
/**
|
|
681
|
-
* Generate Mocha tests for a function
|
|
682
|
-
*/
|
|
683
|
-
generateMochaFunctionTests(fn) {
|
|
684
|
-
const validParams = fn.parameters.map((p) => this.generateTestValue(p)).join(', ');
|
|
685
|
-
const fnCall = fn.isAsync ? `await ${fn.name}(${validParams})` : `${fn.name}(${validParams})`;
|
|
686
|
-
let code = ` describe('${fn.name}', function() {\n`;
|
|
687
|
-
code += ` it('should handle valid input', ${fn.isAsync ? 'async ' : ''}function() {\n`;
|
|
688
|
-
code += ` const result = ${fnCall};\n`;
|
|
689
|
-
code += ` expect(result).to.not.be.undefined;\n`;
|
|
690
|
-
code += ` });\n`;
|
|
691
|
-
code += ` });\n\n`;
|
|
692
|
-
return code;
|
|
693
|
-
}
|
|
694
|
-
/**
|
|
695
|
-
* Generate Mocha tests for a class
|
|
696
|
-
*/
|
|
697
|
-
generateMochaClassTests(cls) {
|
|
698
|
-
const constructorArgs = cls.constructorParams?.map((p) => this.generateTestValue(p)).join(', ') || '';
|
|
699
|
-
let code = ` describe('${cls.name}', function() {\n`;
|
|
700
|
-
code += ` let instance;\n\n`;
|
|
701
|
-
code += ` beforeEach(function() {\n`;
|
|
702
|
-
code += ` instance = new ${cls.name}(${constructorArgs});\n`;
|
|
703
|
-
code += ` });\n\n`;
|
|
704
|
-
code += ` it('should instantiate correctly', function() {\n`;
|
|
705
|
-
code += ` expect(instance).to.be.instanceOf(${cls.name});\n`;
|
|
706
|
-
code += ` });\n`;
|
|
707
|
-
for (const method of cls.methods) {
|
|
708
|
-
if (!method.name.startsWith('_')) {
|
|
709
|
-
const methodParams = method.parameters.map((p) => this.generateTestValue(p)).join(', ');
|
|
710
|
-
code += `\n it('${method.name} should work', ${method.isAsync ? 'async ' : ''}function() {\n`;
|
|
711
|
-
code += ` const result = ${method.isAsync ? 'await ' : ''}instance.${method.name}(${methodParams});\n`;
|
|
712
|
-
code += ` expect(result).to.not.be.undefined;\n`;
|
|
713
|
-
code += ` });\n`;
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
code += ` });\n\n`;
|
|
717
|
-
return code;
|
|
718
|
-
}
|
|
719
|
-
/**
|
|
720
|
-
* Generate real Pytest test code
|
|
721
|
-
*/
|
|
722
|
-
generateRealPytestTest(moduleName, importPath, testType, analysis, patterns) {
|
|
723
|
-
const patternComment = patterns.length > 0
|
|
724
|
-
? `# Applied patterns: ${patterns.map((p) => p.name).join(', ')}\n`
|
|
725
|
-
: '';
|
|
726
|
-
const exports = [];
|
|
727
|
-
for (const fn of analysis.functions) {
|
|
728
|
-
if (fn.isExported)
|
|
729
|
-
exports.push(fn.name);
|
|
730
|
-
}
|
|
731
|
-
for (const cls of analysis.classes) {
|
|
732
|
-
if (cls.isExported)
|
|
733
|
-
exports.push(cls.name);
|
|
734
|
-
}
|
|
735
|
-
const pythonImport = importPath.replace(/\//g, '.').replace(/\.(ts|js)$/, '');
|
|
736
|
-
const importStatement = exports.length > 0
|
|
737
|
-
? `from ${pythonImport} import ${exports.join(', ')}`
|
|
738
|
-
: `import ${pythonImport} as ${moduleName}`;
|
|
739
|
-
let code = `${patternComment}import pytest
|
|
740
|
-
${importStatement}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
class Test${moduleName.charAt(0).toUpperCase() + moduleName.slice(1)}:
|
|
744
|
-
"""${testType} tests for ${moduleName}"""
|
|
745
|
-
|
|
746
|
-
`;
|
|
747
|
-
for (const fn of analysis.functions) {
|
|
748
|
-
code += this.generatePytestFunctionTests(fn);
|
|
749
|
-
}
|
|
750
|
-
for (const cls of analysis.classes) {
|
|
751
|
-
code += this.generatePytestClassTests(cls);
|
|
752
|
-
}
|
|
753
|
-
return code;
|
|
754
|
-
}
|
|
755
|
-
/**
|
|
756
|
-
* Generate Pytest tests for a function
|
|
757
|
-
*/
|
|
758
|
-
generatePytestFunctionTests(fn) {
|
|
759
|
-
const validParams = fn.parameters.map((p) => this.generatePythonTestValue(p)).join(', ');
|
|
760
|
-
let code = ` def test_${fn.name}_valid_input(self):\n`;
|
|
761
|
-
code += ` """Test ${fn.name} with valid input"""\n`;
|
|
762
|
-
code += ` result = ${fn.name}(${validParams})\n`;
|
|
763
|
-
code += ` assert result is not None\n\n`;
|
|
764
|
-
return code;
|
|
765
|
-
}
|
|
766
|
-
/**
|
|
767
|
-
* Generate Pytest tests for a class
|
|
768
|
-
*/
|
|
769
|
-
generatePytestClassTests(cls) {
|
|
770
|
-
const constructorArgs = cls.constructorParams?.map((p) => this.generatePythonTestValue(p)).join(', ') || '';
|
|
771
|
-
let code = `\nclass Test${cls.name}:\n`;
|
|
772
|
-
code += ` """Tests for ${cls.name}"""\n\n`;
|
|
773
|
-
code += ` @pytest.fixture\n`;
|
|
774
|
-
code += ` def instance(self):\n`;
|
|
775
|
-
code += ` return ${cls.name}(${constructorArgs})\n\n`;
|
|
776
|
-
code += ` def test_instantiation(self, instance):\n`;
|
|
777
|
-
code += ` assert isinstance(instance, ${cls.name})\n\n`;
|
|
778
|
-
for (const method of cls.methods) {
|
|
779
|
-
if (!method.name.startsWith('_')) {
|
|
780
|
-
const methodParams = method.parameters.map((p) => this.generatePythonTestValue(p)).join(', ');
|
|
781
|
-
code += ` def test_${method.name}(self, instance):\n`;
|
|
782
|
-
code += ` result = instance.${method.name}(${methodParams})\n`;
|
|
783
|
-
code += ` assert result is not None\n\n`;
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
return code;
|
|
787
|
-
}
|
|
788
|
-
/**
|
|
789
|
-
* Generate a Python test value for a parameter
|
|
790
|
-
*/
|
|
791
|
-
generatePythonTestValue(param) {
|
|
792
|
-
const type = param.type?.toLowerCase() || 'unknown';
|
|
793
|
-
const name = param.name.toLowerCase();
|
|
794
|
-
if (name.includes('id'))
|
|
795
|
-
return `"${faker.string.uuid()}"`;
|
|
796
|
-
if (name.includes('name'))
|
|
797
|
-
return `"${faker.person.fullName()}"`;
|
|
798
|
-
if (name.includes('email'))
|
|
799
|
-
return `"${faker.internet.email()}"`;
|
|
800
|
-
if (type.includes('str'))
|
|
801
|
-
return `"${faker.lorem.word()}"`;
|
|
802
|
-
if (type.includes('int') || type.includes('number')) {
|
|
803
|
-
return String(faker.number.int({ min: 1, max: 100 }));
|
|
804
|
-
}
|
|
805
|
-
if (type.includes('bool'))
|
|
806
|
-
return 'True';
|
|
807
|
-
if (type.includes('list') || type.includes('[]'))
|
|
808
|
-
return '[]';
|
|
809
|
-
if (type.includes('dict') || type.includes('{}'))
|
|
810
|
-
return '{}';
|
|
811
|
-
return 'None';
|
|
812
|
-
}
|
|
354
|
+
// ============================================================================
|
|
355
|
+
// Private Helper Methods - Utility Functions
|
|
356
|
+
// ============================================================================
|
|
813
357
|
async findApplicablePatterns(sourceFile, requestedPatterns) {
|
|
814
358
|
const patterns = [];
|
|
815
|
-
// Check memory for stored patterns
|
|
816
359
|
for (const patternName of requestedPatterns) {
|
|
817
360
|
const stored = await this.memory.get(`pattern:${patternName}`);
|
|
818
361
|
if (stored) {
|
|
819
362
|
patterns.push(stored);
|
|
820
363
|
}
|
|
821
364
|
}
|
|
822
|
-
// Also search for patterns by file type
|
|
823
365
|
const extension = sourceFile.split('.').pop() || '';
|
|
824
366
|
const searchResults = await this.memory.search(`pattern:*:${extension}`, 5);
|
|
825
367
|
for (const key of searchResults) {
|
|
@@ -830,1313 +372,6 @@ class Test${moduleName.charAt(0).toUpperCase() + moduleName.slice(1)}:
|
|
|
830
372
|
}
|
|
831
373
|
return patterns;
|
|
832
374
|
}
|
|
833
|
-
generateStubTestCode(sourceFile, testType, framework, patterns) {
|
|
834
|
-
const moduleName = this.extractModuleName(sourceFile);
|
|
835
|
-
const importPath = this.getImportPath(sourceFile);
|
|
836
|
-
// Generate framework-specific test template
|
|
837
|
-
switch (framework) {
|
|
838
|
-
case 'jest':
|
|
839
|
-
case 'vitest':
|
|
840
|
-
return this.generateJestVitestTest(moduleName, importPath, testType, patterns);
|
|
841
|
-
case 'mocha':
|
|
842
|
-
return this.generateMochaTest(moduleName, importPath, testType, patterns);
|
|
843
|
-
case 'pytest':
|
|
844
|
-
return this.generatePytestTest(moduleName, importPath, testType, patterns);
|
|
845
|
-
default:
|
|
846
|
-
return this.generateJestVitestTest(moduleName, importPath, testType, patterns);
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
generateJestVitestTest(moduleName, importPath, testType, patterns) {
|
|
850
|
-
const patternComment = patterns.length > 0
|
|
851
|
-
? `// Applied patterns: ${patterns.map((p) => p.name).join(', ')}\n`
|
|
852
|
-
: '';
|
|
853
|
-
// Generate pattern-aware test implementations
|
|
854
|
-
const basicOpsTest = this.generateBasicOpsTest(moduleName, patterns);
|
|
855
|
-
const edgeCaseTest = this.generateEdgeCaseTest(moduleName, patterns);
|
|
856
|
-
const errorHandlingTest = this.generateErrorHandlingTest(moduleName, patterns);
|
|
857
|
-
return `${patternComment}import { ${moduleName} } from '${importPath}';
|
|
858
|
-
|
|
859
|
-
describe('${moduleName}', () => {
|
|
860
|
-
describe('${testType} tests', () => {
|
|
861
|
-
it('should be defined', () => {
|
|
862
|
-
expect(${moduleName}).toBeDefined();
|
|
863
|
-
});
|
|
864
|
-
|
|
865
|
-
${basicOpsTest}
|
|
866
|
-
${edgeCaseTest}
|
|
867
|
-
${errorHandlingTest}
|
|
868
|
-
});
|
|
869
|
-
});
|
|
870
|
-
`;
|
|
871
|
-
}
|
|
872
|
-
/**
|
|
873
|
-
* Generate basic operations test based on patterns
|
|
874
|
-
*/
|
|
875
|
-
generateBasicOpsTest(moduleName, patterns) {
|
|
876
|
-
// Check for service pattern
|
|
877
|
-
const isService = patterns.some((p) => p.name.toLowerCase().includes('service') || p.name.toLowerCase().includes('repository'));
|
|
878
|
-
// Check for factory pattern
|
|
879
|
-
const isFactory = patterns.some((p) => p.name.toLowerCase().includes('factory'));
|
|
880
|
-
// Check for async patterns
|
|
881
|
-
const hasAsyncPattern = patterns.some((p) => p.name.toLowerCase().includes('async') || p.name.toLowerCase().includes('promise'));
|
|
882
|
-
if (isService) {
|
|
883
|
-
return ` it('should handle basic operations', async () => {
|
|
884
|
-
// Service pattern: test core functionality
|
|
885
|
-
const instance = new ${moduleName}();
|
|
886
|
-
expect(instance).toBeInstanceOf(${moduleName});
|
|
887
|
-
|
|
888
|
-
// Verify service is properly initialized
|
|
889
|
-
const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(instance))
|
|
890
|
-
.filter(m => m !== 'constructor');
|
|
891
|
-
expect(methods.length).toBeGreaterThan(0);
|
|
892
|
-
});`;
|
|
893
|
-
}
|
|
894
|
-
if (isFactory) {
|
|
895
|
-
return ` it('should handle basic operations', () => {
|
|
896
|
-
// Factory pattern: test object creation
|
|
897
|
-
const result = ${moduleName}.create ? ${moduleName}.create() : new ${moduleName}();
|
|
898
|
-
expect(result).toBeDefined();
|
|
899
|
-
expect(typeof result).not.toBe('undefined');
|
|
900
|
-
});`;
|
|
901
|
-
}
|
|
902
|
-
if (hasAsyncPattern) {
|
|
903
|
-
return ` it('should handle basic operations', async () => {
|
|
904
|
-
// Async pattern: test promise resolution
|
|
905
|
-
const instance = typeof ${moduleName} === 'function'
|
|
906
|
-
? new ${moduleName}()
|
|
907
|
-
: ${moduleName};
|
|
908
|
-
|
|
909
|
-
// Verify async methods resolve properly
|
|
910
|
-
if (typeof instance.execute === 'function') {
|
|
911
|
-
await expect(instance.execute()).resolves.toBeDefined();
|
|
912
|
-
}
|
|
913
|
-
});`;
|
|
914
|
-
}
|
|
915
|
-
// Default implementation
|
|
916
|
-
return ` it('should handle basic operations', () => {
|
|
917
|
-
// Verify module exports expected interface
|
|
918
|
-
const moduleType = typeof ${moduleName};
|
|
919
|
-
expect(['function', 'object']).toContain(moduleType);
|
|
920
|
-
|
|
921
|
-
if (moduleType === 'function') {
|
|
922
|
-
// Class or function: verify instantiation
|
|
923
|
-
const instance = new ${moduleName}();
|
|
924
|
-
expect(instance).toBeDefined();
|
|
925
|
-
} else {
|
|
926
|
-
// Object module: verify properties exist
|
|
927
|
-
expect(Object.keys(${moduleName}).length).toBeGreaterThan(0);
|
|
928
|
-
}
|
|
929
|
-
});`;
|
|
930
|
-
}
|
|
931
|
-
/**
|
|
932
|
-
* Generate edge case test based on patterns
|
|
933
|
-
*/
|
|
934
|
-
generateEdgeCaseTest(moduleName, patterns) {
|
|
935
|
-
const hasValidation = patterns.some((p) => p.name.toLowerCase().includes('validation') || p.name.toLowerCase().includes('validator'));
|
|
936
|
-
const hasCollection = patterns.some((p) => p.name.toLowerCase().includes('collection') || p.name.toLowerCase().includes('list'));
|
|
937
|
-
if (hasValidation) {
|
|
938
|
-
return ` it('should handle edge cases', () => {
|
|
939
|
-
// Validation pattern: test boundary conditions
|
|
940
|
-
const instance = new ${moduleName}();
|
|
941
|
-
|
|
942
|
-
// Test with empty values
|
|
943
|
-
if (typeof instance.validate === 'function') {
|
|
944
|
-
expect(() => instance.validate('')).toBeDefined();
|
|
945
|
-
expect(() => instance.validate(null)).toBeDefined();
|
|
946
|
-
}
|
|
947
|
-
});`;
|
|
948
|
-
}
|
|
949
|
-
if (hasCollection) {
|
|
950
|
-
return ` it('should handle edge cases', () => {
|
|
951
|
-
// Collection pattern: test empty and large datasets
|
|
952
|
-
const instance = new ${moduleName}();
|
|
953
|
-
|
|
954
|
-
// Empty collection should be handled gracefully
|
|
955
|
-
if (typeof instance.add === 'function') {
|
|
956
|
-
expect(() => instance.add(undefined)).toBeDefined();
|
|
957
|
-
}
|
|
958
|
-
if (typeof instance.get === 'function') {
|
|
959
|
-
expect(instance.get('nonexistent')).toBeUndefined();
|
|
960
|
-
}
|
|
961
|
-
});`;
|
|
962
|
-
}
|
|
963
|
-
// Default edge case test
|
|
964
|
-
return ` it('should handle edge cases', () => {
|
|
965
|
-
// Test null/undefined handling
|
|
966
|
-
const instance = typeof ${moduleName} === 'function'
|
|
967
|
-
? new ${moduleName}()
|
|
968
|
-
: ${moduleName};
|
|
969
|
-
|
|
970
|
-
// Module should handle edge case inputs gracefully
|
|
971
|
-
expect(instance).toBeDefined();
|
|
972
|
-
expect(() => JSON.stringify(instance)).not.toThrow();
|
|
973
|
-
});`;
|
|
974
|
-
}
|
|
975
|
-
/**
|
|
976
|
-
* Generate error handling test based on patterns
|
|
977
|
-
*/
|
|
978
|
-
generateErrorHandlingTest(moduleName, patterns) {
|
|
979
|
-
const hasErrorPattern = patterns.some((p) => p.name.toLowerCase().includes('error') || p.name.toLowerCase().includes('exception'));
|
|
980
|
-
const hasAsyncPattern = patterns.some((p) => p.name.toLowerCase().includes('async') || p.name.toLowerCase().includes('promise'));
|
|
981
|
-
if (hasAsyncPattern) {
|
|
982
|
-
return ` it('should handle error conditions', async () => {
|
|
983
|
-
// Async error handling: verify rejections are caught
|
|
984
|
-
const instance = typeof ${moduleName} === 'function'
|
|
985
|
-
? new ${moduleName}()
|
|
986
|
-
: ${moduleName};
|
|
987
|
-
|
|
988
|
-
// Async operations should reject gracefully on invalid input
|
|
989
|
-
const asyncMethods = Object.getOwnPropertyNames(Object.getPrototypeOf(instance) || {})
|
|
990
|
-
.filter(m => m !== 'constructor');
|
|
991
|
-
|
|
992
|
-
// At minimum, module should be stable
|
|
993
|
-
expect(instance).toBeDefined();
|
|
994
|
-
});`;
|
|
995
|
-
}
|
|
996
|
-
if (hasErrorPattern) {
|
|
997
|
-
return ` it('should handle error conditions', () => {
|
|
998
|
-
// Error pattern: verify custom error types
|
|
999
|
-
try {
|
|
1000
|
-
const instance = new ${moduleName}();
|
|
1001
|
-
// Trigger error condition if possible
|
|
1002
|
-
if (typeof instance.throwError === 'function') {
|
|
1003
|
-
expect(() => instance.throwError()).toThrow();
|
|
1004
|
-
}
|
|
1005
|
-
} catch (error) {
|
|
1006
|
-
expect(error).toBeInstanceOf(Error);
|
|
1007
|
-
}
|
|
1008
|
-
});`;
|
|
1009
|
-
}
|
|
1010
|
-
// Default error handling test
|
|
1011
|
-
return ` it('should handle error conditions', () => {
|
|
1012
|
-
// Verify error resilience
|
|
1013
|
-
expect(() => {
|
|
1014
|
-
const instance = typeof ${moduleName} === 'function'
|
|
1015
|
-
? new ${moduleName}()
|
|
1016
|
-
: ${moduleName};
|
|
1017
|
-
return instance;
|
|
1018
|
-
}).not.toThrow();
|
|
1019
|
-
|
|
1020
|
-
// Module should not throw on inspection
|
|
1021
|
-
expect(() => Object.keys(${moduleName})).not.toThrow();
|
|
1022
|
-
});`;
|
|
1023
|
-
}
|
|
1024
|
-
generateMochaTest(moduleName, importPath, testType, patterns) {
|
|
1025
|
-
const patternComment = patterns.length > 0
|
|
1026
|
-
? `// Applied patterns: ${patterns.map((p) => p.name).join(', ')}\n`
|
|
1027
|
-
: '';
|
|
1028
|
-
// Determine if async tests needed based on patterns
|
|
1029
|
-
const isAsync = patterns.some((p) => p.name.toLowerCase().includes('async') || p.name.toLowerCase().includes('promise'));
|
|
1030
|
-
const asyncSetup = isAsync ? 'async ' : '';
|
|
1031
|
-
return `${patternComment}import { expect } from 'chai';
|
|
1032
|
-
import { ${moduleName} } from '${importPath}';
|
|
1033
|
-
|
|
1034
|
-
describe('${moduleName}', function() {
|
|
1035
|
-
describe('${testType} tests', function() {
|
|
1036
|
-
it('should be defined', function() {
|
|
1037
|
-
expect(${moduleName}).to.not.be.undefined;
|
|
1038
|
-
});
|
|
1039
|
-
|
|
1040
|
-
it('should handle basic operations', ${asyncSetup}function() {
|
|
1041
|
-
// Verify module exports expected interface
|
|
1042
|
-
const moduleType = typeof ${moduleName};
|
|
1043
|
-
expect(['function', 'object']).to.include(moduleType);
|
|
1044
|
-
|
|
1045
|
-
if (moduleType === 'function') {
|
|
1046
|
-
const instance = new ${moduleName}();
|
|
1047
|
-
expect(instance).to.exist;
|
|
1048
|
-
} else {
|
|
1049
|
-
expect(Object.keys(${moduleName})).to.have.length.greaterThan(0);
|
|
1050
|
-
}
|
|
1051
|
-
});
|
|
1052
|
-
|
|
1053
|
-
it('should handle edge cases', function() {
|
|
1054
|
-
// Verify resilience to edge inputs
|
|
1055
|
-
const instance = typeof ${moduleName} === 'function'
|
|
1056
|
-
? new ${moduleName}()
|
|
1057
|
-
: ${moduleName};
|
|
1058
|
-
expect(instance).to.exist;
|
|
1059
|
-
expect(() => JSON.stringify(instance)).to.not.throw();
|
|
1060
|
-
});
|
|
1061
|
-
|
|
1062
|
-
it('should handle error conditions', function() {
|
|
1063
|
-
// Verify error resilience
|
|
1064
|
-
expect(() => {
|
|
1065
|
-
const instance = typeof ${moduleName} === 'function'
|
|
1066
|
-
? new ${moduleName}()
|
|
1067
|
-
: ${moduleName};
|
|
1068
|
-
return instance;
|
|
1069
|
-
}).to.not.throw();
|
|
1070
|
-
});
|
|
1071
|
-
});
|
|
1072
|
-
});
|
|
1073
|
-
`;
|
|
1074
|
-
}
|
|
1075
|
-
generatePytestTest(moduleName, importPath, testType, patterns) {
|
|
1076
|
-
const patternComment = patterns.length > 0
|
|
1077
|
-
? `# Applied patterns: ${patterns.map((p) => p.name).join(', ')}\n`
|
|
1078
|
-
: '';
|
|
1079
|
-
// Determine if async tests needed based on patterns
|
|
1080
|
-
const isAsync = patterns.some((p) => p.name.toLowerCase().includes('async') || p.name.toLowerCase().includes('promise'));
|
|
1081
|
-
const asyncDecorator = isAsync ? '@pytest.mark.asyncio\n ' : '';
|
|
1082
|
-
const asyncDef = isAsync ? 'async def' : 'def';
|
|
1083
|
-
return `${patternComment}import pytest
|
|
1084
|
-
from ${importPath} import ${moduleName}
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
class Test${moduleName}:
|
|
1088
|
-
"""${testType} tests for ${moduleName}"""
|
|
1089
|
-
|
|
1090
|
-
def test_is_defined(self):
|
|
1091
|
-
"""Verify the module is properly exported and defined."""
|
|
1092
|
-
assert ${moduleName} is not None
|
|
1093
|
-
|
|
1094
|
-
${asyncDecorator}${asyncDef} test_basic_operations(self):
|
|
1095
|
-
"""Test core functionality with valid inputs."""
|
|
1096
|
-
# Verify module can be instantiated or accessed
|
|
1097
|
-
if callable(${moduleName}):
|
|
1098
|
-
instance = ${moduleName}()
|
|
1099
|
-
assert instance is not None
|
|
1100
|
-
else:
|
|
1101
|
-
assert len(dir(${moduleName})) > 0
|
|
1102
|
-
|
|
1103
|
-
def test_edge_cases(self):
|
|
1104
|
-
"""Test handling of edge case inputs."""
|
|
1105
|
-
# Verify module handles edge cases gracefully
|
|
1106
|
-
instance = ${moduleName}() if callable(${moduleName}) else ${moduleName}
|
|
1107
|
-
assert instance is not None
|
|
1108
|
-
# Module should be serializable
|
|
1109
|
-
import json
|
|
1110
|
-
try:
|
|
1111
|
-
json.dumps(str(instance))
|
|
1112
|
-
except (TypeError, ValueError):
|
|
1113
|
-
pass # Complex objects may not serialize, but shouldn't crash
|
|
1114
|
-
|
|
1115
|
-
def test_error_conditions(self):
|
|
1116
|
-
"""Test error handling and recovery."""
|
|
1117
|
-
# Module instantiation should not raise unexpected errors
|
|
1118
|
-
try:
|
|
1119
|
-
instance = ${moduleName}() if callable(${moduleName}) else ${moduleName}
|
|
1120
|
-
assert instance is not None
|
|
1121
|
-
except TypeError:
|
|
1122
|
-
# Expected if constructor requires arguments
|
|
1123
|
-
pass
|
|
1124
|
-
`;
|
|
1125
|
-
}
|
|
1126
|
-
async generateRedPhaseTest(feature, behavior, _framework) {
|
|
1127
|
-
// Generate TDD RED phase: failing test that defines expected behavior
|
|
1128
|
-
const funcName = this.camelCase(feature);
|
|
1129
|
-
const assertions = this.generateAssertionsFromBehavior(behavior, funcName);
|
|
1130
|
-
const testCode = `describe('${feature}', () => {
|
|
1131
|
-
it('${behavior}', () => {
|
|
1132
|
-
// Red phase: This test should fail initially
|
|
1133
|
-
${assertions}
|
|
1134
|
-
});
|
|
1135
|
-
});`;
|
|
1136
|
-
return {
|
|
1137
|
-
phase: 'red',
|
|
1138
|
-
testCode,
|
|
1139
|
-
nextStep: 'Write the minimal implementation to make this test pass',
|
|
1140
|
-
};
|
|
1141
|
-
}
|
|
1142
|
-
/**
|
|
1143
|
-
* Generate specific assertions from behavior description
|
|
1144
|
-
* Uses NLP-style extraction to infer test values and assertions
|
|
1145
|
-
*/
|
|
1146
|
-
generateAssertionsFromBehavior(behavior, funcName) {
|
|
1147
|
-
const behaviorLower = behavior.toLowerCase();
|
|
1148
|
-
const assertions = [];
|
|
1149
|
-
// Extract context from behavior description
|
|
1150
|
-
const context = this.extractBehaviorContext(behavior);
|
|
1151
|
-
// Build function call with appropriate arguments
|
|
1152
|
-
const funcCall = this.buildFunctionCall(funcName, context, behaviorLower);
|
|
1153
|
-
// Add setup if needed
|
|
1154
|
-
if (context.setupCode) {
|
|
1155
|
-
assertions.push(context.setupCode);
|
|
1156
|
-
}
|
|
1157
|
-
// Generate assertions based on expected outcome
|
|
1158
|
-
if (behaviorLower.includes('return') && behaviorLower.includes('true')) {
|
|
1159
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1160
|
-
assertions.push(` expect(result).toBe(true);`);
|
|
1161
|
-
}
|
|
1162
|
-
else if (behaviorLower.includes('return') && behaviorLower.includes('false')) {
|
|
1163
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1164
|
-
assertions.push(` expect(result).toBe(false);`);
|
|
1165
|
-
}
|
|
1166
|
-
else if (behaviorLower.includes('throw') || behaviorLower.includes('error')) {
|
|
1167
|
-
const errorMsg = context.extractedString || 'Error';
|
|
1168
|
-
assertions.push(` expect(() => ${funcCall}).toThrow(${context.extractedString ? `'${errorMsg}'` : ''});`);
|
|
1169
|
-
}
|
|
1170
|
-
else if (behaviorLower.includes('empty') || behaviorLower.includes('nothing')) {
|
|
1171
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1172
|
-
if (behaviorLower.includes('string')) {
|
|
1173
|
-
assertions.push(` expect(result).toBe('');`);
|
|
1174
|
-
}
|
|
1175
|
-
else if (behaviorLower.includes('object')) {
|
|
1176
|
-
assertions.push(` expect(result).toEqual({});`);
|
|
1177
|
-
}
|
|
1178
|
-
else {
|
|
1179
|
-
assertions.push(` expect(result).toEqual([]);`);
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
else if (behaviorLower.includes('null')) {
|
|
1183
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1184
|
-
assertions.push(` expect(result).toBeNull();`);
|
|
1185
|
-
}
|
|
1186
|
-
else if (behaviorLower.includes('undefined')) {
|
|
1187
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1188
|
-
assertions.push(` expect(result).toBeUndefined();`);
|
|
1189
|
-
}
|
|
1190
|
-
else if (behaviorLower.includes('contain') || behaviorLower.includes('include')) {
|
|
1191
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1192
|
-
const expectedValue = context.extractedString || context.extractedNumber?.toString() || 'expectedItem';
|
|
1193
|
-
if (context.extractedString) {
|
|
1194
|
-
assertions.push(` expect(result).toContain('${expectedValue}');`);
|
|
1195
|
-
}
|
|
1196
|
-
else if (context.extractedNumber !== undefined) {
|
|
1197
|
-
assertions.push(` expect(result).toContain(${expectedValue});`);
|
|
1198
|
-
}
|
|
1199
|
-
else {
|
|
1200
|
-
assertions.push(` expect(result).toContain(testInput); // Contains the input`);
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
else if (behaviorLower.includes('length') || behaviorLower.includes('count')) {
|
|
1204
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1205
|
-
const expectedLength = context.extractedNumber ?? 3;
|
|
1206
|
-
assertions.push(` expect(result).toHaveLength(${expectedLength});`);
|
|
1207
|
-
}
|
|
1208
|
-
else if (behaviorLower.includes('equal') || behaviorLower.includes('match')) {
|
|
1209
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1210
|
-
if (context.extractedString) {
|
|
1211
|
-
assertions.push(` expect(result).toEqual('${context.extractedString}');`);
|
|
1212
|
-
}
|
|
1213
|
-
else if (context.extractedNumber !== undefined) {
|
|
1214
|
-
assertions.push(` expect(result).toEqual(${context.extractedNumber});`);
|
|
1215
|
-
}
|
|
1216
|
-
else {
|
|
1217
|
-
assertions.push(` expect(result).toEqual(expectedOutput);`);
|
|
1218
|
-
}
|
|
1219
|
-
}
|
|
1220
|
-
else if (behaviorLower.includes('greater') || behaviorLower.includes('more than')) {
|
|
1221
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1222
|
-
const threshold = context.extractedNumber ?? 0;
|
|
1223
|
-
assertions.push(` expect(result).toBeGreaterThan(${threshold});`);
|
|
1224
|
-
}
|
|
1225
|
-
else if (behaviorLower.includes('less') || behaviorLower.includes('fewer')) {
|
|
1226
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1227
|
-
const threshold = context.extractedNumber ?? 100;
|
|
1228
|
-
assertions.push(` expect(result).toBeLessThan(${threshold});`);
|
|
1229
|
-
}
|
|
1230
|
-
else if (behaviorLower.includes('valid') || behaviorLower.includes('success')) {
|
|
1231
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1232
|
-
assertions.push(` expect(result).toBeDefined();`);
|
|
1233
|
-
if (behaviorLower.includes('object') || behaviorLower.includes('response')) {
|
|
1234
|
-
assertions.push(` expect(result.success ?? result.valid ?? result.ok).toBeTruthy();`);
|
|
1235
|
-
}
|
|
1236
|
-
else {
|
|
1237
|
-
assertions.push(` expect(result).toBeTruthy();`);
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
else if (behaviorLower.includes('array') || behaviorLower.includes('list')) {
|
|
1241
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1242
|
-
assertions.push(` expect(Array.isArray(result)).toBe(true);`);
|
|
1243
|
-
if (context.extractedNumber !== undefined) {
|
|
1244
|
-
assertions.push(` expect(result.length).toBeGreaterThanOrEqual(${context.extractedNumber});`);
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
else if (behaviorLower.includes('object')) {
|
|
1248
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1249
|
-
assertions.push(` expect(typeof result).toBe('object');`);
|
|
1250
|
-
assertions.push(` expect(result).not.toBeNull();`);
|
|
1251
|
-
}
|
|
1252
|
-
else if (behaviorLower.includes('string')) {
|
|
1253
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1254
|
-
assertions.push(` expect(typeof result).toBe('string');`);
|
|
1255
|
-
if (context.extractedString) {
|
|
1256
|
-
assertions.push(` expect(result).toContain('${context.extractedString}');`);
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
else if (behaviorLower.includes('number')) {
|
|
1260
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1261
|
-
assertions.push(` expect(typeof result).toBe('number');`);
|
|
1262
|
-
assertions.push(` expect(Number.isNaN(result)).toBe(false);`);
|
|
1263
|
-
}
|
|
1264
|
-
else {
|
|
1265
|
-
// Default: check it's defined
|
|
1266
|
-
assertions.push(` const result = ${funcCall};`);
|
|
1267
|
-
assertions.push(` expect(result).toBeDefined();`);
|
|
1268
|
-
}
|
|
1269
|
-
return assertions.join('\n');
|
|
1270
|
-
}
|
|
1271
|
-
/**
|
|
1272
|
-
* Extract contextual information from behavior description
|
|
1273
|
-
*/
|
|
1274
|
-
extractBehaviorContext(behavior) {
|
|
1275
|
-
const context = {};
|
|
1276
|
-
// Extract quoted strings from behavior
|
|
1277
|
-
const stringMatch = behavior.match(/["']([^"']+)["']/);
|
|
1278
|
-
if (stringMatch) {
|
|
1279
|
-
context.extractedString = stringMatch[1];
|
|
1280
|
-
}
|
|
1281
|
-
// Extract numbers from behavior
|
|
1282
|
-
const numberMatch = behavior.match(/\b(\d+)\b/);
|
|
1283
|
-
if (numberMatch) {
|
|
1284
|
-
context.extractedNumber = parseInt(numberMatch[1], 10);
|
|
1285
|
-
}
|
|
1286
|
-
// Detect input type
|
|
1287
|
-
if (/\b(email|e-mail)\b/i.test(behavior)) {
|
|
1288
|
-
context.inputType = 'email';
|
|
1289
|
-
context.setupCode = ` const testInput = 'test@example.com';`;
|
|
1290
|
-
}
|
|
1291
|
-
else if (/\b(url|link|href)\b/i.test(behavior)) {
|
|
1292
|
-
context.inputType = 'url';
|
|
1293
|
-
context.setupCode = ` const testInput = 'https://example.com';`;
|
|
1294
|
-
}
|
|
1295
|
-
else if (/\b(date|time|timestamp)\b/i.test(behavior)) {
|
|
1296
|
-
context.inputType = 'date';
|
|
1297
|
-
context.setupCode = ` const testInput = new Date('2024-01-15');`;
|
|
1298
|
-
}
|
|
1299
|
-
else if (/\b(id|uuid|identifier)\b/i.test(behavior)) {
|
|
1300
|
-
context.inputType = 'id';
|
|
1301
|
-
context.setupCode = ` const testInput = 'abc-123-def';`;
|
|
1302
|
-
}
|
|
1303
|
-
else if (/\b(user|person|customer)\b/i.test(behavior)) {
|
|
1304
|
-
context.inputType = 'user';
|
|
1305
|
-
context.setupCode = ` const testInput = { id: '1', name: 'Test User', email: 'test@example.com' };`;
|
|
1306
|
-
}
|
|
1307
|
-
else if (/\b(config|options|settings)\b/i.test(behavior)) {
|
|
1308
|
-
context.inputType = 'config';
|
|
1309
|
-
context.setupCode = ` const testInput = { enabled: true, timeout: 5000 };`;
|
|
1310
|
-
}
|
|
1311
|
-
return context;
|
|
1312
|
-
}
|
|
1313
|
-
/**
|
|
1314
|
-
* Build function call with appropriate arguments based on context
|
|
1315
|
-
*/
|
|
1316
|
-
buildFunctionCall(funcName, context, behaviorLower) {
|
|
1317
|
-
// If context has setup code, use testInput variable
|
|
1318
|
-
if (context.inputType) {
|
|
1319
|
-
return `${funcName}(testInput)`;
|
|
1320
|
-
}
|
|
1321
|
-
// No input needed
|
|
1322
|
-
if (!behaviorLower.includes('with') && !behaviorLower.includes('given') && !behaviorLower.includes('for')) {
|
|
1323
|
-
return `${funcName}()`;
|
|
1324
|
-
}
|
|
1325
|
-
// Infer input type from behavior
|
|
1326
|
-
if (behaviorLower.includes('string') || behaviorLower.includes('text') || behaviorLower.includes('name')) {
|
|
1327
|
-
const value = context.extractedString || 'test input';
|
|
1328
|
-
return `${funcName}('${value}')`;
|
|
1329
|
-
}
|
|
1330
|
-
if (behaviorLower.includes('number') || behaviorLower.includes('count') || behaviorLower.includes('amount')) {
|
|
1331
|
-
const value = context.extractedNumber ?? 42;
|
|
1332
|
-
return `${funcName}(${value})`;
|
|
1333
|
-
}
|
|
1334
|
-
if (behaviorLower.includes('array') || behaviorLower.includes('list') || behaviorLower.includes('items')) {
|
|
1335
|
-
return `${funcName}([1, 2, 3])`;
|
|
1336
|
-
}
|
|
1337
|
-
if (behaviorLower.includes('object') || behaviorLower.includes('data') || behaviorLower.includes('payload')) {
|
|
1338
|
-
return `${funcName}({ key: 'value' })`;
|
|
1339
|
-
}
|
|
1340
|
-
if (behaviorLower.includes('boolean') || behaviorLower.includes('flag')) {
|
|
1341
|
-
return `${funcName}(true)`;
|
|
1342
|
-
}
|
|
1343
|
-
// Default: use extracted value or generic input
|
|
1344
|
-
if (context.extractedString) {
|
|
1345
|
-
return `${funcName}('${context.extractedString}')`;
|
|
1346
|
-
}
|
|
1347
|
-
if (context.extractedNumber !== undefined) {
|
|
1348
|
-
return `${funcName}(${context.extractedNumber})`;
|
|
1349
|
-
}
|
|
1350
|
-
return `${funcName}(input)`;
|
|
1351
|
-
}
|
|
1352
|
-
async generateGreenPhaseCode(feature, behavior, _framework) {
|
|
1353
|
-
// Generate TDD GREEN phase: minimal implementation to pass the test
|
|
1354
|
-
// Analyze the behavior description to generate appropriate implementation
|
|
1355
|
-
const behaviorLower = behavior.toLowerCase();
|
|
1356
|
-
const funcName = this.camelCase(feature);
|
|
1357
|
-
// Infer return type and implementation from behavior
|
|
1358
|
-
const { returnType, implementation, params } = this.inferImplementationFromBehavior(behaviorLower);
|
|
1359
|
-
const implementationCode = `/**
|
|
1360
|
-
* ${feature}
|
|
1361
|
-
* Behavior: ${behavior}
|
|
1362
|
-
*/
|
|
1363
|
-
export function ${funcName}(${params}): ${returnType} {
|
|
1364
|
-
${implementation}
|
|
1365
|
-
}`;
|
|
1366
|
-
return {
|
|
1367
|
-
phase: 'green',
|
|
1368
|
-
implementationCode,
|
|
1369
|
-
nextStep: 'Refactor the code while keeping tests green',
|
|
1370
|
-
};
|
|
1371
|
-
}
|
|
1372
|
-
/**
|
|
1373
|
-
* Infer implementation details from behavior description using heuristics
|
|
1374
|
-
* Analyzes the behavior text to determine return type, parameters, and minimal implementation
|
|
1375
|
-
*/
|
|
1376
|
-
inferImplementationFromBehavior(behavior) {
|
|
1377
|
-
// Default values
|
|
1378
|
-
let returnType = 'unknown';
|
|
1379
|
-
let implementation = ' return undefined;';
|
|
1380
|
-
let params = '';
|
|
1381
|
-
// Detect return type from behavior description
|
|
1382
|
-
if (behavior.includes('return') || behavior.includes('returns')) {
|
|
1383
|
-
if (behavior.includes('boolean') || behavior.includes('true') || behavior.includes('false') ||
|
|
1384
|
-
behavior.includes('valid') || behavior.includes('is ') || behavior.includes('has ') ||
|
|
1385
|
-
behavior.includes('can ') || behavior.includes('should ')) {
|
|
1386
|
-
returnType = 'boolean';
|
|
1387
|
-
implementation = ' // Validate and return boolean result\n return true;';
|
|
1388
|
-
}
|
|
1389
|
-
else if (behavior.includes('number') || behavior.includes('count') || behavior.includes('sum') ||
|
|
1390
|
-
behavior.includes('total') || behavior.includes('calculate') || behavior.includes('average')) {
|
|
1391
|
-
returnType = 'number';
|
|
1392
|
-
implementation = ' // Perform calculation and return result\n return 0;';
|
|
1393
|
-
}
|
|
1394
|
-
else if (behavior.includes('string') || behavior.includes('text') || behavior.includes('message') ||
|
|
1395
|
-
behavior.includes('name') || behavior.includes('format')) {
|
|
1396
|
-
returnType = 'string';
|
|
1397
|
-
implementation = " // Process and return string result\n return '';";
|
|
1398
|
-
}
|
|
1399
|
-
else if (behavior.includes('array') || behavior.includes('list') || behavior.includes('items') ||
|
|
1400
|
-
behavior.includes('collection') || behavior.includes('filter') || behavior.includes('map')) {
|
|
1401
|
-
returnType = 'unknown[]';
|
|
1402
|
-
implementation = ' // Process and return array\n return [];';
|
|
1403
|
-
}
|
|
1404
|
-
else if (behavior.includes('object') || behavior.includes('data') || behavior.includes('result') ||
|
|
1405
|
-
behavior.includes('response')) {
|
|
1406
|
-
returnType = 'Record<string, unknown>';
|
|
1407
|
-
implementation = ' // Build and return object\n return {};';
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
// Detect if async is needed
|
|
1411
|
-
if (behavior.includes('async') || behavior.includes('await') || behavior.includes('promise') ||
|
|
1412
|
-
behavior.includes('fetch') || behavior.includes('load') || behavior.includes('save') ||
|
|
1413
|
-
behavior.includes('api') || behavior.includes('request')) {
|
|
1414
|
-
returnType = `Promise<${returnType}>`;
|
|
1415
|
-
implementation = implementation.replace('return ', 'return await Promise.resolve(').replace(';', ');');
|
|
1416
|
-
}
|
|
1417
|
-
// Detect parameters from behavior
|
|
1418
|
-
const paramPatterns = [
|
|
1419
|
-
{ pattern: /(?:with|given|for|using)\s+(?:a\s+)?(?:string|text|name)/i, param: 'input: string' },
|
|
1420
|
-
{ pattern: /(?:with|given|for|using)\s+(?:a\s+)?(?:number|count|amount)/i, param: 'value: number' },
|
|
1421
|
-
{ pattern: /(?:with|given|for|using)\s+(?:an?\s+)?(?:array|list|items)/i, param: 'items: unknown[]' },
|
|
1422
|
-
{ pattern: /(?:with|given|for|using)\s+(?:an?\s+)?(?:object|data)/i, param: 'data: Record<string, unknown>' },
|
|
1423
|
-
{ pattern: /(?:with|given|for|using)\s+(?:an?\s+)?id/i, param: 'id: string' },
|
|
1424
|
-
{ pattern: /(?:with|given|for|using)\s+(?:valid|invalid)\s+input/i, param: 'input: unknown' },
|
|
1425
|
-
{ pattern: /(?:when|if)\s+(?:called\s+)?(?:with|without)/i, param: 'input?: unknown' },
|
|
1426
|
-
];
|
|
1427
|
-
const detectedParams = [];
|
|
1428
|
-
for (const { pattern, param } of paramPatterns) {
|
|
1429
|
-
if (pattern.test(behavior) && !detectedParams.includes(param)) {
|
|
1430
|
-
detectedParams.push(param);
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
params = detectedParams.join(', ');
|
|
1434
|
-
// Detect validation logic from behavior
|
|
1435
|
-
if (behavior.includes('validate') || behavior.includes('check') || behavior.includes('verify')) {
|
|
1436
|
-
if (params.includes('input')) {
|
|
1437
|
-
implementation = ` // Validate the input
|
|
1438
|
-
if (input === undefined || input === null) {
|
|
1439
|
-
throw new Error('Invalid input');
|
|
1440
|
-
}
|
|
1441
|
-
${implementation}`;
|
|
1442
|
-
}
|
|
1443
|
-
}
|
|
1444
|
-
// Detect error throwing from behavior
|
|
1445
|
-
if (behavior.includes('throw') || behavior.includes('error') || behavior.includes('exception') ||
|
|
1446
|
-
behavior.includes('invalid') || behavior.includes('fail')) {
|
|
1447
|
-
if (behavior.includes('when') || behavior.includes('if')) {
|
|
1448
|
-
implementation = ` // Check for error conditions
|
|
1449
|
-
if (!input) {
|
|
1450
|
-
throw new Error('Validation failed');
|
|
1451
|
-
}
|
|
1452
|
-
${implementation}`;
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
return { returnType, implementation, params };
|
|
1456
|
-
}
|
|
1457
|
-
async generateRefactoringSuggestions(_feature, _behavior) {
|
|
1458
|
-
return {
|
|
1459
|
-
phase: 'refactor',
|
|
1460
|
-
refactoringChanges: [
|
|
1461
|
-
'Extract common logic into helper functions',
|
|
1462
|
-
'Apply single responsibility principle',
|
|
1463
|
-
'Consider adding type safety improvements',
|
|
1464
|
-
'Review naming conventions',
|
|
1465
|
-
'Optimize performance if needed',
|
|
1466
|
-
],
|
|
1467
|
-
nextStep: 'Apply refactoring changes and ensure all tests still pass',
|
|
1468
|
-
};
|
|
1469
|
-
}
|
|
1470
|
-
generatePropertyTestCode(funcName, property, constraints) {
|
|
1471
|
-
// Analyze property description to generate appropriate generators and assertions
|
|
1472
|
-
const propertyLower = property.toLowerCase();
|
|
1473
|
-
const { generators, assertion, setupCode } = this.analyzePropertyForTestGeneration(propertyLower, funcName, constraints);
|
|
1474
|
-
return `import * as fc from 'fast-check';
|
|
1475
|
-
|
|
1476
|
-
describe('${funcName} property tests', () => {
|
|
1477
|
-
it('${property}', () => {
|
|
1478
|
-
${setupCode}
|
|
1479
|
-
fc.assert(
|
|
1480
|
-
fc.property(${generators.join(', ')}, (${this.generatePropertyParams(generators)}) => {
|
|
1481
|
-
const result = ${funcName}(${this.generatePropertyArgs(generators)});
|
|
1482
|
-
${assertion}
|
|
1483
|
-
})
|
|
1484
|
-
);
|
|
1485
|
-
});
|
|
1486
|
-
});`;
|
|
1487
|
-
}
|
|
1488
|
-
/**
|
|
1489
|
-
* Analyze property description to determine generators and assertions
|
|
1490
|
-
*/
|
|
1491
|
-
analyzePropertyForTestGeneration(propertyLower, funcName, constraints) {
|
|
1492
|
-
const generators = [];
|
|
1493
|
-
let assertion = 'return result !== undefined;';
|
|
1494
|
-
let setupCode = '';
|
|
1495
|
-
// Idempotent property: f(f(x)) === f(x)
|
|
1496
|
-
if (propertyLower.includes('idempotent') || propertyLower.includes('same result')) {
|
|
1497
|
-
generators.push(this.inferGeneratorFromConstraints(constraints, 'input'));
|
|
1498
|
-
assertion = `// Idempotent: applying twice gives same result
|
|
1499
|
-
const firstResult = ${funcName}(input);
|
|
1500
|
-
const secondResult = ${funcName}(firstResult);
|
|
1501
|
-
return JSON.stringify(firstResult) === JSON.stringify(secondResult);`;
|
|
1502
|
-
}
|
|
1503
|
-
// Commutative property: f(a, b) === f(b, a)
|
|
1504
|
-
else if (propertyLower.includes('commutative') || propertyLower.includes('order independent')) {
|
|
1505
|
-
const gen = this.inferGeneratorFromConstraints(constraints, 'value');
|
|
1506
|
-
generators.push(gen, gen);
|
|
1507
|
-
assertion = `// Commutative: order doesn't matter
|
|
1508
|
-
const result1 = ${funcName}(a, b);
|
|
1509
|
-
const result2 = ${funcName}(b, a);
|
|
1510
|
-
return JSON.stringify(result1) === JSON.stringify(result2);`;
|
|
1511
|
-
}
|
|
1512
|
-
// Associative property: f(f(a, b), c) === f(a, f(b, c))
|
|
1513
|
-
else if (propertyLower.includes('associative')) {
|
|
1514
|
-
const gen = this.inferGeneratorFromConstraints(constraints, 'value');
|
|
1515
|
-
generators.push(gen, gen, gen);
|
|
1516
|
-
assertion = `// Associative: grouping doesn't matter
|
|
1517
|
-
const left = ${funcName}(${funcName}(a, b), c);
|
|
1518
|
-
const right = ${funcName}(a, ${funcName}(b, c));
|
|
1519
|
-
return JSON.stringify(left) === JSON.stringify(right);`;
|
|
1520
|
-
}
|
|
1521
|
-
// Identity property: f(x, identity) === x
|
|
1522
|
-
else if (propertyLower.includes('identity') || propertyLower.includes('neutral element')) {
|
|
1523
|
-
generators.push(this.inferGeneratorFromConstraints(constraints, 'input'));
|
|
1524
|
-
const identity = constraints.identity !== undefined ? String(constraints.identity) : '0';
|
|
1525
|
-
setupCode = ` const identity = ${identity};`;
|
|
1526
|
-
assertion = `// Identity: operation with identity returns original
|
|
1527
|
-
const result = ${funcName}(input, identity);
|
|
1528
|
-
return JSON.stringify(result) === JSON.stringify(input);`;
|
|
1529
|
-
}
|
|
1530
|
-
// Inverse property: f(f(x)) === x (e.g., encode/decode)
|
|
1531
|
-
else if (propertyLower.includes('inverse') || propertyLower.includes('reversible') ||
|
|
1532
|
-
propertyLower.includes('round-trip') || propertyLower.includes('encode') ||
|
|
1533
|
-
propertyLower.includes('decode')) {
|
|
1534
|
-
generators.push(this.inferGeneratorFromConstraints(constraints, 'input'));
|
|
1535
|
-
const inverseFn = constraints.inverse || `${funcName}Inverse`;
|
|
1536
|
-
assertion = `// Inverse: applying function and its inverse returns original
|
|
1537
|
-
const encoded = ${funcName}(input);
|
|
1538
|
-
const decoded = ${inverseFn}(encoded);
|
|
1539
|
-
return JSON.stringify(decoded) === JSON.stringify(input);`;
|
|
1540
|
-
}
|
|
1541
|
-
// Distributive property: f(a, b + c) === f(a, b) + f(a, c)
|
|
1542
|
-
else if (propertyLower.includes('distributive')) {
|
|
1543
|
-
const gen = this.inferGeneratorFromConstraints(constraints, 'number');
|
|
1544
|
-
generators.push(gen, gen, gen);
|
|
1545
|
-
assertion = `// Distributive: f(a, b + c) === f(a, b) + f(a, c)
|
|
1546
|
-
const left = ${funcName}(a, b + c);
|
|
1547
|
-
const right = ${funcName}(a, b) + ${funcName}(a, c);
|
|
1548
|
-
return Math.abs(left - right) < 0.0001;`;
|
|
1549
|
-
}
|
|
1550
|
-
// Monotonic property: a <= b implies f(a) <= f(b)
|
|
1551
|
-
else if (propertyLower.includes('monotonic') || propertyLower.includes('preserves order') ||
|
|
1552
|
-
propertyLower.includes('non-decreasing') || propertyLower.includes('sorted')) {
|
|
1553
|
-
generators.push('fc.integer()', 'fc.integer()');
|
|
1554
|
-
assertion = `// Monotonic: preserves order
|
|
1555
|
-
const [small, large] = a <= b ? [a, b] : [b, a];
|
|
1556
|
-
const resultSmall = ${funcName}(small);
|
|
1557
|
-
const resultLarge = ${funcName}(large);
|
|
1558
|
-
return resultSmall <= resultLarge;`;
|
|
1559
|
-
}
|
|
1560
|
-
// Bounds/range property: output is within expected bounds
|
|
1561
|
-
else if (propertyLower.includes('bound') || propertyLower.includes('range') ||
|
|
1562
|
-
propertyLower.includes('between') || propertyLower.includes('clamp')) {
|
|
1563
|
-
generators.push(this.inferGeneratorFromConstraints(constraints, 'input'));
|
|
1564
|
-
const min = constraints.min !== undefined ? constraints.min : 0;
|
|
1565
|
-
const max = constraints.max !== undefined ? constraints.max : 100;
|
|
1566
|
-
assertion = `// Bounded: result is within expected range
|
|
1567
|
-
const result = ${funcName}(input);
|
|
1568
|
-
return result >= ${min} && result <= ${max};`;
|
|
1569
|
-
}
|
|
1570
|
-
// Length preservation
|
|
1571
|
-
else if (propertyLower.includes('length') || propertyLower.includes('size')) {
|
|
1572
|
-
generators.push('fc.array(fc.anything())');
|
|
1573
|
-
if (propertyLower.includes('preserve')) {
|
|
1574
|
-
assertion = `// Length preserved: output has same length as input
|
|
1575
|
-
const result = ${funcName}(input);
|
|
1576
|
-
return Array.isArray(result) && result.length === input.length;`;
|
|
1577
|
-
}
|
|
1578
|
-
else {
|
|
1579
|
-
assertion = `// Length invariant
|
|
1580
|
-
const result = ${funcName}(input);
|
|
1581
|
-
return typeof result.length === 'number' || typeof result.size === 'number';`;
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1584
|
-
// Type preservation
|
|
1585
|
-
else if (propertyLower.includes('type') && propertyLower.includes('preserve')) {
|
|
1586
|
-
generators.push('fc.anything()');
|
|
1587
|
-
assertion = `// Type preserved: output has same type as input
|
|
1588
|
-
const result = ${funcName}(input);
|
|
1589
|
-
return typeof result === typeof input;`;
|
|
1590
|
-
}
|
|
1591
|
-
// Non-null/defined output
|
|
1592
|
-
else if (propertyLower.includes('never null') || propertyLower.includes('always defined') ||
|
|
1593
|
-
propertyLower.includes('non-null')) {
|
|
1594
|
-
generators.push(this.inferGeneratorFromConstraints(constraints, 'input'));
|
|
1595
|
-
assertion = `// Never null: always returns defined value
|
|
1596
|
-
const result = ${funcName}(input);
|
|
1597
|
-
return result !== null && result !== undefined;`;
|
|
1598
|
-
}
|
|
1599
|
-
// Deterministic property: same input always produces same output
|
|
1600
|
-
else if (propertyLower.includes('deterministic') || propertyLower.includes('pure') ||
|
|
1601
|
-
propertyLower.includes('consistent')) {
|
|
1602
|
-
generators.push(this.inferGeneratorFromConstraints(constraints, 'input'));
|
|
1603
|
-
assertion = `// Deterministic: same input always gives same output
|
|
1604
|
-
const result1 = ${funcName}(input);
|
|
1605
|
-
const result2 = ${funcName}(input);
|
|
1606
|
-
return JSON.stringify(result1) === JSON.stringify(result2);`;
|
|
1607
|
-
}
|
|
1608
|
-
// Default case: basic existence check with type-appropriate generator
|
|
1609
|
-
else {
|
|
1610
|
-
generators.push(this.inferGeneratorFromConstraints(constraints, 'input'));
|
|
1611
|
-
assertion = `// Basic property: function returns a value
|
|
1612
|
-
return result !== undefined;`;
|
|
1613
|
-
}
|
|
1614
|
-
return { generators, assertion, setupCode };
|
|
1615
|
-
}
|
|
1616
|
-
/**
|
|
1617
|
-
* Infer the appropriate fast-check generator from constraints
|
|
1618
|
-
*/
|
|
1619
|
-
inferGeneratorFromConstraints(constraints, hint) {
|
|
1620
|
-
// Check explicit type constraint
|
|
1621
|
-
const type = constraints.type?.toLowerCase() || hint.toLowerCase();
|
|
1622
|
-
if (type.includes('string') || type.includes('text')) {
|
|
1623
|
-
const minLength = constraints.minLength;
|
|
1624
|
-
const maxLength = constraints.maxLength;
|
|
1625
|
-
if (minLength !== undefined || maxLength !== undefined) {
|
|
1626
|
-
return `fc.string({ minLength: ${minLength ?? 0}, maxLength: ${maxLength ?? 100} })`;
|
|
1627
|
-
}
|
|
1628
|
-
return 'fc.string()';
|
|
1629
|
-
}
|
|
1630
|
-
if (type.includes('number') || type.includes('int') || type.includes('value')) {
|
|
1631
|
-
const min = constraints.min;
|
|
1632
|
-
const max = constraints.max;
|
|
1633
|
-
if (min !== undefined || max !== undefined) {
|
|
1634
|
-
return `fc.integer({ min: ${min ?? Number.MIN_SAFE_INTEGER}, max: ${max ?? Number.MAX_SAFE_INTEGER} })`;
|
|
1635
|
-
}
|
|
1636
|
-
return 'fc.integer()';
|
|
1637
|
-
}
|
|
1638
|
-
if (type.includes('float') || type.includes('decimal')) {
|
|
1639
|
-
return 'fc.float()';
|
|
1640
|
-
}
|
|
1641
|
-
if (type.includes('boolean') || type.includes('bool')) {
|
|
1642
|
-
return 'fc.boolean()';
|
|
1643
|
-
}
|
|
1644
|
-
if (type.includes('array') || type.includes('list')) {
|
|
1645
|
-
const itemType = constraints.itemType || 'anything';
|
|
1646
|
-
const itemGen = this.getSimpleGenerator(itemType);
|
|
1647
|
-
return `fc.array(${itemGen})`;
|
|
1648
|
-
}
|
|
1649
|
-
if (type.includes('object') || type.includes('record')) {
|
|
1650
|
-
return 'fc.object()';
|
|
1651
|
-
}
|
|
1652
|
-
if (type.includes('date')) {
|
|
1653
|
-
return 'fc.date()';
|
|
1654
|
-
}
|
|
1655
|
-
if (type.includes('uuid') || type.includes('id')) {
|
|
1656
|
-
return 'fc.uuid()';
|
|
1657
|
-
}
|
|
1658
|
-
if (type.includes('email')) {
|
|
1659
|
-
return 'fc.emailAddress()';
|
|
1660
|
-
}
|
|
1661
|
-
// Default to anything
|
|
1662
|
-
return 'fc.anything()';
|
|
1663
|
-
}
|
|
1664
|
-
/**
|
|
1665
|
-
* Get a simple generator for a type name
|
|
1666
|
-
*/
|
|
1667
|
-
getSimpleGenerator(typeName) {
|
|
1668
|
-
const typeMap = {
|
|
1669
|
-
string: 'fc.string()',
|
|
1670
|
-
number: 'fc.integer()',
|
|
1671
|
-
integer: 'fc.integer()',
|
|
1672
|
-
float: 'fc.float()',
|
|
1673
|
-
boolean: 'fc.boolean()',
|
|
1674
|
-
date: 'fc.date()',
|
|
1675
|
-
uuid: 'fc.uuid()',
|
|
1676
|
-
anything: 'fc.anything()',
|
|
1677
|
-
};
|
|
1678
|
-
return typeMap[typeName.toLowerCase()] || 'fc.anything()';
|
|
1679
|
-
}
|
|
1680
|
-
/**
|
|
1681
|
-
* Generate parameter names from generator list
|
|
1682
|
-
*/
|
|
1683
|
-
generatePropertyParams(generators) {
|
|
1684
|
-
if (generators.length === 1) {
|
|
1685
|
-
return 'input';
|
|
1686
|
-
}
|
|
1687
|
-
return generators.map((_, i) => String.fromCharCode(97 + i)).join(', '); // a, b, c...
|
|
1688
|
-
}
|
|
1689
|
-
/**
|
|
1690
|
-
* Generate argument list for function call
|
|
1691
|
-
*/
|
|
1692
|
-
generatePropertyArgs(generators) {
|
|
1693
|
-
if (generators.length === 1) {
|
|
1694
|
-
return 'input';
|
|
1695
|
-
}
|
|
1696
|
-
return generators.map((_, i) => String.fromCharCode(97 + i)).join(', ');
|
|
1697
|
-
}
|
|
1698
|
-
inferGenerators(property, constraints) {
|
|
1699
|
-
const generators = [];
|
|
1700
|
-
const propertyLower = property.toLowerCase();
|
|
1701
|
-
// Analyze property description to infer appropriate generators
|
|
1702
|
-
// String-related properties
|
|
1703
|
-
if (propertyLower.includes('string') ||
|
|
1704
|
-
propertyLower.includes('text') ||
|
|
1705
|
-
propertyLower.includes('name') ||
|
|
1706
|
-
propertyLower.includes('email')) {
|
|
1707
|
-
if (constraints.minLength || constraints.maxLength) {
|
|
1708
|
-
const min = constraints.minLength ?? 0;
|
|
1709
|
-
const max = constraints.maxLength ?? 100;
|
|
1710
|
-
generators.push(`fc.string({ minLength: ${min}, maxLength: ${max} })`);
|
|
1711
|
-
}
|
|
1712
|
-
else {
|
|
1713
|
-
generators.push('fc.string()');
|
|
1714
|
-
}
|
|
1715
|
-
if (propertyLower.includes('email')) {
|
|
1716
|
-
generators.push('fc.emailAddress()');
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
// Number-related properties
|
|
1720
|
-
if (propertyLower.includes('number') ||
|
|
1721
|
-
propertyLower.includes('count') ||
|
|
1722
|
-
propertyLower.includes('amount') ||
|
|
1723
|
-
propertyLower.includes('integer') ||
|
|
1724
|
-
propertyLower.includes('positive') ||
|
|
1725
|
-
propertyLower.includes('negative')) {
|
|
1726
|
-
if (propertyLower.includes('positive')) {
|
|
1727
|
-
generators.push('fc.nat()');
|
|
1728
|
-
}
|
|
1729
|
-
else if (propertyLower.includes('negative')) {
|
|
1730
|
-
generators.push('fc.integer({ max: -1 })');
|
|
1731
|
-
}
|
|
1732
|
-
else if (constraints.min !== undefined || constraints.max !== undefined) {
|
|
1733
|
-
const min = constraints.min ?? Number.MIN_SAFE_INTEGER;
|
|
1734
|
-
const max = constraints.max ?? Number.MAX_SAFE_INTEGER;
|
|
1735
|
-
generators.push(`fc.integer({ min: ${min}, max: ${max} })`);
|
|
1736
|
-
}
|
|
1737
|
-
else {
|
|
1738
|
-
generators.push('fc.integer()');
|
|
1739
|
-
}
|
|
1740
|
-
if (propertyLower.includes('float') || propertyLower.includes('decimal')) {
|
|
1741
|
-
generators.push('fc.float()');
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
// Boolean properties
|
|
1745
|
-
if (propertyLower.includes('boolean') || propertyLower.includes('flag')) {
|
|
1746
|
-
generators.push('fc.boolean()');
|
|
1747
|
-
}
|
|
1748
|
-
// Array-related properties
|
|
1749
|
-
if (propertyLower.includes('array') ||
|
|
1750
|
-
propertyLower.includes('list') ||
|
|
1751
|
-
propertyLower.includes('collection')) {
|
|
1752
|
-
const itemType = constraints.itemType || 'anything';
|
|
1753
|
-
const itemGen = this.getGeneratorForType(itemType);
|
|
1754
|
-
if (constraints.minItems || constraints.maxItems) {
|
|
1755
|
-
const min = constraints.minItems ?? 0;
|
|
1756
|
-
const max = constraints.maxItems ?? 10;
|
|
1757
|
-
generators.push(`fc.array(${itemGen}, { minLength: ${min}, maxLength: ${max} })`);
|
|
1758
|
-
}
|
|
1759
|
-
else {
|
|
1760
|
-
generators.push(`fc.array(${itemGen})`);
|
|
1761
|
-
}
|
|
1762
|
-
}
|
|
1763
|
-
// Object-related properties
|
|
1764
|
-
if (propertyLower.includes('object') || propertyLower.includes('record')) {
|
|
1765
|
-
generators.push('fc.object()');
|
|
1766
|
-
generators.push('fc.dictionary(fc.string(), fc.anything())');
|
|
1767
|
-
}
|
|
1768
|
-
// Date-related properties
|
|
1769
|
-
if (propertyLower.includes('date') || propertyLower.includes('time')) {
|
|
1770
|
-
generators.push('fc.date()');
|
|
1771
|
-
}
|
|
1772
|
-
// UUID properties
|
|
1773
|
-
if (propertyLower.includes('uuid') || propertyLower.includes('id')) {
|
|
1774
|
-
generators.push('fc.uuid()');
|
|
1775
|
-
}
|
|
1776
|
-
// Default fallback if no specific type detected
|
|
1777
|
-
if (generators.length === 0) {
|
|
1778
|
-
generators.push('fc.anything()');
|
|
1779
|
-
}
|
|
1780
|
-
return generators;
|
|
1781
|
-
}
|
|
1782
|
-
getGeneratorForType(type) {
|
|
1783
|
-
const typeGenerators = {
|
|
1784
|
-
string: 'fc.string()',
|
|
1785
|
-
number: 'fc.integer()',
|
|
1786
|
-
integer: 'fc.integer()',
|
|
1787
|
-
float: 'fc.float()',
|
|
1788
|
-
boolean: 'fc.boolean()',
|
|
1789
|
-
date: 'fc.date()',
|
|
1790
|
-
uuid: 'fc.uuid()',
|
|
1791
|
-
anything: 'fc.anything()',
|
|
1792
|
-
};
|
|
1793
|
-
return typeGenerators[type.toLowerCase()] || 'fc.anything()';
|
|
1794
|
-
}
|
|
1795
|
-
collectArbitraries(tests) {
|
|
1796
|
-
const arbitraries = new Set();
|
|
1797
|
-
for (const test of tests) {
|
|
1798
|
-
test.generators.forEach((g) => arbitraries.add(g));
|
|
1799
|
-
}
|
|
1800
|
-
return Array.from(arbitraries);
|
|
1801
|
-
}
|
|
1802
|
-
generateRecordFromSchema(schema, seed, locale) {
|
|
1803
|
-
// Set faker locale and seed for reproducibility
|
|
1804
|
-
faker.seed(seed);
|
|
1805
|
-
if (locale && locale !== 'en') {
|
|
1806
|
-
// Note: faker v8+ uses different locale handling
|
|
1807
|
-
// For now, we use the default locale
|
|
1808
|
-
}
|
|
1809
|
-
const record = {};
|
|
1810
|
-
for (const [key, fieldDef] of Object.entries(schema)) {
|
|
1811
|
-
record[key] = this.generateValueForField(key, fieldDef, seed);
|
|
1812
|
-
}
|
|
1813
|
-
return record;
|
|
1814
|
-
}
|
|
1815
|
-
generateValueForField(fieldName, fieldDef, _seed) {
|
|
1816
|
-
// Handle simple type strings
|
|
1817
|
-
if (typeof fieldDef === 'string') {
|
|
1818
|
-
return this.generateValueForType(fieldDef, fieldName);
|
|
1819
|
-
}
|
|
1820
|
-
// Handle complex field definitions
|
|
1821
|
-
if (typeof fieldDef === 'object' && fieldDef !== null) {
|
|
1822
|
-
const field = fieldDef;
|
|
1823
|
-
// Use explicit faker method if specified
|
|
1824
|
-
if (field.faker) {
|
|
1825
|
-
return this.callFakerMethod(field.faker);
|
|
1826
|
-
}
|
|
1827
|
-
return this.generateValueForType(field.type, fieldName, field);
|
|
1828
|
-
}
|
|
1829
|
-
return null;
|
|
1830
|
-
}
|
|
1831
|
-
generateValueForType(type, fieldName, options) {
|
|
1832
|
-
const normalizedType = type.toLowerCase();
|
|
1833
|
-
// Try to infer the best faker method based on field name and type
|
|
1834
|
-
switch (normalizedType) {
|
|
1835
|
-
case 'string':
|
|
1836
|
-
return this.generateStringValue(fieldName, options);
|
|
1837
|
-
case 'number':
|
|
1838
|
-
case 'int':
|
|
1839
|
-
case 'integer':
|
|
1840
|
-
return this.generateNumberValue(options);
|
|
1841
|
-
case 'float':
|
|
1842
|
-
case 'decimal':
|
|
1843
|
-
return faker.number.float({ min: options?.min ?? 0, max: options?.max ?? 1000, fractionDigits: 2 });
|
|
1844
|
-
case 'boolean':
|
|
1845
|
-
case 'bool':
|
|
1846
|
-
return faker.datatype.boolean();
|
|
1847
|
-
case 'date':
|
|
1848
|
-
case 'datetime':
|
|
1849
|
-
return faker.date.recent().toISOString();
|
|
1850
|
-
case 'email':
|
|
1851
|
-
return faker.internet.email();
|
|
1852
|
-
case 'uuid':
|
|
1853
|
-
case 'id':
|
|
1854
|
-
return faker.string.uuid();
|
|
1855
|
-
case 'url':
|
|
1856
|
-
return faker.internet.url();
|
|
1857
|
-
case 'phone':
|
|
1858
|
-
return faker.phone.number();
|
|
1859
|
-
case 'address':
|
|
1860
|
-
return this.generateAddress();
|
|
1861
|
-
case 'name':
|
|
1862
|
-
case 'fullname':
|
|
1863
|
-
return faker.person.fullName();
|
|
1864
|
-
case 'firstname':
|
|
1865
|
-
return faker.person.firstName();
|
|
1866
|
-
case 'lastname':
|
|
1867
|
-
return faker.person.lastName();
|
|
1868
|
-
case 'username':
|
|
1869
|
-
return faker.internet.username();
|
|
1870
|
-
case 'password':
|
|
1871
|
-
return faker.internet.password();
|
|
1872
|
-
case 'company':
|
|
1873
|
-
return faker.company.name();
|
|
1874
|
-
case 'jobtitle':
|
|
1875
|
-
return faker.person.jobTitle();
|
|
1876
|
-
case 'text':
|
|
1877
|
-
case 'paragraph':
|
|
1878
|
-
return faker.lorem.paragraph();
|
|
1879
|
-
case 'sentence':
|
|
1880
|
-
return faker.lorem.sentence();
|
|
1881
|
-
case 'word':
|
|
1882
|
-
case 'words':
|
|
1883
|
-
return faker.lorem.word();
|
|
1884
|
-
case 'avatar':
|
|
1885
|
-
case 'image':
|
|
1886
|
-
return faker.image.avatar();
|
|
1887
|
-
case 'color':
|
|
1888
|
-
return faker.color.rgb();
|
|
1889
|
-
case 'ipaddress':
|
|
1890
|
-
case 'ip':
|
|
1891
|
-
return faker.internet.ipv4();
|
|
1892
|
-
case 'mac':
|
|
1893
|
-
return faker.internet.mac();
|
|
1894
|
-
case 'latitude':
|
|
1895
|
-
return faker.location.latitude();
|
|
1896
|
-
case 'longitude':
|
|
1897
|
-
return faker.location.longitude();
|
|
1898
|
-
case 'country':
|
|
1899
|
-
return faker.location.country();
|
|
1900
|
-
case 'city':
|
|
1901
|
-
return faker.location.city();
|
|
1902
|
-
case 'zipcode':
|
|
1903
|
-
case 'postalcode':
|
|
1904
|
-
return faker.location.zipCode();
|
|
1905
|
-
case 'creditcard':
|
|
1906
|
-
return faker.finance.creditCardNumber();
|
|
1907
|
-
case 'currency':
|
|
1908
|
-
return faker.finance.currencyCode();
|
|
1909
|
-
case 'amount':
|
|
1910
|
-
case 'price':
|
|
1911
|
-
return faker.finance.amount();
|
|
1912
|
-
case 'json':
|
|
1913
|
-
case 'object':
|
|
1914
|
-
return { key: faker.lorem.word(), value: faker.lorem.sentence() };
|
|
1915
|
-
case 'array':
|
|
1916
|
-
return [faker.lorem.word(), faker.lorem.word(), faker.lorem.word()];
|
|
1917
|
-
case 'enum':
|
|
1918
|
-
if (options?.enum && options.enum.length > 0) {
|
|
1919
|
-
return faker.helpers.arrayElement(options.enum);
|
|
1920
|
-
}
|
|
1921
|
-
return faker.lorem.word();
|
|
1922
|
-
default:
|
|
1923
|
-
// Try to infer from field name
|
|
1924
|
-
return this.inferValueFromFieldName(fieldName);
|
|
1925
|
-
}
|
|
1926
|
-
}
|
|
1927
|
-
generateStringValue(fieldName, options) {
|
|
1928
|
-
const lowerName = fieldName.toLowerCase();
|
|
1929
|
-
// Infer type from field name
|
|
1930
|
-
if (lowerName.includes('email'))
|
|
1931
|
-
return faker.internet.email();
|
|
1932
|
-
if (lowerName.includes('name') && lowerName.includes('first'))
|
|
1933
|
-
return faker.person.firstName();
|
|
1934
|
-
if (lowerName.includes('name') && lowerName.includes('last'))
|
|
1935
|
-
return faker.person.lastName();
|
|
1936
|
-
if (lowerName.includes('name'))
|
|
1937
|
-
return faker.person.fullName();
|
|
1938
|
-
if (lowerName.includes('phone'))
|
|
1939
|
-
return faker.phone.number();
|
|
1940
|
-
if (lowerName.includes('address'))
|
|
1941
|
-
return faker.location.streetAddress();
|
|
1942
|
-
if (lowerName.includes('city'))
|
|
1943
|
-
return faker.location.city();
|
|
1944
|
-
if (lowerName.includes('country'))
|
|
1945
|
-
return faker.location.country();
|
|
1946
|
-
if (lowerName.includes('zip') || lowerName.includes('postal'))
|
|
1947
|
-
return faker.location.zipCode();
|
|
1948
|
-
if (lowerName.includes('url') || lowerName.includes('website'))
|
|
1949
|
-
return faker.internet.url();
|
|
1950
|
-
if (lowerName.includes('username') || lowerName.includes('user'))
|
|
1951
|
-
return faker.internet.username();
|
|
1952
|
-
if (lowerName.includes('password'))
|
|
1953
|
-
return faker.internet.password();
|
|
1954
|
-
if (lowerName.includes('description') || lowerName.includes('bio'))
|
|
1955
|
-
return faker.lorem.paragraph();
|
|
1956
|
-
if (lowerName.includes('title'))
|
|
1957
|
-
return faker.lorem.sentence();
|
|
1958
|
-
if (lowerName.includes('company'))
|
|
1959
|
-
return faker.company.name();
|
|
1960
|
-
if (lowerName.includes('job'))
|
|
1961
|
-
return faker.person.jobTitle();
|
|
1962
|
-
if (lowerName.includes('avatar') || lowerName.includes('image'))
|
|
1963
|
-
return faker.image.avatar();
|
|
1964
|
-
// Apply pattern if provided
|
|
1965
|
-
if (options?.pattern) {
|
|
1966
|
-
return faker.helpers.fromRegExp(options.pattern);
|
|
1967
|
-
}
|
|
1968
|
-
// Default string generation
|
|
1969
|
-
return faker.lorem.words(3);
|
|
1970
|
-
}
|
|
1971
|
-
generateNumberValue(options) {
|
|
1972
|
-
const min = options?.min ?? 0;
|
|
1973
|
-
const max = options?.max ?? 10000;
|
|
1974
|
-
return faker.number.int({ min, max });
|
|
1975
|
-
}
|
|
1976
|
-
generateAddress() {
|
|
1977
|
-
return {
|
|
1978
|
-
street: faker.location.streetAddress(),
|
|
1979
|
-
city: faker.location.city(),
|
|
1980
|
-
state: faker.location.state(),
|
|
1981
|
-
zipCode: faker.location.zipCode(),
|
|
1982
|
-
country: faker.location.country(),
|
|
1983
|
-
};
|
|
1984
|
-
}
|
|
1985
|
-
inferValueFromFieldName(fieldName) {
|
|
1986
|
-
const lowerName = fieldName.toLowerCase();
|
|
1987
|
-
if (lowerName.includes('id'))
|
|
1988
|
-
return faker.string.uuid();
|
|
1989
|
-
if (lowerName.includes('email'))
|
|
1990
|
-
return faker.internet.email();
|
|
1991
|
-
if (lowerName.includes('name'))
|
|
1992
|
-
return faker.person.fullName();
|
|
1993
|
-
if (lowerName.includes('phone'))
|
|
1994
|
-
return faker.phone.number();
|
|
1995
|
-
if (lowerName.includes('date') || lowerName.includes('time'))
|
|
1996
|
-
return faker.date.recent().toISOString();
|
|
1997
|
-
if (lowerName.includes('url'))
|
|
1998
|
-
return faker.internet.url();
|
|
1999
|
-
if (lowerName.includes('count') || lowerName.includes('amount'))
|
|
2000
|
-
return faker.number.int({ min: 0, max: 100 });
|
|
2001
|
-
if (lowerName.includes('price'))
|
|
2002
|
-
return faker.finance.amount();
|
|
2003
|
-
if (lowerName.includes('active') || lowerName.includes('enabled') || lowerName.includes('is')) {
|
|
2004
|
-
return faker.datatype.boolean();
|
|
2005
|
-
}
|
|
2006
|
-
// Default to a random string
|
|
2007
|
-
return faker.lorem.word();
|
|
2008
|
-
}
|
|
2009
|
-
callFakerMethod(methodPath) {
|
|
2010
|
-
try {
|
|
2011
|
-
const parts = methodPath.split('.');
|
|
2012
|
-
let result = faker;
|
|
2013
|
-
for (const part of parts) {
|
|
2014
|
-
if (result && typeof result === 'object' && part in result) {
|
|
2015
|
-
const next = result[part];
|
|
2016
|
-
if (typeof next === 'function') {
|
|
2017
|
-
result = next();
|
|
2018
|
-
}
|
|
2019
|
-
else {
|
|
2020
|
-
result = next;
|
|
2021
|
-
}
|
|
2022
|
-
}
|
|
2023
|
-
else {
|
|
2024
|
-
return faker.lorem.word();
|
|
2025
|
-
}
|
|
2026
|
-
}
|
|
2027
|
-
return result;
|
|
2028
|
-
}
|
|
2029
|
-
catch {
|
|
2030
|
-
return faker.lorem.word();
|
|
2031
|
-
}
|
|
2032
|
-
}
|
|
2033
|
-
linkRelatedRecords(records, schema) {
|
|
2034
|
-
// Find fields with references and link them
|
|
2035
|
-
const referenceFields = [];
|
|
2036
|
-
for (const [key, fieldDef] of Object.entries(schema)) {
|
|
2037
|
-
if (typeof fieldDef === 'object' && fieldDef !== null) {
|
|
2038
|
-
const field = fieldDef;
|
|
2039
|
-
if (field.reference) {
|
|
2040
|
-
referenceFields.push({ field: key, reference: field.reference });
|
|
2041
|
-
}
|
|
2042
|
-
}
|
|
2043
|
-
}
|
|
2044
|
-
// If we have reference fields, link records
|
|
2045
|
-
if (referenceFields.length > 0) {
|
|
2046
|
-
for (let i = 0; i < records.length; i++) {
|
|
2047
|
-
const record = records[i];
|
|
2048
|
-
for (const { field, reference } of referenceFields) {
|
|
2049
|
-
// Link to a random previous record's ID or create a new one
|
|
2050
|
-
if (i > 0 && reference === 'id') {
|
|
2051
|
-
const prevRecord = records[Math.floor(Math.random() * i)];
|
|
2052
|
-
record[field] = prevRecord['id'] ?? faker.string.uuid();
|
|
2053
|
-
}
|
|
2054
|
-
else {
|
|
2055
|
-
record[field] = faker.string.uuid();
|
|
2056
|
-
}
|
|
2057
|
-
}
|
|
2058
|
-
}
|
|
2059
|
-
}
|
|
2060
|
-
}
|
|
2061
|
-
async generateTestForLines(file, lines, framework) {
|
|
2062
|
-
if (lines.length === 0)
|
|
2063
|
-
return null;
|
|
2064
|
-
const testId = uuidv4();
|
|
2065
|
-
const testFile = this.getTestFilePath(file, framework);
|
|
2066
|
-
const moduleName = this.extractModuleName(file);
|
|
2067
|
-
const importPath = this.getImportPath(file);
|
|
2068
|
-
// Generate meaningful coverage test code
|
|
2069
|
-
const testCode = this.generateCoverageTestCode(moduleName, importPath, lines, framework);
|
|
2070
|
-
return {
|
|
2071
|
-
id: testId,
|
|
2072
|
-
name: `Coverage test for lines ${lines[0]}-${lines[lines.length - 1]}`,
|
|
2073
|
-
sourceFile: file,
|
|
2074
|
-
testFile,
|
|
2075
|
-
testCode,
|
|
2076
|
-
type: 'unit',
|
|
2077
|
-
assertions: this.countAssertions(testCode),
|
|
2078
|
-
};
|
|
2079
|
-
}
|
|
2080
|
-
/**
|
|
2081
|
-
* Generate actual coverage test code for specific lines
|
|
2082
|
-
*/
|
|
2083
|
-
generateCoverageTestCode(moduleName, importPath, lines, framework) {
|
|
2084
|
-
const funcName = this.camelCase(moduleName);
|
|
2085
|
-
const lineRange = lines.length === 1
|
|
2086
|
-
? `line ${lines[0]}`
|
|
2087
|
-
: `lines ${lines[0]}-${lines[lines.length - 1]}`;
|
|
2088
|
-
if (framework === 'pytest') {
|
|
2089
|
-
return `# Coverage test for ${lineRange} in ${moduleName}
|
|
2090
|
-
import pytest
|
|
2091
|
-
from ${importPath.replace(/\//g, '.')} import ${funcName}
|
|
2092
|
-
|
|
2093
|
-
class Test${this.pascalCase(moduleName)}Coverage:
|
|
2094
|
-
"""Tests to cover ${lineRange}"""
|
|
2095
|
-
|
|
2096
|
-
def test_cover_${lines[0]}_${lines[lines.length - 1]}(self):
|
|
2097
|
-
"""Exercise code path covering ${lineRange}"""
|
|
2098
|
-
# Arrange: Set up test inputs to reach uncovered lines
|
|
2099
|
-
test_input = None # Replace with appropriate input
|
|
2100
|
-
|
|
2101
|
-
# Act: Execute the code path
|
|
2102
|
-
try:
|
|
2103
|
-
result = ${funcName}(test_input)
|
|
2104
|
-
|
|
2105
|
-
# Assert: Verify expected behavior
|
|
2106
|
-
assert result is not None
|
|
2107
|
-
except Exception as e:
|
|
2108
|
-
# If exception is expected for this path, verify it
|
|
2109
|
-
pytest.fail(f"Unexpected exception: {e}")
|
|
2110
|
-
`;
|
|
2111
|
-
}
|
|
2112
|
-
// Default: Jest/Vitest format
|
|
2113
|
-
return `// Coverage test for ${lineRange} in ${moduleName}
|
|
2114
|
-
import { ${funcName} } from '${importPath}';
|
|
2115
|
-
|
|
2116
|
-
describe('${moduleName} coverage', () => {
|
|
2117
|
-
describe('${lineRange}', () => {
|
|
2118
|
-
it('should execute code path covering ${lineRange}', () => {
|
|
2119
|
-
// Arrange: Set up test inputs to reach uncovered lines
|
|
2120
|
-
const testInput = undefined; // Replace with appropriate input
|
|
2121
|
-
|
|
2122
|
-
// Act: Execute the code path
|
|
2123
|
-
const result = ${funcName}(testInput);
|
|
2124
|
-
|
|
2125
|
-
// Assert: Verify the code was reached and behaves correctly
|
|
2126
|
-
expect(result).toBeDefined();
|
|
2127
|
-
});
|
|
2128
|
-
|
|
2129
|
-
it('should handle edge case for ${lineRange}', () => {
|
|
2130
|
-
// Arrange: Set up edge case input
|
|
2131
|
-
const edgeCaseInput = null;
|
|
2132
|
-
|
|
2133
|
-
// Act & Assert: Verify edge case handling
|
|
2134
|
-
expect(() => ${funcName}(edgeCaseInput)).not.toThrow();
|
|
2135
|
-
});
|
|
2136
|
-
});
|
|
2137
|
-
});
|
|
2138
|
-
`;
|
|
2139
|
-
}
|
|
2140
375
|
groupConsecutiveLines(lines) {
|
|
2141
376
|
if (lines.length === 0)
|
|
2142
377
|
return [];
|
|
@@ -2184,14 +419,10 @@ describe('${moduleName} coverage', () => {
|
|
|
2184
419
|
return Math.max(1, count);
|
|
2185
420
|
}
|
|
2186
421
|
estimateCoverage(tests, target) {
|
|
2187
|
-
// Estimate coverage based on test characteristics
|
|
2188
422
|
const totalAssertions = tests.reduce((sum, t) => sum + t.assertions, 0);
|
|
2189
423
|
const totalTests = tests.length;
|
|
2190
|
-
// Base coverage from test count (each test covers ~3-5% typically)
|
|
2191
424
|
const testBasedCoverage = totalTests * 4;
|
|
2192
|
-
// Additional coverage from assertions (each assertion ~1-2%)
|
|
2193
425
|
const assertionCoverage = totalAssertions * 1.5;
|
|
2194
|
-
// Test type multipliers (integration tests cover more)
|
|
2195
426
|
const typeMultiplier = tests.reduce((mult, t) => {
|
|
2196
427
|
if (t.type === 'integration')
|
|
2197
428
|
return mult + 0.1;
|
|
@@ -2199,23 +430,11 @@ describe('${moduleName} coverage', () => {
|
|
|
2199
430
|
return mult + 0.15;
|
|
2200
431
|
return mult;
|
|
2201
432
|
}, 1);
|
|
2202
|
-
// Calculate estimated coverage with diminishing returns
|
|
2203
433
|
const rawEstimate = (testBasedCoverage + assertionCoverage) * typeMultiplier;
|
|
2204
|
-
const diminishedEstimate = rawEstimate * (1 - rawEstimate / 200);
|
|
2205
|
-
// Cap at target and round
|
|
434
|
+
const diminishedEstimate = rawEstimate * (1 - rawEstimate / 200);
|
|
2206
435
|
const estimatedCoverage = Math.min(target, Math.max(0, diminishedEstimate));
|
|
2207
436
|
return Math.round(estimatedCoverage * 10) / 10;
|
|
2208
437
|
}
|
|
2209
|
-
camelCase(str) {
|
|
2210
|
-
return str
|
|
2211
|
-
.replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase())
|
|
2212
|
-
.replace(/^./, (chr) => chr.toLowerCase());
|
|
2213
|
-
}
|
|
2214
|
-
pascalCase(str) {
|
|
2215
|
-
return str
|
|
2216
|
-
.replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase())
|
|
2217
|
-
.replace(/^./, (chr) => chr.toUpperCase());
|
|
2218
|
-
}
|
|
2219
438
|
async storeGenerationMetadata(tests, patterns) {
|
|
2220
439
|
const metadata = {
|
|
2221
440
|
generatedAt: new Date().toISOString(),
|
|
@@ -2223,8 +442,32 @@ describe('${moduleName} coverage', () => {
|
|
|
2223
442
|
patterns,
|
|
2224
443
|
testIds: tests.map((t) => t.id),
|
|
2225
444
|
};
|
|
2226
|
-
await this.memory.set(`test-generation:metadata:${Date.now()}`, metadata, { namespace: 'test-generation', ttl: 86400 * 7 }
|
|
2227
|
-
);
|
|
445
|
+
await this.memory.set(`test-generation:metadata:${Date.now()}`, metadata, { namespace: 'test-generation', ttl: 86400 * 7 });
|
|
2228
446
|
}
|
|
2229
447
|
}
|
|
448
|
+
// ============================================================================
|
|
449
|
+
// Factory Functions
|
|
450
|
+
// ============================================================================
|
|
451
|
+
/**
|
|
452
|
+
* Create a TestGeneratorService instance with default dependencies
|
|
453
|
+
* Maintains backward compatibility with existing code
|
|
454
|
+
*
|
|
455
|
+
* @param memory - Memory backend for pattern storage
|
|
456
|
+
* @param config - Optional configuration overrides
|
|
457
|
+
* @returns Configured TestGeneratorService instance
|
|
458
|
+
*/
|
|
459
|
+
export function createTestGeneratorService(memory, config = {}) {
|
|
460
|
+
return new TestGeneratorService({ memory }, config);
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Create a TestGeneratorService instance with custom dependencies
|
|
464
|
+
* Used for testing or when custom implementations are needed
|
|
465
|
+
*
|
|
466
|
+
* @param dependencies - All service dependencies
|
|
467
|
+
* @param config - Optional configuration overrides
|
|
468
|
+
* @returns Configured TestGeneratorService instance
|
|
469
|
+
*/
|
|
470
|
+
export function createTestGeneratorServiceWithDependencies(dependencies, config = {}) {
|
|
471
|
+
return new TestGeneratorService(dependencies, config);
|
|
472
|
+
}
|
|
2230
473
|
//# sourceMappingURL=test-generator.js.map
|