|
228 | 228 | (should (member "sample.el:4: beta" result)))) |
229 | 229 | (delete-directory project-dir t)))) |
230 | 230 |
|
| 231 | +(ert-deftest ai-code-test-mcp-server-source-requires-seq-explicitly () |
| 232 | + "The MCP server source should declare its seq dependency explicitly." |
| 233 | + (with-temp-buffer |
| 234 | + (insert-file-contents "ai-code-mcp-server.el") |
| 235 | + (goto-char (point-min)) |
| 236 | + (should (search-forward "(require 'seq)" nil t)))) |
| 237 | + |
231 | 238 | (ert-deftest ai-code-test-mcp-buffer-query-returns-selected-buffer-lines () |
232 | 239 | "Buffer query should return the requested line range from a live buffer." |
233 | 240 | (let ((buffer (generate-new-buffer " *ai-code-mcp-buffer-query*"))) |
|
242 | 249 | (when (buffer-live-p buffer) |
243 | 250 | (kill-buffer buffer))))) |
244 | 251 |
|
| 252 | +(ert-deftest ai-code-test-mcp-buffer-query-preserves-trailing-whitespace () |
| 253 | + "Buffer query should preserve trailing whitespace in the selected text." |
| 254 | + (let ((buffer (generate-new-buffer " *ai-code-mcp-buffer-query-whitespace*"))) |
| 255 | + (unwind-protect |
| 256 | + (with-current-buffer buffer |
| 257 | + (insert "alpha\nbeta \n") |
| 258 | + (should (equal "beta " |
| 259 | + (ai-code-mcp-buffer-query |
| 260 | + (buffer-name buffer) |
| 261 | + 2 |
| 262 | + 1)))) |
| 263 | + (when (buffer-live-p buffer) |
| 264 | + (kill-buffer buffer))))) |
| 265 | + |
| 266 | +(ert-deftest ai-code-test-mcp-buffer-query-requires-positive-line-range () |
| 267 | + "Buffer query should reject non-positive line range arguments." |
| 268 | + (let ((buffer (generate-new-buffer " *ai-code-mcp-buffer-query-range*"))) |
| 269 | + (unwind-protect |
| 270 | + (with-current-buffer buffer |
| 271 | + (insert "alpha\nbeta\n") |
| 272 | + (should-error |
| 273 | + (ai-code-mcp-buffer-query (buffer-name buffer) 0 1)) |
| 274 | + (should-error |
| 275 | + (ai-code-mcp-buffer-query (buffer-name buffer) 1 0))) |
| 276 | + (when (buffer-live-p buffer) |
| 277 | + (kill-buffer buffer))))) |
| 278 | + |
245 | 279 | (ert-deftest ai-code-test-mcp-get-project-files-returns-relative-project-paths () |
246 | 280 | "Project files should list regular files relative to the session project root." |
247 | 281 | (let* ((project-dir (make-temp-file "ai-code-mcp-project-files-" t)) |
|
264 | 298 | (kill-buffer buffer)) |
265 | 299 | (delete-directory project-dir t)))) |
266 | 300 |
|
| 301 | +(ert-deftest ai-code-test-mcp-get-project-files-skips-hidden-directories () |
| 302 | + "Project files should skip hidden directories such as .git." |
| 303 | + (let* ((project-dir (make-temp-file "ai-code-mcp-project-files-hidden-" t)) |
| 304 | + (file-a (expand-file-name "alpha.el" project-dir)) |
| 305 | + (file-b (expand-file-name "nested/beta.el" project-dir)) |
| 306 | + (hidden-file (expand-file-name ".git/HEAD" project-dir)) |
| 307 | + (buffer (generate-new-buffer " *ai-code-mcp-project-files-hidden*")) |
| 308 | + (ai-code-mcp--sessions (make-hash-table :test 'equal)) |
| 309 | + (ai-code-mcp--current-session-id "session-project-files-hidden")) |
| 310 | + (unwind-protect |
| 311 | + (progn |
| 312 | + (make-directory (file-name-directory file-b) t) |
| 313 | + (make-directory (file-name-directory hidden-file) t) |
| 314 | + (with-temp-file file-a |
| 315 | + (insert "(message \"alpha\")\n")) |
| 316 | + (with-temp-file file-b |
| 317 | + (insert "(message \"beta\")\n")) |
| 318 | + (with-temp-file hidden-file |
| 319 | + (insert "ref: refs/heads/main\n")) |
| 320 | + (ai-code-mcp-register-session |
| 321 | + "session-project-files-hidden" |
| 322 | + project-dir |
| 323 | + buffer) |
| 324 | + (should (equal '("alpha.el" "nested/beta.el") |
| 325 | + (sort (ai-code-mcp-get-project-files) #'string<)))) |
| 326 | + (when (buffer-live-p buffer) |
| 327 | + (kill-buffer buffer)) |
| 328 | + (delete-directory project-dir t)))) |
| 329 | + |
267 | 330 | (ert-deftest ai-code-test-mcp-get-project-buffers-lists-open-buffers-in-project () |
268 | 331 | "Project buffers should include file-visiting buffers under the active project." |
269 | 332 | (let* ((project-dir (make-temp-file "ai-code-mcp-project-buffers-" t)) |
|
309 | 372 | "Definitions-at-point should resolve via the xref backend at a file location." |
310 | 373 | (let* ((project-dir (make-temp-file "ai-code-mcp-xref-defs-" t)) |
311 | 374 | (file-path (expand-file-name "defs.el" project-dir)) |
312 | | - (buffer (generate-new-buffer " *ai-code-mcp-xref-defs*"))) |
| 375 | + visited-buffer) |
313 | 376 | (unwind-protect |
314 | 377 | (progn |
315 | 378 | (with-temp-file file-path |
|
330 | 393 | (ai-code-mcp-xref-find-definitions-at-point |
331 | 394 | file-path |
332 | 395 | 2 |
333 | | - 3))))) |
| 396 | + 3)))) |
| 397 | + (setq visited-buffer (find-buffer-visiting file-path))) |
| 398 | + (when (buffer-live-p visited-buffer) |
| 399 | + (kill-buffer visited-buffer)) |
| 400 | + (delete-directory project-dir t)))) |
| 401 | + |
| 402 | +(ert-deftest ai-code-test-mcp-display-path-keeps-external-sibling-absolute () |
| 403 | + "Display path should keep sibling paths outside the project absolute." |
| 404 | + (let* ((project-dir (make-temp-file "ai-code-mcp-display-path-" t)) |
| 405 | + (sibling-dir (concat project-dir "-sibling")) |
| 406 | + (external-file (expand-file-name "other.el" sibling-dir)) |
| 407 | + (buffer (generate-new-buffer " *ai-code-mcp-display-path*")) |
| 408 | + (ai-code-mcp--sessions (make-hash-table :test 'equal)) |
| 409 | + (ai-code-mcp--current-session-id "session-display-path")) |
| 410 | + (unwind-protect |
| 411 | + (progn |
| 412 | + (make-directory sibling-dir t) |
| 413 | + (with-temp-file external-file |
| 414 | + (insert "(message \"other\")\n")) |
| 415 | + (ai-code-mcp-register-session "session-display-path" project-dir buffer) |
| 416 | + (should (equal (expand-file-name external-file) |
| 417 | + (ai-code-mcp--display-path external-file)))) |
334 | 418 | (when (buffer-live-p buffer) |
335 | 419 | (kill-buffer buffer)) |
336 | | - (delete-directory project-dir t)))) |
| 420 | + (let ((visited-buffer (find-buffer-visiting external-file))) |
| 421 | + (when (buffer-live-p visited-buffer) |
| 422 | + (kill-buffer visited-buffer))) |
| 423 | + (delete-directory project-dir t) |
| 424 | + (delete-directory sibling-dir t)))) |
| 425 | + |
| 426 | +(ert-deftest ai-code-test-mcp-format-xref-item-preserves-external-absolute-path () |
| 427 | + "Xref items outside the project should keep their absolute file path." |
| 428 | + (let* ((project-dir (make-temp-file "ai-code-mcp-xref-project-" t)) |
| 429 | + (external-dir (make-temp-file "ai-code-mcp-xref-external-" t)) |
| 430 | + (external-file (expand-file-name "index.el" external-dir)) |
| 431 | + (buffer (generate-new-buffer " *ai-code-mcp-xref-format*")) |
| 432 | + (ai-code-mcp--sessions (make-hash-table :test 'equal)) |
| 433 | + (ai-code-mcp--current-session-id "session-xref-format")) |
| 434 | + (unwind-protect |
| 435 | + (progn |
| 436 | + (with-temp-file external-file |
| 437 | + (insert "(message \"external\")\n")) |
| 438 | + (ai-code-mcp-register-session "session-xref-format" project-dir buffer) |
| 439 | + (should (equal |
| 440 | + (format "%s:1: external summary" |
| 441 | + (expand-file-name external-file)) |
| 442 | + (ai-code-mcp--format-xref-item |
| 443 | + (xref-make |
| 444 | + "external summary" |
| 445 | + (xref-make-file-location external-file 1 0)))))) |
| 446 | + (when (buffer-live-p buffer) |
| 447 | + (kill-buffer buffer)) |
| 448 | + (let ((visited-buffer (find-buffer-visiting external-file))) |
| 449 | + (when (buffer-live-p visited-buffer) |
| 450 | + (kill-buffer visited-buffer))) |
| 451 | + (delete-directory project-dir t) |
| 452 | + (delete-directory external-dir t)))) |
337 | 453 |
|
338 | 454 | (provide 'test_ai-code-mcp-server) |
339 | 455 |
|
|
0 commit comments