-
Notifications
You must be signed in to change notification settings - Fork 0
/
core.clj
111 lines (100 loc) · 3.96 KB
/
core.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
(ns clj-concordion.core
(:require
[clj-concordion.internal.utils :refer :all]
[clojure.test :as test])
(:import
[org.concordion.internal ClassNameBasedSpecificationLocator
FixtureInstance
FixtureRunner]
(org.concordion.api Resource)))
(defn before-suite [fix-inst suite?]
(when suite?
(.beforeSuite fix-inst)))
(defn run-fixture
"Test a Concordion specification using the given fixture object
(which provides the functions used in the specification .md).
The specification file is found on the classpath based on the name
of the fixture's class.
"
[^Object fixture suite?]
(let [fixture-meta (doto (FixtureInstance. fixture)
(before-suite suite?)
(.beforeSpecification)
(.setupForRun fixture))
result (.run
(FixtureRunner.
fixture-meta
(ClassNameBasedSpecificationLocator.))
fixture-meta)]
(do
(.afterSpecification fixture-meta)
(when suite?
(.afterSuite fixture-meta)))
result))
(defn drop-file-suffix [path]
(subs path 0 (.lastIndexOf path ".")))
(defn find-fixture-class [^Resource resource ^String href]
;; See DefaultConcordionRunner.findTestClass
(let [base-name (-> resource
(.getParent)
(.getRelativeResource href)
(.getPath)
(.replaceFirst "/" "")
(.replace "/" ".")
(drop-file-suffix))
variants (map
#(str base-name %)
[nil "Test" "Fixture"])]
(some
#(try
(Class/forName %)
(catch ClassNotFoundException _ nil))
variants)))
(defrecord ClojureTestRunner []
org.concordion.api.Runner
;; ResultSummary execute(Resource resource, String href) throws Exception;
(execute [_ resource href]
(run-fixture
(.newInstance (find-fixture-class resource href))
;; Concordion runs before/after suite only for top pages, not those referenced via concordion:run
false)))
(defn- deffixture*
[name methods]
{:pre [(or (symbol? name) (string? name))
(sequential? methods)
(every? var? methods)]}
(let [class-name (clojure.core/name name)
prefix (str (.replaceAll class-name "\\." "-") "-")
methods* (->> methods
(map var->method-descr)
(mapv (juxt :namesym :args :ret)))
;; implementation functions for the methods:
defns (map
(partial ->defn prefix)
methods)]
`(do
~@defns
(gen-class
:name ~class-name
:methods ~methods*
:prefix ~prefix)
(test/deftest ~(symbol (str prefix "test"))
(run-fixture (new ~(symbol class-name)) true)))))
(defmacro deffixture
"Create a fixture object for a Concordion specification, exposing the functions used in the spec.,
and a clojure.test test to execute the specification.
Params:
- name - a package-prefixed name of the generated fixture class, optionally ending in Fixture (symbol or string)
The name is also used to find the specification .md/.html file.
- methods - a vector of 1+ functions that will be exposed as methods on the fixture object
The function parameters and return value may be type-hinted as ^int or ^bool,
the default being String (the only 3 types supported by Concordion).
Example:
Given the spec math/Addition.md with 'yields [4](- \"?=add(#n1, #n2)\")'
Implement `(defn ^int add [^int n1, ^int n2] (+ n1 n2)` and expose it to the spec.:
`(deffixture math.AdditionFixture [add])`"
[name methods]
(deffixture* name (map resolve methods)))
(do
;; Set our runner (for the "concordion:run" command) as the default runner:
(System/setProperty "concordion.runner.concordion" (.getName ClojureTestRunner)))