From c0588be686bca16d651c2a3312fb9e6aee80c869 Mon Sep 17 00:00:00 2001
From: Gabriel Horner
Date: Thu, 23 Dec 2021 00:28:56 -0500
Subject: [PATCH] Add tests for markdown-clj and tools.namespace
See comment for why only one markdown test could be run.
Closes #1069 and #1064
---
deps.edn | 4 +-
doc/projects.md | 5 +
test-resources/lib_tests/bb-tested-libs.edn | 6 +-
.../tools/namespace/dependency_test.clj | 315 ++++++++++++
.../clojure/tools/namespace/dir_test.clj | 20 +
.../clojure/tools/namespace/find_test.clj | 29 ++
.../clojure/tools/namespace/move_test.clj | 52 ++
.../clojure/tools/namespace/parse_test.clj | 210 ++++++++
.../clojure/tools/namespace/test_helpers.clj | 82 ++++
.../lib_tests/markdown/md_test.cljc | 450 ++++++++++++++++++
.../lib_tests/markdown/nbb_runner.cljs | 10 +
test-resources/lib_tests/markdown/runner.cljs | 5 +
12 files changed, 1186 insertions(+), 2 deletions(-)
create mode 100644 test-resources/lib_tests/clojure/tools/namespace/dependency_test.clj
create mode 100644 test-resources/lib_tests/clojure/tools/namespace/dir_test.clj
create mode 100644 test-resources/lib_tests/clojure/tools/namespace/find_test.clj
create mode 100644 test-resources/lib_tests/clojure/tools/namespace/move_test.clj
create mode 100644 test-resources/lib_tests/clojure/tools/namespace/parse_test.clj
create mode 100644 test-resources/lib_tests/clojure/tools/namespace/test_helpers.clj
create mode 100644 test-resources/lib_tests/markdown/md_test.cljc
create mode 100644 test-resources/lib_tests/markdown/nbb_runner.cljs
create mode 100644 test-resources/lib_tests/markdown/runner.cljs
diff --git a/deps.edn b/deps.edn
index d45a9704..bac671ac 100644
--- a/deps.edn
+++ b/deps.edn
@@ -104,7 +104,9 @@
listora/again {:mvn/version "1.0.0"}
org.clojure/tools.gitlibs {:mvn/version "2.4.172"}
environ/environ {:mvn/version "1.2.0"}
- table/table {:git/url "https://github.com/cldwalker/table", :sha "55aef3d5fced682942af811bf5d642f79fb87688"}}
+ table/table {:git/url "https://github.com/cldwalker/table", :sha "55aef3d5fced682942af811bf5d642f79fb87688"}
+ markdown-clj/markdown-clj {:mvn/version "1.10.8"}
+ org.clojure/tools.namespace {:git/url "https://github.com/babashka/tools.namespace", :sha "a13b037215e21a2e71aa34b27e1dd52c801a2a7b"}}
:classpath-overrides {org.clojure/clojure nil
org.clojure/spec.alpha nil}}
:clj-nvd
diff --git a/doc/projects.md b/doc/projects.md
index 0a55b0b1..2fc9b06e 100644
--- a/doc/projects.md
+++ b/doc/projects.md
@@ -56,6 +56,7 @@ The following libraries and projects are known to work with babashka.
- [contajners](#contajners)
- [dependency](#dependency)
- [specmonstah](#specmonstah)
+ - [markdown-clj](#markdown-clj)
- [Pods](#pods)
- [Projects](#projects-1)
- [babashka-test-action](#babashka-test-action)
@@ -792,6 +793,10 @@ Represent dependency graphs as a directed acylic graph.
Write concise, maintainable test fixtures with clojure.spec.alpha.
+### [markdown-clj](https://github.com/yogthos/markdown-clj)
+
+Markdown parser that translates markdown to html.
+
## Pods
[Babashka pods](https://github.com/babashka/babashka.pods) are programs that can
diff --git a/test-resources/lib_tests/bb-tested-libs.edn b/test-resources/lib_tests/bb-tested-libs.edn
index cbc276be..5d77fd29 100644
--- a/test-resources/lib_tests/bb-tested-libs.edn
+++ b/test-resources/lib_tests/bb-tested-libs.edn
@@ -16,4 +16,8 @@
org.clojars.askonomm/ruuter {:git-sha "78659212f95cac827efc816dfbdab8181c25fc3d", :git-url "https://github.com/askonomm/ruuter", :test-namespaces (ruuter.core-test)}
;; clojure.data.json-gen-test ommitted from test-namespaces b/c it hangs on stest/check
org.clojure/data.json {:git-sha "9f1c9ccf3fd3e5a39cfb7289d3d456e842ddf442", :git-url "https://github.com/clojure/data.json", :test-namespaces (clojure.data.json-test clojure.data.json-test-suite-test clojure.data.json-compat-0-1-test)}
- io.replikativ/hasch {:git-sha "04d9c0bd34d86bad79502d8a6963eb2525a22b15", :git-url "https://github.com/replikativ/hasch", :test-namespaces (hasch.test)}}
+ io.replikativ/hasch {:git-sha "04d9c0bd34d86bad79502d8a6963eb2525a22b15", :git-url "https://github.com/replikativ/hasch", :test-namespaces (hasch.test)}
+ ;; BB-TEST-PATCH: Removed markdown.md-file-test b/c tests hardcode path to test
+ ;; files. Removed markdown.benchmark b/c it depends on criterium which isn't bb compatible
+ markdown-clj/markdown-clj {:git-sha "ac245d3049afa25a6d41fcb5ba5a268f52c610e4", :git-url "https://github.com/yogthos/markdown-clj", :test-namespaces (markdown.md-test)}
+ org.clojure/tools.namespace {:git-sha "a13b037215e21a2e71aa34b27e1dd52c801a2a7b", :git-url "https://github.com/babashka/tools.namespace", :test-namespaces (clojure.tools.namespace.test-helpers clojure.tools.namespace.dependency-test clojure.tools.namespace.find-test clojure.tools.namespace.move-test clojure.tools.namespace.parse-test clojure.tools.namespace.dir-test), :branch "babashka"}}
diff --git a/test-resources/lib_tests/clojure/tools/namespace/dependency_test.clj b/test-resources/lib_tests/clojure/tools/namespace/dependency_test.clj
new file mode 100644
index 00000000..5aedb27f
--- /dev/null
+++ b/test-resources/lib_tests/clojure/tools/namespace/dependency_test.clj
@@ -0,0 +1,315 @@
+(ns clojure.tools.namespace.dependency-test
+ (:use clojure.test
+ clojure.tools.namespace.dependency))
+
+;; building a graph like:
+;;
+;; :a
+;; / |
+;; :b |
+;; \ |
+;; :c
+;; |
+;; :d
+;;
+(def g1 (-> (graph)
+ (depend :b :a) ; "B depends on A"
+ (depend :c :b) ; "C depends on B"
+ (depend :c :a) ; "C depends on A"
+ (depend :d :c))) ; "D depends on C"
+
+;; 'one 'five
+;; | |
+;; 'two |
+;; / \ |
+;; / \ |
+;; / \ /
+;; 'three 'four
+;; | /
+;; 'six /
+;; | /
+;; | /
+;; | /
+;; 'seven
+;;
+(def g2 (-> (graph)
+ (depend 'two 'one)
+ (depend 'three 'two)
+ (depend 'four 'two)
+ (depend 'four 'five)
+ (depend 'six 'three)
+ (depend 'seven 'six)
+ (depend 'seven 'four)))
+
+;; :level0
+;; / | | \
+;; ----- | | -----
+;; / | | \
+;; :level1a :level1b :level1c :level1d
+;; \ | | /
+;; ----- | | -----
+;; \ | | /
+;; :level2
+;; / | | \
+;; ----- | | -----
+;; / | | \
+;; :level3a :level3b :level3c :level3d
+;; \ | | /
+;; ----- | | -----
+;; \ | | /
+;; :level4
+;;
+;; ... and so on in a repeating pattern like that, up to :level26
+
+(def g3 (-> (graph)
+ (depend :level1a :level0)
+ (depend :level1b :level0)
+ (depend :level1c :level0)
+ (depend :level1d :level0)
+ (depend :level2 :level1a)
+ (depend :level2 :level1b)
+ (depend :level2 :level1c)
+ (depend :level2 :level1d)
+
+ (depend :level3a :level2)
+ (depend :level3b :level2)
+ (depend :level3c :level2)
+ (depend :level3d :level2)
+ (depend :level4 :level3a)
+ (depend :level4 :level3b)
+ (depend :level4 :level3c)
+ (depend :level4 :level3d)
+
+ (depend :level5a :level4)
+ (depend :level5b :level4)
+ (depend :level5c :level4)
+ (depend :level5d :level4)
+ (depend :level6 :level5a)
+ (depend :level6 :level5b)
+ (depend :level6 :level5c)
+ (depend :level6 :level5d)
+
+ (depend :level7a :level6)
+ (depend :level7b :level6)
+ (depend :level7c :level6)
+ (depend :level7d :level6)
+ (depend :level8 :level7a)
+ (depend :level8 :level7b)
+ (depend :level8 :level7c)
+ (depend :level8 :level7d)
+
+ (depend :level9a :level8)
+ (depend :level9b :level8)
+ (depend :level9c :level8)
+ (depend :level9d :level8)
+ (depend :level10 :level9a)
+ (depend :level10 :level9b)
+ (depend :level10 :level9c)
+ (depend :level10 :level9d)
+
+ (depend :level11a :level10)
+ (depend :level11b :level10)
+ (depend :level11c :level10)
+ (depend :level11d :level10)
+ (depend :level12 :level11a)
+ (depend :level12 :level11b)
+ (depend :level12 :level11c)
+ (depend :level12 :level11d)
+
+ (depend :level13a :level12)
+ (depend :level13b :level12)
+ (depend :level13c :level12)
+ (depend :level13d :level12)
+ (depend :level14 :level13a)
+ (depend :level14 :level13b)
+ (depend :level14 :level13c)
+ (depend :level14 :level13d)
+
+ (depend :level15a :level14)
+ (depend :level15b :level14)
+ (depend :level15c :level14)
+ (depend :level15d :level14)
+ (depend :level16 :level15a)
+ (depend :level16 :level15b)
+ (depend :level16 :level15c)
+ (depend :level16 :level15d)
+
+ (depend :level17a :level16)
+ (depend :level17b :level16)
+ (depend :level17c :level16)
+ (depend :level17d :level16)
+ (depend :level18 :level17a)
+ (depend :level18 :level17b)
+ (depend :level18 :level17c)
+ (depend :level18 :level17d)
+
+ (depend :level19a :level18)
+ (depend :level19b :level18)
+ (depend :level19c :level18)
+ (depend :level19d :level18)
+ (depend :level20 :level19a)
+ (depend :level20 :level19b)
+ (depend :level20 :level19c)
+ (depend :level20 :level19d)
+
+ (depend :level21a :level20)
+ (depend :level21b :level20)
+ (depend :level21c :level20)
+ (depend :level21d :level20)
+ (depend :level22 :level21a)
+ (depend :level22 :level21b)
+ (depend :level22 :level21c)
+ (depend :level22 :level21d)
+
+ (depend :level23a :level22)
+ (depend :level23b :level22)
+ (depend :level23c :level22)
+ (depend :level23d :level22)
+ (depend :level24 :level23a)
+ (depend :level24 :level23b)
+ (depend :level24 :level23c)
+ (depend :level24 :level23d)
+
+ (depend :level25a :level24)
+ (depend :level25b :level24)
+ (depend :level25c :level24)
+ (depend :level25d :level24)
+ (depend :level26 :level25a)
+ (depend :level26 :level25b)
+ (depend :level26 :level25c)
+ (depend :level26 :level25d)))
+
+(deftest t-transitive-dependencies
+ (is (= #{:a :c :b}
+ (transitive-dependencies g1 :d)))
+ (is (= '#{two four six one five three}
+ (transitive-dependencies g2 'seven))))
+
+(deftest t-transitive-dependencies-deep
+ (is (= #{:level0
+ :level1a :level1b :level1c :level1d
+ :level2
+ :level3a :level3b :level3c :level3d
+ :level4
+ :level5a :level5b :level5c :level5d
+ :level6
+ :level7a :level7b :level7c :level7d
+ :level8
+ :level9a :level9b :level9c :level9d
+ :level10
+ :level11a :level11b :level11c :level11d
+ :level12
+ :level13a :level13b :level13c :level13d
+ :level14
+ :level15a :level15b :level15c :level15d
+ :level16
+ :level17a :level17b :level17c :level17d
+ :level18
+ :level19a :level19b :level19c :level19d
+ :level20
+ :level21a :level21b :level21c :level21d
+ :level22
+ :level23a :level23b :level23c :level23d}
+ (transitive-dependencies g3 :level24)))
+ (is (= #{:level0
+ :level1a :level1b :level1c :level1d
+ :level2
+ :level3a :level3b :level3c :level3d
+ :level4
+ :level5a :level5b :level5c :level5d
+ :level6
+ :level7a :level7b :level7c :level7d
+ :level8
+ :level9a :level9b :level9c :level9d
+ :level10
+ :level11a :level11b :level11c :level11d
+ :level12
+ :level13a :level13b :level13c :level13d
+ :level14
+ :level15a :level15b :level15c :level15d
+ :level16
+ :level17a :level17b :level17c :level17d
+ :level18
+ :level19a :level19b :level19c :level19d
+ :level20
+ :level21a :level21b :level21c :level21d
+ :level22
+ :level23a :level23b :level23c :level23d
+ :level24
+ :level25a :level25b :level25c :level25d}
+ (transitive-dependencies g3 :level26))))
+
+
+(deftest t-transitive-dependents
+ (is (= '#{four seven}
+ (transitive-dependents g2 'five)))
+ (is (= '#{four seven six three}
+ (transitive-dependents g2 'two))))
+
+(defn- before?
+ "True if x comes before y in an ordered collection."
+ [coll x y]
+ (loop [[item & more] (seq coll)]
+ (cond (nil? item) true ; end of the seq
+ (= x item) true ; x comes first
+ (= y item) false
+ :else (recur more))))
+
+(deftest t-before
+ (is (true? (before? [:a :b :c :d] :a :b)))
+ (is (true? (before? [:a :b :c :d] :b :c)))
+ (is (false? (before? [:a :b :c :d] :d :c)))
+ (is (false? (before? [:a :b :c :d] :c :a))))
+
+(deftest t-topo-comparator-1
+ (let [sorted (sort (topo-comparator g1) [:d :a :b :foo])]
+ (are [x y] (before? sorted x y)
+ :a :b
+ :a :d
+ :a :foo
+ :b :d
+ :b :foo
+ :d :foo)))
+
+(deftest t-topo-comparator-2
+ (let [sorted (sort (topo-comparator g2) '[three seven nine eight five])]
+ (are [x y] (before? sorted x y)
+ 'three 'seven
+ 'three 'eight
+ 'three 'nine
+ 'five 'eight
+ 'five 'nine
+ 'seven 'eight
+ 'seven 'nine)))
+
+(deftest t-topo-sort
+ (let [sorted (topo-sort g2)]
+ (are [x y] (before? sorted x y)
+ 'one 'two
+ 'one 'three
+ 'one 'four
+ 'one 'six
+ 'one 'seven
+ 'two 'three
+ 'two 'four
+ 'two 'six
+ 'two 'seven
+ 'three 'six
+ 'three 'seven
+ 'four 'seven
+ 'five 'four
+ 'five 'seven
+ 'six 'seven)))
+
+(deftest t-no-cycles
+ (is (thrown? Exception
+ (-> (graph)
+ (depend :a :b)
+ (depend :b :c)
+ (depend :c :a)))))
+
+(deftest t-no-self-cycles
+ (is (thrown? Exception
+ (-> (graph)
+ (depend :a :b)
+ (depend :a :a)))))
diff --git a/test-resources/lib_tests/clojure/tools/namespace/dir_test.clj b/test-resources/lib_tests/clojure/tools/namespace/dir_test.clj
new file mode 100644
index 00000000..60e56427
--- /dev/null
+++ b/test-resources/lib_tests/clojure/tools/namespace/dir_test.clj
@@ -0,0 +1,20 @@
+(ns clojure.tools.namespace.dir-test
+ (:require [clojure.test :refer [deftest is]]
+ [clojure.tools.namespace.test-helpers :as help]
+ [clojure.tools.namespace.dir :as dir])
+ (:import
+ (java.io File)))
+
+;; Only run this test on Java 1.7+, where java.nio.file.Files is available.
+(when (try (Class/forName "java.nio.file.Files")
+ (catch ClassNotFoundException _ false))
+ (deftest t-scan-by-canonical-path
+ (let [dir (help/create-temp-dir "t-scan-by-canonical-path")
+ main-clj (help/create-source dir 'example.main :clj '[example.one])
+ one-cljc (help/create-source dir 'example.one :clj)
+ other-dir (help/create-temp-dir "t-scan-by-canonical-path-other")
+ link (File. other-dir "link")]
+ (java.nio.file.Files/createSymbolicLink (.toPath link) (.toPath dir)
+ (make-array java.nio.file.attribute.FileAttribute 0))
+ (is (= (::dir/files (dir/scan-dirs {} [dir]))
+ (::dir/files (dir/scan-dirs {} [link])))))))
diff --git a/test-resources/lib_tests/clojure/tools/namespace/find_test.clj b/test-resources/lib_tests/clojure/tools/namespace/find_test.clj
new file mode 100644
index 00000000..d081e84a
--- /dev/null
+++ b/test-resources/lib_tests/clojure/tools/namespace/find_test.clj
@@ -0,0 +1,29 @@
+(ns clojure.tools.namespace.find-test
+ (:require [clojure.test :refer [deftest is]]
+ [clojure.tools.namespace.test-helpers :as help]
+ [clojure.tools.namespace.find :as find])
+ (:import (java.io File)))
+
+(deftest t-find-clj-and-cljc-files
+ "main.clj depends on one.cljc which depends on two.clj.
+ two.cljs also exists but should not be returned"
+ (let [dir (help/create-temp-dir "t-find-clj-and-cljc-files")
+ main-clj (help/create-source dir 'example.main :clj '[example.one])
+ one-cljc (help/create-source dir 'example.one :cljc '[example.two])
+ two-clj (help/create-source dir 'example.two :clj)
+ two-cljs (help/create-source dir 'example.two :cljs)]
+ (is (help/same-files?
+ [main-clj one-cljc two-clj]
+ (find/find-sources-in-dir dir)))))
+
+(deftest t-find-cljs-and-cljc-files
+ "main.cljs depends on one.cljc which depends on two.cljs.
+ two.clj also exists but should not be returned"
+ (let [dir (help/create-temp-dir "t-find-cljs-and-cljc-files")
+ main-cljs (help/create-source dir 'example.main :cljs '[example.one])
+ one-cljc (help/create-source dir 'example.one :cljc '[example.two])
+ two-clj (help/create-source dir 'example.two :clj)
+ two-cljs (help/create-source dir 'example.two :cljs)]
+ (is (help/same-files?
+ [main-cljs one-cljc two-cljs]
+ (find/find-sources-in-dir dir find/cljs)))))
diff --git a/test-resources/lib_tests/clojure/tools/namespace/move_test.clj b/test-resources/lib_tests/clojure/tools/namespace/move_test.clj
new file mode 100644
index 00000000..47de7ac4
--- /dev/null
+++ b/test-resources/lib_tests/clojure/tools/namespace/move_test.clj
@@ -0,0 +1,52 @@
+(ns clojure.tools.namespace.move-test
+ (:require [clojure.java.io :as io]
+ [clojure.test :refer [deftest is]]
+ [clojure.tools.namespace.move :refer [move-ns]]
+ [clojure.tools.namespace.test-helpers :as help])
+ (:import (java.io File)))
+
+(defn- create-file-one [dir]
+ (help/create-source dir 'example.one :clj
+ '[example.two example.three]
+ '[(defn foo []
+ (example.a.four/foo))]))
+
+(defn- create-file-two [dir]
+ (help/create-source dir 'example.two :clj
+ '[example.three example.a.four]))
+
+(defn- create-file-three [dir]
+ (help/create-source dir 'example.three :clj
+ '[example.five]))
+
+(defn- create-file-four [dir]
+ (help/create-source dir 'example.a.four :clj))
+
+(deftest t-move-ns
+ (let [temp-dir (help/create-temp-dir "tools-namespace-t-move-ns")
+ src-dir (io/file temp-dir "src")
+ example-dir (io/file temp-dir "src" "example")
+ file-one (create-file-one src-dir)
+ file-two (create-file-two src-dir)
+ file-three (create-file-three src-dir)
+ old-file-four (create-file-four src-dir)
+ new-file-four (io/file example-dir "b" "four.clj")]
+
+ (let [file-three-last-modified (.lastModified file-three)]
+
+ (Thread/sleep 1500) ;; ensure file timestamps are different
+
+ (move-ns 'example.a.four 'example.b.four src-dir [src-dir])
+
+ (is (.exists new-file-four)
+ "new file should exist")
+ (is (not (.exists old-file-four))
+ "old file should not exist")
+ (is (not (.exists (.getParentFile old-file-four)))
+ "old empty directory should not exist")
+ (is (= file-three-last-modified (.lastModified file-three))
+ "unaffected file should not have been modified")
+ (is (not-any? #(.contains (slurp %) "example.a.four")
+ [file-one file-two file-three new-file-four]))
+ (is (every? #(.contains (slurp %) "example.b.four")
+ [file-one file-two new-file-four])))))
diff --git a/test-resources/lib_tests/clojure/tools/namespace/parse_test.clj b/test-resources/lib_tests/clojure/tools/namespace/parse_test.clj
new file mode 100644
index 00000000..b6ac6aaa
--- /dev/null
+++ b/test-resources/lib_tests/clojure/tools/namespace/parse_test.clj
@@ -0,0 +1,210 @@
+(ns clojure.tools.namespace.parse-test
+ (:use [clojure.test :only (deftest is)]
+ [clojure.tools.namespace.parse :only (deps-from-ns-decl
+ read-ns-decl)]))
+
+(def ns-decl-prefix-list
+ '(ns com.example.one
+ (:require (com.example two
+ [three :as three]
+ [four :refer (a b)])
+ (com.example.sub [five :as five]
+ six))
+ (:use (com.example seven
+ [eight :as eight]
+ (nine :only (c d))
+ [ten]))))
+
+;; Some people like to write prefix lists as vectors, not lists. The
+;; use/require functions accept this form.
+(def ns-decl-prefix-list-as-vector
+ '(ns com.example.one
+ (:require [com.example
+ two
+ [three :as three]
+ [four :refer (a b)]]
+ [com.example.sub
+ [five :as five]
+ six])
+ (:use [com.example
+ seven
+ [eight :as eight]
+ (nine :only (c d))
+ [ten]])))
+
+(def ns-decl-prefix-list-clauses-as-vectors
+ "Sometimes people even write the clauses inside ns as vectors, which
+ clojure.core/ns allows. See TNS-21."
+ '(ns com.example.one
+ [:require [com.example
+ two
+ [three :as three]
+ [four :refer (a b)]]
+ [com.example.sub
+ [five :as five]
+ six]]
+ [:use [com.example
+ seven
+ [eight :as eight]
+ (nine :only (c d))
+ [ten]]]))
+
+(def deps-from-prefix-list
+ '#{com.example.two
+ com.example.three
+ com.example.four
+ com.example.sub.five
+ com.example.sub.six
+ com.example.seven
+ com.example.eight
+ com.example.nine
+ com.example.ten})
+
+(deftest t-prefix-list
+ (is (= deps-from-prefix-list
+ (deps-from-ns-decl ns-decl-prefix-list))))
+
+(deftest t-prefix-list-as-vector
+ (is (= deps-from-prefix-list
+ (deps-from-ns-decl ns-decl-prefix-list-as-vector))))
+
+(deftest t-prefix-list-clauses-as-vectors
+ (is (= deps-from-prefix-list
+ (deps-from-ns-decl ns-decl-prefix-list-clauses-as-vectors))))
+
+(deftest t-no-deps-returns-empty-set
+ (is (= #{} (deps-from-ns-decl '(ns com.example.one)))))
+
+(def multiple-ns-decls
+ '((ns one)
+ (ns two (:require one))
+ (ns three (:require [one :as o] [two :as t]))))
+
+(def multiple-ns-decls-string
+" (println \"Code before first ns\")
+ (ns one)
+ (println \"Some code\")
+ (defn hello-world [] \"Hello, World!\")
+ (ns two (:require one))
+ (println \"Some more code\")
+ (ns three (:require [one :as o] [two :as t]))")
+
+(deftest t-read-multiple-ns-decls
+ (with-open [rdr (clojure.lang.LineNumberingPushbackReader.
+ (java.io.PushbackReader.
+ (java.io.StringReader. multiple-ns-decls-string)))]
+ (is (= multiple-ns-decls
+ (take-while identity (repeatedly #(read-ns-decl rdr)))))))
+
+(def ns-docstring-example
+ "The example ns declaration used in the docstring of clojure.core/ns"
+ '(ns foo.bar
+ (:refer-clojure :exclude [ancestors printf])
+ (:require (clojure.contrib sql combinatorics))
+ (:use (my.lib this that))
+ (:import (java.util Date Timer Random)
+ (java.sql Connection Statement))))
+
+(def deps-from-ns-docstring-example
+ '#{clojure.contrib.sql
+ clojure.contrib.combinatorics
+ my.lib.this
+ my.lib.that})
+
+(deftest t-ns-docstring-example
+ (is (= deps-from-ns-docstring-example
+ (deps-from-ns-decl ns-docstring-example))))
+
+(def require-docstring-example
+ "The example ns declaration used in the docstring of
+ clojure.core/require"
+ '(ns (:require (clojure zip [set :as s]))))
+
+(def deps-from-require-docstring-example
+ '#{clojure.zip
+ clojure.set})
+
+(deftest t-require-docstring-example
+ (is (= deps-from-require-docstring-example
+ (deps-from-ns-decl require-docstring-example))))
+
+(def multiple-clauses
+ "Example showing more than one :require or :use clause in one ns
+ declaration, which clojure.core/ns allows."
+ '(ns foo.bar
+ (:require com.example.one)
+ (:import java.io.File)
+ (:require (com.example two three))
+ (:use (com.example [four :only [x]]))
+ (:use (com.example (five :only [x])))))
+
+(def deps-from-multiple-clauses
+ '#{com.example.one
+ com.example.two
+ com.example.three
+ com.example.four
+ com.example.five})
+
+(deftest t-deps-from-multiple-clauses
+ (is (= deps-from-multiple-clauses
+ (deps-from-ns-decl multiple-clauses))))
+
+(def clauses-without-keywords
+ "Example of require/use clauses with symbols instead of keywords,
+ which clojure.core/ns allows."
+ '(ns foo.bar
+ (require com.example.one)
+ (import java.io.File)
+ (use (com.example (prefixes (two :only [x])
+ three)))))
+
+(def deps-from-clauses-without-keywords
+ '#{com.example.one
+ com.example.prefixes.two
+ com.example.prefixes.three})
+
+(deftest t-clauses-without-keywords
+ (is (= deps-from-clauses-without-keywords
+ (deps-from-ns-decl clauses-without-keywords))))
+
+(def reader-conditionals-string
+ "(ns com.examples.one
+ (:require #?(:clj clojure.string
+ :cljs goog.string)))")
+
+(deftest t-reader-conditionals
+ ;; TODO: the predicate wasn't added to bb yet, will come in version after 0.6.7
+ (when true #_(resolve 'clojure.core/reader-conditional?)
+ (let [actual (-> reader-conditionals-string
+ java.io.StringReader.
+ java.io.PushbackReader.
+ clojure.lang.LineNumberingPushbackReader.
+ read-ns-decl
+ deps-from-ns-decl)]
+ (is (= #{'clojure.string} actual)))))
+
+(def ns-with-npm-dependency
+ "(ns com.examples.one
+ (:require [\"foobar\"] [baz]))")
+
+(deftest npm-dependency
+ (let [actual (-> ns-with-npm-dependency
+ java.io.StringReader.
+ java.io.PushbackReader.
+ clojure.lang.LineNumberingPushbackReader.
+ read-ns-decl
+ deps-from-ns-decl)]
+ (is (= #{'baz} actual))))
+
+(def ns-with-require-macros
+ "(ns com.examples.one
+ (:require-macros [foo :refer [bar]]))")
+
+(deftest require-macros
+ (let [actual (-> ns-with-require-macros
+ java.io.StringReader.
+ java.io.PushbackReader.
+ clojure.lang.LineNumberingPushbackReader.
+ read-ns-decl
+ deps-from-ns-decl)]
+ (is (= #{'foo} actual))))
diff --git a/test-resources/lib_tests/clojure/tools/namespace/test_helpers.clj b/test-resources/lib_tests/clojure/tools/namespace/test_helpers.clj
new file mode 100644
index 00000000..62679e69
--- /dev/null
+++ b/test-resources/lib_tests/clojure/tools/namespace/test_helpers.clj
@@ -0,0 +1,82 @@
+(ns clojure.tools.namespace.test-helpers
+ "Utilities to help with testing files and namespaces."
+ (:require [clojure.java.io :as io]
+ [clojure.string :as string])
+ (:import (java.io Closeable File Writer PrintWriter)))
+
+(defn create-temp-dir
+ "Creates and returns a new temporary directory java.io.File."
+ [name]
+ (let [temp-file (File/createTempFile name nil)]
+ (.delete temp-file)
+ (.mkdirs temp-file)
+ (println "Temporary directory" (.getAbsolutePath temp-file))
+ temp-file))
+
+(defn- write-contents
+ "Writes contents into writer. Strings are written as-is via println,
+ other types written as by prn."
+ [^Writer writer contents]
+ {:pre [(sequential? contents)]}
+ (binding [*out* (PrintWriter. writer)]
+ (doseq [content contents]
+ (if (string? content)
+ (println content)
+ (prn content))
+ (newline))))
+
+(defn create-file
+ "Creates a file from a vector of path elements. Writes contents into
+ the file. Elements of contents may be data, written via prn, or
+ strings, written directly."
+ [path contents]
+ {:pre [(vector? path)]}
+ (let [^File file (apply io/file path)]
+ (when-let [parent (.getParentFile file)]
+ (.mkdirs parent))
+ (with-open [wtr (io/writer file)]
+ (write-contents wtr contents))
+ file))
+
+(defn- sym->path
+ "Converts a symbol name into a vector of path parts, not including
+ file extension."
+ [symbol]
+ {:pre [(symbol? symbol)]
+ :post [(vector? %)]}
+ (-> (name symbol)
+ (string/replace \- \_)
+ (string/split #"\.")))
+
+(defn- source-path
+ "Returns a vector of path components for namespace named sym,
+ with given file extension (keyword)."
+ [sym extension]
+ (let [path (sym->path sym)
+ basename (peek path)
+ filename (str basename \. (name extension))]
+ (conj (pop path) filename)))
+
+(defn create-source
+ "Creates a file at the correct path under base-dir for a namespace
+ named sym, with file extension (keyword), containing a ns
+ declaration which :require's the dependencies (symbols). Optional
+ contents written after the ns declaration as by write-contents."
+ ([base-dir sym extension]
+ (create-source base-dir sym extension nil nil))
+ ([base-dir sym extension dependencies]
+ (create-source base-dir sym extension dependencies nil))
+ ([base-dir sym extension dependencies contents]
+ (let [full-path (into [base-dir] (source-path sym extension))
+ ns-decl (if (seq dependencies)
+ (list 'ns sym (list* :require dependencies))
+ (list 'ns sym))]
+ (create-file full-path (into [ns-decl] contents)))))
+
+(defn same-files?
+ "True if files-a and files-b contain the same canonical File's,
+ regardless of order."
+ [files-a files-b]
+ (= (sort (map #(.getCanonicalPath ^File %) files-a))
+ (sort (map #(.getCanonicalPath ^File %) files-b))))
+
diff --git a/test-resources/lib_tests/markdown/md_test.cljc b/test-resources/lib_tests/markdown/md_test.cljc
new file mode 100644
index 00000000..b2279d00
--- /dev/null
+++ b/test-resources/lib_tests/markdown/md_test.cljc
@@ -0,0 +1,450 @@
+(ns markdown.md-test
+ (:require #?(:cljs [goog.string])
+ [clojure.test :refer [deftest is]]
+ [markdown.core :as markdown]
+ [markdown.tables :as tables]))
+
+(def entry-function
+ #?(:clj markdown/md-to-html-string
+ :cljs markdown/md->html))
+
+(deftest heading1
+ (is (= "Ticket #123
" (entry-function "# Ticket #123")))
+ (is (= "Foo
" (entry-function " # Foo")))
+ (is (= "foo
" (entry-function "#foo")))
+ (is (= "foo
" (entry-function "foo\n===")))
+ (is (= "foo
" (entry-function "#foo#")))
+ (is (= "foo
" (entry-function "#foo#\n")))
+ (is (= "some header with_an_underscore
"
+ (entry-function "# some header `with_an_underscore`")))
+ (is (= "heading1
"
+ (entry-function "* one\n\nheading1\n========\n"))))
+
+(deftest heading2
+ (is (= "foo
" (entry-function "##foo")))
+ (is (= "foo
" (entry-function "foo\n---")))
+ (is (= "foo
" (entry-function "##foo##")))
+ (is (= "foo
" (entry-function "##foo##\n"))))
+
+(deftest heading-with-complex-anchor
+ (is (=
+ "foo bar BAz
some text
"
+ (entry-function "###foo bar BAz\nsome text" :heading-anchors true)))
+ (is (=
+ "foo bar BAz
some text
"
+ (entry-function "###foo bar BAz##\nsome text" :heading-anchors true))))
+
+(deftest br
+ (is (= "foo
" (entry-function "foo "))))
+
+(deftest hr
+ (is (= "
" (entry-function "***")))
+ (is (= "
" (entry-function " * * * ")))
+ (is (= "
" (entry-function " *****")))
+ (is (= "
" (entry-function "- - - "))))
+
+(deftest em
+ (is (= "foo
" (entry-function "*foo*"))))
+
+(deftest italics
+ (is (= "foo
" (entry-function "_foo_"))))
+
+(deftest strong
+ (is (= "foo
" (entry-function "**foo**"))))
+
+(deftest bold-italics
+ (is (= "foo
" (entry-function "***foo***"))))
+
+(deftest bold
+ (is (= "foo
" (entry-function "__foo__"))))
+
+(deftest strong-inside-em
+ (is (= "foobarbaz
" (entry-function "*foo**bar**baz*"))))
+
+(deftest bold-inside-a-list
+ (is (= "- chickens.
See more: Cluck Cluck
"
+ (entry-function "1. chickens. \n\n **See more: [Cluck Cluck](http://cluck.cluck.com)** \n\n"))))
+
+(deftest em-inside-strong
+ (is (= "foobarbaz
" (entry-function "**foo*bar*baz**"))))
+
+(deftest paragraph
+ (is (= "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore
"
+ (entry-function "\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore"))))
+
+(deftest paragraph-multiline
+ (is (= "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore
"
+ (entry-function "\nLorem ipsum dolor\nsit amet, consectetur adipisicing elit,\nsed do eiusmod tempor incididunt ut labore"))))
+
+(deftest paragraph-before-codeblock
+ (is (= "foo
bar\n
baz
"
+ (entry-function "foo\n```\nbar\n```\nbaz")))
+ (is (= "foo \nbar
" (entry-function "```\nfoo \nbar```")))
+ (is (= "
" (entry-function "```\n```")))
+ (is (= "
" (entry-function "```go\n```")))
+ (is (= "<html>\n</html>\n
" (entry-function "```\n\n\n``` "))))
+
+(deftest paragraph-after-codeblock
+ (is (= "foo\n
bar baz
"
+ (entry-function "```\nfoo\n```\nbar\nbaz"))))
+
+(deftest mulitple-paragraphs
+ (is (= "foo bar baz
foo bar baz
"
+ (entry-function "\nfoo bar baz\n\n\nfoo bar baz"))))
+
+(deftest ul
+ (is (= ""
+ (entry-function "* foo\n* bar\n* baz")))
+ (is (= ""
+ (entry-function "- foo\n- bar\n- baz")))
+ (is (= ""
+ (entry-function "+ foo\n+ bar\n+ baz"))))
+
+(deftest list-in-a-codeblock
+ (is
+ (= "list:\n- 1\n- 2\n
"
+ (entry-function "```yaml\nlist:\n- 1\n- 2\n```"))))
+
+(deftest ul-followed-by-paragraph
+ (is (= "paragraph next line
"
+ (entry-function "* foo\n* bar\n* baz\n\nparagraph\nnext line"))))
+
+(deftest ul-with-codeblock
+ (is (= "- foo
- bar
(defn foo []\n bar)\n
- baz
- more text
"
+ (entry-function
+ "\n* foo\n* bar\n ```\n (defn foo []\n bar)\n ```\n* baz\n* more text\n")))
+ (is (= "- foo
- bar
(defn foo []\n bar)\n
text - baz
- more text
"
+ (entry-function
+ "\n* foo\n* bar\n ```\n (defn foo []\n bar)\n ```\n text\n* baz\n* more text\n"))))
+
+(deftest ul-followed-by-multiline-paragraph
+ (is (= "paragraph
"
+ (entry-function "* foo\n* bar\n* baz\n\nparagraph"))))
+
+(deftest ul-nested
+ (is (= "- first item
- first sub-item
- third sub-item
- second item
- first sub-item
- second sub-item
- third item
"
+ (entry-function "* first item\n * first sub-item\n * second sub-item\n * third sub-item\n* second item\n * first sub-item\n * second sub-item\n* third item")))
+ (is (= "- first item
- first sub-item
- third sub-item
- second item
- first sub-item
- second sub-item
- third item
"
+ (entry-function "* first item\n - first sub-item\n - second sub-item\n - third sub-item\n* second item\n + first sub-item\n + second sub-item\n* third item")))
+ (is (= "" (entry-function " * abc\n\n+ def"))))
+
+(deftest ol
+ (is (= "- Foo
- Bar
- Baz
"
+ (entry-function "1. Foo\n2. Bar\n3. Baz"))))
+
+(deftest ul-in-ol
+ (is (= "- Bar
- Subbar
- Baz
"
+ (entry-function "1. Bar\n 2. Subbar\n * foo\n * bar\n * baz\n3. Baz"))))
+
+(deftest ol-in-ul
+ (is (= ""
+ (entry-function "* Foo\n 1. Bar\n 1. Subbar\n* Baz")))
+ (is (= ""
+ (entry-function "* Foo\n 1. Bar"))))
+
+(deftest multilist
+ (is (=
+ ""
+ (entry-function
+ "* foo
+* bar
+
+ * baz
+ 1. foo
+ 2. bar
+
+ * fuzz
+
+ * blah
+ * blue
+* brass"))))
+
+(deftest code
+ (is (= "foo bar baz x = y + z; foo
"
+ (entry-function "foo bar baz `x = y + z;` foo")))
+ (is (= "bar foo --- -- bar foo
"
+ (entry-function "bar `foo --- -- bar` foo")))
+ (is (= "<?xml version='1.0' encoding='UTF-8'?><channel></channel>
"
+ (entry-function "``")))
+ (is (= "foo bar baz (fn [x & xs] (str "x:" x)) foo
"
+ (entry-function "foo bar baz `(fn [x & xs] (str \"x:\" x))` foo")))
+ (is (= "```\nfoo\n```
"
+ (entry-function " ```\n foo\n ```"))))
+
+(deftest multiline-code
+ (is (= "x = 5\ny = 6\nz = x + y
"
+ (entry-function " x = 5\n y = 6\n z = x + y")))
+ (is (= "x = 5\ny = 6\nz = x + y\n(fn [x & xs] (str "x"))
"
+ (entry-function " x = 5\n y = 6\n z = x + y\n (fn [x & xs] (str \"x\"))"))))
+
+(deftest codeblock
+ (is (= "(defn- write^ [writer text]\n (doseq [c text]\n (.write writer (int c))))\n
"
+ (entry-function "```\n(defn- write^ [writer text]\n (doseq [c text]\n (.write writer (int c))))\n```")))
+ (is (= "(fn [x & xs]\n (str "x"))\n
"
+ (entry-function "```\n(fn [x & xs]\n (str \"x\"))\n```")))
+ (is (= "(fn [x & xs]\n (str "x"))\n
"
+ (entry-function "```\n(fn [x & xs]\n (str \"x\"))\n```")))
+ (is (= "(fn [x & xs]\n (str "x"))\n
"
+ (entry-function "```clojure\n(fn [x & xs]\n (str \"x\"))\n```")))
+ (is (= "------------\n============\n ------------\n ============\n
"
+ (entry-function
+ "
+```nohighlight
+------------
+============
+ ------------
+ ============
+```
+"))))
+
+(deftest indented-codeblock
+ (is (= "foo
"
+ (entry-function " foo")))
+ (is (= "foo
bar
"
+ (entry-function " foo\n\nbar")))
+ (is (= "foo
bar"
+ (entry-function " foo\nbar")))
+ (is (= "baz foo
bar
"
+ (entry-function "baz\n foo\n\nbar")))
+ (is (= ""
+ (entry-function ""))))
+
+(deftest strikethrough
+ (is (= "foo
"
+ (entry-function "~~foo~~"))))
+
+(deftest superscript
+ (is (= "foobar baz
"
+ (entry-function "foo^bar baz"))))
+
+(deftest link
+ (is (= "underscoresarefine
"
+ (entry-function "underscores_are_fine")))
+ (is (= "github
"
+ (entry-function "[github](http://github.com)")))
+ (is (= "github
"
+ (entry-function "[github](http://github.com/~)")))
+ (is (= "github
"
+ (entry-function "[github](http://github.com/^)")))
+ (is (= "github
"
+ (entry-function "[github](http://github.com/*)")))
+ (is (= ""
+ (entry-function "* [github](http://github.com/*)")))
+ (is (= "a link
"
+ (entry-function "* hi\n\n[a link](https://see-here)")))
+ (is (= ">!
"
+ (entry-function "[>!](https://clojure.github.io/core.async/#clojure.core.async/>!)")))
+ (is (= "
"
+ (entry-function "[github"
+ (entry-function "[*github*](http://github.com)")))
+ (is (= "github
"
+ (entry-function "[_github_](http://github.com)")))
+ (is (= "github
"
+ (entry-function "[__github__](http://github.com)")))
+ (is (= "github
"
+ (entry-function "[**github**](http://github.com)")))
+ (is (= "github
"
+ (entry-function "[~~github~~](http://github.com)"))))
+
+(deftest img
+ (is (= "
"
+ (entry-function "")))
+ (is (= "
"
+ (entry-function ""))))
+
+(deftest img-link
+ (is (= "
"
+ (entry-function "[](http://travis-ci.org/yogthos/markdown-clj)")))
+ (is (= "
"
+ (entry-function ""))))
+
+(deftest bad-link
+ (is (= "[github](http://github.comfooo
"
+ (entry-function "[github](http://github.comfooo")))
+ (is (= "[github] no way (http://github.com)
"
+ (entry-function "[github] no way (http://github.com)"))))
+
+(deftest bad-link-title
+ (is (= "[github(http://github.comfooo)
"
+ (entry-function "[github(http://github.comfooo)"))))
+
+(deftest blockquote
+ (is (= "Foo bar baz
"
+ (entry-function ">Foo bar baz"))))
+
+(deftest blockquote-footer
+ (is (= " Foo bar baz
"
+ (entry-function "> Foo bar baz\n>- Leo Tolstoy"))))
+
+(deftest blockquote-empty-footer
+ (is (= " Foo bar baz
"
+ (entry-function "> Foo bar baz\n>-"))))
+
+(deftest blockquote-multiline-without-leading-angle-bracket
+ (is (= " Foo bar baz
"
+ (entry-function "> Foo bar\nbaz"))))
+
+(deftest blockquote-multiple-paragraphs
+ (is (= " Foo bar
baz
"
+ (entry-function "> Foo bar\n>\n> baz"))))
+
+(deftest blockquote-bullets
+ (is (= " list:
end.
"
+ (entry-function "> list:\n>* foo\n>* bar\n\nend.")))
+ (is (= "
"
+ (entry-function ">* foo\n>* bar\n>* baz"))))
+
+(deftest blockquote-headings
+ (is (= "Foo
bar baz
"
+ (entry-function "> ## Foo\n>bar baz")))
+ (is (= " Foo
bar
baz
"
+ (entry-function "> Foo\n>## bar\n> baz"))))
+
+(deftest escaped-characters
+ (is
+ (= "^*‘_{}[]footestbar{x}[y]
"
+ (entry-function "\\^\\*\\`\\_\\{\\}\\[\\]*foo*`test`_bar_{x}[y]"))))
+
+(deftest paragraph-after-list
+ (is (= "- a
- b
test bold and italic
"
+ (entry-function "1. a\n2. b\n\ntest **bold** and *italic*"))))
+
+(deftest paragraph-close-before-list
+ (is (= "in paragraph
"
+ (entry-function "in paragraph\n- list"))))
+
+(deftest autourl
+ (is (= "http://example.com/
"
+ (entry-function "")))
+
+ (is (= "Some content with a http://www.google.com/abc__123__efg link it in
"
+ (entry-function "Some content with a link it in")))
+
+ (is (= "http://foo https://bar/baz foo bar
"
+ (entry-function " foo bar")))
+
+ #?(:bb nil :org.babashka/nbb nil
+ :default
+ (is (= "abc@google.com
"
+ (#?(:clj org.apache.commons.lang.StringEscapeUtils/unescapeHtml
+ :cljs goog.string/unescapeEntities)
+ (entry-function "")))))
+
+ #?(:bb nil :org.babashka/nbb nil
+ :default
+ (is (= "abc_def_ghi@google.com
"
+ (#?(:clj org.apache.commons.lang.StringEscapeUtils/unescapeHtml
+ :cljs goog.string/unescapeEntities)
+ (entry-function ""))))))
+
+(deftest not-a-list
+ (is (= "The fish was 192.8 lbs and was amazing to see.
"
+ (entry-function "The fish was\n192.8 lbs and was amazing to see."))))
+
+(deftest dont-encode-chars-in-hrefs
+ (is (= "example_link with tilde ~ and carat ^ and splat *
"
+ (entry-function "[example_link with tilde ~ and carat ^ and splat *](http://www.google.com/example_link_foo~_^*)"))))
+
+(deftest complex-link-with-terminal-encoding-inside-header
+ (is (= ""
+ (entry-function "##With a link [the contents of the_link](http://a.com/under_score_in_the_link/)"))))
+
+(deftest two-links-tests-link-processing
+ (is (= "When you have a pair of links link1 and you want both Wow
"
+ (entry-function "## When you have a pair of links [link1](http://123.com/1) and you want both [Wow](That%27s%20crazy)"))))
+
+(deftest link-then-image-processing
+ (is (= "You can have a link followed by an image 
"
+ (entry-function "You can have a [link](github.com) followed by an image "))))
+
+(deftest image-then-link-processing
+ (is (= "You can have an image
followed by a link
"
+ (entry-function "You can have an image  followed by a [link](github.com)"))))
+
+(deftest link-with-optional-title
+ (is (= "Cryogens site
"
+ (entry-function "[Cryogens site](https://github.com/cryogen-project/cryogen \"Cryogen Github\")"))))
+
+(deftest parse-table-row
+ (is (= (tables/parse-table-row "| table cell contents |") [{:text "table cell contents"}]))
+ (is (= (tables/parse-table-row "| contents 1 | contents 2 | contents 3 | contents 4 |")
+ [{:text "contents 1"} {:text "contents 2"} {:text "contents 3"} {:text "contents 4"}])))
+
+(deftest table-row->str
+ (is (= (tables/table-row->str
+ [{:text "contents 1"} {:text "contents 2"} {:text "contents 3"} {:text "contents 4"}]
+ true)
+ "contents 1 | contents 2 | contents 3 | contents 4 | "))
+ (is (= (tables/table-row->str
+ [{:text "contents 1"} {:text "contents 2"} {:text "contents 3"} {:text "contents 4"}]
+ false)
+ "contents 1 | contents 2 | contents 3 | contents 4 | "))
+ (is (= (tables/table-row->str
+ [{:text "contents 1" :alignment :left}
+ {:text "contents 2" :alignment :center}
+ {:text "contents 3" :alignment :right}
+ {:text "contents 4"}]
+ false)
+ "contents 1 | contents 2 | contents 3 | contents 4 | ")))
+
+(deftest table->str
+ (is (= (tables/table->str
+ {:alignment-seq
+ [{:alignment :left} {:alignment :center} {:alignment :right} {:alignment nil}]
+ :data [[{:text "Header 1"}
+ {:text "Header 2"}
+ {:text "Header 3"}
+ {:text "Header 4"}]
+ [{:text "contents 1"}
+ {:text "contents 2"}
+ {:text "contents 3"}
+ {:text "contents 4"}]]})
+ "| Header 1 | Header 2 | Header 3 | Header 4 |
|---|
| contents 1 | contents 2 | contents 3 | contents 4 |
")))
+
+(deftest divider-seq->alignment
+ (is (= (tables/divider-seq->alignment
+ [{:text "-----"} {:text ":-----"} {:text "-----:"} {:text ":-----:"}])
+ [nil {:alignment :left} {:alignment :right} {:alignment :center}])))
+
+(deftest n-dash
+ (is (= "boo – bar
" (entry-function "boo -- bar"))))
+
+(deftest m-dash
+ (is (= "boo — bar
" (entry-function "boo --- bar"))))
+
+(deftest inhibit-simple
+ (is (= "_abc_
" (entry-function "$_abc_$" :inhibit-separator "$"))))
+
+(deftest inhibit-simple-seq
+ (is (= "_abc_
" (entry-function "$_abc_$" :inhibit-separator [\$]))))
+
+(deftest inhibit-inline-code
+ (is (= "`abc`
" (entry-function "$`abc`$" :inhibit-separator [\$]))))
+
+(deftest inhibit-inside-code
+ (is (= "a*b* & dc
" (entry-function "`a$*b* & d$c`" :inhibit-separator "$"))))
+
+(deftest inhibit-across-backticks
+ (is (= "one` `two
" (entry-function "`one$` `$two`" :inhibit-separator "$"))))
+
+(deftest inhibit-escape
+ (is (= "$
" (entry-function "$$" :inhibit-separator [\$]))))
+
+(deftest inhibit-escape-twice
+ (is (= "$$
" (entry-function "$$$$" :inhibit-separator "$"))))
+
+(deftest img-reprocess
+ (is (= "
and Edit
"
+ (entry-function " and [Edit](#)"))))
+
+(deftest dont-inhibit-text-within-escapes
+ (is (= "$abc$
" (entry-function "$$*abc*$$" :inhibit-separator "$"))))
+
+(deftest inhibit-escape-inside-code
+ (is (= "$
" (entry-function "`$$`" :inhibit-separator "$"))))
+
+(deftest whitespace-paragraphs
+ (is (= "foo
bar
" (entry-function "foo\n \nbar"))))
diff --git a/test-resources/lib_tests/markdown/nbb_runner.cljs b/test-resources/lib_tests/markdown/nbb_runner.cljs
new file mode 100644
index 00000000..ec9bffa0
--- /dev/null
+++ b/test-resources/lib_tests/markdown/nbb_runner.cljs
@@ -0,0 +1,10 @@
+(ns nbb-runner
+ (:require [clojure.string :as str]
+ [clojure.test :refer [run-tests]]
+ [nbb.classpath :as cp]))
+
+(cp/add-classpath (str/join ":" ["src/cljs" "src/cljc" "test"]))
+
+(require '[markdown.md-test])
+
+(run-tests 'markdown.md-test)
diff --git a/test-resources/lib_tests/markdown/runner.cljs b/test-resources/lib_tests/markdown/runner.cljs
new file mode 100644
index 00000000..aa2cf9f4
--- /dev/null
+++ b/test-resources/lib_tests/markdown/runner.cljs
@@ -0,0 +1,5 @@
+(ns markdown.runner
+ (:require [doo.runner :refer-macros [doo-tests]]
+ [markdown.md-test]))
+
+(doo-tests 'markdown.md-test)