|
| 1 | +(ns clojure.core-test.descendants |
| 2 | + (:require [clojure.test :refer [are deftest is testing use-fixtures]] |
| 3 | + [clojure.core-test.portability #?(:cljs :refer-macros :default :refer) [when-var-exists]])) |
| 4 | + |
| 5 | +(when-var-exists descendants |
| 6 | + |
| 7 | + ; Some types for testing descendants by type |
| 8 | + (defprotocol TestDescendantsProtocol) |
| 9 | + (defrecord TestDescendantsRecord [] TestDescendantsProtocol) |
| 10 | + (deftype TestDescendantsType [] TestDescendantsProtocol) |
| 11 | + |
| 12 | + ; A global hierarchy for testing `descendants tag` and `descendants h tag` |
| 13 | + (def global-hierarchy [[TestDescendantsRecord ::record] |
| 14 | + [::t ::p-1] |
| 15 | + [::t ::p-2] |
| 16 | + [::p-1 'ns/p-0] |
| 17 | + [::p-2 ::root] |
| 18 | + ['ns/p-0 ::root]]) |
| 19 | + |
| 20 | + (defn register-global-hierarchy [] |
| 21 | + (doseq [[tag parent] global-hierarchy] |
| 22 | + (derive tag parent))) |
| 23 | + |
| 24 | + (defn unregister-global-hierarchy [] |
| 25 | + (doseq [[tag parent] global-hierarchy] |
| 26 | + (underive tag parent))) |
| 27 | + |
| 28 | + (defn with-global-hierarchy [tests] |
| 29 | + (register-global-hierarchy) |
| 30 | + (tests) |
| 31 | + (unregister-global-hierarchy)) |
| 32 | + |
| 33 | + (use-fixtures :once with-global-hierarchy) |
| 34 | + |
| 35 | + ; A hierarchy for testing `descendants h tag` |
| 36 | + (def datatypes |
| 37 | + (-> (make-hierarchy) |
| 38 | + (derive TestDescendantsRecord ::datatype) |
| 39 | + (derive TestDescendantsType ::datatype) |
| 40 | + (derive TestDescendantsType ::mutable))) |
| 41 | + |
| 42 | + ; Another hierarchy for testing `descendants h tag` |
| 43 | + (def diamond |
| 44 | + (-> (make-hierarchy) |
| 45 | + (derive ::a ::root) |
| 46 | + (derive ::b ::a) |
| 47 | + (derive ::c ::a) |
| 48 | + (derive ::d ::b) |
| 49 | + (derive ::d ::c))) |
| 50 | + |
| 51 | + (deftest test-descendants |
| 52 | + |
| 53 | + (testing "descendants tag" |
| 54 | + |
| 55 | + (testing "returns descendants by relationship globally defined with derive" |
| 56 | + (are [expected tag] (= expected (descendants tag)) |
| 57 | + nil ::t |
| 58 | + #{::t ::p-1} 'ns/p-0 |
| 59 | + #{::t ::p-1 ::p-2 'ns/p-0} ::root |
| 60 | + #{::t} ::p-2 |
| 61 | + #{#?(:bb 'clojure.core_test.descendants/TestDescendantsRecord :default TestDescendantsRecord)} ::record)) |
| 62 | + |
| 63 | + (testing "cannot get descendants by type inheritance" |
| 64 | + (is (nil? (descendants TestDescendantsProtocol))) |
| 65 | + #?(:cljs (is (nil? (descendants js/Object))) |
| 66 | + :default (is (thrown? Exception (descendants Object))))) |
| 67 | + |
| 68 | + (testing "does not throw on invalid tag" |
| 69 | + (are [tag] (nil? (descendants tag)) |
| 70 | + nil |
| 71 | + "anything" |
| 72 | + 42 |
| 73 | + 3.14 |
| 74 | + true |
| 75 | + false |
| 76 | + [] |
| 77 | + {} |
| 78 | + #{} |
| 79 | + '()))) |
| 80 | + |
| 81 | + (testing "descendants h tag" |
| 82 | + |
| 83 | + (testing "returns only descendants declared in h, whether the tag is in global hierarchy or not" |
| 84 | + (are [expected h tag] (= expected (descendants h tag)) |
| 85 | + |
| 86 | + ; tag in h and not in global hierarchy |
| 87 | + nil diamond ::d |
| 88 | + #{::d} diamond ::b |
| 89 | + #{::b ::c ::d} diamond ::a |
| 90 | + #?(:bb #{'clojure.core_test.descendants/TestDescendantsRecord 'clojure.core_test.descendants/TestDescendantsType} |
| 91 | + :default #{TestDescendantsRecord TestDescendantsType}) datatypes ::datatype |
| 92 | + #?(:bb #{'clojure.core_test.descendants/TestDescendantsType} |
| 93 | + :default #{TestDescendantsType}) datatypes ::mutable |
| 94 | + |
| 95 | + ; tag in both h and global hierarchy, only descendants in h are returned |
| 96 | + #{::a ::b ::c ::d} diamond ::root |
| 97 | + |
| 98 | + ; tag not in h but in global hierarchy |
| 99 | + nil datatypes ::root |
| 100 | + nil datatypes ::p-1 |
| 101 | + nil datatypes ::p-2 |
| 102 | + |
| 103 | + ; tag neither in h nor in global hierarchy |
| 104 | + nil datatypes ::d |
| 105 | + nil datatypes ::b |
| 106 | + nil datatypes ::a)) |
| 107 | + |
| 108 | + (testing "cannot get descendants by type inheritance, whether the tag is in h or not" |
| 109 | + (are [h] #?(:cljs (nil? (descendants h js/Object)) |
| 110 | + :default (thrown? Exception (descendants h Object))) |
| 111 | + ; tag in h |
| 112 | + (derive (make-hierarchy) Object ::object) |
| 113 | + ; tag not in h |
| 114 | + diamond |
| 115 | + datatypes)) |
| 116 | + |
| 117 | + (testing "does not throw on invalid tag or hierarchy" |
| 118 | + (are [invalid] (nil? (descendants invalid invalid)) |
| 119 | + nil |
| 120 | + "anything" |
| 121 | + 42 |
| 122 | + 3.14 |
| 123 | + true |
| 124 | + false |
| 125 | + [] |
| 126 | + {} |
| 127 | + #{} |
| 128 | + '()))))) |
0 commit comments