;;; test-ob-elixir-modules.el --- Module definition block tests -*- lexical-binding: t; -*- ;;; Commentary: ;; Tests for the module definition block functionality. ;; Tests the :module header argument and related functions. ;;; Code: (require 'ert) (require 'ob-elixir) (require 'org) (require 'org-element) ;;; Module Block Detection Tests (ert-deftest ob-elixir-test-module-block-detection () "Test that :module header argument is detected in params." (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir :module MyModule\ndef foo, do: :bar\n#+END_SRC\n") (goto-char (point-min)) (search-forward "#+BEGIN_SRC") (let* ((info (org-babel-get-src-block-info)) (params (nth 2 info)) (module-name (cdr (assq :module params)))) (should module-name) (should (string= module-name "MyModule"))))) (ert-deftest ob-elixir-test-module-block-no-execute () "Test that blocks with :module don't execute Elixir code." (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir :module TestMod\ndef foo, do: raise \"should not run\"\n#+END_SRC\n") (goto-char (point-min)) (search-forward "#+BEGIN_SRC") (let ((result (org-babel-execute-src-block))) ;; Should return a message, not execute the code (should (stringp result)) (should (string-match-p "Module.*TestMod.*defined" result))))) ;;; Module Block Gathering Tests (ert-deftest ob-elixir-test-find-module-blocks-single () "Test finding a single module block." (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir :module Helpers\ndef greet(name), do: name\n#+END_SRC\n") (insert "#+BEGIN_SRC elixir\n:ok\n#+END_SRC\n") (goto-char (point-max)) (let ((modules (ob-elixir--find-all-module-blocks (point)))) (should modules) (should (= 1 (length modules))) (should (string= "Helpers" (caar modules))) (should (string-match-p "def greet" (cdar modules)))))) (ert-deftest ob-elixir-test-find-module-blocks-multiple-same-name () "Test that multiple blocks with same module name are merged." (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir :module Helpers\ndef foo, do: 1\n#+END_SRC\n") (insert "#+BEGIN_SRC elixir :module Helpers\ndef bar, do: 2\n#+END_SRC\n") (insert "#+BEGIN_SRC elixir\n:ok\n#+END_SRC\n") (goto-char (point-max)) (let ((modules (ob-elixir--find-all-module-blocks (point)))) (should modules) (should (= 1 (length modules))) (should (string= "Helpers" (caar modules))) (let ((body (cdar modules))) (should (string-match-p "def foo" body)) (should (string-match-p "def bar" body)))))) (ert-deftest ob-elixir-test-find-module-blocks-different-names () "Test finding multiple modules with different names." (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir :module ModA\ndef a, do: 1\n#+END_SRC\n") (insert "#+BEGIN_SRC elixir :module ModB\ndef b, do: 2\n#+END_SRC\n") (insert "#+BEGIN_SRC elixir\n:ok\n#+END_SRC\n") (goto-char (point-max)) (let ((modules (ob-elixir--find-all-module-blocks (point)))) (should modules) (should (= 2 (length modules))) (should (assoc "ModA" modules)) (should (assoc "ModB" modules))))) (ert-deftest ob-elixir-test-find-module-blocks-position-scoped () "Test that only blocks before current position are found." (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir :module Before\ndef before, do: 1\n#+END_SRC\n") (let ((middle-pos (point))) (insert "#+BEGIN_SRC elixir :module After\ndef after, do: 2\n#+END_SRC\n") (let ((modules (ob-elixir--find-all-module-blocks middle-pos))) (should modules) (should (= 1 (length modules))) (should (assoc "Before" modules)) (should-not (assoc "After" modules)))))) (ert-deftest ob-elixir-test-find-module-blocks-no-modules () "Test that nil/empty is returned when no module blocks exist." (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir\n1 + 1\n#+END_SRC\n") (goto-char (point-max)) (let ((modules (ob-elixir--find-all-module-blocks (point)))) (should (null modules))))) ;;; Module Definition Generation Tests (ert-deftest ob-elixir-test-generate-module-definitions-single () "Test generating a single module definition." (let* ((modules '(("MyMod" . "def foo, do: :bar"))) (result (ob-elixir--generate-module-definitions modules))) (should result) (should (string-match-p "defmodule MyMod do" result)) (should (string-match-p "def foo, do: :bar" result)) (should (string-match-p "end" result)))) (ert-deftest ob-elixir-test-generate-module-definitions-multiple () "Test generating multiple module definitions." (let* ((modules '(("ModA" . "def a, do: 1") ("ModB" . "def b, do: 2"))) (result (ob-elixir--generate-module-definitions modules))) (should result) (should (string-match-p "defmodule ModA do" result)) (should (string-match-p "defmodule ModB do" result)))) (ert-deftest ob-elixir-test-generate-module-definitions-empty () "Test that nil is returned for empty modules list." (should (null (ob-elixir--generate-module-definitions nil))) (should (null (ob-elixir--generate-module-definitions '())))) ;;; Integration Tests (ert-deftest ob-elixir-test-module-integration-basic () "Test full integration: define module, import, call function." (skip-unless (executable-find ob-elixir-command)) (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir :module Helpers\n") (insert "def double(x), do: x * 2\n") (insert "#+END_SRC\n\n") (insert "#+BEGIN_IMPORTS elixir\n") (insert "import Helpers\n") (insert "#+END_IMPORTS\n\n") (insert "#+BEGIN_SRC elixir :results value\n") (insert "double(21)\n") (insert "#+END_SRC\n") (goto-char (point-min)) (search-forward "double(21)") (beginning-of-line) (search-backward "#+BEGIN_SRC") (let ((result (org-babel-execute-src-block))) (should result) ;; Scalar numbers come back as strings (should (equal result "42"))))) (ert-deftest ob-elixir-test-module-integration-merged () "Test that merged module functions are all available." (skip-unless (executable-find ob-elixir-command)) (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir :module Math\n") (insert "def double(x), do: x * 2\n") (insert "#+END_SRC\n\n") (insert "#+BEGIN_SRC elixir :module Math\n") (insert "def triple(x), do: x * 3\n") (insert "#+END_SRC\n\n") (insert "#+BEGIN_IMPORTS elixir\n") (insert "import Math\n") (insert "#+END_IMPORTS\n\n") (insert "#+BEGIN_SRC elixir :results value\n") (insert "double(10) + triple(10)\n") (insert "#+END_SRC\n") (goto-char (point-min)) (search-forward "double(10)") (beginning-of-line) (search-backward "#+BEGIN_SRC") (let ((result (org-babel-execute-src-block))) (should result) ;; Scalar numbers come back as strings (should (equal result "50"))))) (ert-deftest ob-elixir-test-module-integration-multiple-modules () "Test multiple different modules." (skip-unless (executable-find ob-elixir-command)) (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir :module ModA\n") (insert "def value, do: 10\n") (insert "#+END_SRC\n\n") (insert "#+BEGIN_SRC elixir :module ModB\n") (insert "def value, do: 20\n") (insert "#+END_SRC\n\n") (insert "#+BEGIN_IMPORTS elixir\n") (insert "alias ModA\nalias ModB\n") (insert "#+END_IMPORTS\n\n") (insert "#+BEGIN_SRC elixir :results value\n") (insert "ModA.value() + ModB.value()\n") (insert "#+END_SRC\n") (goto-char (point-min)) (search-forward "ModA.value()") (beginning-of-line) (search-backward "#+BEGIN_SRC") (let ((result (org-babel-execute-src-block))) (should result) ;; Scalar numbers come back as strings (should (equal result "30"))))) (ert-deftest ob-elixir-test-module-with-private-functions () "Test that defp (private functions) work in modules." (skip-unless (executable-find ob-elixir-command)) (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir :module Helpers\n") (insert "def public(x), do: private_helper(x)\n") (insert "defp private_helper(x), do: x * 2\n") (insert "#+END_SRC\n\n") (insert "#+BEGIN_IMPORTS elixir\n") (insert "import Helpers\n") (insert "#+END_IMPORTS\n\n") (insert "#+BEGIN_SRC elixir :results value\n") (insert "public(21)\n") (insert "#+END_SRC\n") (goto-char (point-min)) (search-forward "public(21)") (beginning-of-line) (search-backward "#+BEGIN_SRC") (let ((result (org-babel-execute-src-block))) (should result) ;; Scalar numbers come back as strings (should (equal result "42"))))) (ert-deftest ob-elixir-test-module-with-module-attributes () "Test that module attributes work in modules." (skip-unless (executable-find ob-elixir-command)) (with-temp-buffer (org-mode) ;; Use MyConfig instead of Config to avoid conflict with Elixir's built-in Config module (insert "#+BEGIN_SRC elixir :module MyConfig\n") (insert "@default_value 42\n") (insert "def get_default, do: @default_value\n") (insert "#+END_SRC\n\n") (insert "#+BEGIN_IMPORTS elixir\n") (insert "import MyConfig\n") (insert "#+END_IMPORTS\n\n") (insert "#+BEGIN_SRC elixir :results value\n") (insert "get_default()\n") (insert "#+END_SRC\n") (goto-char (point-min)) (search-forward "get_default()") (beginning-of-line) (search-backward "#+BEGIN_SRC") (let ((result (org-babel-execute-src-block))) (should result) ;; Scalar numbers come back as strings (should (equal result "42"))))) (ert-deftest ob-elixir-test-module-without-import () "Test that modules are defined but require import to use directly." (skip-unless (executable-find ob-elixir-command)) (with-temp-buffer (org-mode) (insert "#+BEGIN_SRC elixir :module Helpers\n") (insert "def greet, do: \"hello\"\n") (insert "#+END_SRC\n\n") ;; No imports block - must use full module name (insert "#+BEGIN_SRC elixir :results value\n") (insert "Helpers.greet()\n") (insert "#+END_SRC\n") (goto-char (point-min)) (search-forward "Helpers.greet()") (beginning-of-line) (search-backward "#+BEGIN_SRC") (let ((result (org-babel-execute-src-block))) (should result) ;; String values come back with quotes (like other ob-elixir tests) (should (equal result "\"hello\""))))) (provide 'test-ob-elixir-modules) ;;; test-ob-elixir-modules.el ends here