ebox/tests/ebox-layout-boundary-tests.el
Kinneyzhang f1f91468aa
Some checks are pending
CI / test (push) Waiting to run
CI / native-build (macos-latest) (push) Waiting to run
CI / native-build (ubuntu-latest) (push) Waiting to run
CI / native-build (windows-latest) (push) Waiting to run
CI / native-msrv (macos-latest) (push) Waiting to run
CI / native-msrv (ubuntu-latest) (push) Waiting to run
CI / native-msrv (windows-latest) (push) Waiting to run
chore: freeze verified ebox baseline before C1b
2026-09-05 05:07:37 +08:00

217 lines
9.6 KiB
EmacsLisp

;;; ebox-layout-boundary-tests.el --- M2a layout dependency gates -*- lexical-binding: t; -*-
;;; Code:
(require 'ert)
(require 'cl-lib)
(require 'ebox)
(require 'ebox-fixtures)
(defconst ebox-layout-boundary-test--root
(expand-file-name ".." (file-name-directory (or load-file-name buffer-file-name)))
"Repository root used by layout boundary tests.")
(defun ebox-layout-boundary-test--source (file)
"Return repository FILE as text."
(with-temp-buffer
(insert-file-contents
(expand-file-name file ebox-layout-boundary-test--root))
(buffer-string)))
(defun ebox-layout-boundary-test--legacy-static-render (node)
"Render NODE through the pre-E2 static materialization edge."
(let ((candidate (ebox-surface--candidate-root node t)))
(let ((ebox--surface-materialization-active t)
(ebox--region-box-table (make-hash-table :test #'equal))
(ebox--scroll-global-state (make-hash-table :test #'equal))
(ebox--scroll-idle-prefetch-timers (make-hash-table :test #'equal))
(ebox--smooth-scroll-state-table (make-hash-table :test #'equal))
(ebox--render-cache-table (make-hash-table :test #'equal))
(ebox--render-cache-signature-cache (make-hash-table :test #'eq))
(ebox--box-content-render-cache (make-hash-table :test #'eq))
(ebox--viewport-dependent-node-ids-cache (make-hash-table :test #'eq))
(ebox--viewport-dependent-subtree-cache (make-hash-table :test #'eq))
(ebox--viewport-height-dependent-subtree-cache
(make-hash-table :test #'eq))
(ebox--flex-content-min-width-table (make-hash-table :test #'eq))
(ebox--render-runtime-revision nil)
(ebox--render-cache-allow-viewport-dependent nil)
(ebox--render-cache-scroll-state-region-ids nil)
(ebox--render-cache-scroll-state-restorable-p nil)
(ebox--render-cache-scroll-state-retained-cost-cache nil))
(ebox--render-layout candidate))))
(defun ebox-layout-boundary-test--legacy-render (input)
"Render canonical INPUT through the exact pre-E2 direct call edge."
(let* ((node
(ebox-canonical-input--single-root input "legacy E2 artifact"))
(base-source-index (ebox-canonical-input--source-index input))
(ebox--render-source-index base-source-index)
(source-index
(ebox-tree-source-index
node t ebox--render-root-parent-kind base-source-index nil))
(rendered
(if (and (not (ebox-style-cascade-active-p))
(zerop (ebox-tree-author-style-count node))
(not (ebox-surface--inline-inheritance-required-p
node source-index)))
(let ((ebox--region-id-counter ebox--region-id-counter)
(ebox--runtime-node-id-counter
ebox--runtime-node-id-counter))
(ebox-layout-boundary-test--legacy-static-render node))
(let ((ebox--surface-materialization-active t)
(ebox--region-id-counter ebox--region-id-counter)
(ebox--runtime-node-id-counter ebox--runtime-node-id-counter))
(tp-surface-materialize-string
(ebox-surface-producer
node nil t (list :source-base-index base-source-index)))))))
(ebox--strip-paint-origins! rendered)))
(defun ebox-layout-boundary-test--fixtures ()
"Return representative static and materialized layout inputs."
(list
(ebox-test-column
(ebox-test-row
(ebox-test-box (ebox-test-text "A") :width '(48))
(ebox-test-box (ebox-test-text "B") :width '(48)))
(ebox-test-box (ebox-test-text "Tail") :width '(96)))
(ebox-test-flex
:flex-flow '(row wrap) :column-gap '(2)
(ebox-test-box (ebox-test-text "One") :width '(52))
(ebox-test-box (ebox-test-text "Two") :width '(52)))
(ebox-test-grid
:grid-template-columns '((54) (fr 1))
(ebox-test-box (ebox-test-text "Left"))
(ebox-test-box (ebox-test-text "Right")))
(ebox-test-box
:font-size 16
(ebox-test-box (ebox-test-text "Inherited")))))
(ert-deftest ebox-layout-boundary-has-no-surface-or-publication-edge ()
"The layout module depends only on its injected render context."
(let ((source (ebox-layout-boundary-test--source "ebox-layout.el")))
(should-not (string-match-p "(require[[:space:]]+'ebox-surface)" source))
(should-not (string-match-p "\\_<ebox-surface-" source))
(should-not (string-match-p "\\_<tp-surface-" source))
(should (string-match-p "ebox-render-context-candidate-root" source))
(should (string-match-p
"ebox-render-context-materialize-string" source))))
(ert-deftest ebox-incremental-boundary-uses-injected-context-port ()
"Incremental planning has no upward Surface symbol or publication edge."
(let ((source (ebox-layout-boundary-test--source "ebox-incremental.el")))
(should-not (string-match-p "ebox-surface" source))
(should (ebox-incremental-context-port-p
ebox-incremental--context-port))
(should
(string-match-p
"(ebox-incremental-install-context-port"
(ebox-layout-boundary-test--source "ebox-surface.el")))))
(ert-deftest ebox-layout-boundary-preserves-pre-e2-layout-artifacts ()
"The injected route preserves every old character and property interval."
(dolist (input (ebox-layout-boundary-test--fixtures))
(let ((legacy (ebox-layout-boundary-test--legacy-render input))
(current (ebox-render input)))
(should (equal-including-properties current legacy))
(should
(equal (mapcar #'ebox--string-pixel-width (ebox-string-lines current))
(mapcar #'ebox--string-pixel-width
(ebox-string-lines legacy)))))))
(ert-deftest ebox-layout-boundary-static-route-is-a-strict-subset ()
"Static layout uses candidate and inheritance inputs without TP materialize."
(let ((candidate-calls 0)
(inheritance-calls 0)
(materialize-calls 0)
(default ebox--default-layout-context-port))
(let ((ebox--layout-context-port
(ebox-render-context-create-layout-port
:candidate-root
(lambda (&rest arguments)
(cl-incf candidate-calls)
(apply (ebox-layout-context-port-candidate-root default)
arguments))
:inline-inheritance-required-p
(lambda (&rest arguments)
(cl-incf inheritance-calls)
(apply
(ebox-layout-context-port-inline-inheritance-required-p default)
arguments))
:materialize-string
(lambda (&rest arguments)
(cl-incf materialize-calls)
(apply (ebox-layout-context-port-materialize-string default)
arguments)))))
(ebox-render
(ebox-test-box (ebox-test-text "Static") :width '(96))))
(should (= candidate-calls 1))
(should (= inheritance-calls 1))
(should (= materialize-calls 0))))
(ert-deftest ebox-layout-boundary-materialized-route-is-exactly-once ()
"Inherited layout invokes its context materializer exactly once."
(let ((candidate-calls 0)
(inheritance-calls 0)
(materialize-calls 0)
(default ebox--default-layout-context-port))
(let ((ebox--layout-context-port
(ebox-render-context-create-layout-port
:candidate-root
(lambda (&rest arguments)
(cl-incf candidate-calls)
(apply (ebox-layout-context-port-candidate-root default)
arguments))
:inline-inheritance-required-p
(lambda (&rest arguments)
(cl-incf inheritance-calls)
(apply
(ebox-layout-context-port-inline-inheritance-required-p default)
arguments))
:materialize-string
(lambda (&rest arguments)
(cl-incf materialize-calls)
(apply (ebox-layout-context-port-materialize-string default)
arguments)))))
(ebox-render
(ebox-test-box
:font-size 16
(ebox-test-box (ebox-test-text "Inherited")))))
(should (= candidate-calls 0))
;; Author-style pending is sufficient to choose the materialized route,
;; so the inherited-cascade predicate is correctly short-circuited here.
(should (= inheritance-calls 0))
(should (= materialize-calls 1))))
(ert-deftest ebox-layout-boundary-port-fault-leaves-source-unmodified ()
"A materialization-port fault cannot publish or consume source identity."
(let* ((input
(ebox-test-box
:font-size 16
(ebox-test-box (ebox-test-text "Fault"))))
(root (ebox-test-root input))
(source-index (ebox-test-source-index input))
(region-counter ebox--region-id-counter)
(node-counter ebox--runtime-node-id-counter)
(default ebox--default-layout-context-port)
(ebox--layout-context-port
(ebox-render-context-create-layout-port
:candidate-root
(ebox-layout-context-port-candidate-root default)
:inline-inheritance-required-p (lambda (&rest _arguments) t)
:materialize-string
(lambda (&rest _arguments)
(error "Injected E2 materialization fault")))))
(should-error (ebox-render input) :type 'error)
(should (eq (ebox-test-root input) root))
(should (eq (ebox-test-source-index input) source-index))
(should (= ebox--region-id-counter region-counter))
(should (= ebox--runtime-node-id-counter node-counter))
(should-not (plist-member root :node-id))
(should-not (plist-member root :region-id))
(should-not (plist-member root :surface-object))))
(provide 'ebox-layout-boundary-tests)
;;; ebox-layout-boundary-tests.el ends here