;; This Source Code Form is subject to the terms of the Mozilla Public ;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; ;; Copyright (c) KALEIDOS SUBSIDIARY SL (ns common-tests.files.tokens-test (:require [app.common.files.tokens :as cfo] [app.common.test-helpers.files :as thf] [app.common.test-helpers.ids-map :as thi] [app.common.test-helpers.tokens :as tht] [app.common.types.file :as ctf] [app.common.types.tokens-lib :as ctob] [app.common.types.tokens-status :as ctos] [app.common.uuid :as uuid] [clojure.test :as t])) ;; Helper functions (t/deftest test-token-circular-reference? (t/testing "returns nil when token has no references" (let [tokens {"spacing" {:name "spacing" :value "16px"}}] (t/is (nil? (cfo/token-circular-reference? tokens "spacing"))))) (t/testing "returns nil for a simple non-circular reference chain" (let [tokens {"base" {:name "base" :value "10"} "large" {:name "large" :value "{base}"}}] (t/is (nil? (cfo/token-circular-reference? tokens "large"))))) (t/testing "detects direct self-reference" (let [tokens {"self" {:name "self" :value "{self}"}}] (t/is (= "self" (cfo/token-circular-reference? tokens "self"))))) (t/testing "detects indirect circular reference" (let [tokens {"a" {:name "a" :value "{b}"} "b" {:name "b" :value "{c}"} "c" {:name "c" :value "{a}"}}] (t/is (some? (cfo/token-circular-reference? tokens "a"))))) (t/testing "returns nil for diamond dependency (no cycle)" (let [tokens {"base" {:name "base" :value "10"} "left" {:name "left" :value "{base}"} "right" {:name "right" :value "{base}"} "combine" {:name "combine" :value "{left} {right}"}}] (t/is (nil? (cfo/token-circular-reference? tokens "combine"))))) (t/testing "returns nil when token name does not exist in tokens map" (let [tokens {"a" {:name "a" :value "10"}}] (t/is (nil? (cfo/token-circular-reference? tokens "nonexistent"))))) (t/testing "detects circular reference in map-typed values (typography composite)" (let [tokens {"family" {:name "family" :value "Arial"} "size" {:name "size" :value "16px"} "typog" {:name "typog" :value {:font-family {:reference "{family}"} :font-size {:reference "{size}"}}} "cycle" {:name "cycle" :value {:font-family {:reference "{typog}"}}}}] ;; typog references family and size (no cycle) (t/is (nil? (cfo/token-circular-reference? tokens "typog")))))) (t/deftest test-attributes-map (t/testing "creates map from attributes to token name" (t/is (= {:fill "primary" :stroke "primary"} (cfo/attributes-map [:fill :stroke] {:name "primary"})))) (t/testing "returns empty map for empty attributes" (t/is (= {} (cfo/attributes-map [] {:name "primary"})))) (t/testing "maps each attribute independently" (t/is (= {:x "t" :y "t" :z "t"} (cfo/attributes-map [:x :y :z] {:name "t"}))))) (t/deftest test-remove-attributes-for-token (t/testing "removes entries matching both attribute set and token name" (t/is (= {:stroke "other"} (cfo/remove-attributes-for-token [:fill :stroke] "primary" {:fill "primary" :stroke "other"})))) (t/testing "keeps entries with matching attribute but different token name" (t/is (= {:fill "secondary" :stroke "other"} (cfo/remove-attributes-for-token [:fill :stroke] "primary" {:fill "secondary" :stroke "other"})))) (t/testing "keeps entries with matching token name but non-matching attribute" (t/is (= {:opacity "primary"} (cfo/remove-attributes-for-token [:fill :stroke] "primary" {:fill "primary" :opacity "primary"})))) (t/testing "returns empty map when all entries match" (t/is (= {} (cfo/remove-attributes-for-token [:fill] "primary" {:fill "primary"})))) (t/testing "returns empty map for empty applied-tokens" (t/is (= {} (cfo/remove-attributes-for-token [:fill] "primary" {}))))) (t/deftest test-color-token? (t/testing "returns true for color type" (t/is (true? (cfo/color-token? {:type :color})))) (t/testing "returns false for non-color types" (t/is (false? (cfo/color-token? {:type :spacing}))) (t/is (false? (cfo/color-token? {:type :border-radius}))) (t/is (false? (cfo/color-token? {}))))) (t/deftest test-is-reference? (t/testing "returns truthy when value contains opening brace" (t/is (cfo/is-reference? {:value "{foo}"})) (t/is (cfo/is-reference? {:value "calc({bar} + 1)"}))) (t/testing "returns falsy when value has no brace" (t/is (not (cfo/is-reference? {:value "16px"}))) (t/is (not (cfo/is-reference? {:value ""}))))) (t/deftest test-parse-token-value (t/testing "parses double from a token value" (t/is (= {:value 100.1 :unit nil} (cfo/parse-token-value "100.1"))) (t/is (= {:value -9.0 :unit nil} (cfo/parse-token-value "-9")))) (t/testing "trims white-space" (t/is (= {:value -1.3 :unit nil} (cfo/parse-token-value " -1.3 ")))) (t/testing "parses unit: px" (t/is (= {:value 70.3 :unit "px"} (cfo/parse-token-value " 70.3px ")))) (t/testing "parses unit: %" (t/is (= {:value -10.0 :unit "%"} (cfo/parse-token-value "-10%")))) (t/testing "parses unit: px") (t/testing "returns nil for any invalid characters" (t/is (nil? (cfo/parse-token-value " -1.3a ")))) (t/testing "doesnt accept invalid double" (t/is (nil? (cfo/parse-token-value ".3"))))) (t/deftest convert-dtcg-token-test (t/testing "keeps string scalar values untouched" (t/is (= {:name "spacing.16" :type :spacing :value "16"} (cfo/convert-dtcg-token {"name" "spacing.16" "type" "spacing" "value" "16"}))) (t/is (= {:name "spacing.16" :type :spacing :value "16px"} (cfo/convert-dtcg-token {"name" "spacing.16" "type" "spacing" "value" "16px"})))) (t/testing "coerces numeric scalar values to strings" (t/is (= {:name "spacing.16" :type :spacing :value "16"} (cfo/convert-dtcg-token {"name" "spacing.16" "type" "spacing" "value" 16}))) (t/is (= {:name "radius" :type :border-radius :value "4"} (cfo/convert-dtcg-token {"name" "radius" "type" "borderRadius" "value" 4}))))) (t/deftest token-applied-test (t/testing "matches passed token with `:token-attributes`" (t/is (true? (cfo/token-applied? {:name "a"} {:applied-tokens {:x "a"}} #{:x})))) (t/testing "doesn't match empty token" (t/is (nil? (cfo/token-applied? {} {:applied-tokens {:x "a"}} #{:x})))) (t/testing "does't match passed token `:id`" (t/is (nil? (cfo/token-applied? {:name "b"} {:applied-tokens {:x "a"}} #{:x})))) (t/testing "doesn't match passed `:token-attributes`" (t/is (nil? (cfo/token-applied? {:name "a"} {:applied-tokens {:x "a"}} #{:y}))))) (t/deftest shapes-ids-by-applied-attributes (t/testing "Returns set of matched attributes that fit the applied token" (let [attributes #{:x :y :z} shape-applied-x {:id "shape-applied-x" :applied-tokens {:x "1"}} shape-applied-y {:id "shape-applied-y" :applied-tokens {:y "1"}} shape-applied-x-y {:id "shape-applied-x-y" :applied-tokens {:x "1" :y "1"}} shape-applied-none {:id "shape-applied-none" :applied-tokens {}} shape-applied-all {:id "shape-applied-all" :applied-tokens {:x "1" :y "1" :z "1"}} shape-ids (fn [& xs] (into #{} (map :id xs))) shapes [shape-applied-x shape-applied-y shape-applied-x-y shape-applied-all shape-applied-none] expected (cfo/shapes-ids-by-applied-attributes {:name "1"} shapes attributes)] (t/is (= (:x expected) (shape-ids shape-applied-x shape-applied-x-y shape-applied-all))) (t/is (= (:y expected) (shape-ids shape-applied-y shape-applied-x-y shape-applied-all))) (t/is (= (:z expected) (shape-ids shape-applied-all))) (t/is (true? (cfo/shapes-applied-all? expected (shape-ids shape-applied-all) attributes))) (t/is (false? (cfo/shapes-applied-all? expected (apply shape-ids shapes) attributes))) (shape-ids shape-applied-x shape-applied-x-y shape-applied-all)))) (t/deftest tokens-applied-test (t/testing "is true when single shape matches the token and attributes" (t/is (true? (cfo/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "a"}} {:applied-tokens {:x "b"}}] #{:x})))) (t/testing "is false when no shape matches the token or attributes" (t/is (nil? (cfo/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "b"}} {:applied-tokens {:x "b"}}] #{:x}))) (t/is (nil? (cfo/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "a"}} {:applied-tokens {:x "a"}}] #{:y}))))) ;; Tokens lib in file data (t/deftest test-ensure-tokens-lib (t/testing "ensure-tokens-lib should add a tokens-lib and tokens-status to the file data if they are missing" (let [file (thf/sample-file :file1) file-data (ctf/file-data file) file-data' (cfo/ensure-tokens-lib file-data)] (t/is (contains? file-data' :tokens-lib)) (t/is (ctob/tokens-lib? (:tokens-lib file-data'))) (t/is (contains? file-data' :tokens-status)) (t/is (ctos/tokens-status? (:tokens-status file-data'))))) (t/testing "ensure-tokens-lib should add a tokens-lib to the file data if it's missing" (let [tokens-status (ctos/make-tokens-status) file (-> (thf/sample-file :file1) (assoc-in [:data :tokens-status] tokens-status)) file-data (ctf/file-data file) file-data' (cfo/ensure-tokens-lib file-data)] (t/is (contains? file-data' :tokens-lib)) (t/is (ctob/tokens-lib? (:tokens-lib file-data'))) (t/is (= tokens-status (:tokens-status file-data'))))) (t/testing "ensure-tokens-lib should add a tokens-status to the file data if it's missing" (let [tokens-lib (ctob/make-tokens-lib) file (-> (thf/sample-file :file1) (assoc-in [:data :tokens-lib] tokens-lib)) file-data (ctf/file-data file) file-data' (cfo/ensure-tokens-lib file-data)] (t/is (= tokens-lib (:tokens-lib file-data'))) (t/is (contains? file-data' :tokens-status)) (t/is (ctos/tokens-status? (:tokens-status file-data'))))) (t/testing "ensure-tokens-lib should not add a tokens-lib if there is a tokens-source" (let [source-id (uuid/next) tokens-status (ctos/make-tokens-status) file (-> (thf/sample-file :file1) (assoc-in [:data :tokens-source] source-id) (assoc-in [:data :tokens-status] tokens-status)) file-data (ctf/file-data file) file-data' (cfo/ensure-tokens-lib file-data)] (t/is (not (contains? file-data' :tokens-lib))) (t/is (= source-id (:tokens-source file-data'))) (t/is (= tokens-status (:tokens-status file-data'))))) (t/testing "ensure-tokens-lib should not add a tokens-lib if there is a tokens-source, but should add a tokens-status if it's missing" (let [source-id (uuid/next) file (-> (thf/sample-file :file1) (assoc-in [:data :tokens-source] source-id)) file-data (ctf/file-data file) file-data' (cfo/ensure-tokens-lib file-data)] (t/is (not (contains? file-data' :tokens-lib))) (t/is (= source-id (:tokens-source file-data'))) (t/is (contains? file-data' :tokens-status)) (t/is (ctos/tokens-status? (:tokens-status file-data')))))) (t/deftest test-get-tokens-lib (t/testing "returns tokens-lib from file data" (let [tokens-lib (ctob/make-tokens-lib) file-data {:tokens-lib tokens-lib}] (t/is (= tokens-lib (cfo/get-tokens-lib file-data))))) (t/testing "returns nil when no tokens-lib" (t/is (nil? (cfo/get-tokens-lib {}))))) (t/deftest test-get-tokens-source (t/testing "returns tokens-source from file data" (let [source-id (thi/new-id! :tokens-source) file (-> (thf/sample-file :file1) (assoc-in [:data :tokens-source] source-id))] (t/is (= source-id (cfo/get-tokens-source (:data file)))))) (t/testing "returns nil when no tokens-source" (let [file (thf/sample-file :file1)] (t/is (nil? (cfo/get-tokens-source (:data file))))))) (t/deftest test-get-effective-tokens-source (t/testing "returns tokens-source from file data" (let [source-id (thi/new-id! :tokens-source) file (-> (thf/sample-file :file1) (assoc-in [:data :tokens-source] source-id))] (t/is (= source-id (cfo/get-effective-tokens-source (:data file)))))) (t/testing "returns file id when no tokens-source" (let [file (thf/sample-file :file1)] (t/is (= (:id file) (cfo/get-effective-tokens-source file)))))) (t/deftest test-set-tokens-source (t/testing "sets tokens-source on file data" (let [source-id (thi/new-id! :tokens-source) file (thf/sample-file :file1) file-data (:data file) file-data' (cfo/set-tokens-source file-data source-id)] (t/is (= source-id (:tokens-source file-data')))))) (t/deftest test-effective-tokens-source? (t/testing "no tokens, no tokens-source, ask for file id -> true" (let [file (thf/sample-file :file1) file-data (:data file)] (t/is (true? (cfo/effective-tokens-source? file-data (:id file-data)))))) (t/testing "empty tokens-lib, no tokens-source, ask for file id -> true" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib)) file-data (:data file)] (t/is (true? (cfo/effective-tokens-source? file-data (:id file-data)))))) (t/testing "tokens, no tokens-source, ask for file id -> true" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib #(-> % (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) file-data (:data file)] (t/is (true? (cfo/effective-tokens-source? file-data (:id file-data)))))) (t/testing "no tokens, no tokens source, ask for other id -> false" (let [file (thf/sample-file :file1) file-data (:data file)] (t/is (false? (cfo/effective-tokens-source? file-data (uuid/next)))))) (t/testing "empty tokens-lib, no tokens source, ask for other id -> false" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib)) file-data (:data file)] (t/is (false? (cfo/effective-tokens-source? file-data (uuid/next)))))) (t/testing "tokens, no tokens source, ask for other id -> false" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib #(-> % (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) file-data (:data file)] (t/is (false? (cfo/effective-tokens-source? file-data (uuid/next)))))) ;; --- (t/testing "no tokens, tokens source = file id, ask for file id -> true" ;; This case should not occur (let [file (thf/sample-file :file1) file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] (t/is (true? (cfo/effective-tokens-source? file-data (:id file-data)))))) (t/testing "empty tokens-lib, tokens source = file id, ask for file id -> true" ;; This case should not occur (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib)) file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] (t/is (true? (cfo/effective-tokens-source? file-data (:id file-data)))))) (t/testing "tokens, tokens source = file id, ask for file id -> true" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib #(-> % (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] (t/is (true? (cfo/effective-tokens-source? file-data (:id file-data)))))) (t/testing "no tokens, tokens source = file id, ask for other id -> false" ;; This case should not occur (let [file (thf/sample-file :file1) file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] (t/is (false? (cfo/effective-tokens-source? file-data (uuid/next)))))) (t/testing "empty tokens-lib, tokens source = file id, ask for other id -> false" ;; This case should not occur (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib)) file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] (t/is (false? (cfo/effective-tokens-source? file-data (uuid/next)))))) (t/testing "tokens, tokens source = file id, ask for other id -> false" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib #(-> % (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] (t/is (false? (cfo/effective-tokens-source? file-data (uuid/next)))))) ;; --- (t/testing "no tokens, tokens source = other id, ask for file id -> false" (let [source-id (thi/new-id! :tokens-source) file (thf/sample-file :file1) file-data (cfo/set-tokens-source (:data file) source-id)] (t/is (false? (cfo/effective-tokens-source? file-data (:id file-data)))))) (t/testing "empty tokens-lib, tokens source = other id, ask for file id -> false" (let [source-id (thi/new-id! :tokens-source) file (-> (thf/sample-file :file1) (tht/add-tokens-lib)) file-data (cfo/set-tokens-source (:data file) source-id)] (t/is (false? (cfo/effective-tokens-source? file-data (:id file-data)))))) (t/testing "tokens, tokens source = other id, ask for file id -> false" (let [source-id (thi/new-id! :tokens-source) file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib #(-> % (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) file-data (cfo/set-tokens-source (:data file) source-id)] (t/is (false? (cfo/effective-tokens-source? file-data (:id file-data)))))) (t/testing "no tokens, tokens source = other id, ask for this same id -> true" (let [source-id (thi/new-id! :tokens-source) file (thf/sample-file :file1) file-data (cfo/set-tokens-source (:data file) source-id)] (t/is (true? (cfo/effective-tokens-source? file-data source-id))))) (t/testing "empty tokens-lib, tokens source = other id, ask for this same id -> true" (let [source-id (thi/new-id! :tokens-source) file (-> (thf/sample-file :file1) (tht/add-tokens-lib)) file-data (cfo/set-tokens-source (:data file) source-id)] (t/is (true? (cfo/effective-tokens-source? file-data source-id))))) (t/testing "tokens, tokens source = other id, ask for this same id -> true" (let [source-id (thi/new-id! :tokens-source) file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib #(-> % (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) file-data (cfo/set-tokens-source (:data file) source-id)] (t/is (true? (cfo/effective-tokens-source? file-data source-id))))) (t/testing "no tokens, tokens source = other id, ask for a different id -> false" (let [source-id (thi/new-id! :tokens-source) file (thf/sample-file :file1) file-data (cfo/set-tokens-source (:data file) source-id)] (t/is (false? (cfo/effective-tokens-source? file-data (uuid/next)))))) (t/testing "empty tokens-lib, tokens source = other id, ask for a different id -> false" (let [source-id (thi/new-id! :tokens-source) file (-> (thf/sample-file :file1) (tht/add-tokens-lib)) file-data (cfo/set-tokens-source (:data file) source-id)] (t/is (false? (cfo/effective-tokens-source? file-data (uuid/next)))))) (t/testing "tokens, tokens source = other id, ask for a different id -> false" (let [source-id (thi/new-id! :tokens-source) file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib #(-> % (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) file-data (cfo/set-tokens-source (:data file) source-id)] (t/is (false? (cfo/effective-tokens-source? file-data (uuid/next))))))) (t/deftest test-has-own-tokens? (t/testing "no tokens-lib -> false" (let [file (thf/sample-file :file1) file-data (:data file)] (t/is (false? (cfo/has-own-tokens? file-data))))) (t/testing "empty tokens-lib -> false" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib)) file-data (:data file)] (t/is (false? (cfo/has-own-tokens? file-data))))) (t/testing "tokens lib with data -> true" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib #(-> % (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) file-data (:data file)] (t/is (true? (cfo/has-own-tokens? file-data)))))) (t/deftest test-tokens-provider? (t/testing "returns false if it has no tokens" (let [file (thf/sample-file :file1) file-data (:data file)] (t/is (false? (cfo/tokens-provider? file-data))))) (t/testing "returns false if it has an empty tokens-lib and no tokens-source" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib)) file-data (:data file)] (t/is (false? (cfo/tokens-provider? file-data))))) (t/testing "returns false if it has an empty tokens lib and tokens-source is its own id" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib)) file-data (cfo/set-tokens-source (:data file) (:id file))] (t/is (false? (cfo/tokens-provider? file-data))))) (t/testing "returns true if it has tokens and no tokens-source" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib #(-> % (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) file-data (:data file)] (t/is (true? (cfo/tokens-provider? file-data))))) (t/testing "returns true if it has tokens and tokens-source is its own id" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib #(-> % (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) file-data (cfo/set-tokens-source (:data file) (:id file))] (t/is (true? (cfo/tokens-provider? file-data))))) (t/testing "returns false if it has tokens and tokens-source is other id" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib #(-> % (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) file-data (cfo/set-tokens-source (:data file) (uuid/next))] (t/is (false? (cfo/tokens-provider? file-data)))))) (t/deftest test-editable-tokens? (t/testing "returns true when file-data has no tokens-source" (let [file (thf/sample-file :file1) file-data (:data file)] (t/is (true? (cfo/editable-tokens? file-data))))) (t/testing "returns true when tokens-source is the file's own id" (let [file (thf/sample-file :file1) file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] (t/is (true? (cfo/editable-tokens? file-data))))) (t/testing "returns false when tokens-source is a different uuid" (let [source-id (thi/new-id! :tokens-source) file (thf/sample-file :file1) file-data (cfo/set-tokens-source (:data file) source-id)] (t/is (false? (cfo/editable-tokens? file-data)))))) (t/deftest test-get-tokens-status (t/testing "returns tokens-status from file data" (let [tokens-status (ctos/make-tokens-status) file-data {:tokens-status tokens-status}] (t/is (= tokens-status (cfo/get-tokens-status file-data))))) (t/testing "returns nil when no tokens-status" (t/is (nil? (cfo/get-tokens-status {}))))) (t/deftest test-update-tokens-lib (t/testing "update when there is no tokens-lib has no effect" (let [file (thf/sample-file :file1) file' (cfo/update-tokens-lib file #(t/is false "This should not be called"))] (t/is (= file file')))) (t/testing "update a tokens-lib applies the changes correctly" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib)) file' (ctf/update-file-data file #(cfo/update-tokens-lib % ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme1) :name "theme 1"))) tokens-lib' (tht/get-tokens-lib file')] (t/is (= 2 (ctob/theme-count tokens-lib'))) ;; Count the hidden theme (t/is (ctob/token-theme? (ctob/get-theme tokens-lib' (thi/id :theme1))))))) (t/deftest test-update-tokens-status (t/testing "update when there is no tokens-status has no effect" (let [file (thf/sample-file :file1) file' (cfo/update-tokens-status file #(t/is false "This should not be called"))] (t/is (= file file')))) (t/testing "update a tokens-status applies the changes correctly" (let [file (-> (thf/sample-file :file1) (tht/add-tokens-lib) (tht/update-tokens-lib (fn [tokens-lib] (-> tokens-lib (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme1) :name "theme")))))) file' (ctf/update-file-data file #(cfo/update-tokens-status % ctos/set-tokens-status #{(thi/id :theme1)} #{})) tokens-status' (tht/get-tokens-status file')] (t/is (= 1 (count (ctos/get-active-theme-ids tokens-status')))) (t/is (ctos/theme-active? tokens-status' (thi/id :theme1))) (t/is (= 0 (count (ctos/get-active-set-ids tokens-status'))))))) ;; Tokens status with tokens lib ;; This is a private function but it deserves specific tests for all use cases (def calculate-active-sets #'app.common.files.tokens/calculate-active-sets) (t/deftest test-calculate-active-sets (t/testing "returns union of sets from all active themes" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-b) :name "set-b")) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-c) :name "set-c")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a" "set-b"})) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-2) :name "theme-2" :group "" :sets #{"set-c"})))] (t/is (= #{(thi/id :set-a) (thi/id :set-b) (thi/id :set-c)} (calculate-active-sets #{(thi/id :theme-1) (thi/id :theme-2)} tokens-lib))))) (t/testing "deduplicates sets shared by multiple active themes" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-b) :name "set-b")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a" "set-b"})) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-2) :name "theme-2" :group "" :sets #{"set-b"})))] (t/is (= #{(thi/id :set-a) (thi/id :set-b)} (calculate-active-sets #{(thi/id :theme-1) (thi/id :theme-2)} tokens-lib))))) (t/testing "returns empty set when active-theme-ids is empty" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a"})))] (t/is (= #{} (calculate-active-sets #{} tokens-lib))))) (t/testing "ignores active themes that do not exist in the lib" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a"})))] (t/is (= #{(thi/id :set-a)} (calculate-active-sets #{(thi/id :theme-1) (thi/new-id! :nonexistent)} tokens-lib))))) (t/testing "ignores set names that do not exist in the lib" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a" "nonexistent-set"})))] (t/is (contains? (calculate-active-sets #{(thi/id :theme-1)} tokens-lib) (thi/id :set-a))) (t/is (= 2 (count (calculate-active-sets #{(thi/id :theme-1)} tokens-lib)))))) (t/testing "returns empty set when themes have no sets" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{})))] (t/is (= #{} (calculate-active-sets #{(thi/id :theme-1)} tokens-lib))))) (t/testing "returns empty set when there are no themes" (let [tokens-lib (-> (ctob/make-tokens-lib))] (t/is (= #{} (calculate-active-sets #{} tokens-lib)))))) (t/deftest test-get-active-themes (t/testing "returns only themes that are active in the status" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-2) :name "theme-2" :group "")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-3) :name "theme-3" :group ""))) tokens-status (ctos/make-tokens-status :active-theme-ids #{(thi/id :theme-1) (thi/id :theme-3)} :active-set-ids #{})] (t/is (= 2 (count (cfo/get-active-themes tokens-status tokens-lib)))) (let [active-ids (into #{} (map ctob/get-id) (cfo/get-active-themes tokens-status tokens-lib))] (t/is (contains? active-ids (thi/id :theme-1))) (t/is (contains? active-ids (thi/id :theme-3))) (t/is (not (contains? active-ids (thi/id :theme-2))))))) (t/testing "returns empty sequence when no themes are active" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group ""))) tokens-status (ctos/make-tokens-status :active-theme-ids #{} :active-set-ids #{})] (t/is (empty? (cfo/get-active-themes tokens-status tokens-lib))))) (t/testing "returns empty sequence when tokens-lib has no themes" (let [tokens-lib (ctob/make-tokens-lib) tokens-status (ctos/make-tokens-status)] (t/is (empty? (cfo/get-active-themes tokens-status tokens-lib))))) (t/testing "active theme ids in status that do not exist in lib are silently ignored" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group ""))) tokens-status (ctos/make-tokens-status :active-theme-ids #{(thi/id :theme-1) (thi/new-id! :nonexistent)} :active-set-ids #{})] (t/is (= 1 (count (cfo/get-active-themes tokens-status tokens-lib))))))) (t/deftest test-activate-theme (t/testing "activating a theme sets it as active" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status) tokens-status' (cfo/activate-theme tokens-status tokens-lib (thi/id :theme-1))] (t/is (ctos/theme-active? tokens-status' (thi/id :theme-1))))) (t/testing "activating a theme deactivates other themes in the same group" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-b) :name "set-b")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "colors" :sets #{"set-a"})) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-2) :name "theme-2" :group "colors" :sets #{"set-b"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{(thi/id :theme-1)} :active-set-ids #{(thi/id :set-a)}) tokens-status' (cfo/activate-theme tokens-status tokens-lib (thi/id :theme-2))] (t/is (ctos/theme-active? tokens-status' (thi/id :theme-2))) (t/is (not (ctos/theme-active? tokens-status' (thi/id :theme-1)))))) (t/testing "themes in different groups can be active simultaneously" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-b) :name "set-b")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "colors" :sets #{"set-a"})) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-2) :name "theme-2" :group "spacing" :sets #{"set-b"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{(thi/id :theme-1)} :active-set-ids #{(thi/id :set-a)}) tokens-status' (cfo/activate-theme tokens-status tokens-lib (thi/id :theme-2))] (t/is (ctos/theme-active? tokens-status' (thi/id :theme-1))) (t/is (ctos/theme-active? tokens-status' (thi/id :theme-2))))) (t/testing "activating an already-active theme returns status unchanged" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{(thi/id :theme-1)} :active-set-ids #{(thi/id :set-a)}) tokens-status' (cfo/activate-theme tokens-status tokens-lib (thi/id :theme-1))] (t/is (identical? tokens-status tokens-status')))) (t/testing "activating a non-existent theme returns status unchanged" (let [tokens-lib (ctob/make-tokens-lib) tokens-status (ctos/make-tokens-status) tokens-status' (cfo/activate-theme tokens-status tokens-lib (thi/new-id! :nonexistent))] (t/is (identical? tokens-status tokens-status'))))) (t/deftest test-deactivate-theme (t/testing "deactivating an active theme removes it from active themes" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{(thi/id :theme-1)} :active-set-ids #{(thi/id :set-a)}) tokens-status' (cfo/deactivate-theme tokens-status tokens-lib (thi/id :theme-1))] (t/is (not (ctos/theme-active? tokens-status' (thi/id :theme-1)))))) (t/testing "deactivating a theme removes sets not used by remaining active themes" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-b) :name "set-b")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a"})) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-2) :name "theme-2" :group "" :sets #{"set-b"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{(thi/id :theme-1) (thi/id :theme-2)} :active-set-ids #{(thi/id :set-a) (thi/id :set-b)}) tokens-status' (cfo/deactivate-theme tokens-status tokens-lib (thi/id :theme-1))] (t/is (not (ctos/theme-active? tokens-status' (thi/id :theme-1)))) (t/is (ctos/theme-active? tokens-status' (thi/id :theme-2))))) (t/testing "deactivating an already-inactive theme returns status unchanged" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group ""))) tokens-status (ctos/make-tokens-status) tokens-status' (cfo/deactivate-theme tokens-status tokens-lib (thi/id :theme-1))] (t/is (identical? tokens-status tokens-status')))) (t/testing "deactivating a non-existent theme returns status unchanged" (let [tokens-lib (ctob/make-tokens-lib) tokens-status (ctos/make-tokens-status) tokens-status' (cfo/deactivate-theme tokens-status tokens-lib (thi/new-id! :nonexistent))] (t/is (identical? tokens-status tokens-status'))))) (t/deftest test-toggle-theme-active (t/testing "activates an inactive theme" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status) tokens-status' (cfo/toggle-theme-active tokens-status tokens-lib (thi/id :theme-1))] (t/is (ctos/theme-active? tokens-status' (thi/id :theme-1))))) (t/testing "deactivates an active theme" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{(thi/id :theme-1)} :active-set-ids #{(thi/id :set-a)}) tokens-status' (cfo/toggle-theme-active tokens-status tokens-lib (thi/id :theme-1))] (t/is (not (ctos/theme-active? tokens-status' (thi/id :theme-1))))))) (t/deftest test-set-theme-active (t/testing "activates a theme when active? is true" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status) tokens-status' (cfo/set-theme-active tokens-status tokens-lib (thi/id :theme-1) true)] (t/is (ctos/theme-active? tokens-status' (thi/id :theme-1))))) (t/testing "deactivates a theme when active? is false" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1) :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{(thi/id :theme-1)} :active-set-ids #{(thi/id :set-a)}) tokens-status' (cfo/set-theme-active tokens-status tokens-lib (thi/id :theme-1) false)] (t/is (not (ctos/theme-active? tokens-status' (thi/id :theme-1))))))) (t/deftest test-get-active-sets (t/testing "returns active sets resolved from status and lib" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "set-b"))) tokens-status (ctos/make-tokens-status :active-set-ids #{set-a-id}) active-sets (cfo/get-active-sets tokens-status tokens-lib)] (t/is (= 1 (count active-sets))) (t/is (= set-a-id (ctob/get-id (first active-sets)))))) (t/testing "returns empty set when no sets are active" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a"))) tokens-status (ctos/make-tokens-status) active-sets (cfo/get-active-sets tokens-status tokens-lib)] (t/is (empty? active-sets))))) (t/deftest test-set-set-active (t/testing "activates a set and clears all themes" (let [set-a-id (thi/new-id! :set-a) theme-1-id (thi/new-id! :theme-1) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id} :active-set-ids #{}) tokens-status' (cfo/set-set-active tokens-status tokens-lib set-a-id true)] (t/is (ctos/set-active? tokens-status' set-a-id)) (t/is (= #{} (ctos/get-active-theme-ids tokens-status'))))) (t/testing "deactivates a set and clears all themes" (let [set-a-id (thi/new-id! :set-a) theme-1-id (thi/new-id! :theme-1) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id} :active-set-ids #{set-a-id}) tokens-status' (cfo/set-set-active tokens-status tokens-lib set-a-id false)] (t/is (not (ctos/set-active? tokens-status' set-a-id))) (t/is (= #{} (ctos/get-active-theme-ids tokens-status'))))) (t/testing "returns same status when set is already in target state" (let [set-a-id (thi/new-id! :set-a) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a"))) tokens-status (ctos/make-tokens-status :active-set-ids #{set-a-id}) tokens-status' (cfo/set-set-active tokens-status tokens-lib set-a-id true)] (t/is (identical? tokens-status tokens-status')))) (t/testing "returns same status for non-existent set" (let [tokens-lib (ctob/make-tokens-lib) tokens-status (ctos/make-tokens-status) tokens-status' (cfo/set-set-active tokens-status tokens-lib (thi/new-id! :nonexistent) true)] (t/is (identical? tokens-status tokens-status'))))) (t/deftest test-activate-set (t/testing "delegates to set-set-active with true" (let [set-a-id (thi/new-id! :set-a) theme-1-id (thi/new-id! :theme-1) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status) tokens-status' (cfo/activate-set tokens-status tokens-lib set-a-id)] (t/is (ctos/set-active? tokens-status' set-a-id)) (t/is (= #{} (ctos/get-active-theme-ids tokens-status')))))) (t/deftest test-deactivate-set (t/testing "delegates to set-set-active with false" (let [set-a-id (thi/new-id! :set-a) theme-1-id (thi/new-id! :theme-1) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id} :active-set-ids #{set-a-id}) tokens-status' (cfo/deactivate-set tokens-status tokens-lib set-a-id)] (t/is (not (ctos/set-active? tokens-status' set-a-id))) (t/is (= #{} (ctos/get-active-theme-ids tokens-status')))))) (t/deftest test-toggle-set-active (t/testing "activates an inactive set" (let [set-a-id (thi/new-id! :set-a) theme-1-id (thi/new-id! :theme-1) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id} :active-set-ids #{}) tokens-status' (cfo/toggle-set-active tokens-status tokens-lib set-a-id)] (t/is (ctos/set-active? tokens-status' set-a-id)) (t/is (= #{} (ctos/get-active-theme-ids tokens-status'))))) (t/testing "deactivates an active set" (let [set-a-id (thi/new-id! :set-a) theme-1-id (thi/new-id! :theme-1) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id} :active-set-ids #{set-a-id}) tokens-status' (cfo/toggle-set-active tokens-status tokens-lib set-a-id)] (t/is (not (ctos/set-active? tokens-status' set-a-id))) (t/is (= #{} (ctos/get-active-theme-ids tokens-status')))))) (t/deftest test-sets-at-path-all-active? (t/testing "returns :all when all sets at path are active" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "group/set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "group/set-b"))) tokens-status (ctos/make-tokens-status :active-set-ids #{set-a-id set-b-id})] (t/is (= :all (cfo/sets-at-path-all-active? tokens-status tokens-lib ["group"]))))) (t/testing "returns :none when no sets at path are active" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "group/set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "group/set-b"))) tokens-status (ctos/make-tokens-status :active-set-ids #{})] (t/is (= :none (cfo/sets-at-path-all-active? tokens-status tokens-lib ["group"]))))) (t/testing "returns :partial when some sets at path are active" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "group/set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "group/set-b"))) tokens-status (ctos/make-tokens-status :active-set-ids #{set-a-id})] (t/is (= :partial (cfo/sets-at-path-all-active? tokens-status tokens-lib ["group"]))))) (t/testing "returns :none for empty path when no sets exist at root" (let [tokens-lib (ctob/make-tokens-lib) tokens-status (ctos/make-tokens-status)] (t/is (= :none (cfo/sets-at-path-all-active? tokens-status tokens-lib []))))) (t/testing "several combinations with longer paths" (let [baz-id (thi/new-id! :baz) bam-id (thi/new-id! :bam) none-id (thi/new-id! :none) partial-id (thi/new-id! :partial) all-id (thi/new-id! :all) invalid-id (thi/new-id! :invalid) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id baz-id :name "foo/bar/baz")) (ctob/add-set (ctob/make-token-set :id bam-id :name "foo/bar/bam")) (ctob/add-theme (ctob/make-token-theme :id none-id :name "none")) (ctob/add-theme (ctob/make-token-theme :id partial-id :name "partial" :sets #{"foo/bar/baz"})) (ctob/add-theme (ctob/make-token-theme :id all-id :name "all" :sets #{"foo/bar/baz" "foo/bar/bam"})) (ctob/add-theme (ctob/make-token-theme :id invalid-id :name "invalid" :sets #{"foo/missing"}))) expected-none (-> (ctos/make-tokens-status {:active-theme-ids #{none-id} :active-set-ids #{}}) (cfo/sets-at-path-all-active? tokens-lib ["foo"])) expected-all (-> (ctos/make-tokens-status {:active-theme-ids #{all-id} :active-set-ids #{baz-id bam-id}}) (cfo/sets-at-path-all-active? tokens-lib ["foo"])) expected-partial (-> (ctos/make-tokens-status {:active-theme-ids #{partial-id} :active-set-ids #{baz-id}}) (cfo/sets-at-path-all-active? tokens-lib ["foo"])) expected-invalid-none (-> (ctos/make-tokens-status {:active-theme-ids #{invalid-id} :active-set-ids #{}}) (cfo/sets-at-path-all-active? tokens-lib ["foo"]))] (t/is (= :none expected-none)) (t/is (= :all expected-all)) (t/is (= :partial expected-partial)) (t/is (= :none expected-invalid-none))))) (t/deftest test-toggle-set-group-active (t/testing "activates all sets in group when none are active, and deactivate all themes" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) set-c-id (thi/new-id! :set-c) theme-1-id (thi/new-id! :theme-1) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "group/set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "group/set-b")) (ctob/add-set (ctob/make-token-set :id set-c-id :name "group/set-b/child")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id} :active-set-ids #{}) tokens-status' (cfo/toggle-set-group-active tokens-status tokens-lib ["group"])] (t/is (ctos/set-active? tokens-status' set-a-id)) (t/is (ctos/set-active? tokens-status' set-b-id)) (t/is (ctos/set-active? tokens-status' set-c-id)) (t/is (= #{} (ctos/get-active-theme-ids tokens-status'))))) (t/testing "deactivates all sets in group when all are active, and deactivate all themes" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) set-c-id (thi/new-id! :set-c) theme-1-id (thi/new-id! :theme-1) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "group/set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "group/set-b")) (ctob/add-set (ctob/make-token-set :id set-c-id :name "group/set-b/child")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"group/set-a" "group/set-b" "group/set-b/child"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id} :active-set-ids #{set-a-id set-b-id set-c-id}) tokens-status' (cfo/toggle-set-group-active tokens-status tokens-lib ["group"])] (t/is (not (ctos/set-active? tokens-status' set-a-id))) (t/is (not (ctos/set-active? tokens-status' set-b-id))) (t/is (not (ctos/set-active? tokens-status' set-c-id))) (t/is (= #{} (ctos/get-active-theme-ids tokens-status'))))) (t/testing "deactivates all sets in group when only some are active, and deactivate all themes" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) set-c-id (thi/new-id! :set-c) theme-1-id (thi/new-id! :theme-1) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "group/set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "group/set-b")) (ctob/add-set (ctob/make-token-set :id set-c-id :name "group/set-b/child")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id} :active-set-ids #{set-a-id}) tokens-status' (cfo/toggle-set-group-active tokens-status tokens-lib ["group"])] (t/is (not (ctos/set-active? tokens-status' set-a-id))) (t/is (not (ctos/set-active? tokens-status' set-b-id))) (t/is (not (ctos/set-active? tokens-status' set-c-id))) (t/is (= #{} (ctos/get-active-theme-ids tokens-status')))))) (t/deftest test-get-tokens-in-active-sets (t/testing "returns merged tokens from active sets in set order" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) tok-a (ctob/make-token :name "spacing" :type :spacing :value "8px") tok-b (ctob/make-token :name "radius" :type :border-radius :value "4px") tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "set-b")) (ctob/add-token set-a-id tok-a) (ctob/add-token set-b-id tok-b)) tokens-status (ctos/make-tokens-status :active-set-ids #{set-a-id set-b-id}) tokens (cfo/get-tokens-in-active-sets tokens-status tokens-lib)] (t/is (= 2 (count tokens))) (t/is (contains? tokens "spacing")) (t/is (contains? tokens "radius")))) (t/testing "later active sets override earlier sets with same token name" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) tok-a (ctob/make-token :name "spacing" :type :spacing :value "8px") tok-b (ctob/make-token :name "spacing" :type :spacing :value "16px") tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "set-b")) (ctob/add-token set-a-id tok-a) (ctob/add-token set-b-id tok-b)) tokens-status (ctos/make-tokens-status :active-set-ids #{set-a-id set-b-id}) tokens (cfo/get-tokens-in-active-sets tokens-status tokens-lib)] (t/is (= 1 (count tokens))) (t/is (= "16px" (:value (get tokens "spacing")))))) (t/testing "tokens in inactive sets are not included" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) tok-a (ctob/make-token :name "spacing" :type :spacing :value "8px") tok-b (ctob/make-token :name "spacing" :type :spacing :value "16px") tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "set-b")) (ctob/add-token set-a-id tok-a) (ctob/add-token set-b-id tok-b)) tokens-status (ctos/make-tokens-status :active-set-ids #{set-a-id}) tokens (cfo/get-tokens-in-active-sets tokens-status tokens-lib)] (t/is (= 1 (count tokens))) (t/is (= "8px" (:value (get tokens "spacing")))))) (t/testing "returns empty map when no sets are active" (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a"))) tokens-status (ctos/make-tokens-status) tokens (cfo/get-tokens-in-active-sets tokens-status tokens-lib)] (t/is (empty? tokens)))) (t/testing "returns empty map when empty lib" (let [tokens-lib (ctob/make-tokens-lib) tokens-status (ctos/make-tokens-status) tokens (cfo/get-tokens-in-active-sets tokens-status tokens-lib)] (t/is (empty? tokens))))) (t/deftest test-get-tokens-in-active-sets-force (t/testing "includes force-set-id even when not in active sets" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) tok-a (ctob/make-token :name "spacing" :type :spacing :value "8px") tok-b (ctob/make-token :name "radius" :type :border-radius :value "4px") tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "set-b")) (ctob/add-token set-a-id tok-a) (ctob/add-token set-b-id tok-b)) tokens-status (ctos/make-tokens-status :active-set-ids #{set-a-id}) tokens (cfo/get-tokens-in-active-sets-force tokens-status tokens-lib set-b-id)] (t/is (= 2 (count tokens))) (t/is (contains? tokens "spacing")) (t/is (contains? tokens "radius")))) (t/testing "active set tokens override force-set tokens with same name" (let [set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) tok-a (ctob/make-token :name "spacing" :type :spacing :value "8px") tok-b (ctob/make-token :name "spacing" :type :spacing :value "32px") tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "set-b")) (ctob/add-token set-a-id tok-a) (ctob/add-token set-b-id tok-b)) tokens-status (ctos/make-tokens-status :active-set-ids #{set-a-id}) tokens (cfo/get-tokens-in-active-sets-force tokens-status tokens-lib set-b-id)] (t/is (= 1 (count tokens))) (t/is (= "8px" (:value (get tokens "spacing"))))))) (t/deftest test-sync-tokens-status-with-lib (t/testing "removes theme ids that no longer exist in the lib" (let [theme-1-id (thi/new-id! :theme-1) set-a-id (thi/new-id! :set-a) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id (thi/new-id! :removed-theme)} :active-set-ids #{set-a-id}) tokens-status' (cfo/sync-tokens-status-with-lib tokens-status tokens-lib)] (t/is (= #{theme-1-id} (ctos/get-active-theme-ids tokens-status'))) (t/is (ctos/theme-active? tokens-status' theme-1-id)))) (t/testing "removes set ids that no longer exist in the lib (active themes)" (let [theme-1-id (thi/new-id! :theme-1) set-a-id (thi/new-id! :set-a) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id} :active-set-ids #{set-a-id (thi/new-id! :removed-set)}) tokens-status' (cfo/sync-tokens-status-with-lib tokens-status tokens-lib)] (t/is (= #{set-a-id} (ctos/get-active-set-ids tokens-status'))))) (t/testing "removes set ids that no longer exist in the lib (no active themes)" (let [theme-1-id (thi/new-id! :theme-1) set-a-id (thi/new-id! :set-a) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{} :active-set-ids #{set-a-id (thi/new-id! :removed-set)}) tokens-status' (cfo/sync-tokens-status-with-lib tokens-status tokens-lib)] (t/is (= #{set-a-id} (ctos/get-active-set-ids tokens-status'))))) (t/testing "updates active sets when theme changes" (let [theme-1-id (thi/new-id! :theme-1) set-a-id (thi/new-id! :set-a) set-b-id (thi/new-id! :set-b) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-set (ctob/make-token-set :id set-b-id :name "set-b")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"set-b"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id} :active-set-ids #{set-a-id (thi/new-id! :removed-set)}) tokens-status' (cfo/sync-tokens-status-with-lib tokens-status tokens-lib)] (t/is (= #{set-b-id} (ctos/get-active-set-ids tokens-status'))))) (t/testing "returns same status object when everything is valid" (let [theme-1-id (thi/new-id! :theme-1) set-a-id (thi/new-id! :set-a) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id set-a-id :name "set-a")) (ctob/add-theme (ctob/make-token-theme :id theme-1-id :name "theme-1" :group "" :sets #{"set-a"}))) tokens-status (ctos/make-tokens-status :active-theme-ids #{theme-1-id} :active-set-ids #{set-a-id}) tokens-status' (cfo/sync-tokens-status-with-lib tokens-status tokens-lib)] (t/is (identical? tokens-status tokens-status')))) (t/testing "returns same status object when both theme and set ids are empty" (let [tokens-lib (ctob/make-tokens-lib) tokens-status (ctos/make-tokens-status) tokens-status' (cfo/sync-tokens-status-with-lib tokens-status tokens-lib)] (t/is (identical? tokens-status tokens-status')))) (t/testing "removes all themes and sets when lib is empty" (let [tokens-lib (ctob/make-tokens-lib) tokens-status (ctos/make-tokens-status :active-theme-ids #{(thi/new-id! :old-theme)} :active-set-ids #{(thi/new-id! :old-set)}) tokens-status' (cfo/sync-tokens-status-with-lib tokens-status tokens-lib)] (t/is (= #{} (ctos/get-active-theme-ids tokens-status'))) (t/is (= #{} (ctos/get-active-set-ids tokens-status')))))) ;; Mismatched tokens-status and tokens-lib ;; ;; The tokens-status may contain IDs for themes and sets that do not exist in ;; the tokens-lib (e.g. when the status comes from the tokens lib of a different source). ;; All functions must handle this gracefully: return a reasonable result, never ;; throw an exception. (t/deftest test-mismatched-status-lib (let [real-theme-1 (thi/new-id! :real-theme-1) real-theme-2 (thi/new-id! :real-theme-2) real-set-a (thi/new-id! :real-set-a) real-set-b (thi/new-id! :real-set-b) real-set-c (thi/new-id! :real-set-c) invalid-theme-id (thi/new-id! :invalid-theme) invalid-set-id (thi/new-id! :invalid-set) tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :id real-set-a :name "real-set-a")) (ctob/add-set (ctob/make-token-set :id real-set-b :name "real-set-b")) (ctob/add-set (ctob/make-token-set :id real-set-c :name "real-set-c")) (ctob/add-token real-set-a (ctob/make-token :name "spacing" :type :spacing :value "8px")) (ctob/add-token real-set-b (ctob/make-token :name "radius" :type :border-radius :value "4px")) (ctob/add-theme (ctob/make-token-theme :id real-theme-1 :name "theme-1" :group "colors" :sets #{"real-set-a"})) (ctob/add-theme (ctob/make-token-theme :id real-theme-2 :name "theme-2" :group "colors" :sets #{"real-set-b" "real-set-c"}))) ;; Status has one valid and one invalid theme, one valid and one invalid set tokens-status (ctos/make-tokens-status :active-theme-ids #{real-theme-1 invalid-theme-id} :active-set-ids #{real-set-a invalid-set-id})] (t/testing "activate-theme with non-existent theme id returns status unchanged" (let [status' (cfo/activate-theme tokens-status tokens-lib invalid-theme-id)] (t/is (identical? tokens-status status')))) (t/testing "activate-theme with valid theme works despite invalid ids in status" (let [status' (cfo/activate-theme tokens-status tokens-lib real-theme-2)] (t/is (ctos/theme-active? status' real-theme-2)) (t/is (not (ctos/theme-active? status' real-theme-1))) (t/is (ctos/theme-active? status' invalid-theme-id)) (t/is (contains? (ctos/get-active-set-ids status') real-set-b)) (t/is (contains? (ctos/get-active-set-ids status') real-set-c)))) (t/testing "deactivate-theme with non-existent theme id recalculates sets" (let [status' (cfo/deactivate-theme tokens-status tokens-lib invalid-theme-id)] (t/is (not (ctos/theme-active? status' invalid-theme-id))) (t/is (ctos/theme-active? status' real-theme-1)) (t/is (contains? (ctos/get-active-set-ids status') real-set-a)))) (t/testing "toggle-theme-active with non-existent theme id deactivates it" (let [status' (cfo/toggle-theme-active tokens-status tokens-lib invalid-theme-id)] (t/is (not (ctos/theme-active? status' invalid-theme-id))) (t/is (ctos/theme-active? status' real-theme-1)))) (t/testing "toggle-theme-active with valid inactive theme activates it" (let [status' (cfo/toggle-theme-active tokens-status tokens-lib real-theme-2)] (t/is (ctos/theme-active? status' real-theme-2)) (t/is (contains? (ctos/get-active-set-ids status') real-set-b)) (t/is (contains? (ctos/get-active-set-ids status') real-set-c)))) (t/testing "set-theme-active false with non-existent theme recalculates sets" (let [status' (cfo/set-theme-active tokens-status tokens-lib invalid-theme-id false)] (t/is (not (ctos/theme-active? status' invalid-theme-id))) (t/is (contains? (ctos/get-active-set-ids status') real-set-a)))) (t/testing "set-theme-active true with non-existent theme returns status unchanged" (let [status' (cfo/set-theme-active tokens-status tokens-lib invalid-theme-id true)] (t/is (identical? tokens-status status')))) (t/testing "get-active-themes filters out non-existent theme ids" (let [active-themes (cfo/get-active-themes tokens-status tokens-lib)] (t/is (= 1 (count active-themes))) (t/is (= real-theme-1 (ctob/get-id (first active-themes)))))) (t/testing "get-active-sets filters out non-existent set ids" (let [active-sets (cfo/get-active-sets tokens-status tokens-lib)] (t/is (= 1 (count active-sets))) (t/is (= real-set-a (ctob/get-id (first active-sets)))))) (t/testing "set-set-active with non-existent set id returns status unchanged" (t/is (identical? tokens-status (cfo/set-set-active tokens-status tokens-lib invalid-set-id true))) (t/is (identical? tokens-status (cfo/set-set-active tokens-status tokens-lib invalid-set-id false)))) (t/testing "activate-set with non-existent set id returns status unchanged" (t/is (identical? tokens-status (cfo/activate-set tokens-status tokens-lib invalid-set-id)))) (t/testing "deactivate-set with non-existent set id returns status unchanged" (t/is (identical? tokens-status (cfo/deactivate-set tokens-status tokens-lib invalid-set-id)))) (t/testing "toggle-set-active with non-existent set id returns status unchanged" (t/is (identical? tokens-status (cfo/toggle-set-active tokens-status tokens-lib invalid-set-id)))) (t/testing "sets-at-path-all-active? with invalid set ids in status don't cause errors" ;; real-set-a is at [] and is active (plus invalid-set-id); real-set-b, real-set-c at [] inactive (t/is (= :partial (cfo/sets-at-path-all-active? tokens-status tokens-lib []))) ;; All sets at [] active (with invalid id still in status) (let [all-active-status (ctos/make-tokens-status :active-theme-ids #{} :active-set-ids #{real-set-a real-set-b real-set-c invalid-set-id})] (t/is (= :all (cfo/sets-at-path-all-active? all-active-status tokens-lib []))))) (t/testing "toggle-set-group-active with invalid set ids in status don't cause errors" ;; Status has real-set-a + invalid-set-id active -> :partial at [] ;; Toggling :partial deactivates all at [], invalid-set-id remains (let [status' (cfo/toggle-set-group-active tokens-status tokens-lib [])] (t/is (not (ctos/set-active? status' real-set-a))) (t/is (not (ctos/set-active? status' real-set-b))) (t/is (not (ctos/set-active? status' real-set-c))) (t/is (ctos/set-active? status' invalid-set-id))) ;; All sets at [] active + invalid-set-id -> :all at [] ;; Toggling :all deactivates all at [], invalid-set-id remains (let [all-active (ctos/make-tokens-status :active-theme-ids #{} :active-set-ids #{real-set-a real-set-b real-set-c invalid-set-id}) status' (cfo/toggle-set-group-active all-active tokens-lib [])] (t/is (not (ctos/set-active? status' real-set-a))) (t/is (not (ctos/set-active? status' real-set-b))) (t/is (not (ctos/set-active? status' real-set-c))) (t/is (ctos/set-active? status' invalid-set-id)))) (t/testing "get-tokens-in-active-sets with invalid set ids returns tokens from valid sets only" (let [tokens (cfo/get-tokens-in-active-sets tokens-status tokens-lib)] (t/is (= 1 (count tokens))) (t/is (contains? tokens "spacing")) (t/is (not (contains? tokens "radius"))))) (t/testing "get-tokens-in-active-sets-force with invalid set ids and valid force set" (let [tokens (cfo/get-tokens-in-active-sets-force tokens-status tokens-lib real-set-b)] (t/is (= 2 (count tokens))) (t/is (contains? tokens "spacing")) (t/is (contains? tokens "radius")))) (t/testing "get-tokens-in-active-sets-force with non-existent force set id" (let [tokens (cfo/get-tokens-in-active-sets-force tokens-status tokens-lib invalid-set-id)] (t/is (= 1 (count tokens))) (t/is (contains? tokens "spacing")))) (t/testing "all-invalid status: every id is non-existent in lib" (let [all-invalid (ctos/make-tokens-status :active-theme-ids #{invalid-theme-id} :active-set-ids #{invalid-set-id})] ;; get-active-themes returns empty (t/is (empty? (cfo/get-active-themes all-invalid tokens-lib))) ;; get-active-sets returns empty (t/is (empty? (cfo/get-active-sets all-invalid tokens-lib))) ;; get-tokens-in-active-sets returns empty (t/is (empty? (cfo/get-tokens-in-active-sets all-invalid tokens-lib))) ;; get-tokens-in-active-sets-force returns only force set tokens (let [tokens (cfo/get-tokens-in-active-sets-force all-invalid tokens-lib real-set-a)] (t/is (= 1 (count tokens))) (t/is (contains? tokens "spacing"))) ;; activate-theme for non-existent id is no-op (t/is (identical? all-invalid (cfo/activate-theme all-invalid tokens-lib invalid-theme-id))) ;; deactivate-theme removes non-existent id and recalculates (empty) sets (let [status' (cfo/deactivate-theme all-invalid tokens-lib invalid-theme-id)] (t/is (not (ctos/theme-active? status' invalid-theme-id))) (t/is (= #{} (ctos/get-active-set-ids status')))) ;; toggle-theme-active toggles non-existent id (deactivates) (let [status' (cfo/toggle-theme-active all-invalid tokens-lib invalid-theme-id)] (t/is (not (ctos/theme-active? status' invalid-theme-id)))) ;; set-theme-active false removes non-existent id (let [status' (cfo/set-theme-active all-invalid tokens-lib invalid-theme-id false)] (t/is (not (ctos/theme-active? status' invalid-theme-id))))))))