Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes macroexpansions and upgrades clojure(script) versions #178

Merged
merged 7 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Run Specs

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: 21
distribution: 'temurin'

- name: Cache Clojure Dependencies
uses: actions/cache@v4
with:
path: ~/.m2
key: ${{ runner.os }}-deps-${{ hashFiles('**/deps.edn') }}
restore-keys: |
${{ runner.os }}-deps-

- name: Install Clojure CLI
run: curl -O https://download.clojure.org/install/linux-install-1.11.1.1119.sh && chmod +x linux-install-1.11.1.1119.sh && sudo ./linux-install-1.11.1.1119.sh

- name: Build JAR
run: clojure -T:build jar

- name: Install NPM Dependencies
run: npm install

- name: Run Clojure Tests
run: clojure -M:test:spec

- name: Run ClojureScript Tests
run: clojure -M:test:cljs once
11 changes: 11 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# 3.4.7

* fixes bug where `should-throw` would expand string predicates improperly under cljs whitespace optimizations.
* fixes `should<`, `should<=`, `should>`, `should>=`, and other macros to only evaluate forms once.
* upgrades to clojure 1.11.3
* upgrades to clojurescript 1.11.132

# 3.4.6

* adds cloverage support

# 3.4.5

* 3.4.4 was a failed deploy... no compiled java code.
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,20 @@ clj -T:build clean
clj -M:test:cljs
```

To include in a local project

```bash
clj -T:build clean
clj -T:build javac
clj -T:build jar
```

In deps.edn

```clojure
{speclj/speclj {:local/root "/path/to/speclj/target/speclj-3.4.6.jar"}}
```

Make patches and submit them along with an issue (see below).

## Issues
Expand Down
8 changes: 4 additions & 4 deletions deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
:deps {
fresh/fresh {:mvn/version "1.1.2"}
mmargs/mmargs {:mvn/version "1.2.0"}
org.clojure/clojure {:mvn/version "1.11.1"}
org.clojure/clojure {:mvn/version "1.11.3"}
trptcolin/versioneer {:mvn/version "0.1.1"}
}
:aliases {
:test {:extra-deps {
io.github.clojure/tools.build {:mvn/version "0.9.5"}
org.clojure/clojurescript {:mvn/version "1.11.60"}
cloverage/cloverage {:mvn/version "1.2.4"}
org.clojure/clojurescript {:mvn/version "1.11.132"}
cloverage/cloverage {:mvn/version "1.2.4"}
}
:extra-paths ["dev" "spec" "target/classes"]}
:spec {:main-opts ["-m" "speclj.main" "-c"]}
Expand All @@ -19,7 +19,7 @@
clj-commons/pomegranate {:mvn/version "1.2.23"}}
:ns-default build
:extra-paths ["dev"]}
:cov {:main-opts ["-m" "cloverage.coverage" "--runner" ":speclj" "-p" "src" "-s" "spec" "-e" "leiningen.spec" "--foo" "bar"]}
:cov {:main-opts ["-m" "cloverage.coverage" "--runner" ":speclj" "-p" "src" "-s" "spec" "-e" "leiningen.spec" "--foo" "bar"]}
:codox {:extra-deps {codox/codox {:mvn/version "0.10.8"}}
:exec-fn codox.main/generate-docs
:exec-args {:source-paths ["src"]
Expand Down
3 changes: 2 additions & 1 deletion spec/speclj/core_spec.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,9 @@
(swap! widget #(/ % 2)))

(around-all [context]
(swap! widget #(- % 2))
(context))
(swap! widget #(- % 2)))
)

(describe "previous after-all and around-all forms"
(it "executes before after-alls regardless of definition order"
Expand Down
99 changes: 54 additions & 45 deletions src/speclj/core.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -216,31 +216,32 @@
(-make-with name body `speclj.components/new-with-all true))

