|
1 | 1 | (ns ^:no-doc lread.test-doc-blocks.impl.body-prep |
2 | 2 | "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))) |
4 | 12 |
|
5 | 13 | (defn ^:no-doc prep-block-for-conversion-to-test |
6 | 14 | "Convert doc block to Clojure that can be more easily parsed. |
|
29 | 37 | " |
30 | 38 | [block-text] |
31 | 39 | (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 ""} |
35 | 43 | [line :as lines] (string/split-lines block-text)] |
36 | 44 | (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)))] |
40 | 48 | (cond |
41 | | - ;; out 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 (-> acc |
47 | | - (update :body str (str (:out-token acc) " " |
48 | | - (conj (:out acc)) "\n")) |
49 | | - (dissoc :out :out-token)) |
50 | | - 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)) |
51 | 88 |
|
52 | 89 | ;; all done? |
53 | 90 | (not line) |
54 | | - acc |
55 | | - |
56 | | - ;; collecting stdout/stderr expectation |
57 | | - (and (:out acc) |
58 | | - (not assert-token) |
59 | | - (re-matches re-out-continue line)) |
60 | | - (let [[_ out-line] (re-matches re-out-continue line)] |
61 | | - (recur (update acc :out conj (or out-line "")) |
62 | | - (rest lines))) |
63 | | - |
64 | | - ;; out expectation starts |
65 | | - (or (= "=stdout=>" assert-token) |
66 | | - (= "=stderr=>" assert-token)) |
67 | | - (recur (assoc acc |
68 | | - :out (if payload [payload] []) |
69 | | - :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) |
70 | 100 | (rest lines)) |
71 | 101 |
|
72 | | - ;; editor style evaluation expectation: |
73 | | - ;; actual |
74 | | - ;; ;;=> expected |
75 | | - assert-token |
76 | | - (recur (update acc :body str (str assert-token " " payload "\n")) |
| 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)) |
77 | 111 | (rest lines)) |
78 | 112 |
|
79 | | - ;; other lines |
80 | 113 | :else |
81 | | - (recur (update acc :body str (str line "\n")) |
| 114 | + (recur (update state :body str (str line "\n")) |
82 | 115 | (rest lines))))) |
83 | 116 | :body))) |
84 | 117 |
|
85 | 118 |
|
86 | 119 | (comment |
87 | | - (prep-block-for-conversion-to-test ";; =stdout=> line1") |
88 | | - |
89 | | - |
90 | | - ) |
| 120 | + (parseable? " , ") |
| 121 | + |
| 122 | + (prep-block-for-conversion-to-test ";; =stdout=> line1 |
| 123 | +; line2") |
| 124 | + ;; => "=stdout=> [\"line1\" \"line2\"]\n" |
| 125 | + |
| 126 | + (prep-block-for-conversion-to-test |
| 127 | + "(assoc {} :foo :bar :baz :kikka) |
| 128 | +;; => {:foo :bar |
| 129 | +; :baz :kikka}" |
| 130 | + ) |
| 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