@crownpeak/dqm-react-component-dev-mcp 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -0
- package/data/.env.example +22 -0
- package/data/.gitattributes +47 -0
- package/data/.glfrc.json +7 -0
- package/data/.husky/pre-commit +5 -0
- package/data/.nvmrc +1 -0
- package/data/CHANGELOG.md +75 -0
- package/data/CODE_OF_CONDUCT.md +129 -0
- package/data/CONTRIBUTING.md +203 -0
- package/data/DOCS-STRUCTURE.md +307 -0
- package/data/I18N.md +292 -0
- package/data/LICENSE +22 -0
- package/data/README.md +315 -0
- package/data/SECURITY.md +125 -0
- package/data/WIKI-DEPLOYMENT.md +348 -0
- package/data/docs/AI-FEATURES.md +610 -0
- package/data/docs/API-REFERENCE.md +1022 -0
- package/data/docs/AUTHENTICATION.md +301 -0
- package/data/docs/BACKEND-API.md +468 -0
- package/data/docs/DEVELOPMENT.md +375 -0
- package/data/docs/EXAMPLES.md +622 -0
- package/data/docs/MCP-SERVER.md +307 -0
- package/data/docs/MIGRATION-GUIDE.md +367 -0
- package/data/docs/NPM-PUBLISH.md +193 -0
- package/data/docs/QUICKSTART.md +206 -0
- package/data/docs/REDIS-SETUP.md +162 -0
- package/data/docs/SERVER.md +228 -0
- package/data/docs/TROUBLESHOOTING.md +657 -0
- package/data/docs/WIDGET-GUIDE.md +638 -0
- package/data/docs/WIKI-HOME.md +58 -0
- package/data/docs/WIKI-SIDEBAR.md +39 -0
- package/data/package.json +171 -0
- package/data/playwright.config.ts +64 -0
- package/data/probe/.cargo/config.toml +10 -0
- package/data/probe/.claude/commands/performance-review.md +15 -0
- package/data/probe/.clinerules +288 -0
- package/data/probe/.dockerignore +57 -0
- package/data/probe/.githooks/post-commit +11 -0
- package/data/probe/.githooks/pre-commit +99 -0
- package/data/probe/.githooks/pre-commit-vow +9 -0
- package/data/probe/.prompts/engineer.md +41 -0
- package/data/probe/.roomodes +28 -0
- package/data/probe/.windsurfrules +0 -0
- package/data/probe/BASH_TOOL_SUMMARY.md +148 -0
- package/data/probe/BENCHMARKING.md +256 -0
- package/data/probe/CLAUDE.md +226 -0
- package/data/probe/CODE_OF_CONDUCT.md +128 -0
- package/data/probe/CONTRIBUTING.md +193 -0
- package/data/probe/Cargo.toml +120 -0
- package/data/probe/Cross.toml +10 -0
- package/data/probe/DOCKER-README.md +224 -0
- package/data/probe/Dockerfile +32 -0
- package/data/probe/ENHANCED_DEBUG_TELEMETRY.md +188 -0
- package/data/probe/LICENSE +201 -0
- package/data/probe/Makefile +210 -0
- package/data/probe/README.md +824 -0
- package/data/probe/SECURITY.md +67 -0
- package/data/probe/WINDOWS-GUIDE.md +294 -0
- package/data/probe/benches/parsing_benchmarks.rs +370 -0
- package/data/probe/benches/search_benchmarks.rs +599 -0
- package/data/probe/benches/simd_benchmarks.rs +372 -0
- package/data/probe/benches/timing_benchmarks.rs +287 -0
- package/data/probe/build-windows.bat +229 -0
- package/data/probe/codex-config/config.toml +6 -0
- package/data/probe/docs/PERFORMANCE_OPTIMIZATION.md +161 -0
- package/data/probe/examples/cache_demo.rs +46 -0
- package/data/probe/examples/chat/.dockerignore +37 -0
- package/data/probe/examples/chat/ChatSessionManager.js +295 -0
- package/data/probe/examples/chat/Dockerfile +98 -0
- package/data/probe/examples/chat/LICENSE +201 -0
- package/data/probe/examples/chat/LOCAL_IMAGE_SUPPORT.md +195 -0
- package/data/probe/examples/chat/MCP_INTEGRATION.md +400 -0
- package/data/probe/examples/chat/README.md +338 -0
- package/data/probe/examples/chat/TRACING.md +226 -0
- package/data/probe/examples/chat/appTracer.js +968 -0
- package/data/probe/examples/chat/auth.js +76 -0
- package/data/probe/examples/chat/bin/probe-chat.js +13 -0
- package/data/probe/examples/chat/build.js +104 -0
- package/data/probe/examples/chat/cancelRequest.js +84 -0
- package/data/probe/examples/chat/demo-agentic-image-flow.js +88 -0
- package/data/probe/examples/chat/demo-local-images.js +128 -0
- package/data/probe/examples/chat/fileSpanExporter.js +181 -0
- package/data/probe/examples/chat/implement/README.md +228 -0
- package/data/probe/examples/chat/implement/backends/AiderBackend.js +750 -0
- package/data/probe/examples/chat/implement/backends/BaseBackend.js +276 -0
- package/data/probe/examples/chat/implement/backends/ClaudeCodeBackend.js +767 -0
- package/data/probe/examples/chat/implement/backends/MockBackend.js +237 -0
- package/data/probe/examples/chat/implement/backends/registry.js +85 -0
- package/data/probe/examples/chat/implement/core/BackendManager.js +567 -0
- package/data/probe/examples/chat/implement/core/ImplementTool.js +354 -0
- package/data/probe/examples/chat/implement/core/config.js +428 -0
- package/data/probe/examples/chat/implement/core/timeouts.js +58 -0
- package/data/probe/examples/chat/implement/core/utils.js +496 -0
- package/data/probe/examples/chat/implement/types/BackendTypes.js +126 -0
- package/data/probe/examples/chat/index.js +669 -0
- package/data/probe/examples/chat/mcpServer.js +341 -0
- package/data/probe/examples/chat/npm/LICENSE +15 -0
- package/data/probe/examples/chat/npm/README.md +168 -0
- package/data/probe/examples/chat/npm/bin/probe-chat.js +156 -0
- package/data/probe/examples/chat/npm/index.js +259 -0
- package/data/probe/examples/chat/npm/package.json +54 -0
- package/data/probe/examples/chat/package.json +102 -0
- package/data/probe/examples/chat/probeChat.js +456 -0
- package/data/probe/examples/chat/probeTool.js +491 -0
- package/data/probe/examples/chat/storage/JsonChatStorage.js +476 -0
- package/data/probe/examples/chat/telemetry.js +281 -0
- package/data/probe/examples/chat/test/integration/chatFlows.test.js +320 -0
- package/data/probe/examples/chat/test/integration/toolCalling.test.js +471 -0
- package/data/probe/examples/chat/test/mocks/mockLLMProvider.js +269 -0
- package/data/probe/examples/chat/test/test-backends.js +90 -0
- package/data/probe/examples/chat/test/testUtils.js +530 -0
- package/data/probe/examples/chat/test/unit/backendTimeout.test.js +161 -0
- package/data/probe/examples/chat/test/unit/packageFiles.test.js +120 -0
- package/data/probe/examples/chat/test/verify-tests.js +118 -0
- package/data/probe/examples/chat/test-agentic-image-loading.js +294 -0
- package/data/probe/examples/chat/test-ai-sdk-telemetry.js +204 -0
- package/data/probe/examples/chat/test-chat-tracing.js +38 -0
- package/data/probe/examples/chat/test-direct-function.js +49 -0
- package/data/probe/examples/chat/test-file-size-validation.js +103 -0
- package/data/probe/examples/chat/test-full-mcp-integration.js +258 -0
- package/data/probe/examples/chat/test-github-context.txt +12 -0
- package/data/probe/examples/chat/test-hierarchy.js +203 -0
- package/data/probe/examples/chat/test-image-spans.js +37 -0
- package/data/probe/examples/chat/test-local-image-reading.js +176 -0
- package/data/probe/examples/chat/test-mcp-integration.js +136 -0
- package/data/probe/examples/chat/test-mcp-probe-server.js +161 -0
- package/data/probe/examples/chat/test-mcp-with-ai.js +279 -0
- package/data/probe/examples/chat/test-multiple-allowed-dirs.js +111 -0
- package/data/probe/examples/chat/test-probe-mcp-server.js +110 -0
- package/data/probe/examples/chat/test-security-validation.js +145 -0
- package/data/probe/examples/chat/test-simple-tracing.js +32 -0
- package/data/probe/examples/chat/test-trace-verification.js +235 -0
- package/data/probe/examples/chat/test-tracing.js +114 -0
- package/data/probe/examples/chat/tokenCounter.js +419 -0
- package/data/probe/examples/chat/tokenUsageDisplay.js +134 -0
- package/data/probe/examples/chat/webServer.js +1103 -0
- package/data/probe/examples/reranker/Cargo.toml +33 -0
- package/data/probe/examples/reranker/DEBUG_OUTPUT_ANALYSIS.md +71 -0
- package/data/probe/examples/reranker/MODELS.md +66 -0
- package/data/probe/examples/reranker/MODEL_COMPARISON.md +60 -0
- package/data/probe/examples/reranker/MULTI_MODEL_ANALYSIS.md +176 -0
- package/data/probe/examples/reranker/PERFORMANCE_SUMMARY.md +156 -0
- package/data/probe/examples/reranker/README.md +347 -0
- package/data/probe/examples/reranker/RUST_BERT_COMPARISON.md +82 -0
- package/data/probe/examples/reranker/TOKENIZATION_GUIDE.md +120 -0
- package/data/probe/examples/reranker/check_rust_tokenizer.py +108 -0
- package/data/probe/examples/reranker/convert_to_torchscript.py +109 -0
- package/data/probe/examples/reranker/debug_scoring.py +189 -0
- package/data/probe/examples/reranker/debug_tokenization.py +154 -0
- package/data/probe/examples/reranker/download_models.sh +73 -0
- package/data/probe/examples/reranker/requirements.txt +13 -0
- package/data/probe/examples/reranker/run_comprehensive_benchmark.sh +83 -0
- package/data/probe/examples/reranker/rust_bert_test/Cargo.toml +12 -0
- package/data/probe/examples/reranker/rust_bert_test/README.md +54 -0
- package/data/probe/examples/reranker/simple_test.py +50 -0
- package/data/probe/examples/reranker/test_all_models.sh +63 -0
- package/data/probe/examples/reranker/test_bert_results.sh +44 -0
- package/data/probe/examples/reranker/test_cross_encoder.py +334 -0
- package/data/probe/examples/reranker/test_cross_encoder.sh +80 -0
- package/data/probe/examples/reranker/test_exact_comparison.py +151 -0
- package/data/probe/examples/reranker/test_parallel_performance.sh +56 -0
- package/data/probe/examples/reranker/test_scores.py +132 -0
- package/data/probe/install.ps1 +508 -0
- package/data/probe/install.sh +460 -0
- package/data/probe/npm/CLONE_METHOD_EXAMPLES.md +596 -0
- package/data/probe/npm/CONTEXT_COMPACTION.md +303 -0
- package/data/probe/npm/DELEGATE_TOOL_README.md +166 -0
- package/data/probe/npm/MAID_INTEGRATION.md +313 -0
- package/data/probe/npm/MCP_INTEGRATION_SUMMARY.md +241 -0
- package/data/probe/npm/README.md +824 -0
- package/data/probe/npm/bin/.gitignore +7 -0
- package/data/probe/npm/bin/.gitkeep +0 -0
- package/data/probe/npm/bin/README.md +12 -0
- package/data/probe/npm/bin/probe +167 -0
- package/data/probe/npm/docs/CLAUDE_CODE_INTEGRATION.md +414 -0
- package/data/probe/npm/docs/CODEX_INTEGRATION.md +502 -0
- package/data/probe/npm/docs/EDIT_CREATE_TOOLS.md +233 -0
- package/data/probe/npm/docs/RETRY_AND_FALLBACK.md +674 -0
- package/data/probe/npm/example-usage.js +335 -0
- package/data/probe/npm/examples/multi-engine-demo.js +117 -0
- package/data/probe/npm/examples/probe-agent-cli.js +113 -0
- package/data/probe/npm/examples/test-agent-edit.js +114 -0
- package/data/probe/npm/examples/test-edit-create.js +120 -0
- package/data/probe/npm/examples/test-edit-direct.js +114 -0
- package/data/probe/npm/index.d.ts +744 -0
- package/data/probe/npm/jest.config.js +52 -0
- package/data/probe/npm/package.json +117 -0
- package/data/probe/npm/scripts/build-agent.cjs +75 -0
- package/data/probe/npm/scripts/build-cjs.js +124 -0
- package/data/probe/npm/scripts/build-mcp.cjs +36 -0
- package/data/probe/npm/scripts/postinstall.js +216 -0
- package/data/probe/npm/test-codex-e2e.js +78 -0
- package/data/probe/npm/test-download-lock.js +109 -0
- package/data/probe/npm/test-grep-security.js +94 -0
- package/data/probe/npm/test-grep-simplified.js +63 -0
- package/data/probe/npm/test-grep.js +51 -0
- package/data/probe/npm/tests/README.md +96 -0
- package/data/probe/npm/tests/agent-compact-history.test.js +174 -0
- package/data/probe/npm/tests/allow-tests-default.test.js +151 -0
- package/data/probe/npm/tests/contextCompactor.test.js +498 -0
- package/data/probe/npm/tests/delegate-config.test.js +353 -0
- package/data/probe/npm/tests/delegate-integration.test.js +348 -0
- package/data/probe/npm/tests/extractor-integration.test.js +162 -0
- package/data/probe/npm/tests/extractor.test.js +317 -0
- package/data/probe/npm/tests/fixtures/sampleDiagrams.js +267 -0
- package/data/probe/npm/tests/integration/claude-code-auto-fallback.spec.js +148 -0
- package/data/probe/npm/tests/integration/claude-code-multi-step.spec.js +127 -0
- package/data/probe/npm/tests/integration/claude-code-tool-events.spec.js +163 -0
- package/data/probe/npm/tests/integration/codex-auto-fallback.spec.js +191 -0
- package/data/probe/npm/tests/integration/codex-tool-events.spec.js +147 -0
- package/data/probe/npm/tests/integration/examplesChatMcp.test.js +402 -0
- package/data/probe/npm/tests/integration/mcpDotenvSupport.test.js +174 -0
- package/data/probe/npm/tests/integration/mcpErrorHandling.test.js +566 -0
- package/data/probe/npm/tests/integration/mcpRobustness.test.js +564 -0
- package/data/probe/npm/tests/integration/mcpStdoutPurity.test.js +355 -0
- package/data/probe/npm/tests/integration/probeAgentMcp.test.js +398 -0
- package/data/probe/npm/tests/integration/retryFallback.test.js +368 -0
- package/data/probe/npm/tests/integration/schema-in-initial-message.test.js +318 -0
- package/data/probe/npm/tests/integration/schema-validation-loop-prevention.test.js +244 -0
- package/data/probe/npm/tests/integration/schemaRetryLogic.test.js +94 -0
- package/data/probe/npm/tests/integration/validationFlow.test.js +329 -0
- package/data/probe/npm/tests/manual/test-codex-basic.js +110 -0
- package/data/probe/npm/tests/mcp/mcpClientManager.test.js +614 -0
- package/data/probe/npm/tests/mcp/mcpConfig.test.js +359 -0
- package/data/probe/npm/tests/mcp/mcpXmlBridge.test.js +436 -0
- package/data/probe/npm/tests/mcp/mockMcpServer.js +510 -0
- package/data/probe/npm/tests/mcp-strict-syntax.test.js +319 -0
- package/data/probe/npm/tests/mermaidQuoteEscaping.test.js +214 -0
- package/data/probe/npm/tests/nestedQuoteFix.test.js +40 -0
- package/data/probe/npm/tests/setup.js +46 -0
- package/data/probe/npm/tests/unit/allowed-tools.test.js +513 -0
- package/data/probe/npm/tests/unit/attempt-completion-closing-tag-in-content.test.js +188 -0
- package/data/probe/npm/tests/unit/attemptCompletionJsonFix.test.js +238 -0
- package/data/probe/npm/tests/unit/attemptCompletionJsonIssue.test.js +128 -0
- package/data/probe/npm/tests/unit/backtickAutoFix.test.js +35 -0
- package/data/probe/npm/tests/unit/bash-probe-agent-integration.test.js +389 -0
- package/data/probe/npm/tests/unit/bash-simple-commands.test.js +324 -0
- package/data/probe/npm/tests/unit/bash-tool-comprehensive.test.js +371 -0
- package/data/probe/npm/tests/unit/bash-tool-integration.test.js +310 -0
- package/data/probe/npm/tests/unit/bash-tool.test.js +341 -0
- package/data/probe/npm/tests/unit/completion-prompt.test.js +379 -0
- package/data/probe/npm/tests/unit/cwd-path-options.test.js +287 -0
- package/data/probe/npm/tests/unit/delegate-limits.test.js +422 -0
- package/data/probe/npm/tests/unit/direct-content-attempt-completion.test.js +235 -0
- package/data/probe/npm/tests/unit/edit-create-tools.test.js +609 -0
- package/data/probe/npm/tests/unit/enhancedMermaidValidation.test.js +577 -0
- package/data/probe/npm/tests/unit/extract-content.test.js +83 -0
- package/data/probe/npm/tests/unit/extract-multiple-targets.test.js +89 -0
- package/data/probe/npm/tests/unit/fallbackManager.test.js +442 -0
- package/data/probe/npm/tests/unit/githubCompatibilityValidation.test.js +258 -0
- package/data/probe/npm/tests/unit/imageConfig.test.js +149 -0
- package/data/probe/npm/tests/unit/imagePathResolution.test.js +345 -0
- package/data/probe/npm/tests/unit/json-fixing-agent.test.js +238 -0
- package/data/probe/npm/tests/unit/json-validation-enhanced-errors.test.js +199 -0
- package/data/probe/npm/tests/unit/jsonValidationInfiniteLoopFix.test.js +228 -0
- package/data/probe/npm/tests/unit/maidIntegration.test.js +139 -0
- package/data/probe/npm/tests/unit/maxIterationsWarning.test.js +195 -0
- package/data/probe/npm/tests/unit/mermaidEdgeLabelFix.test.js +161 -0
- package/data/probe/npm/tests/unit/mermaidHtmlEntities.test.js +76 -0
- package/data/probe/npm/tests/unit/mermaidInfiniteLoopFix.test.js +64 -0
- package/data/probe/npm/tests/unit/mermaidValidation.test.js +723 -0
- package/data/probe/npm/tests/unit/mermaidValidationVisorExample.test.js +309 -0
- package/data/probe/npm/tests/unit/probe-agent-clone-realistic.test.js +643 -0
- package/data/probe/npm/tests/unit/probe-agent-clone.test.js +476 -0
- package/data/probe/npm/tests/unit/probe-agent-delegate.test.js +400 -0
- package/data/probe/npm/tests/unit/probe-agent-model-option.test.js +118 -0
- package/data/probe/npm/tests/unit/probeTool-security.test.js +283 -0
- package/data/probe/npm/tests/unit/readImageTool.test.js +418 -0
- package/data/probe/npm/tests/unit/retryManager.test.js +317 -0
- package/data/probe/npm/tests/unit/schema-aware-reminders.test.js +288 -0
- package/data/probe/npm/tests/unit/schemaDefinitionDetection.test.js +115 -0
- package/data/probe/npm/tests/unit/schemaUtils.test.js +1268 -0
- package/data/probe/npm/tests/unit/simpleTelemetry.test.js +282 -0
- package/data/probe/npm/tests/unit/simplified-attempt-completion.test.js +274 -0
- package/data/probe/npm/tests/unit/single-quote-json-bug.test.js +231 -0
- package/data/probe/npm/tests/unit/subgraphAutoFix.test.js +110 -0
- package/data/probe/npm/tests/unit/system-prompt.test.js +32 -0
- package/data/probe/npm/tests/unit/types-probe-agent-options.test.js +42 -0
- package/data/probe/npm/tests/unit/xmlParsing.test.js +720 -0
- package/data/probe/npm/tsconfig.json +21 -0
- package/data/probe/result1.txt +19 -0
- package/data/probe/result2.txt +26 -0
- package/data/probe/scripts/benchmark.sh +270 -0
- package/data/probe/scripts/cache_memory_analysis.rs +844 -0
- package/data/probe/scripts/claude-hook-wrapper.sh +56 -0
- package/data/probe/site/.env.example +10 -0
- package/data/probe/site/DEPLOYMENT.md +86 -0
- package/data/probe/site/README.md +183 -0
- package/data/probe/site/adding-languages.md +135 -0
- package/data/probe/site/ai-chat.md +427 -0
- package/data/probe/site/ai-integration.md +1488 -0
- package/data/probe/site/blog/agentic-flow-custom-xml-protocol.md +407 -0
- package/data/probe/site/blog/index.md +118 -0
- package/data/probe/site/blog/v0.6.0-release.md +426 -0
- package/data/probe/site/blog.md +8 -0
- package/data/probe/site/changelog.md +200 -0
- package/data/probe/site/cli-mode.md +437 -0
- package/data/probe/site/code-extraction.md +436 -0
- package/data/probe/site/contributing/README.md +9 -0
- package/data/probe/site/contributing/documentation-cross-references.md +215 -0
- package/data/probe/site/contributing/documentation-maintenance.md +275 -0
- package/data/probe/site/contributing/documentation-structure.md +75 -0
- package/data/probe/site/documentation-cross-references.md +215 -0
- package/data/probe/site/documentation-guide.md +132 -0
- package/data/probe/site/documentation-maintenance.md +275 -0
- package/data/probe/site/features.md +147 -0
- package/data/probe/site/how-it-works.md +118 -0
- package/data/probe/site/index.md +175 -0
- package/data/probe/site/index.md.bak +133 -0
- package/data/probe/site/installation.md +235 -0
- package/data/probe/site/integrations/docker.md +248 -0
- package/data/probe/site/integrations/github-actions.md +413 -0
- package/data/probe/site/language-support-overview.md +168 -0
- package/data/probe/site/mcp-integration.md +587 -0
- package/data/probe/site/mcp-server.md +304 -0
- package/data/probe/site/navigation-structure.md +76 -0
- package/data/probe/site/nodejs-sdk.md +798 -0
- package/data/probe/site/output-formats.md +625 -0
- package/data/probe/site/package.json +21 -0
- package/data/probe/site/public/_headers +28 -0
- package/data/probe/site/public/_redirects +11 -0
- package/data/probe/site/quick-start.md +289 -0
- package/data/probe/site/search-functionality.md +291 -0
- package/data/probe/site/search-reference.md +291 -0
- package/data/probe/site/supported-languages.md +215 -0
- package/data/probe/site/use-cases/README.md +8 -0
- package/data/probe/site/use-cases/advanced-cli.md +253 -0
- package/data/probe/site/use-cases/ai-code-editors.md +239 -0
- package/data/probe/site/use-cases/building-ai-tools.md +529 -0
- package/data/probe/site/use-cases/cli-ai-workflows.md +285 -0
- package/data/probe/site/use-cases/deploying-probe-web-interface.md +255 -0
- package/data/probe/site/use-cases/integrating-probe-into-ai-code-editors.md +161 -0
- package/data/probe/site/use-cases/nodejs-sdk.md +596 -0
- package/data/probe/site/use-cases/team-chat.md +350 -0
- package/data/probe/site/web-interface.md +434 -0
- package/data/probe/site/wrangler.toml +9 -0
- package/data/probe/test-api-key.sh +1 -0
- package/data/probe/test-probe-implementation/hello.js +7 -0
- package/data/probe/test_cases/demonstrate_early_termination_issues.sh +176 -0
- package/data/probe/test_cases/early_termination_issues.rs +533 -0
- package/data/probe/test_data/test_nested_struct.go +26 -0
- package/data/probe/tests/README.md +286 -0
- package/data/probe/tests/README_search_determinism_tests.md +116 -0
- package/data/probe/tests/adjacent_comment_test.rs +152 -0
- package/data/probe/tests/apostrophe_handling_tests.rs +132 -0
- package/data/probe/tests/block_filtering_with_ast_tests.rs +669 -0
- package/data/probe/tests/block_merging_tests.rs +396 -0
- package/data/probe/tests/c_outline_format_tests.rs +2179 -0
- package/data/probe/tests/cache_invalidation_issues.rs.disabled +682 -0
- package/data/probe/tests/cache_order_tests.rs +147 -0
- package/data/probe/tests/cache_query_scoping_tests.rs +221 -0
- package/data/probe/tests/cli_tests.rs +680 -0
- package/data/probe/tests/comment_context_integration_test.rs +240 -0
- package/data/probe/tests/common.rs +33 -0
- package/data/probe/tests/complex_block_merging_tests.rs +599 -0
- package/data/probe/tests/complex_query_block_filtering_tests.rs +422 -0
- package/data/probe/tests/control_flow_closing_braces_test.rs +91 -0
- package/data/probe/tests/cpp_outline_format_tests.rs +1507 -0
- package/data/probe/tests/csharp_outline_format_tests.rs +941 -0
- package/data/probe/tests/elastic_query_integration_tests.rs +922 -0
- package/data/probe/tests/extract_command_tests.rs +1848 -0
- package/data/probe/tests/extract_deduplication_tests.rs +146 -0
- package/data/probe/tests/extract_input_file_tests.rs +84 -0
- package/data/probe/tests/extract_prompt_tests.rs +102 -0
- package/data/probe/tests/filename_search_tests.rs +96 -0
- package/data/probe/tests/fixtures/user/AssemblyInfo.cs +3 -0
- package/data/probe/tests/github_extract_tests.rs +234 -0
- package/data/probe/tests/go_comment_test.rs +253 -0
- package/data/probe/tests/go_outline_format_tests.rs +2587 -0
- package/data/probe/tests/go_path_resolver_tests.rs +96 -0
- package/data/probe/tests/html_outline_format_tests.rs +637 -0
- package/data/probe/tests/integration_tests.rs +837 -0
- package/data/probe/tests/ip_whitelist_test.rs +148 -0
- package/data/probe/tests/java_outline_format_tests.rs +1611 -0
- package/data/probe/tests/javascript_extract_tests.rs +315 -0
- package/data/probe/tests/javascript_outline_format_tests.rs +1464 -0
- package/data/probe/tests/json_format_tests.rs +436 -0
- package/data/probe/tests/json_schema_validation_tests.rs +450 -0
- package/data/probe/tests/lib_usage.rs +60 -0
- package/data/probe/tests/line_comment_context_extension_test.rs +459 -0
- package/data/probe/tests/line_map_cache_tests.rs +114 -0
- package/data/probe/tests/markdown_integration_tests.rs +190 -0
- package/data/probe/tests/mocks/test_ip_whitelist.go +11 -0
- package/data/probe/tests/mocks/test_object.js +27 -0
- package/data/probe/tests/mocks/test_struct.go +50 -0
- package/data/probe/tests/multi_keyword_pattern_tests.rs +464 -0
- package/data/probe/tests/multi_language_syntax_integration_tests.rs +218 -0
- package/data/probe/tests/multiple_capture_groups_tests.rs +169 -0
- package/data/probe/tests/negative_compound_word_tests.rs +246 -0
- package/data/probe/tests/nested_symbol_extraction_tests.rs +99 -0
- package/data/probe/tests/outline_cross_file_interference_test.rs +335 -0
- package/data/probe/tests/outline_keyword_preservation_test.rs +67 -0
- package/data/probe/tests/output_format_edge_cases_tests.rs +693 -0
- package/data/probe/tests/parallel_extraction_tests.rs +178 -0
- package/data/probe/tests/parallel_search_tests.rs +355 -0
- package/data/probe/tests/path_resolver_tests.rs +698 -0
- package/data/probe/tests/php_outline_format_extended_tests.rs +928 -0
- package/data/probe/tests/php_outline_format_tests.rs +768 -0
- package/data/probe/tests/property_tests.proptest-regressions +9 -0
- package/data/probe/tests/property_tests.rs +118 -0
- package/data/probe/tests/python_outline_format_tests.rs +1538 -0
- package/data/probe/tests/query_command_json_tests.rs +438 -0
- package/data/probe/tests/query_command_tests.rs +232 -0
- package/data/probe/tests/query_command_xml_tests.rs +569 -0
- package/data/probe/tests/quoted_term_with_negative_keyword_tests.rs +216 -0
- package/data/probe/tests/required_terms_filename_tests.rs +116 -0
- package/data/probe/tests/ruby_outline_format_tests.rs +1011 -0
- package/data/probe/tests/rust_line_comment_context_test.rs +151 -0
- package/data/probe/tests/rust_outline_format_enhanced_tests.rs +725 -0
- package/data/probe/tests/rust_outline_format_tests.rs +843 -0
- package/data/probe/tests/schemas/xml_output_schema.xsd +38 -0
- package/data/probe/tests/search_determinism_tests.rs +451 -0
- package/data/probe/tests/search_hints_tests.rs +253 -0
- package/data/probe/tests/special_character_escaping_tests.rs +417 -0
- package/data/probe/tests/stemming_compound_word_filtering_tests.rs +535 -0
- package/data/probe/tests/strict_elastic_syntax_tests.rs +404 -0
- package/data/probe/tests/swift_outline_format_tests.rs +3319 -0
- package/data/probe/tests/symbols_tests.rs +166 -0
- package/data/probe/tests/test_file.rs +45 -0
- package/data/probe/tests/test_tokenize.rs +28 -0
- package/data/probe/tests/timeout_tests.rs +82 -0
- package/data/probe/tests/tokenization_tests.rs +195 -0
- package/data/probe/tests/tokenized_block_filtering_tests.rs +174 -0
- package/data/probe/tests/typescript_extract_tests.rs +214 -0
- package/data/probe/tests/typescript_outline_format_tests.rs +2188 -0
- package/data/probe/tests/xml_format_tests.rs +568 -0
- package/data/probe/tests/xml_schema_validation_tests.rs +497 -0
- package/data/scripts/postinstall.mjs +9 -0
- package/data/scripts/set-version.js +0 -0
- package/data/scripts/wiki-build.sh +111 -0
- package/data/scripts/wiki-deploy.sh +73 -0
- package/data/serve.json +12 -0
- package/data/test/demo-dynamic.html +134 -0
- package/data/test/demo-esm.html +105 -0
- package/data/test/demo-iife.html +78 -0
- package/data/tsconfig.json +7 -0
- package/data/vite.server.ts +483 -0
- package/data/vitest.config.ts +40 -0
- package/data/wiki/Home.md +58 -0
- package/data/wiki/_Sidebar.md +39 -0
- package/docs-mcp.config.json +20 -0
- package/package.json +56 -0
- package/src/config.js +111 -0
- package/src/index.js +395 -0
|
@@ -0,0 +1,3319 @@
|
|
|
1
|
+
use anyhow::Result;
|
|
2
|
+
use std::fs;
|
|
3
|
+
use tempfile::TempDir;
|
|
4
|
+
|
|
5
|
+
mod common;
|
|
6
|
+
use common::TestContext;
|
|
7
|
+
|
|
8
|
+
#[test]
|
|
9
|
+
fn test_swift_outline_basic_symbols() -> Result<()> {
|
|
10
|
+
let temp_dir = TempDir::new()?;
|
|
11
|
+
let test_file = temp_dir.path().join("Calculator.swift");
|
|
12
|
+
|
|
13
|
+
let content = r#"import Foundation
|
|
14
|
+
|
|
15
|
+
// Protocol for calculator operations
|
|
16
|
+
protocol CalculatorProtocol {
|
|
17
|
+
func add(_ x: Double, _ y: Double) -> Double
|
|
18
|
+
func subtract(_ x: Double, _ y: Double) -> Double
|
|
19
|
+
func multiply(_ x: Double, _ y: Double) -> Double
|
|
20
|
+
func divide(_ x: Double, _ y: Double) throws -> Double
|
|
21
|
+
var history: [Double] { get }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Custom errors
|
|
25
|
+
enum CalculatorError: Error {
|
|
26
|
+
case divisionByZero
|
|
27
|
+
case invalidInput(String)
|
|
28
|
+
case operationFailed(String)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
extension CalculatorError: LocalizedError {
|
|
32
|
+
var errorDescription: String? {
|
|
33
|
+
switch self {
|
|
34
|
+
case .divisionByZero:
|
|
35
|
+
return "Division by zero is not allowed"
|
|
36
|
+
case .invalidInput(let input):
|
|
37
|
+
return "Invalid input: \(input)"
|
|
38
|
+
case .operationFailed(let operation):
|
|
39
|
+
return "Operation failed: \(operation)"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Base calculator class
|
|
45
|
+
class BaseCalculator: CalculatorProtocol {
|
|
46
|
+
private(set) var name: String
|
|
47
|
+
private(set) var history: [Double] = []
|
|
48
|
+
private let precision: Double
|
|
49
|
+
|
|
50
|
+
init(name: String, precision: Double = 0.001) {
|
|
51
|
+
self.name = name
|
|
52
|
+
self.precision = precision
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func add(_ x: Double, _ y: Double) -> Double {
|
|
56
|
+
let result = x + y
|
|
57
|
+
recordOperation(result)
|
|
58
|
+
return result
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
func subtract(_ x: Double, _ y: Double) -> Double {
|
|
62
|
+
let result = x - y
|
|
63
|
+
recordOperation(result)
|
|
64
|
+
return result
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
func multiply(_ x: Double, _ y: Double) -> Double {
|
|
68
|
+
let result = x * y
|
|
69
|
+
recordOperation(result)
|
|
70
|
+
return result
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func divide(_ x: Double, _ y: Double) throws -> Double {
|
|
74
|
+
guard abs(y) > precision else {
|
|
75
|
+
throw CalculatorError.divisionByZero
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let result = x / y
|
|
79
|
+
recordOperation(result)
|
|
80
|
+
return result
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func clearHistory() {
|
|
84
|
+
history.removeAll()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private func recordOperation(_ result: Double) {
|
|
88
|
+
history.append(result)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Advanced calculator with generics and modern Swift features
|
|
93
|
+
class AdvancedCalculator: BaseCalculator {
|
|
94
|
+
typealias NumberProcessor<T> = (T) -> T where T: Numeric
|
|
95
|
+
|
|
96
|
+
private var constants: [String: Double] = [
|
|
97
|
+
"pi": Double.pi,
|
|
98
|
+
"e": M_E,
|
|
99
|
+
"goldenRatio": (1 + sqrt(5)) / 2
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
private var operationsCount: Int = 0
|
|
103
|
+
|
|
104
|
+
override init(name: String, precision: Double = 0.001) {
|
|
105
|
+
super.init(name: name, precision: precision)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Convenience initializer
|
|
109
|
+
convenience init(name: String) {
|
|
110
|
+
self.init(name: name, precision: 0.001)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Override operations to add counting
|
|
114
|
+
override func add(_ x: Double, _ y: Double) -> Double {
|
|
115
|
+
operationsCount += 1
|
|
116
|
+
return super.add(x, y)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
override func subtract(_ x: Double, _ y: Double) -> Double {
|
|
120
|
+
operationsCount += 1
|
|
121
|
+
return super.subtract(x, y)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
override func multiply(_ x: Double, _ y: Double) -> Double {
|
|
125
|
+
operationsCount += 1
|
|
126
|
+
return super.multiply(x, y)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
override func divide(_ x: Double, _ y: Double) throws -> Double {
|
|
130
|
+
operationsCount += 1
|
|
131
|
+
return try super.divide(x, y)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Generic method with constraints
|
|
135
|
+
func processNumbers<T: Numeric>(_ numbers: [T], with processor: NumberProcessor<T>) -> [T] {
|
|
136
|
+
return numbers.map(processor)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Method with closure parameter
|
|
140
|
+
func transformHistory(_ transformer: @escaping (Double) -> Double) -> [Double] {
|
|
141
|
+
return history.map(transformer)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Computed properties
|
|
145
|
+
var averageResult: Double {
|
|
146
|
+
guard !history.isEmpty else { return 0 }
|
|
147
|
+
return history.reduce(0, +) / Double(history.count)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
var operationsPerformed: Int {
|
|
151
|
+
return operationsCount
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Static factory method
|
|
155
|
+
static func createDefault(name: String) -> AdvancedCalculator {
|
|
156
|
+
return AdvancedCalculator(name: name)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Subscript for accessing constants
|
|
160
|
+
subscript(constant: String) -> Double? {
|
|
161
|
+
get { return constants[constant] }
|
|
162
|
+
set { constants[constant] = newValue }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Nested enum for operation types
|
|
166
|
+
enum OperationType: String, CaseIterable {
|
|
167
|
+
case addition = "add"
|
|
168
|
+
case subtraction = "subtract"
|
|
169
|
+
case multiplication = "multiply"
|
|
170
|
+
case division = "divide"
|
|
171
|
+
|
|
172
|
+
var description: String {
|
|
173
|
+
switch self {
|
|
174
|
+
case .addition: return "Addition"
|
|
175
|
+
case .subtraction: return "Subtraction"
|
|
176
|
+
case .multiplication: return "Multiplication"
|
|
177
|
+
case .division: return "Division"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Nested struct for operation results
|
|
183
|
+
struct OperationResult {
|
|
184
|
+
let value: Double
|
|
185
|
+
let operation: OperationType
|
|
186
|
+
let timestamp: Date
|
|
187
|
+
|
|
188
|
+
init(value: Double, operation: OperationType) {
|
|
189
|
+
self.value = value
|
|
190
|
+
self.operation = operation
|
|
191
|
+
self.timestamp = Date()
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Scientific calculator with advanced mathematical functions
|
|
197
|
+
final class ScientificCalculator: AdvancedCalculator {
|
|
198
|
+
|
|
199
|
+
func sin(_ x: Double) -> Double {
|
|
200
|
+
let result = Foundation.sin(x)
|
|
201
|
+
recordOperation(result)
|
|
202
|
+
return result
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
func cos(_ x: Double) -> Double {
|
|
206
|
+
let result = Foundation.cos(x)
|
|
207
|
+
recordOperation(result)
|
|
208
|
+
return result
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
func tan(_ x: Double) -> Double {
|
|
212
|
+
let result = Foundation.tan(x)
|
|
213
|
+
recordOperation(result)
|
|
214
|
+
return result
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
func log(_ x: Double, base: Double = M_E) throws -> Double {
|
|
218
|
+
guard x > 0 else {
|
|
219
|
+
throw CalculatorError.invalidInput("Cannot take log of zero or negative number")
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
let result = Foundation.log(x) / Foundation.log(base)
|
|
223
|
+
recordOperation(result)
|
|
224
|
+
return result
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
func power(_ base: Double, _ exponent: Double) -> Double {
|
|
228
|
+
let result = pow(base, exponent)
|
|
229
|
+
recordOperation(result)
|
|
230
|
+
return result
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
func factorial(_ n: Int) throws -> Double {
|
|
234
|
+
guard n >= 0 else {
|
|
235
|
+
throw CalculatorError.invalidInput("Factorial of negative number")
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
let result = (1...max(1, n)).reduce(1) { $0 * $1 }
|
|
239
|
+
let doubleResult = Double(result)
|
|
240
|
+
recordOperation(doubleResult)
|
|
241
|
+
return doubleResult
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Computed property for statistics
|
|
245
|
+
var statistics: (mean: Double, median: Double, standardDeviation: Double) {
|
|
246
|
+
guard !history.isEmpty else {
|
|
247
|
+
return (0, 0, 0)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
let mean = history.reduce(0, +) / Double(history.count)
|
|
251
|
+
|
|
252
|
+
let sortedHistory = history.sorted()
|
|
253
|
+
let median: Double
|
|
254
|
+
let count = sortedHistory.count
|
|
255
|
+
|
|
256
|
+
if count % 2 == 0 {
|
|
257
|
+
median = (sortedHistory[count / 2 - 1] + sortedHistory[count / 2]) / 2
|
|
258
|
+
} else {
|
|
259
|
+
median = sortedHistory[count / 2]
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
let variance = history.map { pow($0 - mean, 2) }.reduce(0, +) / Double(history.count)
|
|
263
|
+
let standardDeviation = sqrt(variance)
|
|
264
|
+
|
|
265
|
+
return (mean, median, standardDeviation)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private func recordOperation(_ result: Double) {
|
|
269
|
+
// Call parent's private method through a workaround
|
|
270
|
+
let _ = add(0, result) - result
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Extension for CustomStringConvertible
|
|
275
|
+
extension BaseCalculator: CustomStringConvertible {
|
|
276
|
+
var description: String {
|
|
277
|
+
return "Calculator '\(name)' with \(history.count) operations"
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Extension with default implementations
|
|
282
|
+
extension CalculatorProtocol {
|
|
283
|
+
var historyCount: Int {
|
|
284
|
+
return history.count
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
func lastResult() -> Double? {
|
|
288
|
+
return history.last
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Struct for calculator configuration
|
|
293
|
+
struct CalculatorConfiguration {
|
|
294
|
+
let name: String
|
|
295
|
+
let precision: Double
|
|
296
|
+
let enableHistory: Bool
|
|
297
|
+
|
|
298
|
+
static let `default` = CalculatorConfiguration(
|
|
299
|
+
name: "Default Calculator",
|
|
300
|
+
precision: 0.001,
|
|
301
|
+
enableHistory: true
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
// Factory method
|
|
305
|
+
static func scientific(name: String) -> CalculatorConfiguration {
|
|
306
|
+
return CalculatorConfiguration(
|
|
307
|
+
name: name,
|
|
308
|
+
precision: 0.0001,
|
|
309
|
+
enableHistory: true
|
|
310
|
+
)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Utility functions
|
|
315
|
+
func createCalculator(with config: CalculatorConfiguration) -> BaseCalculator {
|
|
316
|
+
return BaseCalculator(name: config.name, precision: config.precision)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
func performCalculations() {
|
|
320
|
+
let calc = ScientificCalculator.createDefault(name: "Demo Calculator")
|
|
321
|
+
|
|
322
|
+
do {
|
|
323
|
+
print("Calculator: \(calc.name)")
|
|
324
|
+
|
|
325
|
+
// Basic operations
|
|
326
|
+
let sum = calc.add(10, 5)
|
|
327
|
+
let product = calc.multiply(20, 3)
|
|
328
|
+
let quotient = try calc.divide(100, 4)
|
|
329
|
+
|
|
330
|
+
print("10 + 5 = \(sum)")
|
|
331
|
+
print("20 * 3 = \(product)")
|
|
332
|
+
print("100 / 4 = \(quotient)")
|
|
333
|
+
|
|
334
|
+
// Scientific operations
|
|
335
|
+
let sineResult = calc.sin(Double.pi / 2)
|
|
336
|
+
let factorialResult = try calc.factorial(5)
|
|
337
|
+
|
|
338
|
+
print("sin(π/2) = \(sineResult)")
|
|
339
|
+
print("5! = \(factorialResult)")
|
|
340
|
+
|
|
341
|
+
// Statistics
|
|
342
|
+
let stats = calc.statistics
|
|
343
|
+
print("Mean: \(stats.mean)")
|
|
344
|
+
print("Median: \(stats.median)")
|
|
345
|
+
print("Standard Deviation: \(stats.standardDeviation)")
|
|
346
|
+
|
|
347
|
+
// History
|
|
348
|
+
print("History: \(calc.history)")
|
|
349
|
+
print("Operations count: \(calc.operationsPerformed)")
|
|
350
|
+
|
|
351
|
+
} catch {
|
|
352
|
+
print("Error: \(error.localizedDescription)")
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Test functions
|
|
357
|
+
func testBasicCalculator() throws {
|
|
358
|
+
let calc = AdvancedCalculator(name: "Test Calculator")
|
|
359
|
+
|
|
360
|
+
let result1 = calc.add(2, 3)
|
|
361
|
+
guard result1 == 5 else {
|
|
362
|
+
throw CalculatorError.operationFailed("Add test failed")
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
let result2 = calc.multiply(4, 5)
|
|
366
|
+
guard result2 == 20 else {
|
|
367
|
+
throw CalculatorError.operationFailed("Multiply test failed")
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
print("Basic calculator tests passed")
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
func testScientificCalculator() throws {
|
|
374
|
+
let calc = ScientificCalculator(name: "Scientific Test")
|
|
375
|
+
|
|
376
|
+
let result1 = calc.power(2, 3)
|
|
377
|
+
guard result1 == 8 else {
|
|
378
|
+
throw CalculatorError.operationFailed("Power test failed")
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
let result2 = try calc.factorial(4)
|
|
382
|
+
guard result2 == 24 else {
|
|
383
|
+
throw CalculatorError.operationFailed("Factorial test failed")
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
print("Scientific calculator tests passed")
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Main execution
|
|
390
|
+
if CommandLine.arguments.contains("--demo") {
|
|
391
|
+
performCalculations()
|
|
392
|
+
|
|
393
|
+
do {
|
|
394
|
+
try testBasicCalculator()
|
|
395
|
+
try testScientificCalculator()
|
|
396
|
+
} catch {
|
|
397
|
+
print("Test failed: \(error)")
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
"#;
|
|
401
|
+
|
|
402
|
+
fs::write(&test_file, content)?;
|
|
403
|
+
|
|
404
|
+
let ctx = TestContext::new();
|
|
405
|
+
let output = ctx.run_probe(&[
|
|
406
|
+
"extract",
|
|
407
|
+
test_file.to_str().unwrap(),
|
|
408
|
+
"--format",
|
|
409
|
+
"outline",
|
|
410
|
+
"--allow-tests",
|
|
411
|
+
])?;
|
|
412
|
+
|
|
413
|
+
// Verify Swift symbols are extracted
|
|
414
|
+
assert!(
|
|
415
|
+
output.contains("protocol CalculatorProtocol"),
|
|
416
|
+
"Missing CalculatorProtocol - output: {}",
|
|
417
|
+
output
|
|
418
|
+
);
|
|
419
|
+
assert!(
|
|
420
|
+
output.contains("enum CalculatorError") || output.contains("CalculatorError"),
|
|
421
|
+
"Missing CalculatorError enum - output: {}",
|
|
422
|
+
output
|
|
423
|
+
);
|
|
424
|
+
assert!(
|
|
425
|
+
output.contains("class BaseCalculator") || output.contains("BaseCalculator"),
|
|
426
|
+
"Missing BaseCalculator class - output: {}",
|
|
427
|
+
output
|
|
428
|
+
);
|
|
429
|
+
assert!(
|
|
430
|
+
output.contains("class AdvancedCalculator") || output.contains("AdvancedCalculator"),
|
|
431
|
+
"Missing AdvancedCalculator class - output: {}",
|
|
432
|
+
output
|
|
433
|
+
);
|
|
434
|
+
assert!(
|
|
435
|
+
output.contains("final class ScientificCalculator")
|
|
436
|
+
|| output.contains("ScientificCalculator"),
|
|
437
|
+
"Missing ScientificCalculator class - output: {}",
|
|
438
|
+
output
|
|
439
|
+
);
|
|
440
|
+
assert!(
|
|
441
|
+
output.contains("func test") || output.contains("testBasicCalculator"),
|
|
442
|
+
"Missing test functions - output: {}",
|
|
443
|
+
output
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
Ok(())
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
#[test]
|
|
450
|
+
fn test_swift_outline_smart_closing_brace_comments() -> Result<()> {
|
|
451
|
+
let temp_dir = TempDir::new()?;
|
|
452
|
+
let test_file = temp_dir.path().join("ClosingBraceTest.swift");
|
|
453
|
+
|
|
454
|
+
let content = r#"import Foundation
|
|
455
|
+
|
|
456
|
+
// Small function that should NOT get closing brace comments
|
|
457
|
+
func smallFunction(_ x: Int) -> Int {
|
|
458
|
+
let result = x * 2
|
|
459
|
+
return result + 1
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Large function that SHOULD get closing brace comments with Swift // syntax
|
|
463
|
+
func largeFunctionWithGaps(data: [Int]) -> [String] {
|
|
464
|
+
var results: [String] = []
|
|
465
|
+
let processor = DataProcessor()
|
|
466
|
+
|
|
467
|
+
// Phase 1: Initial processing with nested control flow
|
|
468
|
+
for (index, value) in data.enumerated() {
|
|
469
|
+
if value > 100 {
|
|
470
|
+
processor.processLargeValue(value, at: index)
|
|
471
|
+
} else if value < 0 {
|
|
472
|
+
processor.processNegativeValue(value, at: index)
|
|
473
|
+
} else {
|
|
474
|
+
processor.processSmallValue(value, at: index)
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Phase 2: Complex transformation logic
|
|
479
|
+
let transformedData = processor.getTransformedData()
|
|
480
|
+
for item in transformedData {
|
|
481
|
+
switch item.category {
|
|
482
|
+
case .high:
|
|
483
|
+
results.append("HIGH: \(item.value)")
|
|
484
|
+
case .medium:
|
|
485
|
+
results.append("MED: \(item.value)")
|
|
486
|
+
case .low:
|
|
487
|
+
results.append("LOW: \(item.value)")
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Phase 3: Final validation and cleanup
|
|
492
|
+
var validatedResults: [String] = []
|
|
493
|
+
for result in results {
|
|
494
|
+
guard result.count > 5 else { continue }
|
|
495
|
+
validatedResults.append(result)
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return validatedResults
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Another large function to test closing brace behavior
|
|
502
|
+
class LargeProcessorClass {
|
|
503
|
+
private var accumulator: Accumulator
|
|
504
|
+
|
|
505
|
+
init() {
|
|
506
|
+
self.accumulator = Accumulator()
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
func processItems(_ items: [Item]) -> ProcessedResult {
|
|
510
|
+
// Main processing with deeply nested control flow
|
|
511
|
+
for item in items {
|
|
512
|
+
switch item.itemType {
|
|
513
|
+
case .primary:
|
|
514
|
+
if item.weight > 50.0 {
|
|
515
|
+
accumulator.addHeavyPrimary(item)
|
|
516
|
+
} else {
|
|
517
|
+
accumulator.addLightPrimary(item)
|
|
518
|
+
}
|
|
519
|
+
case .secondary:
|
|
520
|
+
accumulator.addSecondary(item)
|
|
521
|
+
case .auxiliary:
|
|
522
|
+
accumulator.addAuxiliary(item)
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return accumulator.finalize()
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Large extension with multiple methods
|
|
531
|
+
extension String {
|
|
532
|
+
func complexStringProcessor() -> ProcessedString {
|
|
533
|
+
let processor = StringProcessor()
|
|
534
|
+
|
|
535
|
+
// Multi-stage string processing
|
|
536
|
+
let stage1 = processor.initialCleanup(self)
|
|
537
|
+
let stage2 = processor.tokenization(stage1)
|
|
538
|
+
let stage3 = processor.normalization(stage2)
|
|
539
|
+
|
|
540
|
+
guard !stage3.isEmpty else {
|
|
541
|
+
return ProcessedString.empty
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Final processing with validation
|
|
545
|
+
let finalResult = processor.finalization(stage3)
|
|
546
|
+
return ProcessedString(content: finalResult)
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
"#;
|
|
550
|
+
|
|
551
|
+
fs::write(&test_file, content)?;
|
|
552
|
+
|
|
553
|
+
let ctx = TestContext::new();
|
|
554
|
+
let output = ctx.run_probe(&[
|
|
555
|
+
"search",
|
|
556
|
+
"large", // Search for large functions/classes
|
|
557
|
+
test_file.to_str().unwrap(),
|
|
558
|
+
"--format",
|
|
559
|
+
"outline",
|
|
560
|
+
])?;
|
|
561
|
+
|
|
562
|
+
// Should find the large functions and classes
|
|
563
|
+
assert!(
|
|
564
|
+
output.contains("largeFunctionWithGaps") || output.contains("LargeProcessorClass"),
|
|
565
|
+
"Missing large functions/classes - output: {}",
|
|
566
|
+
output
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
// Should have closing brace comments with Swift // syntax (not /* */)
|
|
570
|
+
let has_swift_closing_brace_comment = output.contains("} //");
|
|
571
|
+
assert!(
|
|
572
|
+
has_swift_closing_brace_comment,
|
|
573
|
+
"Large functions should have closing brace comments with Swift // syntax - output: {}",
|
|
574
|
+
output
|
|
575
|
+
);
|
|
576
|
+
|
|
577
|
+
// Should NOT have closing braces for small functions
|
|
578
|
+
let small_func_lines: Vec<&str> = output
|
|
579
|
+
.lines()
|
|
580
|
+
.filter(|line| line.contains("smallFunction"))
|
|
581
|
+
.collect();
|
|
582
|
+
|
|
583
|
+
if !small_func_lines.is_empty() {
|
|
584
|
+
// If smallFunction appears in output, verify it doesn't have closing brace comments
|
|
585
|
+
let has_small_func_closing_comment = output.lines().any(|line| {
|
|
586
|
+
line.contains("smallFunction") && (line.contains("} //") || line.contains("} /*"))
|
|
587
|
+
});
|
|
588
|
+
assert!(
|
|
589
|
+
!has_small_func_closing_comment,
|
|
590
|
+
"Small functions should NOT have closing brace comments - output: {}",
|
|
591
|
+
output
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Should be in outline format
|
|
596
|
+
assert!(
|
|
597
|
+
output.contains("---\nFile:"),
|
|
598
|
+
"Missing file delimiter in outline format - output: {}",
|
|
599
|
+
output
|
|
600
|
+
);
|
|
601
|
+
|
|
602
|
+
Ok(())
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
#[test]
|
|
606
|
+
fn test_swift_outline_keyword_highlighting() -> Result<()> {
|
|
607
|
+
let temp_dir = TempDir::new()?;
|
|
608
|
+
let test_file = temp_dir.path().join("KeywordTest.swift");
|
|
609
|
+
|
|
610
|
+
let content = r#"import Foundation
|
|
611
|
+
import SwiftUI
|
|
612
|
+
|
|
613
|
+
// Protocol with associated types and where clauses
|
|
614
|
+
protocol Processable {
|
|
615
|
+
associatedtype InputType
|
|
616
|
+
associatedtype OutputType where OutputType: Codable
|
|
617
|
+
|
|
618
|
+
func process(_ input: InputType) async throws -> OutputType
|
|
619
|
+
var isReady: Bool { get }
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Generic class with constraints
|
|
623
|
+
class DataProcessor<T: Hashable & Codable>: Processable {
|
|
624
|
+
typealias InputType = T
|
|
625
|
+
typealias OutputType = ProcessedData<T>
|
|
626
|
+
|
|
627
|
+
private let queue: DispatchQueue
|
|
628
|
+
private var cache: [T: OutputType] = [:]
|
|
629
|
+
|
|
630
|
+
var isReady: Bool {
|
|
631
|
+
return !cache.isEmpty
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
init(queue: DispatchQueue = .main) {
|
|
635
|
+
self.queue = queue
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// Async function with error handling
|
|
639
|
+
func process(_ input: T) async throws -> OutputType {
|
|
640
|
+
if let cached = cache[input] {
|
|
641
|
+
return cached
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
do {
|
|
645
|
+
let result = try await performProcessing(input)
|
|
646
|
+
cache[input] = result
|
|
647
|
+
return result
|
|
648
|
+
} catch {
|
|
649
|
+
throw ProcessingError.failedToProcess(input, error)
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// Private async helper with guard statements
|
|
654
|
+
private func performProcessing(_ input: T) async throws -> OutputType {
|
|
655
|
+
guard isReady else {
|
|
656
|
+
throw ProcessingError.notReady
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
return try await withCheckedThrowingContinuation { continuation in
|
|
660
|
+
queue.async {
|
|
661
|
+
do {
|
|
662
|
+
let processed = ProcessedData(value: input, timestamp: Date())
|
|
663
|
+
continuation.resume(returning: processed)
|
|
664
|
+
} catch {
|
|
665
|
+
continuation.resume(throwing: error)
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Enum with associated values and computed properties
|
|
673
|
+
enum ProcessingError: Error, LocalizedError {
|
|
674
|
+
case notReady
|
|
675
|
+
case failedToProcess(Any, Error)
|
|
676
|
+
case invalidInput(String)
|
|
677
|
+
|
|
678
|
+
var errorDescription: String? {
|
|
679
|
+
switch self {
|
|
680
|
+
case .notReady:
|
|
681
|
+
return "Processor is not ready"
|
|
682
|
+
case .failedToProcess(let input, let error):
|
|
683
|
+
return "Failed to process \(input): \(error.localizedDescription)"
|
|
684
|
+
case .invalidInput(let input):
|
|
685
|
+
return "Invalid input: \(input)"
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Struct with property wrappers and computed properties
|
|
691
|
+
struct ProcessedData<T: Codable>: Codable {
|
|
692
|
+
@Published var value: T
|
|
693
|
+
let timestamp: Date
|
|
694
|
+
|
|
695
|
+
var age: TimeInterval {
|
|
696
|
+
return Date().timeIntervalSince(timestamp)
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
init(value: T, timestamp: Date) {
|
|
700
|
+
self._value = Published(initialValue: value)
|
|
701
|
+
self.timestamp = timestamp
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// Extension with conditional conformance
|
|
706
|
+
extension ProcessedData: Equatable where T: Equatable {
|
|
707
|
+
static func == (lhs: ProcessedData<T>, rhs: ProcessedData<T>) -> Bool {
|
|
708
|
+
return lhs.value == rhs.value && lhs.timestamp == rhs.timestamp
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// SwiftUI View with ViewBuilder and State
|
|
713
|
+
struct ContentView: View {
|
|
714
|
+
@State private var isLoading: Bool = false
|
|
715
|
+
@StateObject private var processor = DataProcessor<String>()
|
|
716
|
+
|
|
717
|
+
var body: some View {
|
|
718
|
+
VStack {
|
|
719
|
+
if isLoading {
|
|
720
|
+
ProgressView("Processing...")
|
|
721
|
+
} else {
|
|
722
|
+
Button("Start Processing") {
|
|
723
|
+
Task {
|
|
724
|
+
await startProcessing()
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
.padding()
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
@MainActor
|
|
733
|
+
private func startProcessing() async {
|
|
734
|
+
isLoading = true
|
|
735
|
+
defer { isLoading = false }
|
|
736
|
+
|
|
737
|
+
do {
|
|
738
|
+
let result = try await processor.process("test data")
|
|
739
|
+
print("Processed: \(result)")
|
|
740
|
+
} catch {
|
|
741
|
+
print("Error: \(error)")
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// Actor for concurrent processing
|
|
747
|
+
actor ConcurrentProcessor {
|
|
748
|
+
private var tasks: [Task<Void, Never>] = []
|
|
749
|
+
|
|
750
|
+
func addTask(_ operation: @escaping () async -> Void) {
|
|
751
|
+
let task = Task {
|
|
752
|
+
await operation()
|
|
753
|
+
}
|
|
754
|
+
tasks.append(task)
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
func waitForAll() async {
|
|
758
|
+
for task in tasks {
|
|
759
|
+
await task.value
|
|
760
|
+
}
|
|
761
|
+
tasks.removeAll()
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
"#;
|
|
765
|
+
|
|
766
|
+
fs::write(&test_file, content)?;
|
|
767
|
+
|
|
768
|
+
let ctx = TestContext::new();
|
|
769
|
+
let output = ctx.run_probe(&[
|
|
770
|
+
"search",
|
|
771
|
+
"async", // Search for async keyword
|
|
772
|
+
test_file.to_str().unwrap(),
|
|
773
|
+
"--format",
|
|
774
|
+
"outline",
|
|
775
|
+
])?;
|
|
776
|
+
|
|
777
|
+
// Should highlight Swift keywords in the search results
|
|
778
|
+
// Look for async, await, throws, guard, defer, etc.
|
|
779
|
+
let swift_keywords = [
|
|
780
|
+
"async",
|
|
781
|
+
"await",
|
|
782
|
+
"throws",
|
|
783
|
+
"guard",
|
|
784
|
+
"defer",
|
|
785
|
+
"actor",
|
|
786
|
+
"@Published",
|
|
787
|
+
"@State",
|
|
788
|
+
"@MainActor",
|
|
789
|
+
];
|
|
790
|
+
let found_keywords: Vec<&str> = swift_keywords
|
|
791
|
+
.iter()
|
|
792
|
+
.filter(|&keyword| output.contains(keyword))
|
|
793
|
+
.copied()
|
|
794
|
+
.collect();
|
|
795
|
+
|
|
796
|
+
assert!(
|
|
797
|
+
!found_keywords.is_empty(),
|
|
798
|
+
"Should find and highlight Swift keywords. Found: {:?} - output: {}",
|
|
799
|
+
found_keywords,
|
|
800
|
+
output
|
|
801
|
+
);
|
|
802
|
+
|
|
803
|
+
// Should contain the searched term
|
|
804
|
+
assert!(
|
|
805
|
+
output.contains("async"),
|
|
806
|
+
"Should contain the searched async keyword - output: {}",
|
|
807
|
+
output
|
|
808
|
+
);
|
|
809
|
+
|
|
810
|
+
// Should be in outline format
|
|
811
|
+
assert!(
|
|
812
|
+
output.contains("---\nFile:"),
|
|
813
|
+
"Missing file delimiter in outline format - output: {}",
|
|
814
|
+
output
|
|
815
|
+
);
|
|
816
|
+
|
|
817
|
+
Ok(())
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
#[test]
|
|
821
|
+
fn test_swift_outline_array_dictionary_truncation_with_keyword_preservation() -> Result<()> {
|
|
822
|
+
let temp_dir = TempDir::new()?;
|
|
823
|
+
let test_file = temp_dir.path().join("ArrayDictTest.swift");
|
|
824
|
+
|
|
825
|
+
let content = r#"import Foundation
|
|
826
|
+
|
|
827
|
+
struct ConfigurationManager {
|
|
828
|
+
// Large array that should be truncated but preserve keywords
|
|
829
|
+
let supportedLanguages = [
|
|
830
|
+
"swift",
|
|
831
|
+
"objective-c",
|
|
832
|
+
"javascript",
|
|
833
|
+
"typescript",
|
|
834
|
+
"python",
|
|
835
|
+
"java",
|
|
836
|
+
"kotlin",
|
|
837
|
+
"dart",
|
|
838
|
+
"go",
|
|
839
|
+
"rust",
|
|
840
|
+
"c",
|
|
841
|
+
"cpp",
|
|
842
|
+
"csharp",
|
|
843
|
+
"php",
|
|
844
|
+
"ruby",
|
|
845
|
+
"perl",
|
|
846
|
+
"scala",
|
|
847
|
+
"clojure",
|
|
848
|
+
"haskell",
|
|
849
|
+
"erlang",
|
|
850
|
+
"elixir",
|
|
851
|
+
"lua",
|
|
852
|
+
"shell",
|
|
853
|
+
"powershell",
|
|
854
|
+
"dockerfile",
|
|
855
|
+
"yaml",
|
|
856
|
+
"json",
|
|
857
|
+
"xml",
|
|
858
|
+
"html",
|
|
859
|
+
"css",
|
|
860
|
+
"sass",
|
|
861
|
+
"less"
|
|
862
|
+
]
|
|
863
|
+
|
|
864
|
+
// Large dictionary with keyword-rich content
|
|
865
|
+
private var configurationSettings: [String: Any] = [
|
|
866
|
+
"database_host": "localhost",
|
|
867
|
+
"database_port": 5432,
|
|
868
|
+
"database_name": "production_db",
|
|
869
|
+
"api_key_primary": "sk-test-1234567890",
|
|
870
|
+
"api_key_secondary": "sk-backup-0987654321",
|
|
871
|
+
"cache_timeout": 3600,
|
|
872
|
+
"retry_attempts": 3,
|
|
873
|
+
"batch_size": 1000,
|
|
874
|
+
"worker_threads": 8,
|
|
875
|
+
"memory_limit": "2GB",
|
|
876
|
+
"disk_space_threshold": "10GB",
|
|
877
|
+
"network_timeout": 30,
|
|
878
|
+
"authentication_enabled": true,
|
|
879
|
+
"ssl_verification": true,
|
|
880
|
+
"logging_level": "info",
|
|
881
|
+
"debug_mode": false,
|
|
882
|
+
"performance_monitoring": true,
|
|
883
|
+
"error_tracking": true,
|
|
884
|
+
"metrics_collection": true,
|
|
885
|
+
"backup_enabled": true,
|
|
886
|
+
"backup_frequency": "daily",
|
|
887
|
+
"retention_days": 30,
|
|
888
|
+
"compression_enabled": true,
|
|
889
|
+
"encryption_key": "aes-256-gcm",
|
|
890
|
+
"session_timeout": 1800,
|
|
891
|
+
"max_connections": 100,
|
|
892
|
+
"connection_pool_size": 20,
|
|
893
|
+
"query_timeout": 60,
|
|
894
|
+
"transaction_timeout": 120
|
|
895
|
+
]
|
|
896
|
+
|
|
897
|
+
func processLargeDataSet() -> [String] {
|
|
898
|
+
// Large inline array in function
|
|
899
|
+
let processingPipeline = [
|
|
900
|
+
"data_validation",
|
|
901
|
+
"schema_verification",
|
|
902
|
+
"data_cleaning",
|
|
903
|
+
"duplicate_removal",
|
|
904
|
+
"format_standardization",
|
|
905
|
+
"type_conversion",
|
|
906
|
+
"null_handling",
|
|
907
|
+
"validation_rules",
|
|
908
|
+
"business_logic",
|
|
909
|
+
"transformation_rules",
|
|
910
|
+
"aggregation_logic",
|
|
911
|
+
"sorting_criteria",
|
|
912
|
+
"filtering_conditions",
|
|
913
|
+
"output_formatting",
|
|
914
|
+
"result_validation"
|
|
915
|
+
]
|
|
916
|
+
|
|
917
|
+
return processingPipeline.compactMap { step in
|
|
918
|
+
return "processed_\(step)"
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// Function with dictionary containing Swift keywords
|
|
923
|
+
func getSwiftKeywords() -> [String: String] {
|
|
924
|
+
return [
|
|
925
|
+
"async": "Asynchronous function modifier",
|
|
926
|
+
"await": "Suspend execution until async call completes",
|
|
927
|
+
"actor": "Reference type for concurrent programming",
|
|
928
|
+
"guard": "Early exit statement with condition",
|
|
929
|
+
"defer": "Execute code when leaving current scope",
|
|
930
|
+
"throws": "Function can throw errors",
|
|
931
|
+
"rethrows": "Function rethrows callers errors",
|
|
932
|
+
"inout": "Parameter passed by reference",
|
|
933
|
+
"weak": "Weak reference to avoid retain cycles",
|
|
934
|
+
"unowned": "Unowned reference (unsafe)",
|
|
935
|
+
"lazy": "Property initialized on first access",
|
|
936
|
+
"mutating": "Method can modify struct properties",
|
|
937
|
+
"nonmutating": "Explicitly non-mutating method",
|
|
938
|
+
"override": "Override superclass method",
|
|
939
|
+
"final": "Prevent inheritance/overriding",
|
|
940
|
+
"required": "Required initializer",
|
|
941
|
+
"convenience": "Convenience initializer",
|
|
942
|
+
"subscript": "Custom subscript access"
|
|
943
|
+
]
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
"#;
|
|
947
|
+
|
|
948
|
+
fs::write(&test_file, content)?;
|
|
949
|
+
|
|
950
|
+
let ctx = TestContext::new();
|
|
951
|
+
let output = ctx.run_probe(&[
|
|
952
|
+
"search",
|
|
953
|
+
"array", // Search for arrays/collections
|
|
954
|
+
test_file.to_str().unwrap(),
|
|
955
|
+
"--format",
|
|
956
|
+
"outline",
|
|
957
|
+
])?;
|
|
958
|
+
|
|
959
|
+
// Should find the large arrays and dictionaries
|
|
960
|
+
assert!(
|
|
961
|
+
output.contains("supportedLanguages")
|
|
962
|
+
|| output.contains("configurationSettings")
|
|
963
|
+
|| output.contains("processLargeDataSet"),
|
|
964
|
+
"Missing large arrays/dictionaries - output: {}",
|
|
965
|
+
output
|
|
966
|
+
);
|
|
967
|
+
|
|
968
|
+
// Should have array/dictionary truncation markers
|
|
969
|
+
let has_truncation = output.contains("...")
|
|
970
|
+
|| output.contains("/* truncated */")
|
|
971
|
+
|| output.contains("// truncated");
|
|
972
|
+
assert!(
|
|
973
|
+
has_truncation,
|
|
974
|
+
"Large arrays/dictionaries should show truncation markers - output: {}",
|
|
975
|
+
output
|
|
976
|
+
);
|
|
977
|
+
|
|
978
|
+
// Should preserve important keywords even in truncated content
|
|
979
|
+
let important_keywords = [
|
|
980
|
+
"async", "await", "guard", "defer", "throws", "actor", "database", "api_key",
|
|
981
|
+
];
|
|
982
|
+
let preserved_keywords: Vec<&str> = important_keywords
|
|
983
|
+
.iter()
|
|
984
|
+
.filter(|&keyword| output.contains(keyword))
|
|
985
|
+
.copied()
|
|
986
|
+
.collect();
|
|
987
|
+
|
|
988
|
+
assert!(
|
|
989
|
+
!preserved_keywords.is_empty(),
|
|
990
|
+
"Should preserve important keywords in truncated arrays/dicts. Found: {:?} - output: {}",
|
|
991
|
+
preserved_keywords,
|
|
992
|
+
output
|
|
993
|
+
);
|
|
994
|
+
|
|
995
|
+
// Should be in outline format
|
|
996
|
+
assert!(
|
|
997
|
+
output.contains("---\nFile:"),
|
|
998
|
+
"Missing file delimiter in outline format - output: {}",
|
|
999
|
+
output
|
|
1000
|
+
);
|
|
1001
|
+
|
|
1002
|
+
Ok(())
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
#[test]
|
|
1006
|
+
fn test_swift_outline_specific_constructs() -> Result<()> {
|
|
1007
|
+
let temp_dir = TempDir::new()?;
|
|
1008
|
+
let test_file = temp_dir.path().join("SwiftConstructs.swift");
|
|
1009
|
+
|
|
1010
|
+
let content = r#"import Foundation
|
|
1011
|
+
import SwiftUI
|
|
1012
|
+
|
|
1013
|
+
// MARK: - Protocols with Associated Types and Generic Constraints
|
|
1014
|
+
|
|
1015
|
+
protocol DataTransformable {
|
|
1016
|
+
associatedtype InputType
|
|
1017
|
+
associatedtype OutputType: Codable
|
|
1018
|
+
|
|
1019
|
+
func transform(_ input: InputType) throws -> OutputType
|
|
1020
|
+
var transformationId: String { get }
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
protocol Repository {
|
|
1024
|
+
associatedtype Entity: Identifiable
|
|
1025
|
+
associatedtype ID where ID == Entity.ID
|
|
1026
|
+
|
|
1027
|
+
func find(by id: ID) async throws -> Entity?
|
|
1028
|
+
func save(_ entity: Entity) async throws
|
|
1029
|
+
func delete(by id: ID) async throws
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// MARK: - Generic Classes with Inheritance and Constraints
|
|
1033
|
+
|
|
1034
|
+
class BaseDataProcessor<T: Hashable>: NSObject {
|
|
1035
|
+
private let processingQueue: DispatchQueue
|
|
1036
|
+
private var cache: [T: ProcessingResult] = [:]
|
|
1037
|
+
|
|
1038
|
+
override init() {
|
|
1039
|
+
self.processingQueue = DispatchQueue(label: "processing.queue", qos: .background)
|
|
1040
|
+
super.init()
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
func process(_ data: T) -> ProcessingResult {
|
|
1044
|
+
if let cached = cache[data] {
|
|
1045
|
+
return cached
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
let result = ProcessingResult(data: data, timestamp: Date())
|
|
1049
|
+
cache[data] = result
|
|
1050
|
+
return result
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
final class NetworkDataProcessor<T: Codable & Hashable>: BaseDataProcessor<T>, DataTransformable {
|
|
1055
|
+
typealias InputType = T
|
|
1056
|
+
typealias OutputType = NetworkResponse<T>
|
|
1057
|
+
|
|
1058
|
+
let transformationId = "network-processor"
|
|
1059
|
+
private let session: URLSession
|
|
1060
|
+
|
|
1061
|
+
override init() {
|
|
1062
|
+
self.session = URLSession.shared
|
|
1063
|
+
super.init()
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
func transform(_ input: T) throws -> OutputType {
|
|
1067
|
+
// Complex transformation logic here
|
|
1068
|
+
let jsonData = try JSONEncoder().encode(input)
|
|
1069
|
+
return NetworkResponse(data: input, rawData: jsonData)
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
// MARK: - Structs with Property Wrappers and Computed Properties
|
|
1074
|
+
|
|
1075
|
+
struct UserProfile: Codable, Identifiable {
|
|
1076
|
+
let id: UUID
|
|
1077
|
+
@Published var name: String
|
|
1078
|
+
@Published var email: String
|
|
1079
|
+
@UserDefault(key: "user_preferences", defaultValue: UserPreferences())
|
|
1080
|
+
var preferences: UserPreferences
|
|
1081
|
+
|
|
1082
|
+
private let createdAt: Date
|
|
1083
|
+
private var lastUpdated: Date = Date()
|
|
1084
|
+
|
|
1085
|
+
var displayName: String {
|
|
1086
|
+
return name.isEmpty ? "Anonymous User" : name
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
var isValid: Bool {
|
|
1090
|
+
return !name.isEmpty && email.contains("@")
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
init(name: String, email: String) {
|
|
1094
|
+
self.id = UUID()
|
|
1095
|
+
self.name = name
|
|
1096
|
+
self.email = email
|
|
1097
|
+
self.createdAt = Date()
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
mutating func updateProfile(name: String? = nil, email: String? = nil) {
|
|
1101
|
+
if let newName = name {
|
|
1102
|
+
self.name = newName
|
|
1103
|
+
}
|
|
1104
|
+
if let newEmail = email {
|
|
1105
|
+
self.email = newEmail
|
|
1106
|
+
}
|
|
1107
|
+
self.lastUpdated = Date()
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// MARK: - Enums with Associated Values and Methods
|
|
1112
|
+
|
|
1113
|
+
enum APIResponse<T: Codable> {
|
|
1114
|
+
case success(data: T, metadata: ResponseMetadata)
|
|
1115
|
+
case failure(error: APIError, retryAfter: TimeInterval?)
|
|
1116
|
+
case loading(progress: Double)
|
|
1117
|
+
case cached(data: T, cacheTimestamp: Date)
|
|
1118
|
+
|
|
1119
|
+
var isSuccessful: Bool {
|
|
1120
|
+
switch self {
|
|
1121
|
+
case .success, .cached:
|
|
1122
|
+
return true
|
|
1123
|
+
case .failure, .loading:
|
|
1124
|
+
return false
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
func map<U: Codable>(_ transform: (T) -> U) -> APIResponse<U> {
|
|
1129
|
+
switch self {
|
|
1130
|
+
case .success(let data, let metadata):
|
|
1131
|
+
return .success(data: transform(data), metadata: metadata)
|
|
1132
|
+
case .cached(let data, let timestamp):
|
|
1133
|
+
return .cached(data: transform(data), cacheTimestamp: timestamp)
|
|
1134
|
+
case .failure(let error, let retryAfter):
|
|
1135
|
+
return .failure(error: error, retryAfter: retryAfter)
|
|
1136
|
+
case .loading(let progress):
|
|
1137
|
+
return .loading(progress: progress)
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
enum APIError: Error, LocalizedError, CaseIterable {
|
|
1143
|
+
case networkUnavailable
|
|
1144
|
+
case invalidCredentials
|
|
1145
|
+
case serverError(code: Int)
|
|
1146
|
+
case dataCorrupted(description: String)
|
|
1147
|
+
case rateLimitExceeded(resetTime: Date)
|
|
1148
|
+
|
|
1149
|
+
var errorDescription: String? {
|
|
1150
|
+
switch self {
|
|
1151
|
+
case .networkUnavailable:
|
|
1152
|
+
return "Network connection is unavailable"
|
|
1153
|
+
case .invalidCredentials:
|
|
1154
|
+
return "Invalid authentication credentials"
|
|
1155
|
+
case .serverError(let code):
|
|
1156
|
+
return "Server error with code: \(code)"
|
|
1157
|
+
case .dataCorrupted(let description):
|
|
1158
|
+
return "Data corruption: \(description)"
|
|
1159
|
+
case .rateLimitExceeded(let resetTime):
|
|
1160
|
+
return "Rate limit exceeded. Try again after \(resetTime)"
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// MARK: - Extensions with Conditional Conformance
|
|
1166
|
+
|
|
1167
|
+
extension Array where Element: Numeric {
|
|
1168
|
+
func sum() -> Element {
|
|
1169
|
+
return reduce(0, +)
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
func average() -> Double where Element: BinaryInteger {
|
|
1173
|
+
guard !isEmpty else { return 0 }
|
|
1174
|
+
let total = sum()
|
|
1175
|
+
return Double(total) / Double(count)
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
extension Dictionary where Key == String, Value: Codable {
|
|
1180
|
+
func toJSON() throws -> Data {
|
|
1181
|
+
return try JSONSerialization.data(withJSONObject: self)
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
static func fromJSON(_ data: Data) throws -> [String: Value] {
|
|
1185
|
+
let decoded = try JSONSerialization.jsonObject(with: data) as? [String: Any] ?? [:]
|
|
1186
|
+
// Complex conversion logic would go here
|
|
1187
|
+
return [:] // Simplified for testing
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
extension APIResponse: Equatable where T: Equatable {
|
|
1192
|
+
static func == (lhs: APIResponse<T>, rhs: APIResponse<T>) -> Bool {
|
|
1193
|
+
switch (lhs, rhs) {
|
|
1194
|
+
case (.success(let lData, _), .success(let rData, _)):
|
|
1195
|
+
return lData == rData
|
|
1196
|
+
case (.cached(let lData, _), .cached(let rData, _)):
|
|
1197
|
+
return lData == rData
|
|
1198
|
+
case (.loading(let lProgress), .loading(let rProgress)):
|
|
1199
|
+
return lProgress == rProgress
|
|
1200
|
+
case (.failure(_, _), .failure(_, _)):
|
|
1201
|
+
return true
|
|
1202
|
+
default:
|
|
1203
|
+
return false
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
// MARK: - Property Wrappers
|
|
1209
|
+
|
|
1210
|
+
@propertyWrapper
|
|
1211
|
+
struct UserDefault<T: Codable> {
|
|
1212
|
+
let key: String
|
|
1213
|
+
let defaultValue: T
|
|
1214
|
+
|
|
1215
|
+
var wrappedValue: T {
|
|
1216
|
+
get {
|
|
1217
|
+
guard let data = UserDefaults.standard.data(forKey: key) else {
|
|
1218
|
+
return defaultValue
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
do {
|
|
1222
|
+
return try JSONDecoder().decode(T.self, from: data)
|
|
1223
|
+
} catch {
|
|
1224
|
+
return defaultValue
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
set {
|
|
1228
|
+
do {
|
|
1229
|
+
let data = try JSONEncoder().encode(newValue)
|
|
1230
|
+
UserDefaults.standard.set(data, forKey: key)
|
|
1231
|
+
} catch {
|
|
1232
|
+
print("Failed to encode value for key \(key): \(error)")
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
@propertyWrapper
|
|
1239
|
+
struct Clamped<T: Comparable> {
|
|
1240
|
+
private var value: T
|
|
1241
|
+
private let range: ClosedRange<T>
|
|
1242
|
+
|
|
1243
|
+
var wrappedValue: T {
|
|
1244
|
+
get { return value }
|
|
1245
|
+
set { value = min(max(range.lowerBound, newValue), range.upperBound) }
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
init(wrappedValue: T, _ range: ClosedRange<T>) {
|
|
1249
|
+
self.range = range
|
|
1250
|
+
self.value = min(max(range.lowerBound, wrappedValue), range.upperBound)
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// MARK: - Nested Types and Namespacing
|
|
1255
|
+
|
|
1256
|
+
struct NetworkManager {
|
|
1257
|
+
enum RequestMethod: String, CaseIterable {
|
|
1258
|
+
case get = "GET"
|
|
1259
|
+
case post = "POST"
|
|
1260
|
+
case put = "PUT"
|
|
1261
|
+
case delete = "DELETE"
|
|
1262
|
+
case patch = "PATCH"
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
struct Configuration {
|
|
1266
|
+
let baseURL: URL
|
|
1267
|
+
let timeout: TimeInterval
|
|
1268
|
+
let headers: [String: String]
|
|
1269
|
+
|
|
1270
|
+
static let development = Configuration(
|
|
1271
|
+
baseURL: URL(string: "https://dev.api.example.com")!,
|
|
1272
|
+
timeout: 30,
|
|
1273
|
+
headers: ["Content-Type": "application/json"]
|
|
1274
|
+
)
|
|
1275
|
+
|
|
1276
|
+
static let production = Configuration(
|
|
1277
|
+
baseURL: URL(string: "https://api.example.com")!,
|
|
1278
|
+
timeout: 60,
|
|
1279
|
+
headers: ["Content-Type": "application/json"]
|
|
1280
|
+
)
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
class RequestBuilder {
|
|
1284
|
+
private var method: RequestMethod = .get
|
|
1285
|
+
private var path: String = ""
|
|
1286
|
+
private var queryItems: [URLQueryItem] = []
|
|
1287
|
+
private var body: Data?
|
|
1288
|
+
|
|
1289
|
+
func method(_ method: RequestMethod) -> Self {
|
|
1290
|
+
self.method = method
|
|
1291
|
+
return self
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
func path(_ path: String) -> Self {
|
|
1295
|
+
self.path = path
|
|
1296
|
+
return self
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
func query(_ name: String, value: String) -> Self {
|
|
1300
|
+
queryItems.append(URLQueryItem(name: name, value: value))
|
|
1301
|
+
return self
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
func body(_ data: Data) -> Self {
|
|
1305
|
+
self.body = data
|
|
1306
|
+
return self
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
func build(config: Configuration) throws -> URLRequest {
|
|
1310
|
+
guard var components = URLComponents(url: config.baseURL, resolvingAgainstBaseURL: true) else {
|
|
1311
|
+
throw APIError.serverError(code: 0)
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
components.path = path
|
|
1315
|
+
components.queryItems = queryItems.isEmpty ? nil : queryItems
|
|
1316
|
+
|
|
1317
|
+
guard let url = components.url else {
|
|
1318
|
+
throw APIError.serverError(code: 0)
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
var request = URLRequest(url: url)
|
|
1322
|
+
request.httpMethod = method.rawValue
|
|
1323
|
+
request.timeoutInterval = config.timeout
|
|
1324
|
+
request.httpBody = body
|
|
1325
|
+
|
|
1326
|
+
for (key, value) in config.headers {
|
|
1327
|
+
request.setValue(value, forHTTPHeaderField: key)
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
return request
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
"#;
|
|
1335
|
+
|
|
1336
|
+
fs::write(&test_file, content)?;
|
|
1337
|
+
|
|
1338
|
+
let ctx = TestContext::new();
|
|
1339
|
+
let output = ctx.run_probe(&[
|
|
1340
|
+
"search",
|
|
1341
|
+
"protocol", // Search for protocols
|
|
1342
|
+
test_file.to_str().unwrap(),
|
|
1343
|
+
"--format",
|
|
1344
|
+
"outline",
|
|
1345
|
+
])?;
|
|
1346
|
+
|
|
1347
|
+
// Should find Swift-specific constructs
|
|
1348
|
+
let swift_constructs = [
|
|
1349
|
+
"protocol",
|
|
1350
|
+
"class",
|
|
1351
|
+
"struct",
|
|
1352
|
+
"enum",
|
|
1353
|
+
"extension",
|
|
1354
|
+
"@propertyWrapper",
|
|
1355
|
+
];
|
|
1356
|
+
let found_constructs: Vec<&str> = swift_constructs
|
|
1357
|
+
.iter()
|
|
1358
|
+
.filter(|&construct| output.contains(construct))
|
|
1359
|
+
.copied()
|
|
1360
|
+
.collect();
|
|
1361
|
+
|
|
1362
|
+
assert!(
|
|
1363
|
+
!found_constructs.is_empty(),
|
|
1364
|
+
"Should find Swift-specific constructs. Found: {:?} - output: {}",
|
|
1365
|
+
found_constructs,
|
|
1366
|
+
output
|
|
1367
|
+
);
|
|
1368
|
+
|
|
1369
|
+
// Should find specific Swift constructs
|
|
1370
|
+
assert!(
|
|
1371
|
+
output.contains("DataTransformable") || output.contains("Repository"),
|
|
1372
|
+
"Should find protocol definitions - output: {}",
|
|
1373
|
+
output
|
|
1374
|
+
);
|
|
1375
|
+
|
|
1376
|
+
assert!(
|
|
1377
|
+
output.contains("BaseDataProcessor") || output.contains("NetworkDataProcessor"),
|
|
1378
|
+
"Should find class definitions - output: {}",
|
|
1379
|
+
output
|
|
1380
|
+
);
|
|
1381
|
+
|
|
1382
|
+
assert!(
|
|
1383
|
+
output.contains("UserProfile") || output.contains("NetworkManager"),
|
|
1384
|
+
"Should find struct definitions - output: {}",
|
|
1385
|
+
output
|
|
1386
|
+
);
|
|
1387
|
+
|
|
1388
|
+
assert!(
|
|
1389
|
+
output.contains("APIResponse") || output.contains("APIError"),
|
|
1390
|
+
"Should find enum definitions - output: {}",
|
|
1391
|
+
output
|
|
1392
|
+
);
|
|
1393
|
+
|
|
1394
|
+
// Should be in outline format
|
|
1395
|
+
assert!(
|
|
1396
|
+
output.contains("---\nFile:"),
|
|
1397
|
+
"Missing file delimiter in outline format - output: {}",
|
|
1398
|
+
output
|
|
1399
|
+
);
|
|
1400
|
+
|
|
1401
|
+
Ok(())
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
#[test]
|
|
1405
|
+
fn test_swift_outline_control_flow_statements() -> Result<()> {
|
|
1406
|
+
let temp_dir = TempDir::new()?;
|
|
1407
|
+
let test_file = temp_dir.path().join("ControlFlow.swift");
|
|
1408
|
+
|
|
1409
|
+
let content = r#"import Foundation
|
|
1410
|
+
|
|
1411
|
+
struct DataValidator {
|
|
1412
|
+
enum ValidationError: Error {
|
|
1413
|
+
case invalidInput
|
|
1414
|
+
case processingFailed
|
|
1415
|
+
case timeout
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
// Function with comprehensive control flow patterns
|
|
1419
|
+
func validateAndProcessData(_ input: [Any]) async throws -> [String] {
|
|
1420
|
+
var results: [String] = []
|
|
1421
|
+
|
|
1422
|
+
// Guard statement for early exit
|
|
1423
|
+
guard !input.isEmpty else {
|
|
1424
|
+
throw ValidationError.invalidInput
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
// Defer statement for cleanup
|
|
1428
|
+
defer {
|
|
1429
|
+
print("Cleaning up validation resources")
|
|
1430
|
+
cleanup()
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
// For loop with enumerated values
|
|
1434
|
+
for (index, item) in input.enumerated() {
|
|
1435
|
+
// Nested if-else statements
|
|
1436
|
+
if let stringItem = item as? String {
|
|
1437
|
+
if stringItem.count > 100 {
|
|
1438
|
+
results.append("LONG_STRING[\(index)]: \(stringItem.prefix(50))...")
|
|
1439
|
+
} else if stringItem.isEmpty {
|
|
1440
|
+
results.append("EMPTY_STRING[\(index)]")
|
|
1441
|
+
} else {
|
|
1442
|
+
results.append("STRING[\(index)]: \(stringItem)")
|
|
1443
|
+
}
|
|
1444
|
+
} else if let numberItem = item as? NSNumber {
|
|
1445
|
+
let value = numberItem.doubleValue
|
|
1446
|
+
if value > 1000 {
|
|
1447
|
+
results.append("LARGE_NUMBER[\(index)]: \(value)")
|
|
1448
|
+
} else if value < 0 {
|
|
1449
|
+
results.append("NEGATIVE_NUMBER[\(index)]: \(value)")
|
|
1450
|
+
} else {
|
|
1451
|
+
results.append("NUMBER[\(index)]: \(value)")
|
|
1452
|
+
}
|
|
1453
|
+
} else if let arrayItem = item as? [Any] {
|
|
1454
|
+
// Recursive processing with do-catch
|
|
1455
|
+
do {
|
|
1456
|
+
let nestedResults = try await validateAndProcessData(arrayItem)
|
|
1457
|
+
results.append("NESTED_ARRAY[\(index)]: [\(nestedResults.joined(separator: ", "))]")
|
|
1458
|
+
} catch {
|
|
1459
|
+
results.append("NESTED_ARRAY_ERROR[\(index)]: \(error.localizedDescription)")
|
|
1460
|
+
}
|
|
1461
|
+
} else {
|
|
1462
|
+
results.append("UNKNOWN_TYPE[\(index)]: \(type(of: item))")
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
// While loop with complex condition
|
|
1467
|
+
var retryCount = 0
|
|
1468
|
+
while retryCount < 3 && !results.isEmpty {
|
|
1469
|
+
let success = await performValidation(results)
|
|
1470
|
+
if success {
|
|
1471
|
+
break
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
retryCount += 1
|
|
1475
|
+
|
|
1476
|
+
// Nested switch statement
|
|
1477
|
+
switch retryCount {
|
|
1478
|
+
case 1:
|
|
1479
|
+
await Task.sleep(nanoseconds: 1_000_000_000) // 1 second
|
|
1480
|
+
case 2:
|
|
1481
|
+
await Task.sleep(nanoseconds: 2_000_000_000) // 2 seconds
|
|
1482
|
+
case 3:
|
|
1483
|
+
throw ValidationError.timeout
|
|
1484
|
+
default:
|
|
1485
|
+
break
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
// Switch statement with associated values and where clauses
|
|
1490
|
+
for result in results {
|
|
1491
|
+
switch result {
|
|
1492
|
+
case let str where str.hasPrefix("LONG_STRING"):
|
|
1493
|
+
print("Processing long string: \(str)")
|
|
1494
|
+
case let str where str.contains("ERROR"):
|
|
1495
|
+
print("Error found: \(str)")
|
|
1496
|
+
case let str where str.hasPrefix("NUMBER"):
|
|
1497
|
+
print("Number processing: \(str)")
|
|
1498
|
+
default:
|
|
1499
|
+
print("Standard processing: \(result)")
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
return results
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
// Function demonstrating repeat-while loop
|
|
1507
|
+
func processUntilComplete(_ data: inout [String]) {
|
|
1508
|
+
repeat {
|
|
1509
|
+
// Complex nested control flow
|
|
1510
|
+
for (index, item) in data.enumerated() {
|
|
1511
|
+
if item.isEmpty {
|
|
1512
|
+
data.remove(at: index)
|
|
1513
|
+
continue
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
// Nested switch with fallthrough
|
|
1517
|
+
switch item.first {
|
|
1518
|
+
case "A":
|
|
1519
|
+
data[index] = "PROCESSED_A_" + item
|
|
1520
|
+
case "B":
|
|
1521
|
+
data[index] = "PROCESSED_B_" + item
|
|
1522
|
+
case "C":
|
|
1523
|
+
data[index] = "PROCESSED_C_" + item
|
|
1524
|
+
fallthrough
|
|
1525
|
+
case "D":
|
|
1526
|
+
data[index] += "_SPECIAL"
|
|
1527
|
+
default:
|
|
1528
|
+
data[index] = "DEFAULT_" + item
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
} while data.contains { $0.hasPrefix("UNPROCESSED") }
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
// Function with complex guard statements and early returns
|
|
1535
|
+
func complexGuardValidation(_ input: Any?) -> String? {
|
|
1536
|
+
guard let input = input else {
|
|
1537
|
+
return nil
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
guard let stringInput = input as? String else {
|
|
1541
|
+
return "NOT_STRING"
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
guard !stringInput.isEmpty else {
|
|
1545
|
+
return "EMPTY"
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
guard stringInput.count >= 5 else {
|
|
1549
|
+
return "TOO_SHORT"
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
guard stringInput.count <= 100 else {
|
|
1553
|
+
return "TOO_LONG"
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
// Nested if with multiple conditions
|
|
1557
|
+
if stringInput.hasPrefix("SPECIAL_") && stringInput.hasSuffix("_END") {
|
|
1558
|
+
if stringInput.contains("IMPORTANT") {
|
|
1559
|
+
return "SPECIAL_IMPORTANT"
|
|
1560
|
+
} else if stringInput.contains("URGENT") {
|
|
1561
|
+
return "SPECIAL_URGENT"
|
|
1562
|
+
} else {
|
|
1563
|
+
return "SPECIAL_NORMAL"
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
return "VALID"
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
// Function with do-catch blocks and error handling
|
|
1571
|
+
func processWithErrorHandling(_ items: [String]) throws -> [String] {
|
|
1572
|
+
var processedItems: [String] = []
|
|
1573
|
+
|
|
1574
|
+
for item in items {
|
|
1575
|
+
do {
|
|
1576
|
+
// First processing step
|
|
1577
|
+
let step1 = try validateItem(item)
|
|
1578
|
+
|
|
1579
|
+
do {
|
|
1580
|
+
// Nested processing with different error handling
|
|
1581
|
+
let step2 = try transformItem(step1)
|
|
1582
|
+
processedItems.append(step2)
|
|
1583
|
+
} catch ValidationError.processingFailed {
|
|
1584
|
+
// Handle specific error type
|
|
1585
|
+
processedItems.append("PROCESSING_FAILED: \(item)")
|
|
1586
|
+
} catch {
|
|
1587
|
+
// Handle other errors
|
|
1588
|
+
processedItems.append("UNKNOWN_ERROR: \(item) - \(error)")
|
|
1589
|
+
}
|
|
1590
|
+
} catch ValidationError.invalidInput {
|
|
1591
|
+
// Skip invalid inputs
|
|
1592
|
+
continue
|
|
1593
|
+
} catch ValidationError.timeout {
|
|
1594
|
+
// Propagate timeout errors
|
|
1595
|
+
throw ValidationError.timeout
|
|
1596
|
+
} catch {
|
|
1597
|
+
// Log and continue with other errors
|
|
1598
|
+
print("Unexpected error processing \(item): \(error)")
|
|
1599
|
+
processedItems.append("ERROR: \(item)")
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
return processedItems
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
// Private helper functions
|
|
1607
|
+
private func cleanup() {
|
|
1608
|
+
print("Performing cleanup")
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
private func performValidation(_ results: [String]) async -> Bool {
|
|
1612
|
+
// Simulate async validation
|
|
1613
|
+
await Task.sleep(nanoseconds: 100_000_000) // 0.1 second
|
|
1614
|
+
return !results.isEmpty
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
private func validateItem(_ item: String) throws -> String {
|
|
1618
|
+
if item.isEmpty {
|
|
1619
|
+
throw ValidationError.invalidInput
|
|
1620
|
+
}
|
|
1621
|
+
return "VALIDATED_\(item)"
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
private func transformItem(_ item: String) throws -> String {
|
|
1625
|
+
if item.contains("FAIL") {
|
|
1626
|
+
throw ValidationError.processingFailed
|
|
1627
|
+
}
|
|
1628
|
+
return "TRANSFORMED_\(item)"
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
// Extension with additional control flow patterns
|
|
1633
|
+
extension DataValidator {
|
|
1634
|
+
func processWithComplexSwitchStatement(_ value: Any) -> String {
|
|
1635
|
+
switch value {
|
|
1636
|
+
case let str as String where str.count > 10:
|
|
1637
|
+
return "LONG_STRING: \(str.prefix(10))..."
|
|
1638
|
+
|
|
1639
|
+
case let str as String where str.isEmpty:
|
|
1640
|
+
return "EMPTY_STRING"
|
|
1641
|
+
|
|
1642
|
+
case let str as String:
|
|
1643
|
+
return "STRING: \(str)"
|
|
1644
|
+
|
|
1645
|
+
case let num as Int where num > 100:
|
|
1646
|
+
return "LARGE_INT: \(num)"
|
|
1647
|
+
|
|
1648
|
+
case let num as Int where num < 0:
|
|
1649
|
+
return "NEGATIVE_INT: \(num)"
|
|
1650
|
+
|
|
1651
|
+
case let num as Int:
|
|
1652
|
+
return "INT: \(num)"
|
|
1653
|
+
|
|
1654
|
+
case let array as [Any] where array.count > 5:
|
|
1655
|
+
return "LARGE_ARRAY: \(array.count) items"
|
|
1656
|
+
|
|
1657
|
+
case let array as [Any]:
|
|
1658
|
+
return "ARRAY: \(array.count) items"
|
|
1659
|
+
|
|
1660
|
+
case Optional<Any>.none:
|
|
1661
|
+
return "NIL_VALUE"
|
|
1662
|
+
|
|
1663
|
+
case Optional<Any>.some(let unwrapped):
|
|
1664
|
+
return "OPTIONAL: \(processWithComplexSwitchStatement(unwrapped))"
|
|
1665
|
+
|
|
1666
|
+
default:
|
|
1667
|
+
return "UNKNOWN_TYPE: \(type(of: value))"
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
"#;
|
|
1672
|
+
|
|
1673
|
+
fs::write(&test_file, content)?;
|
|
1674
|
+
|
|
1675
|
+
let ctx = TestContext::new();
|
|
1676
|
+
let output = ctx.run_probe(&[
|
|
1677
|
+
"search",
|
|
1678
|
+
"guard", // Search for guard statements
|
|
1679
|
+
test_file.to_str().unwrap(),
|
|
1680
|
+
"--format",
|
|
1681
|
+
"outline",
|
|
1682
|
+
])?;
|
|
1683
|
+
|
|
1684
|
+
// Should find Swift control flow statements
|
|
1685
|
+
let control_flow_keywords = [
|
|
1686
|
+
"guard", "defer", "if", "while", "for", "switch", "do", "catch", "repeat",
|
|
1687
|
+
];
|
|
1688
|
+
let found_keywords: Vec<&str> = control_flow_keywords
|
|
1689
|
+
.iter()
|
|
1690
|
+
.filter(|&keyword| output.contains(keyword))
|
|
1691
|
+
.copied()
|
|
1692
|
+
.collect();
|
|
1693
|
+
|
|
1694
|
+
assert!(
|
|
1695
|
+
!found_keywords.is_empty(),
|
|
1696
|
+
"Should find Swift control flow keywords. Found: {:?} - output: {}",
|
|
1697
|
+
found_keywords,
|
|
1698
|
+
output
|
|
1699
|
+
);
|
|
1700
|
+
|
|
1701
|
+
// Should find guard statements specifically
|
|
1702
|
+
assert!(
|
|
1703
|
+
output.contains("guard"),
|
|
1704
|
+
"Should find guard statements - output: {}",
|
|
1705
|
+
output
|
|
1706
|
+
);
|
|
1707
|
+
|
|
1708
|
+
// Should find nested control structures
|
|
1709
|
+
let nested_patterns = ["nested", "if", "switch", "case", "while"];
|
|
1710
|
+
let found_nested: Vec<&str> = nested_patterns
|
|
1711
|
+
.iter()
|
|
1712
|
+
.filter(|&pattern| output.contains(pattern))
|
|
1713
|
+
.copied()
|
|
1714
|
+
.collect();
|
|
1715
|
+
|
|
1716
|
+
assert!(
|
|
1717
|
+
found_nested.len() >= 2,
|
|
1718
|
+
"Should find nested control flow patterns. Found: {:?} - output: {}",
|
|
1719
|
+
found_nested,
|
|
1720
|
+
output
|
|
1721
|
+
);
|
|
1722
|
+
|
|
1723
|
+
// Should show closing braces for large control blocks
|
|
1724
|
+
let has_closing_braces = output.contains("} //") || output.contains("} /*");
|
|
1725
|
+
assert!(
|
|
1726
|
+
has_closing_braces,
|
|
1727
|
+
"Large control flow blocks should have closing brace comments - output: {}",
|
|
1728
|
+
output
|
|
1729
|
+
);
|
|
1730
|
+
|
|
1731
|
+
// Should be in outline format
|
|
1732
|
+
assert!(
|
|
1733
|
+
output.contains("---\nFile:"),
|
|
1734
|
+
"Missing file delimiter in outline format - output: {}",
|
|
1735
|
+
output
|
|
1736
|
+
);
|
|
1737
|
+
|
|
1738
|
+
Ok(())
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
#[test]
|
|
1742
|
+
fn test_swift_outline_test_detection_patterns() -> Result<()> {
|
|
1743
|
+
let temp_dir = TempDir::new()?;
|
|
1744
|
+
let test_file = temp_dir.path().join("SwiftTests.swift");
|
|
1745
|
+
|
|
1746
|
+
let content = r#"import XCTest
|
|
1747
|
+
@testable import MyApp
|
|
1748
|
+
import Foundation
|
|
1749
|
+
|
|
1750
|
+
// MARK: - XCTest Framework Tests
|
|
1751
|
+
|
|
1752
|
+
class CalculatorTests: XCTestCase {
|
|
1753
|
+
var calculator: Calculator!
|
|
1754
|
+
|
|
1755
|
+
override func setUpWithError() throws {
|
|
1756
|
+
calculator = Calculator()
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
override func tearDownWithError() throws {
|
|
1760
|
+
calculator = nil
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
func testAddition() {
|
|
1764
|
+
let result = calculator.add(2, 3)
|
|
1765
|
+
XCTAssertEqual(result, 5, "Addition should work correctly")
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
func testSubtraction() throws {
|
|
1769
|
+
let result = calculator.subtract(5, 3)
|
|
1770
|
+
XCTAssertEqual(result, 2)
|
|
1771
|
+
|
|
1772
|
+
// Test with negative result
|
|
1773
|
+
let negativeResult = calculator.subtract(3, 5)
|
|
1774
|
+
XCTAssertEqual(negativeResult, -2)
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
func testMultiplication() {
|
|
1778
|
+
XCTAssertEqual(calculator.multiply(4, 5), 20)
|
|
1779
|
+
XCTAssertEqual(calculator.multiply(-2, 3), -6)
|
|
1780
|
+
XCTAssertEqual(calculator.multiply(0, 100), 0)
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
func testDivision() throws {
|
|
1784
|
+
let result = try calculator.divide(10, 2)
|
|
1785
|
+
XCTAssertEqual(result, 5.0, accuracy: 0.001)
|
|
1786
|
+
|
|
1787
|
+
// Test division by zero throws error
|
|
1788
|
+
XCTAssertThrowsError(try calculator.divide(10, 0)) { error in
|
|
1789
|
+
XCTAssertTrue(error is CalculatorError)
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
func testPerformance() {
|
|
1794
|
+
measure {
|
|
1795
|
+
for i in 0..<1000 {
|
|
1796
|
+
_ = calculator.add(Double(i), Double(i + 1))
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
func testAsyncOperation() async throws {
|
|
1802
|
+
let result = try await calculator.asyncCalculation(5, 10)
|
|
1803
|
+
XCTAssertEqual(result, 15)
|
|
1804
|
+
|
|
1805
|
+
await XCTAssertThrowsErrorAsync(try await calculator.asyncCalculation(0, 0))
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
func testExpectation() {
|
|
1809
|
+
let expectation = expectation(description: "Async calculation completed")
|
|
1810
|
+
|
|
1811
|
+
calculator.performAsyncCalculation { result in
|
|
1812
|
+
XCTAssertNotNil(result)
|
|
1813
|
+
expectation.fulfill()
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
waitForExpectations(timeout: 5.0)
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// MARK: - Performance Tests
|
|
1821
|
+
|
|
1822
|
+
class PerformanceTests: XCTestCase {
|
|
1823
|
+
|
|
1824
|
+
func testCalculatorPerformance() {
|
|
1825
|
+
let calculator = Calculator()
|
|
1826
|
+
|
|
1827
|
+
measure {
|
|
1828
|
+
for _ in 0..<10000 {
|
|
1829
|
+
_ = calculator.add(1.0, 2.0)
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
func testMemoryUsage() {
|
|
1835
|
+
measureMetrics([.wallClockTime, .peakMemoryUsage]) {
|
|
1836
|
+
let largeArray = Array(0..<100000)
|
|
1837
|
+
_ = largeArray.map { $0 * 2 }
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
// MARK: - UI Tests
|
|
1843
|
+
|
|
1844
|
+
class AppUITests: XCTestCase {
|
|
1845
|
+
let app = XCUIApplication()
|
|
1846
|
+
|
|
1847
|
+
override func setUpWithError() throws {
|
|
1848
|
+
continueAfterFailure = false
|
|
1849
|
+
app.launch()
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
func testBasicNavigation() throws {
|
|
1853
|
+
let tabBar = app.tabBars.firstMatch
|
|
1854
|
+
XCTAssertTrue(tabBar.exists)
|
|
1855
|
+
|
|
1856
|
+
app.buttons["Calculator"].tap()
|
|
1857
|
+
|
|
1858
|
+
let calculatorView = app.otherElements["CalculatorView"]
|
|
1859
|
+
XCTAssertTrue(calculatorView.waitForExistence(timeout: 5))
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
func testCalculatorInput() {
|
|
1863
|
+
app.buttons["5"].tap()
|
|
1864
|
+
app.buttons["+"].tap()
|
|
1865
|
+
app.buttons["3"].tap()
|
|
1866
|
+
app.buttons["="].tap()
|
|
1867
|
+
|
|
1868
|
+
let result = app.staticTexts["8"]
|
|
1869
|
+
XCTAssertTrue(result.exists)
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
func testScreenshots() {
|
|
1873
|
+
takeScreenshot(name: "main_screen")
|
|
1874
|
+
|
|
1875
|
+
app.buttons["Settings"].tap()
|
|
1876
|
+
takeScreenshot(name: "settings_screen")
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
private func takeScreenshot(name: String) {
|
|
1880
|
+
let screenshot = app.screenshot()
|
|
1881
|
+
let attachment = XCTAttachment(screenshot: screenshot)
|
|
1882
|
+
attachment.name = name
|
|
1883
|
+
attachment.lifetime = .keepAlways
|
|
1884
|
+
add(attachment)
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
// MARK: - Simple Test Functions (Non-XCTest)
|
|
1889
|
+
|
|
1890
|
+
struct SimpleTests {
|
|
1891
|
+
// Simple test functions that should be detected
|
|
1892
|
+
static func testStringOperations() -> Bool {
|
|
1893
|
+
let str = "Hello, World!"
|
|
1894
|
+
|
|
1895
|
+
// Test string length
|
|
1896
|
+
guard str.count == 13 else {
|
|
1897
|
+
print("String length test failed")
|
|
1898
|
+
return false
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
// Test string contains
|
|
1902
|
+
guard str.contains("World") else {
|
|
1903
|
+
print("String contains test failed")
|
|
1904
|
+
return false
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
// Test string prefix
|
|
1908
|
+
guard str.hasPrefix("Hello") else {
|
|
1909
|
+
print("String prefix test failed")
|
|
1910
|
+
return false
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
print("All string tests passed")
|
|
1914
|
+
return true
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
static func testArrayOperations() -> Bool {
|
|
1918
|
+
let numbers = [1, 2, 3, 4, 5]
|
|
1919
|
+
|
|
1920
|
+
// Test array count
|
|
1921
|
+
guard numbers.count == 5 else {
|
|
1922
|
+
print("Array count test failed")
|
|
1923
|
+
return false
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
// Test array contains
|
|
1927
|
+
guard numbers.contains(3) else {
|
|
1928
|
+
print("Array contains test failed")
|
|
1929
|
+
return false
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
// Test array sum
|
|
1933
|
+
let sum = numbers.reduce(0, +)
|
|
1934
|
+
guard sum == 15 else {
|
|
1935
|
+
print("Array sum test failed: expected 15, got \(sum)")
|
|
1936
|
+
return false
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
print("All array tests passed")
|
|
1940
|
+
return true
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
static func testMathOperations() -> Bool {
|
|
1944
|
+
// Test basic arithmetic
|
|
1945
|
+
guard 2 + 2 == 4 else {
|
|
1946
|
+
print("Addition test failed")
|
|
1947
|
+
return false
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
guard 10 - 3 == 7 else {
|
|
1951
|
+
print("Subtraction test failed")
|
|
1952
|
+
return false
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
guard 4 * 5 == 20 else {
|
|
1956
|
+
print("Multiplication test failed")
|
|
1957
|
+
return false
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
guard 15 / 3 == 5 else {
|
|
1961
|
+
print("Division test failed")
|
|
1962
|
+
return false
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
print("All math tests passed")
|
|
1966
|
+
return true
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
static func runAllTests() {
|
|
1970
|
+
print("Running simple tests...")
|
|
1971
|
+
|
|
1972
|
+
let stringTestPassed = testStringOperations()
|
|
1973
|
+
let arrayTestPassed = testArrayOperations()
|
|
1974
|
+
let mathTestPassed = testMathOperations()
|
|
1975
|
+
|
|
1976
|
+
if stringTestPassed && arrayTestPassed && mathTestPassed {
|
|
1977
|
+
print("All simple tests passed!")
|
|
1978
|
+
} else {
|
|
1979
|
+
print("Some tests failed.")
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
// MARK: - Mock and Stub Test Helpers
|
|
1985
|
+
|
|
1986
|
+
class MockNetworkService {
|
|
1987
|
+
var shouldReturnError = false
|
|
1988
|
+
|
|
1989
|
+
func fetchData() async throws -> Data {
|
|
1990
|
+
if shouldReturnError {
|
|
1991
|
+
throw NetworkError.connectionFailed
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
let jsonString = "{\"message\": \"Hello, World!\"}"
|
|
1995
|
+
return jsonString.data(using: .utf8)!
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
enum NetworkError: Error {
|
|
2000
|
+
case connectionFailed
|
|
2001
|
+
case invalidResponse
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
// MARK: - Integration Tests
|
|
2005
|
+
|
|
2006
|
+
class IntegrationTests: XCTestCase {
|
|
2007
|
+
var mockService: MockNetworkService!
|
|
2008
|
+
var dataProcessor: DataProcessor!
|
|
2009
|
+
|
|
2010
|
+
override func setUp() {
|
|
2011
|
+
super.setUp()
|
|
2012
|
+
mockService = MockNetworkService()
|
|
2013
|
+
dataProcessor = DataProcessor(networkService: mockService)
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
func testDataProcessingFlow() async throws {
|
|
2017
|
+
// Test successful flow
|
|
2018
|
+
mockService.shouldReturnError = false
|
|
2019
|
+
let result = try await dataProcessor.processData()
|
|
2020
|
+
|
|
2021
|
+
XCTAssertNotNil(result)
|
|
2022
|
+
XCTAssertEqual(result.message, "Hello, World!")
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
func testErrorHandling() async {
|
|
2026
|
+
// Test error flow
|
|
2027
|
+
mockService.shouldReturnError = true
|
|
2028
|
+
|
|
2029
|
+
do {
|
|
2030
|
+
_ = try await dataProcessor.processData()
|
|
2031
|
+
XCTFail("Expected error to be thrown")
|
|
2032
|
+
} catch {
|
|
2033
|
+
XCTAssertTrue(error is NetworkError)
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
func testRetryLogic() async throws {
|
|
2038
|
+
var attemptCount = 0
|
|
2039
|
+
mockService.shouldReturnError = true
|
|
2040
|
+
|
|
2041
|
+
// Mock will fail first two attempts, succeed on third
|
|
2042
|
+
dataProcessor.retryHandler = {
|
|
2043
|
+
attemptCount += 1
|
|
2044
|
+
if attemptCount >= 3 {
|
|
2045
|
+
self.mockService.shouldReturnError = false
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
let result = try await dataProcessor.processDataWithRetry(maxAttempts: 3)
|
|
2050
|
+
XCTAssertNotNil(result)
|
|
2051
|
+
XCTAssertEqual(attemptCount, 3)
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
"#;
|
|
2055
|
+
|
|
2056
|
+
fs::write(&test_file, content)?;
|
|
2057
|
+
|
|
2058
|
+
let ctx = TestContext::new();
|
|
2059
|
+
let output = ctx.run_probe(&[
|
|
2060
|
+
"search",
|
|
2061
|
+
"test", // Search for test-related content
|
|
2062
|
+
test_file.to_str().unwrap(),
|
|
2063
|
+
"--format",
|
|
2064
|
+
"outline",
|
|
2065
|
+
"--allow-tests", // Enable test detection
|
|
2066
|
+
])?;
|
|
2067
|
+
|
|
2068
|
+
// Should find XCTest framework test classes
|
|
2069
|
+
assert!(
|
|
2070
|
+
output.contains("XCTestCase")
|
|
2071
|
+
|| output.contains("CalculatorTests")
|
|
2072
|
+
|| output.contains("PerformanceTests"),
|
|
2073
|
+
"Should find XCTest framework test classes - output: {}",
|
|
2074
|
+
output
|
|
2075
|
+
);
|
|
2076
|
+
|
|
2077
|
+
// Should find XCTest methods
|
|
2078
|
+
let xctest_methods = [
|
|
2079
|
+
"testAddition",
|
|
2080
|
+
"testSubtraction",
|
|
2081
|
+
"testMultiplication",
|
|
2082
|
+
"testDivision",
|
|
2083
|
+
"testPerformance",
|
|
2084
|
+
];
|
|
2085
|
+
let found_xctest_methods: Vec<&str> = xctest_methods
|
|
2086
|
+
.iter()
|
|
2087
|
+
.filter(|&method| output.contains(method))
|
|
2088
|
+
.copied()
|
|
2089
|
+
.collect();
|
|
2090
|
+
|
|
2091
|
+
assert!(
|
|
2092
|
+
!found_xctest_methods.is_empty(),
|
|
2093
|
+
"Should find XCTest methods. Found: {:?} - output: {}",
|
|
2094
|
+
found_xctest_methods,
|
|
2095
|
+
output
|
|
2096
|
+
);
|
|
2097
|
+
|
|
2098
|
+
// Should find simple test functions (non-XCTest)
|
|
2099
|
+
let simple_test_functions = [
|
|
2100
|
+
"testStringOperations",
|
|
2101
|
+
"testArrayOperations",
|
|
2102
|
+
"testMathOperations",
|
|
2103
|
+
];
|
|
2104
|
+
let found_simple_tests: Vec<&str> = simple_test_functions
|
|
2105
|
+
.iter()
|
|
2106
|
+
.filter(|&func| output.contains(func))
|
|
2107
|
+
.copied()
|
|
2108
|
+
.collect();
|
|
2109
|
+
|
|
2110
|
+
assert!(
|
|
2111
|
+
!found_simple_tests.is_empty(),
|
|
2112
|
+
"Should find simple test functions. Found: {:?} - output: {}",
|
|
2113
|
+
found_simple_tests,
|
|
2114
|
+
output
|
|
2115
|
+
);
|
|
2116
|
+
|
|
2117
|
+
// Should find XCTest assertions and patterns
|
|
2118
|
+
let xctest_patterns = [
|
|
2119
|
+
"XCTAssert",
|
|
2120
|
+
"XCTAssertEqual",
|
|
2121
|
+
"XCTAssertThrowsError",
|
|
2122
|
+
"expectation",
|
|
2123
|
+
"measure",
|
|
2124
|
+
];
|
|
2125
|
+
let found_patterns: Vec<&str> = xctest_patterns
|
|
2126
|
+
.iter()
|
|
2127
|
+
.filter(|&pattern| output.contains(pattern))
|
|
2128
|
+
.copied()
|
|
2129
|
+
.collect();
|
|
2130
|
+
|
|
2131
|
+
assert!(
|
|
2132
|
+
!found_patterns.is_empty(),
|
|
2133
|
+
"Should find XCTest assertion patterns. Found: {:?} - output: {}",
|
|
2134
|
+
found_patterns,
|
|
2135
|
+
output
|
|
2136
|
+
);
|
|
2137
|
+
|
|
2138
|
+
// Should find test setup and teardown methods
|
|
2139
|
+
let setup_teardown = ["setUp", "tearDown", "setUpWithError", "tearDownWithError"];
|
|
2140
|
+
let found_setup: Vec<&str> = setup_teardown
|
|
2141
|
+
.iter()
|
|
2142
|
+
.filter(|&method| output.contains(method))
|
|
2143
|
+
.copied()
|
|
2144
|
+
.collect();
|
|
2145
|
+
|
|
2146
|
+
// Note: This is optional since setup/teardown might not always be in search results
|
|
2147
|
+
if !found_setup.is_empty() {
|
|
2148
|
+
println!("Found setup/teardown methods: {:?}", found_setup);
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
// Should find async test patterns
|
|
2152
|
+
let async_patterns = ["async", "await", "XCTAssertThrowsErrorAsync"];
|
|
2153
|
+
let found_async: Vec<&str> = async_patterns
|
|
2154
|
+
.iter()
|
|
2155
|
+
.filter(|&pattern| output.contains(pattern))
|
|
2156
|
+
.copied()
|
|
2157
|
+
.collect();
|
|
2158
|
+
|
|
2159
|
+
assert!(
|
|
2160
|
+
!found_async.is_empty(),
|
|
2161
|
+
"Should find async test patterns. Found: {:?} - output: {}",
|
|
2162
|
+
found_async,
|
|
2163
|
+
output
|
|
2164
|
+
);
|
|
2165
|
+
|
|
2166
|
+
// Should be in outline format
|
|
2167
|
+
assert!(
|
|
2168
|
+
output.contains("---\nFile:"),
|
|
2169
|
+
"Missing file delimiter in outline format - output: {}",
|
|
2170
|
+
output
|
|
2171
|
+
);
|
|
2172
|
+
|
|
2173
|
+
Ok(())
|
|
2174
|
+
}
|
|
2175
|
+
|
|
2176
|
+
#[test]
|
|
2177
|
+
fn test_swift_outline_modern_features() -> Result<()> {
|
|
2178
|
+
let temp_dir = TempDir::new()?;
|
|
2179
|
+
let test_file = temp_dir.path().join("ModernSwift.swift");
|
|
2180
|
+
|
|
2181
|
+
let content = r#"import SwiftUI
|
|
2182
|
+
import Combine
|
|
2183
|
+
import Foundation
|
|
2184
|
+
|
|
2185
|
+
// MARK: - Actors for Concurrency
|
|
2186
|
+
|
|
2187
|
+
actor DataManager {
|
|
2188
|
+
private var cache: [String: Any] = [:]
|
|
2189
|
+
private var subscribers: [AnyCancellable] = []
|
|
2190
|
+
|
|
2191
|
+
func store(key: String, value: Any) {
|
|
2192
|
+
cache[key] = value
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
func retrieve(key: String) -> Any? {
|
|
2196
|
+
return cache[key]
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
func clearCache() {
|
|
2200
|
+
cache.removeAll()
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
// Async function within actor
|
|
2204
|
+
func processData(_ data: [String]) async throws -> [String] {
|
|
2205
|
+
var results: [String] = []
|
|
2206
|
+
|
|
2207
|
+
for item in data {
|
|
2208
|
+
// Simulate async processing
|
|
2209
|
+
try await Task.sleep(nanoseconds: 1_000_000) // 1ms
|
|
2210
|
+
results.append("PROCESSED_\(item)")
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
return results
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
// MARK: - Async/Await Functions
|
|
2218
|
+
|
|
2219
|
+
class AsyncNetworkService {
|
|
2220
|
+
private let session = URLSession.shared
|
|
2221
|
+
|
|
2222
|
+
func fetchData(from url: URL) async throws -> Data {
|
|
2223
|
+
let (data, response) = try await session.data(from: url)
|
|
2224
|
+
|
|
2225
|
+
guard let httpResponse = response as? HTTPURLResponse,
|
|
2226
|
+
200...299 ~= httpResponse.statusCode else {
|
|
2227
|
+
throw NetworkError.invalidResponse
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
return data
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
func fetchMultipleResources(urls: [URL]) async throws -> [Data] {
|
|
2234
|
+
// Concurrent execution using async let
|
|
2235
|
+
async let firstData = fetchData(from: urls[0])
|
|
2236
|
+
async let secondData = fetchData(from: urls[1])
|
|
2237
|
+
async let thirdData = fetchData(from: urls[2])
|
|
2238
|
+
|
|
2239
|
+
return try await [firstData, secondData, thirdData]
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
func processWithTaskGroup(urls: [URL]) async throws -> [String] {
|
|
2243
|
+
return try await withThrowingTaskGroup(of: String.self) { group in
|
|
2244
|
+
for url in urls {
|
|
2245
|
+
group.addTask {
|
|
2246
|
+
let data = try await self.fetchData(from: url)
|
|
2247
|
+
return String(data: data, encoding: .utf8) ?? "EMPTY"
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
var results: [String] = []
|
|
2252
|
+
for try await result in group {
|
|
2253
|
+
results.append(result)
|
|
2254
|
+
}
|
|
2255
|
+
return results
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
// MARK: - SwiftUI Views with State Management
|
|
2261
|
+
|
|
2262
|
+
struct ContentView: View {
|
|
2263
|
+
@StateObject private var viewModel = ContentViewModel()
|
|
2264
|
+
@Environment(\.colorScheme) var colorScheme
|
|
2265
|
+
@AppStorage("user_preference") var userPreference: String = "default"
|
|
2266
|
+
|
|
2267
|
+
var body: some View {
|
|
2268
|
+
NavigationStack {
|
|
2269
|
+
VStack(spacing: 20) {
|
|
2270
|
+
HeaderView(title: "Modern Swift Demo")
|
|
2271
|
+
|
|
2272
|
+
AsyncButton("Load Data") {
|
|
2273
|
+
await viewModel.loadData()
|
|
2274
|
+
}
|
|
2275
|
+
.disabled(viewModel.isLoading)
|
|
2276
|
+
|
|
2277
|
+
if viewModel.isLoading {
|
|
2278
|
+
ProgressView("Loading...")
|
|
2279
|
+
.progressViewStyle(CircularProgressViewStyle())
|
|
2280
|
+
} else {
|
|
2281
|
+
DataListView(items: viewModel.items)
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
Spacer()
|
|
2285
|
+
}
|
|
2286
|
+
.padding()
|
|
2287
|
+
.navigationTitle("Demo")
|
|
2288
|
+
.task {
|
|
2289
|
+
await viewModel.initializeData()
|
|
2290
|
+
}
|
|
2291
|
+
.refreshable {
|
|
2292
|
+
await viewModel.refreshData()
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
.preferredColorScheme(colorScheme)
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
// MARK: - SwiftUI Components with ViewBuilder
|
|
2300
|
+
|
|
2301
|
+
struct HeaderView: View {
|
|
2302
|
+
let title: String
|
|
2303
|
+
@State private var isAnimated = false
|
|
2304
|
+
|
|
2305
|
+
var body: some View {
|
|
2306
|
+
Text(title)
|
|
2307
|
+
.font(.largeTitle)
|
|
2308
|
+
.fontWeight(.bold)
|
|
2309
|
+
.scaleEffect(isAnimated ? 1.1 : 1.0)
|
|
2310
|
+
.animation(.spring(response: 0.5, dampingFraction: 0.8), value: isAnimated)
|
|
2311
|
+
.onAppear {
|
|
2312
|
+
withAnimation {
|
|
2313
|
+
isAnimated = true
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2319
|
+
struct AsyncButton<Label: View>: View {
|
|
2320
|
+
let label: Label
|
|
2321
|
+
let action: () async -> Void
|
|
2322
|
+
@State private var isPerforming = false
|
|
2323
|
+
|
|
2324
|
+
init(_ titleKey: LocalizedStringKey, action: @escaping () async -> Void) where Label == Text {
|
|
2325
|
+
self.label = Text(titleKey)
|
|
2326
|
+
self.action = action
|
|
2327
|
+
}
|
|
2328
|
+
|
|
2329
|
+
init(action: @escaping () async -> Void, @ViewBuilder label: () -> Label) {
|
|
2330
|
+
self.label = label()
|
|
2331
|
+
self.action = action
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
var body: some View {
|
|
2335
|
+
Button {
|
|
2336
|
+
Task {
|
|
2337
|
+
isPerforming = true
|
|
2338
|
+
defer { isPerforming = false }
|
|
2339
|
+
await action()
|
|
2340
|
+
}
|
|
2341
|
+
} label: {
|
|
2342
|
+
if isPerforming {
|
|
2343
|
+
ProgressView()
|
|
2344
|
+
.progressViewStyle(CircularProgressViewStyle(tint: .white))
|
|
2345
|
+
.scaleEffect(0.8)
|
|
2346
|
+
} else {
|
|
2347
|
+
label
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
.disabled(isPerforming)
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2354
|
+
struct DataListView: View {
|
|
2355
|
+
let items: [DataItem]
|
|
2356
|
+
@State private var selectedItem: DataItem?
|
|
2357
|
+
|
|
2358
|
+
var body: some View {
|
|
2359
|
+
LazyVStack(spacing: 12) {
|
|
2360
|
+
ForEach(items) { item in
|
|
2361
|
+
DataRowView(item: item)
|
|
2362
|
+
.onTapGesture {
|
|
2363
|
+
selectedItem = item
|
|
2364
|
+
}
|
|
2365
|
+
.contextMenu {
|
|
2366
|
+
Button("Share") {
|
|
2367
|
+
shareItem(item)
|
|
2368
|
+
}
|
|
2369
|
+
Button("Delete", role: .destructive) {
|
|
2370
|
+
deleteItem(item)
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
.sheet(item: $selectedItem) { item in
|
|
2376
|
+
DataDetailView(item: item)
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
private func shareItem(_ item: DataItem) {
|
|
2381
|
+
// Share implementation
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
private func deleteItem(_ item: DataItem) {
|
|
2385
|
+
// Delete implementation
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
// MARK: - Observable Pattern with Combine
|
|
2390
|
+
|
|
2391
|
+
@MainActor
|
|
2392
|
+
class ContentViewModel: ObservableObject {
|
|
2393
|
+
@Published var items: [DataItem] = []
|
|
2394
|
+
@Published var isLoading = false
|
|
2395
|
+
@Published var errorMessage: String?
|
|
2396
|
+
|
|
2397
|
+
private let dataManager = DataManager()
|
|
2398
|
+
private let networkService = AsyncNetworkService()
|
|
2399
|
+
private var cancellables = Set<AnyCancellable>()
|
|
2400
|
+
|
|
2401
|
+
func initializeData() async {
|
|
2402
|
+
await loadData()
|
|
2403
|
+
setupSubscriptions()
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2406
|
+
func loadData() async {
|
|
2407
|
+
isLoading = true
|
|
2408
|
+
defer { isLoading = false }
|
|
2409
|
+
|
|
2410
|
+
do {
|
|
2411
|
+
// Simulate network delay
|
|
2412
|
+
try await Task.sleep(nanoseconds: 2_000_000_000) // 2 seconds
|
|
2413
|
+
|
|
2414
|
+
let urls = [
|
|
2415
|
+
URL(string: "https://api.example.com/data1")!,
|
|
2416
|
+
URL(string: "https://api.example.com/data2")!,
|
|
2417
|
+
URL(string: "https://api.example.com/data3")!
|
|
2418
|
+
]
|
|
2419
|
+
|
|
2420
|
+
let results = try await networkService.processWithTaskGroup(urls: urls)
|
|
2421
|
+
|
|
2422
|
+
items = results.enumerated().map { index, content in
|
|
2423
|
+
DataItem(id: UUID(), title: "Item \(index + 1)", content: content)
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
// Store in actor-managed cache
|
|
2427
|
+
await dataManager.store(key: "cached_items", value: items)
|
|
2428
|
+
|
|
2429
|
+
} catch {
|
|
2430
|
+
errorMessage = error.localizedDescription
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
func refreshData() async {
|
|
2435
|
+
await loadData()
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
private func setupSubscriptions() {
|
|
2439
|
+
// Combine reactive programming
|
|
2440
|
+
$items
|
|
2441
|
+
.debounce(for: .milliseconds(300), scheduler: RunLoop.main)
|
|
2442
|
+
.sink { items in
|
|
2443
|
+
print("Items updated: \(items.count)")
|
|
2444
|
+
}
|
|
2445
|
+
.store(in: &cancellables)
|
|
2446
|
+
|
|
2447
|
+
$errorMessage
|
|
2448
|
+
.compactMap { $0 }
|
|
2449
|
+
.sink { error in
|
|
2450
|
+
print("Error occurred: \(error)")
|
|
2451
|
+
}
|
|
2452
|
+
.store(in: &cancellables)
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
// MARK: - Data Models with Property Wrappers
|
|
2457
|
+
|
|
2458
|
+
struct DataItem: Identifiable, Codable {
|
|
2459
|
+
let id: UUID
|
|
2460
|
+
let title: String
|
|
2461
|
+
let content: String
|
|
2462
|
+
@CodingKey("created_at") let createdAt: Date = Date()
|
|
2463
|
+
|
|
2464
|
+
enum CodingKeys: String, CodingKey {
|
|
2465
|
+
case id, title, content
|
|
2466
|
+
case createdAt = "created_at"
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2470
|
+
// MARK: - Custom Property Wrappers
|
|
2471
|
+
|
|
2472
|
+
@propertyWrapper
|
|
2473
|
+
struct Capitalized {
|
|
2474
|
+
private var value: String
|
|
2475
|
+
|
|
2476
|
+
var wrappedValue: String {
|
|
2477
|
+
get { value }
|
|
2478
|
+
set { value = newValue.capitalized }
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
init(wrappedValue: String) {
|
|
2482
|
+
self.value = wrappedValue.capitalized
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
@propertyWrapper
|
|
2487
|
+
struct UserDefaultsBacked<T: Codable> {
|
|
2488
|
+
let key: String
|
|
2489
|
+
let defaultValue: T
|
|
2490
|
+
|
|
2491
|
+
var wrappedValue: T {
|
|
2492
|
+
get {
|
|
2493
|
+
guard let data = UserDefaults.standard.data(forKey: key),
|
|
2494
|
+
let value = try? JSONDecoder().decode(T.self, from: data) else {
|
|
2495
|
+
return defaultValue
|
|
2496
|
+
}
|
|
2497
|
+
return value
|
|
2498
|
+
}
|
|
2499
|
+
set {
|
|
2500
|
+
guard let data = try? JSONEncoder().encode(newValue) else { return }
|
|
2501
|
+
UserDefaults.standard.set(data, forKey: key)
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
// MARK: - Structured Concurrency Example
|
|
2507
|
+
|
|
2508
|
+
class ConcurrentDataProcessor {
|
|
2509
|
+
private let dataManager = DataManager()
|
|
2510
|
+
|
|
2511
|
+
func processLargeDataSet(_ data: [String]) async throws -> ProcessingResult {
|
|
2512
|
+
// Use structured concurrency for parallel processing
|
|
2513
|
+
return try await withThrowingTaskGroup(of: ProcessedChunk.self) { group in
|
|
2514
|
+
let chunks = data.chunked(into: 100) // Assume we have this extension
|
|
2515
|
+
|
|
2516
|
+
for (index, chunk) in chunks.enumerated() {
|
|
2517
|
+
group.addTask { [weak self] in
|
|
2518
|
+
guard let self = self else { throw ProcessingError.cancelled }
|
|
2519
|
+
|
|
2520
|
+
let processedData = try await self.dataManager.processData(chunk)
|
|
2521
|
+
return ProcessedChunk(index: index, data: processedData)
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
var results: [ProcessedChunk] = []
|
|
2526
|
+
for try await chunk in group {
|
|
2527
|
+
results.append(chunk)
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
// Sort by index to maintain order
|
|
2531
|
+
results.sort { $0.index < $1.index }
|
|
2532
|
+
let finalData = results.flatMap { $0.data }
|
|
2533
|
+
|
|
2534
|
+
return ProcessingResult(
|
|
2535
|
+
totalItems: data.count,
|
|
2536
|
+
processedItems: finalData.count,
|
|
2537
|
+
data: finalData
|
|
2538
|
+
)
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2543
|
+
// MARK: - Result Builders (Function Builders)
|
|
2544
|
+
|
|
2545
|
+
@resultBuilder
|
|
2546
|
+
struct ViewConfigBuilder {
|
|
2547
|
+
static func buildBlock(_ components: ViewConfig...) -> [ViewConfig] {
|
|
2548
|
+
components
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2551
|
+
static func buildIf(_ component: ViewConfig?) -> ViewConfig? {
|
|
2552
|
+
component
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
static func buildEither(first: ViewConfig) -> ViewConfig {
|
|
2556
|
+
first
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
static func buildEither(second: ViewConfig) -> ViewConfig {
|
|
2560
|
+
second
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
|
|
2564
|
+
struct ViewConfig {
|
|
2565
|
+
let name: String
|
|
2566
|
+
let properties: [String: Any]
|
|
2567
|
+
|
|
2568
|
+
init(name: String, properties: [String: Any] = [:]) {
|
|
2569
|
+
self.name = name
|
|
2570
|
+
self.properties = properties
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
func createView(@ViewConfigBuilder _ builder: () -> [ViewConfig]) -> UIView {
|
|
2575
|
+
let configs = builder()
|
|
2576
|
+
let view = UIView()
|
|
2577
|
+
// Apply configurations to view
|
|
2578
|
+
return view
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
// MARK: - Supporting Types
|
|
2582
|
+
|
|
2583
|
+
struct ProcessedChunk {
|
|
2584
|
+
let index: Int
|
|
2585
|
+
let data: [String]
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
struct ProcessingResult {
|
|
2589
|
+
let totalItems: Int
|
|
2590
|
+
let processedItems: Int
|
|
2591
|
+
let data: [String]
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
enum ProcessingError: Error {
|
|
2595
|
+
case cancelled
|
|
2596
|
+
case invalidData
|
|
2597
|
+
case timeout
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2600
|
+
enum NetworkError: Error {
|
|
2601
|
+
case invalidResponse
|
|
2602
|
+
case noData
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
// MARK: - Extensions
|
|
2606
|
+
|
|
2607
|
+
extension Array {
|
|
2608
|
+
func chunked(into size: Int) -> [[Element]] {
|
|
2609
|
+
return stride(from: 0, to: count, by: size).map {
|
|
2610
|
+
Array(self[$0..<Swift.min($0 + size, count)])
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
// MARK: - Protocol with Async Requirements
|
|
2616
|
+
|
|
2617
|
+
protocol AsyncDataProvider {
|
|
2618
|
+
associatedtype DataType: Codable
|
|
2619
|
+
|
|
2620
|
+
func fetchData() async throws -> [DataType]
|
|
2621
|
+
func updateData(_ data: [DataType]) async throws
|
|
2622
|
+
func deleteData(matching predicate: @escaping (DataType) -> Bool) async throws
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
// MARK: - Generic Async Iterator
|
|
2626
|
+
|
|
2627
|
+
struct AsyncDataIterator<T>: AsyncIteratorProtocol, AsyncSequence {
|
|
2628
|
+
typealias Element = T
|
|
2629
|
+
|
|
2630
|
+
private let data: [T]
|
|
2631
|
+
private var index = 0
|
|
2632
|
+
|
|
2633
|
+
init(_ data: [T]) {
|
|
2634
|
+
self.data = data
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
mutating func next() async -> T? {
|
|
2638
|
+
guard index < data.count else { return nil }
|
|
2639
|
+
defer { index += 1 }
|
|
2640
|
+
|
|
2641
|
+
// Simulate async delay
|
|
2642
|
+
try? await Task.sleep(nanoseconds: 10_000_000) // 10ms
|
|
2643
|
+
return data[index]
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
func makeAsyncIterator() -> AsyncDataIterator<T> {
|
|
2647
|
+
return self
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
"#;
|
|
2651
|
+
|
|
2652
|
+
fs::write(&test_file, content)?;
|
|
2653
|
+
|
|
2654
|
+
let ctx = TestContext::new();
|
|
2655
|
+
let output = ctx.run_probe(&[
|
|
2656
|
+
"search",
|
|
2657
|
+
"async", // Search for modern async features
|
|
2658
|
+
test_file.to_str().unwrap(),
|
|
2659
|
+
"--format",
|
|
2660
|
+
"outline",
|
|
2661
|
+
])?;
|
|
2662
|
+
|
|
2663
|
+
// Should find modern Swift keywords and features
|
|
2664
|
+
let modern_features = [
|
|
2665
|
+
"async",
|
|
2666
|
+
"await",
|
|
2667
|
+
"actor",
|
|
2668
|
+
"@MainActor",
|
|
2669
|
+
"@Published",
|
|
2670
|
+
"@StateObject",
|
|
2671
|
+
"@State",
|
|
2672
|
+
];
|
|
2673
|
+
let found_modern: Vec<&str> = modern_features
|
|
2674
|
+
.iter()
|
|
2675
|
+
.filter(|&feature| output.contains(feature))
|
|
2676
|
+
.copied()
|
|
2677
|
+
.collect();
|
|
2678
|
+
|
|
2679
|
+
assert!(
|
|
2680
|
+
!found_modern.is_empty(),
|
|
2681
|
+
"Should find modern Swift features. Found: {:?} - output: {}",
|
|
2682
|
+
found_modern,
|
|
2683
|
+
output
|
|
2684
|
+
);
|
|
2685
|
+
|
|
2686
|
+
// Should find SwiftUI-specific constructs
|
|
2687
|
+
let swiftui_features = [
|
|
2688
|
+
"View",
|
|
2689
|
+
"VStack",
|
|
2690
|
+
"NavigationStack",
|
|
2691
|
+
"Button",
|
|
2692
|
+
"@ViewBuilder",
|
|
2693
|
+
];
|
|
2694
|
+
let found_swiftui: Vec<&str> = swiftui_features
|
|
2695
|
+
.iter()
|
|
2696
|
+
.filter(|&feature| output.contains(feature))
|
|
2697
|
+
.copied()
|
|
2698
|
+
.collect();
|
|
2699
|
+
|
|
2700
|
+
assert!(
|
|
2701
|
+
!found_swiftui.is_empty(),
|
|
2702
|
+
"Should find SwiftUI constructs. Found: {:?} - output: {}",
|
|
2703
|
+
found_swiftui,
|
|
2704
|
+
output
|
|
2705
|
+
);
|
|
2706
|
+
|
|
2707
|
+
// Should find structured concurrency patterns
|
|
2708
|
+
let concurrency_patterns = [
|
|
2709
|
+
"TaskGroup",
|
|
2710
|
+
"withThrowingTaskGroup",
|
|
2711
|
+
"Task.sleep",
|
|
2712
|
+
"async let",
|
|
2713
|
+
];
|
|
2714
|
+
let found_concurrency: Vec<&str> = concurrency_patterns
|
|
2715
|
+
.iter()
|
|
2716
|
+
.filter(|&pattern| output.contains(pattern))
|
|
2717
|
+
.copied()
|
|
2718
|
+
.collect();
|
|
2719
|
+
|
|
2720
|
+
assert!(
|
|
2721
|
+
!found_concurrency.is_empty(),
|
|
2722
|
+
"Should find structured concurrency patterns. Found: {:?} - output: {}",
|
|
2723
|
+
found_concurrency,
|
|
2724
|
+
output
|
|
2725
|
+
);
|
|
2726
|
+
|
|
2727
|
+
// Should find property wrapper usage
|
|
2728
|
+
let property_wrapper_patterns = ["@propertyWrapper", "@UserDefaultsBacked", "@Capitalized"];
|
|
2729
|
+
let found_property_wrappers: Vec<&str> = property_wrapper_patterns
|
|
2730
|
+
.iter()
|
|
2731
|
+
.filter(|&pattern| output.contains(pattern))
|
|
2732
|
+
.copied()
|
|
2733
|
+
.collect();
|
|
2734
|
+
|
|
2735
|
+
assert!(
|
|
2736
|
+
!found_property_wrappers.is_empty(),
|
|
2737
|
+
"Should find property wrapper patterns. Found: {:?} - output: {}",
|
|
2738
|
+
found_property_wrappers,
|
|
2739
|
+
output
|
|
2740
|
+
);
|
|
2741
|
+
|
|
2742
|
+
// Should find Combine framework usage
|
|
2743
|
+
let combine_patterns = ["@Published", "AnyCancellable", "sink", "debounce"];
|
|
2744
|
+
let found_combine: Vec<&str> = combine_patterns
|
|
2745
|
+
.iter()
|
|
2746
|
+
.filter(|&pattern| output.contains(pattern))
|
|
2747
|
+
.copied()
|
|
2748
|
+
.collect();
|
|
2749
|
+
|
|
2750
|
+
// Note: Combine patterns might not always appear in outline search results
|
|
2751
|
+
if !found_combine.is_empty() {
|
|
2752
|
+
println!("Found Combine patterns: {:?}", found_combine);
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
// Should find result builder usage
|
|
2756
|
+
let result_builder_patterns = ["@resultBuilder", "buildBlock", "ViewConfigBuilder"];
|
|
2757
|
+
let found_result_builders: Vec<&str> = result_builder_patterns
|
|
2758
|
+
.iter()
|
|
2759
|
+
.filter(|&pattern| output.contains(pattern))
|
|
2760
|
+
.copied()
|
|
2761
|
+
.collect();
|
|
2762
|
+
|
|
2763
|
+
// Note: Result builders might not always appear in outline search results
|
|
2764
|
+
if !found_result_builders.is_empty() {
|
|
2765
|
+
println!("Found result builder patterns: {:?}", found_result_builders);
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
// Should be in outline format
|
|
2769
|
+
assert!(
|
|
2770
|
+
output.contains("---\nFile:"),
|
|
2771
|
+
"Missing file delimiter in outline format - output: {}",
|
|
2772
|
+
output
|
|
2773
|
+
);
|
|
2774
|
+
|
|
2775
|
+
Ok(())
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2778
|
+
#[test]
|
|
2779
|
+
fn test_swift_outline_small_vs_large_functions_closing_braces() -> Result<()> {
|
|
2780
|
+
let temp_dir = TempDir::new()?;
|
|
2781
|
+
let test_file = temp_dir.path().join("FunctionSizes.swift");
|
|
2782
|
+
|
|
2783
|
+
let content = r#"import Foundation
|
|
2784
|
+
|
|
2785
|
+
// MARK: - Small Functions (should NOT get closing brace comments)
|
|
2786
|
+
|
|
2787
|
+
func simpleAdd(_ a: Int, _ b: Int) -> Int {
|
|
2788
|
+
return a + b
|
|
2789
|
+
}
|
|
2790
|
+
|
|
2791
|
+
func quickCheck(_ value: String) -> Bool {
|
|
2792
|
+
return !value.isEmpty
|
|
2793
|
+
}
|
|
2794
|
+
|
|
2795
|
+
func shortGreeting(_ name: String) -> String {
|
|
2796
|
+
return "Hello, \(name)!"
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2799
|
+
func basicValidation(_ input: String) -> Bool {
|
|
2800
|
+
guard !input.isEmpty else { return false }
|
|
2801
|
+
return input.count >= 3
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
func smallCalculation(_ numbers: [Int]) -> Int {
|
|
2805
|
+
return numbers.reduce(0, +)
|
|
2806
|
+
}
|
|
2807
|
+
|
|
2808
|
+
// MARK: - Medium Functions (might get closing brace comments depending on gaps)
|
|
2809
|
+
|
|
2810
|
+
func mediumProcessing(_ data: [String]) -> [String] {
|
|
2811
|
+
var results: [String] = []
|
|
2812
|
+
|
|
2813
|
+
for item in data {
|
|
2814
|
+
if item.hasPrefix("PROCESS_") {
|
|
2815
|
+
results.append(item.uppercased())
|
|
2816
|
+
} else if item.hasPrefix("SKIP_") {
|
|
2817
|
+
continue
|
|
2818
|
+
} else {
|
|
2819
|
+
results.append(item.lowercased())
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2823
|
+
return results.sorted()
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
func mediumValidation(_ input: Any) -> ValidationResult {
|
|
2827
|
+
if let stringInput = input as? String {
|
|
2828
|
+
if stringInput.isEmpty {
|
|
2829
|
+
return .invalid("Empty string")
|
|
2830
|
+
} else if stringInput.count < 3 {
|
|
2831
|
+
return .invalid("Too short")
|
|
2832
|
+
} else {
|
|
2833
|
+
return .valid
|
|
2834
|
+
}
|
|
2835
|
+
} else if let numberInput = input as? NSNumber {
|
|
2836
|
+
let value = numberInput.doubleValue
|
|
2837
|
+
return value > 0 ? .valid : .invalid("Negative number")
|
|
2838
|
+
} else {
|
|
2839
|
+
return .invalid("Unsupported type")
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
// MARK: - Large Functions (should get closing brace comments with Swift // syntax)
|
|
2844
|
+
|
|
2845
|
+
func complexDataProcessing(_ dataset: [Any]) -> ProcessingResult {
|
|
2846
|
+
var processedItems: [ProcessedItem] = []
|
|
2847
|
+
var errors: [ProcessingError] = []
|
|
2848
|
+
var statistics = ProcessingStatistics()
|
|
2849
|
+
|
|
2850
|
+
// Phase 1: Initial validation and categorization
|
|
2851
|
+
for (index, item) in dataset.enumerated() {
|
|
2852
|
+
do {
|
|
2853
|
+
let validatedItem = try validateDataItem(item, at: index)
|
|
2854
|
+
|
|
2855
|
+
switch validatedItem.category {
|
|
2856
|
+
case .highPriority:
|
|
2857
|
+
statistics.highPriorityCount += 1
|
|
2858
|
+
processedItems.append(ProcessedItem(
|
|
2859
|
+
id: UUID(),
|
|
2860
|
+
originalIndex: index,
|
|
2861
|
+
data: validatedItem.data,
|
|
2862
|
+
priority: .high,
|
|
2863
|
+
processingTime: Date()
|
|
2864
|
+
))
|
|
2865
|
+
|
|
2866
|
+
case .mediumPriority:
|
|
2867
|
+
statistics.mediumPriorityCount += 1
|
|
2868
|
+
processedItems.append(ProcessedItem(
|
|
2869
|
+
id: UUID(),
|
|
2870
|
+
originalIndex: index,
|
|
2871
|
+
data: validatedItem.data,
|
|
2872
|
+
priority: .medium,
|
|
2873
|
+
processingTime: Date()
|
|
2874
|
+
))
|
|
2875
|
+
|
|
2876
|
+
case .lowPriority:
|
|
2877
|
+
statistics.lowPriorityCount += 1
|
|
2878
|
+
processedItems.append(ProcessedItem(
|
|
2879
|
+
id: UUID(),
|
|
2880
|
+
originalIndex: index,
|
|
2881
|
+
data: validatedItem.data,
|
|
2882
|
+
priority: .low,
|
|
2883
|
+
processingTime: Date()
|
|
2884
|
+
))
|
|
2885
|
+
|
|
2886
|
+
case .deferred:
|
|
2887
|
+
statistics.deferredCount += 1
|
|
2888
|
+
// Deferred items are processed later
|
|
2889
|
+
continue
|
|
2890
|
+
}
|
|
2891
|
+
} catch {
|
|
2892
|
+
errors.append(ProcessingError(
|
|
2893
|
+
index: index,
|
|
2894
|
+
item: item,
|
|
2895
|
+
error: error,
|
|
2896
|
+
timestamp: Date()
|
|
2897
|
+
))
|
|
2898
|
+
statistics.errorCount += 1
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
|
|
2902
|
+
// Phase 2: Advanced processing for complex items
|
|
2903
|
+
var complexProcessedItems: [ProcessedItem] = []
|
|
2904
|
+
for item in processedItems {
|
|
2905
|
+
if item.priority == .high {
|
|
2906
|
+
// Complex processing for high priority items
|
|
2907
|
+
let enhancedData = performComplexTransformation(item.data)
|
|
2908
|
+
let analysisResult = performDeepAnalysis(enhancedData)
|
|
2909
|
+
|
|
2910
|
+
var updatedItem = item
|
|
2911
|
+
updatedItem.data = enhancedData
|
|
2912
|
+
updatedItem.analysisScore = analysisResult.score
|
|
2913
|
+
updatedItem.confidence = analysisResult.confidence
|
|
2914
|
+
updatedItem.metadata = analysisResult.metadata
|
|
2915
|
+
|
|
2916
|
+
complexProcessedItems.append(updatedItem)
|
|
2917
|
+
statistics.complexProcessingCount += 1
|
|
2918
|
+
} else {
|
|
2919
|
+
// Standard processing for lower priority items
|
|
2920
|
+
complexProcessedItems.append(item)
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
// Phase 3: Final validation and result compilation
|
|
2925
|
+
let finalResults = complexProcessedItems.compactMap { item -> ProcessedItem? in
|
|
2926
|
+
guard item.analysisScore > 0.5 else {
|
|
2927
|
+
statistics.rejectedCount += 1
|
|
2928
|
+
return nil
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
statistics.acceptedCount += 1
|
|
2932
|
+
return item
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
// Phase 4: Generate comprehensive report
|
|
2936
|
+
let processingReport = ProcessingReport(
|
|
2937
|
+
totalItemsProcessed: dataset.count,
|
|
2938
|
+
successfulItems: finalResults.count,
|
|
2939
|
+
errorCount: errors.count,
|
|
2940
|
+
statistics: statistics,
|
|
2941
|
+
processingDuration: Date().timeIntervalSince(statistics.startTime),
|
|
2942
|
+
qualityScore: calculateQualityScore(finalResults)
|
|
2943
|
+
)
|
|
2944
|
+
|
|
2945
|
+
return ProcessingResult(
|
|
2946
|
+
processedItems: finalResults,
|
|
2947
|
+
errors: errors,
|
|
2948
|
+
statistics: statistics,
|
|
2949
|
+
report: processingReport
|
|
2950
|
+
)
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
func massiveDataTransformation(_ input: [ComplexDataStructure]) async throws -> [TransformedData] {
|
|
2954
|
+
var transformedResults: [TransformedData] = []
|
|
2955
|
+
let processor = AsyncDataProcessor()
|
|
2956
|
+
let validator = DataValidator()
|
|
2957
|
+
let enhancer = DataEnhancer()
|
|
2958
|
+
|
|
2959
|
+
// Batch processing configuration
|
|
2960
|
+
let batchSize = 100
|
|
2961
|
+
let maxConcurrentTasks = 4
|
|
2962
|
+
let timeout: TimeInterval = 300 // 5 minutes
|
|
2963
|
+
|
|
2964
|
+
// Initialize monitoring and logging
|
|
2965
|
+
let processingMonitor = ProcessingMonitor()
|
|
2966
|
+
await processingMonitor.startMonitoring()
|
|
2967
|
+
|
|
2968
|
+
defer {
|
|
2969
|
+
Task {
|
|
2970
|
+
await processingMonitor.stopMonitoring()
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2974
|
+
// Phase 1: Preprocessing and validation
|
|
2975
|
+
for (batchIndex, batch) in input.chunked(into: batchSize).enumerated() {
|
|
2976
|
+
await processingMonitor.logBatchStart(batchIndex, itemCount: batch.count)
|
|
2977
|
+
|
|
2978
|
+
do {
|
|
2979
|
+
// Parallel validation of batch items
|
|
2980
|
+
let validationResults = try await withThrowingTaskGroup(of: ValidationResult.self) { group in
|
|
2981
|
+
for item in batch {
|
|
2982
|
+
group.addTask {
|
|
2983
|
+
return try await validator.validateAsync(item)
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
var results: [ValidationResult] = []
|
|
2988
|
+
for try await result in group {
|
|
2989
|
+
results.append(result)
|
|
2990
|
+
}
|
|
2991
|
+
return results
|
|
2992
|
+
}
|
|
2993
|
+
|
|
2994
|
+
// Process validated items
|
|
2995
|
+
for (itemIndex, validationResult) in validationResults.enumerated() {
|
|
2996
|
+
let originalItem = batch[itemIndex]
|
|
2997
|
+
|
|
2998
|
+
switch validationResult.status {
|
|
2999
|
+
case .valid:
|
|
3000
|
+
// Transform valid items
|
|
3001
|
+
let transformedItem = try await processor.transform(originalItem)
|
|
3002
|
+
let enhancedItem = try await enhancer.enhance(transformedItem)
|
|
3003
|
+
transformedResults.append(enhancedItem)
|
|
3004
|
+
|
|
3005
|
+
case .validWithWarnings:
|
|
3006
|
+
// Handle items with warnings
|
|
3007
|
+
let transformedItem = try await processor.transformWithWarnings(originalItem, warnings: validationResult.warnings)
|
|
3008
|
+
transformedResults.append(transformedItem)
|
|
3009
|
+
|
|
3010
|
+
case .invalid:
|
|
3011
|
+
// Log invalid items for manual review
|
|
3012
|
+
await processingMonitor.logInvalidItem(originalItem, reason: validationResult.reason)
|
|
3013
|
+
continue
|
|
3014
|
+
|
|
3015
|
+
case .requiresManualReview:
|
|
3016
|
+
// Queue for manual review
|
|
3017
|
+
await processingMonitor.queueForManualReview(originalItem, notes: validationResult.notes)
|
|
3018
|
+
continue
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
|
|
3022
|
+
await processingMonitor.logBatchCompletion(batchIndex, successCount: validationResults.count)
|
|
3023
|
+
|
|
3024
|
+
} catch {
|
|
3025
|
+
await processingMonitor.logBatchError(batchIndex, error: error)
|
|
3026
|
+
throw ProcessingError.batchProcessingFailed(batchIndex: batchIndex, underlyingError: error)
|
|
3027
|
+
}
|
|
3028
|
+
|
|
3029
|
+
// Rate limiting between batches
|
|
3030
|
+
if batchIndex < input.chunked(into: batchSize).count - 1 {
|
|
3031
|
+
try await Task.sleep(nanoseconds: 100_000_000) // 100ms delay
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
|
|
3035
|
+
// Phase 2: Post-processing optimization
|
|
3036
|
+
let optimizedResults = try await optimizeTransformedData(transformedResults)
|
|
3037
|
+
|
|
3038
|
+
// Phase 3: Quality assurance
|
|
3039
|
+
let qualityResults = try await performQualityAssurance(optimizedResults)
|
|
3040
|
+
|
|
3041
|
+
// Phase 4: Final reporting
|
|
3042
|
+
let finalReport = await generateProcessingReport(
|
|
3043
|
+
originalCount: input.count,
|
|
3044
|
+
transformedCount: qualityResults.count,
|
|
3045
|
+
monitor: processingMonitor
|
|
3046
|
+
)
|
|
3047
|
+
|
|
3048
|
+
await processingMonitor.saveFinalReport(finalReport)
|
|
3049
|
+
|
|
3050
|
+
return qualityResults
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
// MARK: - Helper Functions and Supporting Types
|
|
3054
|
+
|
|
3055
|
+
private func validateDataItem(_ item: Any, at index: Int) throws -> ValidatedDataItem {
|
|
3056
|
+
// Validation logic here
|
|
3057
|
+
return ValidatedDataItem(data: item, category: .mediumPriority)
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
private func performComplexTransformation(_ data: Any) -> Any {
|
|
3061
|
+
// Complex transformation logic
|
|
3062
|
+
return data
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
private func performDeepAnalysis(_ data: Any) -> AnalysisResult {
|
|
3066
|
+
return AnalysisResult(score: 0.8, confidence: 0.9, metadata: [:])
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
private func calculateQualityScore(_ items: [ProcessedItem]) -> Double {
|
|
3070
|
+
guard !items.isEmpty else { return 0.0 }
|
|
3071
|
+
return items.map(\.analysisScore).reduce(0, +) / Double(items.count)
|
|
3072
|
+
}
|
|
3073
|
+
|
|
3074
|
+
private func optimizeTransformedData(_ data: [TransformedData]) async throws -> [TransformedData] {
|
|
3075
|
+
// Optimization logic
|
|
3076
|
+
return data
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
private func performQualityAssurance(_ data: [TransformedData]) async throws -> [TransformedData] {
|
|
3080
|
+
// Quality assurance logic
|
|
3081
|
+
return data
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
private func generateProcessingReport(originalCount: Int, transformedCount: Int, monitor: ProcessingMonitor) async -> ProcessingReport {
|
|
3085
|
+
return ProcessingReport(
|
|
3086
|
+
totalItemsProcessed: originalCount,
|
|
3087
|
+
successfulItems: transformedCount,
|
|
3088
|
+
errorCount: 0,
|
|
3089
|
+
statistics: ProcessingStatistics(),
|
|
3090
|
+
processingDuration: 0,
|
|
3091
|
+
qualityScore: 1.0
|
|
3092
|
+
)
|
|
3093
|
+
}
|
|
3094
|
+
|
|
3095
|
+
// MARK: - Supporting Data Structures
|
|
3096
|
+
|
|
3097
|
+
struct ProcessedItem {
|
|
3098
|
+
var id: UUID
|
|
3099
|
+
let originalIndex: Int
|
|
3100
|
+
var data: Any
|
|
3101
|
+
let priority: Priority
|
|
3102
|
+
let processingTime: Date
|
|
3103
|
+
var analysisScore: Double = 0.0
|
|
3104
|
+
var confidence: Double = 0.0
|
|
3105
|
+
var metadata: [String: Any] = [:]
|
|
3106
|
+
}
|
|
3107
|
+
|
|
3108
|
+
struct ProcessingResult {
|
|
3109
|
+
let processedItems: [ProcessedItem]
|
|
3110
|
+
let errors: [ProcessingError]
|
|
3111
|
+
let statistics: ProcessingStatistics
|
|
3112
|
+
let report: ProcessingReport
|
|
3113
|
+
}
|
|
3114
|
+
|
|
3115
|
+
struct ProcessingStatistics {
|
|
3116
|
+
var highPriorityCount = 0
|
|
3117
|
+
var mediumPriorityCount = 0
|
|
3118
|
+
var lowPriorityCount = 0
|
|
3119
|
+
var deferredCount = 0
|
|
3120
|
+
var errorCount = 0
|
|
3121
|
+
var complexProcessingCount = 0
|
|
3122
|
+
var rejectedCount = 0
|
|
3123
|
+
var acceptedCount = 0
|
|
3124
|
+
let startTime = Date()
|
|
3125
|
+
}
|
|
3126
|
+
|
|
3127
|
+
struct ProcessingReport {
|
|
3128
|
+
let totalItemsProcessed: Int
|
|
3129
|
+
let successfulItems: Int
|
|
3130
|
+
let errorCount: Int
|
|
3131
|
+
let statistics: ProcessingStatistics
|
|
3132
|
+
let processingDuration: TimeInterval
|
|
3133
|
+
let qualityScore: Double
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
enum Priority {
|
|
3137
|
+
case high, medium, low
|
|
3138
|
+
}
|
|
3139
|
+
|
|
3140
|
+
enum ValidationStatus {
|
|
3141
|
+
case valid, validWithWarnings, invalid, requiresManualReview
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
struct ValidationResult {
|
|
3145
|
+
let status: ValidationStatus
|
|
3146
|
+
let warnings: [String] = []
|
|
3147
|
+
let reason: String = ""
|
|
3148
|
+
let notes: [String] = []
|
|
3149
|
+
}
|
|
3150
|
+
|
|
3151
|
+
struct ValidatedDataItem {
|
|
3152
|
+
let data: Any
|
|
3153
|
+
let category: DataCategory
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
enum DataCategory {
|
|
3157
|
+
case highPriority, mediumPriority, lowPriority, deferred
|
|
3158
|
+
}
|
|
3159
|
+
|
|
3160
|
+
struct ProcessingError: Error {
|
|
3161
|
+
let index: Int
|
|
3162
|
+
let item: Any
|
|
3163
|
+
let error: Error
|
|
3164
|
+
let timestamp: Date
|
|
3165
|
+
|
|
3166
|
+
static func batchProcessingFailed(batchIndex: Int, underlyingError: Error) -> ProcessingError {
|
|
3167
|
+
return ProcessingError(
|
|
3168
|
+
index: batchIndex,
|
|
3169
|
+
item: "Batch \(batchIndex)",
|
|
3170
|
+
error: underlyingError,
|
|
3171
|
+
timestamp: Date()
|
|
3172
|
+
)
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
|
|
3176
|
+
struct ComplexDataStructure {
|
|
3177
|
+
let id: String
|
|
3178
|
+
let data: [String: Any]
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3181
|
+
struct TransformedData {
|
|
3182
|
+
let id: String
|
|
3183
|
+
let transformedData: [String: Any]
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3186
|
+
struct AnalysisResult {
|
|
3187
|
+
let score: Double
|
|
3188
|
+
let confidence: Double
|
|
3189
|
+
let metadata: [String: Any]
|
|
3190
|
+
}
|
|
3191
|
+
|
|
3192
|
+
// Mock classes for compilation
|
|
3193
|
+
class AsyncDataProcessor {
|
|
3194
|
+
func transform(_ item: ComplexDataStructure) async throws -> TransformedData {
|
|
3195
|
+
return TransformedData(id: item.id, transformedData: item.data)
|
|
3196
|
+
}
|
|
3197
|
+
|
|
3198
|
+
func transformWithWarnings(_ item: ComplexDataStructure, warnings: [String]) async throws -> TransformedData {
|
|
3199
|
+
return TransformedData(id: item.id, transformedData: item.data)
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
|
|
3203
|
+
class DataValidator {
|
|
3204
|
+
func validateAsync(_ item: ComplexDataStructure) async throws -> ValidationResult {
|
|
3205
|
+
return ValidationResult(status: .valid)
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
class DataEnhancer {
|
|
3210
|
+
func enhance(_ item: TransformedData) async throws -> TransformedData {
|
|
3211
|
+
return item
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
actor ProcessingMonitor {
|
|
3216
|
+
func startMonitoring() async { }
|
|
3217
|
+
func stopMonitoring() async { }
|
|
3218
|
+
func logBatchStart(_ index: Int, itemCount: Int) async { }
|
|
3219
|
+
func logBatchCompletion(_ index: Int, successCount: Int) async { }
|
|
3220
|
+
func logBatchError(_ index: Int, error: Error) async { }
|
|
3221
|
+
func logInvalidItem(_ item: ComplexDataStructure, reason: String) async { }
|
|
3222
|
+
func queueForManualReview(_ item: ComplexDataStructure, notes: [String]) async { }
|
|
3223
|
+
func saveFinalReport(_ report: ProcessingReport) async { }
|
|
3224
|
+
}
|
|
3225
|
+
"#;
|
|
3226
|
+
|
|
3227
|
+
fs::write(&test_file, content)?;
|
|
3228
|
+
|
|
3229
|
+
let ctx = TestContext::new();
|
|
3230
|
+
let output = ctx.run_probe(&[
|
|
3231
|
+
"search",
|
|
3232
|
+
"function", // Search for functions
|
|
3233
|
+
test_file.to_str().unwrap(),
|
|
3234
|
+
"--format",
|
|
3235
|
+
"outline",
|
|
3236
|
+
])?;
|
|
3237
|
+
|
|
3238
|
+
// Should find both small and large functions
|
|
3239
|
+
let small_functions = [
|
|
3240
|
+
"simpleAdd",
|
|
3241
|
+
"quickCheck",
|
|
3242
|
+
"shortGreeting",
|
|
3243
|
+
"basicValidation",
|
|
3244
|
+
"smallCalculation",
|
|
3245
|
+
];
|
|
3246
|
+
let found_small: Vec<&str> = small_functions
|
|
3247
|
+
.iter()
|
|
3248
|
+
.filter(|&func| output.contains(func))
|
|
3249
|
+
.copied()
|
|
3250
|
+
.collect();
|
|
3251
|
+
|
|
3252
|
+
let large_functions = ["complexDataProcessing", "massiveDataTransformation"];
|
|
3253
|
+
let found_large: Vec<&str> = large_functions
|
|
3254
|
+
.iter()
|
|
3255
|
+
.filter(|&func| output.contains(func))
|
|
3256
|
+
.copied()
|
|
3257
|
+
.collect();
|
|
3258
|
+
|
|
3259
|
+
// Should find functions of various sizes
|
|
3260
|
+
assert!(
|
|
3261
|
+
!found_small.is_empty() || !found_large.is_empty(),
|
|
3262
|
+
"Should find functions of various sizes. Small: {:?}, Large: {:?} - output: {}",
|
|
3263
|
+
found_small,
|
|
3264
|
+
found_large,
|
|
3265
|
+
output
|
|
3266
|
+
);
|
|
3267
|
+
|
|
3268
|
+
// Check closing brace behavior - large functions should have them
|
|
3269
|
+
let has_closing_brace_comments = output.contains("} //");
|
|
3270
|
+
if !found_large.is_empty() {
|
|
3271
|
+
assert!(
|
|
3272
|
+
has_closing_brace_comments,
|
|
3273
|
+
"Large functions should have closing brace comments with Swift // syntax - output: {}",
|
|
3274
|
+
output
|
|
3275
|
+
);
|
|
3276
|
+
}
|
|
3277
|
+
|
|
3278
|
+
// Verify small functions do NOT have closing brace comments if they appear in output
|
|
3279
|
+
if !found_small.is_empty() {
|
|
3280
|
+
let small_func_lines: Vec<&str> = output
|
|
3281
|
+
.lines()
|
|
3282
|
+
.filter(|line| small_functions.iter().any(|&func| line.contains(func)))
|
|
3283
|
+
.collect();
|
|
3284
|
+
|
|
3285
|
+
// Check if any small function lines have closing brace comments
|
|
3286
|
+
let small_func_has_closing_comments = small_func_lines
|
|
3287
|
+
.iter()
|
|
3288
|
+
.any(|line| line.contains("} //") || line.contains("} /*"));
|
|
3289
|
+
|
|
3290
|
+
// Small functions should NOT have closing brace comments
|
|
3291
|
+
if small_func_has_closing_comments {
|
|
3292
|
+
println!("Warning: Small functions appear to have closing brace comments");
|
|
3293
|
+
}
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
// Should detect different function complexity levels
|
|
3297
|
+
let complexity_indicators = ["Phase", "batch", "async", "await", "complex", "validation"];
|
|
3298
|
+
let found_complexity: Vec<&str> = complexity_indicators
|
|
3299
|
+
.iter()
|
|
3300
|
+
.filter(|&indicator| output.contains(indicator))
|
|
3301
|
+
.copied()
|
|
3302
|
+
.collect();
|
|
3303
|
+
|
|
3304
|
+
assert!(
|
|
3305
|
+
!found_complexity.is_empty(),
|
|
3306
|
+
"Should detect function complexity indicators. Found: {:?} - output: {}",
|
|
3307
|
+
found_complexity,
|
|
3308
|
+
output
|
|
3309
|
+
);
|
|
3310
|
+
|
|
3311
|
+
// Should be in outline format
|
|
3312
|
+
assert!(
|
|
3313
|
+
output.contains("---\nFile:"),
|
|
3314
|
+
"Missing file delimiter in outline format - output: {}",
|
|
3315
|
+
output
|
|
3316
|
+
);
|
|
3317
|
+
|
|
3318
|
+
Ok(())
|
|
3319
|
+
}
|