ebox/tests/ebox-css-layout-tests.el
Kinneyzhang 79f5bc23d1 feat: add CSS sizing and native text interaction capabilities
Normalize size units and intrinsic sizing across Elisp and native layout. Add help, pointer, hover-style and keymap support with reusable interaction adapters.

Keep content updates local, preserve scroll caches and hover borders, and avoid rebuilding retained plans and ownership metadata for stable geometry.

Validation: make check and native-rust-tests passed; targeted native interaction and scroll publication regressions passed.
2026-09-09 22:25:18 +08:00

560 lines
28 KiB
EmacsLisp

;;; ebox-css-layout-tests.el --- CSS used-size regression tests -*- lexical-binding: t; -*-
;;; Commentary:
;; Exercise the boundary between pure CSS lengths and buffer layout geometry.
;;; Code:
(require 'ert)
(require 'cl-lib)
(require 'ebox-fixtures)
(defun ebox-css-layout-test--glyph-width (string)
"Measure STRING with seven-pixel glyphs and Emacs's per-space truncation."
(cl-loop for index below (or (string-match "\n" string) (length string))
for display = (get-text-property index 'display string)
for width = (and (consp display) (eq (car display) 'space)
(plist-get (cdr display) :width))
sum (cond ((and (consp width) (numberp (car width)))
(floor (car width)))
((numberp width) (floor (* 7 width)))
(t 7))))
(defmacro ebox-css-layout-test--with-pixel-display (&rest body)
"Run BODY with an independent whole-pixel display oracle."
(declare (indent 0) (debug t))
`(let ((ebox-runtime-idle-prewarm nil)
(ebox-runtime-idle-reflow-cache-prewarm nil))
(cl-letf (((symbol-function 'string-pixel-width)
#'ebox-css-layout-test--glyph-width)
((symbol-function 'ebox-native-reflow-layout-ready-p)
(lambda () nil)))
(ebox-clear-cache)
(unwind-protect (progn ,@body)
(ebox-clear-cache)))))
(defun ebox-css-layout-test--display (string)
"Return STRING text and display properties without retained identities."
(list (substring-no-properties string)
(cl-loop for index below (length string)
collect (get-text-property index 'display string))))
(defun ebox-css-layout-test--assert-pixel-lines (output width)
"Assert every OUTPUT line measures WIDTH in the model and real glyph oracle."
(dolist (line (ebox-string-lines output))
(should (= (ebox--string-pixel-width line) width))
(should (= (ebox-css-layout-test--glyph-width line) width))))
(ert-deftest ebox-css-layout-percentage-text-and-blank-share-pixel-boundaries ()
"Centered text and blank fill consume the same final percentage width."
(ebox-css-layout-test--with-pixel-display
(let* ((ebox-viewport-width 207)
(input (ebox-build
'(box :width (% 50) :height (lh 2) :border "red"
:text-align center "X")))
(output (ebox-render input)))
(should (= (ebox-size-resolve '(% 50) '(:percent-base 207)) 103.5))
(should (= (ebox-string-height output) 2))
(ebox-css-layout-test--assert-pixel-lines output 103))))
(ert-deftest ebox-css-layout-percentage-siblings-share-the-remaining-pixel ()
"Two 50-percent Row children divide an odd extent into 50 and 51 pixels."
(ebox-css-layout-test--with-pixel-display
(let* ((ebox-viewport-width 101)
(output
(ebox-render
(ebox-build
'(row :width (px 101)
(box :width (% 50) :height (lh 2) :border "red"
:text-align center "A")
(box :width (% 50) :height (lh 2) :border "blue"
:text-align center "B"))))))
(ebox-css-layout-test--assert-pixel-lines output 101)
(dolist (line (ebox-string-lines output))
(let ((offsets
(cl-loop for index below (length line)
when (get-text-property index 'ebox-bl line)
collect (ebox-css-layout-test--glyph-width
(substring line 0 index)))))
(should (equal offsets '(0 50))))))))
(ert-deftest ebox-css-layout-fractional-chrome-shares-the-content-boundary ()
"Margins, padding and centered content share one cumulative pixel grid."
(ebox-css-layout-test--with-pixel-display
(ebox-css-layout-test--assert-pixel-lines
(ebox-render
(ebox-build
'(box :width (px 20) :height (lh 2) :box-sizing border-box
:padding-inline (px 0.5) :margin-inline (px 0.5)
:border "red" :text-align center "X")))
21)))
(ert-deftest ebox-css-layout-pixel-quantization-preserves-private-input ()
"Fractional runs split per glyph; zero widths keep ownership and newlines."
(let* ((display '(space :width (0.5) :height 1))
(source (propertize " \n " 'display display 'ebox-content 17))
(before (copy-sequence source))
(result (ebox--quantize-pixel-spaces source)))
(should (equal-including-properties source before))
(should (equal display '(space :width (0.5) :height 1)))
(should (equal (mapcar (lambda (index)
(plist-get (cdr (get-text-property index 'display
result)) :width))
'(0 1 3 4))
'((0) (1) (0) (1))))
(dolist (index '(0 1 3 4))
(should (= (get-text-property index 'ebox-content result) 17))
(should (= (plist-get (cdr (get-text-property index 'display result))
:height)
1)))
(should (eq result (ebox--quantize-pixel-spaces result)))
(let ((integer (ebox-pixel-space 12)))
(should (eq integer (ebox--quantize-pixel-spaces integer))))))
(defun ebox-css-layout-test--retained-label (label &optional color)
"Build a stable percentage LABEL whose text parity can introduce fractions."
(ebox-build
`(column :key root :width (vw 100)
(box :key label :width (% 100) :height (lh 2) :border "red"
:text-align center :bgcolor ,(or color "#FFFFFF") ,label))))
(ert-deftest ebox-css-layout-retained-new-fractions-and-paint-match-fresh ()
"A local text edit can introduce a half-pixel, even with unchanged sizes."
(ebox-css-layout-test--with-pixel-display
(let ((ebox-viewport-width 101)
(ebox-viewport-height 20))
(with-temp-buffer
(ebox-render-to-buffer
(current-buffer) (ebox-css-layout-test--retained-label "A"))
(should-not (plist-get (ebox--buffer-render-state (current-buffer))
:fractional-pixel-output-p))
;; The first update introduces fractions into an integer-only prior
;; frame. Paint must preserve the flag; later integer output clears it.
(dolist (case '(("AA" nil t) ("AA" "#DDEEFF" t)
("AAA" "#DDEEFF" nil) ("AAAA" "#DDEEFF" t)
("A" "#DDEEFF" nil)))
(let* ((input (ebox-css-layout-test--retained-label
(nth 0 case) (nth 1 case)))
(_report (ebox-commit (current-buffer) input))
(actual (buffer-string))
(fresh (ebox-render input)))
(should (eq (plist-get (ebox--buffer-render-state (current-buffer))
:fractional-pixel-output-p)
(nth 2 case)))
(ebox-css-layout-test--assert-pixel-lines actual 101)
(should (equal (ebox-css-layout-test--display actual)
(ebox-css-layout-test--display fresh)))))))))
(ert-deftest ebox-css-layout-retained-fractional-sibling-origin-matches-fresh ()
"Sequential edits never quantize the second fractional sibling at origin zero."
(ebox-css-layout-test--with-pixel-display
(let ((ebox-viewport-width 101)
(ebox-viewport-height 20))
(cl-labels ((input (width right)
(ebox-build
`(row :key root :width (px 101)
(box :key left :width ,width :height (lh 2)
:border "red" :text-align center "A")
(box :key right :width ,width :height (lh 2)
:border "blue" :text-align center ,right)))))
(with-temp-buffer
(ebox-render-to-buffer (current-buffer) (input '(% 50) "B"))
(dolist (case '(((% 50) "BB" t) ((% 50) "BBB" t)
((px 50) "BBB" nil) ((px 50) "B" nil)
((% 50) "BB" t)))
(let* ((next (input (nth 0 case) (nth 1 case)))
(_report (ebox-commit (current-buffer) next))
(actual (buffer-string)))
(should (eq (plist-get (ebox--buffer-render-state (current-buffer))
:fractional-pixel-output-p)
(nth 2 case)))
(ebox-css-layout-test--assert-pixel-lines actual 101)
(should (equal (ebox-css-layout-test--display actual)
(ebox-css-layout-test--display
(ebox-render next)))))))))))
(defun ebox-css-layout-test--fractional-scroll (offset &optional boundary mixed)
"Build a centered percentage scroll at OFFSET with optional BOUNDARY.
MIXED starts with three integral rows before the fractional cached rows."
(let ((scroll
(apply #'ebox-test-box
:key 'scroll :width '(% 100) :height 3 :overflow 'scroll
:text-align 'center :scroll-offset offset
(append
(and (eq boundary 'chrome) (list :border "red"))
(list
(ebox-test-text
(mapconcat (lambda (index)
(format (if (and mixed (< index 3)) "%03d" "%02d")
index))
(number-sequence 0 31) "\n")))))))
(if (eq boundary 'nested)
(ebox-test-box :width '(101) scroll)
scroll)))
(ert-deftest ebox-css-layout-fractional-root-scroll-reuses-complete-pixel-lines ()
"Cached full physical rows scroll without layout or projection work."
(ebox-css-layout-test--with-pixel-display
(let ((ebox-viewport-width 101)
(ebox-viewport-height 3))
(with-temp-buffer
(ebox-render-to-buffer
(current-buffer) (ebox-css-layout-test--fractional-scroll 10))
(let* ((state (ebox--buffer-render-state (current-buffer)))
(region (car (plist-get state :scroll-region-ids)))
(scroll (gethash region (plist-get state :scroll-state-table)))
(raw (plist-get scroll :content-lines))
(rendered (plist-get scroll :rendered-content-lines))
(before (copy-tree (mapcar #'ebox-css-layout-test--display
rendered)))
(offset 10))
(should (plist-get state :fractional-pixel-output-p))
(should (ebox--scroll-state-retained-window-ready-p scroll))
(dolist (next '(11 12 11 16 10))
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
(lambda (&rest _) (ert-fail "cached scroll rendered root")))
((symbol-function 'ebox-surface--render-candidate-node)
(lambda (&rest _) (ert-fail "cached scroll reran layout")))
((symbol-function 'ebox-surface--complete-projection)
(lambda (&rest _) (ert-fail "cached scroll reprojected styles"))))
(should (= (ebox--scroll-region-by region (- next offset) 1)
(- next offset))))
(setq offset next
state (ebox--buffer-render-state (current-buffer))
scroll (gethash region (plist-get state :scroll-state-table)))
(let ((lines (plist-get (plist-get state :surface-fragments)
:scroll-lines)))
(should lines)
(should-not (cl-some #'ebox--fractional-pixel-spaces-p lines))
(should (equal (ebox-css-layout-test--display (ebox-lines-join lines))
(ebox-css-layout-test--display (buffer-string)))))
(should (eq (plist-get (ebox-buffer-update-report (current-buffer))
:projection-kind)
'scroll-patch))
(should (plist-get state :fractional-pixel-output-p))
(should (eq raw (plist-get scroll :content-lines)))
(should (eq rendered (plist-get scroll :rendered-content-lines)))
(should (equal before
(mapcar #'ebox-css-layout-test--display rendered)))
(ebox-css-layout-test--assert-pixel-lines (buffer-string) 101)
(should (equal (ebox-css-layout-test--display (buffer-string))
(ebox-css-layout-test--display
(ebox-render
(ebox-css-layout-test--fractional-scroll offset)))))))))))
(ert-deftest ebox-css-layout-fractional-root-scroll-retains-new-raw-fraction-flag ()
"A newly visible fractional row keeps its raw flag after returning to integers."
(ebox-css-layout-test--with-pixel-display
(let ((ebox-viewport-width 101)
(ebox-viewport-height 3))
(with-temp-buffer
(ebox-render-to-buffer
(current-buffer) (ebox-css-layout-test--fractional-scroll 0 nil t))
(let* ((state (ebox--buffer-render-state (current-buffer)))
(region (car (plist-get state :scroll-region-ids)))
(raw (plist-get (gethash region (plist-get state :scroll-state-table))
:rendered-content-lines)))
(should-not (plist-get state :fractional-pixel-output-p))
(dolist (delta '(1 -1))
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
(lambda (&rest _) (ert-fail "fractional row rerendered root"))))
(should (= (ebox--scroll-region-by region delta 1) delta)))
(setq state (ebox--buffer-render-state (current-buffer)))
(should (plist-get state :fractional-pixel-output-p))
(ebox-css-layout-test--assert-pixel-lines (buffer-string) 101))
;; Integral line strings keep their existing ownership-template keys.
(let ((lines (plist-get (plist-get state :surface-fragments) :scroll-lines)))
(cl-mapc (lambda (actual source) (should (eq actual source)))
lines (seq-take raw 3))))))))
(ert-deftest ebox-css-layout-fractional-scroll-keeps-wrapper-fallbacks ()
"Nested or chrome-bearing fractional scrolls retain full-line projection."
(ebox-css-layout-test--with-pixel-display
(let ((ebox-viewport-width 101)
(ebox-viewport-height 3))
(dolist (boundary '(nested chrome))
(with-temp-buffer
(ebox-render-to-buffer
(current-buffer) (ebox-css-layout-test--fractional-scroll 10 boundary))
(let* ((state (ebox--buffer-render-state (current-buffer)))
(region (car (plist-get state :scroll-region-ids)))
(original (symbol-function 'ebox-surface--render-candidate))
(calls 0))
(should (plist-get state :fractional-pixel-output-p))
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
(lambda (&rest args)
(cl-incf calls)
(apply original args))))
(should (= (ebox--scroll-region-by region 1 1) 1)))
(should (= calls 1))
(should (equal (ebox-css-layout-test--display (buffer-string))
(ebox-css-layout-test--display
(ebox-render
(ebox-css-layout-test--fractional-scroll
11 boundary)))))))))))
(ert-deftest ebox-css-layout-fractional-scroll-rolls-back-normalized-output ()
"Failed publication preserves raw caches and retries the cached scroll path."
(ebox-css-layout-test--with-pixel-display
(let ((ebox-viewport-width 101)
(ebox-viewport-height 3))
(with-temp-buffer
(ebox-render-to-buffer
(current-buffer) (ebox-css-layout-test--fractional-scroll 10))
(let* ((surface ebox-surface--buffer-surface)
(state (tp-surface-client-state surface))
(revision (tp-surface-revision surface))
(region (car (plist-get state :scroll-region-ids)))
(scroll (gethash region (plist-get state :scroll-state-table)))
(raw (plist-get scroll :rendered-content-lines))
(before (copy-tree (mapcar #'ebox-css-layout-test--display raw)))
(contents (buffer-string)))
(let ((tp--surface-publication-step-function
(lambda (step _surface)
(when (eq step 'client-state)
(error "reject normalized scroll publication")))))
(should-error (ebox--scroll-region-by region 1 1)))
(should (= (tp-surface-revision surface) revision))
(should (eq (tp-surface-client-state surface) state))
(should (= (plist-get (ebox-scroll-state region) :scroll-offset) 10))
(should (eq raw (plist-get (ebox-scroll-state region) :rendered-content-lines)))
(should (equal before (mapcar #'ebox-css-layout-test--display raw)))
(should (equal-including-properties contents (buffer-string)))
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
(lambda (&rest _) (ert-fail "retry rerendered root"))))
(should (= (ebox--scroll-region-by region 1 1) 1)))
(ebox-css-layout-test--assert-pixel-lines (buffer-string) 101))))))
(ert-deftest ebox-css-layout-percent-and-viewport-use-distinct-bases ()
(let* ((ebox-viewport-width 800)
(ebox-viewport-height 40)
(ebox--css-viewport-width 800)
(ebox--css-viewport-height 800)
(ebox--css-containing-height 800)
(ebox--css-size-context-active-p t)
(box (ebox-test-root
(ebox-build '(box :width (px 200) :height (vh 50) "x")))))
(ebox--call-with-box-content-context
box
(lambda ()
(should (= (ebox--size-pixels '(% 50) nil 'width) 100))
(should (= (ebox--size-pixels '(vw 50) nil 'width) 400))
(should (= (ebox--size-pixels '(% 50) nil 'height) 200))
(should (= (ebox--size-pixels '(vh 50) nil 'height) 400))))))
(ert-deftest ebox-css-layout-auto-height-does-not-resolve-child-percent ()
(let* ((ebox-viewport-width 800)
(ebox--css-containing-height 800)
(box (ebox-test-root
(ebox-build '(box :width (px 200) "x")))))
(ebox--call-with-box-content-context
box
(lambda ()
(should-not (ebox--size-pixels '(% 50) nil 'height))
(should (= (ebox--resolve-size-content-height
box '(% 50) 3)
3))))))
(ert-deftest ebox-css-layout-explicit-indefinite-percent-basis ()
(let ((ebox-viewport-width 400)
(ebox--css-containing-height 600))
(should-not (ebox--size-pixels '(% 100) nil 'width nil))
(should-not (ebox--size-pixels '(% 100) nil 'height nil))
(should (= (ebox--size-pixels '(% 100) nil 'width 0) 0))))
(ert-deftest ebox-css-layout-definite-parent-height-applies-constraints ()
(let ((ebox-viewport-width 400)
(ebox--css-size-context-active-p t)
(ebox--css-viewport-height 400)
(box (ebox-test-root
(ebox-build '(box :height (vh 50) :min-height (vh 12.5)
:max-height (vh 25) "x")))))
(ebox--call-with-box-content-context
box
(lambda ()
(should (= (ebox--size-pixels '(% 50) nil 'height) 50))))))
(ert-deftest ebox-css-layout-font-units-use-projected-zero-and-line ()
(let* ((fact (ebox-font--make-fact
:measurement-metrics '(:zero-width 9 :height 24)))
(box (list :ebox-font-fact fact)))
(should (= (ebox--size-pixels '(ch 10) box) 90))
(should (= (ebox--size-pixels '(lh 3) box 'height) 72))
(should (= (ebox--resolve-height-expression-lines '(lh 3) box) 3))
(let ((ebox--css-font-fact fact))
(should (= (ebox--size-pixels '(ch 10)) 90)))))
(ert-deftest ebox-css-layout-rounds-height-after-complete-expression ()
(let* ((fact (ebox-font--make-fact
:measurement-metrics '(:zero-width 10 :height 20)))
(box (ebox-test-root
(ebox-build
'(box :height (calc (- (vh 50) (lh 0.4))) "x"))))
(ebox--css-size-context-active-p t)
(ebox--css-viewport-height 490))
(setq box (plist-put box :ebox-font-fact fact))
(should (< (abs (- (ebox--resolve-height-expression-lines
'(calc (- (vh 50) (lh 0.4))) box)
11.85))
1e-9))
(should (= (ebox--content-height box 1) 11))))
(ert-deftest ebox-css-layout-vertical-padding-percent-refers-to-width ()
(let ((ebox-viewport-width 200)
(ebox--css-containing-height 1000)
(box (list :ebox-font-fact
(ebox-font--make-fact
:measurement-metrics '(:zero-width 10 :height 20)))))
(should (= (ebox--edge-used-value box :padding-top-height '(% 10)) 1))
(should (= (ebox--edge-used-value box :padding-left-pixel '(% 10)) 20))))
(ert-deftest ebox-css-layout-height-keywords-and-minimum-precedence ()
(let ((ebox--css-containing-height 10))
(dolist (keyword '(min-content max-content fit-content))
(let ((box (ebox-test-root
(ebox-build `(box :height ,keyword "x")))))
(should (= (ebox--content-height box 4) 4))))
(let ((box (ebox-test-root
(ebox-build '(box :height (lh 2)
:min-height (lh 5)
:max-height (lh 3) "x")))))
(should (= (ebox--content-height box 1) 5)))))
(ert-deftest ebox-css-layout-inline-content-wraps-at-final-used-width ()
"Intrinsic keywords and bounds size the text flow as well as its paint."
(ebox-css-layout-test--with-pixel-display
(let ((ebox-viewport-width 56))
(dolist (kind '(single multiple column))
(dolist (case '(((:width min-content)
28 ("red" "ink" "on" "blue"))
((:width fit-content)
56 ("red ink" "on blue"))
((:width max-content)
105 ("red ink on blue"))
((:width (px 7) :min-width min-content)
28 ("red" "ink" "on" "blue"))
((:width (px 7) :min-width fit-content)
56 ("red ink" "on blue"))
((:width (px 7) :min-width max-content)
105 ("red ink on blue"))
((:width (px 140) :max-width min-content)
28 ("red" "ink" "on" "blue"))
((:width (px 140) :max-width fit-content)
56 ("red ink" "on blue"))
((:width (px 140) :max-width max-content)
105 ("red ink on blue"))
((:width max-content :max-width (px 56))
56 ("red ink" "on blue"))
((:width min-content :min-width (px 56))
56 ("red ink" "on blue"))
((:width (px 7) :min-width (px 56)
:max-width (px 28))
56 ("red ink" "on blue"))))
(ert-info ((format "%S flow, declarations %S" kind (car case)))
(let* ((form
(append
(list (if (eq kind 'column) 'column 'box))
(car case)
(pcase kind
('single '("red ink on blue"))
('multiple '((text "red ink ") (text "on blue")))
('column '((text "red ink on blue"))))))
(output (ebox-render (ebox-build form))))
(ebox-css-layout-test--assert-pixel-lines output (nth 1 case))
(should (equal (mapcar #'string-trim (ebox-string-lines output))
(nth 2 case))))))))))
(ert-deftest ebox-css-layout-intrinsic-text-viewport-keeps-nested-contexts ()
"Intrinsic probes stay unwrapped; final nested percentages use the used width."
(ebox-css-layout-test--with-pixel-display
(dolist (form '((box :width fit-content
(column (text "red ink on blue")))
(column :width fit-content
(box :width (% 100) "red ink on blue"))))
(let* ((input (ebox-build form))
(node (ebox-test-root input)))
(dolist (width '(56 140 14 84 28 56))
(let* ((ebox-viewport-width width)
(output (ebox-render input)))
(ebox-css-layout-test--assert-pixel-lines
output (max 28 (min 105 width)))
(should (equal (mapcar #'string-trim (ebox-string-lines output))
(pcase width
((or 14 28) '("red" "ink" "on" "blue"))
(56 '("red ink" "on blue"))
(84 '("red ink on" "blue"))
(140 '("red ink on blue")))))
(should (eq (ebox-get node :width) 'fit-content))
(should (eq (ebox-get node :wrap-mode) 'word))))))
(let ((ebox-viewport-width 56))
(dolist (kind '(box column))
(let ((output (ebox-render
(ebox-build
`(,kind :width min-content :wrap-mode none
(text "red ink on blue"))))))
(ebox-css-layout-test--assert-pixel-lines output 105)
(should (equal (substring-no-properties output)
"red ink on blue")))))))
(ert-deftest ebox-css-layout-intrinsic-parent-keeps-child-width-constraints ()
"Measuring a parent must retain each nested child's independent used width."
(ebox-css-layout-test--with-pixel-display
(let ((ebox-viewport-width 56))
(dolist (parent '(box column))
(dolist (child '(box column))
(dolist (properties '((:width min-content)
(:width (px 7) :min-width min-content)
(:width (px 140) :max-width min-content)))
(ert-info ((format "%S parent, %S child %S"
parent child properties))
(let ((output
(ebox-render
(ebox-build
`(,parent :width max-content
(,child ,@properties
(text "red ink on blue")))))))
(ebox-css-layout-test--assert-pixel-lines output 28)
(should (equal (mapcar #'string-trim (ebox-string-lines output))
'("red" "ink" "on" "blue")))))))))))
(ert-deftest ebox-css-layout-used-edge-ranges-are-explicit ()
(should-error
(ebox--edge-used-value nil :margin-left-pixel
'(calc (- (px 1) (px 2)))))
(should (= (ebox--edge-used-value nil :padding-left-pixel
'(calc (- (px 1) (px 2))))
0)))
(ert-deftest ebox-css-layout-equivalent-pixels-have-identical-display ()
(should (equal-including-properties (ebox-pixel-space 214)
(ebox-pixel-space 214.0)))
(should (equal (get-text-property 0 'display (ebox-pixel-space 2.5))
'(space :width (2.5)))))
(ert-deftest ebox-css-layout-cyclic-grid-gaps-overflow-intrinsic-box ()
(dolist
(case
'(((grid :width max-content
:grid-template-columns ((px 10) (px 10))
:column-gap (% 50) :overflow visible
(box "A") (box "B"))
20 1 30 1)
((grid :width (px 10)
:grid-template-columns ((px 10))
:grid-template-rows ((lh 2) (lh 2))
:row-gap (% 50) :overflow visible
(box "A") (box "B"))
10 4 10 6)))
(let* ((input (ebox-build (car case)))
(node (ebox-test-root input))
(ebox--render-source-index (ebox-test-source-index input))
(ebox--surface-materialization-active t)
(rendered (ebox--render-layout node)))
(should (= (ebox--content-pixel node) (nth 1 case)))
(should (= (ebox--total-height node) (nth 2 case)))
(should (= (ebox--string-max-pixel-width rendered) (nth 3 case)))
(should (= (ebox-string-height rendered) (nth 4 case))))))
(provide 'ebox-css-layout-tests)
;;; ebox-css-layout-tests.el ends here