From 03626ed5fd15ad00f1cedd6a0599195f24051139 Mon Sep 17 00:00:00 2001 From: Denis Smetannikov Date: Mon, 12 Feb 2024 01:52:00 +0400 Subject: [PATCH] Enhance test coverage (#164) * Enhance test coverage * Remove splint from lint sequence in bb.edn The changes of this commit are made to the lint sequence inside bb.edn file. The 'splint' style check was removed from the sequencing. Now, the lint sequence now includes only 'cljfmt', 'cljstyle', 'eastwood', and 'kondo'. This simplifies the sequence and prioritizes the rest of the style checks. * Refactor complex number functionality and add tests The code was restructured to reorder, rename, and modify complex number functions in Clojure for two models ("Ben's way" and "Alyssa's way"). Float typecasting was added to some functions to ensure accurate calculations. Corresponding tests were also implemented in a new test file to validate and ensure the correctness of these revised functions. These changes enhance code clarity and testing comprehensiveness in handling complex numbers. * Reformat imports in book_2_4_test.clj The :require block in the testing file book_2_4_test.clj has been reformatted to improve readability. No functionality was changed in this commit, just the way the code is organized for aesthetically pleasing and more manageable structure. * Refactor exception handling across multiple test files Refactored exception handling in tests across multiple modules, replacing previous implementations with the centralized and enhanced `is-exception?` macro. This macro captures the exception type and message and eliminates repeated code, enhancing code cleanliness and maintainability. * Modify exception checking in tests Refactored the way exceptions are checked in tests across various modules. This was done by changing from direct exception checks to using the `is-exception?` macro. This improves code readability and makes the test scripts more maintainable. * Correct naming for test coverage workflow Fixed a typo and improved the naming pattern for the "test coverage" workflow in the main GitHub actions YAML file. This change contributes to better workflow organization and execution clarity. * Add test files for ex-2-73 and ex-2-75 and improve derivation functions Created new test files for exercises 2-73 and 2-75. The test cases for these exercises are now fully covered. Also, made some improvements in the derivation functions in exercise 2-73 by replacing `put` with `put-op` and `get` with `get-op` methods to manage operations in a more optimized way. * Update clj-kondo configuration and clojure.test import Updated the clj-kondo command in the lint task to run in parallel, improving performance. Also simplified the clojure.test import statement in the ex_2_75_test file to only include 'deftest' and 'is', making the dependencies clearer and more specific. * Update clj-kondo settings and refactor test file imports The clj-kondo command in the lint task has been updated to run in parallel, setting the fail level as a warning. This amendment should improve performance by running in a non-blocking mode. The clojure.test import usage in the book_2_ * Refactor exception handling and update test cases Simplified exception handling by removing explicit checks for exception types, now only checks for expected messages. Updated multiple test cases correspondingly. Also made minor alterations to error messages for better clarity. * Refactor error message formatting in misc.clj The error message formatting has been adjusted for clarity in the misc.clj file. An extraneous check in the 'apply-generic-test' in the book_2_5_test.clj file has also been removed for improved simplicity. --- .github/workflows/main.yml | 2 +- bb.edn | 5 +- src/sicp/chapter_2/part_1/ex_2_10.clj | 2 +- src/sicp/chapter_2/part_2/book_2_2.clj | 5 +- src/sicp/chapter_2/part_4/book_2_4.clj | 82 +++++------ src/sicp/chapter_2/part_4/ex_2_73.clj | 23 +-- src/sicp/chapter_2/part_5/book_2_5.clj | 2 +- src/sicp/misc.clj | 17 ++- .../{ex_1_3_test.clj => ex_1_03_test.clj} | 2 +- .../{ex_1_4_test.clj => ex_1_04_test.clj} | 2 +- .../{ex_1_5_test.clj => ex_1_05_test.clj} | 5 +- .../{ex_1_6_test.clj => ex_1_06_test.clj} | 2 +- .../{ex_1_7_test.clj => ex_1_07_test.clj} | 2 +- .../{ex_1_8_test.clj => ex_1_08_test.clj} | 2 +- .../{ex_1_9_test.clj => ex_1_09_test.clj} | 8 +- test/sicp/chapter_1/part_2/ex_1_25_test.clj | 7 +- test/sicp/chapter_1/part_2/ex_1_26_test.clj | 5 +- test/sicp/chapter_1/part_3/book_1_3_test.clj | 13 +- test/sicp/chapter_2/part_1/book_2_1_test.clj | 6 +- test/sicp/chapter_2/part_1/ex_2_10_test.clj | 11 +- test/sicp/chapter_2/part_1/ex_2_11_test.clj | 17 ++- test/sicp/chapter_2/part_2/book_2_2_test.clj | 15 +- test/sicp/chapter_2/part_3/ex_2_68_test.clj | 19 +-- test/sicp/chapter_2/part_4/book_2_4_test.clj | 132 ++++++++++++++++++ test/sicp/chapter_2/part_4/ex_2_73_test.clj | 24 ++++ test/sicp/chapter_2/part_4/ex_2_75_test.clj | 18 +++ test/sicp/chapter_2/part_5/book_2_5_test.clj | 55 ++++---- test/sicp/misc_test.clj | 7 +- 28 files changed, 359 insertions(+), 131 deletions(-) rename test/sicp/chapter_1/part_1/{ex_1_3_test.clj => ex_1_03_test.clj} (90%) rename test/sicp/chapter_1/part_1/{ex_1_4_test.clj => ex_1_04_test.clj} (87%) rename test/sicp/chapter_1/part_1/{ex_1_5_test.clj => ex_1_05_test.clj} (79%) rename test/sicp/chapter_1/part_1/{ex_1_6_test.clj => ex_1_06_test.clj} (93%) rename test/sicp/chapter_1/part_1/{ex_1_7_test.clj => ex_1_07_test.clj} (98%) rename test/sicp/chapter_1/part_1/{ex_1_8_test.clj => ex_1_08_test.clj} (91%) rename test/sicp/chapter_1/part_2/{ex_1_9_test.clj => ex_1_09_test.clj} (51%) create mode 100644 test/sicp/chapter_2/part_4/book_2_4_test.clj create mode 100644 test/sicp/chapter_2/part_4/ex_2_73_test.clj create mode 100644 test/sicp/chapter_2/part_4/ex_2_75_test.clj diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7613baa..525bce2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,7 +30,7 @@ jobs: run: lein test tests-coverage: - name: Test Coverge + name: Tests - Coverge runs-on: ubuntu-latest steps: - name: Checkout diff --git a/bb.edn b/bb.edn index 9bde4cd..37a12c7 100644 --- a/bb.edn +++ b/bb.edn @@ -3,8 +3,7 @@ style:cljfmt (shell "cljfmt check") style:cljstyle (shell "cljstyle check") style:splint (shell "lein splint ./src ./test") - lint (do (run 'style:splint) - (run 'style:cljfmt) + lint (do (run 'style:cljfmt) (run 'style:cljstyle) (run 'lint:eastwood) (run 'lint:kondo)) @@ -15,7 +14,7 @@ (run 'fix:cljstyle)) ; Linters lint:eastwood (shell "clojure -M:test:eastwood") - lint:kondo (shell "clj-kondo --lint test src") + lint:kondo (shell "clj-kondo --parallel --fail-level warning --lint test src") ; Local development pre-push (do (run 'fix) (run 'lint) diff --git a/src/sicp/chapter_2/part_1/ex_2_10.clj b/src/sicp/chapter_2/part_1/ex_2_10.clj index c36637c..8cb4ab1 100644 --- a/src/sicp/chapter_2/part_1/ex_2_10.clj +++ b/src/sicp/chapter_2/part_1/ex_2_10.clj @@ -12,7 +12,7 @@ (if (< (* (m/lower-bound interval-2) (m/upper-bound interval-2)) 0) - (m/error "interval-2 is spanning zero") + (m/error "Interval-2 is spanning zero") (m/mul-interval interval-1 (m/make-interval (/ 1.0 (m/lower-bound interval-2)) diff --git a/src/sicp/chapter_2/part_2/book_2_2.clj b/src/sicp/chapter_2/part_2/book_2_2.clj index 86c9ffc..e27a0d9 100644 --- a/src/sicp/chapter_2/part_2/book_2_2.clj +++ b/src/sicp/chapter_2/part_2/book_2_2.clj @@ -175,9 +175,8 @@ (defn my-filter [predicate sequence] (cond (m/list-empty? sequence) nil - (predicate (m/car sequence)) - (cons (m/car sequence) - (my-filter predicate (m/cdr sequence))) + (predicate (m/car sequence)) (cons (m/car sequence) + (my-filter predicate (m/cdr sequence))) :else (my-filter predicate (m/cdr sequence)))) (defn accumulate diff --git a/src/sicp/chapter_2/part_4/book_2_4.clj b/src/sicp/chapter_2/part_4/book_2_4.clj index 19ab9b6..d0cece0 100644 --- a/src/sicp/chapter_2/part_4/book_2_4.clj +++ b/src/sicp/chapter_2/part_4/book_2_4.clj @@ -4,81 +4,81 @@ (comment "2.4.1 Representations for Complex Numbers ----------------------------------------------") -; Ben's way -(defn real-part-Ben +; Ben's way ---------------------------------------------------------------------------------------- +(defn Ben-real-part [z] - (first z)) + (float (first z))) -(defn imag-part-Ben +(defn Ben-imag-part [z] - (second z)) + (float (second z))) -(defn magnitude-Ben +(defn Ben-magnitude [z] - (Math/sqrt (+ (Math/pow (real-part-Ben z) 2) - (Math/pow (imag-part-Ben z) 2)))) + (Math/sqrt (+ (Math/pow (Ben-real-part z) 2) + (Math/pow (Ben-imag-part z) 2)))) -(defn angle-v1 +(defn Ben-angle [z] - (Math/atan2 (imag-part-Ben z) (real-part-Ben z))) + (Math/atan2 (Ben-imag-part z) (Ben-real-part z))) -(defn make-from-real-imag-Ben - ([x y] [x y]) - ([z] [(real-part-Ben z) (imag-part-Ben z)])) +(defn Ben-make-from-real-imag + ([x y] [(float x) (float y)]) + ([z] [(Ben-real-part z) (Ben-imag-part z)])) -(defn make-from-mag-ang-Ben +(defn Ben-make-from-mag-ang ([r a] [(* r (Math/cos a)) (* r (Math/sin a))]) - ([z] [(magnitude-Ben z) (angle-v1 z)])) + ([z] [(Ben-magnitude z) (Ben-angle z)])) -(defn add-complex-Ben +(defn Ben-add-complex [z1 z2] - (make-from-real-imag-Ben - (+ (real-part-Ben z1) (real-part-Ben z2)) - (+ (imag-part-Ben z1) (imag-part-Ben z2)))) + (Ben-make-from-real-imag + (+ (Ben-real-part z1) (Ben-real-part z2)) + (+ (Ben-imag-part z1) (Ben-imag-part z2)))) -(defn sub-complex-Ben +(defn Ben-sub-complex [z1 z2] - (make-from-real-imag-Ben - (- (real-part-Ben z1) (real-part-Ben z2)) - (- (imag-part-Ben z1) (imag-part-Ben z2)))) + (Ben-make-from-real-imag + (- (Ben-real-part z1) (Ben-real-part z2)) + (- (Ben-imag-part z1) (Ben-imag-part z2)))) -(defn mul-complex-Ben +(defn Ben-mul-complex [z1 z2] - (make-from-mag-ang-Ben - (* (magnitude-Ben z1) (magnitude-Ben z2)) - (+ (angle-v1 z1) (angle-v1 z2)))) + (Ben-make-from-mag-ang + (* (Ben-magnitude z1) (Ben-magnitude z2)) + (+ (Ben-angle z1) (Ben-angle z2)))) -(defn div-complex-Ben +(defn Ben-div-complex [z1 z2] - (make-from-mag-ang-Ben - (/ (magnitude-Ben z1) (magnitude-Ben z2)) - (- (angle-v1 z1) (angle-v1 z2)))) + (Ben-make-from-mag-ang + (/ (Ben-magnitude z1) (Ben-magnitude z2)) + (- (Ben-angle z1) (Ben-angle z2)))) -; Alyssa's way -(defn magnitude-Alyssa +; Alyssa's way ------------------------------------------------------------------------------------- +(defn Alyssa-magnitude [z] (first z)) -(defn angle-Alyssa +(defn Alyssa-angle [z] (second z)) -(defn real-part-Alyssa +(defn Alyssa-real-part [z] - (* (magnitude-Alyssa z) (Math/cos (angle-Alyssa z)))) + (* (Alyssa-magnitude z) (Math/cos (Alyssa-angle z)))) -(defn imag-part-Alyssa +(defn Alyssa-imag-part [z] - (* (magnitude-Alyssa z) (Math/sin (angle-Alyssa z)))) + (* (Alyssa-magnitude z) (Math/sin (Alyssa-angle z)))) -(defn make-from-real-imag-Alyssa +(defn Alyssa-make-from-real-imag [x y] [(Math/sqrt (+ (Math/pow x 2) (Math/pow y 2))) (Math/atan2 y x)]) -(defn make-from-mag-ang-Alyssa +(defn Alyssa-make-from-mag-ang [r a] - [r a]) + [(float r) (float a)]) (comment "2.4.2") diff --git a/src/sicp/chapter_2/part_4/ex_2_73.clj b/src/sicp/chapter_2/part_4/ex_2_73.clj index ded4a07..4fb31c9 100644 --- a/src/sicp/chapter_2/part_4/ex_2_73.clj +++ b/src/sicp/chapter_2/part_4/ex_2_73.clj @@ -59,6 +59,16 @@ ; ((get (operator exp) 'deriv) ; (operands exp) var) +(def derivations (atom {})) + +(defn put-op + [op method deriv-fn] + (swap! derivations assoc-in [op method] deriv-fn)) + +(defn get-op + [op method] + (get-in @derivations [op method])) + (defn deriv [exp var] (cond @@ -87,7 +97,7 @@ (cond (number? exp) 0 (b23/variable? exp) (if (b23/same-variable? exp var) 1 0) - :else ((get :deriv (operator exp)) + :else ((get-op :deriv (operator exp)) (operands exp) var))) @@ -96,11 +106,6 @@ ; Sorry, I'm lazy and took examples of code here and rewrite it to Clojure ; https://github.com/ivanjovanovic/sicp/blob/master/2.4/e-2.73.scm -(defn put - [param1 param2 deriver] - ; Just for linter - (println param1 param2 deriver)) - (defn make-sum ([a b] (list '+ a b)) ([a b c] (list '+ a b c))) @@ -118,7 +123,7 @@ (make-sum (deriv (addend operands) var) (deriv (augend operands) var)))] ; and methods for putting the thing in the table - (put '+ 'deriv derive-sum))) + (put-op '+ :deriv derive-sum))) (defn install-product-derivation [] @@ -133,7 +138,7 @@ (multiplicand operands)) var))] ; put that into table - (put '* 'deriv derive-product))) + (put-op '* :deriv derive-product))) (defn install-exponent-derivation [] @@ -146,4 +151,4 @@ (make-product (power operands) (make-exponent (base operands) (dec (power operands)))) (deriv (base operands) var)))] - (put '** 'deriv derive-exponent))) + (put-op '** :deriv derive-exponent))) diff --git a/src/sicp/chapter_2/part_5/book_2_5.clj b/src/sicp/chapter_2/part_5/book_2_5.clj index 4dfbcd5..5b9f79a 100644 --- a/src/sicp/chapter_2/part_5/book_2_5.clj +++ b/src/sicp/chapter_2/part_5/book_2_5.clj @@ -29,7 +29,7 @@ operation (get-op op type-tags)] (if operation (apply operation (map #(:contents %) args)) - (throw (IllegalArgumentException. (str "No method for: " op " " type-tags)))))) + (throw (IllegalArgumentException. (str "No method for: " op)))))) ; -------------------------------------------------------------------------------------------------- diff --git a/src/sicp/misc.clj b/src/sicp/misc.clj index 7d7ff18..7fb05c9 100644 --- a/src/sicp/misc.clj +++ b/src/sicp/misc.clj @@ -1,4 +1,6 @@ -(ns sicp.misc) +(ns sicp.misc + (:require + [clojure.test :refer [is]])) (comment "Chapter #1 The Elements of Programming -------------------------------------------------") @@ -191,3 +193,16 @@ (if (empty? list1) (if (empty? list2) '() list2) (cons (first list1) (append (rest list1) list2)))) + +(defmacro is-exception? + [test-code & [expected-message]] + `(try + (do + ~test-code + (is false "Execution of the code expects any type of exception to be thrown")) + (catch Exception exception# + (cond + (not (nil? ~expected-message)) (is (= (.getMessage exception#) ~expected-message) + (str "Expected message: " ~expected-message ", but got: " (.getMessage exception#))) + ; For valid test cases, the expected exception type and message should be nil + :else true)))) diff --git a/test/sicp/chapter_1/part_1/ex_1_3_test.clj b/test/sicp/chapter_1/part_1/ex_1_03_test.clj similarity index 90% rename from test/sicp/chapter_1/part_1/ex_1_3_test.clj rename to test/sicp/chapter_1/part_1/ex_1_03_test.clj index 9682fd5..9a9ca1e 100644 --- a/test/sicp/chapter_1/part_1/ex_1_3_test.clj +++ b/test/sicp/chapter_1/part_1/ex_1_03_test.clj @@ -1,4 +1,4 @@ -(ns sicp.chapter-1.part-1.ex-1-3-test +(ns sicp.chapter-1.part-1.ex-1-03-test (:require [clojure.test :refer [deftest is]] [sicp.chapter-1.part-1.ex-1-03 :refer [sum-larger-numbers-square]])) diff --git a/test/sicp/chapter_1/part_1/ex_1_4_test.clj b/test/sicp/chapter_1/part_1/ex_1_04_test.clj similarity index 87% rename from test/sicp/chapter_1/part_1/ex_1_4_test.clj rename to test/sicp/chapter_1/part_1/ex_1_04_test.clj index 5689278..206c256 100644 --- a/test/sicp/chapter_1/part_1/ex_1_4_test.clj +++ b/test/sicp/chapter_1/part_1/ex_1_04_test.clj @@ -1,4 +1,4 @@ -(ns sicp.chapter-1.part-1.ex-1-4-test +(ns sicp.chapter-1.part-1.ex-1-04-test (:require [clojure.test :refer [deftest is]] [sicp.chapter-1.part-1.ex-1-04 :refer [a-plus-abs-b]])) diff --git a/test/sicp/chapter_1/part_1/ex_1_5_test.clj b/test/sicp/chapter_1/part_1/ex_1_05_test.clj similarity index 79% rename from test/sicp/chapter_1/part_1/ex_1_5_test.clj rename to test/sicp/chapter_1/part_1/ex_1_05_test.clj index 6d3302a..f278b55 100644 --- a/test/sicp/chapter_1/part_1/ex_1_5_test.clj +++ b/test/sicp/chapter_1/part_1/ex_1_05_test.clj @@ -1,4 +1,4 @@ -(ns sicp.chapter-1.part-1.ex-1-5-test +(ns sicp.chapter-1.part-1.ex-1-05-test (:require [clojure.test :refer [deftest is]] [sicp.chapter-1.part-1.ex-1-05 :refer [p test_1_5]])) @@ -7,4 +7,5 @@ ; Normal: Operand "p" will not be evaluated until it's needed by some primitive operation. So result is 0. (is (= 0 (test_1_5 0 p))) ; Applicative: Operand "y" will be by default evaluated. Then it will end up in recursion since (p) points to itself. - (is (= p (test_1_5 1 p)))) + (is (= p (test_1_5 1 p))) + (is (= p (test_1_5 1 (p))))) diff --git a/test/sicp/chapter_1/part_1/ex_1_6_test.clj b/test/sicp/chapter_1/part_1/ex_1_06_test.clj similarity index 93% rename from test/sicp/chapter_1/part_1/ex_1_6_test.clj rename to test/sicp/chapter_1/part_1/ex_1_06_test.clj index 3c2e7ac..1b36012 100644 --- a/test/sicp/chapter_1/part_1/ex_1_6_test.clj +++ b/test/sicp/chapter_1/part_1/ex_1_06_test.clj @@ -1,4 +1,4 @@ -(ns sicp.chapter-1.part-1.ex-1-6-test +(ns sicp.chapter-1.part-1.ex-1-06-test (:require [clojure.test :refer [deftest is]] [sicp.chapter-1.part-1.book-1-1 :as b11] diff --git a/test/sicp/chapter_1/part_1/ex_1_7_test.clj b/test/sicp/chapter_1/part_1/ex_1_07_test.clj similarity index 98% rename from test/sicp/chapter_1/part_1/ex_1_7_test.clj rename to test/sicp/chapter_1/part_1/ex_1_07_test.clj index 3067dad..ae3f2b3 100644 --- a/test/sicp/chapter_1/part_1/ex_1_7_test.clj +++ b/test/sicp/chapter_1/part_1/ex_1_07_test.clj @@ -1,4 +1,4 @@ -(ns sicp.chapter-1.part-1.ex-1-7-test +(ns sicp.chapter-1.part-1.ex-1-07-test (:require [clojure.test :refer [deftest is]] [sicp.chapter-1.part-1.book-1-1 :as b11] diff --git a/test/sicp/chapter_1/part_1/ex_1_8_test.clj b/test/sicp/chapter_1/part_1/ex_1_08_test.clj similarity index 91% rename from test/sicp/chapter_1/part_1/ex_1_8_test.clj rename to test/sicp/chapter_1/part_1/ex_1_08_test.clj index 40aa998..d1d2dc9 100644 --- a/test/sicp/chapter_1/part_1/ex_1_8_test.clj +++ b/test/sicp/chapter_1/part_1/ex_1_08_test.clj @@ -1,4 +1,4 @@ -(ns sicp.chapter-1.part-1.ex-1-8-test +(ns sicp.chapter-1.part-1.ex-1-08-test (:require [clojure.test :refer [deftest is]] [sicp.chapter-1.part-1.ex-1-08 :refer [cube-root-iter]])) diff --git a/test/sicp/chapter_1/part_2/ex_1_9_test.clj b/test/sicp/chapter_1/part_2/ex_1_09_test.clj similarity index 51% rename from test/sicp/chapter_1/part_2/ex_1_9_test.clj rename to test/sicp/chapter_1/part_2/ex_1_09_test.clj index 507e3e7..98168b6 100644 --- a/test/sicp/chapter_1/part_2/ex_1_9_test.clj +++ b/test/sicp/chapter_1/part_2/ex_1_09_test.clj @@ -1,10 +1,12 @@ -(ns sicp.chapter-1.part-2.ex-1-9-test +(ns sicp.chapter-1.part-2.ex-1-09-test (:require [clojure.test :refer [deftest is]] [sicp.chapter-1.part-2.ex-1-09 :refer [plus plus-v2]])) (deftest plus-test - (is (= 3 (plus 1 2)))) + (is (= 3 (plus 1 2))) + (is (= 2 (plus 0 2)))) (deftest plus-v2-test - (is (= 3 (plus-v2 1 2)))) + (is (= 3 (plus-v2 1 2))) + (is (= 2 (plus-v2 0 2)))) diff --git a/test/sicp/chapter_1/part_2/ex_1_25_test.clj b/test/sicp/chapter_1/part_2/ex_1_25_test.clj index ea015dc..ad7c4de 100644 --- a/test/sicp/chapter_1/part_2/ex_1_25_test.clj +++ b/test/sicp/chapter_1/part_2/ex_1_25_test.clj @@ -1,7 +1,12 @@ (ns sicp.chapter-1.part-2.ex-1-25-test (:require [clojure.test :refer [deftest is]] - [sicp.chapter-1.part-2.ex-1-25 :refer [expmod expmod-alyssa]])) + [sicp.chapter-1.part-2.ex-1-25 :refer [expmod expmod-alyssa fast-expt]])) + +(deftest fast-expt-test + (is (= 1 (fast-expt 2 0))) + (is (= 16 (fast-expt 2 4))) + (is (= 3125 (fast-expt 5 5)))) (deftest expmod-test (is (= 1 (expmod 2 0 3))) diff --git a/test/sicp/chapter_1/part_2/ex_1_26_test.clj b/test/sicp/chapter_1/part_2/ex_1_26_test.clj index 9fdfdde..f1b466c 100644 --- a/test/sicp/chapter_1/part_2/ex_1_26_test.clj +++ b/test/sicp/chapter_1/part_2/ex_1_26_test.clj @@ -4,4 +4,7 @@ [sicp.chapter-1.part-2.ex-1-26 :refer [expmod]])) (deftest expmod-test - (is (= 1 (expmod 2 0 3)))) + (is (= 1 (expmod 2 0 3))) + (is (= 1 (expmod 2 4 3))) + (is (= 25 (expmod 5 10 40))) + (is (= 0 (expmod 10 5 40)))) diff --git a/test/sicp/chapter_1/part_3/book_1_3_test.clj b/test/sicp/chapter_1/part_3/book_1_3_test.clj index d28543d..a72320a 100644 --- a/test/sicp/chapter_1/part_3/book_1_3_test.clj +++ b/test/sicp/chapter_1/part_3/book_1_3_test.clj @@ -54,6 +54,16 @@ (is (= 0.24998750000000042 (b13/integral m/cube 0 1 0.01))) (is (= 0.249999875000001 (b13/integral m/cube 0 1 0.001)))) +(deftest f-1-test + (is (= 4 (b13/f-1 1 2))) + (is (= 603 (b13/f-1 2 10))) + (is (= 178 (b13/f-1 2 5)))) + +(deftest f-2-test + (is (= 4 (b13/f-2 1 2))) + (is (= 603 (b13/f-1 2 10))) + (is (= 178 (b13/f-2 2 5)))) + (comment "1.3.2 Constructing Procedures Using Lambda ---------------------------------------------") (deftest pi-sum-lamda-test @@ -76,7 +86,8 @@ (deftest half-interval-method-test (is (= 6.103515625E-5 (b13/half-interval-method m/cube -1.0 9.0))) (is (= 3.14111328125 (b13/half-interval-method #(Math/sin %) 2.0 4.0))) - (is (= 1.89306640625 (b13/half-interval-method #(- (m/cube %) (* 2 %) 3) 1.0 2.0)))) + (is (= 1.89306640625 (b13/half-interval-method #(- (m/cube %) (* 2 %) 3) 1.0 2.0))) + (is (= true (m/is-exception? (b13/half-interval-method m/cube 1 1) "Values are not of opposite sign 1 1")))) (deftest fixed-point-test (is (= 0.7390822985224024 (b13/fixed-point #(Math/cos %) -1.0))) diff --git a/test/sicp/chapter_2/part_1/book_2_1_test.clj b/test/sicp/chapter_2/part_1/book_2_1_test.clj index 192d135..c4822d9 100644 --- a/test/sicp/chapter_2/part_1/book_2_1_test.clj +++ b/test/sicp/chapter_2/part_1/book_2_1_test.clj @@ -1,7 +1,8 @@ (ns sicp.chapter-2.part-1.book-2-1-test (:require [clojure.test :refer [deftest is]] - [sicp.chapter-2.part-1.book-2-1 :as b21])) + [sicp.chapter-2.part-1.book-2-1 :as b21] + [sicp.misc :as m])) (comment "2 Building Abstractions with Data ------------------------------------------------------") @@ -75,4 +76,5 @@ (deftest pair-alt-test (is (= 1 (b21/car-alt (b21/pair-alt 1 2)))) - (is (= 2 (b21/cdr-alt (b21/pair-alt 1 2))))) + (is (= 2 (b21/cdr-alt (b21/pair-alt 1 2)))) + (is (= true (m/is-exception? ((b21/pair-alt 1 2) 2) "Argument not 0 or 1: CONS")))) diff --git a/test/sicp/chapter_2/part_1/ex_2_10_test.clj b/test/sicp/chapter_2/part_1/ex_2_10_test.clj index b3bdf80..1f38c78 100644 --- a/test/sicp/chapter_2/part_1/ex_2_10_test.clj +++ b/test/sicp/chapter_2/part_1/ex_2_10_test.clj @@ -5,12 +5,5 @@ [sicp.misc :as m])) (deftest div-interval-test - (is (= [-1.5 -0.5] - (div-interval (m/make-interval 10 15) (m/make-interval -10 -20))))) - -(deftest exception-with-message-test - (try - (div-interval (m/make-interval 1 2) (m/make-interval -1 2)) - (is false "Exception not thrown") - (catch Exception e - (is (= (.getMessage e) "interval-2 is spanning zero"))))) + (is (= [-1.5 -0.5] (div-interval (m/make-interval 10 15) (m/make-interval -10 -20)))) + (is (= true (m/is-exception? (div-interval (m/make-interval 1 2) (m/make-interval -1 2)) "Interval-2 is spanning zero")))) diff --git a/test/sicp/chapter_2/part_1/ex_2_11_test.clj b/test/sicp/chapter_2/part_1/ex_2_11_test.clj index 4d0802d..c9367c9 100644 --- a/test/sicp/chapter_2/part_1/ex_2_11_test.clj +++ b/test/sicp/chapter_2/part_1/ex_2_11_test.clj @@ -31,7 +31,13 @@ (def i-+ (m/make-interval -1 1)) (def i-- (m/make-interval -1 -1)) +(def j++ (m/make-interval 2 2)) +(def j+- (m/make-interval 2 -2)) +(def j-+ (m/make-interval -2 2)) +(def j-- (m/make-interval -2 -2)) + (deftest mul-interval-test + ; i (is (= [1 1] (mul-interval i++ i++))) (is (= [1 -1] (mul-interval i++ i+-))) (is (= [-1 -1] (mul-interval i++ i--))) @@ -39,7 +45,16 @@ (is (= [1 1] (mul-interval i-- i--))) (is (= [-1 1] (mul-interval i-+ i-+))) (is (= [1 1] (mul-interval i+- i+-))) - (is (= [1 -1] (mul-interval i+- i-+)))) + (is (= [1 -1] (mul-interval i+- i-+))) + ; j + (is (= [4 4] (mul-interval j++ j++))) + (is (= [4 -4] (mul-interval j++ j+-))) + (is (= [-4 -4] (mul-interval j++ j--))) + (is (= [4 -4] (mul-interval j+- j--))) + (is (= [4 4] (mul-interval j-- j--))) + (is (= [-2 2] (mul-interval i-+ j-+))) + (is (= [4 4] (mul-interval j+- j+-))) + (is (= [4 -4] (mul-interval j+- j-+)))) (deftest mul-interval-old-test (is (= [1 1] (m/mul-interval i++ i++))) diff --git a/test/sicp/chapter_2/part_2/book_2_2_test.clj b/test/sicp/chapter_2/part_2/book_2_2_test.clj index 9c642dc..dad2267 100644 --- a/test/sicp/chapter_2/part_2/book_2_2_test.clj +++ b/test/sicp/chapter_2/part_2/book_2_2_test.clj @@ -20,6 +20,9 @@ prime-sum-pairs prime-sum? product-of-squares-of-odd-elements + scale-list + scale-list-2 + my-filter scale-tree scale-tree-v0 sum-odd-squares @@ -57,6 +60,14 @@ (is (= '(1 4 9 16 25) (append '(1 4 9 16 25) '()))) (is (= '(1 4 9 16 25 3 2 1) (append '(1 4 9 16 25) '(3 2 1))))) +(deftest scale-list-test + (is (= '(2 4 6 8 10) (scale-list '(1 2 3 4 5) 2))) + (is (= '(10 20 30 40 50) (scale-list '(1 2 3 4 5) 10)))) + +(deftest scale-list-2-test + (is (= '(2 4 6 8 10) (scale-list-2 '(1 2 3 4 5) 2))) + (is (= '(10 20 30 40 50) (scale-list-2 '(1 2 3 4 5) 10)))) + (deftest my-map-test ; Custom (is (= '(10 2.5 11.6 17) (my-map abs (list -10 2.5 -11.6 17)))) @@ -97,7 +108,9 @@ (is (= '(0 2 8 34) (even-fibs 10)))) (deftest my-filter-test - (is (= '(1 3 5) (filter odd? '(1 2 3 4 5))))) + (is (= '(1 3 5) (filter odd? '(1 2 3 4 5)))) + (is (= '(1 3 5) (my-filter odd? '(1 2 3 4 5)))) + (is (= '(2 4) (my-filter even? '(1 2 3 4 5))))) (deftest accumulate-test (is (= 15 (accumulate + 0 '(1 2 3 4 5)))) diff --git a/test/sicp/chapter_2/part_3/ex_2_68_test.clj b/test/sicp/chapter_2/part_3/ex_2_68_test.clj index d43c251..69776ad 100644 --- a/test/sicp/chapter_2/part_3/ex_2_68_test.clj +++ b/test/sicp/chapter_2/part_3/ex_2_68_test.clj @@ -2,26 +2,15 @@ (:require [clojure.test :refer [deftest is]] [sicp.chapter-2.part-3.book-2-3 :as b23] - [sicp.chapter-2.part-3.ex-2-68 :refer [encode encode-symbol]])) + [sicp.chapter-2.part-3.ex-2-68 :refer [encode encode-symbol]] + [sicp.misc :as m])) (deftest encode-symbol-test (is (= b23/huffman-A (encode-symbol :A b23/huffman-tree))) (is (= b23/huffman-B (encode-symbol :B b23/huffman-tree))) (is (= b23/huffman-C (encode-symbol :C b23/huffman-tree))) - (is (= b23/huffman-D (encode-symbol :D b23/huffman-tree)))) - -(deftest encode-symbol-exception-test - (is (thrown-with-msg? - Exception - #"Symbol not found in tree :Z" - (encode-symbol :Z b23/huffman-tree)))) - -(deftest encode-exception-test - (try - (encode-symbol :Z b23/huffman-tree) - (is false "Exception not thrown") - (catch Exception e - (is (= (.getMessage e) "Symbol not found in tree :Z"))))) + (is (= b23/huffman-D (encode-symbol :D b23/huffman-tree))) + (is (= true (m/is-exception? (encode-symbol :Z b23/huffman-tree) "Symbol not found in tree :Z")))) (deftest encode-test (is (= '(0 ; A diff --git a/test/sicp/chapter_2/part_4/book_2_4_test.clj b/test/sicp/chapter_2/part_4/book_2_4_test.clj new file mode 100644 index 0000000..edb86c7 --- /dev/null +++ b/test/sicp/chapter_2/part_4/book_2_4_test.clj @@ -0,0 +1,132 @@ +(ns sicp.chapter-2.part-4.book-2-4-test + (:require + [clojure.test :refer [deftest is]] + [sicp.chapter-2.part-4.book-2-4 :as b24] + [sicp.misc :as m])) + +(def angle-60 (/ Math/PI 3)) +(def radius 2.0) +(def x 1.0000000000000002) +(def y 1.7320508075688772) + +(comment "2.4 Multiple Representations for Abstract Data -----------------------------------------") + +(comment "2.4.1 Representations for Complex Numbers ----------------------------------------------") + +; Ben's way ---------------------------------------------------------------------------------------- +(deftest Ben-add-complex-test + (is (= (b24/Ben-make-from-real-imag 2.0 3.4641016) + (b24/Ben-add-complex (b24/Ben-make-from-real-imag x y) + (b24/Ben-make-from-real-imag x y)))) + (is (= '(12.0 20.0) (b24/Ben-add-complex '(10 0) '(2 20))))) + +(deftest Ben-sub-complex-test + (is (= '(0.0 0.0) (b24/Ben-sub-complex [x y] [x y]))) + (is (= [1.0 1.0] (b24/Ben-sub-complex '(2 3) '(1 2))))) + +(deftest Ben-mul-complex-test + (is (= '(-13.999999999999998 22.0) (b24/Ben-mul-complex '(2 4) '(3 5)))) + (is (= '(11.0 8.0) (b24/Ben-mul-complex '(2 1) '(6 1))))) + +(deftest Ben-div-complex-test + (is (= '(2.0 0.0) (b24/Ben-div-complex '(2 2) '(1 1)))) + (is (= '(0.7647058823529411 0.0588235294117646) (b24/Ben-div-complex '(2 4) '(3 5))))) + +; Alyssa's way ------------------------------------------------------------------------------------- + +(deftest Alyssa-make-from-real-imag-test + (is (= [radius angle-60] (b24/Alyssa-make-from-real-imag x y)))) + +(deftest Alyssa-make-from-mag-ang-test + (let [z (b24/Ben-make-from-real-imag x y) + bm (b24/Ben-real-part z) + ba (b24/Ben-imag-part z)] + (is (= [bm ba] (b24/Alyssa-make-from-mag-ang x y))))) + +(deftest Alyssa-real-part-test + (let [z (b24/Ben-make-from-real-imag '(1 0)) + br (b24/Ben-real-part z)] + (is (= br (b24/Alyssa-real-part '(1 0)))))) + +(deftest Alyssa-imag-part-test + (let [z (b24/Ben-make-from-real-imag '(0 0)) + bi (b24/Ben-imag-part z)] + (is (= bi (b24/Alyssa-imag-part '(0 0)))))) + +(deftest Ben-make-from-real-imag-test + (is (= '(1.0 2.0) (b24/Ben-make-from-real-imag '(1 2))))) + +; Tagged data -------------------------------------------------------------------------------------- + +(deftest attach-tag-test + (is (= '(:test x y) (b24/attach-tag :test '(x y)))) + (is (= '(:test) (b24/attach-tag :test '())))) + +(deftest type-tag-test + (is (= :test (b24/type-tag (b24/attach-tag :test '(x y)))))) + +(deftest contents-test + (is (= '(x y) (b24/contents (b24/attach-tag :test '(x y)))))) + +(deftest rectangular?-test + (is (= false (b24/rectangular? (b24/attach-tag :test '(x y))))) + (is (= true (b24/rectangular? (b24/attach-tag :rectangular '(x y)))))) + +(deftest polar?-test + (is (= false (b24/polar? (b24/attach-tag :test '(x y))))) + (is (= true (b24/polar? (b24/attach-tag :polar '(x y)))))) + +; Rectangular +(deftest make-from-real-imag-rectangular-test + (is (= [:rectangular x y] (b24/make-from-real-imag-rectangular x y))) + (is (= [:rectangular x y] (b24/make-from-real-imag-v2 x y)))) + +(deftest make-from-mag-ang-rectangular-test + (is (= [:rectangular x y] (b24/make-from-mag-ang-rectangular radius angle-60)))) + +(deftest make-from-real-imag-polar-test + (is (= [:polar radius angle-60] (b24/make-from-real-imag-polar x y)))) + +(deftest make-from-mag-ang-polar-test + (is (= [:polar radius angle-60] (b24/make-from-mag-ang-polar radius angle-60))) + (is (= [:polar radius angle-60] (b24/make-from-mag-ang-v2 radius angle-60)))) + +; Compounding of Polar and Rectangular ways +(deftest real-part-test + (is (= x (b24/real-part (b24/make-from-mag-ang-polar radius angle-60)))) + (is (= x (b24/real-part (b24/make-from-real-imag-polar x y)))) + (is (= x (b24/real-part (b24/make-from-real-imag-rectangular x y)))) + (is (= x (b24/real-part (b24/make-from-mag-ang-rectangular radius angle-60))))) + +(deftest imag-part-test + (is (= y (b24/imag-part (b24/make-from-mag-ang-polar radius angle-60)))) + (is (= y (b24/imag-part (b24/make-from-real-imag-polar x y)))) + (is (= y (b24/imag-part (b24/make-from-real-imag-rectangular x y)))) + (is (= y (b24/imag-part (b24/make-from-mag-ang-rectangular radius angle-60))))) + +(deftest magnitude-test + (is (= radius (b24/magnitude (b24/make-from-mag-ang-polar radius angle-60)))) + (is (= radius (b24/magnitude (b24/make-from-real-imag-polar x y)))) + (is (= radius (b24/magnitude (b24/make-from-real-imag-rectangular x y)))) + (is (= radius (b24/magnitude (b24/make-from-mag-ang-rectangular radius angle-60))))) + +(deftest angle-test + (is (= angle-60 (b24/angle (b24/make-from-mag-ang-polar radius angle-60)))) + (is (= angle-60 (b24/angle (b24/make-from-real-imag-polar x y)))) + (is (= angle-60 (b24/angle (b24/make-from-real-imag-rectangular x y)))) + (is (= angle-60 (b24/angle (b24/make-from-mag-ang-rectangular radius angle-60))))) + +(deftest add-complex-test + (is (= [:rectangular (* 2 x) (* 2 y)] + (b24/add-complex + (b24/make-from-mag-ang-polar radius angle-60) + (b24/make-from-real-imag-rectangular x y))))) + +(comment "2.4.3 Data-Directed Programming and Additivity -----------------------------------------") + +(deftest make-from-real-imag-test + (is (= x ((b24/make-from-real-imag x y) :real-part))) + (is (= y ((b24/make-from-real-imag x y) :imag-part))) + (is (= radius ((b24/make-from-real-imag x y) :magnitude))) + (is (= angle-60 ((b24/make-from-real-imag x y) :angle))) + (is (= true (m/is-exception? ((b24/make-from-real-imag x y) :undefined) "Unknown op: MAKE-FROM-REAL-IMAG :undefined")))) diff --git a/test/sicp/chapter_2/part_4/ex_2_73_test.clj b/test/sicp/chapter_2/part_4/ex_2_73_test.clj new file mode 100644 index 0000000..1451d6d --- /dev/null +++ b/test/sicp/chapter_2/part_4/ex_2_73_test.clj @@ -0,0 +1,24 @@ +(ns sicp.chapter-2.part-4.ex-2-73-test + (:require + [clojure.test :refer [deftest is]] + [sicp.chapter-2.part-4.ex-2-73 :as ex-2-73] + [sicp.misc :as m])) + +(ex-2-73/install-sum-derivation) +(ex-2-73/install-product-derivation) +(ex-2-73/install-exponent-derivation) + +(deftest deriv-test + (is (= 0 (ex-2-73/deriv 10 5))) + (is (= 0 (ex-2-73/deriv 'x 5))) + (is (= 0 (ex-2-73/deriv 'x 'y))) + (is (= 0 (ex-2-73/deriv '+ 'y))) + (is (= 0 (ex-2-73/deriv '(+ 2 2) 'x))) + (is (= 0 (ex-2-73/deriv '(* 2 2) 'x))) + (is (= true (m/is-exception? (ex-2-73/deriv '(** 2 2) 'x) "unknown expression type: DERIV (** 2 2)")))) + +(deftest deriv-v2-test + (is (= 0 (ex-2-73/deriv-v2 10 5))) + (is (= 0 (ex-2-73/deriv-v2 'x 5))) + (is (= 0 (ex-2-73/deriv-v2 'x 'y))) + (is (= 0 (ex-2-73/deriv-v2 '+ 'y)))) diff --git a/test/sicp/chapter_2/part_4/ex_2_75_test.clj b/test/sicp/chapter_2/part_4/ex_2_75_test.clj new file mode 100644 index 0000000..072cc92 --- /dev/null +++ b/test/sicp/chapter_2/part_4/ex_2_75_test.clj @@ -0,0 +1,18 @@ +(ns sicp.chapter-2.part-4.ex-2-75-test + (:require + [clojure.test :refer [deftest is]] + [sicp.chapter-2.part-4.ex-2-75 :refer [make-from-mag-ang]] + [sicp.misc :as m])) + +(def angle-60 (/ Math/PI 3)) +(def radius 2.0) +(def x 1.0000000000000002) +(def y 1.7320508075688772) + +(deftest make-from-mag-ang-test + (is (= x ((make-from-mag-ang radius angle-60) :real-part))) + (is (= y ((make-from-mag-ang radius angle-60) :imag-part))) + (is (= radius ((make-from-mag-ang radius angle-60) :magnitude))) + (is (= angle-60 ((make-from-mag-ang radius angle-60) :angle))) + (is (= true (m/is-exception? ((make-from-mag-ang radius angle-60) :undefined) + "Unknown op: MAKE-FROM-REAL-IMAG :undefined")))) diff --git a/test/sicp/chapter_2/part_5/book_2_5_test.clj b/test/sicp/chapter_2/part_5/book_2_5_test.clj index de4a2c1..ab09e5e 100644 --- a/test/sicp/chapter_2/part_5/book_2_5_test.clj +++ b/test/sicp/chapter_2/part_5/book_2_5_test.clj @@ -1,38 +1,41 @@ (ns sicp.chapter-2.part-5.book-2-5-test (:require [clojure.test :refer [deftest is]] - [sicp.chapter-2.part-5.book-2-5 :refer [add - div - install-rational-package - install-scheme-number-package - make-rational - make-scheme-number - mul - sub]])) + [sicp.chapter-2.part-5.book-2-5 :as b25] + [sicp.misc :as m])) -(install-scheme-number-package) -(install-rational-package) +(b25/install-scheme-number-package) +(b25/install-rational-package) +(b25/install-complex-package) + +(deftest install-test + (is (= :done (b25/install-scheme-number-package))) + (is (= :done (b25/install-rational-package))) + (is (= :done (b25/install-complex-package)))) (deftest add-test - (is (= (make-scheme-number 3) (add (make-scheme-number 1) (make-scheme-number 2)))) - (is (= (make-scheme-number 4) (add (make-scheme-number 2) (make-scheme-number 2)))) - (is (= (make-rational 4 1) (add (make-rational 2 1) (make-rational 2 1)))) - (is (= (make-rational 1 1) (add (make-rational 2 3) (make-rational 1 3))))) + (is (= (b25/make-scheme-number 3) (b25/add (b25/make-scheme-number 1) (b25/make-scheme-number 2)))) + (is (= (b25/make-scheme-number 4) (b25/add (b25/make-scheme-number 2) (b25/make-scheme-number 2)))) + (is (= (b25/make-rational 4 1) (b25/add (b25/make-rational 2 1) (b25/make-rational 2 1)))) + (is (= (b25/make-rational 1 1) (b25/add (b25/make-rational 2 3) (b25/make-rational 1 3))))) (deftest sub-test - (is (= (make-scheme-number 1) (sub (make-scheme-number 4) (make-scheme-number 3)))) - (is (= (make-scheme-number -6) (sub (make-scheme-number 4) (make-scheme-number 10)))) - (is (= (make-rational 0 1) (sub (make-rational 2 1) (make-rational 2 1)))) - (is (= (make-rational 1 3) (sub (make-rational 2 3) (make-rational 1 3))))) + (is (= (b25/make-scheme-number 1) (b25/sub (b25/make-scheme-number 4) (b25/make-scheme-number 3)))) + (is (= (b25/make-scheme-number -6) (b25/sub (b25/make-scheme-number 4) (b25/make-scheme-number 10)))) + (is (= (b25/make-rational 0 1) (b25/sub (b25/make-rational 2 1) (b25/make-rational 2 1)))) + (is (= (b25/make-rational 1 3) (b25/sub (b25/make-rational 2 3) (b25/make-rational 1 3))))) (deftest mul-test - (is (= (make-scheme-number 12) (mul (make-scheme-number 4) (make-scheme-number 3)))) - (is (= (make-scheme-number -40) (mul (make-scheme-number -4) (make-scheme-number 10)))) - (is (= (make-rational 4 1) (mul (make-rational 2 1) (make-rational 2 1)))) - (is (= (make-rational 2 9) (mul (make-rational 2 3) (make-rational 1 3))))) + (is (= (b25/make-scheme-number 12) (b25/mul (b25/make-scheme-number 4) (b25/make-scheme-number 3)))) + (is (= (b25/make-scheme-number -40) (b25/mul (b25/make-scheme-number -4) (b25/make-scheme-number 10)))) + (is (= (b25/make-rational 4 1) (b25/mul (b25/make-rational 2 1) (b25/make-rational 2 1)))) + (is (= (b25/make-rational 2 9) (b25/mul (b25/make-rational 2 3) (b25/make-rational 1 3))))) (deftest div-test - (is (= (make-scheme-number 20) (div (make-scheme-number 100) (make-scheme-number 5)))) - (is (= (make-scheme-number 1/2) (div (make-scheme-number 3) (make-scheme-number 6)))) - (is (= (make-rational 1 1) (div (make-rational 2 1) (make-rational 2 1)))) - (is (= (make-rational 2 1) (div (make-rational 2 3) (make-rational 1 3))))) + (is (= (b25/make-scheme-number 20) (b25/div (b25/make-scheme-number 100) (b25/make-scheme-number 5)))) + (is (= (b25/make-scheme-number 1/2) (b25/div (b25/make-scheme-number 3) (b25/make-scheme-number 6)))) + (is (= (b25/make-rational 1 1) (b25/div (b25/make-rational 2 1) (b25/make-rational 2 1)))) + (is (= (b25/make-rational 2 1) (b25/div (b25/make-rational 2 3) (b25/make-rational 1 3))))) + +(deftest apply-generic-test + (is (= true (m/is-exception? ((b25/apply-generic :undefined 1 2)) "No method for: :undefined")))) diff --git a/test/sicp/misc_test.clj b/test/sicp/misc_test.clj index 8243957..b0edba5 100644 --- a/test/sicp/misc_test.clj +++ b/test/sicp/misc_test.clj @@ -6,10 +6,9 @@ (comment "Chapter #1 The Elements of Programming -------------------------------------------------") (deftest error-test - (try - (m/error "123") - (catch Exception e - (is (= (.getMessage e) "123"))))) + (is (= true (m/is-exception? (m/error "123")))) + (is (= true (m/is-exception? (m/error "123") "123"))) + (is (= true (m/is-exception? (m/error "123") "123")))) (deftest square-test (is (= 4 (m/square 2)))