Skip to content

Commit 2edd731

Browse files
committed
Multiline eval expectations complete when parsable
We now know know that an eval expectation is complete when its form parses successfully. Added the lovely nubank matcher combinators dep to help with test assertions. Now that things are a bit more complicated, algorithm and naming in code. It might be a bit easier to follow now? Hope so.
1 parent 11b98c3 commit 2edd731

File tree

3 files changed

+279
-136
lines changed

3 files changed

+279
-136
lines changed

deps.edn

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@
6262
;;
6363

6464
;; for kaocha see also tests.edn
65-
:kaocha {:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
65+
:kaocha {:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}
66+
nubank/matcher-combinators {:mvn/version "3.9.1"}}
6667
:extra-paths ["test"]
6768
:main-opts ["-m" "kaocha.runner"]}
6869

Lines changed: 110 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
(ns ^:no-doc lread.test-doc-blocks.impl.body-prep
22
"Prep a doc block to be converted into a test."
3-
(:require [clojure.string :as string]))
3+
(:require [clojure.string :as string]
4+
[rewrite-clj.zip :as z]))
5+
6+
(defn- parseable? [s]
7+
(try
8+
(let [zloc (z/of-string s)]
9+
(not= :forms (z/tag zloc)))
10+
(catch Exception _ex
11+
false)))
412

