mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
215 lines
11 KiB
Clojure
215 lines
11 KiB
Clojure
;; 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 performance-tests.render-wasm.boolean-test
|
|
(:require
|
|
[app.common.geom.point :as gpt]
|
|
[app.common.geom.shapes.intersect :as gint]
|
|
[app.common.types.path :as path]
|
|
[app.common.types.path.segment :as segm]
|
|
[app.common.uuid :as uuid]
|
|
[benches.render-wasm.builder :as b :include-macros true]
|
|
[benches.render-wasm.snapshot :as snapshot]
|
|
[cljs.test :as t :include-macros true]
|
|
[performance-tests.render-wasm.test-helpers :as helpers]))
|
|
|
|
(t/deftest difference-of-overlapping-rects-keeps-hierarchy-and-bounds
|
|
(let [red {:fill-color "#ff0000" :fill-opacity 1}
|
|
blue {:fill-color "#0000ff" :fill-opacity 1}
|
|
instance (b/scene {: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 (helpers/children-of instance uuid/zero))
|
|
children (helpers/children-of instance (:id bool))]
|
|
(t/is (= :bool (:type bool)))
|
|
(t/is (= :difference (:bool-type bool)))
|
|
(t/is (= (:id bool) (snapshot/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] (helpers/selrect bool)))))
|
|
|
|
(t/deftest difference-excludes-points-in-removed-overlap
|
|
(let [instance (b/scene {: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 (helpers/children-of instance uuid/zero))
|
|
lines (segm/path->lines bool)]
|
|
(t/is (true? (gint/is-point-inside-nonzero? (gpt/point 25 25) lines))
|
|
"a point in the kept region stays inside the content")
|
|
(t/is (false? (gint/is-point-inside-nonzero? (gpt/point 75 75) lines))
|
|
"a point in the subtracted overlap is excluded from the content")))
|
|
|
|
(t/deftest union-derives-canonical-bounds
|
|
(let [instance (b/scene {:seed 1}
|
|
(b/bool {:bool-type :union}
|
|
(b/rect {:x 0 :y 0 :width 100 :height 100})
|
|
(b/rect {:x 50 :y 50 :width 100 :height 100})))
|
|
bool (first (helpers/children-of instance uuid/zero))]
|
|
(t/is (= :union (:bool-type bool)))
|
|
(t/is (= [0 0 150 150] (helpers/selrect bool)))))
|
|
|
|
(t/deftest difference-picks-the-first-child-as-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/scene {: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]})))
|
|
diff-bool (first (helpers/children-of difference uuid/zero))]
|
|
(t/is (= [red] (:fills diff-bool)))
|
|
(t/is (= blur (:blur diff-bool)))))
|
|
|
|
(t/deftest supplied-styles-override-inherited
|
|
(let [instance (b/scene {: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 (helpers/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/scene {: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 (helpers/children-of instance uuid/zero))]
|
|
(t/is (= [blue] (:fills bool)))))
|
|
|
|
(t/deftest single-child-bool-uses-the-child-path
|
|
(let [instance (b/scene {:seed 1}
|
|
(b/bool {:bool-type :difference}
|
|
(b/rect {:x 10 :y 20 :width 30 :height 40})))
|
|
bool (first (helpers/children-of instance uuid/zero))]
|
|
(t/is (= 1 (count (:shapes bool))))
|
|
(t/is (= [10 20 30 40] (helpers/selrect bool)))
|
|
(t/is (= (:selrect bool) (path/calc-selrect (:content bool))))))
|
|
|
|
(t/deftest nested-bools-finalize-inside-out
|
|
(let [instance (b/scene {: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 (helpers/children-of instance uuid/zero))
|
|
inner (first (helpers/children-of instance (:id outer)))]
|
|
(t/is (= :bool (:type inner)))
|
|
(t/is (= [0 0 100 100] (helpers/selrect inner)))
|
|
(t/is (= [0 0 250 100] (helpers/selrect outer)))
|
|
(t/is (= (:selrect outer) (path/calc-selrect (:content outer))))))
|
|
|
|
(t/deftest bool-inside-frame-keeps-frame-ids
|
|
(let [instance (b/scene {: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 (helpers/children-of instance uuid/zero))
|
|
bool (first (helpers/children-of instance (:id frame)))
|
|
rects (helpers/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/scene {: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 (helpers/children-of instance uuid/zero))
|
|
bool (first (helpers/children-of instance (:id group)))]
|
|
(t/is (= :bool (:type bool)))
|
|
(t/is (= [10 20 50 70] (helpers/selrect group)))
|
|
(t/is (= uuid/zero (:frame-id bool)))))
|
|
|
|
(t/deftest empty-bool-is-rejected
|
|
(let [data (helpers/failure-data #(b/scene {:seed 1} (b/bool {:bool-type :union})))]
|
|
(t/is (= ::b/empty-bool (:type data)))))
|
|
|
|
(t/deftest caught-empty-bool-still-fails-finish
|
|
(let [state (helpers/run-scope {:seed 1}
|
|
(fn []
|
|
(try
|
|
(b/bool {:bool-type :union})
|
|
(catch :default _ nil))))]
|
|
(t/is (= ::b/unfinished-container
|
|
(:type (helpers/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 (helpers/failure-data #(b/scene {: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 (helpers/failure-data #(b/scene {: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 (helpers/failure-data #(b/scene {:seed 1} (b/bool {:name "B"} (b/rect)))))))
|
|
(let [data (helpers/failure-data #(b/scene {:seed 1} (b/bool {:bool-type :merge} (b/rect))))]
|
|
(t/is (= ::b/bool-type (:type data)))
|
|
(t/is (= :merge (:bool-type data)))
|
|
(t/is (= #{:union :difference :intersection :exclude} (set (:supported data))))))
|
|
|
|
(t/deftest frame-child-is-rejected
|
|
(let [data (helpers/failure-data
|
|
#(b/scene {: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/scene {: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 (helpers/children-of instance uuid/zero))]
|
|
(t/is (= [0 0 100 100] (helpers/selrect bool))))
|
|
(finally
|
|
(set! path/wasm:calc-bool-content original)))))
|
|
|
|
(t/deftest non-map-bool-attrs-are-rejected
|
|
(t/is (= ::b/invalid-attrs
|
|
(:type (helpers/failure-data #(b/scene {:seed 1} (b/bool :hero (b/rect)))))))
|
|
(let [state (helpers/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]))))))
|