|
8 | 8 | [com.gfredericks.test.chuck.generators :as gen']
|
9 | 9 | [clojure.test.check.generators :as gen]
|
10 | 10 | [clojure.core.typed :as t]
|
| 11 | + [clojure.core.typed.analyzer :as ana2] |
| 12 | + [clojure.tools.analyzer.jvm :as taj] |
| 13 | + [clojure.core.typed.analyzer.jvm :as jana2] |
11 | 14 | [clojure.core.typed.runtime-infer :refer :all :as infer]
|
12 |
| - [clojure.core.typed.checker.jvm.check-form-clj :as chk-clj] |
13 | 15 | [clojure.core.typed.coerce-utils :as coerce]
|
14 | 16 | [clojure.core.typed.annotator.pprint :refer [pprint]]
|
15 | 17 | [clojure.core.typed.annotator.parse :refer [prs parse-type]]
|
16 | 18 | [clojure.core.typed.annotator.rep :refer [infer-result
|
17 | 19 | var-path
|
18 | 20 | key-path
|
19 | 21 | fn-rng-path
|
20 |
| - fn-dom-path ]] |
| 22 | + fn-dom-path]] |
21 | 23 | [clojure.core.typed.annotator.track :refer [track-var]]
|
22 | 24 | [clojure.core.typed.annotator.join :refer [make-Union
|
23 | 25 | join*
|
|
1066 | 1068 | {'config-in t}
|
1067 | 1069 | ))))
|
1068 | 1070 |
|
1069 |
| -(defmacro infer-test |
1070 |
| - "Given a vector of definitions :defs and a vector of tests :tests, then |
1071 |
| - does these steps in order. Short-circuits and returns a false value if previous steps fail. |
1072 |
| - Returns a true value on success. |
| 1071 | +(deftest instrument-top-level-form-test |
| 1072 | + (is (.contains (with-out-str (instrument-top-level-form '(println "a"))) |
| 1073 | + "a\n")) |
| 1074 | + (is (.contains |
| 1075 | + (with-out-str (instrument-top-level-form '(do (def a "a") (println a)))) |
| 1076 | + "a\n"))) |
1073 | 1077 |
|
1074 |
| - 1. Generates specs and types for the definitions |
1075 |
| - 2. Ensure generated specs and types are identical to :expected-types and :expected-specs, respectively (when provided). |
1076 |
| - These are either vectors of annotations, or a string that contains vectors |
1077 |
| - of annotations that will be `read` in the correct namespace (useful to aid keyword namespace |
1078 |
| - resolution in specs). |
1079 |
| - If one of these is not provided, the respective annotations are pprint'ed so they can |
1080 |
| - be easily copied into the test. |
1081 |
| - 3. Evaluates generated specs. |
1082 |
| - 4. Exercises spec aliases. |
1083 |
| - 5. Exercises spec'd functions. |
1084 |
| - 6. Instruments all spec'd functions. |
1085 |
| - 7. Runs :test code again under spec instrumentation." |
1086 |
| - [& {:keys [defs tests expected-specs expected-types] :as opts}] |
| 1078 | +(declare *-from-infer-results) |
| 1079 | + |
| 1080 | +;TODO remove # suffixes |
| 1081 | +(defn infer-test* |
| 1082 | + [{:keys [defs tests expected-specs expected-types] :as opts}] |
1087 | 1083 | (assert (vector? defs))
|
1088 | 1084 | (assert (vector? tests))
|
1089 |
| - `(let [ns# (create-ns (gensym))] |
| 1085 | + (let [ns# (create-ns (gensym))] |
1090 | 1086 | (binding [*ns* ns#
|
1091 | 1087 | *ann-for-ns* (constantly ns#)]
|
1092 | 1088 | (refer-clojure)
|
1093 |
| - (require '~'[clojure.core.typed :as t]) |
| 1089 | + (require '[clojure.core.typed :as t]) |
1094 | 1090 | (when spec-ns
|
1095 |
| - (require [spec-ns :as '~'s])) |
| 1091 | + (require [spec-ns :as 's])) |
1096 | 1092 | (let [result# (atom :ok)
|
1097 | 1093 | run-until-bad-result!# (fn [f# c#]
|
1098 | 1094 | (loop [c# c#]
|
1099 | 1095 | (when @result#
|
1100 | 1096 | (when (seq c#)
|
1101 | 1097 | (do (f# (first c#))
|
1102 | 1098 | (recur (rest c#)))))))
|
1103 |
| - defs# '~defs |
1104 |
| - tests# '~tests |
1105 |
| - _# (t/refresh-runtime-infer) |
| 1099 | + defs# defs |
| 1100 | + tests# tests |
| 1101 | + _# (infer/refresh-runtime-infer) |
1106 | 1102 | _# (run-until-bad-result!#
|
1107 | 1103 | (fn [f#]
|
1108 |
| - (let [{ex# :ex} (chk-clj/check-form-info-with-config |
1109 |
| - f# |
1110 |
| - (assoc (chk-clj/config-map) :should-runtime-infer? true) |
1111 |
| - {})] |
1112 |
| - (when ex# |
1113 |
| - (println (str "Form " f# " failed to evaluate, with error: " ex#)) |
1114 |
| - (reset! result# nil)))) |
| 1104 | + (try (instrument-top-level-form f#) |
| 1105 | + (catch Throwable e# |
| 1106 | + (println (str "Failed to evaluate " f# " with error " e#)) |
| 1107 | + (reset! result# nil)))) |
1115 | 1108 | (concat defs# tests#))]
|
1116 | 1109 | (when @result#
|
1117 |
| - (let [expected-specs# (let [s# '~expected-specs] |
| 1110 | + (let [expected-specs# (let [s# expected-specs] |
1118 | 1111 | (if (string? s#)
|
1119 | 1112 | (read-string s#)
|
1120 | 1113 | s#))
|
1121 | 1114 | _# (assert ((some-fn nil? vector?) expected-specs#))
|
1122 |
| - expected-types# (let [t# '~expected-types] |
| 1115 | + expected-types# (let [t# expected-types] |
1123 | 1116 | (if (string? t#)
|
1124 | 1117 | (read-string t#)
|
1125 | 1118 | t#))
|
|
1149 | 1142 | (let [instrumentable-syms# (set
|
1150 | 1143 | (keep (fn [spc#]
|
1151 | 1144 | (when (seq? spc#)
|
1152 |
| - (when (= '~'s/fdef (first spc#)) |
| 1145 | + (when (= 's/fdef (first spc#)) |
1153 | 1146 | (let [^clojure.lang.Var v# (resolve (second spc#))]
|
1154 | 1147 | (when (var? v#)
|
1155 | 1148 | (coerce/var->symbol v#))))))
|
1156 | 1149 | (:top-level specs#)))
|
1157 | 1150 | spec-defs# (set
|
1158 | 1151 | (keep (fn [spc#]
|
1159 | 1152 | (when (seq? spc#)
|
1160 |
| - (when (= '~'s/def (first spc#)) |
| 1153 | + (when (= 's/def (first spc#)) |
1161 | 1154 | (let [kw# (second spc#)]
|
1162 | 1155 | (when (keyword? kw#)
|
1163 | 1156 | (when (namespace kw#)
|
1164 | 1157 | kw#))))))
|
1165 | 1158 | (:top-level specs#)))
|
1166 |
| - _# (require ['~'clojure.spec.test.alpha]) |
1167 |
| - instrument# (resolve '~'clojure.spec.test.alpha/instrument) |
| 1159 | + _# (require ['clojure.spec.test.alpha]) |
| 1160 | + instrument# (resolve 'clojure.spec.test.alpha/instrument) |
1168 | 1161 | _# (assert instrument#)
|
1169 |
| - exercise# (resolve '~'clojure.spec.alpha/exercise) |
| 1162 | + exercise# (resolve 'clojure.spec.alpha/exercise) |
1170 | 1163 | _# (assert exercise#)
|
1171 |
| - exercise-fn# (resolve '~'clojure.spec.alpha/exercise-fn) |
| 1164 | + exercise-fn# (resolve 'clojure.spec.alpha/exercise-fn) |
1172 | 1165 | _# (assert exercise-fn#)
|
1173 | 1166 | exercise-fn-or-fail# (fn [sym#]
|
1174 | 1167 | (try (doall (exercise-fn# sym#))
|
|
1219 | 1212 | (run-until-bad-result!# eval-or-fail# tests#))))
|
1220 | 1213 | @result#))))))
|
1221 | 1214 |
|
| 1215 | +(defmacro infer-test |
| 1216 | + "Given a vector of definitions :defs and a vector of tests :tests, then |
| 1217 | + does these steps in order. Short-circuits and returns a false value if previous steps fail. |
| 1218 | + Returns a true value on success. |
| 1219 | +
|
| 1220 | + 1. Generates specs and types for the definitions |
| 1221 | + 2. Ensure generated specs and types are identical to :expected-types and :expected-specs, respectively (when provided). |
| 1222 | + These are either vectors of annotations, or a string that contains vectors |
| 1223 | + of annotations that will be `read` in the correct namespace (useful to aid keyword namespace |
| 1224 | + resolution in specs). |
| 1225 | + If one of these is not provided, the respective annotations are pprint'ed so they can |
| 1226 | + be easily copied into the test. |
| 1227 | + 3. Evaluates generated specs. |
| 1228 | + 4. Exercises spec aliases. |
| 1229 | + 5. Exercises spec'd functions. |
| 1230 | + 6. Instruments all spec'd functions. |
| 1231 | + 7. Runs :test code again under spec instrumentation." |
| 1232 | + [& {:keys [defs tests expected-specs expected-types] :as opts}] |
| 1233 | + `(infer-test* '~opts)) |
| 1234 | + |
1222 | 1235 | (defn *-from-infer-results [ns config]
|
1223 | 1236 | (binding [*ann-for-ns* (constantly *ns*)
|
1224 | 1237 | *debug* (if-let [[_ debug] (find config :debug)]
|
|
0 commit comments