(defmacro ^:no-doc -to-s [thing]
`(if (nil? ~thing) "nil" (pr-str ~thing)))
`(if-some [thing# ~thing] (pr-str thing#) "nil"))

(defmacro -fail
"Useful for making custom assertions."
[message]
`(throw (-new-failure ~message)))

(defmacro ^:no-doc wrong-types [assertion a b]
`(let [type-a# (if (nil? ~a) "nil" (speclj.platform/type-name (type ~a)))
type-b# (if (nil? ~b) "nil" (speclj.platform/type-name (type ~b)))]
`(let [a# ~a
b# ~b
type-a# (if (nil? a#) "nil" (speclj.platform/type-name (type a#)))
type-b# (if (nil? b#) "nil" (speclj.platform/type-name (type b#)))]
(str ~assertion " doesn't know how to handle these types: [" type-a# " " type-b# "]")))

(defmacro should
"Asserts the truthy-ness of a form"
[form]
`(let [value# ~form]
(if-not value#
(when-not value#
(-fail (str "Expected truthy but was: " (-to-s value#) "")))))

(defmacro should-not
"Asserts the falsy-ness of a form"
[form]
`(let [value# ~form]
(when value#
(-fail (str "Expected falsy but was: " (-to-s value#))))))
`(when-let [value# ~form]
(-fail (str "Expected falsy but was: " (-to-s value#)))))

(defmacro should=
"Asserts that two forms evaluate to equal values, with the expected value as the first parameter."
Expand Down Expand Up @@ -325,7 +326,7 @@
`(let [expected# ~expected
actual# ~actual]
(cond
(nil? actual#) nil ; automatic pass!
(nil? actual#) nil ; automatic pass!
(and (string? expected#) (string? actual#))
(when (not (= -1 (.indexOf actual# expected#)))
(-fail (str "Expected: " (-to-s expected#) speclj.platform/endl "not to be in: " (-to-s actual#) " (using .contains)")))
Expand Down Expand Up @@ -378,25 +379,28 @@
"Collection: " (-to-s coll#))))))))

(defmacro ^:no-doc -remove-first [coll value]
`(loop [coll# ~coll seen# []]
(if (empty? coll#)
seen#
(let [f# (first coll#)]
(if (= f# ~value)
(concat seen# (rest coll#))
(recur (rest coll#) (conj seen# f#)))))))
`(let [value# ~value]
(loop [coll# ~coll seen# []]
(if (empty? coll#)
seen#
(let [f# (first coll#)]
(if (= f# value#)
(concat seen# (rest coll#))
(recur (rest coll#) (conj seen# f#))))))))

(defmacro ^:no-doc -coll-difference [coll1 coll2]
`(if (map? ~coll1)
(first (clojure.data/diff ~coll1 ~coll2))
(loop [match-with# ~coll1 match-against# ~coll2 diff# []]
(if (empty? match-with#)
diff#
(let [f# (first match-with#)
r# (rest match-with#)]
(if (some #(= % f#) match-against#)
(recur r# (-remove-first match-against# f#) diff#)
(recur r# match-against# (conj diff# f#))))))))
`(let [coll1# ~coll1
coll2# ~coll2]
(if (map? coll1#)
(first (clojure.data/diff coll1# coll2#))
(loop [match-with# coll1# match-against# coll2# diff# []]
(if (empty? match-with#)
diff#
(let [f# (first match-with#)
r# (rest match-with#)]
(if (some #(= % f#) match-against#)
(recur r# (-remove-first match-against# f#) diff#)
(recur r# match-against# (conj diff# f#)))))))))

(defmacro should-start-with
"Assertion of prefix in strings and sequences.
Expand Down Expand Up @@ -554,7 +558,7 @@
(defmacro ^:no-doc -create-should-throw-failure [expected actual expr]
`(let [expected-name# (speclj.platform/type-name ~expected)
expected-gaps# (apply str (repeat (count expected-name#) " "))
actual-string# (if ~actual (pr-str ~actual) "<nothing thrown>")]
actual-string# (if-let [actual# ~actual] (pr-str actual#) "<nothing thrown>")]
(-new-failure (str "Expected " expected-name# " thrown from: " (pr-str ~expr) speclj.platform/endl
" " expected-gaps# " but got: " actual-string#))))

Expand All @@ -579,14 +583,15 @@ There are three options for passing different kinds of predicates:
`(let [e# (should-throw ~throwable-type ~form)
regex# (if-cljs js/RegExp java.util.regex.Pattern)]
(try-catch-anything
(cond (instance? regex# ~predicate)
(should-not-be-nil (re-find ~predicate (speclj.platform/error-message e#)))
(let [predicate# ~predicate]
(cond (instance? regex# predicate#)
(should-not-be-nil (re-find predicate# (speclj.platform/error-message e#)))

(ifn? ~predicate)
(should= true (~predicate e#))
(ifn? predicate#)
(should= true (predicate# e#))

:else
(should= ~predicate (speclj.platform/error-message e#)))
:else
(should= predicate# (speclj.platform/error-message e#))))

(catch f# (-fail (str "Expected exception predicate didn't match" speclj.platform/endl (speclj.platform/error-message f#))))))))

Expand Down Expand Up @@ -811,30 +816,34 @@ There are three options for passing different kinds of predicates:
(defmacro should<
"Asserts that the first numeric form is less than the second numeric form, using the built-in < function."
[a b]
`(cond
(not (and (number? ~a) (number? ~b))) (throw (-new-exception (wrong-types "should<" ~a ~b)))
:else (when-not (< ~a ~b) (-fail (str "expected " ~a " to be less than " ~b " but got: (< " ~a " " ~b ")")))))
`(let [a# ~a b# ~b]
(if (and (number? a#) (number? b#))
(when-not (< a# b#) (-fail (str "expected " a# " to be less than " b# " but got: (< " a# " " b# ")")))
(throw (-new-exception (wrong-types "should<" a# b#))))))

(defmacro should>
"Asserts that the first numeric form is greater than the second numeric form, using the built-in > function."
[a b]
`(cond
(not (and (number? ~a) (number? ~b))) (throw (-new-exception (wrong-types "should>" ~a ~b)))
:else (when-not (> ~a ~b) (-fail (str "expected " ~a " to be greater than " ~b " but got: (> " ~a " " ~b ")")))))
`(let [a# ~a b# ~b]
(if (and (number? a#) (number? b#))
(when-not (> a# b#) (-fail (str "expected " a# " to be greater than " b# " but got: (> " a# " " b# ")")))
(throw (-new-exception (wrong-types "should>" a# b#))))))

(defmacro should<=
"Asserts that the first numeric form is less than or equal to the second numeric form, using the built-in <= function."
[a b]
`(cond
(not (and (number? ~a) (number? ~b))) (throw (-new-exception (wrong-types "should<=" ~a ~b)))
:else (when-not (<= ~a ~b) (-fail (str "expected " ~a " to be less than or equal to " ~b " but got: (<= " ~a " " ~b ")")))))
`(let [a# ~a b# ~b]
(if (and (number? a#) (number? b#))
(when-not (<= a# b#) (-fail (str "expected " a# " to be less than or equal to " b# " but got: (<= " a# " " b# ")")))
(throw (-new-exception (wrong-types "should<=" a# b#))))))

(defmacro should>=
"Asserts that the first numeric form is greater than or equal to the second numeric form, using the built-in >= function."
[a b]
`(cond
(not (and (number? ~a) (number? ~b))) (throw (-new-exception (wrong-types "should>=" ~a ~b)))
:else (when-not (>= ~a ~b) (-fail (str "expected " ~a " to be greater than or equal to " ~b " but got: (>= " ~a " " ~b ")")))))
`(let [a# ~a b# ~b]
(if (and (number? a#) (number? b#))
(when-not (>= a# b#) (-fail (str "expected " a# " to be greater than or equal to " b# " but got: (>= " a# " " b# ")")))
(throw (-new-exception (wrong-types "should>=" a# b#))))))

(defmacro run-specs []
"If evaluated outside the context of a spec run, it will run all the specs that have been evaluated using the default
Expand All @@ -845,5 +854,5 @@ are evaluated by evaluation the file as a script. Optional configuration parame
`(if-cljs
(comment "Ignoring run-specs for clojurescript")
(do
(require '[speclj.cli]) ; require all speclj files
(require '[speclj.cli]) ; require all speclj files
(speclj.run.standard/run-specs))))
Loading