mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +00:00
* 🎉 Add tests for app.common.geom.bounds-map * 🎉 Add tests for app.common.geom and descendant namespaces * 📎 Fix linting issues --------- Co-authored-by: Luis de Dios <luis.dedios@kaleidos.net>
137 lines
5.7 KiB
Clojure
137 lines
5.7 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 INC
|
|
|
|
(ns common-tests.geom-shapes-common-test
|
|
(:require
|
|
[app.common.geom.matrix :as gmt]
|
|
[app.common.geom.point :as gpt]
|
|
[app.common.geom.rect :as grc]
|
|
[app.common.geom.shapes.common :as gco]
|
|
[app.common.math :as mth]
|
|
[clojure.test :as t]))
|
|
|
|
(t/deftest points->center-test
|
|
(t/testing "Center of a unit square"
|
|
(let [points [(gpt/point 0 0) (gpt/point 10 0)
|
|
(gpt/point 10 10) (gpt/point 0 10)]
|
|
center (gco/points->center points)]
|
|
(t/is (mth/close? 5.0 (:x center)))
|
|
(t/is (mth/close? 5.0 (:y center)))))
|
|
|
|
(t/testing "Center of a rectangle"
|
|
(let [points [(gpt/point 0 0) (gpt/point 20 0)
|
|
(gpt/point 20 10) (gpt/point 0 10)]
|
|
center (gco/points->center points)]
|
|
(t/is (mth/close? 10.0 (:x center)))
|
|
(t/is (mth/close? 5.0 (:y center)))))
|
|
|
|
(t/testing "Center of a translated square"
|
|
(let [points [(gpt/point 100 200) (gpt/point 150 200)
|
|
(gpt/point 150 250) (gpt/point 100 250)]
|
|
center (gco/points->center points)]
|
|
(t/is (mth/close? 125.0 (:x center)))
|
|
(t/is (mth/close? 225.0 (:y center))))))
|
|
|
|
(t/deftest shape->center-test
|
|
(t/testing "Center from shape selrect (proper rect record)"
|
|
(let [shape {:selrect (grc/make-rect 10 20 100 50)}
|
|
center (gco/shape->center shape)]
|
|
(t/is (mth/close? 60.0 (:x center)))
|
|
(t/is (mth/close? 45.0 (:y center))))))
|
|
|
|
(t/deftest transform-points-test
|
|
(t/testing "Transform with identity matrix leaves points unchanged"
|
|
(let [points [(gpt/point 0 0) (gpt/point 10 0)
|
|
(gpt/point 10 10) (gpt/point 0 10)]
|
|
result (gco/transform-points points (gmt/matrix))]
|
|
(doseq [[p r] (map vector points result)]
|
|
(t/is (mth/close? (:x p) (:x r)))
|
|
(t/is (mth/close? (:y p) (:y r))))))
|
|
|
|
(t/testing "Transform with translation matrix"
|
|
(let [points [(gpt/point 0 0) (gpt/point 10 0)
|
|
(gpt/point 10 10) (gpt/point 0 10)]
|
|
mtx (gmt/translate-matrix (gpt/point 5 10))
|
|
result (gco/transform-points points mtx)]
|
|
(t/is (mth/close? 5.0 (:x (first result))))
|
|
(t/is (mth/close? 10.0 (:y (first result))))))
|
|
|
|
(t/testing "Transform around a center point"
|
|
(let [points [(gpt/point 0 0) (gpt/point 10 0)
|
|
(gpt/point 10 10) (gpt/point 0 10)]
|
|
center (gco/points->center points)
|
|
mtx (gmt/scale-matrix (gpt/point 2 2))
|
|
result (gco/transform-points points center mtx)]
|
|
;; Scaling around center (5,5) by 2x: (0,0)→(-5,-5)
|
|
(t/is (mth/close? -5.0 (:x (first result))))
|
|
(t/is (mth/close? -5.0 (:y (first result))))))
|
|
|
|
(t/testing "Transform with nil matrix returns points unchanged"
|
|
(let [points [(gpt/point 1 2) (gpt/point 3 4)]
|
|
result (gco/transform-points points nil)]
|
|
(t/is (= points result))))
|
|
|
|
(t/testing "Transform empty points returns empty"
|
|
(let [result (gco/transform-points [] (gmt/matrix))]
|
|
(t/is (= [] result)))))
|
|
|
|
(t/deftest invalid-geometry?-test
|
|
(t/testing "Valid geometry is not invalid"
|
|
(let [shape {:selrect (grc/make-rect 0 0 100 50)
|
|
:points [(gpt/point 0 0) (gpt/point 100 0)
|
|
(gpt/point 100 50) (gpt/point 0 50)]}]
|
|
(t/is (not (gco/invalid-geometry? shape)))))
|
|
|
|
(t/testing "NaN x in selrect is invalid"
|
|
(let [selrect (grc/make-rect 0 0 100 50)
|
|
selrect (assoc selrect :x ##NaN)
|
|
shape {:selrect selrect
|
|
:points [(gpt/point 0 0) (gpt/point 100 0)
|
|
(gpt/point 100 50) (gpt/point 0 50)]}]
|
|
(t/is (true? (gco/invalid-geometry? shape)))))
|
|
|
|
(t/testing "NaN in points is invalid"
|
|
(let [shape {:selrect (grc/make-rect 0 0 100 50)
|
|
:points [(gpt/point ##NaN 0) (gpt/point 100 0)
|
|
(gpt/point 100 50) (gpt/point 0 50)]}]
|
|
(t/is (true? (gco/invalid-geometry? shape))))))
|
|
|
|
(t/deftest shape->points-test
|
|
(t/testing "Identity transform uses reconstructed points from corners"
|
|
(let [points [(gpt/point 10 20) (gpt/point 40 20)
|
|
(gpt/point 40 60) (gpt/point 10 60)]
|
|
shape {:transform (gmt/matrix) :points points}
|
|
result (gco/shape->points shape)]
|
|
(t/is (= 4 (count result)))
|
|
;; p0 and p2 are used to reconstruct p1 and p3
|
|
(t/is (mth/close? 10.0 (:x (nth result 0))))
|
|
(t/is (mth/close? 20.0 (:y (nth result 0))))
|
|
(t/is (mth/close? 40.0 (:x (nth result 2))))
|
|
(t/is (mth/close? 60.0 (:y (nth result 2))))))
|
|
|
|
(t/testing "Non-identity transform returns points as-is"
|
|
(let [points [(gpt/point 10 20) (gpt/point 40 20)
|
|
(gpt/point 40 60) (gpt/point 10 60)]
|
|
shape {:transform (gmt/translate-matrix (gpt/point 5 5)) :points points}
|
|
result (gco/shape->points shape)]
|
|
(t/is (= points result)))))
|
|
|
|
(t/deftest transform-selrect-test
|
|
(t/testing "Transform selrect with identity matrix"
|
|
(let [selrect (grc/make-rect 10 20 100 50)
|
|
result (gco/transform-selrect selrect (gmt/matrix))]
|
|
(t/is (mth/close? 10.0 (:x result)))
|
|
(t/is (mth/close? 20.0 (:y result)))
|
|
(t/is (mth/close? 100.0 (:width result)))
|
|
(t/is (mth/close? 50.0 (:height result)))))
|
|
|
|
(t/testing "Transform selrect with translation"
|
|
(let [selrect (grc/make-rect 0 0 100 50)
|
|
mtx (gmt/translate-matrix (gpt/point 10 20))
|
|
result (gco/transform-selrect selrect mtx)]
|
|
(t/is (mth/close? 10.0 (:x result)))
|
|
(t/is (mth/close? 20.0 (:y result))))))
|