From c80bf573a5dc468ed62a7a3d5ddf182e6ea05b80 Mon Sep 17 00:00:00 2001 From: Nathan Marz Date: Thu, 1 Sep 2016 20:32:38 -0400 Subject: [PATCH] updated tests, lots of errors --- src/clj/com/rpl/specter/macros.clj | 11 ++ src/clj/com/rpl/specter/transients.cljc | 6 +- src/clj/com/rpl/specter/zipper.cljc | 17 ++- test/com/rpl/specter/core_test.cljc | 195 ++++++++---------------- test/com/rpl/specter/test_helpers.clj | 10 +- 5 files changed, 85 insertions(+), 154 deletions(-) diff --git a/src/clj/com/rpl/specter/macros.clj b/src/clj/com/rpl/specter/macros.clj index e675e51..d52c9dc 100644 --- a/src/clj/com/rpl/specter/macros.clj +++ b/src/clj/com/rpl/specter/macros.clj @@ -86,6 +86,17 @@ (defmacro providepath [name apath] `(i/providepath* ~name (path ~apath))) +(defmacro recursive-path [params self-sym path] + (if (empty? params) + `(let [~self-sym (i/local-declarepath)] + (providepath ~self-sym ~path) + ~self-sym) + `(i/direct-nav-obj + (fn ~params + (let [~self-sym (i/local-declarepath)] + (providepath ~self-sym ~path) + ~self-sym))))) + ;; copied from tools.macro to avoid the dependency (defn ^:no-doc name-with-attributes "To be used in macro definitions. diff --git a/src/clj/com/rpl/specter/transients.cljc b/src/clj/com/rpl/specter/transients.cljc index de475f8..a6a4ac3 100644 --- a/src/clj/com/rpl/specter/transients.cljc +++ b/src/clj/com/rpl/specter/transients.cljc @@ -2,12 +2,10 @@ #?(:cljs (:require-macros [com.rpl.specter.macros :refer - [defnav - defpathedfn]])) + [defnav]])) (:use #?(:clj [com.rpl.specter.macros :only - [defnav - defpathedfn]])) + [defnav]])) (:require [com.rpl.specter.navs :as n] [com.rpl.specter :refer [subselect selected?]])) diff --git a/src/clj/com/rpl/specter/zipper.cljc b/src/clj/com/rpl/specter/zipper.cljc index 2632ccf..bada765 100644 --- a/src/clj/com/rpl/specter/zipper.cljc +++ b/src/clj/com/rpl/specter/zipper.cljc @@ -1,10 +1,11 @@ (ns com.rpl.specter.zipper #?(:cljs (:require-macros [com.rpl.specter.macros - :refer [defnav nav declarepath providepath]])) + :refer [defnav nav declarepath providepath recursive-path]])) #?(:clj (:use - [com.rpl.specter.macros :only [defnav nav declarepath providepath]])) + [com.rpl.specter.macros :only [defnav nav declarepath providepath + recursive-path]])) (:require [com.rpl.specter :as s] [clojure.zip :as zip])) @@ -116,15 +117,15 @@ (zip/remove inserted)))) -(declarepath ^{:doc "Navigate the zipper to the first element +(def ^{:doc "Navigate the zipper to the first element in the structure matching predfn. A linear scan is done using NEXT to find the element."} - find-first [predfn]) + find-first + (recursive-path [predfn] p + (s/if-path [NODE (s/pred predfn)] + s/STAY + [NEXT p]))) -(providepath find-first - (s/if-path [NODE s/pred] - s/STAY - [NEXT (s/params-reset find-first)])) (declarepath ^{:doc "Navigate to every element reachable using calls diff --git a/test/com/rpl/specter/core_test.cljc b/test/com/rpl/specter/core_test.cljc index 4b0b762..3014059 100644 --- a/test/com/rpl/specter/core_test.cljc +++ b/test/com/rpl/specter/core_test.cljc @@ -5,21 +5,21 @@ [com.rpl.specter.cljs-test-helpers :refer [for-all+]] [com.rpl.specter.test-helpers :refer [ic-test]] [com.rpl.specter.macros - :refer [paramsfn defprotocolpath defnav extend-protocolpath + :refer [defprotocolpath defnav extend-protocolpath nav declarepath providepath select select-one select-one! - select-first transform setval replace-in defnavconstructor + select-first transform setval replace-in select-any selected-any? collected? traverse - multi-transform path]])) + multi-transform path dynamicnav recursive-path]])) (:use #?(:clj [clojure.test :only [deftest is]]) #?(:clj [clojure.test.check.clojure-test :only [defspec]]) #?(:clj [com.rpl.specter.test-helpers :only [for-all+ ic-test]]) #?(:clj [com.rpl.specter.macros - :only [paramsfn defprotocolpath defnav extend-protocolpath + :only [defprotocolpath defnav extend-protocolpath nav declarepath providepath select select-one select-one! - select-first transform setval replace-in defnavconstructor + select-first transform setval replace-in select-any selected-any? collected? traverse - multi-transform path]])) + multi-transform path dynamicnav recursive-path]])) @@ -476,44 +476,12 @@ (gen-map-with-keys gen/keyword gen/int k2) k1)) pred (gen/elements [inc dec])] - (let [p (s/comp-paths s/keypath s/keypath)] + (let [p (dynamicnav [a b] (path (s/keypath a) (s/keypath b)))] (and (= (s/compiled-select (p k1 k2) m1) (select [k1 k2] m1)) (= (s/compiled-transform (p k1 k2) pred m1) (transform [k1 k2] pred m1)))))) -(defspec various-orders-comp-test - (for-all+ - [k1 (limit-size 3 gen/keyword) - k2 (limit-size 3 gen/keyword) - k3 (limit-size 3 gen/keyword) - m1 (limit-size 5 - (gen-map-with-keys - gen/keyword - (gen-map-with-keys - gen/keyword - (gen-map-with-keys - gen/keyword - gen/int - k3) - - k2) - k1)) - pred (gen/elements [inc dec])] - (let [paths [((s/comp-paths s/keypath s/keypath k3) k1 k2) - (s/comp-paths k1 k2 k3) - ((s/comp-paths s/keypath k2 s/keypath) k1 k3) - ((s/comp-paths k1 s/keypath k3) k2) - (s/comp-paths k1 (s/keypath k2) k3) - ((s/comp-paths (s/keypath k1) s/keypath (s/keypath k3)) k2) - ((s/comp-paths s/keypath (s/keypath k2) s/keypath) k1 k3)]] - - - (and - (apply = (for [p paths] (s/compiled-select p m1))) - (apply = (for [p paths] (s/compiled-transform p pred m1))))))) - - (defspec filterer-param-test (for-all+ [k gen/keyword @@ -529,18 +497,24 @@ pred (gen/elements [odd? even?]) updater (gen/elements [inc dec])] (and - (= (s/compiled-select ((s/filterer s/keypath pred) k) v) - (s/compiled-select (s/filterer k pred) v)) - (= (s/compiled-transform ((s/comp-paths (s/filterer s/keypath pred) s/ALL k2) k) + (= (select (s/filterer (s/keypath k) pred) v) + (select (s/filterer k pred) v)) + (= (transform [(s/filterer (s/keypath k) pred) s/ALL k2] updater v) - (s/compiled-transform (s/comp-paths (s/filterer k pred) s/ALL k2) + (transform [(s/filterer k pred) s/ALL k2] updater v))))) (deftest nested-param-paths - (let [p (s/filterer s/keypath (s/selected? s/ALL s/keypath (s/filterer s/keypath even?) s/ALL)) + (let [p (fn [a b c] + (path + (s/filterer (s/keypath a) + (s/selected? s/ALL + (s/keypath b) + (s/filterer (s/keypath c) even?) + s/ALL)))) p2 (p :a :b :c) p3 (s/filterer :a (s/selected? s/ALL :b (s/filterer :c even?) s/ALL)) data [{:a [{:b [{:c 4 :d 5}]}]} @@ -574,9 +548,9 @@ gen/int k)))] (and - (= (s/compiled-select ((s/subselect s/ALL s/keypath) k) v) + (= (s/compiled-select (s/subselect s/ALL (s/keypath k)) v) [(map k v)]) - (let [v2 (s/compiled-transform ((s/comp-paths (s/subselect s/ALL s/keypath)) k) + (let [v2 (s/compiled-transform (s/comp-paths (s/subselect s/ALL (s/keypath k))) reverse v)] (and (= (map k v) (reverse (map k v2))) @@ -601,11 +575,11 @@ pred2 (gen/elements [odd? even?]) updater (gen/elements [inc dec])] - (let [paths [((s/multi-path [s/keypath pred1] [s/keypath pred2] k3) k1 k2) - ((s/multi-path [k1 pred1] [s/keypath pred2] s/keypath) k2 k3) - ((s/multi-path [s/keypath pred1] [s/keypath pred2] s/keypath) k1 k2 k3) + (let [paths [(path (s/multi-path [(s/keypath k1) pred1 [(s/keypath k2) pred2 k3]])) + (path (s/multi-path [k1 pred1] [(s/keypath k2) pred2 (s/keypath k3)])) + (path (s/multi-path [(s/keypath k1) pred1 [(s/keypath k2) pred2 (s/keypath k3)]])) (s/multi-path [k1 pred1] [k2 pred2] k3) - ((s/multi-path [k1 pred1] [s/keypath pred2] k3) k2)]] + (path (s/multi-path [k1 pred1] [(s/keypath k2) pred2 k3]))]] (and (apply = @@ -617,18 +591,6 @@ (transform p updater m))))))) - -(defspec paramsfn-test - (for-all+ - [v (gen/vector (gen/elements (range 10))) - val (gen/elements (range 10)) - op (gen/elements [inc dec]) - comparator (gen/elements [= > <])] - (let [cpath (s/comp-paths s/ALL (paramsfn [p] [v] (comparator v p)))] - (= (transform (cpath val) op v) - (transform [s/ALL #(comparator % val)] op v))))) - - (defspec subset-test (for-all+ [s1 (gen/vector (limit-size 5 gen/keyword)) @@ -711,14 +673,12 @@ [:bb [:aa 34 [:abc 10 [:ccc 9 8 [:abc 9 1]]]] [:abc 1 [:abc 3]]])))) - -(declarepath map-key-walker [akey]) - -(providepath map-key-walker - [s/ALL - (s/if-path [s/FIRST (paramsfn [akey] [curr] (= curr akey))] - s/LAST - [s/LAST (s/params-reset map-key-walker)])]) +(def map-key-walker + (recursive-path [akey] p + [s/ALL + (s/if-path [s/FIRST #(= % akey)] + s/LAST + [s/LAST p])])) (deftest recursive-params-path-test (is (= #{1 2 3} (set (select (map-key-walker :aaa) @@ -731,7 +691,7 @@ (deftest recursive-params-composable-path-test - (let [p (s/comp-paths s/keypath map-key-walker)] + (let [p (fn [k k2] (path (s/keypath k) (map-key-walker k2)))] (is (= [1] (select (p 1 :a) [{:a 3} {:a 1} {:a 2}]))))) @@ -740,13 +700,13 @@ (is (= {3 21 4 31} (transform [s/ALL s/ALL] inc {2 20 3 30})))) -(declarepath NestedHigherOrderWalker [k]) -(providepath NestedHigherOrderWalker - (s/if-path vector? - (s/if-path [s/FIRST (paramsfn [k] [e] (= k e))] - (s/continue-then-stay s/ALL (s/params-reset NestedHigherOrderWalker)) - [s/ALL (s/params-reset NestedHigherOrderWalker)]))) +(def NestedHigherOrderWalker + (recursive-path [k] p + (s/if-path vector? + (s/if-path [s/FIRST #(= % k)] + (s/continue-then-stay s/ALL p) + [s/ALL p])))) (deftest nested-higher-order-walker-test @@ -758,13 +718,13 @@ #?(:clj (deftest large-params-test - (let [path (apply s/comp-paths (repeat 25 s/keypath)) + (let [path (apply com.rpl.specter.impl/comp-navs (for [i (range 25)] (s/keypath i))) m (reduce (fn [m k] {k m}) :a (reverse (range 25)))] - (is (= :a (select-one (apply path (range 25)) m)))))) + (is (= :a (select-one path m)))))) ;;TODO: there's a bug in clojurescript that won't allow ;; non function implementations of IFn to have more than 20 arguments @@ -799,8 +759,8 @@ (defrecord LabeledUser [account]) (defrecord LabeledFamily [accounts]) (extend-protocolpath LabeledAccountPath - LabeledUser [:account s/keypath] - LabeledFamily [:accounts s/keypath s/ALL]))) + LabeledUser [:account (s/keypath label)] + LabeledFamily [:accounts (s/keypath label) s/ALL]))) #?(:clj @@ -878,16 +838,13 @@ (= q1 q2) (= (type q1) (type q2)))))) -(defnavconstructor double-str-keypath - [p s/keypath] - [s1 s2] - (p (str s1 s2))) +(defn ^:direct-nav double-str-keypath [s1 s2] + (path (s/keypath (str s1 s2)))) -(defnavconstructor some-keypath - [p s/keypath] - ([] (p "a")) - ([k1] (p (str k1 "!"))) - ([k & args] (p "bbb"))) +(defn ^:direct-nav some-keypath + ([] (s/keypath "a")) + ([k1] (s/keypath (str k1 "!"))) + ([k & args] (s/keypath "bbb"))) (deftest nav-constructor-test ;; this also tests that the eval done by clj platform during inline @@ -903,35 +860,30 @@ (deftest inline-caching-test (ic-test - true [k] [s/ALL (s/must k)] inc [{:a 1} {:b 2 :c 3} {:a 7 :d -1}] [[:a] [:b] [:c] [:d] [:e]]) (ic-test - true [] [s/ALL #{4 5 11} #(> % 2) (fn [e] (< e 7))] inc (range 20) []) (ic-test - false [v] (if v :a :b) inc {:a 1 :b 2} [[true] [false]]) (ic-test - true [v] [s/ALL (double-str-keypath v (inc v))] str [{"12" :a "1011" :b} {"1011" :c}] [[1] [10]]) (ic-test - false [k] (*APATH* k) str @@ -940,7 +892,6 @@ (binding [*APATH* s/must] (ic-test - false [k] (*APATH* k) inc @@ -948,7 +899,6 @@ [[:a] [:b] [:c]])) (ic-test - true [k k2] [s/ALL (s/selected? (s/must k) #(> % 2)) (s/must k2)] dec @@ -956,7 +906,6 @@ [[:a :b] [:b :a] [:c :d] [:b :c]]) (ic-test - true [] [(s/transformed s/STAY inc)] inc @@ -964,30 +913,17 @@ []) - (s/must-cache-paths!) - (is (thrown? #?(:clj Exception :cljs js/Error) - (select (if true :a :b) nil))) + ;; verifying that these don't throw errors + (is (= 1 (select-any (if true :a :b) {:a 1}))) + (is (= 3 (select-any (*APATH* :a) {:a 3}))) + (is (= 2 (select-any [:a (identity even?)] {:a 2}))) - (is (thrown? #?(:clj Exception :cljs js/Error) - (select (*APATH* :a) nil))) + (is (= [10 11] (select-one! [(s/putval 10) (s/transformed s/STAY #(inc %))] 10))) - (is (thrown? #?(:clj Exception :cljs js/Error) - (select [:a (identity even?)] {:a 2}))) + (is (= 2 (let [p :a] (select-one! [p even?] {:a 2})))) - ;; this tests a bug that existed before ^:staticparam annotation - ;; for pathedfns - (is (thrown? #?(:clj Exception :cljs js/Error) - (select [(s/putval 10) (s/transformed s/STAY #(inc %))] 10))) + (is (= [{:a 2}] (let [p :a] (select [s/ALL (s/selected? p even?)] [{:a 2}]))))) - (let [p :a] - (is (thrown? #?(:clj Exception :cljs js/Error) - (select [p even?] {:a 2})))) - - (let [p :a] - (is (thrown? #?(:clj Exception :cljs js/Error) - (select [s/ALL (s/selected? p even?)] [{:a 2}])))) - - (s/must-cache-paths! false)) (deftest nested-inline-caching-test @@ -1024,8 +960,7 @@ -;; there was a bug where the transform-fn was being factored by inline caching -;; this verifies that it doesn't do inline caching +;; verifies that late binding of dynamic parameters works correctly (deftest transformed-inline-caching (dotimes [i 10] (is (= [(inc i)] (select (s/transformed s/STAY #(+ % i)) 1))))) @@ -1271,12 +1206,11 @@ (= (reduce + i (traverse [s/ALL p] v)) (reduce + i (filter p v)))))) - -(declarepath KeyAccumWalker [k]) -(providepath KeyAccumWalker - (s/if-path - s/must s/STAY - [s/ALL (s/collect-one s/FIRST) s/LAST (s/params-reset KeyAccumWalker)])) +(def KeyAccumWalker + (recursive-path [k] p + (s/if-path (s/must k) + s/STAY + [s/ALL (s/collect-one s/FIRST) s/LAST p]))) (deftest recursive-if-path-select-vals-test @@ -1338,13 +1272,4 @@ [even? (s/terminal-val 100)] [#(= 100 %) (s/terminal inc)] [#(= 101 %) (s/terminal inc)]) - - 1)))) - -(deftest inline-lean-path - ;; use executors from ALL because it's a lean navigator - (let [e (.-executors s/ALL)] - (is (identical? e (.-executors (path :a (s/view inc))))) - (is (identical? e (.-executors (path (s/keypath :a) (s/srange 2 7))))) - (is (identical? e (.-executors (path :a (s/selected? (s/view inc) (s/selected? (s/srange 2 7))))))))) diff --git a/test/com/rpl/specter/test_helpers.clj b/test/com/rpl/specter/test_helpers.clj index f304b43..7c00094 100644 --- a/test/com/rpl/specter/test_helpers.clj +++ b/test/com/rpl/specter/test_helpers.clj @@ -5,7 +5,7 @@ [clojure.test]) (:use [com.rpl.specter.macros :only [select transform]] - [com.rpl.specter :only [select* transform* must-cache-paths!]])) + [com.rpl.specter :only [select* transform*]])) ;; it seems like gen/bind and gen/return are a monad (hence the names) @@ -22,7 +22,7 @@ ~@body))) -(defmacro ic-test [must-cache? params-decl apath transform-fn data params] +(defmacro ic-test [params-decl apath transform-fn data params] (let [platform (if (contains? &env :locals) :cljs :clj) is-sym (if (= platform :clj) 'clojure.test/is 'cljs.test/is)] `(let [icfnsel# (fn [~@params-decl] (select ~apath ~data)) @@ -30,11 +30,7 @@ regfnsel# (fn [~@params-decl] (select* ~apath ~data)) regfntran# (fn [~@params-decl] (transform* ~apath ~transform-fn ~data)) params# (if (empty? ~params) [[]] ~params)] - - (must-cache-paths! ~must-cache?) (dotimes [_# 3] (doseq [ps# params#] (~is-sym (= (apply icfnsel# ps#) (apply regfnsel# ps#))) - (~is-sym (= (apply icfntran# ps#) (apply regfntran# ps#))))) - - (must-cache-paths! false)))) + (~is-sym (= (apply icfntran# ps#) (apply regfntran# ps#))))))))