;; test-doc-block will generate an assertion to verify (+ 1 2 3) evaluates to the expected 6
user=> (+ 1 2 3)
6
Test-doc-blocks will find Clojure source code blocks in your documents and generate tests for them.
A test is generated for each Clojure code block.
Any code block with with a (case insenstive) language of clj
cljs
cljc
or starting with Clojure
is recognized as a Clojure code block.
Assertions are automatically generated for:
REPL session style prompts :
;; test-doc-block will generate an assertion to verify (+ 1 2 3) evaluates to the expected 6
user=> (+ 1 2 3)
6
Editor style eval to comment, with some extras:
;; test-doc-blocks will generate an assertion to verify (+ 1 2 3 4) evaluates to the expected 10
(+ 1 2 3 4)
;; => 10
;; it understands that Clojure and ClojureScript can evaluate differently
\C
;; =clj=> \C
;; =cljs=> "C"
;; and verifies, when asked, to check what was written to stdout
(println "hey there!")
;; stdout=> hey there!
;; multiple stdout lines can be verified like so (notice the use single of ;):
(println "is this right?\nor not?")
;; =stdout=>
; is this right?
; or not?
Sometimes we might care about evaluated result, stderr and stdout.
;; A snippit of Clojure where we check result, stderr and stdout
(do
(println "To out I go")
(binding [*out* *err*] (println "To err is human"))
(* 9 9))
;; => 81
;; =stderr=> To err is human
;; =stdout=> To out I go
;; And the same idea for ClojureScript
(do
(println "To out I go")
(binding [*print-fn* *print-err-fn*] (println "To err is human"))
(* 9 9))
;; => 81
;; =stderr=> To err is human
;; =stdout=> To out I go
Test-doc-blocks will plunk your code blocks into a test even when there are no REPL assertions found. It is sometimes just nice to know that your code snippit will run without exception.
(->> "here we are only checking that our code will run"
reverse
reverse
(apply str))
You can, to some limited extent, communicate your intent to test-doc-blocks.
Test-doc-blocks will look for AsciiDoc comments that begin with :test-doc-blocks
.
It currently understands four options:
:test-doc-blocks/apply
- controls to what code blocks options are applied
:test-doc-blocks/skip
- skips the next code block
:test-doc-blocks/reader-cond
- wraps your code block in a reader conditional
:test-doc-blocks/test-ns
- specifies the test namespace
:test-doc-blocks/platform
- specifies Clojure file type to generate for test ns
:test-doc-blocks/meta
- attach metadata to generated tests
By default, new options are applied to the next Clojure code block only.
You can change this by including the :test-doc-blocks/apply
option:
:next
- default - applies new options to next Clojure code block only
:all-next
- applies new options to all subsequent code blocks in the document until specifically overridden with new opts
By default test-doc-blocks will create tests for all Clojure code blocks it finds.
Tell test-doc-blocks to skip the next Clojure code block via the following AsciiDoc comment:
//:test-doc-blocks/skip
[source,clojure]
----
;; no tests will be generated for this code Clojure code block
(something we don't want to test)
----
A cljc library might want to explain ClojureScript vs Clojure usage without using reader conditionals in the code block.
To wrap the generated test for your code block in a reader conditional use the :test-doc-blocks/reader-conditional
inline option.
This can be especially handy to show differences in (requires …)
for clj and cljs in separate code blocks.
Here’s a somewhat contrived example.
Clojure specific code:
//#:test-doc-blocks {:reader-cond :clj}
[source,clojure]
----
;; This code block will be wrapped in a #?(:clj (do ...))
(require '[clojure.edn :refer [read-string]])
----
ClojureScript specific code:
//#:test-doc-blocks {:reader-cond :cljs}
[source,clojure]
----
;; This code block will be wrapped in a #?(:cljs (do ...))
(require '[cljs.reader :refer [read-string]])
----
Later in doc, cross-platform cljc code that relies on the above:
[source,clojure]
----
;; And our generic cljc code:
(read-string "[1 2 3]")
=> [1 2 3]
----
No special checking is done; but :reader-cond
only makes sense for :cljc
platform code blocks and when your code block contains no reader conditionals.
If you don’t tell test-doc-blocks what namespace you want tests in, it will come up with one based on the document filename.
For this file, test-doc-blocks, up to this point, has been generating tests to example-adoc-test
.
If this does not work for you, you can override this default in via an AsciiDoc comment:
//{:test-doc-blocks/test-ns example-adoc-new-ns-test}
[source,clojure]
----
;; this code block will generate tests under example-adoc-new-ns-test
user=> (* 2 4)
8
----
Do what you like, but test runners usually look for tests namespaces ending in -test .
|
Changing the test-ns is useful for code blocks that need to be isolated.
//{:test-doc-blocks/test-ns example-adoc-new-ns.ns1-test}
[source,clojure]
----
;; this code block will generate tests under example-adoc-new-ns.ns1-test
(require '[clojure.string :as string])
(string/join ", " [1 2 3])
=> "1, 2, 3"
----
By default, test-doc-blocks generates .cljc
tests.
You can override this default on the command line via :platform
and via inline option via :test-doc-blocks/platform
.
Valid values are:
:cljc
- the default - generates .cljc
test files
:clj
- generates .clj
test files
:cljs
- generates .cljs
test files
When specifying the platform, remember that:
For Clojure my-ns-file.clj
will be picked over my-ns-file.cljc
For ClojureScript my-ns-file.cljs
will be picked over my-ns-file.cljc
So if you are generating mixed platforms, you might want to specify the test-ns as well.
//#:test-doc-blocks{:platform :cljs :test-ns example-adoc-cljs-test}
[source,clojure]
----
;; this code block will generate a test under example-adoc-cljs-test ns to a .cljs file
(import '[goog.events EventType])
EventType.CLICK
;;=> "click"
(require '[goog.math :as math])
(math/clamp -1 0 5)
;;=> 0
----
Test runners support including and excluding tests based on truthy metadata.
You can attach metadata to generated tests via the :test-doc-blocks/meta
option.
A new :test-doc-blocks/meta
will override any and all previous meta values.
We offer two syntaxes:
:test-doc-blocks-meta :my-kw
generates {:my-kw true}
metadata.
:test-doc-blocks-meta {:my-kw1 my-value1 :my-kw2 my-value2}
the explicit option for those that need it
Example code blocks:
//#:test-doc-blocks{:meta :testing-meta123}
[source,clojure]
----
;; this code block will generate a test with metadata {:testing-meta123 true}
user=> (into [] {:a 1})
[[:a 1]]
----
//#:test-doc-blocks{:meta {:testing-meta123 "a-specific-value" :testing-meta789 :yip}}
[source,clojure]
----
;; this code block will generate a test with metadata:
;; {:testing-meta123 "a-specific-value" :testing-meta789 :yip}
(reduce
(fn [acc n]
(str acc "!" n))
""
["oh" "my" "goodness"])
;; => "!oh!my!goodness"
----
Test-doc-blocks will try to give each test block some context by including its filename, section title and starting line number.
It recognizes that AsciiDoc recognizes CommonMark style single line headers.
## this type of md header
I think there is also support for 2 line headers but the rules might be a differ a bit from CommonMark. As 2 line CommonMark headers in a AsciiDoc file should be rare, we’ll not try to parse these variants in AsciiDoc docs for now:
And this level 1 type
=====================
And this level 2 type
---------------------
This code block should be include "Section Titles" as part of the context for its generated test.
```Clojure
(require '[clojure.string :as string])
(string/join "!" ["well" "how" "about" "that"])
;; => "well!how!about!that"
```
Did you know AsciiDoc supports CommonMark syntax for section headings and code blocks?
Well it does! And test-doc-blocks recognizes this fact.
```Clojure
(require '[clojure.set :as set])
(set/map-invert {:a 1 :b 2})
;; => {1 :a, 2 :b}
```
It is common for REPL style code block examples to include inline requires and imports.
Test-doc-blocks will make an honest attempt to lift these inline requires up into the ns declaration of the generated test. This allows the generated tests to be run by ClojureScript which only supports inline requires in the REPL.
Test-doc-blocks should be able to handle common import and require formats. If we’ve missed one, let us know.
;; Stick the basics for requires, shorthand notation isn't supported
;; Some examples:
(require '[clojure.string :as string])
(require '[clojure.string])
(require 'clojure.string)
(require '[clojure.string :as string] '[clojure.set :as cset])
;; For cljc code examples it is fine for your requires and imports to contain, or be wrapped by, reader conditionals
;; Some examples of supported imports
#?@(:clj [(import 'java.util.List)
(import '[java.util List Queue Set])]
:cljs [(import 'goog.math.Long '[goog.math Vec2 Vec3])])
In the general case, running tests in no specific or random order is a good thing. In the case of test-doc-blocks, this might not be what you want.
If your code blocks are self-contained examples, then test run order won’t be an issue for you. If your separate code blocks represent a larger flow, then order is important.
If we start in one code block…
(def var-block1 (+ 1 2 3))
…and continue in another:
(def var-block2 (+ 4 5 6))
(+ var-block1 var-block2)
;; => 21
…and then maybe another:
(+ var-block1 var-block2 79)
;; => 100
... then run order is important to your generated tests.
Test-doc-blocks makes use of test-ns-hook
in generated tests to specify the run order be the same as the doc blocks order in your documents.
Kaocha does not support test-ns-hook
.
It will by default randomize the order of tests for each test run.
For Kaocha, randomization can be disabled from the command line via --no-randomize
or in its tests.edn
via :randomize? false
.
The REPL makes use of pr
to output what it has evaluated.
The pr
docstring states:
By default, pr and prn print in a way that objects can be read by the reader
Some libraries break this contract.
For example, rewrite-clj overrides pr
to display output for its nodes that is easily digestable by humans, but not at all digestable by Clojure.
If pr
has been overriden for your library, you have choices for test-doc-blocks:
Skip the block (see inline options)
Avoid REPL assertions that effect the overriden pr
Have your code blocks include call pr
on affected evaluations and use =stdout⇒
to compare for expected output.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close