513
(defn ^:no-doc prep-block-for-conversion-to-test
614
"Convert doc block to Clojure that can be more easily parsed.
@@ -29,77 +37,128 @@
2937
"
3038
[block-text]
3139
(let [re-editor-style-out-expected #"^\s*(?:;;\s*){0,1}(=stdout=>|=stderr=>)(?:\s*$| {0,1}(.*))"
32-
re-out-continue #"^\s*;+(?:\s*$| {0,1}(.*))"
33-
re-editor-style-expected #"^\s*(?:;;\s*){0,1}(=clj=>|=cljs=>|=>)\s*(.*$)"]
34-
(-> (loop [acc {:body ""}
40+
re-line-continue #"^\s*;+(?:\s*$| {0,1}(.*))"
41+
re-editor-style-expected #"^\s*(?:;;\s*){0,1}(=clj=>|=cljs=>|=>)\s*(.*$)"]
42+
(-> (loop [{:keys [body parsing assert-token expectation eo-assert?] :as state} {:body ""}
3543
[line :as lines] (string/split-lines block-text)]
3644
(let [line (and line (string/trimr line))
37-
[_ assert-token payload] (when line
38-
(or (re-matches re-editor-style-expected line)
39-
(re-matches re-editor-style-out-expected line)))]
45+
[_ line-assert-token line-payload] (when line
46+
(or (re-matches re-editor-style-expected line)
47+
(re-matches re-editor-style-out-expected line)))]
4048
(cond
41-
;; expectation ends
42-
(and (:out acc) (or (not line)
43-
assert-token
44-
(not (re-matches re-out-continue line))
45-
(re-matches re-editor-style-expected line)))
46-
(recur (as-> acc acc
47-
(case (:style acc)
48-
:out
49-
(update acc :body str (str (:out-token acc) " "
50-
(conj (:out acc)) "\n"))
51-
:editor
52-
(update acc :body str (str (:assert-token acc) " "
53-
(string/join "\n" (:out acc))
54-
"\n")))
55-
(dissoc acc :out :out-token :assert-token :style))
56-
lines)
49+
(= :eval-expectation parsing)
50+
(cond
51+
;; end of eval expectation?
52+
(or (not line) eo-assert?)
53+
(recur {:body (str body
54+
assert-token " "
55+
(string/join "\n" expectation)
56+
"\n")}
57+
lines)
58+
59+
:else
60+
(let [[_ line-continue] (re-matches re-line-continue line)
61+
eval-line (or line-continue line)]
62+
(recur (let [{:keys [expectation] :as state} (update state :expectation conj (or eval-line ""))]
63+
(if (parseable? (string/join "\n" expectation))
64+
(assoc state :eo-assert? true)
65+
state))
66+
(rest lines))))
67+
68+
(= :out-expectation parsing)
69+
(cond
70+
;; end of expecation?
71+
(or (not line)
72+
line-assert-token
73+
eo-assert?
74+
(not (re-matches re-line-continue line)))
75+
(recur {:body (str body
76+
assert-token " "
77+
(conj expectation)
78+
"\n")}
79+
lines)
80+
81+
(re-matches re-line-continue line)
82+
(let [[_ line-continue] (re-matches re-line-continue line)]
83+
(recur (update state :expectation conj (or line-continue ""))
84+
(rest lines)))
85+
86+
:else
87+
(recur (assoc state :eo-assert? true) lines))
5788

5889
;; all done?
5990
(not line)
60-
acc
61-
62-
;; collecting expectation
63-
(and (:out acc)
64-
(not assert-token)
65-
(re-matches re-out-continue line))
66-
(let [[_ out-line] (re-matches re-out-continue line)]
67-
(recur (update acc :out conj (or out-line ""))
68-
(rest lines)))
69-
70-
;; out expectation starts
71-
(or (= "=stdout=>" assert-token)
72-
(= "=stderr=>" assert-token))
73-
(recur (assoc acc
74-
:style :out
75-
:out (if payload [payload] [])
76-
:out-token assert-token)
91+
state
92+
93+
;; start of out expection
94+
(or (= "=stdout=>" line-assert-token)
95+
(= "=stderr=>" line-assert-token))
96+
(recur (assoc state
97+
:parsing :out-expectation
98+
:expectation (if line-payload [line-payload] [])
99+
:assert-token line-assert-token)
77100
(rest lines))
78101

79-
;; editor style evaluation expectation:
80-
;; actual
81-
;; ;;=> expected
82-
assert-token
83-
(recur (assoc acc
84-
:out (if payload [payload] [])
85-
:style :editor
86-
:assert-token assert-token)
102+
;; editor style expectation
103+
line-assert-token
104+
(recur (let [{:keys [expectation] :as state} (assoc state
105+
:parsing :eval-expectation
106+
:expectation (if line-payload [line-payload] [])
107+
:assert-token line-assert-token)]
108+
(if (parseable? (string/join "\n" expectation))
109+
(assoc state :eo-assert? true)
110+
state))
87111
(rest lines))
88112

89-
;; other lines
90113
:else
91-
(recur (update acc :body str (str line "\n"))
114+
(recur (update state :body str (str line "\n"))
92115
(rest lines)))))
93116
:body)))
94117

95118

96119
(comment
120+
(parseable? " , ")
121+
97122
(prep-block-for-conversion-to-test ";; =stdout=> line1
98123
; line2")
124+
;; => "=stdout=> [\"line1\" \"line2\"]\n"
99125

100126
(prep-block-for-conversion-to-test
101127
"(assoc {} :foo :bar :baz :kikka)
102128
;; => {:foo :bar
103129
; :baz :kikka}"
104130
)
105-
)
131+
;; => "(assoc {} :foo :bar :baz :kikka)\n=> {:foo :bar\n :baz :kikka}\n"
132+
133+
(prep-block-for-conversion-to-test
134+
"(assoc {} :foo :bar :baz :kikka)
135+
;; => ^{:foo :bar
136+
;; :baz :kikka} []
137+
;; some other comment
138+
;; more comments
139+
;; =stdout=> foo
140+
"
141+
)
142+
;; => "(assoc {} :foo :bar :baz :kikka)\n=> ^{:foo :bar\n :baz :kikka} []\n;; some other comment\n;; more comments\n=stdout=> [\"foo\"]\n"
143+
144+
145+
(parseable? " ")
146+
;; => false
147+
(parseable? " 32 ")
148+
;; => true
149+
150+
;; only :a will be significant
151+
(parseable? ":a 2 3")
152+
;; => true
153+
154+
(parseable? "[:a 2\n;;some foo\n 3]")
155+
;; => true
156+
157+
(parseable? ";; foo")
158+
;; => false
159+
160+
;; for now don't skip discards, user should get error for this eventualy
161+
(parseable? "#_ 3")
162+
;; => true
163+
164+
:eoc)

0 commit comments

Comments
 (0)