diff --git a/docs/GENERATORS.md b/docs/GENERATORS.md index b22a8a658..ec6f7ee13 100644 --- a/docs/GENERATORS.md +++ b/docs/GENERATORS.md @@ -11,7 +11,8 @@ To generate a practice exercise's tests, the test generator: 2. Uses `tests.toml` file to omit and excluded test cases 3. Transforms the test cases (optional) 4. Renders the test cases using the exercise's generator template -5. Writes the rendered template to the exercise's test file +5. Format the rendered template using [cljfmt](https://github.com/weavejester/cljfmt) +6. Writes the formatted template to the exercise's test file ### Step 1: read `canonical-data.json` file @@ -80,7 +81,15 @@ If you define _both_ functions, `add-remove-test-cases` is called first and `upd The (potentially transformed) test cases are then passed to the `.meta/generator.tpl` file, which defines how the tests should be rendered based on those test cases. -### Step 5: write the rendered template to the exercise's test file +### Step 5: format the rendered template using cljfmt + +The rendered template is then formatted using [cljfmt](https://github.com/weavejester/cljfmt). +This has the following benefits: + +- Exercises are formatted consistently +- You're not required to worry much about whitespace and alignment when writing templates + +### Step 6: write the rendered template to the exercise's test file Finally, the output of the rendered template is written to the exercise's test file. diff --git a/exercises/practice/change/test/change_test.clj b/exercises/practice/change/test/change_test.clj index f182f3a3a..689c117a0 100644 --- a/exercises/practice/change/test/change_test.clj +++ b/exercises/practice/change/test/change_test.clj @@ -6,64 +6,63 @@ (testing "change for 1 cent" (is (= '(1) (change/issue 1 #{1 5 10 25}))))) - + (deftest issue_test_2 (testing "single coin change" (is (= '(25) (change/issue 25 #{1 5 10 25 100}))))) - + (deftest issue_test_3 (testing "multiple coin change" (is (= '(5 10) (change/issue 15 #{1 5 10 25 100}))))) - + (deftest issue_test_4 (testing "change with Lilliputian Coins" (is (= '(4 4 15) (change/issue 23 #{1 4 15 20 50}))))) - + (deftest issue_test_5 (testing "change with Lower Elbonia Coins" (is (= '(21 21 21) (change/issue 63 #{1 5 10 21 25}))))) - + (deftest issue_test_6 (testing "large target values" (is (= '(2 2 5 20 20 50 100 100 100 100 100 100 100 100 100) (change/issue 999 #{1 2 5 10 20 50 100}))))) - + (deftest issue_test_7 (testing "possible change without unit coins available" (is (= '(2 2 2 5 10) (change/issue 21 #{2 5 10 20 50}))))) - + (deftest issue_test_8 (testing "another possible change without unit coins available" (is (= '(4 4 4 5 5 5) (change/issue 27 #{4 5}))))) - + (deftest issue_test_9 (testing "a greedy approach is not optimal" (is (= '(10 10) (change/issue 20 #{1 10 11}))))) - + (deftest issue_test_10 (testing "no coins make 0 change" (is (= '() (change/issue 0 #{1 5 10 21 25}))))) - + (deftest issue_test_11 (testing "error testing for change smaller than the smallest of coins" (is (thrown-with-msg? IllegalArgumentException #"^can't make target with given coins$" (change/issue 3 #{5 10}))))) - + (deftest issue_test_12 (testing "error if no combination can add up to target" (is (thrown-with-msg? IllegalArgumentException #"^can't make target with given coins$" (change/issue 94 #{5 10}))))) - + (deftest issue_test_13 (testing "cannot find negative change values" (is (thrown-with-msg? IllegalArgumentException #"^target can't be negative$" (change/issue -5 #{1 2 5}))))) - \ No newline at end of file diff --git a/exercises/practice/largest-series-product/test/largest_series_product_test.clj b/exercises/practice/largest-series-product/test/largest_series_product_test.clj index 07d8d6b49..e34c9e985 100644 --- a/exercises/practice/largest-series-product/test/largest_series_product_test.clj +++ b/exercises/practice/largest-series-product/test/largest_series_product_test.clj @@ -5,52 +5,51 @@ (deftest largest-product_test_1 (testing "finds the largest product if span equals length" (is (= 18 (largest-series-product/largest-product 2 "29"))))) - + (deftest largest-product_test_2 (testing "can find the largest product of 2 with numbers in order" (is (= 72 (largest-series-product/largest-product 2 "0123456789"))))) - + (deftest largest-product_test_3 (testing "can find the largest product of 2" (is (= 48 (largest-series-product/largest-product 2 "576802143"))))) - + (deftest largest-product_test_4 (testing "can find the largest product of 3 with numbers in order" (is (= 504 (largest-series-product/largest-product 3 "0123456789"))))) - + (deftest largest-product_test_5 (testing "can find the largest product of 3" (is (= 270 (largest-series-product/largest-product 3 "1027839564"))))) - + (deftest largest-product_test_6 (testing "can find the largest product of 5 with numbers in order" (is (= 15120 (largest-series-product/largest-product 5 "0123456789"))))) - + (deftest largest-product_test_7 (testing "can get the largest product of a big number" (is (= 23520 (largest-series-product/largest-product 6 "73167176531330624919225119674426574742355349194934"))))) - + (deftest largest-product_test_8 (testing "reports zero if the only digits are zero" (is (= 0 (largest-series-product/largest-product 2 "0000"))))) - + (deftest largest-product_test_9 (testing "reports zero if all spans include zero" (is (= 0 (largest-series-product/largest-product 3 "99099"))))) - + (deftest largest-product_test_10 (testing "rejects span longer than string length" (is (thrown-with-msg? IllegalArgumentException #"^span must be smaller than string length$" (largest-series-product/largest-product 4 "123"))))) - + (deftest largest-product_test_11 (testing "rejects empty string and nonzero span" (is (thrown-with-msg? IllegalArgumentException #"^span must be smaller than string length$" (largest-series-product/largest-product 1 ""))))) - + (deftest largest-product_test_12 (testing "rejects invalid character in digits" (is (thrown-with-msg? IllegalArgumentException #"^digits input must only contain digits$" (largest-series-product/largest-product 2 "1234a5"))))) - + (deftest largest-product_test_13 (testing "rejects negative span" (is (thrown-with-msg? IllegalArgumentException #"^span must not be negative$" (largest-series-product/largest-product -1 "12345"))))) - \ No newline at end of file diff --git a/exercises/practice/saddle-points/test/saddle_points_test.clj b/exercises/practice/saddle-points/test/saddle_points_test.clj index b931f42c5..979fc2a86 100644 --- a/exercises/practice/saddle-points/test/saddle_points_test.clj +++ b/exercises/practice/saddle-points/test/saddle_points_test.clj @@ -6,83 +6,66 @@ (testing "Can identify single saddle point" (is (= #{[2 1]} (saddle-points/saddle-points - [ - [9 8 7] - [5 3 2] - [6 6 7] - ]))))) + [[9 8 7] + [5 3 2] + [6 6 7]]))))) (deftest saddle-points_test_2 (testing "Can identify that empty matrix has no saddle points" (is (= #{} (saddle-points/saddle-points - [ - ]))))) + []))))) (deftest saddle-points_test_3 (testing "Can identify lack of saddle points when there are none" (is (= #{} (saddle-points/saddle-points - [ - [1 2 3] - [3 1 2] - [2 3 1] - ]))))) + [[1 2 3] + [3 1 2] + [2 3 1]]))))) (deftest saddle-points_test_4 (testing "Can identify multiple saddle points in a column" (is (= #{[2 2] [1 2] [3 2]} (saddle-points/saddle-points - [ - [4 5 4] - [3 5 5] - [1 5 4] - ]))))) + [[4 5 4] + [3 5 5] + [1 5 4]]))))) (deftest saddle-points_test_5 (testing "Can identify multiple saddle points in a row" (is (= #{[2 2] [2 3] [2 1]} (saddle-points/saddle-points - [ - [6 7 8] - [5 5 5] - [7 5 6] - ]))))) + [[6 7 8] + [5 5 5] + [7 5 6]]))))) (deftest saddle-points_test_6 (testing "Can identify saddle point in bottom right corner" (is (= #{[3 3]} (saddle-points/saddle-points - [ - [8 7 9] - [6 7 6] - [3 2 5] - ]))))) + [[8 7 9] + [6 7 6] + [3 2 5]]))))) (deftest saddle-points_test_7 (testing "Can identify saddle points in a non square matrix" (is (= #{[1 1] [1 3]} (saddle-points/saddle-points - [ - [3 1 3] - [3 2 4] - ]))))) + [[3 1 3] + [3 2 4]]))))) (deftest saddle-points_test_8 (testing "Can identify that saddle points in a single column matrix are those with the minimum value" (is (= #{[4 1] [2 1]} (saddle-points/saddle-points - [ - [2] - [1] - [4] - [1] - ]))))) + [[2] + [1] + [4] + [1]]))))) (deftest saddle-points_test_9 (testing "Can identify that saddle points in a single row matrix are those with the maximum value" (is (= #{[1 4] [1 2]} (saddle-points/saddle-points - [ - [2 5 3 5] - ]))))) + [[2 5 3 5]]))))) diff --git a/exercises/practice/simple-cipher/test/simple_cipher_test.clj b/exercises/practice/simple-cipher/test/simple_cipher_test.clj index 77657ba91..e571eb3f2 100644 --- a/exercises/practice/simple-cipher/test/simple_cipher_test.clj +++ b/exercises/practice/simple-cipher/test/simple_cipher_test.clj @@ -9,47 +9,46 @@ (deftest encode_test_1 (testing "Random key cipher ▶ Can encode" (let [key (simple-cipher/rand-key)] - (is (= (subs key 0 (count "aaaaaaaaaa")) (simple-cipher/encode key "aaaaaaaaaa")))))) - + (is (= (subs key 0 (count "aaaaaaaaaa")) (simple-cipher/encode key "aaaaaaaaaa")))))) + (deftest encode_test_2 (testing "Substitution cipher ▶ Can encode" (is (= "abcdefghij" (simple-cipher/encode "abcdefghij" "aaaaaaaaaa"))))) - + (deftest encode_test_3 (testing "Substitution cipher ▶ Can double shift encode" (is (= "qayaeaagaciai" (simple-cipher/encode "iamapandabear" "iamapandabear"))))) - + (deftest encode_test_4 (testing "Substitution cipher ▶ Can wrap on encode" (is (= "zabcdefghi" (simple-cipher/encode "abcdefghij" "zzzzzzzzzz"))))) - + (deftest encode_test_5 (testing "Substitution cipher ▶ Can encode messages longer than the key" (is (= "iboaqcnecbfcr" (simple-cipher/encode "abc" "iamapandabear"))))) - + (deftest decode_test_1 (testing "Random key cipher ▶ Can decode" (let [key (simple-cipher/rand-key)] (is (= "aaaaaaaaaa" (simple-cipher/decode key (subs key 0 (count "aaaaaaaaaa"))))))) - -(deftest decode_test_2 - (testing "Random key cipher ▶ Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method" - (let [key (simple-cipher/rand-key)] - (is (= "abcdefghij" (simple-cipher/decode key (simple-cipher/encode key "abcdefghij"))))) - -(deftest decode_test_3 - (testing "Substitution cipher ▶ Can decode" - (is (= "aaaaaaaaaa" (simple-cipher/decode "abcdefghij" "abcdefghij")))))) - -(deftest decode_test_4 - (testing "Substitution cipher ▶ Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method" - (is (= "abcdefghij" (simple-cipher/decode "abcdefghij" (simple-cipher/encode "abcdefghij" "abcdefghij")))))) - -(deftest decode_test_5 - (testing "Substitution cipher ▶ Can wrap on decode" - (is (= "zzzzzzzzzz" (simple-cipher/decode "abcdefghij" "zabcdefghi")))))) - -(deftest decode_test_6 - (testing "Substitution cipher ▶ Can decode messages longer than the key" - (is (= "iamapandabear" (simple-cipher/decode "abc" "iboaqcnecbfcr")))))) - \ No newline at end of file + + (deftest decode_test_2 + (testing "Random key cipher ▶ Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method" + (let [key (simple-cipher/rand-key)] + (is (= "abcdefghij" (simple-cipher/decode key (simple-cipher/encode key "abcdefghij"))))) + + (deftest decode_test_3 + (testing "Substitution cipher ▶ Can decode" + (is (= "aaaaaaaaaa" (simple-cipher/decode "abcdefghij" "abcdefghij")))))) + + (deftest decode_test_4 + (testing "Substitution cipher ▶ Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method" + (is (= "abcdefghij" (simple-cipher/decode "abcdefghij" (simple-cipher/encode "abcdefghij" "abcdefghij")))))) + + (deftest decode_test_5 + (testing "Substitution cipher ▶ Can wrap on decode" + (is (= "zzzzzzzzzz" (simple-cipher/decode "abcdefghij" "zabcdefghi")))))) + + (deftest decode_test_6 + (testing "Substitution cipher ▶ Can decode messages longer than the key" + (is (= "iamapandabear" (simple-cipher/decode "abc" "iboaqcnecbfcr")))))) diff --git a/exercises/practice/wordy/test/wordy_test.clj b/exercises/practice/wordy/test/wordy_test.clj index 159fe3b39..1ed8a5bd8 100644 --- a/exercises/practice/wordy/test/wordy_test.clj +++ b/exercises/practice/wordy/test/wordy_test.clj @@ -5,92 +5,91 @@ (deftest evaluate_test_1 (testing "just a number" (is (= 5 (wordy/evaluate "What is 5?"))))) - + (deftest evaluate_test_2 (testing "addition" (is (= 2 (wordy/evaluate "What is 1 plus 1?"))))) - + (deftest evaluate_test_3 (testing "more addition" (is (= 55 (wordy/evaluate "What is 53 plus 2?"))))) - + (deftest evaluate_test_4 (testing "addition with negative numbers" (is (= -11 (wordy/evaluate "What is -1 plus -10?"))))) - + (deftest evaluate_test_5 (testing "large addition" (is (= 45801 (wordy/evaluate "What is 123 plus 45678?"))))) - + (deftest evaluate_test_6 (testing "subtraction" (is (= 16 (wordy/evaluate "What is 4 minus -12?"))))) - + (deftest evaluate_test_7 (testing "multiplication" (is (= -75 (wordy/evaluate "What is -3 multiplied by 25?"))))) - + (deftest evaluate_test_8 (testing "division" (is (= -11 (wordy/evaluate "What is 33 divided by -3?"))))) - + (deftest evaluate_test_9 (testing "multiple additions" (is (= 3 (wordy/evaluate "What is 1 plus 1 plus 1?"))))) - + (deftest evaluate_test_10 (testing "addition and subtraction" (is (= 8 (wordy/evaluate "What is 1 plus 5 minus -2?"))))) - + (deftest evaluate_test_11 (testing "multiple subtraction" (is (= 3 (wordy/evaluate "What is 20 minus 4 minus 13?"))))) - + (deftest evaluate_test_12 (testing "subtraction then addition" (is (= 14 (wordy/evaluate "What is 17 minus 6 plus 3?"))))) - + (deftest evaluate_test_13 (testing "multiple multiplication" (is (= -12 (wordy/evaluate "What is 2 multiplied by -2 multiplied by 3?"))))) - + (deftest evaluate_test_14 (testing "addition and multiplication" (is (= -8 (wordy/evaluate "What is -3 plus 7 multiplied by -2?"))))) - + (deftest evaluate_test_15 (testing "multiple division" (is (= 2 (wordy/evaluate "What is -12 divided by 2 divided by -3?"))))) - + (deftest evaluate_test_16 (testing "unknown operation" (is (thrown-with-msg? IllegalArgumentException #"^unknown operation$" (wordy/evaluate "What is 52 cubed?"))))) - + (deftest evaluate_test_17 (testing "Non math question" (is (thrown-with-msg? IllegalArgumentException #"^syntax error$" (wordy/evaluate "Who is the President of the United States?"))))) - + (deftest evaluate_test_18 (testing "reject problem missing an operand" (is (thrown-with-msg? IllegalArgumentException #"^syntax error$" (wordy/evaluate "What is 1 plus?"))))) - + (deftest evaluate_test_19 (testing "reject problem with no operands or operators" (is (thrown-with-msg? IllegalArgumentException #"^syntax error$" (wordy/evaluate "What is?"))))) - + (deftest evaluate_test_20 (testing "reject two operations in a row" (is (thrown-with-msg? IllegalArgumentException #"^syntax error$" (wordy/evaluate "What is 1 plus plus 2?"))))) - + (deftest evaluate_test_21 (testing "reject two numbers in a row" (is (thrown-with-msg? IllegalArgumentException #"^syntax error$" (wordy/evaluate "What is 1 plus 2 1?"))))) - + (deftest evaluate_test_22 (testing "reject postfix notation" (is (thrown-with-msg? IllegalArgumentException #"^syntax error$" (wordy/evaluate "What is 1 2 plus?"))))) - + (deftest evaluate_test_23 (testing "reject prefix notation" (is (thrown-with-msg? IllegalArgumentException #"^syntax error$" (wordy/evaluate "What is plus 1 2?"))))) - \ No newline at end of file diff --git a/generators/deps.edn b/generators/deps.edn index f54ec7909..ee4a86698 100644 --- a/generators/deps.edn +++ b/generators/deps.edn @@ -3,4 +3,5 @@ hbs/hbs {:mvn/version "1.0.3"} io.github.tonsky/toml-clj {:mvn/version "0.1.0"} clj-jgit/clj-jgit {:mvn/version "1.1.0"} - org.slf4j/slf4j-nop {:mvn/version "1.7.30"}}} + org.slf4j/slf4j-nop {:mvn/version "1.7.30"} + dev.weavejester/cljfmt {:mvn/version "0.13.0"}}} diff --git a/generators/src/formatting.clj b/generators/src/formatting.clj new file mode 100644 index 000000000..c9982bea4 --- /dev/null +++ b/generators/src/formatting.clj @@ -0,0 +1,5 @@ +(ns formatting + (:require [cljfmt.core :refer [reformat-string]])) + +(defn format-code [code] + (reformat-string code)) diff --git a/generators/src/templates.clj b/generators/src/templates.clj index 650281f42..df443b85e 100644 --- a/generators/src/templates.clj +++ b/generators/src/templates.clj @@ -4,7 +4,8 @@ [hbs.ext :refer :all :exclude [hash]] [clojure.string :as str] [log] - [paths]) + [paths] + [formatting]) (:import [com.github.jknack.handlebars Formatter EscapingStrategy])) (defn format-string [s _next] @@ -91,4 +92,5 @@ (let [template (slurp (paths/generator-template-file slug)) data (test-cases->data slug test-cases)] (->> (render reg template data) + (formatting/format-code) (spit (paths/tests-file slug)))))