mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 14:00:37 +00:00
🚧 WIP Step 5, bools
This commit is contained in:
parent
bd17e6d431
commit
bfde40d1ab
@ -19,7 +19,10 @@
|
||||
(frame {:x 0 :y 0 :width 100 :height 100}
|
||||
(rect))
|
||||
(group :tiles {}
|
||||
(rect [:tile 3] {})))
|
||||
(rect [:tile 3] {}))
|
||||
(bool :diff {:bool-type :difference}
|
||||
(rect {:x 0 :y 0 :width 100 :height 100})
|
||||
(rect {:x 50 :y 50 :width 100 :height 100})))
|
||||
|
||||
`params` is a map with `:seed` (required), optional `:root` attributes for
|
||||
the canonical root frame, and optional `:defaults` with one attribute
|
||||
@ -114,3 +117,28 @@
|
||||
~label-or-attrs
|
||||
nil
|
||||
(fn [] ~@body))))
|
||||
|
||||
(defmacro bool
|
||||
"Adds a boolean shape to the current scope, runs `body` with the bool as
|
||||
parent, and returns the bool uuid.
|
||||
|
||||
Forms: `(bool attrs & body)` and `(bool label attrs & body)`. `label` is a
|
||||
literal keyword or vector stored in the instance `:refs`. `attrs` must
|
||||
carry `:bool-type` (`:union`, `:difference`, `:intersection` or
|
||||
`:exclude`). Content and geometry derive from the children after they
|
||||
finalize, so geometry, content and transform attrs are rejected. Fills,
|
||||
strokes, shadows and blurs are inherited from the head child (first for
|
||||
`:difference`, last otherwise) unless attrs supply them. A bool needs at
|
||||
least one child and cannot contain frames."
|
||||
[label-or-attrs & body]
|
||||
(if (or (keyword? label-or-attrs) (vector? label-or-attrs))
|
||||
`(benches.render-wasm.scenes.builder/with-container
|
||||
:bool
|
||||
~(first body)
|
||||
~label-or-attrs
|
||||
(fn [] ~@(rest body)))
|
||||
`(benches.render-wasm.scenes.builder/with-container
|
||||
:bool
|
||||
~label-or-attrs
|
||||
nil
|
||||
(fn [] ~@body))))
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
A fixture scope owns one seeded generator, one object map, and one label
|
||||
map. Shape constructors add themselves to the current parent: `rect`, and
|
||||
the `frame`/`group` container scopes. The scope returns a validated
|
||||
the `frame`/`group`/`bool` container scopes. The scope returns a validated
|
||||
snapshot in the ticket02 contract `{:objects ... :refs ...}`.
|
||||
|
||||
Construction is synchronous by design: the scope and the current parent
|
||||
@ -27,13 +27,16 @@
|
||||
Coordinates stay page-absolute: nesting supplies ownership and order, not
|
||||
translation. Frames keep authored bounds; groups derive bounds from their
|
||||
children inside out; a masked group takes the geometry of its first child.
|
||||
Booleans derive content and geometry from their children with the canonical
|
||||
path engine and inherit style from the head child unless attrs supply it.
|
||||
|
||||
Masked groups, frame/group scopes are this ticket; booleans ticket19;
|
||||
paths ticket07/08."
|
||||
Masked groups and the frame/group/bool scopes live here; paths ticket07/08."
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.types.color :as clr]
|
||||
[app.common.types.path :as path]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.uuid :as uuid]
|
||||
@ -55,12 +58,12 @@
|
||||
[seed]
|
||||
(let [state (atom (bit-or seed 0))]
|
||||
(fn []
|
||||
(let [s (swap! state (fn [s] (bit-or (+ s 0x6d2b79f5) 0)))
|
||||
v (js/Math.imul (bit-xor s (unsigned-bit-shift-right s 15))
|
||||
(bit-or s 1))
|
||||
v (bit-xor v (+ v (js/Math.imul (bit-xor v (unsigned-bit-shift-right v 7))
|
||||
(bit-or v 61))))
|
||||
v (bit-xor v (unsigned-bit-shift-right v 14))]
|
||||
(let [s (swap! state (fn [s] (bit-or (+ s 0x6d2b79f5) 0)))
|
||||
v (js/Math.imul (bit-xor s (unsigned-bit-shift-right s 15))
|
||||
(bit-or s 1))
|
||||
v (bit-xor v (+ v (js/Math.imul (bit-xor v (unsigned-bit-shift-right v 7))
|
||||
(bit-or v 61))))
|
||||
v (bit-xor v (unsigned-bit-shift-right v 14))]
|
||||
(/ (unsigned-bit-shift-right v 0) 4294967296)))))
|
||||
|
||||
(defn rng-float
|
||||
@ -256,11 +259,33 @@
|
||||
id))
|
||||
|
||||
(def ^:private frame-bounds-keys
|
||||
"Frames do not derive their bounds from children."
|
||||
[:x :y :width :height])
|
||||
|
||||
(def ^:private group-geometry-keys
|
||||
"Group geometry derives from its children."
|
||||
[:x :y :width :height :selrect :points])
|
||||
|
||||
(def ^:private bool-geometry-keys
|
||||
"Bool geometry, content and placement derive from its children."
|
||||
[:x :y :width :height :selrect :points :content])
|
||||
|
||||
(def ^:private bool-transform-keys
|
||||
"Construction does not accept transforms: `path/update-geometry` would
|
||||
pivot them on the empty pre-finalization selrect."
|
||||
[:transform :transform-inverse :rotation :flip-x :flip-y])
|
||||
|
||||
(defn- reject-attrs!
|
||||
"Throws when `attrs` carries any of `attr-keys`. Shared by containers
|
||||
whose geometry or content derives from their children."
|
||||
[attrs id error-type message attr-keys]
|
||||
(doseq [key attr-keys]
|
||||
(when (some? (get attrs key))
|
||||
(throw (ex-info message
|
||||
{:type error-type
|
||||
:id id
|
||||
:key key})))))
|
||||
|
||||
(defn- setup-frame
|
||||
[id attrs]
|
||||
(when-not (map? attrs)
|
||||
@ -289,14 +314,70 @@
|
||||
(throw (ex-info "group attrs must be a map; the label form takes the attrs map next"
|
||||
{:type ::invalid-attrs
|
||||
:id id})))
|
||||
(doseq [key group-geometry-keys]
|
||||
(when (some? (get attrs key))
|
||||
(throw (ex-info "group derives its geometry from children"
|
||||
{:type ::group-geometry
|
||||
:id id
|
||||
:key key}))))
|
||||
(reject-attrs! attrs id ::group-geometry
|
||||
"group derives its geometry from children"
|
||||
group-geometry-keys)
|
||||
(cts/setup-shape (assoc attrs :id id :type :group)))
|
||||
|
||||
(defn- setup-bool
|
||||
[id attrs]
|
||||
(when-not (map? attrs)
|
||||
(throw (ex-info "bool attrs must be a map; the label form takes the attrs map next"
|
||||
{:type ::invalid-attrs
|
||||
:id id})))
|
||||
(reject-attrs! attrs id ::bool-geometry
|
||||
"bool derives its geometry and content from children"
|
||||
bool-geometry-keys)
|
||||
(reject-attrs! attrs id ::bool-transform
|
||||
"bool construction does not accept transforms"
|
||||
bool-transform-keys)
|
||||
(when-not (contains? cts/bool-types (:bool-type attrs))
|
||||
(throw (ex-info "bool requires :bool-type :union :difference :intersection or :exclude"
|
||||
{:type ::bool-type
|
||||
:id id
|
||||
:bool-type (:bool-type attrs)
|
||||
:supported cts/bool-types})))
|
||||
(cts/setup-shape (assoc attrs :id id :type :bool)))
|
||||
|
||||
(defn- bool-head
|
||||
"Canonical style head: the first child is the base for `:difference`, the
|
||||
last child otherwise."
|
||||
[bool-shape children]
|
||||
(if (= :difference (:bool-type bool-shape))
|
||||
(first children)
|
||||
(last children)))
|
||||
|
||||
(defn- finalize-bool!
|
||||
[state id]
|
||||
(let [scope @state
|
||||
bool (get-in scope [:objects id])
|
||||
children (mapv (:objects scope) (:shapes bool))]
|
||||
(when (empty? children)
|
||||
(throw (ex-info "bool requires at least one child"
|
||||
{:type ::empty-bool
|
||||
:id id})))
|
||||
(when-let [frame (first (filter cfh/frame-shape? children))]
|
||||
(throw (ex-info "bool children cannot be frames"
|
||||
{:type ::frame-in-bool
|
||||
:id id
|
||||
:child (:id frame)})))
|
||||
(let [inherited (d/without-nils
|
||||
(select-keys (bool-head bool children)
|
||||
path/bool-style-properties))
|
||||
supplied (d/without-nils
|
||||
(select-keys (get-in scope [:container-attrs id])
|
||||
path/bool-style-properties))
|
||||
bool (-> bool (merge inherited) (merge supplied))
|
||||
|
||||
;; `path/update-bool-shape` dispatches to `path/wasm:calc-bool-content`,
|
||||
;; the renderer override, so fixture content would depend on renderer
|
||||
;; initialization and A/B configuration. Compose the pure helpers:
|
||||
;; fixture generation is untimed and must not vary with the renderer
|
||||
;; being compared.
|
||||
content (path/calc-bool-content bool (:objects scope))
|
||||
bool (path/update-geometry bool content)]
|
||||
(swap! state assoc-in [:objects id] bool))))
|
||||
|
||||
(defn- finalize-group!
|
||||
[state id]
|
||||
(let [scope @state
|
||||
@ -313,24 +394,30 @@
|
||||
|
||||
(def ^:private container-specs
|
||||
"Per-container behavior: how to build it, which parent scope it opens,
|
||||
and how to finalize it after the body. Ticket19 extends the table with
|
||||
booleans."
|
||||
and how to finalize it after the body. `:keep-attrs?` records the raw
|
||||
attrs in the scope so the finalizer can let supplied styles win over
|
||||
inherited ones."
|
||||
{:frame {:setup setup-frame
|
||||
:parent (fn [id _parent] {:id id :frame-id id})
|
||||
:finalize (fn [_state _id] nil)}
|
||||
:group {:setup setup-group
|
||||
:parent (fn [id parent] {:id id :frame-id (:frame-id parent)})
|
||||
:finalize finalize-group!}})
|
||||
:finalize finalize-group!}
|
||||
:bool {:setup setup-bool
|
||||
:parent (fn [id parent] {:id id :frame-id (:frame-id parent)})
|
||||
:finalize finalize-bool!
|
||||
:keep-attrs? true}})
|
||||
|
||||
(defn with-container
|
||||
"Creates a frame or group, runs `thunk` with the new parent in scope,
|
||||
finalizes groups, and returns the container uuid.
|
||||
"Creates a frame, group or bool, runs `thunk` with the new parent in
|
||||
scope, finalizes the containers that derive state from children, and
|
||||
returns the container uuid.
|
||||
|
||||
Any exception from the body or the finalizer marks the container
|
||||
unfinished and propagates; `finish!` then rejects the instance even if the
|
||||
caller catches the exception."
|
||||
[type attrs label thunk]
|
||||
(let [{:keys [setup parent finalize]}
|
||||
(let [{:keys [setup parent finalize keep-attrs?]}
|
||||
(or (get container-specs type)
|
||||
(throw (ex-info "unsupported container type"
|
||||
{:type ::invalid-container
|
||||
@ -338,6 +425,8 @@
|
||||
state (ensure-state *state*)
|
||||
id (rng-uuid (:rng @state))
|
||||
shape (setup id attrs)]
|
||||
(when keep-attrs?
|
||||
(swap! state assoc-in [:container-attrs id] attrs))
|
||||
(add-object! state label shape)
|
||||
(binding [*parent* (parent id *parent*)]
|
||||
(try
|
||||
|
||||
242
frontend/test/frontend_tests/benches/boolean_fixture_test.cljs
Normal file
242
frontend/test/frontend_tests/benches/boolean_fixture_test.cljs
Normal file
@ -0,0 +1,242 @@
|
||||
;; 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 frontend-tests.benches.boolean-fixture-test
|
||||
(:require
|
||||
[app.common.types.path :as path]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.uuid :as uuid]
|
||||
[benches.render-wasm.scenes.builder :as b :include-macros true]
|
||||
[benches.render-wasm.scenes.common :as common]
|
||||
[cljs.test :as t :include-macros true]))
|
||||
|
||||
(defn- failure-data
|
||||
[f]
|
||||
(try
|
||||
(f)
|
||||
nil
|
||||
(catch :default cause
|
||||
(ex-data cause))))
|
||||
|
||||
(defn- selrect
|
||||
[shape]
|
||||
[(:x (:selrect shape)) (:y (:selrect shape))
|
||||
(:width (:selrect shape)) (:height (:selrect shape))])
|
||||
|
||||
(defn- children-of
|
||||
[instance id]
|
||||
(mapv (:objects instance) (get-in instance [:objects id :shapes])))
|
||||
|
||||
(defn- run-scope
|
||||
"Runs `f` inside a raw scope and returns the scope state, so tests can
|
||||
inspect partial builds without calling finish!."
|
||||
[params f]
|
||||
(let [state (b/start params)]
|
||||
(binding [b/*state* state
|
||||
b/*defaults* {}]
|
||||
(f))
|
||||
state))
|
||||
|
||||
(t/deftest difference-of-overlapping-rects-derives-the-l-shape
|
||||
(let [red {:fill-color "#ff0000" :fill-opacity 1}
|
||||
blue {:fill-color "#0000ff" :fill-opacity 1}
|
||||
instance (b/fixture {:seed 1}
|
||||
(b/bool :l-shape {:bool-type :difference :name "L"}
|
||||
(b/rect {:x 0 :y 0 :width 100 :height 100 :fills [red]})
|
||||
(b/rect {:x 50 :y 50 :width 100 :height 100 :fills [blue]})))
|
||||
bool (first (children-of instance uuid/zero))
|
||||
children (children-of instance (:id bool))]
|
||||
(t/is (= :bool (:type bool)))
|
||||
(t/is (= :difference (:bool-type bool)))
|
||||
(t/is (= (:id bool) (common/ref-id instance :l-shape)))
|
||||
(t/is (= 2 (count children)))
|
||||
(t/is (= [(:id (first children)) (:id (second children))] (:shapes bool)))
|
||||
(t/is (= [(:id bool) (:id bool)]
|
||||
[(:parent-id (first children)) (:parent-id (second children))]))
|
||||
(t/is (= [uuid/zero uuid/zero]
|
||||
[(:frame-id (first children)) (:frame-id (second children))]))
|
||||
(t/is (= [0 0 100 100] (selrect bool)))
|
||||
(t/is (= (:selrect bool) (path/calc-selrect (:content bool))))
|
||||
(t/is (= 4 (count (:points bool))))
|
||||
(t/is (= #{[0 0] [100 0] [100 50] [50 50] [50 100] [0 100]}
|
||||
(set (map (juxt :x :y) (path/get-points (:content bool))))))))
|
||||
|
||||
(t/deftest union-intersection-and-exclude-derive-canonical-bounds
|
||||
(doseq [[bool-type expected] [[:union [0 0 150 150]]
|
||||
[:intersection [50 50 50 50]]
|
||||
[:exclude [0 0 150 150]]]]
|
||||
(let [instance (b/fixture {:seed 1}
|
||||
(b/bool {:bool-type bool-type}
|
||||
(b/rect {:x 0 :y 0 :width 100 :height 100})
|
||||
(b/rect {:x 50 :y 50 :width 100 :height 100})))
|
||||
bool (first (children-of instance uuid/zero))]
|
||||
(t/is (= bool-type (:bool-type bool)))
|
||||
(t/is (= expected (selrect bool)) (str bool-type)))))
|
||||
|
||||
(t/deftest operation-picks-the-canonical-style-head
|
||||
(let [red {:fill-color "#ff0000" :fill-opacity 1}
|
||||
blue {:fill-color "#0000ff" :fill-opacity 1}
|
||||
blur {:id (uuid/custom 3 3) :type :layer-blur :value 4 :hidden false}
|
||||
difference (b/fixture {:seed 1}
|
||||
(b/bool {:bool-type :difference}
|
||||
(b/rect {:x 0 :y 0 :width 10 :height 10
|
||||
:fills [red] :blur blur})
|
||||
(b/rect {:x 5 :y 0 :width 10 :height 10
|
||||
:fills [blue]})))
|
||||
union (b/fixture {:seed 1}
|
||||
(b/bool {:bool-type :union}
|
||||
(b/rect {:x 0 :y 0 :width 10 :height 10
|
||||
:fills [red] :blur blur})
|
||||
(b/rect {:x 5 :y 0 :width 10 :height 10
|
||||
:fills [blue]})))
|
||||
diff-bool (first (children-of difference uuid/zero))
|
||||
union-bool (first (children-of union uuid/zero))]
|
||||
(t/is (= [red] (:fills diff-bool)))
|
||||
(t/is (= blur (:blur diff-bool)))
|
||||
(t/is (= [blue] (:fills union-bool)))
|
||||
(t/is (nil? (:blur union-bool)))))
|
||||
|
||||
(t/deftest supplied-styles-override-inherited
|
||||
(let [instance (b/fixture {:seed 1}
|
||||
(b/bool {:bool-type :union :fills []}
|
||||
(b/rect {:x 0 :y 0 :width 10 :height 10
|
||||
:fills [{:fill-color "#ff0000" :fill-opacity 1}]})
|
||||
(b/rect {:x 5 :y 0 :width 10 :height 10
|
||||
:fills [{:fill-color "#0000ff" :fill-opacity 1}]})))
|
||||
bool (first (children-of instance uuid/zero))]
|
||||
(t/is (= [] (:fills bool)))))
|
||||
|
||||
(t/deftest nil-styles-do-not-count-as-supplied
|
||||
(let [red {:fill-color "#ff0000" :fill-opacity 1}
|
||||
blue {:fill-color "#0000ff" :fill-opacity 1}
|
||||
instance (b/fixture {:seed 1}
|
||||
(b/bool {:bool-type :union :fills nil}
|
||||
(b/rect {:x 0 :y 0 :width 10 :height 10 :fills [red]})
|
||||
(b/rect {:x 5 :y 0 :width 10 :height 10 :fills [blue]})))
|
||||
bool (first (children-of instance uuid/zero))]
|
||||
(t/is (= [blue] (:fills bool)))))
|
||||
|
||||
(t/deftest single-child-bool-uses-the-child-path
|
||||
(let [instance (b/fixture {:seed 1}
|
||||
(b/bool {:bool-type :difference}
|
||||
(b/rect {:x 10 :y 20 :width 30 :height 40})))
|
||||
bool (first (children-of instance uuid/zero))]
|
||||
(t/is (= 1 (count (:shapes bool))))
|
||||
(t/is (= [10 20 30 40] (selrect bool)))
|
||||
(t/is (= (:selrect bool) (path/calc-selrect (:content bool))))))
|
||||
|
||||
(t/deftest nested-bools-finalize-inside-out
|
||||
(let [instance (b/fixture {:seed 1}
|
||||
(b/bool {:bool-type :union}
|
||||
(b/bool {:bool-type :difference}
|
||||
(b/rect {:x 0 :y 0 :width 100 :height 100})
|
||||
(b/rect {:x 50 :y 50 :width 100 :height 100}))
|
||||
(b/rect {:x 200 :y 0 :width 50 :height 50})))
|
||||
outer (first (children-of instance uuid/zero))
|
||||
inner (first (children-of instance (:id outer)))]
|
||||
(t/is (= :bool (:type inner)))
|
||||
(t/is (= [0 0 100 100] (selrect inner)))
|
||||
(t/is (= [0 0 250 100] (selrect outer)))
|
||||
(t/is (= (:selrect outer) (path/calc-selrect (:content outer))))))
|
||||
|
||||
(t/deftest bool-inside-frame-keeps-frame-ids
|
||||
(let [instance (b/fixture {:seed 1}
|
||||
(b/frame {:x 0 :y 0 :width 200 :height 200}
|
||||
(b/bool {:bool-type :union}
|
||||
(b/rect {:x 10 :y 10 :width 10 :height 10})
|
||||
(b/rect {:x 30 :y 10 :width 10 :height 10}))))
|
||||
frame (first (children-of instance uuid/zero))
|
||||
bool (first (children-of instance (:id frame)))
|
||||
rects (children-of instance (:id bool))]
|
||||
(t/is (= (:id frame) (:parent-id bool)))
|
||||
(t/is (= (:id frame) (:frame-id bool)))
|
||||
(t/is (= [(:id frame) (:id frame)] (mapv :frame-id rects)))
|
||||
(t/is (= [(:id bool) (:id bool)] (mapv :parent-id rects)))))
|
||||
|
||||
(t/deftest bool-inside-group-derives-group-bounds
|
||||
(let [instance (b/fixture {:seed 1}
|
||||
(b/group {}
|
||||
(b/bool {:bool-type :union}
|
||||
(b/rect {:x 10 :y 20 :width 30 :height 40})
|
||||
(b/rect {:x 50 :y 80 :width 10 :height 10}))))
|
||||
group (first (children-of instance uuid/zero))
|
||||
bool (first (children-of instance (:id group)))]
|
||||
(t/is (= :bool (:type bool)))
|
||||
(t/is (= [10 20 50 70] (selrect group)))
|
||||
(t/is (= uuid/zero (:frame-id bool)))))
|
||||
|
||||
(t/deftest empty-bool-is-rejected
|
||||
(let [data (failure-data #(b/fixture {:seed 1} (b/bool {:bool-type :union})))]
|
||||
(t/is (= ::b/empty-bool (:type data)))))
|
||||
|
||||
(t/deftest caught-empty-bool-still-fails-finish
|
||||
(let [state (run-scope {:seed 1}
|
||||
(fn []
|
||||
(try
|
||||
(b/bool {:bool-type :union})
|
||||
(catch :default _ nil))))]
|
||||
(t/is (= ::b/unfinished-container
|
||||
(:type (failure-data #(b/finish! state)))))))
|
||||
|
||||
(t/deftest bool-geometry-attrs-are-rejected
|
||||
(doseq [attrs [{:bool-type :union :x 1}
|
||||
{:bool-type :union :selrect {:x 0 :y 0 :width 1 :height 1}}
|
||||
{:bool-type :union :content []}]]
|
||||
(let [data (failure-data #(b/fixture {:seed 1} (b/bool attrs (b/rect))))]
|
||||
(t/is (= ::b/bool-geometry (:type data)) (str attrs))
|
||||
(t/is (contains? #{:x :selrect :content} (:key data)) (str attrs)))))
|
||||
|
||||
(t/deftest bool-transform-attrs-are-rejected
|
||||
(doseq [attrs [{:bool-type :union :rotation 45}
|
||||
{:bool-type :union :transform "m"}
|
||||
{:bool-type :union :transform-inverse "m"}
|
||||
{:bool-type :union :flip-x true}
|
||||
{:bool-type :union :flip-y true}]]
|
||||
(let [data (failure-data #(b/fixture {:seed 1} (b/bool attrs (b/rect))))]
|
||||
(t/is (= ::b/bool-transform (:type data)) (str attrs)))))
|
||||
|
||||
(t/deftest bool-type-is-required-and-validated
|
||||
(t/is (= ::b/bool-type
|
||||
(:type (failure-data #(b/fixture {:seed 1} (b/bool {:name "B"} (b/rect)))))))
|
||||
(let [data (failure-data #(b/fixture {:seed 1} (b/bool {:bool-type :merge} (b/rect))))]
|
||||
(t/is (= ::b/bool-type (:type data)))
|
||||
(t/is (= :merge (:bool-type data)))
|
||||
(t/is (= cts/bool-types (:supported data)))))
|
||||
|
||||
(t/deftest frame-child-is-rejected
|
||||
(let [data (failure-data
|
||||
#(b/fixture {:seed 1}
|
||||
(b/bool {:bool-type :union}
|
||||
(b/frame {:x 0 :y 0 :width 10 :height 10}
|
||||
(b/rect)))))]
|
||||
(t/is (= ::b/frame-in-bool (:type data)))
|
||||
(t/is (uuid? (:child data)))))
|
||||
|
||||
(t/deftest bool-generation-ignores-the-renderer-override
|
||||
(let [original path/wasm:calc-bool-content]
|
||||
(try
|
||||
(set! path/wasm:calc-bool-content
|
||||
(fn [& _]
|
||||
(throw (ex-info "renderer override ran during generation"
|
||||
{:type ::unexpected-renderer-call}))))
|
||||
(let [instance (b/fixture {:seed 1}
|
||||
(b/bool {:bool-type :difference}
|
||||
(b/rect {:x 0 :y 0 :width 100 :height 100})
|
||||
(b/rect {:x 50 :y 50 :width 100 :height 100})))
|
||||
bool (first (children-of instance uuid/zero))]
|
||||
(t/is (= [0 0 100 100] (selrect bool))))
|
||||
(finally
|
||||
(set! path/wasm:calc-bool-content original)))))
|
||||
|
||||
(t/deftest non-map-bool-attrs-are-rejected
|
||||
(t/is (= ::b/invalid-attrs
|
||||
(:type (failure-data #(b/fixture {:seed 1} (b/bool :hero (b/rect)))))))
|
||||
(let [state (run-scope {:seed 1}
|
||||
(fn []
|
||||
(try
|
||||
(b/bool :hero (b/rect))
|
||||
(catch :default _ nil))))]
|
||||
(t/is (= 1 (count (get-in @state [:objects uuid/zero :shapes]))))))
|
||||
Loading…
x
Reference in New Issue
Block a user