mirror of
https://github.com/penpot/penpot.git
synced 2026-04-26 03:38:18 +00:00
107 lines
4.7 KiB
Clojure
107 lines
4.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-flex-layout-test
|
||
(:require
|
||
[app.common.geom.rect :as grc]
|
||
[app.common.geom.shapes.flex-layout.positions :as flp]
|
||
[app.common.math :as mth]
|
||
[app.common.types.shape :as cts]
|
||
[app.common.types.shape.layout :as ctl]
|
||
[clojure.test :as t]))
|
||
|
||
;; ---- helpers ----
|
||
|
||
(defn- make-col-frame
|
||
"Minimal col? flex frame with wrap enabled.
|
||
wrap is required for the content-around? predicate to activate."
|
||
[& {:as opts}]
|
||
(cts/setup-shape (merge {:type :frame
|
||
:layout :flex
|
||
:layout-flex-dir :column
|
||
:layout-wrap-type :wrap
|
||
:x 0 :y 0 :width 200 :height 200}
|
||
opts)))
|
||
|
||
(defn- rect->bounds
|
||
"Convert a rect to the 4-point layout-bounds vector expected by gpo/*."
|
||
[rect]
|
||
(grc/rect->points rect))
|
||
|
||
;; ---- get-base-line (around? branch) ----
|
||
;;
|
||
;; Bug: in positions.cljc the col? + around? branch had a mis-parenthesised
|
||
;; expression `(/ free-width num-lines) 2`, which was parsed as three
|
||
;; arguments to `max`:
|
||
;; (max lines-gap-col (/ free-width num-lines) 2)
|
||
;; instead of the intended two-argument max with a nested division:
|
||
;; (max lines-gap-col (/ free-width num-lines 2))
|
||
;;
|
||
;; For a col? layout the cross-axis is horizontal (hv), so the around? offset
|
||
;; is applied as hv(delta) — i.e. the delta ends up in (:x base-p).
|
||
|
||
(t/deftest get-base-line-around-uses-half-per-line-free-width
|
||
(t/testing "col? + content-around? offset is free-width / num-lines / 2"
|
||
;; Layout: col? wrap, width=200, 3 lines each 20px wide → free-width=140
|
||
;; lines-gap-col = 0 (no gap defined)
|
||
;; Expected horizontal offset = max(0, 140/3/2) ≈ 23.33
|
||
;; Before the bug fix the formula was (max ... (/ 140 3) 2) ≈ 46.67.
|
||
(let [frame (make-col-frame :layout-align-content :space-around)
|
||
bounds (rect->bounds (grc/make-rect 0 0 200 200))
|
||
;; 3 lines of 20px each (widths); no row gap
|
||
num-lines 3
|
||
total-width 60
|
||
total-height 0
|
||
base-p (flp/get-base-line frame bounds total-width total-height num-lines)
|
||
free-width (- 200 total-width)
|
||
;; lines-gap-col = (dec 3) * 0 = 0; max(0, free-width/num-lines/2)
|
||
expected-x (/ free-width num-lines 2)]
|
||
|
||
;; The base point x-coordinate (hv offset) should equal half per-line free space.
|
||
(t/is (mth/close? expected-x (:x base-p) 0.01))))
|
||
|
||
(t/testing "col? + content-around? offset respects lines-gap-col minimum"
|
||
;; When the accumulated column gap exceeds the computed half-per-line value
|
||
;; max(lines-gap-col, free-width/num-lines/2) returns the gap.
|
||
(let [frame (make-col-frame :layout-align-content :space-around
|
||
:layout-gap {:column-gap 50 :row-gap 0})
|
||
bounds (rect->bounds (grc/make-rect 0 0 200 200))
|
||
;; 4 lines × 20px = 80px used; free-width=120; half-per-line = 120/4/2 = 15
|
||
;; lines-gap-col = (dec 4)*50 = 150 → max(150, 15) = 150
|
||
num-lines 4
|
||
total-width 80
|
||
total-height 0
|
||
base-p (flp/get-base-line frame bounds total-width total-height num-lines)
|
||
lines-gap-col (* (dec num-lines) 50)]
|
||
|
||
(t/is (mth/close? lines-gap-col (:x base-p) 0.01)))))
|
||
|
||
;; ---- v-end? guard (drop-line-area) ----
|
||
;;
|
||
;; Bug: `v-end?` inside `drop-line-area` was guarded by `row?` instead of
|
||
;; `col?`, so vertical-end alignment in a column layout was never triggered.
|
||
;; We verify the predicate behaviour directly via ctl/v-end?.
|
||
|
||
(t/deftest v-end-guard-uses-col-not-row
|
||
(t/testing "v-end? is true for col? frame with justify-content :end"
|
||
;; col? + justify-content=:end → ctl/v-end? must be true
|
||
(let [frame (cts/setup-shape {:type :frame
|
||
:layout :flex
|
||
:layout-flex-dir :column
|
||
:layout-justify-content :end
|
||
:x 0 :y 0 :width 100 :height 100})]
|
||
(t/is (true? (ctl/v-end? frame)))))
|
||
|
||
(t/testing "v-end? is false for row? frame with only justify-content :end"
|
||
;; row? + justify-content=:end alone does NOT set v-end?; for row layouts
|
||
;; v-end? checks align-items, not justify-content.
|
||
(let [frame (cts/setup-shape {:type :frame
|
||
:layout :flex
|
||
:layout-flex-dir :row
|
||
:layout-justify-content :end
|
||
:x 0 :y 0 :width 100 :height 100})]
|
||
(t/is (not (ctl/v-end? frame))))))
|