@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.
Files changed (444) hide show
  1. package/README.md +138 -0
  2. package/data/.env.example +22 -0
  3. package/data/.gitattributes +47 -0
  4. package/data/.glfrc.json +7 -0
  5. package/data/.husky/pre-commit +5 -0
  6. package/data/.nvmrc +1 -0
  7. package/data/CHANGELOG.md +75 -0
  8. package/data/CODE_OF_CONDUCT.md +129 -0
  9. package/data/CONTRIBUTING.md +203 -0
  10. package/data/DOCS-STRUCTURE.md +307 -0
  11. package/data/I18N.md +292 -0
  12. package/data/LICENSE +22 -0
  13. package/data/README.md +315 -0
  14. package/data/SECURITY.md +125 -0
  15. package/data/WIKI-DEPLOYMENT.md +348 -0
  16. package/data/docs/AI-FEATURES.md +610 -0
  17. package/data/docs/API-REFERENCE.md +1022 -0
  18. package/data/docs/AUTHENTICATION.md +301 -0
  19. package/data/docs/BACKEND-API.md +468 -0
  20. package/data/docs/DEVELOPMENT.md +375 -0
  21. package/data/docs/EXAMPLES.md +622 -0
  22. package/data/docs/MCP-SERVER.md +307 -0
  23. package/data/docs/MIGRATION-GUIDE.md +367 -0
  24. package/data/docs/NPM-PUBLISH.md +193 -0
  25. package/data/docs/QUICKSTART.md +206 -0
  26. package/data/docs/REDIS-SETUP.md +162 -0
  27. package/data/docs/SERVER.md +228 -0
  28. package/data/docs/TROUBLESHOOTING.md +657 -0
  29. package/data/docs/WIDGET-GUIDE.md +638 -0
  30. package/data/docs/WIKI-HOME.md +58 -0
  31. package/data/docs/WIKI-SIDEBAR.md +39 -0
  32. package/data/package.json +171 -0
  33. package/data/playwright.config.ts +64 -0
  34. package/data/probe/.cargo/config.toml +10 -0
  35. package/data/probe/.claude/commands/performance-review.md +15 -0
  36. package/data/probe/.clinerules +288 -0
  37. package/data/probe/.dockerignore +57 -0
  38. package/data/probe/.githooks/post-commit +11 -0
  39. package/data/probe/.githooks/pre-commit +99 -0
  40. package/data/probe/.githooks/pre-commit-vow +9 -0
  41. package/data/probe/.prompts/engineer.md +41 -0
  42. package/data/probe/.roomodes +28 -0
  43. package/data/probe/.windsurfrules +0 -0
  44. package/data/probe/BASH_TOOL_SUMMARY.md +148 -0
  45. package/data/probe/BENCHMARKING.md +256 -0
  46. package/data/probe/CLAUDE.md +226 -0
  47. package/data/probe/CODE_OF_CONDUCT.md +128 -0
  48. package/data/probe/CONTRIBUTING.md +193 -0
  49. package/data/probe/Cargo.toml +120 -0
  50. package/data/probe/Cross.toml +10 -0
  51. package/data/probe/DOCKER-README.md +224 -0
  52. package/data/probe/Dockerfile +32 -0
  53. package/data/probe/ENHANCED_DEBUG_TELEMETRY.md +188 -0
  54. package/data/probe/LICENSE +201 -0
  55. package/data/probe/Makefile +210 -0
  56. package/data/probe/README.md +824 -0
  57. package/data/probe/SECURITY.md +67 -0
  58. package/data/probe/WINDOWS-GUIDE.md +294 -0
  59. package/data/probe/benches/parsing_benchmarks.rs +370 -0
  60. package/data/probe/benches/search_benchmarks.rs +599 -0
  61. package/data/probe/benches/simd_benchmarks.rs +372 -0
  62. package/data/probe/benches/timing_benchmarks.rs +287 -0
  63. package/data/probe/build-windows.bat +229 -0
  64. package/data/probe/codex-config/config.toml +6 -0
  65. package/data/probe/docs/PERFORMANCE_OPTIMIZATION.md +161 -0
  66. package/data/probe/examples/cache_demo.rs +46 -0
  67. package/data/probe/examples/chat/.dockerignore +37 -0
  68. package/data/probe/examples/chat/ChatSessionManager.js +295 -0
  69. package/data/probe/examples/chat/Dockerfile +98 -0
  70. package/data/probe/examples/chat/LICENSE +201 -0
  71. package/data/probe/examples/chat/LOCAL_IMAGE_SUPPORT.md +195 -0
  72. package/data/probe/examples/chat/MCP_INTEGRATION.md +400 -0
  73. package/data/probe/examples/chat/README.md +338 -0
  74. package/data/probe/examples/chat/TRACING.md +226 -0
  75. package/data/probe/examples/chat/appTracer.js +968 -0
  76. package/data/probe/examples/chat/auth.js +76 -0
  77. package/data/probe/examples/chat/bin/probe-chat.js +13 -0
  78. package/data/probe/examples/chat/build.js +104 -0
  79. package/data/probe/examples/chat/cancelRequest.js +84 -0
  80. package/data/probe/examples/chat/demo-agentic-image-flow.js +88 -0
  81. package/data/probe/examples/chat/demo-local-images.js +128 -0
  82. package/data/probe/examples/chat/fileSpanExporter.js +181 -0
  83. package/data/probe/examples/chat/implement/README.md +228 -0
  84. package/data/probe/examples/chat/implement/backends/AiderBackend.js +750 -0
  85. package/data/probe/examples/chat/implement/backends/BaseBackend.js +276 -0
  86. package/data/probe/examples/chat/implement/backends/ClaudeCodeBackend.js +767 -0
  87. package/data/probe/examples/chat/implement/backends/MockBackend.js +237 -0
  88. package/data/probe/examples/chat/implement/backends/registry.js +85 -0
  89. package/data/probe/examples/chat/implement/core/BackendManager.js +567 -0
  90. package/data/probe/examples/chat/implement/core/ImplementTool.js +354 -0
  91. package/data/probe/examples/chat/implement/core/config.js +428 -0
  92. package/data/probe/examples/chat/implement/core/timeouts.js +58 -0
  93. package/data/probe/examples/chat/implement/core/utils.js +496 -0
  94. package/data/probe/examples/chat/implement/types/BackendTypes.js +126 -0
  95. package/data/probe/examples/chat/index.js +669 -0
  96. package/data/probe/examples/chat/mcpServer.js +341 -0
  97. package/data/probe/examples/chat/npm/LICENSE +15 -0
  98. package/data/probe/examples/chat/npm/README.md +168 -0
  99. package/data/probe/examples/chat/npm/bin/probe-chat.js +156 -0
  100. package/data/probe/examples/chat/npm/index.js +259 -0
  101. package/data/probe/examples/chat/npm/package.json +54 -0
  102. package/data/probe/examples/chat/package.json +102 -0
  103. package/data/probe/examples/chat/probeChat.js +456 -0
  104. package/data/probe/examples/chat/probeTool.js +491 -0
  105. package/data/probe/examples/chat/storage/JsonChatStorage.js +476 -0
  106. package/data/probe/examples/chat/telemetry.js +281 -0
  107. package/data/probe/examples/chat/test/integration/chatFlows.test.js +320 -0
  108. package/data/probe/examples/chat/test/integration/toolCalling.test.js +471 -0
  109. package/data/probe/examples/chat/test/mocks/mockLLMProvider.js +269 -0
  110. package/data/probe/examples/chat/test/test-backends.js +90 -0
  111. package/data/probe/examples/chat/test/testUtils.js +530 -0
  112. package/data/probe/examples/chat/test/unit/backendTimeout.test.js +161 -0
  113. package/data/probe/examples/chat/test/unit/packageFiles.test.js +120 -0
  114. package/data/probe/examples/chat/test/verify-tests.js +118 -0
  115. package/data/probe/examples/chat/test-agentic-image-loading.js +294 -0
  116. package/data/probe/examples/chat/test-ai-sdk-telemetry.js +204 -0
  117. package/data/probe/examples/chat/test-chat-tracing.js +38 -0
  118. package/data/probe/examples/chat/test-direct-function.js +49 -0
  119. package/data/probe/examples/chat/test-file-size-validation.js +103 -0
  120. package/data/probe/examples/chat/test-full-mcp-integration.js +258 -0
  121. package/data/probe/examples/chat/test-github-context.txt +12 -0
  122. package/data/probe/examples/chat/test-hierarchy.js +203 -0
  123. package/data/probe/examples/chat/test-image-spans.js +37 -0
  124. package/data/probe/examples/chat/test-local-image-reading.js +176 -0
  125. package/data/probe/examples/chat/test-mcp-integration.js +136 -0
  126. package/data/probe/examples/chat/test-mcp-probe-server.js +161 -0
  127. package/data/probe/examples/chat/test-mcp-with-ai.js +279 -0
  128. package/data/probe/examples/chat/test-multiple-allowed-dirs.js +111 -0
  129. package/data/probe/examples/chat/test-probe-mcp-server.js +110 -0
  130. package/data/probe/examples/chat/test-security-validation.js +145 -0
  131. package/data/probe/examples/chat/test-simple-tracing.js +32 -0
  132. package/data/probe/examples/chat/test-trace-verification.js +235 -0
  133. package/data/probe/examples/chat/test-tracing.js +114 -0
  134. package/data/probe/examples/chat/tokenCounter.js +419 -0
  135. package/data/probe/examples/chat/tokenUsageDisplay.js +134 -0
  136. package/data/probe/examples/chat/webServer.js +1103 -0
  137. package/data/probe/examples/reranker/Cargo.toml +33 -0
  138. package/data/probe/examples/reranker/DEBUG_OUTPUT_ANALYSIS.md +71 -0
  139. package/data/probe/examples/reranker/MODELS.md +66 -0
  140. package/data/probe/examples/reranker/MODEL_COMPARISON.md +60 -0
  141. package/data/probe/examples/reranker/MULTI_MODEL_ANALYSIS.md +176 -0
  142. package/data/probe/examples/reranker/PERFORMANCE_SUMMARY.md +156 -0
  143. package/data/probe/examples/reranker/README.md +347 -0
  144. package/data/probe/examples/reranker/RUST_BERT_COMPARISON.md +82 -0
  145. package/data/probe/examples/reranker/TOKENIZATION_GUIDE.md +120 -0
  146. package/data/probe/examples/reranker/check_rust_tokenizer.py +108 -0
  147. package/data/probe/examples/reranker/convert_to_torchscript.py +109 -0
  148. package/data/probe/examples/reranker/debug_scoring.py +189 -0
  149. package/data/probe/examples/reranker/debug_tokenization.py +154 -0
  150. package/data/probe/examples/reranker/download_models.sh +73 -0
  151. package/data/probe/examples/reranker/requirements.txt +13 -0
  152. package/data/probe/examples/reranker/run_comprehensive_benchmark.sh +83 -0
  153. package/data/probe/examples/reranker/rust_bert_test/Cargo.toml +12 -0
  154. package/data/probe/examples/reranker/rust_bert_test/README.md +54 -0
  155. package/data/probe/examples/reranker/simple_test.py +50 -0
  156. package/data/probe/examples/reranker/test_all_models.sh +63 -0
  157. package/data/probe/examples/reranker/test_bert_results.sh +44 -0
  158. package/data/probe/examples/reranker/test_cross_encoder.py +334 -0
  159. package/data/probe/examples/reranker/test_cross_encoder.sh +80 -0
  160. package/data/probe/examples/reranker/test_exact_comparison.py +151 -0
  161. package/data/probe/examples/reranker/test_parallel_performance.sh +56 -0
  162. package/data/probe/examples/reranker/test_scores.py +132 -0
  163. package/data/probe/install.ps1 +508 -0
  164. package/data/probe/install.sh +460 -0
  165. package/data/probe/npm/CLONE_METHOD_EXAMPLES.md +596 -0
  166. package/data/probe/npm/CONTEXT_COMPACTION.md +303 -0
  167. package/data/probe/npm/DELEGATE_TOOL_README.md +166 -0
  168. package/data/probe/npm/MAID_INTEGRATION.md +313 -0
  169. package/data/probe/npm/MCP_INTEGRATION_SUMMARY.md +241 -0
  170. package/data/probe/npm/README.md +824 -0
  171. package/data/probe/npm/bin/.gitignore +7 -0
  172. package/data/probe/npm/bin/.gitkeep +0 -0
  173. package/data/probe/npm/bin/README.md +12 -0
  174. package/data/probe/npm/bin/probe +167 -0
  175. package/data/probe/npm/docs/CLAUDE_CODE_INTEGRATION.md +414 -0
  176. package/data/probe/npm/docs/CODEX_INTEGRATION.md +502 -0
  177. package/data/probe/npm/docs/EDIT_CREATE_TOOLS.md +233 -0
  178. package/data/probe/npm/docs/RETRY_AND_FALLBACK.md +674 -0
  179. package/data/probe/npm/example-usage.js +335 -0
  180. package/data/probe/npm/examples/multi-engine-demo.js +117 -0
  181. package/data/probe/npm/examples/probe-agent-cli.js +113 -0
  182. package/data/probe/npm/examples/test-agent-edit.js +114 -0
  183. package/data/probe/npm/examples/test-edit-create.js +120 -0
  184. package/data/probe/npm/examples/test-edit-direct.js +114 -0
  185. package/data/probe/npm/index.d.ts +744 -0
  186. package/data/probe/npm/jest.config.js +52 -0
  187. package/data/probe/npm/package.json +117 -0
  188. package/data/probe/npm/scripts/build-agent.cjs +75 -0
  189. package/data/probe/npm/scripts/build-cjs.js +124 -0
  190. package/data/probe/npm/scripts/build-mcp.cjs +36 -0
  191. package/data/probe/npm/scripts/postinstall.js +216 -0
  192. package/data/probe/npm/test-codex-e2e.js +78 -0
  193. package/data/probe/npm/test-download-lock.js +109 -0
  194. package/data/probe/npm/test-grep-security.js +94 -0
  195. package/data/probe/npm/test-grep-simplified.js +63 -0
  196. package/data/probe/npm/test-grep.js +51 -0
  197. package/data/probe/npm/tests/README.md +96 -0
  198. package/data/probe/npm/tests/agent-compact-history.test.js +174 -0
  199. package/data/probe/npm/tests/allow-tests-default.test.js +151 -0
  200. package/data/probe/npm/tests/contextCompactor.test.js +498 -0
  201. package/data/probe/npm/tests/delegate-config.test.js +353 -0
  202. package/data/probe/npm/tests/delegate-integration.test.js +348 -0
  203. package/data/probe/npm/tests/extractor-integration.test.js +162 -0
  204. package/data/probe/npm/tests/extractor.test.js +317 -0
  205. package/data/probe/npm/tests/fixtures/sampleDiagrams.js +267 -0
  206. package/data/probe/npm/tests/integration/claude-code-auto-fallback.spec.js +148 -0
  207. package/data/probe/npm/tests/integration/claude-code-multi-step.spec.js +127 -0
  208. package/data/probe/npm/tests/integration/claude-code-tool-events.spec.js +163 -0
  209. package/data/probe/npm/tests/integration/codex-auto-fallback.spec.js +191 -0
  210. package/data/probe/npm/tests/integration/codex-tool-events.spec.js +147 -0
  211. package/data/probe/npm/tests/integration/examplesChatMcp.test.js +402 -0
  212. package/data/probe/npm/tests/integration/mcpDotenvSupport.test.js +174 -0
  213. package/data/probe/npm/tests/integration/mcpErrorHandling.test.js +566 -0
  214. package/data/probe/npm/tests/integration/mcpRobustness.test.js +564 -0
  215. package/data/probe/npm/tests/integration/mcpStdoutPurity.test.js +355 -0
  216. package/data/probe/npm/tests/integration/probeAgentMcp.test.js +398 -0
  217. package/data/probe/npm/tests/integration/retryFallback.test.js +368 -0
  218. package/data/probe/npm/tests/integration/schema-in-initial-message.test.js +318 -0
  219. package/data/probe/npm/tests/integration/schema-validation-loop-prevention.test.js +244 -0
  220. package/data/probe/npm/tests/integration/schemaRetryLogic.test.js +94 -0
  221. package/data/probe/npm/tests/integration/validationFlow.test.js +329 -0
  222. package/data/probe/npm/tests/manual/test-codex-basic.js +110 -0
  223. package/data/probe/npm/tests/mcp/mcpClientManager.test.js +614 -0
  224. package/data/probe/npm/tests/mcp/mcpConfig.test.js +359 -0
  225. package/data/probe/npm/tests/mcp/mcpXmlBridge.test.js +436 -0
  226. package/data/probe/npm/tests/mcp/mockMcpServer.js +510 -0
  227. package/data/probe/npm/tests/mcp-strict-syntax.test.js +319 -0
  228. package/data/probe/npm/tests/mermaidQuoteEscaping.test.js +214 -0
  229. package/data/probe/npm/tests/nestedQuoteFix.test.js +40 -0
  230. package/data/probe/npm/tests/setup.js +46 -0
  231. package/data/probe/npm/tests/unit/allowed-tools.test.js +513 -0
  232. package/data/probe/npm/tests/unit/attempt-completion-closing-tag-in-content.test.js +188 -0
  233. package/data/probe/npm/tests/unit/attemptCompletionJsonFix.test.js +238 -0
  234. package/data/probe/npm/tests/unit/attemptCompletionJsonIssue.test.js +128 -0
  235. package/data/probe/npm/tests/unit/backtickAutoFix.test.js +35 -0
  236. package/data/probe/npm/tests/unit/bash-probe-agent-integration.test.js +389 -0
  237. package/data/probe/npm/tests/unit/bash-simple-commands.test.js +324 -0
  238. package/data/probe/npm/tests/unit/bash-tool-comprehensive.test.js +371 -0
  239. package/data/probe/npm/tests/unit/bash-tool-integration.test.js +310 -0
  240. package/data/probe/npm/tests/unit/bash-tool.test.js +341 -0
  241. package/data/probe/npm/tests/unit/completion-prompt.test.js +379 -0
  242. package/data/probe/npm/tests/unit/cwd-path-options.test.js +287 -0
  243. package/data/probe/npm/tests/unit/delegate-limits.test.js +422 -0
  244. package/data/probe/npm/tests/unit/direct-content-attempt-completion.test.js +235 -0
  245. package/data/probe/npm/tests/unit/edit-create-tools.test.js +609 -0
  246. package/data/probe/npm/tests/unit/enhancedMermaidValidation.test.js +577 -0
  247. package/data/probe/npm/tests/unit/extract-content.test.js +83 -0
  248. package/data/probe/npm/tests/unit/extract-multiple-targets.test.js +89 -0
  249. package/data/probe/npm/tests/unit/fallbackManager.test.js +442 -0
  250. package/data/probe/npm/tests/unit/githubCompatibilityValidation.test.js +258 -0
  251. package/data/probe/npm/tests/unit/imageConfig.test.js +149 -0
  252. package/data/probe/npm/tests/unit/imagePathResolution.test.js +345 -0
  253. package/data/probe/npm/tests/unit/json-fixing-agent.test.js +238 -0
  254. package/data/probe/npm/tests/unit/json-validation-enhanced-errors.test.js +199 -0
  255. package/data/probe/npm/tests/unit/jsonValidationInfiniteLoopFix.test.js +228 -0
  256. package/data/probe/npm/tests/unit/maidIntegration.test.js +139 -0
  257. package/data/probe/npm/tests/unit/maxIterationsWarning.test.js +195 -0
  258. package/data/probe/npm/tests/unit/mermaidEdgeLabelFix.test.js +161 -0
  259. package/data/probe/npm/tests/unit/mermaidHtmlEntities.test.js +76 -0
  260. package/data/probe/npm/tests/unit/mermaidInfiniteLoopFix.test.js +64 -0
  261. package/data/probe/npm/tests/unit/mermaidValidation.test.js +723 -0
  262. package/data/probe/npm/tests/unit/mermaidValidationVisorExample.test.js +309 -0
  263. package/data/probe/npm/tests/unit/probe-agent-clone-realistic.test.js +643 -0
  264. package/data/probe/npm/tests/unit/probe-agent-clone.test.js +476 -0
  265. package/data/probe/npm/tests/unit/probe-agent-delegate.test.js +400 -0
  266. package/data/probe/npm/tests/unit/probe-agent-model-option.test.js +118 -0
  267. package/data/probe/npm/tests/unit/probeTool-security.test.js +283 -0
  268. package/data/probe/npm/tests/unit/readImageTool.test.js +418 -0
  269. package/data/probe/npm/tests/unit/retryManager.test.js +317 -0
  270. package/data/probe/npm/tests/unit/schema-aware-reminders.test.js +288 -0
  271. package/data/probe/npm/tests/unit/schemaDefinitionDetection.test.js +115 -0
  272. package/data/probe/npm/tests/unit/schemaUtils.test.js +1268 -0
  273. package/data/probe/npm/tests/unit/simpleTelemetry.test.js +282 -0
  274. package/data/probe/npm/tests/unit/simplified-attempt-completion.test.js +274 -0
  275. package/data/probe/npm/tests/unit/single-quote-json-bug.test.js +231 -0
  276. package/data/probe/npm/tests/unit/subgraphAutoFix.test.js +110 -0
  277. package/data/probe/npm/tests/unit/system-prompt.test.js +32 -0
  278. package/data/probe/npm/tests/unit/types-probe-agent-options.test.js +42 -0
  279. package/data/probe/npm/tests/unit/xmlParsing.test.js +720 -0
  280. package/data/probe/npm/tsconfig.json +21 -0
  281. package/data/probe/result1.txt +19 -0
  282. package/data/probe/result2.txt +26 -0
  283. package/data/probe/scripts/benchmark.sh +270 -0
  284. package/data/probe/scripts/cache_memory_analysis.rs +844 -0
  285. package/data/probe/scripts/claude-hook-wrapper.sh +56 -0
  286. package/data/probe/site/.env.example +10 -0
  287. package/data/probe/site/DEPLOYMENT.md +86 -0
  288. package/data/probe/site/README.md +183 -0
  289. package/data/probe/site/adding-languages.md +135 -0
  290. package/data/probe/site/ai-chat.md +427 -0
  291. package/data/probe/site/ai-integration.md +1488 -0
  292. package/data/probe/site/blog/agentic-flow-custom-xml-protocol.md +407 -0
  293. package/data/probe/site/blog/index.md +118 -0
  294. package/data/probe/site/blog/v0.6.0-release.md +426 -0
  295. package/data/probe/site/blog.md +8 -0
  296. package/data/probe/site/changelog.md +200 -0
  297. package/data/probe/site/cli-mode.md +437 -0
  298. package/data/probe/site/code-extraction.md +436 -0
  299. package/data/probe/site/contributing/README.md +9 -0
  300. package/data/probe/site/contributing/documentation-cross-references.md +215 -0
  301. package/data/probe/site/contributing/documentation-maintenance.md +275 -0
  302. package/data/probe/site/contributing/documentation-structure.md +75 -0
  303. package/data/probe/site/documentation-cross-references.md +215 -0
  304. package/data/probe/site/documentation-guide.md +132 -0
  305. package/data/probe/site/documentation-maintenance.md +275 -0
  306. package/data/probe/site/features.md +147 -0
  307. package/data/probe/site/how-it-works.md +118 -0
  308. package/data/probe/site/index.md +175 -0
  309. package/data/probe/site/index.md.bak +133 -0
  310. package/data/probe/site/installation.md +235 -0
  311. package/data/probe/site/integrations/docker.md +248 -0
  312. package/data/probe/site/integrations/github-actions.md +413 -0
  313. package/data/probe/site/language-support-overview.md +168 -0
  314. package/data/probe/site/mcp-integration.md +587 -0
  315. package/data/probe/site/mcp-server.md +304 -0
  316. package/data/probe/site/navigation-structure.md +76 -0
  317. package/data/probe/site/nodejs-sdk.md +798 -0
  318. package/data/probe/site/output-formats.md +625 -0
  319. package/data/probe/site/package.json +21 -0
  320. package/data/probe/site/public/_headers +28 -0
  321. package/data/probe/site/public/_redirects +11 -0
  322. package/data/probe/site/quick-start.md +289 -0
  323. package/data/probe/site/search-functionality.md +291 -0
  324. package/data/probe/site/search-reference.md +291 -0
  325. package/data/probe/site/supported-languages.md +215 -0
  326. package/data/probe/site/use-cases/README.md +8 -0
  327. package/data/probe/site/use-cases/advanced-cli.md +253 -0
  328. package/data/probe/site/use-cases/ai-code-editors.md +239 -0
  329. package/data/probe/site/use-cases/building-ai-tools.md +529 -0
  330. package/data/probe/site/use-cases/cli-ai-workflows.md +285 -0
  331. package/data/probe/site/use-cases/deploying-probe-web-interface.md +255 -0
  332. package/data/probe/site/use-cases/integrating-probe-into-ai-code-editors.md +161 -0
  333. package/data/probe/site/use-cases/nodejs-sdk.md +596 -0
  334. package/data/probe/site/use-cases/team-chat.md +350 -0
  335. package/data/probe/site/web-interface.md +434 -0
  336. package/data/probe/site/wrangler.toml +9 -0
  337. package/data/probe/test-api-key.sh +1 -0
  338. package/data/probe/test-probe-implementation/hello.js +7 -0
  339. package/data/probe/test_cases/demonstrate_early_termination_issues.sh +176 -0
  340. package/data/probe/test_cases/early_termination_issues.rs +533 -0
  341. package/data/probe/test_data/test_nested_struct.go +26 -0
  342. package/data/probe/tests/README.md +286 -0
  343. package/data/probe/tests/README_search_determinism_tests.md +116 -0
  344. package/data/probe/tests/adjacent_comment_test.rs +152 -0
  345. package/data/probe/tests/apostrophe_handling_tests.rs +132 -0
  346. package/data/probe/tests/block_filtering_with_ast_tests.rs +669 -0
  347. package/data/probe/tests/block_merging_tests.rs +396 -0
  348. package/data/probe/tests/c_outline_format_tests.rs +2179 -0
  349. package/data/probe/tests/cache_invalidation_issues.rs.disabled +682 -0
  350. package/data/probe/tests/cache_order_tests.rs +147 -0
  351. package/data/probe/tests/cache_query_scoping_tests.rs +221 -0
  352. package/data/probe/tests/cli_tests.rs +680 -0
  353. package/data/probe/tests/comment_context_integration_test.rs +240 -0
  354. package/data/probe/tests/common.rs +33 -0
  355. package/data/probe/tests/complex_block_merging_tests.rs +599 -0
  356. package/data/probe/tests/complex_query_block_filtering_tests.rs +422 -0
  357. package/data/probe/tests/control_flow_closing_braces_test.rs +91 -0
  358. package/data/probe/tests/cpp_outline_format_tests.rs +1507 -0
  359. package/data/probe/tests/csharp_outline_format_tests.rs +941 -0
  360. package/data/probe/tests/elastic_query_integration_tests.rs +922 -0
  361. package/data/probe/tests/extract_command_tests.rs +1848 -0
  362. package/data/probe/tests/extract_deduplication_tests.rs +146 -0
  363. package/data/probe/tests/extract_input_file_tests.rs +84 -0
  364. package/data/probe/tests/extract_prompt_tests.rs +102 -0
  365. package/data/probe/tests/filename_search_tests.rs +96 -0
  366. package/data/probe/tests/fixtures/user/AssemblyInfo.cs +3 -0
  367. package/data/probe/tests/github_extract_tests.rs +234 -0
  368. package/data/probe/tests/go_comment_test.rs +253 -0
  369. package/data/probe/tests/go_outline_format_tests.rs +2587 -0
  370. package/data/probe/tests/go_path_resolver_tests.rs +96 -0
  371. package/data/probe/tests/html_outline_format_tests.rs +637 -0
  372. package/data/probe/tests/integration_tests.rs +837 -0
  373. package/data/probe/tests/ip_whitelist_test.rs +148 -0
  374. package/data/probe/tests/java_outline_format_tests.rs +1611 -0
  375. package/data/probe/tests/javascript_extract_tests.rs +315 -0
  376. package/data/probe/tests/javascript_outline_format_tests.rs +1464 -0
  377. package/data/probe/tests/json_format_tests.rs +436 -0
  378. package/data/probe/tests/json_schema_validation_tests.rs +450 -0
  379. package/data/probe/tests/lib_usage.rs +60 -0
  380. package/data/probe/tests/line_comment_context_extension_test.rs +459 -0
  381. package/data/probe/tests/line_map_cache_tests.rs +114 -0
  382. package/data/probe/tests/markdown_integration_tests.rs +190 -0
  383. package/data/probe/tests/mocks/test_ip_whitelist.go +11 -0
  384. package/data/probe/tests/mocks/test_object.js +27 -0
  385. package/data/probe/tests/mocks/test_struct.go +50 -0
  386. package/data/probe/tests/multi_keyword_pattern_tests.rs +464 -0
  387. package/data/probe/tests/multi_language_syntax_integration_tests.rs +218 -0
  388. package/data/probe/tests/multiple_capture_groups_tests.rs +169 -0
  389. package/data/probe/tests/negative_compound_word_tests.rs +246 -0
  390. package/data/probe/tests/nested_symbol_extraction_tests.rs +99 -0
  391. package/data/probe/tests/outline_cross_file_interference_test.rs +335 -0
  392. package/data/probe/tests/outline_keyword_preservation_test.rs +67 -0
  393. package/data/probe/tests/output_format_edge_cases_tests.rs +693 -0
  394. package/data/probe/tests/parallel_extraction_tests.rs +178 -0
  395. package/data/probe/tests/parallel_search_tests.rs +355 -0
  396. package/data/probe/tests/path_resolver_tests.rs +698 -0
  397. package/data/probe/tests/php_outline_format_extended_tests.rs +928 -0
  398. package/data/probe/tests/php_outline_format_tests.rs +768 -0
  399. package/data/probe/tests/property_tests.proptest-regressions +9 -0
  400. package/data/probe/tests/property_tests.rs +118 -0
  401. package/data/probe/tests/python_outline_format_tests.rs +1538 -0
  402. package/data/probe/tests/query_command_json_tests.rs +438 -0
  403. package/data/probe/tests/query_command_tests.rs +232 -0
  404. package/data/probe/tests/query_command_xml_tests.rs +569 -0
  405. package/data/probe/tests/quoted_term_with_negative_keyword_tests.rs +216 -0
  406. package/data/probe/tests/required_terms_filename_tests.rs +116 -0
  407. package/data/probe/tests/ruby_outline_format_tests.rs +1011 -0
  408. package/data/probe/tests/rust_line_comment_context_test.rs +151 -0
  409. package/data/probe/tests/rust_outline_format_enhanced_tests.rs +725 -0
  410. package/data/probe/tests/rust_outline_format_tests.rs +843 -0
  411. package/data/probe/tests/schemas/xml_output_schema.xsd +38 -0
  412. package/data/probe/tests/search_determinism_tests.rs +451 -0
  413. package/data/probe/tests/search_hints_tests.rs +253 -0
  414. package/data/probe/tests/special_character_escaping_tests.rs +417 -0
  415. package/data/probe/tests/stemming_compound_word_filtering_tests.rs +535 -0
  416. package/data/probe/tests/strict_elastic_syntax_tests.rs +404 -0
  417. package/data/probe/tests/swift_outline_format_tests.rs +3319 -0
  418. package/data/probe/tests/symbols_tests.rs +166 -0
  419. package/data/probe/tests/test_file.rs +45 -0
  420. package/data/probe/tests/test_tokenize.rs +28 -0
  421. package/data/probe/tests/timeout_tests.rs +82 -0
  422. package/data/probe/tests/tokenization_tests.rs +195 -0
  423. package/data/probe/tests/tokenized_block_filtering_tests.rs +174 -0
  424. package/data/probe/tests/typescript_extract_tests.rs +214 -0
  425. package/data/probe/tests/typescript_outline_format_tests.rs +2188 -0
  426. package/data/probe/tests/xml_format_tests.rs +568 -0
  427. package/data/probe/tests/xml_schema_validation_tests.rs +497 -0
  428. package/data/scripts/postinstall.mjs +9 -0
  429. package/data/scripts/set-version.js +0 -0
  430. package/data/scripts/wiki-build.sh +111 -0
  431. package/data/scripts/wiki-deploy.sh +73 -0
  432. package/data/serve.json +12 -0
  433. package/data/test/demo-dynamic.html +134 -0
  434. package/data/test/demo-esm.html +105 -0
  435. package/data/test/demo-iife.html +78 -0
  436. package/data/tsconfig.json +7 -0
  437. package/data/vite.server.ts +483 -0
  438. package/data/vitest.config.ts +40 -0
  439. package/data/wiki/Home.md +58 -0
  440. package/data/wiki/_Sidebar.md +39 -0
  441. package/docs-mcp.config.json +20 -0
  442. package/package.json +56 -0
  443. package/src/config.js +111 -0
  444. 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
+ }