function definitions outside modules

This commit is contained in:
2026-01-25 09:49:44 +01:00
parent 4e07ffa70c
commit 6ad1c86b95
7 changed files with 1576 additions and 63 deletions

View File

@@ -0,0 +1,281 @@
;;; 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

View File

@@ -26,6 +26,7 @@
(require 'test-ob-elixir-org)
(require 'test-ob-elixir-deps)
(require 'test-ob-elixir-imports)
(require 'test-ob-elixir-modules)
;; (require 'test-ob-elixir-sessions)
;;; Smoke Test