mirror of
https://github.com/penpot/penpot.git
synced 2025-01-23 23:18:48 -05:00
✨ Improved tests for geom transforms
This commit is contained in:
parent
8bc37416a0
commit
1fb5ffb59b
5 changed files with 279 additions and 85 deletions
94
backend/tests/app/tests/test_common_geom.clj
Normal file
94
backend/tests/app/tests/test_common_geom.clj
Normal file
|
@ -0,0 +1,94 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns app.tests.test_common_geom
|
||||
(:require
|
||||
[clojure.test :as t]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.matrix :as gmt]))
|
||||
|
||||
(t/deftest point-constructors-test
|
||||
(t/testing "Create point with both coordinates"
|
||||
(let [p (gpt/point 1 2)]
|
||||
(t/is (= (:x p) 1))
|
||||
(t/is (= (:y p) 2))))
|
||||
|
||||
(t/testing "Create point with single coordinate"
|
||||
(let [p (gpt/point 1)]
|
||||
(t/is (= (:x p) 1))
|
||||
(t/is (= (:y p) 1))))
|
||||
|
||||
(t/testing "Create empty point"
|
||||
(let [p (gpt/point)]
|
||||
(t/is (= (:x p) 0))
|
||||
(t/is (= (:y p) 0)))))
|
||||
|
||||
(t/deftest point-add-test
|
||||
(t/testing "Adds two points together"
|
||||
(let [p1 (gpt/point 1 1)
|
||||
p2 (gpt/point 2 2)
|
||||
p3 (gpt/add p1 p2)]
|
||||
(t/is (= (:x p3) 3))
|
||||
(t/is (= (:y p3) 3)))))
|
||||
|
||||
(t/deftest point-subtract-test
|
||||
(t/testing "Point substraction"
|
||||
(let [p1 (gpt/point 3 3)
|
||||
p2 (gpt/point 2 2)
|
||||
p3 (gpt/subtract p1 p2)]
|
||||
(t/is (= (:x p3) 1))
|
||||
(t/is (= (:y p3) 1)))))
|
||||
|
||||
(t/deftest point-distance-test
|
||||
(let [p1 (gpt/point 0 0)
|
||||
p2 (gpt/point 10 0)
|
||||
d (gpt/distance p1 p2)]
|
||||
(t/is (number? d))
|
||||
(t/is (= d 10.0))))
|
||||
|
||||
(t/deftest point-length-test
|
||||
(let [p1 (gpt/point 10 0)
|
||||
ln (gpt/length p1)]
|
||||
(t/is (number? ln))
|
||||
(t/is (= ln 10.0))))
|
||||
|
||||
(t/deftest point-angle-test
|
||||
(t/testing "Get angle a 90 degree angle"
|
||||
(let [p1 (gpt/point 0 10)
|
||||
angle (gpt/angle p1)]
|
||||
(t/is (number? angle))
|
||||
(t/is (= angle 90.0))))
|
||||
|
||||
(t/testing "Get 45 degree angle"
|
||||
(let [p1 (gpt/point 0 10)
|
||||
p2 (gpt/point 10 10)
|
||||
angle (gpt/angle-with-other p1 p2)]
|
||||
(t/is (number? angle))
|
||||
(t/is (= angle 45.0)))))
|
||||
|
||||
(t/deftest matrix-constructors-test
|
||||
(let [m (gmt/matrix)]
|
||||
(t/is (= (str m) "matrix(1,0,0,1,0,0)")))
|
||||
(let [m (gmt/matrix 1 1 1 2 2 2)]
|
||||
(t/is (= (str m) "matrix(1,1,1,2,2,2)"))))
|
||||
|
||||
(t/deftest matrix-translate-test
|
||||
(let [m (-> (gmt/matrix)
|
||||
(gmt/translate (gpt/point 2 10)))]
|
||||
(t/is (= (str m) "matrix(1,0,0,1,2,10)"))))
|
||||
|
||||
(t/deftest matrix-scale-test
|
||||
(let [m (-> (gmt/matrix)
|
||||
(gmt/scale (gpt/point 2)))]
|
||||
(t/is (= (str m) "matrix(2,0,0,2,0,0)"))))
|
||||
|
||||
(t/deftest matrix-rotate-test
|
||||
(let [m (-> (gmt/matrix)
|
||||
(gmt/rotate 10))]
|
||||
(t/is (= (str m) "matrix(0.984807753012208,0.17364817766693033,-0.17364817766693033,0.984807753012208,0,0)"))))
|
179
backend/tests/app/tests/test_common_geom_shapes.clj
Normal file
179
backend/tests/app/tests/test_common_geom_shapes.clj
Normal file
|
@ -0,0 +1,179 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns app.tests.test-common-geom-shapes
|
||||
(:require
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages :refer [make-minimal-shape]]
|
||||
[clojure.test :as t]))
|
||||
|
||||
(def default-path [{:command :move-to :params {:x 0 :y 0}}
|
||||
{:command :line-to :params {:x 20 :y 20}}
|
||||
{:command :line-to :params {:x 30 :y 30}}
|
||||
{:command :curve-to :params {:x 40 :y 40 :c1x 35 :c1y 35 :c2x 45 :c2y 45}}
|
||||
{:command :close-path}])
|
||||
|
||||
(defn add-path-data [shape]
|
||||
(let [content (:content shape default-path)
|
||||
selrect (gsh/content->selrect content)
|
||||
points (gsh/rect->points selrect)]
|
||||
(assoc shape
|
||||
:content content
|
||||
:selrect selrect
|
||||
:points points)))
|
||||
|
||||
(defn add-rect-data [shape]
|
||||
(let [selrect (gsh/rect->selrect shape)
|
||||
points (gsh/rect->points selrect)]
|
||||
(assoc shape
|
||||
:selrect selrect
|
||||
:points points)))
|
||||
|
||||
(defn create-test-shape
|
||||
([type] (create-test-shape type {}))
|
||||
([type params]
|
||||
(-> (make-minimal-shape type)
|
||||
(merge params)
|
||||
(cond->
|
||||
(= type :path) (add-path-data)
|
||||
(not= type :path) (add-rect-data)))))
|
||||
|
||||
|
||||
(t/deftest transform-shape-tests
|
||||
(t/testing "Shape without modifiers should stay the same"
|
||||
(t/are [type]
|
||||
(let [shape-before (create-test-shape type)
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(= shape-before shape-after))
|
||||
|
||||
:rect :path))
|
||||
|
||||
|
||||
(t/testing "Transform shape with translation modifiers"
|
||||
(t/are [type]
|
||||
(let [modifiers {:displacement (gmt/translate-matrix (gpt/point 10 -10))}]
|
||||
(let [shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/is (not= shape-before shape-after))
|
||||
|
||||
(t/is (== (get-in shape-before [:selrect :x])
|
||||
(- 10 (get-in shape-after [:selrect :x]))))
|
||||
|
||||
(t/is (== (get-in shape-before [:selrect :y])
|
||||
(+ 10 (get-in shape-after [:selrect :y]))))
|
||||
|
||||
(t/is (== (get-in shape-before [:selrect :width])
|
||||
(get-in shape-after [:selrect :width])))
|
||||
|
||||
(t/is (== (get-in shape-before [:selrect :height])
|
||||
(get-in shape-after [:selrect :height])))))
|
||||
|
||||
:rect :path))
|
||||
|
||||
(t/testing "Transform with empty translation"
|
||||
(t/are [type]
|
||||
(let [modifiers {:displacement (gmt/matrix)}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/are [prop]
|
||||
(t/is (== (get-in shape-before [:selrect prop])
|
||||
(get-in shape-after [:selrect prop])))
|
||||
:x :y :width :height :x1 :y1 :x2 :y2))
|
||||
:rect :path))
|
||||
|
||||
(t/testing "Transform shape with resize modifiers"
|
||||
(t/are [type]
|
||||
(let [modifiers {:resize-origin (gpt/point 0 0)
|
||||
:resize-vector (gpt/point 2 2)
|
||||
:resize-transform (gmt/matrix)}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/is (not= shape-before shape-after))
|
||||
|
||||
(t/is (== (get-in shape-before [:selrect :x])
|
||||
(get-in shape-after [:selrect :x])))
|
||||
|
||||
(t/is (== (get-in shape-before [:selrect :y])
|
||||
(get-in shape-after [:selrect :y])))
|
||||
|
||||
(t/is (== (* 2 (get-in shape-before [:selrect :width]))
|
||||
(get-in shape-after [:selrect :width])))
|
||||
|
||||
(t/is (== (* 2 (get-in shape-before [:selrect :height]))
|
||||
(get-in shape-after [:selrect :height]))))
|
||||
:rect :path))
|
||||
|
||||
(t/testing "Transform with empty resize"
|
||||
(t/are [type]
|
||||
(let [modifiers {:resize-origin (gpt/point 0 0)
|
||||
:resize-vector (gpt/point 1 1)
|
||||
:resize-transform (gmt/matrix)}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/are [prop]
|
||||
(t/is (== (get-in shape-before [:selrect prop])
|
||||
(get-in shape-after [:selrect prop])))
|
||||
:x :y :width :height :x1 :y1 :x2 :y2))
|
||||
:rect :path))
|
||||
|
||||
(t/testing "Transform with resize=0"
|
||||
(t/are [type]
|
||||
(let [modifiers {:resize-origin (gpt/point 0 0)
|
||||
:resize-vector (gpt/point 0 0)
|
||||
:resize-transform (gmt/matrix)}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/is (> (get-in shape-before [:selrect :width])
|
||||
(get-in shape-after [:selrect :width])))
|
||||
(t/is (> (get-in shape-after [:selrect :width]) 0))
|
||||
|
||||
(t/is (> (get-in shape-before [:selrect :height])
|
||||
(get-in shape-after [:selrect :height])))
|
||||
(t/is (> (get-in shape-after [:selrect :height]) 0)))
|
||||
:rect :path))
|
||||
|
||||
(t/testing "Transform shape with rotation modifiers"
|
||||
(t/are [type]
|
||||
(let [modifiers {:rotation 30}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/is (not= shape-before shape-after))
|
||||
|
||||
(t/is (not (== (get-in shape-before [:selrect :x])
|
||||
(get-in shape-after [:selrect :x]))))
|
||||
|
||||
(t/is (not (== (get-in shape-before [:selrect :y])
|
||||
(get-in shape-after [:selrect :y])))))
|
||||
:rect :path))
|
||||
|
||||
(t/testing "Transform shape with rotation = 0 should leave equal selrect"
|
||||
(t/are [type]
|
||||
(let [modifiers {:rotation 0}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/are [prop]
|
||||
(t/is (== (get-in shape-before [:selrect prop])
|
||||
(get-in shape-after [:selrect prop])))
|
||||
:x :y :width :height :x1 :y1 :x2 :y2))
|
||||
:rect :path))
|
||||
|
||||
(t/testing "Transform shape with invalid selrect fails gracefuly"
|
||||
(t/are [type selrect]
|
||||
(let [modifiers {:displacement (gmt/matrix)}
|
||||
shape-before (-> (create-test-shape type {:modifiers modifiers})
|
||||
(assoc :selrect selrect))
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(= (:selrect shape-before) (:selrect shape-after)))
|
||||
|
||||
:rect {:x 0 :y 0 :width ##Inf :height ##Inf}
|
||||
:path {:x 0 :y 0 :width ##Inf :height ##Inf}
|
||||
:rect nil
|
||||
:path nil)))
|
|
@ -102,7 +102,6 @@
|
|||
(let [calc-extremities
|
||||
(fn [command prev]
|
||||
(case (:command command)
|
||||
:close-path []
|
||||
:move-to [(command->point command)]
|
||||
|
||||
;; If it's a line we add the beginning point and endpoint
|
||||
|
@ -116,7 +115,8 @@
|
|||
(curve-extremities (command->point prev)
|
||||
(command->point command)
|
||||
(command->point command :c1)
|
||||
(command->point command :c2)))))
|
||||
(command->point command :c2)))
|
||||
[]))
|
||||
|
||||
extremities (mapcat calc-extremities
|
||||
content
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
[app.common.geom.shapes.common :as gco]))
|
||||
|
||||
(defn rect->points [{:keys [x y width height]}]
|
||||
(assert (number? x))
|
||||
(assert (number? y))
|
||||
(assert (and (number? width) (> width 0)))
|
||||
(assert (and (number? height) (> height 0)))
|
||||
[(gpt/point x y)
|
||||
(gpt/point (+ x width) y)
|
||||
(gpt/point (+ x width) (+ y height))
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
(ns app.test-util-geom
|
||||
(:require [cljs.test :as t :include-macros true]
|
||||
[cljs.pprint :refer [pprint]]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.matrix :as gmt]))
|
||||
|
||||
(t/deftest point-constructors-test
|
||||
(let [p (gpt/point 1 2)]
|
||||
(t/is (= (:x p) 1))
|
||||
(t/is (= (:y p) 2)))
|
||||
|
||||
(let [p (gpt/point 1)]
|
||||
(t/is (= (:x p) 1))
|
||||
(t/is (= (:y p) 1)))
|
||||
|
||||
(let [p (gpt/point)]
|
||||
(t/is (= (:x p) 0))
|
||||
(t/is (= (:y p) 0))))
|
||||
|
||||
;; (t/deftest point-rotate-test
|
||||
;; (let [p1 (gpt/point 10 0)
|
||||
;; p2 (gpt/rotate p1 90)]
|
||||
;; (t/is (= (:x p2) 0))
|
||||
;; (t/is (= (:y p2) 10))))
|
||||
|
||||
(t/deftest point-add-test
|
||||
(let [p1 (gpt/point 1 1)
|
||||
p2 (gpt/point 2 2)
|
||||
p3 (gpt/add p1 p2)]
|
||||
(t/is (= (:x p3) 3))
|
||||
(t/is (= (:y p3) 3))))
|
||||
|
||||
(t/deftest point-subtract-test
|
||||
(let [p1 (gpt/point 3 3)
|
||||
p2 (gpt/point 2 2)
|
||||
p3 (gpt/subtract p1 p2)]
|
||||
(t/is (= (:x p3) 1))
|
||||
(t/is (= (:y p3) 1))))
|
||||
|
||||
(t/deftest point-distance-test
|
||||
(let [p1 (gpt/point 0 0)
|
||||
p2 (gpt/point 10 0)
|
||||
d (gpt/distance p1 p2)]
|
||||
(t/is (number? d))
|
||||
(t/is (= d 10))))
|
||||
|
||||
(t/deftest point-length-test
|
||||
(let [p1 (gpt/point 10 0)
|
||||
ln (gpt/length p1)]
|
||||
(t/is (number? ln))
|
||||
(t/is (= ln 10))))
|
||||
|
||||
(t/deftest point-angle-test
|
||||
(let [p1 (gpt/point 0 10)
|
||||
angle (gpt/angle p1)]
|
||||
(t/is (number? angle))
|
||||
(t/is (= angle 90)))
|
||||
(let [p1 (gpt/point 0 10)
|
||||
p2 (gpt/point 10 10)
|
||||
angle (gpt/angle-with-other p1 p2)]
|
||||
(t/is (number? angle))
|
||||
(t/is (= angle 45))))
|
||||
|
||||
(t/deftest matrix-constructors-test
|
||||
(let [m (gmt/matrix)]
|
||||
(t/is (= (str m) "matrix(1,0,0,1,0,0)")))
|
||||
(let [m (gmt/matrix 1 1 1 2 2 2)]
|
||||
(t/is (= (str m) "matrix(1,1,1,2,2,2)"))))
|
||||
|
||||
(t/deftest matrix-translate-test
|
||||
(let [m (-> (gmt/matrix)
|
||||
(gmt/translate (gpt/point 2 10)))]
|
||||
(t/is (= (str m) "matrix(1,0,0,1,2,10)"))))
|
||||
|
||||
(t/deftest matrix-scale-test
|
||||
(let [m (-> (gmt/matrix)
|
||||
(gmt/scale (gpt/point 2)))]
|
||||
(t/is (= (str m) "matrix(2,0,0,2,0,0)"))))
|
||||
|
||||
(t/deftest matrix-rotate-test
|
||||
(let [m (-> (gmt/matrix)
|
||||
(gmt/rotate 10))]
|
||||
(t/is (= (str m) "matrix(0.984807753012208,0.17364817766693033,-0.17364817766693033,0.984807753012208,0,0)"))))
|
Loading…
Add table
Reference in a new issue