mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 14:00:37 +00:00
🔧 Add tests and validations to variant functions
This commit is contained in:
parent
ffbd1dfda5
commit
f041d7cb4e
@ -1126,12 +1126,13 @@
|
||||
#?(:cljs
|
||||
(defmethod process-change :validate-shapes
|
||||
[data {:keys [page-id shape-ids context]} libraries]
|
||||
(if libraries
|
||||
(when libraries
|
||||
(println "Validating shapes: \n"
|
||||
" file-id:" (str (:id data)) "\n"
|
||||
" page-id:" (str page-id) "\n"
|
||||
" shape-ids:" (str shape-ids) "\n"
|
||||
" context:" context)
|
||||
(let [file {:data data :id uuid/zero}
|
||||
(let [file {:id (:id data) :data data}
|
||||
errors (reduce (fn [acc shape-id]
|
||||
(if-let [page (ctpl/get-page data page-id)]
|
||||
(let [page-errors (val/validate-shape shape-id file page libraries)]
|
||||
@ -1145,8 +1146,7 @@
|
||||
(ex/raise :type :validation
|
||||
:code :referential-integrity
|
||||
:hint (str "error on validating shapes: " context)
|
||||
:details errors))
|
||||
data))
|
||||
:details errors))))
|
||||
data))
|
||||
|
||||
;; === Operations
|
||||
|
||||
@ -56,6 +56,10 @@
|
||||
:undo-changes '()
|
||||
:origin origin}))
|
||||
|
||||
(defn empty-changes?
|
||||
[changes]
|
||||
(empty? (:redo-changes changes)))
|
||||
|
||||
(defn set-save-undo?
|
||||
[changes save-undo?]
|
||||
(assoc changes :save-undo? save-undo?))
|
||||
@ -1240,18 +1244,22 @@
|
||||
|
||||
(defn get-library-data
|
||||
[changes]
|
||||
(assert-library! changes)
|
||||
(::library-data (meta changes)))
|
||||
|
||||
(defn get-objects
|
||||
[changes]
|
||||
(assert-objects! changes)
|
||||
(dm/get-in (::file-data (meta changes)) [:pages-index uuid/zero :objects]))
|
||||
|
||||
(defn get-page
|
||||
[changes]
|
||||
(assert-page! changes)
|
||||
(::page (meta changes)))
|
||||
|
||||
(defn get-page-id
|
||||
[changes]
|
||||
(assert-page-id! changes)
|
||||
(::page-id (meta changes)))
|
||||
|
||||
(defn set-text-content
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.variant :as cfv]
|
||||
[app.common.path-names :as cpn]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.types.component :as ctk]
|
||||
@ -280,6 +279,8 @@
|
||||
"Shape expected to be main instance"
|
||||
shape file page))
|
||||
(when-not (= (:component-file shape) (:id file))
|
||||
(prn "shape" (:id shape) (:name shape) (:component-file shape))
|
||||
(prn "file" (:id file) (:name file))
|
||||
(report-error :component-main-external
|
||||
"Main instance should refer to a component in the same file"
|
||||
shape file page))
|
||||
@ -588,16 +589,27 @@
|
||||
objects (:objects page)
|
||||
file-data (:data file)
|
||||
first-child (get objects (first shapes))
|
||||
prop-names (cfv/extract-properties-names first-child file-data)
|
||||
clean-path (cpn/clean-path container-name)
|
||||
clean-path (if (str/blank? clean-path)
|
||||
"(empty)" ;; this may occur if the name contains only separators
|
||||
clean-path)]
|
||||
clean-path)
|
||||
|
||||
extract-properties-names
|
||||
(fn [shape]
|
||||
;; Get the names of the properties of the shape's component
|
||||
(->> shape
|
||||
(#(ctkl/get-component file-data (:component-id %) true))
|
||||
:variant-properties
|
||||
(map :name)))
|
||||
|
||||
prop-names (extract-properties-names first-child)]
|
||||
|
||||
(when-not (= container-name clean-path)
|
||||
(report-error :variant-container-bad-name
|
||||
(str/ffmt "Variant container % has a bad name %" shape-id container-name)
|
||||
shape file page
|
||||
:clean-name clean-path))
|
||||
|
||||
(run! (fn [child-id]
|
||||
(when-let [child (get objects child-id)]
|
||||
(if (not (ctk/is-variant? child))
|
||||
@ -611,7 +623,7 @@
|
||||
(str/ffmt "Main instance in variant % should have the variant-id of the container but has %" (:id child) (:variant-id child))
|
||||
child file page
|
||||
:variant-id shape-id))
|
||||
(when (not= prop-names (cfv/extract-properties-names child file-data))
|
||||
(when (not= prop-names (extract-properties-names child))
|
||||
(report-error :invalid-variant-properties
|
||||
(str/ffmt "Variant % has invalid properties %" (:id child) (vec prop-names))
|
||||
child file page
|
||||
|
||||
@ -6,12 +6,16 @@
|
||||
(ns app.common.files.variant
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.types.component :as ctc]
|
||||
[app.common.types.components-list :as ctcl]
|
||||
[app.common.types.component :as ctk]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.variant :as ctv]))
|
||||
|
||||
(defn find-variant-components
|
||||
"Find a list of the components that belongs to this variant-id"
|
||||
"Find the components that belong to the variant container identified by `variant-id`,
|
||||
preserving the order defined by the container's shapes.
|
||||
|
||||
Example return:
|
||||
(<component1> <component2> ...)"
|
||||
([data variant-id]
|
||||
(let [page-id (->> data
|
||||
:components
|
||||
@ -22,22 +26,24 @@
|
||||
objects (dm/get-in data [:pages-index page-id :objects])]
|
||||
(find-variant-components data objects variant-id)))
|
||||
([data objects variant-id]
|
||||
(assert (or (uuid? variant-id) (nil? variant-id)))
|
||||
;; We can't simply filter components, because we need to maintain the order
|
||||
(->> (dm/get-in objects [variant-id :shapes])
|
||||
(map #(dm/get-in objects [% :component-id]))
|
||||
(map #(ctcl/get-component data % true))
|
||||
reverse)))
|
||||
|
||||
(defn extract-properties-names
|
||||
[shape data]
|
||||
(->> shape
|
||||
(#(ctcl/get-component data (:component-id %) true))
|
||||
:variant-properties
|
||||
(map :name)))
|
||||
(let [container (get objects variant-id)]
|
||||
(if (ctv/variant-container? container)
|
||||
(->> (:shapes container)
|
||||
(map #(dm/get-in objects [% :component-id]))
|
||||
(map #(ctkl/get-component data % true))
|
||||
reverse)
|
||||
[]))))
|
||||
|
||||
(defn extract-properties-values
|
||||
"Get a map of properties associated to their possible values"
|
||||
"Get a map of variant property names to their distinct possible values,
|
||||
collected from all components that belong to the variant container.
|
||||
|
||||
Example return:
|
||||
[{:name 'Property 1' :value ('Value1' 'Value2')}]"
|
||||
[data objects variant-id]
|
||||
(assert (or (uuid? variant-id) (nil? variant-id)))
|
||||
(->> (find-variant-components data objects variant-id)
|
||||
(mapcat :variant-properties)
|
||||
(group-by :name)
|
||||
@ -47,9 +53,13 @@
|
||||
:value (->> v (map :value) distinct)}
|
||||
mdata))))))
|
||||
|
||||
(defn get-variant-mains
|
||||
[component data]
|
||||
(assert (ctv/valid-variant-component? component) "expected valid component variant")
|
||||
(defn- get-variant-mains
|
||||
"Return the ids of the main instance shapes of the variant this component belongs to,
|
||||
in the order they appear in the container.
|
||||
|
||||
Example return:
|
||||
[<main-shape-a-id> <main-shape-b-id>]"
|
||||
[data component]
|
||||
(when-let [variant-id (:variant-id component)]
|
||||
(let [page-id (:main-instance-page component)
|
||||
objects (-> (dm/get-in data [:pages-index page-id])
|
||||
@ -57,27 +67,30 @@
|
||||
(dm/get-in objects [variant-id :shapes]))))
|
||||
|
||||
(defn is-secondary-variant?
|
||||
[component data]
|
||||
(let [shapes (get-variant-mains component data)]
|
||||
"Return true if the component is a secondary variant in its variant container.
|
||||
The primary variant is the last one in the container's children list.
|
||||
Return false if the component is the primary variant or if it's not part of a variant."
|
||||
[data component]
|
||||
(let [shapes (get-variant-mains data component)]
|
||||
(and (seq shapes)
|
||||
(not= (:main-instance-id component) (last shapes)))))
|
||||
|
||||
(defn get-primary-variant
|
||||
"Return the main instance of the primary variant (the last one) in the variant container."
|
||||
[data component]
|
||||
(let [page-id (:main-instance-page component)
|
||||
objects (-> (dm/get-in data [:pages-index page-id])
|
||||
(get :objects))
|
||||
variant-id (:variant-id component)]
|
||||
(->> (dm/get-in objects [variant-id :shapes])
|
||||
(let [page-id (:main-instance-page component)
|
||||
objects (-> (dm/get-in data [:pages-index page-id])
|
||||
(get :objects))]
|
||||
(->> (get-variant-mains data component)
|
||||
peek
|
||||
(get objects))))
|
||||
|
||||
(defn get-primary-component
|
||||
[data component-id]
|
||||
(when-let [component (ctcl/get-component data component-id)]
|
||||
(if (ctc/is-variant? component)
|
||||
(when-let [component (ctkl/get-component data component-id)]
|
||||
(if (ctk/is-variant? component)
|
||||
(->> component
|
||||
(get-primary-variant data)
|
||||
:component-id
|
||||
(ctcl/get-component data))
|
||||
(ctkl/get-component data))
|
||||
component)))
|
||||
|
||||
@ -15,92 +15,145 @@
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(defn generate-update-property-name
|
||||
"Update the name of a variant property at position `pos` for all components in the variant.
|
||||
The new name may be added a suffix to ensure it is unique among the other property names."
|
||||
[changes variant-id pos new-name]
|
||||
(let [data (pcb/get-library-data changes)
|
||||
objects (pcb/get-objects changes)
|
||||
related-components (cfv/find-variant-components data objects variant-id)
|
||||
|
||||
props (-> related-components last :variant-properties)
|
||||
prop-names (mapv :name props)
|
||||
prop-names (concat (subvec prop-names 0 pos) (subvec prop-names (inc pos)))
|
||||
new-name (ctv/update-number-in-repeated-item prop-names new-name)]
|
||||
(reduce (fn [changes component]
|
||||
(pcb/update-component
|
||||
changes (:id component)
|
||||
(fn [component]
|
||||
(d/update-in-when component [:variant-properties pos] #(assoc % :name new-name)))
|
||||
{:apply-changes-local-library? true}))
|
||||
(if (or (nil? variant-id) (nil? pos))
|
||||
changes
|
||||
(let [data (pcb/get-library-data changes)
|
||||
objects (pcb/get-objects changes)
|
||||
related-components (cfv/find-variant-components data objects variant-id)]
|
||||
(if (empty? related-components)
|
||||
changes
|
||||
(let [props (-> related-components last :variant-properties)
|
||||
num-props (count props)]
|
||||
(if (or (< pos 0) (>= pos num-props))
|
||||
changes
|
||||
related-components)))
|
||||
(let [prop-names (mapv :name props)
|
||||
prop-names (concat (subvec prop-names 0 pos) (subvec prop-names (inc pos)))
|
||||
new-name (ctv/update-number-in-repeated-item prop-names new-name)
|
||||
|
||||
changes (reduce (fn [changes component]
|
||||
(pcb/update-component
|
||||
changes (:id component)
|
||||
(fn [component]
|
||||
(d/update-in-when component [:variant-properties pos] #(assoc % :name new-name)))
|
||||
{:apply-changes-local-library? true}))
|
||||
changes
|
||||
related-components)
|
||||
|
||||
ids-to-validate (map :main-instance-id related-components)
|
||||
|
||||
changes (pcb/validate-shapes changes
|
||||
(pcb/get-page-id changes)
|
||||
ids-to-validate
|
||||
(str "generate-update-property-name: " variant-id
|
||||
" pos: " pos " new-name: " new-name))]
|
||||
changes)))))))
|
||||
|
||||
(defn generate-remove-property
|
||||
"Remove the variant property at position `pos` for all components in the variant and their
|
||||
respective main instances."
|
||||
[changes variant-id pos]
|
||||
(let [data (pcb/get-library-data changes)
|
||||
objects (pcb/get-objects changes)
|
||||
related-components (cfv/find-variant-components data objects variant-id)
|
||||
props (-> related-components first :variant-properties)]
|
||||
(if (and (seq props) (<= 0 pos) (< pos (count props)))
|
||||
(reduce (fn [changes component]
|
||||
(let [props (:variant-properties component)
|
||||
props (d/remove-at-index props pos)
|
||||
main-id (:main-instance-id component)
|
||||
name (ctv/properties-to-name props)]
|
||||
(-> changes
|
||||
(pcb/update-component (:id component) #(assoc % :variant-properties props)
|
||||
{:apply-changes-local-library? true})
|
||||
(pcb/update-shapes [main-id] #(assoc % :variant-name name)))))
|
||||
changes
|
||||
related-components)
|
||||
changes)))
|
||||
(if (nil? pos)
|
||||
changes
|
||||
(let [data (pcb/get-library-data changes)
|
||||
objects (pcb/get-objects changes)
|
||||
related-components (cfv/find-variant-components data objects variant-id)
|
||||
props (-> related-components first :variant-properties)]
|
||||
(if (and (seq props) (<= 0 pos) (< pos (count props)))
|
||||
(let [changes (reduce (fn [changes component]
|
||||
(let [props (:variant-properties component)
|
||||
props (d/remove-at-index props pos)
|
||||
main-id (:main-instance-id component)
|
||||
name (ctv/properties-to-name props)]
|
||||
(-> changes
|
||||
(pcb/update-component (:id component) #(assoc % :variant-properties props)
|
||||
{:apply-changes-local-library? true})
|
||||
(pcb/update-shapes [main-id] #(assoc % :variant-name name)))))
|
||||
changes
|
||||
related-components)
|
||||
|
||||
ids-to-validate (map :main-instance-id related-components)
|
||||
|
||||
changes (pcb/validate-shapes changes
|
||||
(pcb/get-page-id changes)
|
||||
ids-to-validate
|
||||
(str "generate-remove-property: " variant-id " pos: " pos))]
|
||||
changes)
|
||||
changes))))
|
||||
|
||||
(defn generate-update-property-value
|
||||
"Update the value of the variant property at position 'pos' for the given component and its main instance."
|
||||
[changes component-id pos value]
|
||||
(let [data (pcb/get-library-data changes)
|
||||
component (ctcl/get-component data component-id true)
|
||||
main-id (:main-instance-id component)
|
||||
name (-> (:variant-properties component)
|
||||
(update pos assoc :value value)
|
||||
ctv/properties-to-name)]
|
||||
(-> changes
|
||||
(pcb/update-component component-id #(assoc-in % [:variant-properties pos :value] value)
|
||||
{:apply-changes-local-library? true})
|
||||
(pcb/update-shapes [main-id] #(assoc % :variant-name name)))))
|
||||
|
||||
(if (or (nil? component-id) (nil? pos))
|
||||
changes
|
||||
(let [data (pcb/get-library-data changes)
|
||||
component (ctcl/get-component data component-id true)]
|
||||
(if (and component (< pos (count (:variant-properties component))))
|
||||
(let [main-id (:main-instance-id component)
|
||||
props (:variant-properties component)
|
||||
name (-> props
|
||||
(update pos assoc :value value)
|
||||
ctv/properties-to-name)]
|
||||
(-> changes
|
||||
(pcb/update-component component-id #(assoc-in % [:variant-properties pos :value] value)
|
||||
{:apply-changes-local-library? true})
|
||||
(pcb/update-shapes [main-id] #(assoc % :variant-name name))))
|
||||
changes))))
|
||||
|
||||
(defn generate-set-variant-error
|
||||
"Set an invalid property value as a :variant-error attribute in the main instance of the given component.
|
||||
If value is nil, remove the :variant-error attribute."
|
||||
[changes component-id value]
|
||||
(let [data (pcb/get-library-data changes)
|
||||
component (ctcl/get-component data component-id true)
|
||||
main-id (:main-instance-id component)]
|
||||
(-> changes
|
||||
(pcb/update-shapes [main-id] (if (nil? value)
|
||||
#(dissoc % :variant-error)
|
||||
#(assoc % :variant-error value))))))
|
||||
|
||||
(if (nil? component-id)
|
||||
changes
|
||||
(let [data (pcb/get-library-data changes)
|
||||
component (ctcl/get-component data component-id true)]
|
||||
(if component
|
||||
(let [main-id (:main-instance-id component)]
|
||||
(-> changes
|
||||
(pcb/update-shapes [main-id] (if (nil? value)
|
||||
#(dissoc % :variant-error)
|
||||
#(assoc % :variant-error value)))))
|
||||
changes))))
|
||||
|
||||
(defn generate-reorder-variant-poperties
|
||||
"Change the order of the variant properties for all components in the variant.
|
||||
Move the property at the given position to some space between positions.
|
||||
Clamp the positions to the valid range of property indexes."
|
||||
[changes variant-id from-pos to-space-between-pos]
|
||||
(let [data (pcb/get-library-data changes)
|
||||
objects (pcb/get-objects changes)
|
||||
related-components (cfv/find-variant-components data objects variant-id)]
|
||||
(reduce (fn [changes component]
|
||||
(let [props (:variant-properties component)
|
||||
props (d/reorder props from-pos to-space-between-pos)
|
||||
main-id (:main-instance-id component)
|
||||
name (ctv/properties-to-name props)]
|
||||
(-> changes
|
||||
(pcb/update-component (:id component)
|
||||
#(assoc % :variant-properties props)
|
||||
{:apply-changes-local-library? true})
|
||||
(pcb/update-shapes [main-id]
|
||||
#(assoc % :variant-name name)))))
|
||||
changes
|
||||
related-components)))
|
||||
|
||||
(if (or (nil? variant-id) (nil? from-pos) (nil? to-space-between-pos))
|
||||
changes
|
||||
(let [data (pcb/get-library-data changes)
|
||||
objects (pcb/get-objects changes)
|
||||
related-components (cfv/find-variant-components data objects variant-id)]
|
||||
(reduce (fn [changes component]
|
||||
(let [props (:variant-properties component)
|
||||
props' (d/reorder props from-pos to-space-between-pos)
|
||||
main-id (:main-instance-id component)
|
||||
name (ctv/properties-to-name props')]
|
||||
(if (not= props props')
|
||||
(-> changes
|
||||
(pcb/update-component (:id component)
|
||||
#(assoc % :variant-properties props')
|
||||
{:apply-changes-local-library? true})
|
||||
(pcb/update-shapes [main-id]
|
||||
#(assoc % :variant-name name)))
|
||||
changes)))
|
||||
changes
|
||||
related-components))))
|
||||
|
||||
(defn generate-add-new-property
|
||||
"Add a new variant property to all components in the variant and their respective main instances.
|
||||
|
||||
The new property name may be given or it will be generated based on the next available property
|
||||
number. In any case, it may be modified to be unique among the other property names.
|
||||
|
||||
The value may also be given, or else it will be an empty value, unless fill-values? is true, in
|
||||
which case the value will be set to a default value based on the property number.
|
||||
|
||||
The editing? flag, if set, will be added to the metadata of the properties, for later use."
|
||||
[changes variant-id & {:keys [fill-values? editing? property-name property-value]}]
|
||||
(let [data (pcb/get-library-data changes)
|
||||
objects (pcb/get-objects changes)
|
||||
@ -158,10 +211,11 @@
|
||||
(assoc :name new-name))))))
|
||||
|
||||
(defn generate-make-shapes-no-variant
|
||||
"Extract some components from a variant, removing the variant-id and variant-name from the
|
||||
main instances and the variant-id and variant-properties from the components."
|
||||
[changes shapes]
|
||||
(reduce generate-make-shape-no-variant changes shapes))
|
||||
|
||||
|
||||
(defn- create-new-properties-from-variant
|
||||
[shape min-props data container-name base-properties]
|
||||
(let [component (ctcl/get-component data (:component-id shape) true)
|
||||
@ -184,8 +238,9 @@
|
||||
shape-name (ctv/remove-prefix (:name shape) container-name)]
|
||||
(ctv/path-to-properties shape-name base-properties min-props)))
|
||||
|
||||
|
||||
(defn generate-make-shapes-variant
|
||||
"Introduce some components into a variant, adding the variant-id and variant-name to the
|
||||
main instances and the variant-id and variant-properties to the components."
|
||||
[changes shapes variant-container]
|
||||
(let [data (pcb/get-library-data changes)
|
||||
objects (pcb/get-objects changes)
|
||||
|
||||
@ -78,17 +78,41 @@
|
||||
[properties]
|
||||
(> (count properties) 1))
|
||||
|
||||
(defn variant-component?
|
||||
[component]
|
||||
(some? (:variant-id component)))
|
||||
|
||||
(defn variant-shape?
|
||||
[shape]
|
||||
(some? (:variant-id shape)))
|
||||
|
||||
(defn variant-container?
|
||||
[shape]
|
||||
(some? (:is-variant-container shape)))
|
||||
|
||||
(defn properties-to-name
|
||||
"Transform the properties into a name, with the values separated by comma"
|
||||
"Transform the properties into a name, with the values separated by comma, excluding the empty ones.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'Property 1' :value 'Button'}
|
||||
{:name 'Property 2' :value 'Primary'}] -> 'Button, Primary'"
|
||||
[properties]
|
||||
(assert (or (sequential? properties) (nil? properties)))
|
||||
(->> properties
|
||||
(map :value)
|
||||
(remove str/empty?)
|
||||
(str/join ", ")))
|
||||
|
||||
(defn next-property-number
|
||||
"Returns the next property number, to avoid duplicates on the property names"
|
||||
"Returns the next property number, to avoid duplicates on the property names.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 3' :value 'y'}] -> 4"
|
||||
[properties]
|
||||
(assert (or (sequential? properties) (nil? properties)))
|
||||
(let [numbers (keep
|
||||
#(some->> (:name %) (re-find property-regex) second d/parse-integer)
|
||||
properties)
|
||||
@ -98,14 +122,29 @@
|
||||
(inc (max max-num (count properties)))))
|
||||
|
||||
(defn add-new-property
|
||||
"Adds a new property with generated name and provided value to the existing properties list."
|
||||
"Adds a new property with generated name and provided value to the existing properties list.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'Property 1' :value 'x'}] 'y' -> [{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 2' :value 'y'}]"
|
||||
[properties value]
|
||||
(assert (or (sequential? properties) (nil? properties)))
|
||||
(assert (or (string? value) (nil? value)))
|
||||
(conj properties {:name (str property-prefix (next-property-number properties))
|
||||
:value value}))
|
||||
:value value}))
|
||||
|
||||
(defn add-new-properties
|
||||
"Adds new properties with generated names and provided values to the existing properties list."
|
||||
"Adds new properties with generated names and provided values to the existing properties list.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'Property 1' :value 'x'}] ['a' 'b'] -> [{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 2' :value 'a'}
|
||||
{:name 'Property 3' :value 'b'}]"
|
||||
[properties values]
|
||||
(assert (or (sequential? properties) (nil? properties)))
|
||||
(assert (or (sequential? values) (nil? values)))
|
||||
(let [next-prop-num (next-property-number properties)
|
||||
xf (map-indexed (fn [i v]
|
||||
{:name (str property-prefix (+ next-prop-num i))
|
||||
@ -114,10 +153,21 @@
|
||||
|
||||
(defn path-to-properties
|
||||
"From a list of properties and a name with path, assign each token of the
|
||||
path as value of a different property"
|
||||
path as value of a different property. It can add blank properties if
|
||||
necessary, until the min-properties number is reached.
|
||||
|
||||
Example with min-properties=4:
|
||||
|
||||
'Button / Primary / Hover' -> [{:name 'Property 1' :value 'Button'}
|
||||
{:name 'Property 2' :value 'Primary'}
|
||||
{:name 'Property 3' :value 'Hover'}
|
||||
{:name 'Property 4' :value ''}]"
|
||||
([path properties]
|
||||
(path-to-properties path properties 0))
|
||||
([path properties min-properties]
|
||||
(assert (or (string? path) (nil? path)))
|
||||
(assert (or (sequential? properties) (nil? properties)))
|
||||
(assert (int? min-properties))
|
||||
(let [cpath (cpn/split-path path)
|
||||
total-properties (max (count cpath) min-properties)
|
||||
assigned (mapv #(assoc % :value (nth cpath %2 "")) properties (range))
|
||||
@ -127,8 +177,14 @@
|
||||
(add-new-properties assigned remaining))))
|
||||
|
||||
(defn properties-map->formula
|
||||
"Transforms a map of properties to a formula of properties omitting the empty ones"
|
||||
"Transforms a map of properties to a formula of properties omitting the empty ones.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'Property 1' :value 'Button'}
|
||||
{:name 'Property 2' :value 'Primary'}] -> 'Property 1=Button, Property 2=Primary'"
|
||||
[properties]
|
||||
(assert (or (sequential? properties) (nil? properties)))
|
||||
(->> properties
|
||||
(keep (fn [{:keys [name value]}]
|
||||
(when (not (str/blank? value))
|
||||
@ -136,9 +192,15 @@
|
||||
(str/join ", ")))
|
||||
|
||||
(defn properties-formula->map
|
||||
"Transforms a formula of properties to a map of properties"
|
||||
[s]
|
||||
(->> (str/split s ",")
|
||||
"Transforms a formula of properties to a map of properties.
|
||||
|
||||
Example:
|
||||
|
||||
'Property 1=Button, Property 2=Primary' -> [{:name 'Property 1' :value 'Button'}
|
||||
{:name 'Property 2' :value 'Primary'}]"
|
||||
[formula]
|
||||
(assert (or (string? formula) (nil? formula)))
|
||||
(->> (str/split formula ",")
|
||||
(mapv #(str/split % "=" 2))
|
||||
(filter (fn [[_ v]] (not (str/blank? v))))
|
||||
(mapv (fn [[k v]]
|
||||
@ -146,9 +208,15 @@
|
||||
:value (str/trim v)}))))
|
||||
|
||||
(defn valid-properties-formula?
|
||||
"Checks if a formula is valid"
|
||||
[s]
|
||||
(->> (str/split s ",")
|
||||
"Checks if a formula is valid.
|
||||
|
||||
Example:
|
||||
|
||||
'Property 1=Button, Property 2=Primary' -> true
|
||||
'Property 1=Button, Property 2' -> false"
|
||||
[formula]
|
||||
(assert (or (string? formula) (nil? formula)))
|
||||
(->> (str/split formula ",")
|
||||
(mapv #(str/split % "=" 2))
|
||||
(every? #(and (= 2 (count %))
|
||||
(not (str/blank? (first %)))
|
||||
@ -156,20 +224,45 @@
|
||||
(<= (count (second %)) property-max-length)))))
|
||||
|
||||
(defn find-properties-to-remove
|
||||
"Compares two property maps to find which properties should be removed"
|
||||
"Compares two property maps to find which properties should be removed.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 2' :value 'y'}]
|
||||
[{:name 'Property 1' :value 'x'}] -> [{:name 'Property 2' :value 'y'}]"
|
||||
[prev-properties upd-properties]
|
||||
(assert (or (sequential? prev-properties) (nil? prev-properties)))
|
||||
(assert (or (sequential? upd-properties) (nil? upd-properties)))
|
||||
(let [upd-names (set (map :name upd-properties))]
|
||||
(filterv #(not (contains? upd-names (:name %))) prev-properties)))
|
||||
|
||||
(defn find-properties-to-update
|
||||
"Compares two property maps to find which properties should be updated"
|
||||
"Compares two property maps to find which properties should be updated.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 2' :value 'y'}]
|
||||
[{:name 'Property 1' :value 'new-x'}
|
||||
{:name 'Property 2' :value 'y'}] -> [{:name 'Property 1' :value 'new-x'}]"
|
||||
[prev-properties upd-properties]
|
||||
(assert (or (sequential? prev-properties) (nil? prev-properties)))
|
||||
(assert (or (sequential? upd-properties) (nil? upd-properties)))
|
||||
(filterv #(some (fn [prop] (and (= (:name %) (:name prop))
|
||||
(not= (:value %) (:value prop)))) prev-properties) upd-properties))
|
||||
|
||||
(defn find-properties-to-add
|
||||
"Compares two property maps to find which properties should be added"
|
||||
"Compares two property maps to find which properties should be added.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'Property 1' :value 'x'}]
|
||||
[{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 2' :value 'y'}] -> [{:name 'Property 2' :value 'y'}]"
|
||||
[prev-properties upd-properties]
|
||||
(assert (or (sequential? prev-properties) (nil? prev-properties)))
|
||||
(assert (or (sequential? upd-properties) (nil? upd-properties)))
|
||||
(let [prev-names (set (map :name prev-properties))]
|
||||
(filterv #(not (contains? prev-names (:name %))) upd-properties)))
|
||||
|
||||
@ -193,8 +286,15 @@
|
||||
|
||||
(defn update-number-in-repeated-item
|
||||
"Add, keep or update a number in parentheses for a given item, if necessary, depending on the items
|
||||
already present in a list, to avoid repetitions"
|
||||
already present in a list, to avoid repetitions.
|
||||
|
||||
Example:
|
||||
|
||||
['Property'] 'Property' -> 'Property (1)'
|
||||
['Property' 'Property (1)'] 'Property' -> 'Property (2)'"
|
||||
[items item]
|
||||
(assert (or (sequential? items) (nil? items)))
|
||||
(assert (or (string? item) (nil? item)))
|
||||
(let [names (group-numbers-by-base-name items)
|
||||
[base num] (split-base-name-and-number item)
|
||||
nums-taken (get names base #{})]
|
||||
@ -204,8 +304,15 @@
|
||||
(str base (when (pos? n) (str " (" n ")")))))))
|
||||
|
||||
(defn update-number-in-repeated-prop-names
|
||||
"Add, keep or update a number for each prop name depending on the previous ones"
|
||||
"Add, keep or update a number for each prop name depending on the previous ones.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'Property' :value 'x'}
|
||||
{:name 'Property' :value 'y'}] -> [{:name 'Property' :value 'x'}
|
||||
{:name 'Property (1)' :value 'y'}]"
|
||||
[properties]
|
||||
(assert (or (sequential? properties) (nil? properties)))
|
||||
(->> properties
|
||||
(reduce (fn [acc prop]
|
||||
(conj acc {:name (update-number-in-repeated-item (mapv :name acc) (:name prop))
|
||||
@ -213,16 +320,30 @@
|
||||
[])))
|
||||
|
||||
(defn find-index-for-property-name
|
||||
"Finds the index of a name in a property map"
|
||||
"Finds the index of a name in a property map.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 2' :value 'y'}] 'Property 2' -> 1"
|
||||
[properties name]
|
||||
(assert (or (sequential? properties) (nil? properties)))
|
||||
(assert (or (string? name) (nil? name)))
|
||||
(some (fn [[idx prop]]
|
||||
(when (= (:name prop) name)
|
||||
idx))
|
||||
(map-indexed vector properties)))
|
||||
|
||||
(defn remove-prefix
|
||||
"Removes the given prefix (with or without a trailing ' / ') from the beginning of the name"
|
||||
"Removes the given prefix (with or without a trailing ' / ') from the beginning of the name.
|
||||
|
||||
Example:
|
||||
|
||||
'Button / Primary' 'Button' -> 'Primary'
|
||||
'Button / Primary' 'Other' -> 'Button / Primary'"
|
||||
[name prefix]
|
||||
(assert (or (string? name) (nil? name)))
|
||||
(assert (or (string? prefix) (nil? prefix)))
|
||||
(let [long-name (str prefix " / ")]
|
||||
(cond
|
||||
(str/starts-with? name long-name)
|
||||
@ -278,8 +399,20 @@
|
||||
- Otherwise, assign p2's value to the first unused property in properties1. A property is considered used if:
|
||||
- Its name exists in both properties1 and properties2, or
|
||||
- Its value has already been updated during the merge.
|
||||
- If no unused properties are available in properties1, append a new property with a default name and p2's value."
|
||||
- If no unused properties are available in properties1, append a new property with a default name and p2's value.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'Property 1' :value 'a'}
|
||||
{:name 'Property 2' :value 'b'}]
|
||||
[{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 2' :value 'y'}
|
||||
{:name 'Property 3' :value 'z'}] -> [{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 2' :value 'y'}
|
||||
{:name 'Property 3' :value 'z'}]"
|
||||
[properties1 properties2]
|
||||
(assert (or (sequential? properties1) (nil? properties1)))
|
||||
(assert (or (sequential? properties2) (nil? properties2)))
|
||||
(let [properties2 (remove #(str/empty? (:value %)) properties2)]
|
||||
(-> (reduce
|
||||
(fn [{:keys [properties used-pos]} prop]
|
||||
@ -294,11 +427,21 @@
|
||||
|
||||
(defn compare-properties
|
||||
"Compares vectors of properties keeping the value if it is the same for all
|
||||
or setting a custom value where their values do not coincide"
|
||||
or setting a custom value where their values do not coincide.
|
||||
|
||||
Example:
|
||||
|
||||
[[{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 2' :value 'y'}]
|
||||
[{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 2' :value 'z'}]] -> [{:name 'Property 1' :value 'x'}
|
||||
{:name 'Property 2' :value nil}]"
|
||||
([properties-list]
|
||||
(compare-properties properties-list nil))
|
||||
|
||||
([properties-list distinct-mark]
|
||||
(assert (or (sequential? properties-list) (nil? properties-list)))
|
||||
(assert (or (string? distinct-mark) (nil? distinct-mark)))
|
||||
(let [grouped (group-by :name (apply concat properties-list))
|
||||
check-values (fn [values]
|
||||
(let [vals (map :value values)]
|
||||
@ -309,19 +452,19 @@
|
||||
{:name name :value (check-values values)})
|
||||
grouped))))
|
||||
|
||||
(defn same-variant?
|
||||
"Determines if all elements belong to the same variant"
|
||||
[components]
|
||||
(let [variant-ids (distinct (map :variant-id components))
|
||||
not-blank? (complement str/blank?)]
|
||||
(and
|
||||
(= 1 (count variant-ids))
|
||||
(not-blank? (first variant-ids)))))
|
||||
|
||||
(defn distance
|
||||
(defn properties-distance
|
||||
"Computes a weighted distance between two property lists `properties1` and `properties2`.
|
||||
Latter properties weight less that previous ones"
|
||||
Latter properties weight less that previous ones.
|
||||
|
||||
Example:
|
||||
|
||||
[{:name 'type' :value 'primary'}
|
||||
{:name 'status' :value 'default'}]
|
||||
[{:name 'type' :value 'primary'}
|
||||
{:name 'status' :value 'hover'}] -> 1.0"
|
||||
[properties1 properties2]
|
||||
(assert (or (sequential? properties1) (nil? properties1)))
|
||||
(assert (or (sequential? properties2) (nil? properties2)))
|
||||
(let [total-num-properties (count properties1)
|
||||
xform (map-indexed
|
||||
(fn [idx [p1 p2]]
|
||||
@ -335,7 +478,11 @@
|
||||
|
||||
(defn variant-name-to-name
|
||||
"Transforms a variant-name (its properties values) into a standard name:
|
||||
the real name of the shape joined by the properties values separated by '/'"
|
||||
the real name of the shape joined by the properties values separated by '/'.
|
||||
|
||||
Example:
|
||||
|
||||
{:name 'Button' :variant-name 'Primary, Hover'} -> 'Button / Primary / Hover'"
|
||||
[variant]
|
||||
(cpn/merge-path-item (:name variant) (str/replace (:variant-name variant) #", " " / ")))
|
||||
|
||||
@ -345,8 +492,13 @@
|
||||
["true" "false"]])
|
||||
|
||||
(defn find-boolean-pair
|
||||
"Given a vector, return a map that contains the boolean equivalency if the values match
|
||||
with any of the boolean pairs. Returns nil if none match."
|
||||
"Given a collection, return a map that contains the boolean equivalency if the values match
|
||||
with any of the boolean pairs. Returns nil if none match.
|
||||
|
||||
Example:
|
||||
|
||||
['on' 'off'] -> {'on' true 'off' false}
|
||||
['foo' 'bar'] -> nil"
|
||||
[[a b :as v]]
|
||||
(let [a' (-> a str/trim str/lower)
|
||||
b' (-> b str/trim str/lower)]
|
||||
@ -358,3 +510,18 @@
|
||||
(= a' f)) {b true a false}
|
||||
:else nil))
|
||||
boolean-pairs))))
|
||||
|
||||
(defn same-variant?
|
||||
"Determines if all elements belong to the same variant.
|
||||
|
||||
Example:
|
||||
|
||||
[{:variant-id 'abc'} {:variant-id 'abc'}] -> true
|
||||
[{:variant-id 'abc'} {:variant-id 'def'}] -> false"
|
||||
[components]
|
||||
(assert (or (sequential? components) (nil? components)))
|
||||
(let [variant-ids (distinct (map :variant-id components))
|
||||
not-blank? (complement str/blank?)]
|
||||
(and
|
||||
(= 1 (count variant-ids))
|
||||
(not-blank? (first variant-ids)))))
|
||||
|
||||
199
common/test/common_tests/files/variant_test.cljc
Normal file
199
common/test/common_tests/files/variant_test.cljc
Normal file
@ -0,0 +1,199 @@
|
||||
;; 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.variant-test
|
||||
(:require
|
||||
[app.common.files.variant :as fv]
|
||||
[app.common.test-helpers.components :as thc]
|
||||
[app.common.test-helpers.compositions :as tho]
|
||||
[app.common.test-helpers.files :as thf]
|
||||
[app.common.test-helpers.ids-map :as thi]
|
||||
[app.common.test-helpers.variants :as thv]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.test :as t]))
|
||||
|
||||
(t/use-fixtures :each thi/test-fixture)
|
||||
|
||||
;; ============================================================
|
||||
;; find-variant-components
|
||||
;; ============================================================
|
||||
|
||||
(t/deftest find-variant-components-empty
|
||||
(let [file (thf/sample-file :file1)
|
||||
data (:data file)
|
||||
page (thf/current-page file)
|
||||
objects (:objects page)]
|
||||
(t/is (= (fv/find-variant-components data (uuid/next))
|
||||
[]))
|
||||
(t/is (= (fv/find-variant-components data objects (uuid/next))
|
||||
[]))))
|
||||
|
||||
(t/deftest find-variant-components-non-variant
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(tho/add-simple-component :c01 :m01 :s01))
|
||||
data (:data file)
|
||||
page (thf/current-page file)
|
||||
objects (:objects page)]
|
||||
(t/is (= (fv/find-variant-components data (thi/id :m01))
|
||||
[]))
|
||||
(t/is (= (fv/find-variant-components data objects (thi/id :m01))
|
||||
[]))))
|
||||
|
||||
(t/deftest find-variant-components-normal
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
data (:data file)
|
||||
page (thf/current-page file)
|
||||
objects (:objects page)
|
||||
result (fv/find-variant-components data objects (thi/id :v01))]
|
||||
(t/is (= (count result) 2))
|
||||
(t/is (every? #(contains? % :id) result))
|
||||
(t/is (every? #(contains? % :variant-id) result))))
|
||||
|
||||
(t/deftest find-variant-components-single-variant
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
data (:data file)
|
||||
page (thf/current-page file)
|
||||
objects (:objects page)
|
||||
result (fv/find-variant-components data objects (thi/id :v01))]
|
||||
;; Verify the order is maintained (reversed from shapes order)
|
||||
(t/is (= (:variant-id (first result)) (thi/id :v01)))
|
||||
(t/is (= (:variant-id (second result)) (thi/id :v01)))))
|
||||
|
||||
;; ============================================================
|
||||
;; extract-properties-values
|
||||
;; ============================================================
|
||||
|
||||
(t/deftest extract-properties-values-empty
|
||||
(let [file (thf/sample-file :file1)
|
||||
data (:data file)
|
||||
page (thf/current-page file)
|
||||
objects (:objects page)]
|
||||
(t/is (= (fv/extract-properties-values data objects (uuid/next))
|
||||
[]))))
|
||||
|
||||
(t/deftest extract-properties-values-non-variant
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(tho/add-simple-component :c01 :m01 :s01))
|
||||
data (:data file)
|
||||
page (thf/current-page file)
|
||||
objects (:objects page)]
|
||||
(t/is (= (fv/extract-properties-values data objects (thi/id :m01))
|
||||
[]))))
|
||||
|
||||
(t/deftest extract-properties-values-normal
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
data (:data file)
|
||||
page (thf/current-page file)
|
||||
objects (:objects page)
|
||||
result (fv/extract-properties-values data objects (thi/id :v01))]
|
||||
(t/is (seq result))
|
||||
(t/is (every? #(contains? % :name) result))
|
||||
(t/is (every? #(contains? % :value) result))
|
||||
(t/is (= (:name (first result)) "Property 1"))
|
||||
(t/is (= (set (:value (first result))) #{"Value1" "Value2"}))))
|
||||
|
||||
(t/deftest extract-properties-values-two-properties
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant-two-properties :v01 :c01 :m01 :c02 :m02))
|
||||
data (:data file)
|
||||
page (thf/current-page file)
|
||||
objects (:objects page)
|
||||
result (fv/extract-properties-values data objects (thi/id :v01))]
|
||||
(t/is (= (count result) 2))
|
||||
(t/is (= (set (map :name result)) #{"Property 1" "Property 2"}))))
|
||||
|
||||
;; ============================================================
|
||||
;; is-secondary-variant?
|
||||
;; ============================================================
|
||||
|
||||
(t/deftest is-secondary-variant-primary
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
data (:data file)
|
||||
component (thc/get-component file :c01)]
|
||||
(t/is (not (fv/is-secondary-variant? data component)))))
|
||||
|
||||
(t/deftest is-secondary-variant-secondary
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
data (:data file)
|
||||
component (thc/get-component file :c02)]
|
||||
(t/is (fv/is-secondary-variant? data component))))
|
||||
|
||||
(t/deftest is-secondary-variant-not-variant
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(tho/add-simple-component :c01 :m01 :s01))
|
||||
data (:data file)
|
||||
component (thc/get-component file :c01)]
|
||||
(t/is (not (fv/is-secondary-variant? data component)))))
|
||||
|
||||
(t/deftest is-secondary-variant-no-shapes
|
||||
(let [file (thf/sample-file :file1)
|
||||
data (:data file)
|
||||
component {:id :comp :variant-id (thi/id :file1) :main-instance-page (thi/id :file1)}]
|
||||
(t/is (not (fv/is-secondary-variant? data component)))))
|
||||
|
||||
;; ============================================================
|
||||
;; get-primary-variant
|
||||
;; ============================================================
|
||||
|
||||
(t/deftest get-primary-variant-nil
|
||||
(let [file (thf/sample-file :file1)
|
||||
data (:data file)]
|
||||
(t/is (nil? (fv/get-primary-variant data nil)))))
|
||||
|
||||
(t/deftest get-primary-variant-empty
|
||||
(let [file (thf/sample-file :file1)
|
||||
data (:data file)
|
||||
component {:id :comp :variant-id (thi/id :file1) :main-instance-page (thi/id :file1)}]
|
||||
(t/is (nil? (fv/get-primary-variant data component)))))
|
||||
|
||||
(t/deftest get-primary-variant-normal
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
data (:data file)
|
||||
component (thc/get-component file :c01)
|
||||
result (fv/get-primary-variant data component)]
|
||||
(t/is (some? result))
|
||||
(t/is (contains? result :id))
|
||||
(t/is (contains? result :component-id))))
|
||||
|
||||
;; ============================================================
|
||||
;; get-primary-component
|
||||
;; ============================================================
|
||||
|
||||
(t/deftest get-primary-component-empty
|
||||
(let [file (thf/sample-file :file1)
|
||||
data (:data file)]
|
||||
(t/is (nil? (fv/get-primary-component data nil)))
|
||||
(t/is (nil? (fv/get-primary-component data (uuid/next))))))
|
||||
|
||||
(t/deftest get-primary-component-not-variant
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(tho/add-simple-component :c01 :m01 :s01))
|
||||
data (:data file)
|
||||
result (fv/get-primary-component data (thi/id :c01))]
|
||||
(t/is (= (:id result) (thi/id :c01)))
|
||||
(t/is (= result (thc/get-component file :c01)))))
|
||||
|
||||
(t/deftest get-primary-component-already-primary
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
data (:data file)
|
||||
result (fv/get-primary-component data (thi/id :c01))]
|
||||
(t/is (= (:id result) (thi/id :c01)))
|
||||
(t/is (= result (thc/get-component file :c01)))))
|
||||
|
||||
(t/deftest get-primary-component-secondary
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
data (:data file)
|
||||
result (fv/get-primary-component data (thi/id :c02))]
|
||||
(t/is (= (:id result) (thi/id :c01)))
|
||||
(t/is (= result (thc/get-component file :c01)))))
|
||||
@ -432,7 +432,9 @@
|
||||
file-deleted (thf/apply-changes file changes)
|
||||
page-deleted (thf/current-page file-deleted)
|
||||
|
||||
changes (cll/generate-restore-component (pcb/empty-changes)
|
||||
changes (cll/generate-restore-component (-> (pcb/empty-changes)
|
||||
(pcb/with-library-data (:data file-deleted))
|
||||
(pcb/with-objects (:objects page-deleted)))
|
||||
(:data file-deleted)
|
||||
(thi/id :component1)
|
||||
(:id file-deleted)
|
||||
|
||||
657
common/test/common_tests/logic/variant_properties_test.cljc
Normal file
657
common/test/common_tests/logic/variant_properties_test.cljc
Normal file
@ -0,0 +1,657 @@
|
||||
;; 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.logic.variant-properties-test
|
||||
(:require
|
||||
[app.common.files.changes-builder :as pcb]
|
||||
[app.common.logic.variant-properties :as clvp]
|
||||
[app.common.test-helpers.components :as thc]
|
||||
[app.common.test-helpers.compositions :as tho]
|
||||
[app.common.test-helpers.files :as thf]
|
||||
[app.common.test-helpers.ids-map :as thi]
|
||||
[app.common.test-helpers.shapes :as ths]
|
||||
[app.common.test-helpers.variants :as thv]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.test :as t]))
|
||||
|
||||
(t/use-fixtures :each thi/test-fixture)
|
||||
|
||||
;; =============================================================================
|
||||
;; generate-update-property-name tests
|
||||
;; =============================================================================
|
||||
|
||||
(t/deftest test-update-property-name-no-op
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant-two-properties :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
base-changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page)))]
|
||||
|
||||
;; variant-id nil
|
||||
(let [changes (clvp/generate-update-property-name base-changes nil 0 "NewName")]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; variant-id non-existent
|
||||
(let [changes (clvp/generate-update-property-name base-changes (uuid/next) 0 "NewName")]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; pos nil
|
||||
(let [changes (clvp/generate-update-property-name base-changes v-id nil "NewName")]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; pos out of range (negative)
|
||||
(let [changes (clvp/generate-update-property-name base-changes v-id -1 "NewName")]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; pos out of range (too large)
|
||||
(let [changes (clvp/generate-update-property-name base-changes v-id 100 "NewName")]
|
||||
(t/is (pcb/empty-changes? changes)))))
|
||||
|
||||
(t/deftest test-update-property-name
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant-two-properties :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-update-property-name v-id 0 "NewName1")
|
||||
(clvp/generate-update-property-name v-id 1 "NewName2"))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (-> comp01' :variant-properties first :name) "NewName1"))
|
||||
(t/is (= (-> comp01' :variant-properties last :name) "NewName2"))
|
||||
(t/is (= (-> comp02' :variant-properties first :name) "NewName1"))
|
||||
(t/is (= (-> comp02' :variant-properties last :name) "NewName2"))))
|
||||
|
||||
(t/deftest test-update-property-name-duplicate
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant-two-properties :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-update-property-name v-id 0 "Property 2"))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
(t/is (= "Property 2 (1)" (-> comp01' :variant-properties first :name)))
|
||||
(t/is (= "Property 2" (-> comp01' :variant-properties last :name)))
|
||||
(t/is (= "Property 2 (1)" (-> comp02' :variant-properties first :name)))
|
||||
(t/is (= "Property 2" (-> comp02' :variant-properties last :name)))))
|
||||
|
||||
;; =============================================================================
|
||||
;; generate-remove-property tests
|
||||
;; =============================================================================
|
||||
|
||||
(t/deftest test-remove-property-no-op
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant-two-properties :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
orig-names (mapv :name (:variant-properties comp01))
|
||||
|
||||
base-changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page)))]
|
||||
|
||||
;; variant-id nil
|
||||
(let [changes (clvp/generate-remove-property base-changes nil 0)
|
||||
file' (thf/apply-changes file changes)
|
||||
comp01' (thc/get-component file' :c01)]
|
||||
(t/is (= orig-names (mapv :name (:variant-properties comp01')))))
|
||||
|
||||
;; variant-id non-existent
|
||||
(let [changes (clvp/generate-remove-property base-changes (uuid/next) 0)
|
||||
file' (thf/apply-changes file changes)
|
||||
comp01' (thc/get-component file' :c01)]
|
||||
(t/is (= orig-names (mapv :name (:variant-properties comp01')))))
|
||||
|
||||
;; pos nil
|
||||
(let [changes (clvp/generate-remove-property base-changes v-id nil)
|
||||
file' (thf/apply-changes file changes)
|
||||
comp01' (thc/get-component file' :c01)]
|
||||
(t/is (= orig-names (mapv :name (:variant-properties comp01')))))
|
||||
|
||||
;; pos out of range (negative)
|
||||
(let [changes (clvp/generate-remove-property base-changes v-id -1)
|
||||
file' (thf/apply-changes file changes)
|
||||
comp01' (thc/get-component file' :c01)]
|
||||
(t/is (= orig-names (mapv :name (:variant-properties comp01')))))
|
||||
|
||||
;; pos out of range (too large)
|
||||
(let [changes (clvp/generate-remove-property base-changes v-id 100)
|
||||
file' (thf/apply-changes file changes)
|
||||
comp01' (thc/get-component file' :c01)]
|
||||
(t/is (= orig-names (mapv :name (:variant-properties comp01')))))))
|
||||
|
||||
(t/deftest test-remove-property
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-add-new-property v-id))
|
||||
|
||||
file (thf/apply-changes file changes)
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
comp02 (thc/get-component file :c02)
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-remove-property v-id 0))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count (:variant-properties comp01)) 2))
|
||||
(t/is (= (count (:variant-properties comp01')) 1))
|
||||
(t/is (= (count (:variant-properties comp02)) 2))
|
||||
(t/is (= (count (:variant-properties comp02')) 1))
|
||||
(t/is (= (-> comp01' :variant-properties first :name) "Property 2"))))
|
||||
|
||||
;; =============================================================================
|
||||
;; generate-update-property-value tests
|
||||
;; =============================================================================
|
||||
|
||||
(t/deftest test-update-property-value-no-op
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant-two-properties :v01 :c01 :m01 :c02 :m02))
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
c01-id (:id comp01)
|
||||
|
||||
base-changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page)))]
|
||||
|
||||
;; component-id nil
|
||||
(let [changes (clvp/generate-update-property-value base-changes nil 0 "NewVal")]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; component-id non-existent
|
||||
(let [changes (clvp/generate-update-property-value base-changes (uuid/next) 0 "NewVal")]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; pos nil
|
||||
(let [changes (clvp/generate-update-property-value base-changes c01-id nil "NewVal")]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; pos out of range
|
||||
(let [changes (clvp/generate-update-property-value base-changes c01-id 100 "NewVal")]
|
||||
(t/is (pcb/empty-changes? changes)))))
|
||||
|
||||
(t/deftest test-update-property-value
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
comp02 (thc/get-component file :c02)
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-update-property-value (:id comp01) 0 "NewValue1")
|
||||
(clvp/generate-update-property-value (:id comp02) 0 "NewValue2"))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (-> comp01' :variant-properties first :value) "NewValue1"))
|
||||
(t/is (= (-> comp02' :variant-properties first :value) "NewValue2"))))
|
||||
|
||||
(t/deftest test-update-property-value-duplicate-value
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant-two-properties :v01 :c01 :m01 :c02 :m02))
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
comp02 (thc/get-component file :c02)
|
||||
c01-id (:id comp01)
|
||||
c02-id (:id comp02)
|
||||
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-update-property-value c01-id 0 "SharedValue")
|
||||
(clvp/generate-update-property-value c02-id 0 "SharedValue"))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
(t/is (= "SharedValue" (-> comp01' :variant-properties first :value)))
|
||||
(t/is (= "SharedValue" (-> comp02' :variant-properties first :value)))))
|
||||
|
||||
;; =============================================================================
|
||||
;; generate-set-variant-error tests
|
||||
;; =============================================================================
|
||||
|
||||
(t/deftest test-set-variant-error-no-op
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
page (thf/current-page file)
|
||||
|
||||
base-changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page)))]
|
||||
|
||||
;; component-id nil
|
||||
(let [changes (clvp/generate-set-variant-error base-changes nil "error")]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; component-id non-existent
|
||||
(let [changes (clvp/generate-set-variant-error base-changes (uuid/next) "error")]
|
||||
(t/is (pcb/empty-changes? changes)))))
|
||||
|
||||
(t/deftest test-set-variant-error-set
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
c01-id (:id comp01)
|
||||
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-set-variant-error c01-id "MyError"))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
main01' (ths/get-shape file' :m01)]
|
||||
|
||||
(t/is (= "MyError" (:variant-error main01')))))
|
||||
|
||||
(t/deftest test-set-variant-error-add-and-clear
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
c01-id (:id comp01)
|
||||
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-set-variant-error c01-id "SomeError")
|
||||
(clvp/generate-set-variant-error c01-id nil))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
main01' (ths/get-shape file' :m01)]
|
||||
|
||||
(t/is (nil? (:variant-error main01')))))
|
||||
|
||||
;; =============================================================================
|
||||
;; generate-reorder-variant-poperties tests
|
||||
;; =============================================================================
|
||||
|
||||
(t/deftest test-reorder-variant-properties-no-op
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant-two-properties :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
base-changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page)))]
|
||||
|
||||
;; variant-id nil
|
||||
(let [changes (clvp/generate-reorder-variant-poperties base-changes nil 0 1)]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; variant-id non-existent
|
||||
(let [changes (clvp/generate-reorder-variant-poperties base-changes (uuid/next) 0 1)]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; from-pos nil
|
||||
(let [changes (clvp/generate-reorder-variant-poperties base-changes v-id nil 1)]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; to-space-between-pos nil
|
||||
(let [changes (clvp/generate-reorder-variant-poperties base-changes v-id 0 nil)]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; from-pos negative is clamped to 0
|
||||
(let [changes (clvp/generate-reorder-variant-poperties base-changes v-id -1 1)]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; to-space-between-pos too large is clamped to last index
|
||||
(let [changes (clvp/generate-reorder-variant-poperties base-changes v-id 1 100)]
|
||||
(t/is (pcb/empty-changes? changes)))))
|
||||
|
||||
(t/deftest test-reorder-variant-properties-move
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant-two-properties :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-reorder-variant-poperties v-id 0 2))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
comp01' (thc/get-component file' :c01)]
|
||||
|
||||
(t/is (= "Property 2" (-> comp01' :variant-properties first :name)))
|
||||
(t/is (= "Property 1" (-> comp01' :variant-properties last :name)))))
|
||||
|
||||
(t/deftest test-reorder-variant-properties-clamped-pos
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant-two-properties :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
base-changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page)))]
|
||||
|
||||
(let [changes (clvp/generate-reorder-variant-poperties base-changes v-id 0 100)
|
||||
file' (thf/apply-changes file changes)
|
||||
comp01' (thc/get-component file' :c01)]
|
||||
(t/is (= "Property 2" (-> comp01' :variant-properties first :name)))
|
||||
(t/is (= "Property 1" (-> comp01' :variant-properties last :name))))
|
||||
|
||||
(let [changes (clvp/generate-reorder-variant-poperties base-changes v-id 1 -1)
|
||||
file' (thf/apply-changes file changes)
|
||||
comp01' (thc/get-component file' :c01)]
|
||||
(t/is (= "Property 2" (-> comp01' :variant-properties first :name)))
|
||||
(t/is (= "Property 1" (-> comp01' :variant-properties last :name))))))
|
||||
|
||||
;; =============================================================================
|
||||
;; generate-add-new-property tests
|
||||
;; =============================================================================
|
||||
|
||||
(t/deftest test-add-new-property-no-op
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
page (thf/current-page file)
|
||||
|
||||
base-changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page)))]
|
||||
|
||||
;; variant-id nil
|
||||
(let [changes (clvp/generate-add-new-property base-changes nil)]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; variant-id non-existent
|
||||
(let [changes (clvp/generate-add-new-property base-changes (uuid/next))]
|
||||
(t/is (pcb/empty-changes? changes)))))
|
||||
|
||||
(t/deftest test-add-new-property-without-values
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
comp02 (thc/get-component file :c02)
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-add-new-property v-id))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count (:variant-properties comp01)) 1))
|
||||
(t/is (= (count (:variant-properties comp01')) 2))
|
||||
(t/is (= (count (:variant-properties comp02)) 1))
|
||||
(t/is (= (count (:variant-properties comp02')) 2))
|
||||
(t/is (= (-> comp01' :variant-properties last :value) ""))))
|
||||
|
||||
(t/deftest test-add-new-property-with-values
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
comp02 (thc/get-component file :c02)
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-add-new-property v-id {:fill-values? true}))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count (:variant-properties comp01)) 1))
|
||||
(t/is (= (count (:variant-properties comp01')) 2))
|
||||
(t/is (= (count (:variant-properties comp02)) 1))
|
||||
(t/is (= (count (:variant-properties comp02')) 2))
|
||||
(t/is (= (-> comp01' :variant-properties last :value) "Value 1"))
|
||||
(t/is (= (-> comp02' :variant-properties last :value) "Value 2"))))
|
||||
|
||||
(t/deftest test-add-new-property-with-the-same-value
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
comp02 (thc/get-component file :c02)
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-add-new-property v-id {:property-value "Value 1"}))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count (:variant-properties comp01)) 1))
|
||||
(t/is (= (count (:variant-properties comp01')) 2))
|
||||
(t/is (= (count (:variant-properties comp02)) 1))
|
||||
(t/is (= (count (:variant-properties comp02')) 2))
|
||||
(t/is (= (-> comp01' :variant-properties last :value) "Value 1"))
|
||||
(t/is (= (-> comp02' :variant-properties last :value) "Value 1"))))
|
||||
|
||||
(t/deftest test-add-new-property-duplicate-name
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-add-new-property v-id {:property-name "Property 1"}))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
comp01' (thc/get-component file' :c01)
|
||||
prop-names (mapv :name (:variant-properties comp01'))]
|
||||
|
||||
(t/is (= 2 (count prop-names)))
|
||||
(t/is (= "Property 1" (first prop-names)))
|
||||
(t/is (= "Property 1 (1)" (last prop-names)))))
|
||||
|
||||
;; =============================================================================
|
||||
;; generate-make-shapes-no-variant tests
|
||||
;; =============================================================================
|
||||
|
||||
(t/deftest test-make-shapes-no-variant-no-op
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
page (thf/current-page file)
|
||||
|
||||
base-changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page)))]
|
||||
|
||||
;; empty shapes list
|
||||
(let [changes (clvp/generate-make-shapes-no-variant base-changes [])]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; nil shapes list
|
||||
(let [changes (clvp/generate-make-shapes-no-variant base-changes nil)]
|
||||
(t/is (pcb/empty-changes? changes)))))
|
||||
|
||||
(t/deftest test-make-shapes-no-variant-remove
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
page (thf/current-page file)
|
||||
|
||||
main01 (ths/get-shape file :m01)
|
||||
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-make-shapes-no-variant [main01]))
|
||||
|
||||
file' (thf/apply-changes file changes :validate? false)
|
||||
|
||||
comp01' (thc/get-component file' :c01)
|
||||
main01' (ths/get-shape file' :m01)]
|
||||
|
||||
(t/is (nil? (:variant-id comp01')))
|
||||
(t/is (nil? (:variant-properties comp01')))
|
||||
(t/is (nil? (:variant-id main01')))
|
||||
(t/is (nil? (:variant-name main01')))))
|
||||
|
||||
;; =============================================================================
|
||||
;; generate-make-shapes-variant tests
|
||||
;; =============================================================================
|
||||
|
||||
(t/deftest test-make-shapes-variant-no-op
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
page (thf/current-page file)
|
||||
|
||||
base-changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page)))
|
||||
|
||||
container (ths/get-shape file :v01)]
|
||||
|
||||
;; empty shapes list
|
||||
(let [changes (clvp/generate-make-shapes-variant base-changes [] container)]
|
||||
(t/is (pcb/empty-changes? changes)))
|
||||
|
||||
;; nil shapes list
|
||||
(let [container (ths/get-shape file :v01)
|
||||
changes (clvp/generate-make-shapes-variant base-changes nil container)]
|
||||
(t/is (pcb/empty-changes? changes)))))
|
||||
|
||||
(t/deftest test-make-shapes-variant-convert
|
||||
(let [file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
|
||||
container (ths/get-shape file :v01)
|
||||
v-id (:id container)
|
||||
|
||||
;; Add a non-variant component under the variant container
|
||||
file (tho/add-simple-component file :c03 :m03 :sh03
|
||||
:root-params {:parent-label :v01})
|
||||
|
||||
m03 (ths/get-shape file :m03)
|
||||
page (thf/current-page file)
|
||||
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-make-shapes-variant [m03] container))
|
||||
|
||||
file' (thf/apply-changes file changes :validate? false)
|
||||
|
||||
c03' (thc/get-component file' :c03)
|
||||
m03' (ths/get-shape file' :m03)]
|
||||
|
||||
(t/is (= v-id (:variant-id c03')))
|
||||
(t/is (= v-id (:variant-id m03')))
|
||||
(t/is (= "Property 1" (-> c03' :variant-properties first :name)))
|
||||
(t/is (= "Frame1" (-> c03' :variant-properties first :value)))
|
||||
(t/is (= "Frame1" (-> m03' :variant-name)))))
|
||||
@ -10,8 +10,6 @@
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.logic.libraries :as cll]
|
||||
[app.common.logic.shapes :as cls]
|
||||
[app.common.logic.variant-properties :as clvp]
|
||||
[app.common.test-helpers.components :as thc]
|
||||
[app.common.test-helpers.files :as thf]
|
||||
[app.common.test-helpers.ids-map :as thi]
|
||||
[app.common.test-helpers.shapes :as ths]
|
||||
@ -20,221 +18,6 @@
|
||||
|
||||
(t/use-fixtures :each thi/test-fixture)
|
||||
|
||||
(t/deftest test-update-property-name
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant-two-properties :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-update-property-name v-id 0 "NewName1")
|
||||
(clvp/generate-update-property-name v-id 1 "NewName2"))
|
||||
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (-> comp01' :variant-properties first :name) "NewName1"))
|
||||
(t/is (= (-> comp01' :variant-properties last :name) "NewName2"))
|
||||
(t/is (= (-> comp02' :variant-properties first :name) "NewName1"))
|
||||
(t/is (= (-> comp02' :variant-properties last :name) "NewName2"))))
|
||||
|
||||
|
||||
|
||||
(t/deftest test-add-new-property-without-values
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
comp02 (thc/get-component file :c02)
|
||||
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-add-new-property v-id))
|
||||
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count (:variant-properties comp01)) 1))
|
||||
(t/is (= (count (:variant-properties comp01')) 2))
|
||||
(t/is (= (count (:variant-properties comp02)) 1))
|
||||
(t/is (= (count (:variant-properties comp02')) 2))
|
||||
(t/is (= (-> comp01' :variant-properties last :value) ""))))
|
||||
|
||||
|
||||
|
||||
(t/deftest test-add-new-property-with-values
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
comp02 (thc/get-component file :c02)
|
||||
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-add-new-property v-id {:fill-values? true}))
|
||||
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count (:variant-properties comp01)) 1))
|
||||
(t/is (= (count (:variant-properties comp01')) 2))
|
||||
(t/is (= (count (:variant-properties comp02)) 1))
|
||||
(t/is (= (count (:variant-properties comp02')) 2))
|
||||
(t/is (= (-> comp01' :variant-properties last :value) "Value 1"))
|
||||
(t/is (= (-> comp02' :variant-properties last :value) "Value 2"))))
|
||||
|
||||
|
||||
|
||||
(t/deftest test-add-new-property-with-the-same-value
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
comp02 (thc/get-component file :c02)
|
||||
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-add-new-property v-id {:property-value "Value 1"}))
|
||||
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count (:variant-properties comp01)) 1))
|
||||
(t/is (= (count (:variant-properties comp01')) 2))
|
||||
(t/is (= (count (:variant-properties comp02)) 1))
|
||||
(t/is (= (count (:variant-properties comp02')) 2))
|
||||
(t/is (= (-> comp01' :variant-properties last :value) "Value 1"))
|
||||
(t/is (= (-> comp02' :variant-properties last :value) "Value 1"))))
|
||||
|
||||
|
||||
|
||||
(t/deftest test-remove-property
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
v-id (-> (ths/get-shape file :v01) :id)
|
||||
page (thf/current-page file)
|
||||
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-add-new-property v-id))
|
||||
|
||||
|
||||
file (thf/apply-changes file changes)
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
comp02 (thc/get-component file :c02)
|
||||
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-remove-property v-id 0))
|
||||
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count (:variant-properties comp01)) 2))
|
||||
(t/is (= (count (:variant-properties comp01')) 1))
|
||||
(t/is (= (count (:variant-properties comp02)) 2))
|
||||
(t/is (= (count (:variant-properties comp02')) 1))
|
||||
(t/is (= (-> comp01' :variant-properties first :name) "Property 2"))))
|
||||
|
||||
(t/deftest test-update-property-value
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||
|
||||
page (thf/current-page file)
|
||||
|
||||
comp01 (thc/get-component file :c01)
|
||||
comp02 (thc/get-component file :c02)
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(clvp/generate-update-property-value (:id comp01) 0 "NewValue1")
|
||||
(clvp/generate-update-property-value (:id comp02) 0 "NewValue2"))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
comp01' (thc/get-component file' :c01)
|
||||
comp02' (thc/get-component file' :c02)]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (-> comp01' :variant-properties first :value) "NewValue1"))
|
||||
(t/is (= (-> comp02' :variant-properties first :value) "NewValue2"))))
|
||||
|
||||
|
||||
(t/deftest test-duplicate-variant-container
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
@ -245,9 +28,6 @@
|
||||
|
||||
variant-container (ths/get-shape file :v01)
|
||||
|
||||
|
||||
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
@ -274,7 +54,6 @@
|
||||
(t/is (= (count objects) 4))
|
||||
(t/is (= (count objects') 7))))
|
||||
|
||||
|
||||
(t/deftest test-delete-variant
|
||||
;; When a variant container becomes empty, it id automatically deleted
|
||||
(let [;; ==== Setup
|
||||
@ -288,7 +67,7 @@
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page-id (:id page))
|
||||
(pcb/with-page page)
|
||||
(pcb/with-library-data (:data file))
|
||||
(pcb/with-objects (:objects page))
|
||||
(#(second (cls/generate-delete-shapes % #{m01-id m02-id} {}))))
|
||||
@ -304,7 +83,6 @@
|
||||
;; The variant containew is nil after the deletion
|
||||
(t/is (nil? container'))))
|
||||
|
||||
|
||||
(t/deftest test-instantiate-component-over-variant-container
|
||||
;; When a component is instantiated at a position over a variant container,
|
||||
;; the new copy must not become a child of the container (its children can
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
[common-tests.files.shapes-builder-test]
|
||||
[common-tests.files.tokens-test]
|
||||
[common-tests.files.validate-test]
|
||||
[common-tests.files.variant-test]
|
||||
[common-tests.geom-align-test]
|
||||
[common-tests.geom-bounds-layout-nil-test]
|
||||
[common-tests.geom-bounds-map-test]
|
||||
@ -136,6 +137,7 @@
|
||||
'common-tests.files.shapes-builder-test
|
||||
'common-tests.files.tokens-test
|
||||
'common-tests.files.validate-test
|
||||
'common-tests.files.variant-test
|
||||
'common-tests.geom-align-test
|
||||
'common-tests.geom-bounds-layout-nil-test
|
||||
'common-tests.geom-bounds-map-test
|
||||
@ -187,6 +189,7 @@
|
||||
'common-tests.logic.variants-switch-test
|
||||
'common-tests.logic.variants-test
|
||||
'common-tests.math-test
|
||||
'common-tests.types.variant-test
|
||||
'common-tests.media-test
|
||||
'common-tests.path-names-test
|
||||
'common-tests.path-names-tree-test
|
||||
|
||||
@ -7,10 +7,238 @@
|
||||
(ns common-tests.types.variant-test
|
||||
(:require
|
||||
[app.common.types.variant :as ctv]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.test :as t]))
|
||||
|
||||
(t/deftest variant-component
|
||||
(t/is (not (ctv/variant-component? nil)))
|
||||
(t/is (not (ctv/variant-component? {})))
|
||||
(t/is (ctv/variant-component? {:variant-id (uuid/next)})))
|
||||
|
||||
(t/deftest variant-distance01
|
||||
(t/deftest variant-shape
|
||||
(t/is (not (ctv/variant-shape? nil)))
|
||||
(t/is (not (ctv/variant-shape? {})))
|
||||
(t/is (ctv/variant-shape? {:variant-id (uuid/next)})))
|
||||
|
||||
(t/deftest variant-container
|
||||
(t/is (not (ctv/variant-container? nil)))
|
||||
(t/is (not (ctv/variant-container? {})))
|
||||
(t/is (ctv/variant-container? {:is-variant-container true})))
|
||||
|
||||
(t/deftest properties-to-name-test
|
||||
(t/is (= "" (ctv/properties-to-name [])))
|
||||
(t/is (= "" (ctv/properties-to-name nil)))
|
||||
(t/is (= "Button, Primary" (ctv/properties-to-name [{:name "Property 1" :value "Button"}
|
||||
{:name "Property 2" :value "Primary"}])))
|
||||
(t/is (= "Button" (ctv/properties-to-name [{:name "Property 1" :value "Button"}
|
||||
{:name "Property 2" :value ""}]))))
|
||||
|
||||
(t/deftest next-property-number-test
|
||||
(t/is (= 1 (ctv/next-property-number [])))
|
||||
(t/is (= 1 (ctv/next-property-number nil)))
|
||||
(t/is (= 2 (ctv/next-property-number [{:name "Property 1" :value "x"}])))
|
||||
(t/is (= 4 (ctv/next-property-number [{:name "Property 3" :value "x"}])))
|
||||
(t/is (= 3 (ctv/next-property-number [{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}]))))
|
||||
|
||||
(t/deftest add-new-property-test
|
||||
(t/is (= [{:name "Property 1" :value "x"}]
|
||||
(ctv/add-new-property [] "x")))
|
||||
(t/is (= [{:name "Property 1" :value "x"}]
|
||||
(ctv/add-new-property nil "x")))
|
||||
(t/is (= [{:name "Property 1" :value "x"} {:name "Property 2" :value "y"}]
|
||||
(ctv/add-new-property [{:name "Property 1" :value "x"}] "y"))))
|
||||
|
||||
(t/deftest add-new-properties-test
|
||||
(t/is (= [{:name "Property 1" :value "a"} {:name "Property 2" :value "b"}]
|
||||
(ctv/add-new-properties [] ["a" "b"])))
|
||||
(t/is (= '({:name "Property 2" :value "b"} {:name "Property 1" :value "a"})
|
||||
(ctv/add-new-properties nil ["a" "b"])))
|
||||
(t/is (= [{:name "Property 1" :value "x"} {:name "Property 2" :value "a"} {:name "Property 3" :value "b"}]
|
||||
(ctv/add-new-properties [{:name "Property 1" :value "x"}] ["a" "b"]))))
|
||||
|
||||
(t/deftest path-to-properties-test
|
||||
(t/is (= [] (ctv/path-to-properties "" [])))
|
||||
(t/is (= [{:name "Property 1" :value "a"} {:name "Property 2" :value "b"}]
|
||||
(ctv/path-to-properties "a / b" nil)))
|
||||
(t/is (= [{:name "Property 1" :value "Button"}
|
||||
{:name "Property 2" :value "Primary"}
|
||||
{:name "Property 3" :value "Hover"}]
|
||||
(ctv/path-to-properties "Button / Primary / Hover" [])))
|
||||
(t/is (= [{:name "Property 1" :value "Button"}
|
||||
{:name "Property 2" :value "Primary"}
|
||||
{:name "Property 3" :value "Hover"}
|
||||
{:name "Property 4" :value ""}]
|
||||
(ctv/path-to-properties "Button / Primary / Hover" [] 4)))
|
||||
(t/is (= [{:name "Property 1" :value "Button"}
|
||||
{:name "Property 2" :value "Primary"}]
|
||||
(ctv/path-to-properties "Button / Primary" [{:name "Property 1" :value "old"}
|
||||
{:name "Property 2" :value "old2"}]))))
|
||||
|
||||
(t/deftest properties-map->formula-test
|
||||
(t/is (= "" (ctv/properties-map->formula [])))
|
||||
(t/is (= "" (ctv/properties-map->formula nil)))
|
||||
(t/is (= "Property 1=Button, Property 2=Primary"
|
||||
(ctv/properties-map->formula [{:name "Property 1" :value "Button"}
|
||||
{:name "Property 2" :value "Primary"}])))
|
||||
(t/is (= "Property 1=Button"
|
||||
(ctv/properties-map->formula [{:name "Property 1" :value "Button"}
|
||||
{:name "Property 2" :value ""}]))))
|
||||
|
||||
(t/deftest properties-formula->map-test
|
||||
(t/is (= [] (ctv/properties-formula->map "")))
|
||||
(t/is (= [] (ctv/properties-formula->map nil)))
|
||||
(t/is (= [{:name "Property 1" :value "Button"} {:name "Property 2" :value "Primary"}]
|
||||
(ctv/properties-formula->map "Property 1=Button, Property 2=Primary")))
|
||||
(t/is (= [{:name "Property 1" :value "Button"}]
|
||||
(ctv/properties-formula->map "Property 1=Button, Property 2="))))
|
||||
|
||||
(t/deftest valid-properties-formula?-test
|
||||
(t/is (= true (ctv/valid-properties-formula? "Property 1=Button, Property 2=Primary")))
|
||||
(t/is (= false (ctv/valid-properties-formula? "")))
|
||||
(t/is (= true (ctv/valid-properties-formula? nil)))
|
||||
(t/is (= false (ctv/valid-properties-formula? "Property 1=Button, Property 2"))))
|
||||
|
||||
(t/deftest find-properties-to-remove-test
|
||||
(t/is (= [] (ctv/find-properties-to-remove [] [])))
|
||||
(t/is (= [] (ctv/find-properties-to-remove nil nil)))
|
||||
(t/is (= [{:name "Property 3" :value "z"}]
|
||||
(ctv/find-properties-to-remove [{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}
|
||||
{:name "Property 3" :value "z"}]
|
||||
[{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}])))
|
||||
(t/is (= [{:name "Property 1" :value "x"} {:name "Property 2" :value "y"}]
|
||||
(ctv/find-properties-to-remove [{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}]
|
||||
[{:name "Property 3" :value "z"}]))))
|
||||
|
||||
(t/deftest find-properties-to-update-test
|
||||
(t/is (= [] (ctv/find-properties-to-update [] [])))
|
||||
(t/is (= [] (ctv/find-properties-to-update nil nil)))
|
||||
(t/is (= [{:name "Property 1" :value "new-x"}]
|
||||
(ctv/find-properties-to-update [{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}]
|
||||
[{:name "Property 1" :value "new-x"}
|
||||
{:name "Property 2" :value "y"}])))
|
||||
(t/is (= [{:name "Property 1" :value "new-x"} {:name "Property 2" :value "new-y"}]
|
||||
(ctv/find-properties-to-update [{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}]
|
||||
[{:name "Property 1" :value "new-x"}
|
||||
{:name "Property 2" :value "new-y"}]))))
|
||||
|
||||
(t/deftest find-properties-to-add-test
|
||||
(t/is (= [] (ctv/find-properties-to-add [] [])))
|
||||
(t/is (= [] (ctv/find-properties-to-add nil nil)))
|
||||
(t/is (= [{:name "Property 3" :value "z"}]
|
||||
(ctv/find-properties-to-add [{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}]
|
||||
[{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}
|
||||
{:name "Property 3" :value "z"}])))
|
||||
(t/is (= [{:name "Property 2" :value "y"}]
|
||||
(ctv/find-properties-to-add [{:name "Property 1" :value "x"}]
|
||||
[{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}]))))
|
||||
|
||||
(t/deftest update-number-in-repeated-item-test
|
||||
(t/is (= "Property" (ctv/update-number-in-repeated-item [] "Property")))
|
||||
(t/is (= "Property" (ctv/update-number-in-repeated-item nil "Property")))
|
||||
(t/is (= "Property (1)" (ctv/update-number-in-repeated-item ["Property"] "Property")))
|
||||
(t/is (= "Property (2)" (ctv/update-number-in-repeated-item ["Property" "Property (1)"] "Property")))
|
||||
(t/is (= "Property" (ctv/update-number-in-repeated-item ["Other"] "Property"))))
|
||||
|
||||
(t/deftest update-number-in-repeated-prop-names-test
|
||||
(t/is (= [] (ctv/update-number-in-repeated-prop-names [])))
|
||||
(t/is (= [] (ctv/update-number-in-repeated-prop-names nil)))
|
||||
(t/is (= [{:name "Property" :value "x"}]
|
||||
(ctv/update-number-in-repeated-prop-names [{:name "Property" :value "x"}])))
|
||||
(t/is (= [{:name "Property" :value "x"} {:name "Property (1)" :value "y"}]
|
||||
(ctv/update-number-in-repeated-prop-names [{:name "Property" :value "x"}
|
||||
{:name "Property" :value "y"}])))
|
||||
(t/is (= [{:name "Property" :value "x"} {:name "Property (1)" :value "y"} {:name "Property (2)" :value "z"}]
|
||||
(ctv/update-number-in-repeated-prop-names [{:name "Property" :value "x"}
|
||||
{:name "Property" :value "y"}
|
||||
{:name "Property" :value "z"}]))))
|
||||
|
||||
(t/deftest find-index-for-property-name-test
|
||||
(t/is (= nil (ctv/find-index-for-property-name [] "Property 1")))
|
||||
(t/is (= nil (ctv/find-index-for-property-name nil "Property 1")))
|
||||
(t/is (= 0 (ctv/find-index-for-property-name [{:name "Property 1" :value "x"}] "Property 1")))
|
||||
(t/is (= 1 (ctv/find-index-for-property-name [{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}] "Property 2")))
|
||||
(t/is (= nil (ctv/find-index-for-property-name [{:name "Property 1" :value "x"}] "Property 3"))))
|
||||
|
||||
(t/deftest remove-prefix-test
|
||||
(t/is (= "name" (ctv/remove-prefix "name" "")))
|
||||
(t/is (= "name" (ctv/remove-prefix "name" nil)))
|
||||
(t/is (= "Primary" (ctv/remove-prefix "Button / Primary" "Button")))
|
||||
(t/is (= "Primary" (ctv/remove-prefix "Button / Primary" "Button / ")))
|
||||
(t/is (= "Button / Primary" (ctv/remove-prefix "Button / Primary" "Other"))))
|
||||
|
||||
(t/deftest merge-properties-test
|
||||
(t/is (= [] (ctv/merge-properties [] [])))
|
||||
(t/is (= [] (ctv/merge-properties nil nil)))
|
||||
(t/is (= [{:name "Property 1" :value "x"} {:name "Property 2" :value "y"}]
|
||||
(ctv/merge-properties [{:name "Property 1" :value "a"}
|
||||
{:name "Property 2" :value "b"}]
|
||||
[{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}])))
|
||||
(t/is (= [{:name "Property 1" :value "x"} {:name "Property 2" :value "y"} {:name "Property 3" :value "z"}]
|
||||
(ctv/merge-properties [{:name "Property 1" :value "a"}
|
||||
{:name "Property 2" :value "b"}]
|
||||
[{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}
|
||||
{:name "Property 3" :value "z"}])))
|
||||
(t/is (= [{:name "Property 1" :value "a"} {:name "Property 2" :value "y"}]
|
||||
(ctv/merge-properties [{:name "Property 1" :value "a"}
|
||||
{:name "Property 2" :value "b"}]
|
||||
[{:name "Property 2" :value "y"}]))))
|
||||
|
||||
(t/deftest compare-properties-test
|
||||
(t/is (= [] (ctv/compare-properties [])))
|
||||
(t/is (= [] (ctv/compare-properties nil)))
|
||||
(t/is (= [{:name "Property 1" :value "x"} {:name "Property 2" :value "y"}]
|
||||
(ctv/compare-properties [[{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}]])))
|
||||
(t/is (= [{:name "Property 1" :value "x"} {:name "Property 2" :value nil}]
|
||||
(ctv/compare-properties [[{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}]
|
||||
[{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "z"}]])))
|
||||
(t/is (= [{:name "Property 1" :value "x"} {:name "Property 2" :value "*"}]
|
||||
(ctv/compare-properties [[{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "y"}]
|
||||
[{:name "Property 1" :value "x"}
|
||||
{:name "Property 2" :value "z"}]]
|
||||
"*"))))
|
||||
|
||||
(t/deftest variant-name-to-name-test
|
||||
(t/is (= "Button / Primary / Hover" (ctv/variant-name-to-name {:name "Button" :variant-name "Primary, Hover"})))
|
||||
(t/is (= "Button" (ctv/variant-name-to-name {:name "Button" :variant-name ""})))
|
||||
(t/is (= "Button" (ctv/variant-name-to-name {:name "Button" :variant-name nil})))
|
||||
(t/is (= "" (ctv/variant-name-to-name {:name "" :variant-name ""})))
|
||||
(t/is (= nil (ctv/variant-name-to-name {:name nil :variant-name nil}))))
|
||||
|
||||
(t/deftest find-boolean-pair-test
|
||||
(t/is (= {"on" true "off" false} (ctv/find-boolean-pair ["on" "off"])))
|
||||
(t/is (= {"yes" true "no" false} (ctv/find-boolean-pair ["yes" "no"])))
|
||||
(t/is (= {"true" true "false" false} (ctv/find-boolean-pair ["true" "false"])))
|
||||
(t/is (= {"on" true "off" false} (ctv/find-boolean-pair ["off" "on"])))
|
||||
(t/is (= {"ON" true "OFF" false} (ctv/find-boolean-pair ["ON" "OFF"])))
|
||||
(t/is (= nil (ctv/find-boolean-pair ["foo" "bar"])))
|
||||
(t/is (= nil (ctv/find-boolean-pair nil)))
|
||||
(t/is (= nil (ctv/find-boolean-pair ["on"]))))
|
||||
|
||||
(t/deftest same-variant?-test
|
||||
(t/is (= false (ctv/same-variant? [])))
|
||||
(t/is (= false (ctv/same-variant? nil)))
|
||||
(t/is (= true (ctv/same-variant? [{:variant-id "abc"}])))
|
||||
(t/is (= true (ctv/same-variant? [{:variant-id "abc"} {:variant-id "abc"}])))
|
||||
(t/is (= false (ctv/same-variant? [{:variant-id "abc"} {:variant-id "def"}])))
|
||||
(t/is (= false (ctv/same-variant? [{:variant-id ""} {:variant-id ""}]))))
|
||||
|
||||
(t/deftest properties-distance01
|
||||
;;c1: primary, default, rounded, blue, dark
|
||||
;;c2: primary, hover, squared, blue, dark
|
||||
;;c3: primary, default, squared, blue, light
|
||||
@ -35,12 +263,11 @@
|
||||
{:name "borders" :value "rounded"}
|
||||
{:name "color" :value "blue"}
|
||||
{:name "theme" :value "light"}]
|
||||
dist2 (ctv/distance target props2)
|
||||
dist3 (ctv/distance target props3)]
|
||||
dist2 (ctv/properties-distance target props2)
|
||||
dist3 (ctv/properties-distance target props3)]
|
||||
(t/is (< dist3 dist2))))
|
||||
|
||||
|
||||
(t/deftest variant-distance02
|
||||
(t/deftest properties-distance02
|
||||
;;c1: primary, default, rounded, blue, dark
|
||||
;;c2: primary, hover, squared, red, dark
|
||||
;;c3: secondary, hover, rounded, blue, dark
|
||||
@ -65,11 +292,11 @@
|
||||
{:name "borders" :value "rounded"}
|
||||
{:name "color" :value "blue"}
|
||||
{:name "theme" :value "dark"}]
|
||||
dist2 (ctv/distance target props2)
|
||||
dist3 (ctv/distance target props3)]
|
||||
dist2 (ctv/properties-distance target props2)
|
||||
dist3 (ctv/properties-distance target props3)]
|
||||
(t/is (< dist2 dist3))))
|
||||
|
||||
(t/deftest variant-distance03
|
||||
(t/deftest properties-distance03
|
||||
;;c1: primary, default, rounded, blue, dark
|
||||
;;c2: secondary, default, rounded, blue, light
|
||||
;;c3: secondary, hover, squared, blue, dark
|
||||
@ -101,12 +328,18 @@
|
||||
{:name "borders" :value "rounded"}
|
||||
{:name "color" :value "blue"}
|
||||
{:name "theme" :value "dark"}]
|
||||
dist2 (ctv/distance target props2)
|
||||
dist3 (ctv/distance target props3)
|
||||
dist4 (ctv/distance target props4)]
|
||||
dist2 (ctv/properties-distance target props2)
|
||||
dist3 (ctv/properties-distance target props3)
|
||||
dist4 (ctv/properties-distance target props4)]
|
||||
(t/is (< dist2 dist4))
|
||||
(t/is (< dist4 dist3))))
|
||||
|
||||
(t/deftest properties-distance04
|
||||
(t/is (= 0 (ctv/properties-distance [] [])))
|
||||
(t/is (= 0 (ctv/properties-distance nil nil)))
|
||||
(t/is (= 0 (ctv/properties-distance [{:name "a" :value "x"}] [{:name "a" :value "x"}])))
|
||||
(t/is (= 2.0 (ctv/properties-distance [{:name "a" :value "x"} {:name "b" :value "y"}] [{:name "a" :value "x"} {:name "b" :value "z"}]))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1230,26 +1230,28 @@
|
||||
(ptk/reify ::show-component-in-assets
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [file-id (:current-file-id state)
|
||||
fdata (dsh/lookup-file-data state file-id)
|
||||
component (cfv/get-primary-component fdata component-id)
|
||||
cpath (:path component)
|
||||
cpath (cpn/split-path cpath)
|
||||
paths (map (fn [i] (cpn/join-path (take (inc i) cpath)))
|
||||
(range (count cpath)))]
|
||||
(let [file-id (:current-file-id state)
|
||||
fdata (dsh/lookup-file-data state file-id)
|
||||
primary-component (cfv/get-primary-component fdata component-id)
|
||||
cpath (:path primary-component)
|
||||
cpath (cpn/split-path cpath)
|
||||
paths (map (fn [i] (cpn/join-path (take (inc i) cpath)))
|
||||
(range (count cpath)))]
|
||||
(rx/concat
|
||||
(rx/from (map #(set-assets-group-open file-id :components % true) paths))
|
||||
(rx/of (dcm/go-to-workspace :layout :assets)
|
||||
(set-assets-section-open file-id :library true)
|
||||
(set-assets-section-open file-id :components true)
|
||||
(select-single-asset file-id (:id component) :components)))))
|
||||
(select-single-asset file-id (:id primary-component) :components)))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [file-id (:current-file-id state)
|
||||
fdata (dsh/lookup-file-data state file-id)
|
||||
component (cfv/get-primary-component fdata component-id)
|
||||
wrapper-id (str "component-shape-id-" (:id component))]
|
||||
(let [file-id (:current-file-id state)
|
||||
fdata (dsh/lookup-file-data state file-id)
|
||||
component (ctkl/get-component fdata component-id)
|
||||
primary-variant (cfv/get-primary-variant fdata component)
|
||||
primary-component (ctkl/get-component fdata (:component-id primary-variant))
|
||||
wrapper-id (str "component-shape-id-" (:id primary-component))]
|
||||
(tm/schedule-on-idle #(dom/scroll-into-view-if-needed! (dom/get-element wrapper-id)))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@ -803,7 +803,7 @@
|
||||
(remove #(= (:id %) component-id))
|
||||
(filter #(= (dm/get-in % [:variant-properties pos :value]) val))
|
||||
(reverse))
|
||||
nearest-comp (apply min-key #(ctv/distance target-props (:variant-properties %)) valid-comps)
|
||||
nearest-comp (apply min-key #(ctv/properties-distance target-props (:variant-properties %)) valid-comps)
|
||||
shape-parents (cfh/get-parents-with-self current-page-objects (:parent-id shape))
|
||||
nearest-comp-children (cfh/get-children-with-self component-page-objects (:main-instance-id nearest-comp))
|
||||
comps-nesting-loop? (seq? (cfh/components-nesting-loop? nearest-comp-children shape-parents))
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
graphics 0
|
||||
typographies (count (:typographies data))
|
||||
components (count (->> (ctkl/components-seq data)
|
||||
(remove #(cfv/is-secondary-variant? % data))))
|
||||
(remove #(cfv/is-secondary-variant? data %))))
|
||||
tokens-lib (cfo/get-tokens-lib data)
|
||||
tokens (if (some? tokens-lib) (count (ctob/get-all-tokens tokens-lib)) 0)
|
||||
token-sets (if (some? tokens-lib) (count (ctob/get-sets tokens-lib)) 0)
|
||||
|
||||
@ -345,7 +345,7 @@
|
||||
(mf/with-memo [filters library]
|
||||
(as-> (into [] (ctkl/components-seq library)) $
|
||||
(cmm/apply-filters $ filters)
|
||||
(remove #(cfv/is-secondary-variant? % library) $)))
|
||||
(remove #(cfv/is-secondary-variant? library %) $)))
|
||||
|
||||
filtered-typographies
|
||||
(mf/with-memo [filters typographies]
|
||||
|
||||
@ -717,7 +717,7 @@
|
||||
:components
|
||||
vals
|
||||
(remove #(true? (:deleted %)))
|
||||
(remove #(cfv/is-secondary-variant? % current-lib-data))
|
||||
(remove #(cfv/is-secondary-variant? current-lib-data %))
|
||||
(map #(assoc % :full-name (cpn/merge-path-item-with-dot (:path %) (:name %)))))
|
||||
|
||||
count-variants (fn [component]
|
||||
|
||||
@ -1150,7 +1150,7 @@
|
||||
components (->> data
|
||||
:components
|
||||
(remove (comp :deleted second))
|
||||
(remove (comp #(cfv/is-secondary-variant? % data) second))
|
||||
(remove (comp #(cfv/is-secondary-variant? data %) second))
|
||||
(map first)
|
||||
(map #(lib-component-proxy plugin-id file-id %)))]
|
||||
(apply array components)))}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user