@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,2587 @@
|
|
|
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_go_outline_basic_symbols() -> Result<()> {
|
|
10
|
+
let temp_dir = TempDir::new()?;
|
|
11
|
+
let test_file = temp_dir.path().join("basic.go");
|
|
12
|
+
|
|
13
|
+
let content = r#"// Package calculator provides arithmetic operations
|
|
14
|
+
package calculator
|
|
15
|
+
|
|
16
|
+
import (
|
|
17
|
+
"fmt"
|
|
18
|
+
"math"
|
|
19
|
+
"errors"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
// Calculator represents a calculator with history tracking
|
|
23
|
+
type Calculator struct {
|
|
24
|
+
Name string
|
|
25
|
+
History []float64
|
|
26
|
+
precision int
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// CalculatorInterface defines the contract for calculator operations
|
|
30
|
+
type CalculatorInterface interface {
|
|
31
|
+
Add(x, y float64) float64
|
|
32
|
+
Subtract(x, y float64) float64
|
|
33
|
+
Multiply(x, y float64) float64
|
|
34
|
+
Divide(x, y float64) (float64, error)
|
|
35
|
+
GetHistory() []float64
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Operation represents a mathematical operation
|
|
39
|
+
type Operation int
|
|
40
|
+
|
|
41
|
+
const (
|
|
42
|
+
// Addition represents the addition operation
|
|
43
|
+
Addition Operation = iota
|
|
44
|
+
// Subtraction represents the subtraction operation
|
|
45
|
+
Subtraction
|
|
46
|
+
// Multiplication represents the multiplication operation
|
|
47
|
+
Multiplication
|
|
48
|
+
// Division represents the division operation
|
|
49
|
+
Division
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
var (
|
|
53
|
+
// DefaultPrecision is the default decimal precision
|
|
54
|
+
DefaultPrecision = 2
|
|
55
|
+
// ErrDivisionByZero is returned when dividing by zero
|
|
56
|
+
ErrDivisionByZero = errors.New("division by zero")
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
// NewCalculator creates a new calculator instance
|
|
60
|
+
func NewCalculator(name string) *Calculator {
|
|
61
|
+
return &Calculator{
|
|
62
|
+
Name: name,
|
|
63
|
+
History: make([]float64, 0),
|
|
64
|
+
precision: DefaultPrecision,
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Add adds two numbers and returns the result
|
|
69
|
+
func (c *Calculator) Add(x, y float64) float64 {
|
|
70
|
+
result := x + y
|
|
71
|
+
c.recordOperation(result)
|
|
72
|
+
return c.roundToPrecision(result)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Subtract subtracts y from x and returns the result
|
|
76
|
+
func (c *Calculator) Subtract(x, y float64) float64 {
|
|
77
|
+
result := x - y
|
|
78
|
+
c.recordOperation(result)
|
|
79
|
+
return c.roundToPrecision(result)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Multiply multiplies two numbers and returns the result
|
|
83
|
+
func (c *Calculator) Multiply(x, y float64) float64 {
|
|
84
|
+
result := x * y
|
|
85
|
+
c.recordOperation(result)
|
|
86
|
+
return c.roundToPrecision(result)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Divide divides x by y and returns the result and any error
|
|
90
|
+
func (c *Calculator) Divide(x, y float64) (float64, error) {
|
|
91
|
+
if y == 0 {
|
|
92
|
+
return 0, ErrDivisionByZero
|
|
93
|
+
}
|
|
94
|
+
result := x / y
|
|
95
|
+
c.recordOperation(result)
|
|
96
|
+
return c.roundToPrecision(result), nil
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// GetHistory returns a copy of the calculation history
|
|
100
|
+
func (c *Calculator) GetHistory() []float64 {
|
|
101
|
+
history := make([]float64, len(c.History))
|
|
102
|
+
copy(history, c.History)
|
|
103
|
+
return history
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ClearHistory clears the calculation history
|
|
107
|
+
func (c *Calculator) ClearHistory() {
|
|
108
|
+
c.History = c.History[:0]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// SetPrecision sets the decimal precision for results
|
|
112
|
+
func (c *Calculator) SetPrecision(precision int) {
|
|
113
|
+
if precision >= 0 {
|
|
114
|
+
c.precision = precision
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// recordOperation adds a result to the history
|
|
119
|
+
func (c *Calculator) recordOperation(result float64) {
|
|
120
|
+
c.History = append(c.History, result)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// roundToPrecision rounds a value to the calculator's precision
|
|
124
|
+
func (c *Calculator) roundToPrecision(value float64) float64 {
|
|
125
|
+
multiplier := math.Pow(10, float64(c.precision))
|
|
126
|
+
return math.Round(value*multiplier) / multiplier
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// CreateCalculator is a factory function for creating calculators
|
|
130
|
+
func CreateCalculator(name string, precision int) *Calculator {
|
|
131
|
+
calc := NewCalculator(name)
|
|
132
|
+
calc.SetPrecision(precision)
|
|
133
|
+
return calc
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ProcessNumbers processes a slice of numbers using a calculator
|
|
137
|
+
func ProcessNumbers(calc CalculatorInterface, numbers []float64, op Operation) ([]float64, error) {
|
|
138
|
+
if len(numbers) < 2 {
|
|
139
|
+
return nil, errors.New("need at least two numbers")
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
results := make([]float64, 0, len(numbers)-1)
|
|
143
|
+
accumulator := numbers[0]
|
|
144
|
+
|
|
145
|
+
for i := 1; i < len(numbers); i++ {
|
|
146
|
+
var result float64
|
|
147
|
+
var err error
|
|
148
|
+
|
|
149
|
+
switch op {
|
|
150
|
+
case Addition:
|
|
151
|
+
result = calc.Add(accumulator, numbers[i])
|
|
152
|
+
case Subtraction:
|
|
153
|
+
result = calc.Subtract(accumulator, numbers[i])
|
|
154
|
+
case Multiplication:
|
|
155
|
+
result = calc.Multiply(accumulator, numbers[i])
|
|
156
|
+
case Division:
|
|
157
|
+
result, err = calc.Divide(accumulator, numbers[i])
|
|
158
|
+
if err != nil {
|
|
159
|
+
return nil, fmt.Errorf("division error at index %d: %w", i, err)
|
|
160
|
+
}
|
|
161
|
+
default:
|
|
162
|
+
return nil, fmt.Errorf("unsupported operation: %d", op)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
results = append(results, result)
|
|
166
|
+
accumulator = result
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return results, nil
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// init initializes package-level variables
|
|
173
|
+
func init() {
|
|
174
|
+
DefaultPrecision = 4
|
|
175
|
+
fmt.Println("Calculator package initialized")
|
|
176
|
+
}
|
|
177
|
+
"#;
|
|
178
|
+
|
|
179
|
+
fs::write(&test_file, content)?;
|
|
180
|
+
|
|
181
|
+
let ctx = TestContext::new();
|
|
182
|
+
let output = ctx.run_probe(&[
|
|
183
|
+
"search",
|
|
184
|
+
"Calculator",
|
|
185
|
+
test_file.to_str().unwrap(),
|
|
186
|
+
"--format",
|
|
187
|
+
"outline",
|
|
188
|
+
])?;
|
|
189
|
+
|
|
190
|
+
// Verify Go symbols are found
|
|
191
|
+
assert!(
|
|
192
|
+
output.contains("type Calculator struct"),
|
|
193
|
+
"Missing Calculator struct - output: {}",
|
|
194
|
+
output
|
|
195
|
+
);
|
|
196
|
+
assert!(
|
|
197
|
+
output.contains("type CalculatorInterface interface"),
|
|
198
|
+
"Missing CalculatorInterface - output: {}",
|
|
199
|
+
output
|
|
200
|
+
);
|
|
201
|
+
assert!(
|
|
202
|
+
output.contains("type Operation int"),
|
|
203
|
+
"Missing Operation type - output: {}",
|
|
204
|
+
output
|
|
205
|
+
);
|
|
206
|
+
assert!(
|
|
207
|
+
output.contains("func NewCalculator"),
|
|
208
|
+
"Missing NewCalculator function - output: {}",
|
|
209
|
+
output
|
|
210
|
+
);
|
|
211
|
+
assert!(
|
|
212
|
+
output.contains("func (c *Calculator) Add"),
|
|
213
|
+
"Missing Add method - output: {}",
|
|
214
|
+
output
|
|
215
|
+
);
|
|
216
|
+
assert!(
|
|
217
|
+
output.contains("func ProcessNumbers"),
|
|
218
|
+
"Missing ProcessNumbers function - output: {}",
|
|
219
|
+
output
|
|
220
|
+
);
|
|
221
|
+
assert!(
|
|
222
|
+
output.contains("func init"),
|
|
223
|
+
"Missing init function - output: {}",
|
|
224
|
+
output
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
Ok(())
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
#[test]
|
|
231
|
+
fn test_go_outline_control_flow_statements() -> Result<()> {
|
|
232
|
+
let temp_dir = TempDir::new()?;
|
|
233
|
+
let test_file = temp_dir.path().join("control_flow.go");
|
|
234
|
+
|
|
235
|
+
let content = r#"package main
|
|
236
|
+
|
|
237
|
+
import (
|
|
238
|
+
"fmt"
|
|
239
|
+
"math/rand"
|
|
240
|
+
"time"
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
// ComplexAlgorithm demonstrates various control flow statements with gaps
|
|
244
|
+
func ComplexAlgorithm(data []int, threshold int) map[string]int {
|
|
245
|
+
result := make(map[string]int)
|
|
246
|
+
counter := 0
|
|
247
|
+
|
|
248
|
+
// First processing phase with for loop
|
|
249
|
+
for i, item := range data {
|
|
250
|
+
if item > threshold {
|
|
251
|
+
counter++
|
|
252
|
+
|
|
253
|
+
// Complex nested conditions
|
|
254
|
+
if counter%2 == 0 {
|
|
255
|
+
result[fmt.Sprintf("even_%d", counter)] = item
|
|
256
|
+
} else {
|
|
257
|
+
result[fmt.Sprintf("odd_%d", counter)] = item
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Additional processing
|
|
261
|
+
switch {
|
|
262
|
+
case item < 0:
|
|
263
|
+
result[fmt.Sprintf("negative_%d", i)] = item
|
|
264
|
+
case item == 0:
|
|
265
|
+
result["zero"] = 0
|
|
266
|
+
case item > 1000:
|
|
267
|
+
result[fmt.Sprintf("large_%d", i)] = item
|
|
268
|
+
default:
|
|
269
|
+
result[fmt.Sprintf("regular_%d", i)] = item
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Second processing phase with traditional for loop
|
|
275
|
+
for i := 0; i < len(data); i++ {
|
|
276
|
+
value := data[i]
|
|
277
|
+
|
|
278
|
+
switch value {
|
|
279
|
+
case 0:
|
|
280
|
+
result[fmt.Sprintf("zero_index_%d", i)] = 0
|
|
281
|
+
case 1:
|
|
282
|
+
result[fmt.Sprintf("one_index_%d", i)] = 1
|
|
283
|
+
default:
|
|
284
|
+
if value < 0 {
|
|
285
|
+
result[fmt.Sprintf("negative_index_%d", i)] = value
|
|
286
|
+
} else {
|
|
287
|
+
result[fmt.Sprintf("positive_index_%d", i)] = value
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return result
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ProcessMatrix demonstrates nested loops with complex control flow
|
|
296
|
+
func ProcessMatrix(matrix [][]int) [][]int {
|
|
297
|
+
processed := make([][]int, len(matrix))
|
|
298
|
+
|
|
299
|
+
for i, row := range matrix {
|
|
300
|
+
newRow := make([]int, len(row))
|
|
301
|
+
|
|
302
|
+
for j, cell := range row {
|
|
303
|
+
var processedCell int
|
|
304
|
+
|
|
305
|
+
switch {
|
|
306
|
+
case cell > 0:
|
|
307
|
+
processedCell = cell * 2
|
|
308
|
+
case cell < 0:
|
|
309
|
+
if cell < -100 {
|
|
310
|
+
processedCell = cell * -1
|
|
311
|
+
} else {
|
|
312
|
+
processedCell = cell + 100
|
|
313
|
+
}
|
|
314
|
+
default:
|
|
315
|
+
processedCell = 1
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
newRow[j] = processedCell
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
processed[i] = newRow
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return processed
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ProcessWithChannels demonstrates goroutines and channel operations
|
|
328
|
+
func ProcessWithChannels(data []int, workers int) ([]int, error) {
|
|
329
|
+
if len(data) == 0 {
|
|
330
|
+
return nil, fmt.Errorf("empty data slice")
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
jobs := make(chan int, len(data))
|
|
334
|
+
results := make(chan int, len(data))
|
|
335
|
+
processed := make([]int, 0, len(data))
|
|
336
|
+
|
|
337
|
+
// Start workers
|
|
338
|
+
for w := 0; w < workers; w++ {
|
|
339
|
+
go func() {
|
|
340
|
+
for job := range jobs {
|
|
341
|
+
var result int
|
|
342
|
+
|
|
343
|
+
// Complex processing
|
|
344
|
+
switch {
|
|
345
|
+
case job%2 == 0:
|
|
346
|
+
result = job * job
|
|
347
|
+
case job%3 == 0:
|
|
348
|
+
result = job * 3
|
|
349
|
+
case job%5 == 0:
|
|
350
|
+
result = job * 5
|
|
351
|
+
default:
|
|
352
|
+
result = job + 10
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Simulate processing time
|
|
356
|
+
time.Sleep(time.Millisecond * time.Duration(rand.Intn(100)))
|
|
357
|
+
results <- result
|
|
358
|
+
}
|
|
359
|
+
}()
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Send jobs
|
|
363
|
+
go func() {
|
|
364
|
+
for _, job := range data {
|
|
365
|
+
jobs <- job
|
|
366
|
+
}
|
|
367
|
+
close(jobs)
|
|
368
|
+
}()
|
|
369
|
+
|
|
370
|
+
// Collect results
|
|
371
|
+
for i := 0; i < len(data); i++ {
|
|
372
|
+
select {
|
|
373
|
+
case result := <-results:
|
|
374
|
+
processed = append(processed, result)
|
|
375
|
+
case <-time.After(5 * time.Second):
|
|
376
|
+
return nil, fmt.Errorf("timeout waiting for results")
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return processed, nil
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// AnalyzeData demonstrates type assertions and error handling
|
|
384
|
+
func AnalyzeData(input interface{}) (string, error) {
|
|
385
|
+
switch v := input.(type) {
|
|
386
|
+
case nil:
|
|
387
|
+
return "", fmt.Errorf("nil input")
|
|
388
|
+
case string:
|
|
389
|
+
if len(v) == 0 {
|
|
390
|
+
return "", fmt.Errorf("empty string")
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if len(v) > 100 {
|
|
394
|
+
return "large_string", nil
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Check if all digits
|
|
398
|
+
for _, r := range v {
|
|
399
|
+
if r < '0' || r > '9' {
|
|
400
|
+
return "text_string", nil
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return "numeric_string", nil
|
|
404
|
+
|
|
405
|
+
case int:
|
|
406
|
+
switch {
|
|
407
|
+
case v < 0:
|
|
408
|
+
return "negative_int", nil
|
|
409
|
+
case v == 0:
|
|
410
|
+
return "zero_int", nil
|
|
411
|
+
case v <= 10:
|
|
412
|
+
return "small_int", nil
|
|
413
|
+
case v <= 100:
|
|
414
|
+
return "medium_int", nil
|
|
415
|
+
default:
|
|
416
|
+
return "large_int", nil
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
case []int:
|
|
420
|
+
if len(v) == 0 {
|
|
421
|
+
return "empty_slice", nil
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
total := 0
|
|
425
|
+
for _, num := range v {
|
|
426
|
+
total += num
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if total > 1000 {
|
|
430
|
+
return "large_sum_slice", nil
|
|
431
|
+
}
|
|
432
|
+
return "regular_slice", nil
|
|
433
|
+
|
|
434
|
+
default:
|
|
435
|
+
return "", fmt.Errorf("unsupported type: %T", v)
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
func main() {
|
|
440
|
+
data := []int{1, 2, 3, 4, 5, -1, -2, 0, 100, 1001}
|
|
441
|
+
result := ComplexAlgorithm(data, 0)
|
|
442
|
+
fmt.Printf("Complex algorithm result: %+v\n", result)
|
|
443
|
+
|
|
444
|
+
matrix := [][]int{{1, 2}, {-1, 0}, {100, -200}}
|
|
445
|
+
processed := ProcessMatrix(matrix)
|
|
446
|
+
fmt.Printf("Processed matrix: %+v\n", processed)
|
|
447
|
+
|
|
448
|
+
channelResult, err := ProcessWithChannels(data, 3)
|
|
449
|
+
if err != nil {
|
|
450
|
+
fmt.Printf("Channel processing error: %v\n", err)
|
|
451
|
+
} else {
|
|
452
|
+
fmt.Printf("Channel result: %+v\n", channelResult)
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
analysis, _ := AnalyzeData("12345")
|
|
456
|
+
fmt.Printf("Analysis result: %s\n", analysis)
|
|
457
|
+
}
|
|
458
|
+
"#;
|
|
459
|
+
|
|
460
|
+
fs::write(&test_file, content)?;
|
|
461
|
+
|
|
462
|
+
let ctx = TestContext::new();
|
|
463
|
+
let output = ctx.run_probe(&[
|
|
464
|
+
"search",
|
|
465
|
+
"Algorithm",
|
|
466
|
+
test_file.to_str().unwrap(),
|
|
467
|
+
"--format",
|
|
468
|
+
"outline",
|
|
469
|
+
])?;
|
|
470
|
+
|
|
471
|
+
// Verify control flow structures
|
|
472
|
+
assert!(
|
|
473
|
+
output.contains("func ComplexAlgorithm"),
|
|
474
|
+
"Missing ComplexAlgorithm function - output: {}",
|
|
475
|
+
output
|
|
476
|
+
);
|
|
477
|
+
assert!(
|
|
478
|
+
output.contains("func ProcessMatrix"),
|
|
479
|
+
"Missing ProcessMatrix function - output: {}",
|
|
480
|
+
output
|
|
481
|
+
);
|
|
482
|
+
assert!(
|
|
483
|
+
output.contains("func ProcessWithChannels"),
|
|
484
|
+
"Missing ProcessWithChannels function - output: {}",
|
|
485
|
+
output
|
|
486
|
+
);
|
|
487
|
+
assert!(
|
|
488
|
+
output.contains("func AnalyzeData"),
|
|
489
|
+
"Missing AnalyzeData function - output: {}",
|
|
490
|
+
output
|
|
491
|
+
);
|
|
492
|
+
assert!(
|
|
493
|
+
output.contains("func main"),
|
|
494
|
+
"Missing main function - output: {}",
|
|
495
|
+
output
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
// Should contain control flow keywords
|
|
499
|
+
let has_control_flow = output.contains("for ")
|
|
500
|
+
|| output.contains("switch ")
|
|
501
|
+
|| output.contains("if ")
|
|
502
|
+
|| output.contains("select ");
|
|
503
|
+
assert!(
|
|
504
|
+
has_control_flow,
|
|
505
|
+
"Missing control flow statements - output: {}",
|
|
506
|
+
output
|
|
507
|
+
);
|
|
508
|
+
|
|
509
|
+
// Should contain closing braces
|
|
510
|
+
assert!(
|
|
511
|
+
output.contains("}"),
|
|
512
|
+
"Missing closing braces - output: {}",
|
|
513
|
+
output
|
|
514
|
+
);
|
|
515
|
+
|
|
516
|
+
Ok(())
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
#[test]
|
|
520
|
+
fn test_go_outline_interfaces_and_structs() -> Result<()> {
|
|
521
|
+
let temp_dir = TempDir::new()?;
|
|
522
|
+
let test_file = temp_dir.path().join("interfaces_structs.go");
|
|
523
|
+
|
|
524
|
+
let content = r#"package main
|
|
525
|
+
|
|
526
|
+
import (
|
|
527
|
+
"encoding/json"
|
|
528
|
+
"fmt"
|
|
529
|
+
"io"
|
|
530
|
+
"time"
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
// Reader interface embeds io.Reader with additional methods
|
|
534
|
+
type Reader interface {
|
|
535
|
+
io.Reader
|
|
536
|
+
Reset()
|
|
537
|
+
Size() int64
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Writer interface combines multiple interfaces
|
|
541
|
+
type Writer interface {
|
|
542
|
+
io.Writer
|
|
543
|
+
io.Closer
|
|
544
|
+
Flush() error
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Processor interface defines data processing contract
|
|
548
|
+
type Processor interface {
|
|
549
|
+
Process(data []byte) ([]byte, error)
|
|
550
|
+
SetOptions(options map[string]interface{})
|
|
551
|
+
GetStats() ProcessingStats
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// ProcessingStats represents processing statistics
|
|
555
|
+
type ProcessingStats struct {
|
|
556
|
+
BytesProcessed int64 `json:"bytes_processed"`
|
|
557
|
+
Duration time.Duration `json:"duration"`
|
|
558
|
+
ErrorCount int `json:"error_count"`
|
|
559
|
+
StartTime time.Time `json:"start_time"`
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// User represents a user entity with JSON tags
|
|
563
|
+
type User struct {
|
|
564
|
+
ID string `json:"id" db:"id"`
|
|
565
|
+
Username string `json:"username" db:"username" validate:"required,min=3,max=20"`
|
|
566
|
+
Email string `json:"email" db:"email" validate:"required,email"`
|
|
567
|
+
FirstName string `json:"first_name" db:"first_name"`
|
|
568
|
+
LastName string `json:"last_name" db:"last_name"`
|
|
569
|
+
Age int `json:"age" db:"age" validate:"min=0,max=150"`
|
|
570
|
+
IsActive bool `json:"is_active" db:"is_active"`
|
|
571
|
+
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
572
|
+
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// DataProcessor implements the Processor interface
|
|
576
|
+
type DataProcessor struct {
|
|
577
|
+
options map[string]interface{}
|
|
578
|
+
stats ProcessingStats
|
|
579
|
+
buffer []byte
|
|
580
|
+
maxSize int64
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// NewDataProcessor creates a new data processor
|
|
584
|
+
func NewDataProcessor(maxSize int64) *DataProcessor {
|
|
585
|
+
return &DataProcessor{
|
|
586
|
+
options: make(map[string]interface{}),
|
|
587
|
+
stats: ProcessingStats{
|
|
588
|
+
StartTime: time.Now(),
|
|
589
|
+
},
|
|
590
|
+
maxSize: maxSize,
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Process processes the input data according to configured options
|
|
595
|
+
func (dp *DataProcessor) Process(data []byte) ([]byte, error) {
|
|
596
|
+
dp.stats.StartTime = time.Now()
|
|
597
|
+
start := time.Now()
|
|
598
|
+
|
|
599
|
+
// Validate input size
|
|
600
|
+
if int64(len(data)) > dp.maxSize {
|
|
601
|
+
dp.stats.ErrorCount++
|
|
602
|
+
return nil, fmt.Errorf("data size %d exceeds maximum %d", len(data), dp.maxSize)
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// Process based on options
|
|
606
|
+
result := make([]byte, 0, len(data))
|
|
607
|
+
|
|
608
|
+
if compress, ok := dp.options["compress"].(bool); ok && compress {
|
|
609
|
+
// Simulate compression
|
|
610
|
+
for i, b := range data {
|
|
611
|
+
if i%2 == 0 {
|
|
612
|
+
result = append(result, b)
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
} else {
|
|
616
|
+
result = append(result, data...)
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if transform, ok := dp.options["transform"].(string); ok {
|
|
620
|
+
switch transform {
|
|
621
|
+
case "uppercase":
|
|
622
|
+
for i, b := range result {
|
|
623
|
+
if b >= 'a' && b <= 'z' {
|
|
624
|
+
result[i] = b - 32
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
case "lowercase":
|
|
628
|
+
for i, b := range result {
|
|
629
|
+
if b >= 'A' && b <= 'Z' {
|
|
630
|
+
result[i] = b + 32
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
dp.stats.BytesProcessed += int64(len(data))
|
|
637
|
+
dp.stats.Duration += time.Since(start)
|
|
638
|
+
|
|
639
|
+
return result, nil
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// SetOptions sets processing options
|
|
643
|
+
func (dp *DataProcessor) SetOptions(options map[string]interface{}) {
|
|
644
|
+
if dp.options == nil {
|
|
645
|
+
dp.options = make(map[string]interface{})
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
for k, v := range options {
|
|
649
|
+
dp.options[k] = v
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// GetStats returns current processing statistics
|
|
654
|
+
func (dp *DataProcessor) GetStats() ProcessingStats {
|
|
655
|
+
return dp.stats
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// UserRepository defines user storage operations
|
|
659
|
+
type UserRepository interface {
|
|
660
|
+
Create(user *User) error
|
|
661
|
+
GetByID(id string) (*User, error)
|
|
662
|
+
GetByUsername(username string) (*User, error)
|
|
663
|
+
Update(user *User) error
|
|
664
|
+
Delete(id string) error
|
|
665
|
+
List(offset, limit int) ([]*User, error)
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// InMemoryUserRepository implements UserRepository for testing
|
|
669
|
+
type InMemoryUserRepository struct {
|
|
670
|
+
users map[string]*User
|
|
671
|
+
counter int
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// NewInMemoryUserRepository creates a new in-memory repository
|
|
675
|
+
func NewInMemoryUserRepository() *InMemoryUserRepository {
|
|
676
|
+
return &InMemoryUserRepository{
|
|
677
|
+
users: make(map[string]*User),
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Create adds a new user to the repository
|
|
682
|
+
func (r *InMemoryUserRepository) Create(user *User) error {
|
|
683
|
+
if user == nil {
|
|
684
|
+
return fmt.Errorf("user cannot be nil")
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if user.ID == "" {
|
|
688
|
+
r.counter++
|
|
689
|
+
user.ID = fmt.Sprintf("user_%d", r.counter)
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if _, exists := r.users[user.ID]; exists {
|
|
693
|
+
return fmt.Errorf("user with ID %s already exists", user.ID)
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
user.CreatedAt = time.Now()
|
|
697
|
+
user.UpdatedAt = user.CreatedAt
|
|
698
|
+
r.users[user.ID] = user
|
|
699
|
+
|
|
700
|
+
return nil
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// GetByID retrieves a user by ID
|
|
704
|
+
func (r *InMemoryUserRepository) GetByID(id string) (*User, error) {
|
|
705
|
+
if id == "" {
|
|
706
|
+
return nil, fmt.Errorf("id cannot be empty")
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
user, exists := r.users[id]
|
|
710
|
+
if !exists {
|
|
711
|
+
return nil, fmt.Errorf("user with ID %s not found", id)
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// Return a copy to prevent external modifications
|
|
715
|
+
userCopy := *user
|
|
716
|
+
return &userCopy, nil
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// GetByUsername retrieves a user by username
|
|
720
|
+
func (r *InMemoryUserRepository) GetByUsername(username string) (*User, error) {
|
|
721
|
+
if username == "" {
|
|
722
|
+
return nil, fmt.Errorf("username cannot be empty")
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
for _, user := range r.users {
|
|
726
|
+
if user.Username == username {
|
|
727
|
+
userCopy := *user
|
|
728
|
+
return &userCopy, nil
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
return nil, fmt.Errorf("user with username %s not found", username)
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// Update modifies an existing user
|
|
736
|
+
func (r *InMemoryUserRepository) Update(user *User) error {
|
|
737
|
+
if user == nil || user.ID == "" {
|
|
738
|
+
return fmt.Errorf("user and ID cannot be nil/empty")
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if _, exists := r.users[user.ID]; !exists {
|
|
742
|
+
return fmt.Errorf("user with ID %s not found", user.ID)
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
user.UpdatedAt = time.Now()
|
|
746
|
+
r.users[user.ID] = user
|
|
747
|
+
|
|
748
|
+
return nil
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Delete removes a user from the repository
|
|
752
|
+
func (r *InMemoryUserRepository) Delete(id string) error {
|
|
753
|
+
if id == "" {
|
|
754
|
+
return fmt.Errorf("id cannot be empty")
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
if _, exists := r.users[id]; !exists {
|
|
758
|
+
return fmt.Errorf("user with ID %s not found", id)
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
delete(r.users, id)
|
|
762
|
+
return nil
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// List returns a paginated list of users
|
|
766
|
+
func (r *InMemoryUserRepository) List(offset, limit int) ([]*User, error) {
|
|
767
|
+
if offset < 0 || limit <= 0 {
|
|
768
|
+
return nil, fmt.Errorf("invalid offset or limit")
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
users := make([]*User, 0, len(r.users))
|
|
772
|
+
for _, user := range r.users {
|
|
773
|
+
users = append(users, user)
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Simple pagination
|
|
777
|
+
start := offset
|
|
778
|
+
end := offset + limit
|
|
779
|
+
|
|
780
|
+
if start >= len(users) {
|
|
781
|
+
return []*User{}, nil
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
if end > len(users) {
|
|
785
|
+
end = len(users)
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
result := make([]*User, 0, end-start)
|
|
789
|
+
for i := start; i < end; i++ {
|
|
790
|
+
userCopy := *users[i]
|
|
791
|
+
result = append(result, &userCopy)
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
return result, nil
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// ToJSON converts a user to JSON bytes
|
|
798
|
+
func (u *User) ToJSON() ([]byte, error) {
|
|
799
|
+
return json.Marshal(u)
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// FromJSON populates a user from JSON bytes
|
|
803
|
+
func (u *User) FromJSON(data []byte) error {
|
|
804
|
+
return json.Unmarshal(data, u)
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// IsValid performs basic validation on the user
|
|
808
|
+
func (u *User) IsValid() error {
|
|
809
|
+
if u.Username == "" {
|
|
810
|
+
return fmt.Errorf("username is required")
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if len(u.Username) < 3 || len(u.Username) > 20 {
|
|
814
|
+
return fmt.Errorf("username must be 3-20 characters")
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if u.Email == "" {
|
|
818
|
+
return fmt.Errorf("email is required")
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
if u.Age < 0 || u.Age > 150 {
|
|
822
|
+
return fmt.Errorf("age must be between 0 and 150")
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
return nil
|
|
826
|
+
}
|
|
827
|
+
"#;
|
|
828
|
+
|
|
829
|
+
fs::write(&test_file, content)?;
|
|
830
|
+
|
|
831
|
+
let ctx = TestContext::new();
|
|
832
|
+
let output = ctx.run_probe(&[
|
|
833
|
+
"search",
|
|
834
|
+
"type",
|
|
835
|
+
test_file.to_str().unwrap(),
|
|
836
|
+
"--format",
|
|
837
|
+
"outline",
|
|
838
|
+
])?;
|
|
839
|
+
|
|
840
|
+
// Verify interfaces and structs
|
|
841
|
+
assert!(
|
|
842
|
+
output.contains("type Reader interface"),
|
|
843
|
+
"Missing Reader interface - output: {}",
|
|
844
|
+
output
|
|
845
|
+
);
|
|
846
|
+
assert!(
|
|
847
|
+
output.contains("type Processor interface"),
|
|
848
|
+
"Missing Processor interface - output: {}",
|
|
849
|
+
output
|
|
850
|
+
);
|
|
851
|
+
assert!(
|
|
852
|
+
output.contains("type ProcessingStats struct"),
|
|
853
|
+
"Missing ProcessingStats struct - output: {}",
|
|
854
|
+
output
|
|
855
|
+
);
|
|
856
|
+
assert!(
|
|
857
|
+
output.contains("type User struct"),
|
|
858
|
+
"Missing User struct - output: {}",
|
|
859
|
+
output
|
|
860
|
+
);
|
|
861
|
+
assert!(
|
|
862
|
+
output.contains("type DataProcessor struct"),
|
|
863
|
+
"Missing DataProcessor struct - output: {}",
|
|
864
|
+
output
|
|
865
|
+
);
|
|
866
|
+
assert!(
|
|
867
|
+
output.contains("type InMemoryUserRepository struct"),
|
|
868
|
+
"Missing InMemoryUserRepository struct - output: {}",
|
|
869
|
+
output
|
|
870
|
+
);
|
|
871
|
+
assert!(
|
|
872
|
+
output.contains("func NewDataProcessor"),
|
|
873
|
+
"Missing constructor function - output: {}",
|
|
874
|
+
output
|
|
875
|
+
);
|
|
876
|
+
|
|
877
|
+
Ok(())
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
#[test]
|
|
881
|
+
fn test_go_outline_test_patterns() -> Result<()> {
|
|
882
|
+
let temp_dir = TempDir::new()?;
|
|
883
|
+
let test_file = temp_dir.path().join("test_patterns_test.go");
|
|
884
|
+
|
|
885
|
+
let content = r#"package calculator
|
|
886
|
+
|
|
887
|
+
import (
|
|
888
|
+
"testing"
|
|
889
|
+
"reflect"
|
|
890
|
+
"fmt"
|
|
891
|
+
)
|
|
892
|
+
|
|
893
|
+
// TestCalculatorAdd tests the Add method
|
|
894
|
+
func TestCalculatorAdd(t *testing.T) {
|
|
895
|
+
calc := NewCalculator("Test")
|
|
896
|
+
|
|
897
|
+
tests := []struct {
|
|
898
|
+
name string
|
|
899
|
+
x, y float64
|
|
900
|
+
expected float64
|
|
901
|
+
}{
|
|
902
|
+
{"positive numbers", 2.5, 3.5, 6.0},
|
|
903
|
+
{"negative numbers", -2.5, -1.5, -4.0},
|
|
904
|
+
{"mixed signs", -2.5, 3.5, 1.0},
|
|
905
|
+
{"with zero", 0, 5.5, 5.5},
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
for _, tt := range tests {
|
|
909
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
910
|
+
result := calc.Add(tt.x, tt.y)
|
|
911
|
+
if result != tt.expected {
|
|
912
|
+
t.Errorf("Add(%v, %v) = %v, want %v", tt.x, tt.y, result, tt.expected)
|
|
913
|
+
}
|
|
914
|
+
})
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// TestCalculatorDivide tests division with error handling
|
|
919
|
+
func TestCalculatorDivide(t *testing.T) {
|
|
920
|
+
calc := NewCalculator("Test")
|
|
921
|
+
|
|
922
|
+
// Test successful division
|
|
923
|
+
result, err := calc.Divide(10, 2)
|
|
924
|
+
if err != nil {
|
|
925
|
+
t.Fatalf("Unexpected error: %v", err)
|
|
926
|
+
}
|
|
927
|
+
if result != 5.0 {
|
|
928
|
+
t.Errorf("Divide(10, 2) = %v, want 5.0", result)
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// Test division by zero
|
|
932
|
+
_, err = calc.Divide(10, 0)
|
|
933
|
+
if err == nil {
|
|
934
|
+
t.Error("Expected error for division by zero, got nil")
|
|
935
|
+
}
|
|
936
|
+
if err != ErrDivisionByZero {
|
|
937
|
+
t.Errorf("Expected ErrDivisionByZero, got %v", err)
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
// TestCalculatorHistory tests history tracking
|
|
942
|
+
func TestCalculatorHistory(t *testing.T) {
|
|
943
|
+
calc := NewCalculator("Test")
|
|
944
|
+
|
|
945
|
+
// Initially empty
|
|
946
|
+
history := calc.GetHistory()
|
|
947
|
+
if len(history) != 0 {
|
|
948
|
+
t.Errorf("Expected empty history, got %v", history)
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// Add some operations
|
|
952
|
+
calc.Add(1, 2)
|
|
953
|
+
calc.Subtract(5, 3)
|
|
954
|
+
calc.Multiply(2, 4)
|
|
955
|
+
|
|
956
|
+
history = calc.GetHistory()
|
|
957
|
+
expected := []float64{3.0, 2.0, 8.0}
|
|
958
|
+
|
|
959
|
+
if !reflect.DeepEqual(history, expected) {
|
|
960
|
+
t.Errorf("History = %v, want %v", history, expected)
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// Test clear history
|
|
964
|
+
calc.ClearHistory()
|
|
965
|
+
history = calc.GetHistory()
|
|
966
|
+
if len(history) != 0 {
|
|
967
|
+
t.Errorf("Expected empty history after clear, got %v", history)
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// BenchmarkCalculatorAdd benchmarks the Add method
|
|
972
|
+
func BenchmarkCalculatorAdd(b *testing.B) {
|
|
973
|
+
calc := NewCalculator("Benchmark")
|
|
974
|
+
|
|
975
|
+
b.ResetTimer()
|
|
976
|
+
for i := 0; i < b.N; i++ {
|
|
977
|
+
calc.Add(float64(i), float64(i+1))
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// BenchmarkCalculatorOperations benchmarks all operations
|
|
982
|
+
func BenchmarkCalculatorOperations(b *testing.B) {
|
|
983
|
+
calc := NewCalculator("Benchmark")
|
|
984
|
+
|
|
985
|
+
benchmarks := []struct {
|
|
986
|
+
name string
|
|
987
|
+
fn func()
|
|
988
|
+
}{
|
|
989
|
+
{"Add", func() { calc.Add(10.5, 20.3) }},
|
|
990
|
+
{"Subtract", func() { calc.Subtract(30.7, 15.2) }},
|
|
991
|
+
{"Multiply", func() { calc.Multiply(5.5, 7.8) }},
|
|
992
|
+
{"Divide", func() { calc.Divide(100.0, 4.0) }},
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
for _, bm := range benchmarks {
|
|
996
|
+
b.Run(bm.name, func(b *testing.B) {
|
|
997
|
+
for i := 0; i < b.N; i++ {
|
|
998
|
+
bm.fn()
|
|
999
|
+
}
|
|
1000
|
+
})
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
// TestProcessNumbers tests the ProcessNumbers function
|
|
1005
|
+
func TestProcessNumbers(t *testing.T) {
|
|
1006
|
+
calc := NewCalculator("Test")
|
|
1007
|
+
|
|
1008
|
+
tests := []struct {
|
|
1009
|
+
name string
|
|
1010
|
+
numbers []float64
|
|
1011
|
+
operation Operation
|
|
1012
|
+
expected []float64
|
|
1013
|
+
wantError bool
|
|
1014
|
+
}{
|
|
1015
|
+
{
|
|
1016
|
+
name: "addition",
|
|
1017
|
+
numbers: []float64{1, 2, 3, 4},
|
|
1018
|
+
operation: Addition,
|
|
1019
|
+
expected: []float64{3, 6, 10},
|
|
1020
|
+
wantError: false,
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
name: "multiplication",
|
|
1024
|
+
numbers: []float64{2, 3, 4},
|
|
1025
|
+
operation: Multiplication,
|
|
1026
|
+
expected: []float64{6, 24},
|
|
1027
|
+
wantError: false,
|
|
1028
|
+
},
|
|
1029
|
+
{
|
|
1030
|
+
name: "division with zero",
|
|
1031
|
+
numbers: []float64{10, 0, 5},
|
|
1032
|
+
operation: Division,
|
|
1033
|
+
wantError: true,
|
|
1034
|
+
},
|
|
1035
|
+
{
|
|
1036
|
+
name: "empty slice",
|
|
1037
|
+
numbers: []float64{},
|
|
1038
|
+
operation: Addition,
|
|
1039
|
+
wantError: true,
|
|
1040
|
+
},
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
for _, tt := range tests {
|
|
1044
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
1045
|
+
result, err := ProcessNumbers(calc, tt.numbers, tt.operation)
|
|
1046
|
+
|
|
1047
|
+
if tt.wantError {
|
|
1048
|
+
if err == nil {
|
|
1049
|
+
t.Error("Expected error, got nil")
|
|
1050
|
+
}
|
|
1051
|
+
return
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
if err != nil {
|
|
1055
|
+
t.Fatalf("Unexpected error: %v", err)
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
if !reflect.DeepEqual(result, tt.expected) {
|
|
1059
|
+
t.Errorf("ProcessNumbers() = %v, want %v", result, tt.expected)
|
|
1060
|
+
}
|
|
1061
|
+
})
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// ExampleCalculator demonstrates calculator usage
|
|
1066
|
+
func ExampleCalculator() {
|
|
1067
|
+
calc := NewCalculator("Demo")
|
|
1068
|
+
|
|
1069
|
+
result := calc.Add(10, 20)
|
|
1070
|
+
fmt.Printf("10 + 20 = %.1f\n", result)
|
|
1071
|
+
|
|
1072
|
+
result = calc.Multiply(5, 6)
|
|
1073
|
+
fmt.Printf("5 * 6 = %.1f\n", result)
|
|
1074
|
+
|
|
1075
|
+
history := calc.GetHistory()
|
|
1076
|
+
fmt.Printf("History: %v\n", history)
|
|
1077
|
+
|
|
1078
|
+
// Output:
|
|
1079
|
+
// 10 + 20 = 30.0
|
|
1080
|
+
// 5 * 6 = 30.0
|
|
1081
|
+
// History: [30 30]
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
// ExampleProcessNumbers demonstrates ProcessNumbers function
|
|
1085
|
+
func ExampleProcessNumbers() {
|
|
1086
|
+
calc := NewCalculator("Example")
|
|
1087
|
+
numbers := []float64{2, 4, 6}
|
|
1088
|
+
|
|
1089
|
+
result, err := ProcessNumbers(calc, numbers, Multiplication)
|
|
1090
|
+
if err != nil {
|
|
1091
|
+
fmt.Printf("Error: %v\n", err)
|
|
1092
|
+
return
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
fmt.Printf("Results: %v\n", result)
|
|
1096
|
+
// Output: Results: [8 48]
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// TestMain sets up and tears down test environment
|
|
1100
|
+
func TestMain(m *testing.M) {
|
|
1101
|
+
fmt.Println("Setting up tests...")
|
|
1102
|
+
|
|
1103
|
+
// Run tests
|
|
1104
|
+
code := m.Run()
|
|
1105
|
+
|
|
1106
|
+
fmt.Println("Cleaning up tests...")
|
|
1107
|
+
|
|
1108
|
+
// Exit with the test result code
|
|
1109
|
+
fmt.Printf("Tests completed with code: %d\n", code)
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
// Helper functions for testing
|
|
1113
|
+
func setupTestCalculator() *Calculator {
|
|
1114
|
+
return NewCalculator("TestCalc")
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
func assertFloatEqual(t *testing.T, got, want float64) {
|
|
1118
|
+
const epsilon = 1e-9
|
|
1119
|
+
if diff := got - want; diff < -epsilon || diff > epsilon {
|
|
1120
|
+
t.Errorf("got %v, want %v (diff: %v)", got, want, diff)
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
func createTestData(size int) []float64 {
|
|
1125
|
+
data := make([]float64, size)
|
|
1126
|
+
for i := 0; i < size; i++ {
|
|
1127
|
+
data[i] = float64(i + 1)
|
|
1128
|
+
}
|
|
1129
|
+
return data
|
|
1130
|
+
}
|
|
1131
|
+
"#;
|
|
1132
|
+
|
|
1133
|
+
fs::write(&test_file, content)?;
|
|
1134
|
+
|
|
1135
|
+
let ctx = TestContext::new();
|
|
1136
|
+
let output = ctx.run_probe(&[
|
|
1137
|
+
"search",
|
|
1138
|
+
"Test",
|
|
1139
|
+
test_file.to_str().unwrap(),
|
|
1140
|
+
"--format",
|
|
1141
|
+
"outline",
|
|
1142
|
+
"--allow-tests",
|
|
1143
|
+
])?;
|
|
1144
|
+
|
|
1145
|
+
// Verify test patterns
|
|
1146
|
+
assert!(
|
|
1147
|
+
output.contains("func TestCalculatorAdd"),
|
|
1148
|
+
"Missing test function - output: {}",
|
|
1149
|
+
output
|
|
1150
|
+
);
|
|
1151
|
+
assert!(
|
|
1152
|
+
output.contains("func TestCalculatorDivide"),
|
|
1153
|
+
"Missing test function with error handling - output: {}",
|
|
1154
|
+
output
|
|
1155
|
+
);
|
|
1156
|
+
assert!(
|
|
1157
|
+
output.contains("func BenchmarkCalculatorAdd"),
|
|
1158
|
+
"Missing benchmark function - output: {}",
|
|
1159
|
+
output
|
|
1160
|
+
);
|
|
1161
|
+
assert!(
|
|
1162
|
+
output.contains("func ExampleCalculator"),
|
|
1163
|
+
"Missing example function - output: {}",
|
|
1164
|
+
output
|
|
1165
|
+
);
|
|
1166
|
+
assert!(
|
|
1167
|
+
output.contains("func TestMain"),
|
|
1168
|
+
"Missing TestMain function - output: {}",
|
|
1169
|
+
output
|
|
1170
|
+
);
|
|
1171
|
+
assert!(
|
|
1172
|
+
output.contains("func setupTestCalculator"),
|
|
1173
|
+
"Missing test helper function - output: {}",
|
|
1174
|
+
output
|
|
1175
|
+
);
|
|
1176
|
+
|
|
1177
|
+
Ok(())
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
#[test]
|
|
1181
|
+
fn test_go_outline_large_function_closing_braces() -> Result<()> {
|
|
1182
|
+
let temp_dir = TempDir::new()?;
|
|
1183
|
+
let test_file = temp_dir.path().join("large_function.go");
|
|
1184
|
+
|
|
1185
|
+
let content = r#"package main
|
|
1186
|
+
|
|
1187
|
+
import (
|
|
1188
|
+
"fmt"
|
|
1189
|
+
"sort"
|
|
1190
|
+
"strings"
|
|
1191
|
+
"time"
|
|
1192
|
+
)
|
|
1193
|
+
|
|
1194
|
+
// ComplexDataProcessor processes data through multiple phases with gaps
|
|
1195
|
+
func ComplexDataProcessor(data []string, options map[string]interface{}) (map[string][]string, error) {
|
|
1196
|
+
results := make(map[string][]string)
|
|
1197
|
+
categories := make(map[string][]string)
|
|
1198
|
+
|
|
1199
|
+
// Phase 1: Input validation and sanitization
|
|
1200
|
+
cleanedData := make([]string, 0, len(data))
|
|
1201
|
+
for i, item := range data {
|
|
1202
|
+
if item == "" {
|
|
1203
|
+
fmt.Printf("Warning: empty item at index %d\n", i)
|
|
1204
|
+
continue
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
// Clean whitespace
|
|
1208
|
+
cleaned := strings.TrimSpace(item)
|
|
1209
|
+
if len(cleaned) == 0 {
|
|
1210
|
+
fmt.Printf("Warning: whitespace-only item at index %d\n", i)
|
|
1211
|
+
continue
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
cleanedData = append(cleanedData, cleaned)
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// Phase 2: Categorization based on content
|
|
1218
|
+
for _, item := range cleanedData {
|
|
1219
|
+
var category string
|
|
1220
|
+
|
|
1221
|
+
// Determine category based on content
|
|
1222
|
+
if strings.HasPrefix(item, "http") {
|
|
1223
|
+
category = "urls"
|
|
1224
|
+
} else if strings.Contains(item, "@") {
|
|
1225
|
+
category = "emails"
|
|
1226
|
+
} else if len(item) <= 10 {
|
|
1227
|
+
// Check if numeric
|
|
1228
|
+
isNumeric := true
|
|
1229
|
+
for _, r := range item {
|
|
1230
|
+
if r < '0' || r > '9' {
|
|
1231
|
+
isNumeric = false
|
|
1232
|
+
break
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
if isNumeric {
|
|
1237
|
+
category = "numbers"
|
|
1238
|
+
} else {
|
|
1239
|
+
category = "short_text"
|
|
1240
|
+
}
|
|
1241
|
+
} else if len(item) > 100 {
|
|
1242
|
+
category = "long_text"
|
|
1243
|
+
} else {
|
|
1244
|
+
category = "medium_text"
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
// Store in category map
|
|
1248
|
+
if categories[category] == nil {
|
|
1249
|
+
categories[category] = make([]string, 0)
|
|
1250
|
+
}
|
|
1251
|
+
categories[category] = append(categories[category], item)
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// Phase 3: Processing each category with specific rules
|
|
1255
|
+
for categoryName, items := range categories {
|
|
1256
|
+
processedItems := make([]string, 0, len(items))
|
|
1257
|
+
|
|
1258
|
+
switch categoryName {
|
|
1259
|
+
case "urls":
|
|
1260
|
+
// URL processing
|
|
1261
|
+
for _, url := range items {
|
|
1262
|
+
if strings.HasPrefix(url, "https://") {
|
|
1263
|
+
processedItems = append(processedItems, fmt.Sprintf("SECURE_URL: %s", url))
|
|
1264
|
+
} else if strings.HasPrefix(url, "http://") {
|
|
1265
|
+
processedItems = append(processedItems, fmt.Sprintf("INSECURE_URL: %s", url))
|
|
1266
|
+
} else {
|
|
1267
|
+
processedItems = append(processedItems, fmt.Sprintf("PARTIAL_URL: %s", url))
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
case "emails":
|
|
1272
|
+
// Email processing with validation
|
|
1273
|
+
for _, email := range items {
|
|
1274
|
+
parts := strings.Split(email, "@")
|
|
1275
|
+
if len(parts) == 2 {
|
|
1276
|
+
domain := parts[1]
|
|
1277
|
+
if strings.Contains(domain, ".") {
|
|
1278
|
+
processedItems = append(processedItems, fmt.Sprintf("VALID_EMAIL: %s", email))
|
|
1279
|
+
} else {
|
|
1280
|
+
processedItems = append(processedItems, fmt.Sprintf("INVALID_DOMAIN: %s", email))
|
|
1281
|
+
}
|
|
1282
|
+
} else {
|
|
1283
|
+
processedItems = append(processedItems, fmt.Sprintf("MALFORMED_EMAIL: %s", email))
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
case "numbers":
|
|
1288
|
+
// Number processing with sorting
|
|
1289
|
+
sort.Strings(items)
|
|
1290
|
+
for i, num := range items {
|
|
1291
|
+
processedItems = append(processedItems, fmt.Sprintf("NUM_%d: %s", i+1, num))
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
case "short_text":
|
|
1295
|
+
// Short text processing - uppercase
|
|
1296
|
+
for _, text := range items {
|
|
1297
|
+
processedItems = append(processedItems, strings.ToUpper(text))
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
case "medium_text":
|
|
1301
|
+
// Medium text processing - title case
|
|
1302
|
+
for _, text := range items {
|
|
1303
|
+
words := strings.Fields(text)
|
|
1304
|
+
titleWords := make([]string, len(words))
|
|
1305
|
+
|
|
1306
|
+
for i, word := range words {
|
|
1307
|
+
if len(word) > 0 {
|
|
1308
|
+
titleWords[i] = strings.ToUpper(word[:1]) + strings.ToLower(word[1:])
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
processedItems = append(processedItems, strings.Join(titleWords, " "))
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
case "long_text":
|
|
1316
|
+
// Long text processing - truncate and summarize
|
|
1317
|
+
for _, text := range items {
|
|
1318
|
+
if len(text) > 200 {
|
|
1319
|
+
truncated := text[:197] + "..."
|
|
1320
|
+
summary := fmt.Sprintf("LONG_TEXT (len=%d): %s", len(text), truncated)
|
|
1321
|
+
processedItems = append(processedItems, summary)
|
|
1322
|
+
} else {
|
|
1323
|
+
processedItems = append(processedItems, fmt.Sprintf("MEDIUM_LONG: %s", text))
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
default:
|
|
1328
|
+
// Default processing - add timestamp
|
|
1329
|
+
timestamp := time.Now().Format("15:04:05")
|
|
1330
|
+
for _, item := range items {
|
|
1331
|
+
processedItems = append(processedItems, fmt.Sprintf("[%s] %s", timestamp, item))
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
results[categoryName] = processedItems
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
// Phase 4: Apply global options and filters
|
|
1339
|
+
if options != nil {
|
|
1340
|
+
if sortResults, ok := options["sort"].(bool); ok && sortResults {
|
|
1341
|
+
for category, items := range results {
|
|
1342
|
+
sort.Strings(items)
|
|
1343
|
+
results[category] = items
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
if maxPerCategory, ok := options["max_per_category"].(int); ok && maxPerCategory > 0 {
|
|
1348
|
+
for category, items := range results {
|
|
1349
|
+
if len(items) > maxPerCategory {
|
|
1350
|
+
results[category] = items[:maxPerCategory]
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
if excludeEmpty, ok := options["exclude_empty"].(bool); ok && excludeEmpty {
|
|
1356
|
+
for category, items := range results {
|
|
1357
|
+
if len(items) == 0 {
|
|
1358
|
+
delete(results, category)
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// Phase 5: Final validation and cleanup
|
|
1365
|
+
finalResults := make(map[string][]string)
|
|
1366
|
+
totalItems := 0
|
|
1367
|
+
|
|
1368
|
+
for category, items := range results {
|
|
1369
|
+
if len(items) > 0 {
|
|
1370
|
+
finalResults[category] = items
|
|
1371
|
+
totalItems += len(items)
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
fmt.Printf("Processing completed: %d items across %d categories\n", totalItems, len(finalResults))
|
|
1376
|
+
return finalResults, nil
|
|
1377
|
+
}
|
|
1378
|
+
"#;
|
|
1379
|
+
|
|
1380
|
+
fs::write(&test_file, content)?;
|
|
1381
|
+
|
|
1382
|
+
let ctx = TestContext::new();
|
|
1383
|
+
let output = ctx.run_probe(&[
|
|
1384
|
+
"search",
|
|
1385
|
+
"ComplexDataProcessor",
|
|
1386
|
+
test_file.to_str().unwrap(),
|
|
1387
|
+
"--format",
|
|
1388
|
+
"outline",
|
|
1389
|
+
])?;
|
|
1390
|
+
|
|
1391
|
+
// Verify large function is shown with closing braces
|
|
1392
|
+
assert!(
|
|
1393
|
+
output.contains("func ComplexDataProcessor"),
|
|
1394
|
+
"Missing ComplexDataProcessor function - output: {}",
|
|
1395
|
+
output
|
|
1396
|
+
);
|
|
1397
|
+
|
|
1398
|
+
// Should have closing braces for large blocks
|
|
1399
|
+
let closing_braces_count = output.matches("}").count();
|
|
1400
|
+
assert!(
|
|
1401
|
+
closing_braces_count >= 3,
|
|
1402
|
+
"Should have multiple closing braces for nested blocks - output: {}",
|
|
1403
|
+
output
|
|
1404
|
+
);
|
|
1405
|
+
|
|
1406
|
+
Ok(())
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
#[test]
|
|
1410
|
+
fn test_go_outline_search_command() -> Result<()> {
|
|
1411
|
+
let temp_dir = TempDir::new()?;
|
|
1412
|
+
let test_file = temp_dir.path().join("search_test.go");
|
|
1413
|
+
|
|
1414
|
+
let content = r#"package main
|
|
1415
|
+
|
|
1416
|
+
import "fmt"
|
|
1417
|
+
|
|
1418
|
+
type DataProcessor struct {
|
|
1419
|
+
processedCount int
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
func (dp *DataProcessor) ProcessData(data []interface{}) []interface{} {
|
|
1423
|
+
dp.processedCount++
|
|
1424
|
+
result := make([]interface{}, 0, len(data))
|
|
1425
|
+
|
|
1426
|
+
for _, item := range data {
|
|
1427
|
+
if item != nil {
|
|
1428
|
+
result = append(result, item)
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
return result
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
func (dp *DataProcessor) GetProcessedCount() int {
|
|
1436
|
+
return dp.processedCount
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
func ProcessFile(filename string) string {
|
|
1440
|
+
return fmt.Sprintf("Processed %s", filename)
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
func ProcessAsync(data map[string]interface{}) map[string]interface{} {
|
|
1444
|
+
result := make(map[string]interface{})
|
|
1445
|
+
result["processed"] = true
|
|
1446
|
+
|
|
1447
|
+
for k, v := range data {
|
|
1448
|
+
result[k] = v
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
return result
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
func TestDataProcessing() {
|
|
1455
|
+
processor := &DataProcessor{}
|
|
1456
|
+
result := processor.ProcessData([]interface{}{1, 2, nil, 3})
|
|
1457
|
+
|
|
1458
|
+
if len(result) != 3 {
|
|
1459
|
+
fmt.Println("Test failed")
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
"#;
|
|
1463
|
+
|
|
1464
|
+
fs::write(&test_file, content)?;
|
|
1465
|
+
|
|
1466
|
+
let ctx = TestContext::new();
|
|
1467
|
+
let output = ctx.run_probe(&[
|
|
1468
|
+
"search",
|
|
1469
|
+
"process",
|
|
1470
|
+
temp_dir.path().to_str().unwrap(),
|
|
1471
|
+
"--format",
|
|
1472
|
+
"outline",
|
|
1473
|
+
"--allow-tests",
|
|
1474
|
+
])?;
|
|
1475
|
+
|
|
1476
|
+
// Should find symbols containing "process"
|
|
1477
|
+
assert!(
|
|
1478
|
+
output.contains("DataProcessor")
|
|
1479
|
+
|| output.contains("ProcessData")
|
|
1480
|
+
|| output.contains("ProcessFile")
|
|
1481
|
+
|| output.contains("ProcessAsync"),
|
|
1482
|
+
"Should find process-related symbols - output: {}",
|
|
1483
|
+
output
|
|
1484
|
+
);
|
|
1485
|
+
|
|
1486
|
+
Ok(())
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
#[test]
|
|
1490
|
+
fn test_go_outline_closing_brace_comments_with_go_syntax() -> Result<()> {
|
|
1491
|
+
let temp_dir = TempDir::new()?;
|
|
1492
|
+
let test_file = temp_dir.path().join("closing_brace_comments.go");
|
|
1493
|
+
|
|
1494
|
+
let content = r#"package main
|
|
1495
|
+
|
|
1496
|
+
import (
|
|
1497
|
+
"context"
|
|
1498
|
+
"fmt"
|
|
1499
|
+
"sync"
|
|
1500
|
+
"time"
|
|
1501
|
+
)
|
|
1502
|
+
|
|
1503
|
+
// SmallFunction should NOT get closing brace comments (under 20 lines)
|
|
1504
|
+
func SmallFunction(x, y int) int {
|
|
1505
|
+
result := x + y
|
|
1506
|
+
if result > 10 {
|
|
1507
|
+
result *= 2
|
|
1508
|
+
}
|
|
1509
|
+
return result
|
|
1510
|
+
} // No comment expected here
|
|
1511
|
+
|
|
1512
|
+
// LargeFunctionWithGaps should get Go-style closing brace comments (// syntax)
|
|
1513
|
+
func LargeFunctionWithGaps(ctx context.Context, data []int) ([]string, error) {
|
|
1514
|
+
results := make([]string, 0, len(data))
|
|
1515
|
+
var wg sync.WaitGroup
|
|
1516
|
+
ch := make(chan string, len(data))
|
|
1517
|
+
|
|
1518
|
+
// Phase 1: Parallel processing
|
|
1519
|
+
for i, value := range data {
|
|
1520
|
+
wg.Add(1)
|
|
1521
|
+
go func(idx, val int) {
|
|
1522
|
+
defer wg.Done()
|
|
1523
|
+
|
|
1524
|
+
// Complex processing logic
|
|
1525
|
+
processed := val * 2
|
|
1526
|
+
if processed > 100 {
|
|
1527
|
+
processed = processed / 3
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
select {
|
|
1531
|
+
case ch <- fmt.Sprintf("item_%d: %d", idx, processed):
|
|
1532
|
+
// Successfully sent
|
|
1533
|
+
case <-ctx.Done():
|
|
1534
|
+
return
|
|
1535
|
+
case <-time.After(time.Second):
|
|
1536
|
+
// Timeout handling
|
|
1537
|
+
ch <- fmt.Sprintf("timeout_%d: %d", idx, processed)
|
|
1538
|
+
}
|
|
1539
|
+
}(i, value)
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// Phase 2: Wait for completion
|
|
1543
|
+
go func() {
|
|
1544
|
+
wg.Wait()
|
|
1545
|
+
close(ch)
|
|
1546
|
+
}()
|
|
1547
|
+
|
|
1548
|
+
// Phase 3: Collect results with timeout
|
|
1549
|
+
timeout := time.After(5 * time.Second)
|
|
1550
|
+
for {
|
|
1551
|
+
select {
|
|
1552
|
+
case result, ok := <-ch:
|
|
1553
|
+
if !ok {
|
|
1554
|
+
// Channel closed, all done
|
|
1555
|
+
return results, nil
|
|
1556
|
+
}
|
|
1557
|
+
results = append(results, result)
|
|
1558
|
+
|
|
1559
|
+
case <-timeout:
|
|
1560
|
+
return nil, fmt.Errorf("processing timeout")
|
|
1561
|
+
|
|
1562
|
+
case <-ctx.Done():
|
|
1563
|
+
return nil, ctx.Err()
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
// This return should never be reached
|
|
1568
|
+
return results, nil
|
|
1569
|
+
} // Should have Go-style comment: // func LargeFunctionWithGaps
|
|
1570
|
+
|
|
1571
|
+
// AnotherLargeFunction with nested control flow and generics
|
|
1572
|
+
func AnotherLargeFunction[T comparable](items []T, filter func(T) bool) map[T]int {
|
|
1573
|
+
counts := make(map[T]int)
|
|
1574
|
+
|
|
1575
|
+
// Phase 1: Initial counting
|
|
1576
|
+
for _, item := range items {
|
|
1577
|
+
if filter != nil {
|
|
1578
|
+
if filter(item) {
|
|
1579
|
+
counts[item]++
|
|
1580
|
+
} else {
|
|
1581
|
+
// Skip filtered items
|
|
1582
|
+
continue
|
|
1583
|
+
}
|
|
1584
|
+
} else {
|
|
1585
|
+
counts[item]++
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
// Phase 2: Normalization
|
|
1590
|
+
total := 0
|
|
1591
|
+
for _, count := range counts {
|
|
1592
|
+
total += count
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
if total == 0 {
|
|
1596
|
+
return counts
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
// Phase 3: Calculate percentages (scaled by 100)
|
|
1600
|
+
normalized := make(map[T]int)
|
|
1601
|
+
for item, count := range counts {
|
|
1602
|
+
percentage := (count * 100) / total
|
|
1603
|
+
if percentage > 0 {
|
|
1604
|
+
normalized[item] = percentage
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
return normalized
|
|
1609
|
+
} // Should have Go-style comment: // func AnotherLargeFunction
|
|
1610
|
+
"#;
|
|
1611
|
+
|
|
1612
|
+
fs::write(&test_file, content)?;
|
|
1613
|
+
|
|
1614
|
+
let ctx = TestContext::new();
|
|
1615
|
+
let output = ctx.run_probe(&[
|
|
1616
|
+
"search",
|
|
1617
|
+
"LargeFunctionWithGaps",
|
|
1618
|
+
test_file.to_str().unwrap(),
|
|
1619
|
+
"--format",
|
|
1620
|
+
"outline",
|
|
1621
|
+
])?;
|
|
1622
|
+
|
|
1623
|
+
// Should find all functions
|
|
1624
|
+
assert!(
|
|
1625
|
+
output.contains("SmallFunction") || output.contains("LargeFunctionWithGaps"),
|
|
1626
|
+
"Should find test functions - output: {}",
|
|
1627
|
+
output
|
|
1628
|
+
);
|
|
1629
|
+
|
|
1630
|
+
// Large functions should have Go-style closing brace comments when gaps are present
|
|
1631
|
+
if output.contains("...") {
|
|
1632
|
+
// Check for Go-style comments (// syntax, not # or /* */)
|
|
1633
|
+
let has_go_comment_syntax = output.contains("// func")
|
|
1634
|
+
|| output.contains("// LargeFunctionWithGaps")
|
|
1635
|
+
|| output.contains("// AnotherLargeFunction");
|
|
1636
|
+
|
|
1637
|
+
// Should not have Python/Shell style comments (#) or C-style block comments (/* */)
|
|
1638
|
+
let has_wrong_comment_syntax =
|
|
1639
|
+
output.contains("# func") || output.contains("/* func") || output.contains("*/");
|
|
1640
|
+
|
|
1641
|
+
assert!(
|
|
1642
|
+
has_go_comment_syntax || !has_wrong_comment_syntax,
|
|
1643
|
+
"Large functions should use Go-style closing brace comments (// syntax) - output: {}",
|
|
1644
|
+
output
|
|
1645
|
+
);
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
Ok(())
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
#[test]
|
|
1652
|
+
fn test_go_outline_small_functions_no_closing_braces() -> Result<()> {
|
|
1653
|
+
let temp_dir = TempDir::new()?;
|
|
1654
|
+
let test_file = temp_dir.path().join("small_functions.go");
|
|
1655
|
+
|
|
1656
|
+
let content = r#"package utils
|
|
1657
|
+
|
|
1658
|
+
import "fmt"
|
|
1659
|
+
|
|
1660
|
+
// add performs simple addition (small function)
|
|
1661
|
+
func add(a, b int) int {
|
|
1662
|
+
return a + b
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
// multiply performs simple multiplication (small function)
|
|
1666
|
+
func multiply(x, y int) int {
|
|
1667
|
+
result := x * y
|
|
1668
|
+
return result
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
// formatMessage creates a formatted message (small function)
|
|
1672
|
+
func formatMessage(name string, age int) string {
|
|
1673
|
+
return fmt.Sprintf("Hello %s, you are %d years old", name, age)
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
// SimpleStruct for testing small methods
|
|
1677
|
+
type SimpleStruct struct {
|
|
1678
|
+
Value int
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
// GetValue returns the value (small method)
|
|
1682
|
+
func (s SimpleStruct) GetValue() int {
|
|
1683
|
+
return s.Value
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
// SetValue sets the value (small method)
|
|
1687
|
+
func (s *SimpleStruct) SetValue(val int) {
|
|
1688
|
+
s.Value = val
|
|
1689
|
+
}
|
|
1690
|
+
"#;
|
|
1691
|
+
|
|
1692
|
+
fs::write(&test_file, content)?;
|
|
1693
|
+
|
|
1694
|
+
let ctx = TestContext::new();
|
|
1695
|
+
let output = ctx.run_probe(&[
|
|
1696
|
+
"search",
|
|
1697
|
+
"add",
|
|
1698
|
+
test_file.to_str().unwrap(),
|
|
1699
|
+
"--format",
|
|
1700
|
+
"outline",
|
|
1701
|
+
])?;
|
|
1702
|
+
|
|
1703
|
+
// Should find small functions
|
|
1704
|
+
assert!(
|
|
1705
|
+
output.contains("add") || output.contains("multiply") || output.contains("GetValue"),
|
|
1706
|
+
"Should find small functions - output: {}",
|
|
1707
|
+
output
|
|
1708
|
+
);
|
|
1709
|
+
|
|
1710
|
+
// Small functions should NOT have closing brace comments when fully shown
|
|
1711
|
+
let has_closing_brace_comments =
|
|
1712
|
+
output.contains("// func") || output.contains("// add") || output.contains("// multiply");
|
|
1713
|
+
|
|
1714
|
+
// Either no closing brace comments (if complete) or has ellipsis (if truncated)
|
|
1715
|
+
let has_ellipsis = output.contains("...");
|
|
1716
|
+
assert!(
|
|
1717
|
+
!has_closing_brace_comments || has_ellipsis,
|
|
1718
|
+
"Small functions should not have closing brace comments unless truncated - output: {}",
|
|
1719
|
+
output
|
|
1720
|
+
);
|
|
1721
|
+
|
|
1722
|
+
Ok(())
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
#[test]
|
|
1726
|
+
fn test_go_outline_keyword_highlighting() -> Result<()> {
|
|
1727
|
+
let temp_dir = TempDir::new()?;
|
|
1728
|
+
let test_file = temp_dir.path().join("keyword_highlighting.go");
|
|
1729
|
+
|
|
1730
|
+
let content = r#"package main
|
|
1731
|
+
|
|
1732
|
+
import (
|
|
1733
|
+
"context"
|
|
1734
|
+
"fmt"
|
|
1735
|
+
"sync"
|
|
1736
|
+
)
|
|
1737
|
+
|
|
1738
|
+
// TestKeywordHighlighting demonstrates Go keywords in various contexts
|
|
1739
|
+
func TestKeywordHighlighting() {
|
|
1740
|
+
// Basic control flow keywords
|
|
1741
|
+
if true {
|
|
1742
|
+
fmt.Println("if keyword")
|
|
1743
|
+
} else {
|
|
1744
|
+
fmt.Println("else keyword")
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
// For loop keywords
|
|
1748
|
+
for i := 0; i < 10; i++ {
|
|
1749
|
+
if i%2 == 0 {
|
|
1750
|
+
continue
|
|
1751
|
+
}
|
|
1752
|
+
if i > 7 {
|
|
1753
|
+
break
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
// Switch statement keywords
|
|
1758
|
+
switch value := 42; value {
|
|
1759
|
+
case 42:
|
|
1760
|
+
fmt.Println("case keyword")
|
|
1761
|
+
default:
|
|
1762
|
+
fmt.Println("default keyword")
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
// DeferAndPanicKeywords demonstrates defer, panic, and recover
|
|
1767
|
+
func DeferAndPanicKeywords() {
|
|
1768
|
+
defer func() {
|
|
1769
|
+
if r := recover(); r != nil {
|
|
1770
|
+
fmt.Println("recover keyword:", r)
|
|
1771
|
+
}
|
|
1772
|
+
}()
|
|
1773
|
+
|
|
1774
|
+
defer fmt.Println("defer keyword executed")
|
|
1775
|
+
|
|
1776
|
+
panic("panic keyword triggered")
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
// ChannelKeywords demonstrates channel operations
|
|
1780
|
+
func ChannelKeywords() {
|
|
1781
|
+
ch := make(chan string, 5)
|
|
1782
|
+
|
|
1783
|
+
go func() {
|
|
1784
|
+
ch <- "goroutine keyword"
|
|
1785
|
+
close(ch)
|
|
1786
|
+
}()
|
|
1787
|
+
|
|
1788
|
+
select {
|
|
1789
|
+
case msg := <-ch:
|
|
1790
|
+
fmt.Println("select keyword:", msg)
|
|
1791
|
+
default:
|
|
1792
|
+
fmt.Println("default in select")
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
// InterfaceKeywords demonstrates interface and type keywords
|
|
1797
|
+
type Processor interface {
|
|
1798
|
+
Process(data interface{}) interface{}
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
// StructKeywords demonstrates struct and method keywords
|
|
1802
|
+
type DataStruct struct {
|
|
1803
|
+
value interface{}
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
func (d *DataStruct) Process(data interface{}) interface{} {
|
|
1807
|
+
return struct {
|
|
1808
|
+
original interface{}
|
|
1809
|
+
processed interface{}
|
|
1810
|
+
}{
|
|
1811
|
+
original: d.value,
|
|
1812
|
+
processed: data,
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
// GenericKeywords demonstrates type constraints and generic syntax
|
|
1817
|
+
func GenericFunction[T comparable, U any](items []T, mapper func(T) U) map[T]U {
|
|
1818
|
+
result := make(map[T]U)
|
|
1819
|
+
for _, item := range items {
|
|
1820
|
+
result[item] = mapper(item)
|
|
1821
|
+
}
|
|
1822
|
+
return result
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
// ContextKeywords demonstrates context usage
|
|
1826
|
+
func ContextFunction(ctx context.Context) error {
|
|
1827
|
+
select {
|
|
1828
|
+
case <-ctx.Done():
|
|
1829
|
+
return ctx.Err()
|
|
1830
|
+
default:
|
|
1831
|
+
return nil
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
"#;
|
|
1835
|
+
|
|
1836
|
+
fs::write(&test_file, content)?;
|
|
1837
|
+
|
|
1838
|
+
let ctx = TestContext::new();
|
|
1839
|
+
let output = ctx.run_probe(&[
|
|
1840
|
+
"search",
|
|
1841
|
+
"keyword",
|
|
1842
|
+
test_file.to_str().unwrap(),
|
|
1843
|
+
"--format",
|
|
1844
|
+
"outline",
|
|
1845
|
+
])?;
|
|
1846
|
+
|
|
1847
|
+
// Should find functions with keyword-related names
|
|
1848
|
+
assert!(
|
|
1849
|
+
output.contains("TestKeywordHighlighting")
|
|
1850
|
+
|| output.contains("DeferAndPanicKeywords")
|
|
1851
|
+
|| output.contains("ChannelKeywords"),
|
|
1852
|
+
"Should find keyword-related functions - output: {}",
|
|
1853
|
+
output
|
|
1854
|
+
);
|
|
1855
|
+
|
|
1856
|
+
// Should preserve Go keywords in the outline when they are highlighted/matched
|
|
1857
|
+
let go_keywords_preserved = output.contains("if ")
|
|
1858
|
+
|| output.contains("for ")
|
|
1859
|
+
|| output.contains("switch ")
|
|
1860
|
+
|| output.contains("select ")
|
|
1861
|
+
|| output.contains("defer ")
|
|
1862
|
+
|| output.contains("go ")
|
|
1863
|
+
|| output.contains("type ")
|
|
1864
|
+
|| output.contains("func ")
|
|
1865
|
+
|| output.contains("interface")
|
|
1866
|
+
|| output.contains("struct");
|
|
1867
|
+
|
|
1868
|
+
assert!(
|
|
1869
|
+
go_keywords_preserved,
|
|
1870
|
+
"Go keywords should be preserved in outline format - output: {}",
|
|
1871
|
+
output
|
|
1872
|
+
);
|
|
1873
|
+
|
|
1874
|
+
Ok(())
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
#[test]
|
|
1878
|
+
fn test_go_outline_slice_map_struct_truncation() -> Result<()> {
|
|
1879
|
+
let temp_dir = TempDir::new()?;
|
|
1880
|
+
let test_file = temp_dir.path().join("truncation_test.go");
|
|
1881
|
+
|
|
1882
|
+
let content = r#"package main
|
|
1883
|
+
|
|
1884
|
+
import (
|
|
1885
|
+
"fmt"
|
|
1886
|
+
"time"
|
|
1887
|
+
)
|
|
1888
|
+
|
|
1889
|
+
// LargeSliceFunction demonstrates slice truncation with keyword preservation
|
|
1890
|
+
func LargeSliceFunction() []string {
|
|
1891
|
+
largeSlice := []string{
|
|
1892
|
+
"item1", "item2", "item3", "item4", "item5",
|
|
1893
|
+
"item6", "item7", "item8", "item9", "item10",
|
|
1894
|
+
"item11", "item12", "item13", "item14", "item15",
|
|
1895
|
+
"item16", "item17", "item18", "item19", "item20",
|
|
1896
|
+
"item21", "item22", "item23", "item24", "item25",
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
// This slice should be truncated but preserve the make keyword
|
|
1900
|
+
result := make([]string, 0, len(largeSlice))
|
|
1901
|
+
|
|
1902
|
+
for i, item := range largeSlice {
|
|
1903
|
+
if i%2 == 0 {
|
|
1904
|
+
result = append(result, fmt.Sprintf("even_%s", item))
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
return result
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
// LargeMapFunction demonstrates map truncation with keyword preservation
|
|
1912
|
+
func LargeMapFunction() map[string]interface{} {
|
|
1913
|
+
largeMap := map[string]interface{}{
|
|
1914
|
+
"key1": "value1", "key2": "value2", "key3": "value3",
|
|
1915
|
+
"key4": "value4", "key5": "value5", "key6": "value6",
|
|
1916
|
+
"key7": "value7", "key8": "value8", "key9": "value9",
|
|
1917
|
+
"key10": "value10", "key11": "value11", "key12": "value12",
|
|
1918
|
+
"key13": "value13", "key14": "value14", "key15": "value15",
|
|
1919
|
+
"key16": "value16", "key17": "value17", "key18": "value18",
|
|
1920
|
+
"key19": "value19", "key20": "value20", "key21": "value21",
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
// This map should be truncated but preserve the make keyword
|
|
1924
|
+
result := make(map[string]interface{})
|
|
1925
|
+
|
|
1926
|
+
for key, value := range largeMap {
|
|
1927
|
+
if len(key) > 4 {
|
|
1928
|
+
result[key] = value
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
return result
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
// ComplexStruct demonstrates struct truncation with keyword preservation
|
|
1936
|
+
type ComplexStruct struct {
|
|
1937
|
+
Field1 string `json:"field1" db:"field1" validate:"required"`
|
|
1938
|
+
Field2 int `json:"field2" db:"field2" validate:"min=0,max=100"`
|
|
1939
|
+
Field3 float64 `json:"field3" db:"field3"`
|
|
1940
|
+
Field4 bool `json:"field4" db:"field4"`
|
|
1941
|
+
Field5 time.Time `json:"field5" db:"field5"`
|
|
1942
|
+
Field6 []string `json:"field6" db:"field6"`
|
|
1943
|
+
Field7 map[string]int `json:"field7" db:"field7"`
|
|
1944
|
+
Field8 interface{} `json:"field8" db:"field8"`
|
|
1945
|
+
Field9 *string `json:"field9" db:"field9"`
|
|
1946
|
+
Field10 chan string `json:"-" db:"field10"`
|
|
1947
|
+
Field11 func() error `json:"-" db:"-"`
|
|
1948
|
+
Field12 struct {
|
|
1949
|
+
NestedField1 string `json:"nested1"`
|
|
1950
|
+
NestedField2 int `json:"nested2"`
|
|
1951
|
+
NestedField3 bool `json:"nested3"`
|
|
1952
|
+
} `json:"field12"`
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
// LargeStructFunction demonstrates struct initialization truncation
|
|
1956
|
+
func LargeStructFunction() ComplexStruct {
|
|
1957
|
+
return ComplexStruct{
|
|
1958
|
+
Field1: "value1",
|
|
1959
|
+
Field2: 42,
|
|
1960
|
+
Field3: 3.14159,
|
|
1961
|
+
Field4: true,
|
|
1962
|
+
Field5: time.Now(),
|
|
1963
|
+
Field6: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"},
|
|
1964
|
+
Field7: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5},
|
|
1965
|
+
Field8: "interface value",
|
|
1966
|
+
Field9: &[]string{"pointer to string"}[0],
|
|
1967
|
+
Field10: make(chan string, 10),
|
|
1968
|
+
Field11: func() error { return nil },
|
|
1969
|
+
Field12: struct {
|
|
1970
|
+
NestedField1 string `json:"nested1"`
|
|
1971
|
+
NestedField2 int `json:"nested2"`
|
|
1972
|
+
NestedField3 bool `json:"nested3"`
|
|
1973
|
+
}{
|
|
1974
|
+
NestedField1: "nested value",
|
|
1975
|
+
NestedField2: 99,
|
|
1976
|
+
NestedField3: false,
|
|
1977
|
+
},
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
"#;
|
|
1981
|
+
|
|
1982
|
+
fs::write(&test_file, content)?;
|
|
1983
|
+
|
|
1984
|
+
let ctx = TestContext::new();
|
|
1985
|
+
let output = ctx.run_probe(&[
|
|
1986
|
+
"search",
|
|
1987
|
+
"slice",
|
|
1988
|
+
test_file.to_str().unwrap(),
|
|
1989
|
+
"--format",
|
|
1990
|
+
"outline",
|
|
1991
|
+
])?;
|
|
1992
|
+
|
|
1993
|
+
// Should find functions related to slices
|
|
1994
|
+
assert!(
|
|
1995
|
+
output.contains("LargeSliceFunction") || output.len() > 10,
|
|
1996
|
+
"Should find slice-related content - output: {}",
|
|
1997
|
+
output
|
|
1998
|
+
);
|
|
1999
|
+
|
|
2000
|
+
// When content is truncated, should preserve Go keywords
|
|
2001
|
+
if output.contains("...") {
|
|
2002
|
+
let preserves_keywords = output.contains("make")
|
|
2003
|
+
|| output.contains("[]string")
|
|
2004
|
+
|| output.contains("map[")
|
|
2005
|
+
|| output.contains("struct")
|
|
2006
|
+
|| output.contains("func")
|
|
2007
|
+
|| output.contains("type")
|
|
2008
|
+
|| output.contains("interface{}");
|
|
2009
|
+
|
|
2010
|
+
assert!(
|
|
2011
|
+
preserves_keywords,
|
|
2012
|
+
"Should preserve Go keywords when truncating slices/maps/structs - output: {}",
|
|
2013
|
+
output
|
|
2014
|
+
);
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
Ok(())
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
#[test]
|
|
2021
|
+
fn test_go_outline_comprehensive_go_specific_constructs() -> Result<()> {
|
|
2022
|
+
let temp_dir = TempDir::new()?;
|
|
2023
|
+
let test_file = temp_dir.path().join("go_specific_constructs.go");
|
|
2024
|
+
|
|
2025
|
+
let content = r#"package main
|
|
2026
|
+
|
|
2027
|
+
import (
|
|
2028
|
+
"context"
|
|
2029
|
+
"fmt"
|
|
2030
|
+
"sync"
|
|
2031
|
+
"time"
|
|
2032
|
+
)
|
|
2033
|
+
|
|
2034
|
+
// GenericProcessor demonstrates Go generics with type constraints
|
|
2035
|
+
type GenericProcessor[T comparable, U any] struct {
|
|
2036
|
+
items []T
|
|
2037
|
+
mapper func(T) U
|
|
2038
|
+
results chan ProcessResult[T, U]
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
type ProcessResult[T comparable, U any] struct {
|
|
2042
|
+
Input T
|
|
2043
|
+
Output U
|
|
2044
|
+
Error error
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
// NewGenericProcessor creates a new generic processor
|
|
2048
|
+
func NewGenericProcessor[T comparable, U any](mapper func(T) U) *GenericProcessor[T, U] {
|
|
2049
|
+
return &GenericProcessor[T, U]{
|
|
2050
|
+
items: make([]T, 0),
|
|
2051
|
+
mapper: mapper,
|
|
2052
|
+
results: make(chan ProcessResult[T, U], 100),
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
// ProcessWithGenerics demonstrates generics with complex operations
|
|
2057
|
+
func (gp *GenericProcessor[T, U]) ProcessWithGenerics(ctx context.Context, items []T) <-chan ProcessResult[T, U] {
|
|
2058
|
+
output := make(chan ProcessResult[T, U])
|
|
2059
|
+
|
|
2060
|
+
go func() {
|
|
2061
|
+
defer close(output)
|
|
2062
|
+
defer func() {
|
|
2063
|
+
if r := recover(); r != nil {
|
|
2064
|
+
select {
|
|
2065
|
+
case output <- ProcessResult[T, U]{Error: fmt.Errorf("panic: %v", r)}:
|
|
2066
|
+
case <-ctx.Done():
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
}()
|
|
2070
|
+
|
|
2071
|
+
var wg sync.WaitGroup
|
|
2072
|
+
semaphore := make(chan struct{}, 10) // Limit concurrent goroutines
|
|
2073
|
+
|
|
2074
|
+
for _, item := range items {
|
|
2075
|
+
select {
|
|
2076
|
+
case <-ctx.Done():
|
|
2077
|
+
return
|
|
2078
|
+
case semaphore <- struct{}{}:
|
|
2079
|
+
wg.Add(1)
|
|
2080
|
+
go func(input T) {
|
|
2081
|
+
defer wg.Done()
|
|
2082
|
+
defer func() { <-semaphore }()
|
|
2083
|
+
|
|
2084
|
+
result := ProcessResult[T, U]{Input: input}
|
|
2085
|
+
|
|
2086
|
+
defer func() {
|
|
2087
|
+
if r := recover(); r != nil {
|
|
2088
|
+
result.Error = fmt.Errorf("processing panic: %v", r)
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
select {
|
|
2092
|
+
case output <- result:
|
|
2093
|
+
case <-ctx.Done():
|
|
2094
|
+
}
|
|
2095
|
+
}()
|
|
2096
|
+
|
|
2097
|
+
result.Output = gp.mapper(input)
|
|
2098
|
+
}(item)
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
wg.Wait()
|
|
2103
|
+
}()
|
|
2104
|
+
|
|
2105
|
+
return output
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
// ChannelOperationsDemo demonstrates complex channel operations
|
|
2109
|
+
func ChannelOperationsDemo(ctx context.Context) error {
|
|
2110
|
+
// Buffered channels with different types
|
|
2111
|
+
stringChan := make(chan string, 5)
|
|
2112
|
+
intChan := make(chan int, 3)
|
|
2113
|
+
errorChan := make(chan error, 1)
|
|
2114
|
+
doneChan := make(chan struct{})
|
|
2115
|
+
|
|
2116
|
+
// Worker goroutines with different patterns
|
|
2117
|
+
go func() {
|
|
2118
|
+
defer close(stringChan)
|
|
2119
|
+
for i := 0; i < 10; i++ {
|
|
2120
|
+
select {
|
|
2121
|
+
case stringChan <- fmt.Sprintf("message_%d", i):
|
|
2122
|
+
time.Sleep(100 * time.Millisecond)
|
|
2123
|
+
case <-ctx.Done():
|
|
2124
|
+
return
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
}()
|
|
2128
|
+
|
|
2129
|
+
go func() {
|
|
2130
|
+
defer close(intChan)
|
|
2131
|
+
for i := 0; i < 5; i++ {
|
|
2132
|
+
select {
|
|
2133
|
+
case intChan <- i * i:
|
|
2134
|
+
time.Sleep(200 * time.Millisecond)
|
|
2135
|
+
case <-ctx.Done():
|
|
2136
|
+
return
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
}()
|
|
2140
|
+
|
|
2141
|
+
// Complex select statement with multiple cases
|
|
2142
|
+
go func() {
|
|
2143
|
+
defer close(doneChan)
|
|
2144
|
+
|
|
2145
|
+
for {
|
|
2146
|
+
select {
|
|
2147
|
+
case msg, ok := <-stringChan:
|
|
2148
|
+
if !ok {
|
|
2149
|
+
return
|
|
2150
|
+
}
|
|
2151
|
+
fmt.Printf("Received string: %s\n", msg)
|
|
2152
|
+
|
|
2153
|
+
case num, ok := <-intChan:
|
|
2154
|
+
if !ok {
|
|
2155
|
+
return
|
|
2156
|
+
}
|
|
2157
|
+
fmt.Printf("Received int: %d\n", num)
|
|
2158
|
+
|
|
2159
|
+
case err := <-errorChan:
|
|
2160
|
+
fmt.Printf("Received error: %v\n", err)
|
|
2161
|
+
return
|
|
2162
|
+
|
|
2163
|
+
case <-time.After(1 * time.Second):
|
|
2164
|
+
fmt.Println("Timeout in select")
|
|
2165
|
+
|
|
2166
|
+
case <-ctx.Done():
|
|
2167
|
+
fmt.Println("Context cancelled")
|
|
2168
|
+
return
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
}()
|
|
2172
|
+
|
|
2173
|
+
select {
|
|
2174
|
+
case <-doneChan:
|
|
2175
|
+
return nil
|
|
2176
|
+
case <-ctx.Done():
|
|
2177
|
+
return ctx.Err()
|
|
2178
|
+
case <-time.After(5 * time.Second):
|
|
2179
|
+
return fmt.Errorf("operation timeout")
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
// TypeSwitchAndAssertions demonstrates type switches and type assertions
|
|
2184
|
+
func TypeSwitchAndAssertions(input interface{}) (string, error) {
|
|
2185
|
+
switch v := input.(type) {
|
|
2186
|
+
case nil:
|
|
2187
|
+
return "nil", nil
|
|
2188
|
+
|
|
2189
|
+
case string:
|
|
2190
|
+
if len(v) == 0 {
|
|
2191
|
+
return "empty_string", nil
|
|
2192
|
+
}
|
|
2193
|
+
return fmt.Sprintf("string: %s", v), nil
|
|
2194
|
+
|
|
2195
|
+
case int:
|
|
2196
|
+
return fmt.Sprintf("int: %d", v), nil
|
|
2197
|
+
|
|
2198
|
+
case int64:
|
|
2199
|
+
return fmt.Sprintf("int64: %d", v), nil
|
|
2200
|
+
|
|
2201
|
+
case float64:
|
|
2202
|
+
return fmt.Sprintf("float64: %.2f", v), nil
|
|
2203
|
+
|
|
2204
|
+
case bool:
|
|
2205
|
+
return fmt.Sprintf("bool: %t", v), nil
|
|
2206
|
+
|
|
2207
|
+
case []interface{}:
|
|
2208
|
+
return fmt.Sprintf("slice_length: %d", len(v)), nil
|
|
2209
|
+
|
|
2210
|
+
case map[string]interface{}:
|
|
2211
|
+
return fmt.Sprintf("map_keys: %d", len(v)), nil
|
|
2212
|
+
|
|
2213
|
+
case chan string:
|
|
2214
|
+
return "string_channel", nil
|
|
2215
|
+
|
|
2216
|
+
case <-chan string:
|
|
2217
|
+
return "receive_only_string_channel", nil
|
|
2218
|
+
|
|
2219
|
+
case chan<- string:
|
|
2220
|
+
return "send_only_string_channel", nil
|
|
2221
|
+
|
|
2222
|
+
default:
|
|
2223
|
+
// Type assertion attempt
|
|
2224
|
+
if stringer, ok := input.(fmt.Stringer); ok {
|
|
2225
|
+
return fmt.Sprintf("stringer: %s", stringer.String()), nil
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
return "", fmt.Errorf("unsupported type: %T", input)
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
// EmbeddedTypesAndMethods demonstrates embedded types and method promotion
|
|
2233
|
+
type Reader interface {
|
|
2234
|
+
Read([]byte) (int, error)
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
type Writer interface {
|
|
2238
|
+
Write([]byte) (int, error)
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
type Closer interface {
|
|
2242
|
+
Close() error
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
type ReadWriteCloser interface {
|
|
2246
|
+
Reader
|
|
2247
|
+
Writer
|
|
2248
|
+
Closer
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
type FileManager struct {
|
|
2252
|
+
ReadWriteCloser // Embedded interface
|
|
2253
|
+
filename string
|
|
2254
|
+
metadata map[string]interface{}
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
func (fm *FileManager) GetFilename() string {
|
|
2258
|
+
return fm.filename
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
func (fm *FileManager) SetMetadata(key string, value interface{}) {
|
|
2262
|
+
if fm.metadata == nil {
|
|
2263
|
+
fm.metadata = make(map[string]interface{})
|
|
2264
|
+
}
|
|
2265
|
+
fm.metadata[key] = value
|
|
2266
|
+
}
|
|
2267
|
+
"#;
|
|
2268
|
+
|
|
2269
|
+
fs::write(&test_file, content)?;
|
|
2270
|
+
|
|
2271
|
+
let ctx = TestContext::new();
|
|
2272
|
+
let output = ctx.run_probe(&[
|
|
2273
|
+
"search",
|
|
2274
|
+
"GenericProcessor",
|
|
2275
|
+
test_file.to_str().unwrap(),
|
|
2276
|
+
"--format",
|
|
2277
|
+
"outline",
|
|
2278
|
+
])?;
|
|
2279
|
+
|
|
2280
|
+
// Should find Go-specific constructs
|
|
2281
|
+
assert!(
|
|
2282
|
+
output.contains("GenericProcessor")
|
|
2283
|
+
|| output.contains("ProcessWithGenerics")
|
|
2284
|
+
|| output.contains("ChannelOperationsDemo")
|
|
2285
|
+
|| output.contains("TypeSwitchAndAssertions"),
|
|
2286
|
+
"Should find Go-specific construct functions - output: {}",
|
|
2287
|
+
output
|
|
2288
|
+
);
|
|
2289
|
+
|
|
2290
|
+
// Should contain Go-specific syntax elements
|
|
2291
|
+
let go_specific_syntax = output.contains("chan ")
|
|
2292
|
+
|| output.contains("select {")
|
|
2293
|
+
|| output.contains("defer ")
|
|
2294
|
+
|| output.contains("go func")
|
|
2295
|
+
|| output.contains("interface{}")
|
|
2296
|
+
|| output.contains("make(chan")
|
|
2297
|
+
|| output.contains("<-")
|
|
2298
|
+
|| output.contains(".(type)");
|
|
2299
|
+
|
|
2300
|
+
assert!(
|
|
2301
|
+
go_specific_syntax,
|
|
2302
|
+
"Should contain Go-specific syntax in outline format - output: {}",
|
|
2303
|
+
output
|
|
2304
|
+
);
|
|
2305
|
+
|
|
2306
|
+
Ok(())
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
#[test]
|
|
2310
|
+
fn test_go_outline_enhanced_testing_patterns() -> Result<()> {
|
|
2311
|
+
let temp_dir = TempDir::new()?;
|
|
2312
|
+
let test_file = temp_dir.path().join("enhanced_testing_patterns_test.go");
|
|
2313
|
+
|
|
2314
|
+
let content = r#"package calculator
|
|
2315
|
+
|
|
2316
|
+
import (
|
|
2317
|
+
"context"
|
|
2318
|
+
"fmt"
|
|
2319
|
+
"reflect"
|
|
2320
|
+
"testing"
|
|
2321
|
+
"time"
|
|
2322
|
+
)
|
|
2323
|
+
|
|
2324
|
+
// TestWithSubtests demonstrates table-driven tests with subtests
|
|
2325
|
+
func TestWithSubtests(t *testing.T) {
|
|
2326
|
+
testCases := []struct {
|
|
2327
|
+
name string
|
|
2328
|
+
input int
|
|
2329
|
+
expected int
|
|
2330
|
+
wantErr bool
|
|
2331
|
+
}{
|
|
2332
|
+
{"positive number", 5, 25, false},
|
|
2333
|
+
{"negative number", -3, 9, false},
|
|
2334
|
+
{"zero", 0, 0, false},
|
|
2335
|
+
{"large number", 100, 10000, false},
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
for _, tc := range testCases {
|
|
2339
|
+
t.Run(tc.name, func(t *testing.T) {
|
|
2340
|
+
result := tc.input * tc.input
|
|
2341
|
+
if result != tc.expected {
|
|
2342
|
+
t.Errorf("got %d, want %d", result, tc.expected)
|
|
2343
|
+
}
|
|
2344
|
+
})
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
// TestWithContext demonstrates context-aware testing
|
|
2349
|
+
func TestWithContext(t *testing.T) {
|
|
2350
|
+
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
2351
|
+
defer cancel()
|
|
2352
|
+
|
|
2353
|
+
done := make(chan bool, 1)
|
|
2354
|
+
go func() {
|
|
2355
|
+
// Simulate long-running operation
|
|
2356
|
+
time.Sleep(1 * time.Second)
|
|
2357
|
+
done <- true
|
|
2358
|
+
}()
|
|
2359
|
+
|
|
2360
|
+
select {
|
|
2361
|
+
case <-done:
|
|
2362
|
+
t.Log("Operation completed successfully")
|
|
2363
|
+
case <-ctx.Done():
|
|
2364
|
+
t.Fatal("Test timed out")
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
// TestParallelExecution demonstrates parallel test execution
|
|
2369
|
+
func TestParallelExecution(t *testing.T) {
|
|
2370
|
+
t.Parallel()
|
|
2371
|
+
|
|
2372
|
+
testCases := []int{1, 2, 3, 4, 5}
|
|
2373
|
+
|
|
2374
|
+
for _, tc := range testCases {
|
|
2375
|
+
tc := tc // Capture loop variable
|
|
2376
|
+
t.Run(fmt.Sprintf("parallel_%d", tc), func(t *testing.T) {
|
|
2377
|
+
t.Parallel()
|
|
2378
|
+
|
|
2379
|
+
// Simulate some work
|
|
2380
|
+
time.Sleep(100 * time.Millisecond)
|
|
2381
|
+
result := tc * tc
|
|
2382
|
+
|
|
2383
|
+
if result <= 0 {
|
|
2384
|
+
t.Errorf("Expected positive result, got %d", result)
|
|
2385
|
+
}
|
|
2386
|
+
})
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
// BenchmarkWithComplexOperations demonstrates advanced benchmarking
|
|
2391
|
+
func BenchmarkWithComplexOperations(b *testing.B) {
|
|
2392
|
+
benchmarks := []struct {
|
|
2393
|
+
name string
|
|
2394
|
+
size int
|
|
2395
|
+
fn func(int) interface{}
|
|
2396
|
+
}{
|
|
2397
|
+
{"SliceOperations", 1000, func(n int) interface{} {
|
|
2398
|
+
slice := make([]int, n)
|
|
2399
|
+
for i := 0; i < n; i++ {
|
|
2400
|
+
slice[i] = i * i
|
|
2401
|
+
}
|
|
2402
|
+
return slice
|
|
2403
|
+
}},
|
|
2404
|
+
{"MapOperations", 1000, func(n int) interface{} {
|
|
2405
|
+
m := make(map[int]int, n)
|
|
2406
|
+
for i := 0; i < n; i++ {
|
|
2407
|
+
m[i] = i * i
|
|
2408
|
+
}
|
|
2409
|
+
return m
|
|
2410
|
+
}},
|
|
2411
|
+
{"ChannelOperations", 100, func(n int) interface{} {
|
|
2412
|
+
ch := make(chan int, n)
|
|
2413
|
+
go func() {
|
|
2414
|
+
defer close(ch)
|
|
2415
|
+
for i := 0; i < n; i++ {
|
|
2416
|
+
ch <- i
|
|
2417
|
+
}
|
|
2418
|
+
}()
|
|
2419
|
+
|
|
2420
|
+
var results []int
|
|
2421
|
+
for val := range ch {
|
|
2422
|
+
results = append(results, val)
|
|
2423
|
+
}
|
|
2424
|
+
return results
|
|
2425
|
+
}},
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
for _, bm := range benchmarks {
|
|
2429
|
+
b.Run(bm.name, func(b *testing.B) {
|
|
2430
|
+
b.ResetTimer()
|
|
2431
|
+
for i := 0; i < b.N; i++ {
|
|
2432
|
+
bm.fn(bm.size)
|
|
2433
|
+
}
|
|
2434
|
+
})
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
// ExampleComplexDataStructures demonstrates complex examples
|
|
2439
|
+
func ExampleComplexDataStructures() {
|
|
2440
|
+
// Generic map with complex operations
|
|
2441
|
+
data := map[string]interface{}{
|
|
2442
|
+
"numbers": []int{1, 2, 3, 4, 5},
|
|
2443
|
+
"strings": []string{"a", "b", "c"},
|
|
2444
|
+
"nested": map[string]interface{}{
|
|
2445
|
+
"inner": "value",
|
|
2446
|
+
"count": 42,
|
|
2447
|
+
},
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
// Type assertions and processing
|
|
2451
|
+
if numbers, ok := data["numbers"].([]int); ok {
|
|
2452
|
+
total := 0
|
|
2453
|
+
for _, num := range numbers {
|
|
2454
|
+
total += num
|
|
2455
|
+
}
|
|
2456
|
+
fmt.Printf("Sum of numbers: %d\n", total)
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
if nested, ok := data["nested"].(map[string]interface{}); ok {
|
|
2460
|
+
if count, ok := nested["count"].(int); ok {
|
|
2461
|
+
fmt.Printf("Nested count: %d\n", count)
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
// Output:
|
|
2466
|
+
// Sum of numbers: 15
|
|
2467
|
+
// Nested count: 42
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2470
|
+
// TestWithGenerics demonstrates testing with generic functions
|
|
2471
|
+
func TestWithGenerics[T comparable](t *testing.T) {
|
|
2472
|
+
// This would be called with specific types in actual usage
|
|
2473
|
+
testGenericFunction := func(items []T, target T) bool {
|
|
2474
|
+
for _, item := range items {
|
|
2475
|
+
if item == target {
|
|
2476
|
+
return true
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
return false
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
// Note: This is conceptual - Go's testing package doesn't support generic test functions yet
|
|
2483
|
+
_ = testGenericFunction
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
// BenchmarkGenericOperations demonstrates benchmarking with generics
|
|
2487
|
+
func BenchmarkGenericOperations(b *testing.B) {
|
|
2488
|
+
intSlice := make([]int, 1000)
|
|
2489
|
+
for i := range intSlice {
|
|
2490
|
+
intSlice[i] = i
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2493
|
+
stringSlice := make([]string, 1000)
|
|
2494
|
+
for i := range stringSlice {
|
|
2495
|
+
stringSlice[i] = fmt.Sprintf("item_%d", i)
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
b.Run("IntOperations", func(b *testing.B) {
|
|
2499
|
+
b.ResetTimer()
|
|
2500
|
+
for i := 0; i < b.N; i++ {
|
|
2501
|
+
genericSearch(intSlice, 500)
|
|
2502
|
+
}
|
|
2503
|
+
})
|
|
2504
|
+
|
|
2505
|
+
b.Run("StringOperations", func(b *testing.B) {
|
|
2506
|
+
b.ResetTimer()
|
|
2507
|
+
for i := 0; i < b.N; i++ {
|
|
2508
|
+
genericSearch(stringSlice, "item_500")
|
|
2509
|
+
}
|
|
2510
|
+
})
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
func genericSearch[T comparable](slice []T, target T) bool {
|
|
2514
|
+
for _, item := range slice {
|
|
2515
|
+
if item == target {
|
|
2516
|
+
return true
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
return false
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
// TestWithReflection demonstrates reflection-based testing
|
|
2523
|
+
func TestWithReflection(t *testing.T) {
|
|
2524
|
+
testStruct := struct {
|
|
2525
|
+
Name string `json:"name" validate:"required"`
|
|
2526
|
+
Age int `json:"age" validate:"min=0,max=150"`
|
|
2527
|
+
Email string `json:"email" validate:"email"`
|
|
2528
|
+
}{
|
|
2529
|
+
Name: "John Doe",
|
|
2530
|
+
Age: 30,
|
|
2531
|
+
Email: "john@example.com",
|
|
2532
|
+
}
|
|
2533
|
+
|
|
2534
|
+
v := reflect.ValueOf(testStruct)
|
|
2535
|
+
typ := reflect.TypeOf(testStruct)
|
|
2536
|
+
|
|
2537
|
+
for i := 0; i < v.NumField(); i++ {
|
|
2538
|
+
field := v.Field(i)
|
|
2539
|
+
fieldType := typ.Field(i)
|
|
2540
|
+
|
|
2541
|
+
jsonTag := fieldType.Tag.Get("json")
|
|
2542
|
+
validateTag := fieldType.Tag.Get("validate")
|
|
2543
|
+
|
|
2544
|
+
t.Logf("Field: %s, Type: %s, JSON: %s, Validation: %s, Value: %v",
|
|
2545
|
+
fieldType.Name, field.Type(), jsonTag, validateTag, field.Interface())
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
"#;
|
|
2549
|
+
|
|
2550
|
+
fs::write(&test_file, content)?;
|
|
2551
|
+
|
|
2552
|
+
let ctx = TestContext::new();
|
|
2553
|
+
let output = ctx.run_probe(&[
|
|
2554
|
+
"search",
|
|
2555
|
+
"Test",
|
|
2556
|
+
test_file.to_str().unwrap(),
|
|
2557
|
+
"--format",
|
|
2558
|
+
"outline",
|
|
2559
|
+
"--allow-tests",
|
|
2560
|
+
])?;
|
|
2561
|
+
|
|
2562
|
+
// Should find various testing patterns
|
|
2563
|
+
assert!(
|
|
2564
|
+
output.contains("TestWithSubtests")
|
|
2565
|
+
|| output.contains("TestWithContext")
|
|
2566
|
+
|| output.contains("BenchmarkWithComplexOperations")
|
|
2567
|
+
|| output.contains("ExampleComplexDataStructures"),
|
|
2568
|
+
"Should find enhanced testing pattern functions - output: {}",
|
|
2569
|
+
output
|
|
2570
|
+
);
|
|
2571
|
+
|
|
2572
|
+
// Should contain Go testing-specific elements
|
|
2573
|
+
let testing_patterns = output.contains("t.Run")
|
|
2574
|
+
|| output.contains("b.Run")
|
|
2575
|
+
|| output.contains("testing.T")
|
|
2576
|
+
|| output.contains("testing.B")
|
|
2577
|
+
|| output.contains("t.Parallel")
|
|
2578
|
+
|| output.contains("b.ResetTimer");
|
|
2579
|
+
|
|
2580
|
+
assert!(
|
|
2581
|
+
testing_patterns,
|
|
2582
|
+
"Should contain Go testing patterns in outline format - output: {}",
|
|
2583
|
+
output
|
|
2584
|
+
);
|
|
2585
|
+
|
|
2586
|
+
Ok(())
|
|
2587
|
+
}
|