|
447 | 447 | (ai-code-take-notes t) |
448 | 448 | (should (equal captured-file "/tmp/project/.ai.code.files/test-notes.org"))))) |
449 | 449 |
|
| 450 | +(ert-deftest ai-code-test-derive-architecture-guardrails-creates-template-and-prompt () |
| 451 | + "Test `ai-code-derive-architecture-guardrails' initializes the Org file and prompt." |
| 452 | + (let* ((tmp-root (make-temp-file "ai-code-guardrails" t)) |
| 453 | + (target-file (expand-file-name ".ai.code.files/architecture/guardrails.org" tmp-root)) |
| 454 | + captured-initial-prompt |
| 455 | + captured-final-prompt) |
| 456 | + (unwind-protect |
| 457 | + (cl-letf (((symbol-function 'ai-code--git-root) |
| 458 | + (lambda (&optional _dir) |
| 459 | + tmp-root)) |
| 460 | + ((symbol-function 'ai-code-read-string) |
| 461 | + (lambda (prompt initial-input &optional _candidate-list) |
| 462 | + (should (equal prompt "Prompt: ")) |
| 463 | + (setq captured-initial-prompt initial-input) |
| 464 | + initial-input)) |
| 465 | + ((symbol-function 'ai-code--insert-prompt) |
| 466 | + (lambda (prompt) |
| 467 | + (setq captured-final-prompt prompt)))) |
| 468 | + (ai-code-derive-architecture-guardrails) |
| 469 | + (should (file-exists-p target-file)) |
| 470 | + (with-temp-buffer |
| 471 | + (insert-file-contents target-file) |
| 472 | + (should (string-match-p (regexp-quote "#+TITLE: Architecture Guardrails") |
| 473 | + (buffer-string))) |
| 474 | + (should (string-match-p (regexp-quote "* Dependency Rules") |
| 475 | + (buffer-string))) |
| 476 | + (should (string-match-p (regexp-quote "* Required Validation") |
| 477 | + (buffer-string)))) |
| 478 | + (should (string-match-p (regexp-quote "Derive a lightweight architecture guardrails document") |
| 479 | + captured-initial-prompt)) |
| 480 | + (should (string-match-p (regexp-quote "current code, tests, docs, and filenames") |
| 481 | + captured-initial-prompt)) |
| 482 | + (should (string-match-p (regexp-quote "Do not invent an ideal architecture") |
| 483 | + captured-initial-prompt)) |
| 484 | + (should (string-match-p (regexp-quote "Keep it concise") |
| 485 | + captured-initial-prompt)) |
| 486 | + (should (string-match-p (regexp-quote "@.ai.code.files/architecture/guardrails.org") |
| 487 | + captured-initial-prompt)) |
| 488 | + (should (string-match-p (regexp-quote "Org-mode format") |
| 489 | + captured-initial-prompt)) |
| 490 | + (should (equal captured-final-prompt captured-initial-prompt))) |
| 491 | + (ignore-errors (delete-directory tmp-root t))))) |
| 492 | + |
| 493 | +(ert-deftest ai-code-test-derive-architecture-guardrails-preserves-existing-file () |
| 494 | + "Test `ai-code-derive-architecture-guardrails' does not overwrite an existing file." |
| 495 | + (let* ((tmp-root (make-temp-file "ai-code-guardrails-existing" t)) |
| 496 | + (files-dir (expand-file-name ".ai.code.files/architecture" tmp-root)) |
| 497 | + (target-file (expand-file-name "guardrails.org" files-dir)) |
| 498 | + (existing-content "#+TITLE: Existing guardrails\n")) |
| 499 | + (unwind-protect |
| 500 | + (progn |
| 501 | + (make-directory files-dir t) |
| 502 | + (with-temp-file target-file |
| 503 | + (insert existing-content)) |
| 504 | + (cl-letf (((symbol-function 'ai-code--git-root) |
| 505 | + (lambda (&optional _dir) |
| 506 | + tmp-root)) |
| 507 | + ((symbol-function 'ai-code-read-string) |
| 508 | + (lambda (_prompt initial-input &optional _candidate-list) |
| 509 | + initial-input)) |
| 510 | + ((symbol-function 'ai-code--insert-prompt) |
| 511 | + (lambda (_prompt)))) |
| 512 | + (ai-code-derive-architecture-guardrails)) |
| 513 | + (with-temp-buffer |
| 514 | + (insert-file-contents target-file) |
| 515 | + (should (equal (buffer-string) existing-content)))) |
| 516 | + (ignore-errors (delete-directory tmp-root t))))) |
| 517 | + |
| 518 | +(ert-deftest ai-code-test-derive-architecture-guardrails-errors-outside-git-repo () |
| 519 | + "Test `ai-code-derive-architecture-guardrails' requires a git repository." |
| 520 | + (cl-letf (((symbol-function 'ai-code--git-root) |
| 521 | + (lambda (&optional _dir) |
| 522 | + nil))) |
| 523 | + (should-error (ai-code-derive-architecture-guardrails) |
| 524 | + :type 'user-error))) |
| 525 | + |
| 526 | +(ert-deftest ai-code-test-derive-architecture-guardrails-reports-cancelled-request () |
| 527 | + "Test `ai-code-derive-architecture-guardrails' reports cancellation." |
| 528 | + (let* ((tmp-root (make-temp-file "ai-code-guardrails-cancel" t)) |
| 529 | + captured-message |
| 530 | + insert-called) |
| 531 | + (unwind-protect |
| 532 | + (cl-letf (((symbol-function 'ai-code--git-root) |
| 533 | + (lambda (&optional _dir) |
| 534 | + tmp-root)) |
| 535 | + ((symbol-function 'ai-code-read-string) |
| 536 | + (lambda (&rest _args) |
| 537 | + nil)) |
| 538 | + ((symbol-function 'ai-code--insert-prompt) |
| 539 | + (lambda (&rest _args) |
| 540 | + (setq insert-called t))) |
| 541 | + ((symbol-function 'message) |
| 542 | + (lambda (format-string &rest args) |
| 543 | + (setq captured-message |
| 544 | + (apply #'format format-string args))))) |
| 545 | + (ai-code-derive-architecture-guardrails) |
| 546 | + (should-not insert-called) |
| 547 | + (should (equal captured-message |
| 548 | + "Architecture guardrails request cancelled"))) |
| 549 | + (ignore-errors (delete-directory tmp-root t))))) |
| 550 | + |
| 551 | +(ert-deftest ai-code-test-menu-source-includes-derive-architecture-guardrails-entry () |
| 552 | + "Test the menu source exposes the architecture guardrails command." |
| 553 | + (let ((repo-root |
| 554 | + (file-name-directory (locate-library "ai-code-discussion")))) |
| 555 | + (with-temp-buffer |
| 556 | + (insert-file-contents (expand-file-name "ai-code.el" repo-root)) |
| 557 | + (should (re-search-forward |
| 558 | + "(\"A\" \"Derive Architecture Guardrails\" ai-code-derive-architecture-guardrails)" |
| 559 | + nil t))))) |
| 560 | + |
450 | 561 | (provide 'test_ai-code-discussion) |
451 | 562 |
|
452 | 563 | ;;; test_ai-code-discussion.el ends here |
0 commit comments