refactor: make semantic generation authoritative
This commit is contained in:
parent
d5ccb30125
commit
0cde865d3a
4
Makefile
4
Makefile
@ -1,8 +1,8 @@
|
||||
EMACS ?= emacs
|
||||
LOAD_PATH = -L . -L examples -L scripts -L ../ebox -L ../tp -L ../ecss
|
||||
SOURCES = etaf-view.el etaf-compiler.el etaf-component.el etaf-reactive.el etaf-observer.el etaf-context.el etaf-theme-tp.el etaf-resource.el etaf-data.el etaf-render-port.el etaf-renderer.el etaf-runtime.el etaf-behavior.el etaf-actions.el etaf-events.el etaf-performance.el etaf.el scripts/emacs-gui-verifier.el
|
||||
SOURCES = etaf-view.el etaf-compiler.el etaf-component.el etaf-reactive.el etaf-observer.el etaf-context.el etaf-theme-tp.el etaf-resource.el etaf-data.el etaf-generation.el etaf-render-port.el etaf-renderer.el etaf-runtime.el etaf-behavior.el etaf-actions.el etaf-events.el etaf-performance.el etaf.el scripts/emacs-gui-verifier.el
|
||||
EXAMPLES = examples/etaf-counter-example.el examples/etaf-data-example.el examples/etaf-resource-example.el
|
||||
TESTS = tests/etaf-tests.el tests/etaf-compiler-tests.el tests/etaf-component-frontends-tests.el tests/etaf-resource-tests.el tests/etaf-data-tests.el tests/etaf-theme-tp-tests.el tests/etaf-examples-tests.el tests/etaf-observer-tests.el tests/etaf-performance-tests.el tests/etaf-gui-verifier-tests.el tests/etaf-m0a-current-characterization-tests.el tests/etaf-interaction-contract-tests.el tests/etaf-m0b-component-manifest-tests.el tests/etaf-render-port-tests.el
|
||||
TESTS = tests/etaf-tests.el tests/etaf-compiler-tests.el tests/etaf-component-frontends-tests.el tests/etaf-resource-tests.el tests/etaf-data-tests.el tests/etaf-theme-tp-tests.el tests/etaf-examples-tests.el tests/etaf-observer-tests.el tests/etaf-performance-tests.el tests/etaf-gui-verifier-tests.el tests/etaf-m0a-current-characterization-tests.el tests/etaf-interaction-contract-tests.el tests/etaf-m0b-component-manifest-tests.el tests/etaf-render-port-tests.el tests/etaf-generation-tests.el
|
||||
|
||||
.PHONY: test compile load checkdoc docs-check check clean
|
||||
|
||||
|
||||
@ -450,6 +450,14 @@ through one outer reactive dispatch. A local owner evaluates into a candidate
|
||||
generation and Ebox logical replacement; disjoint owners are coalesced into
|
||||
one TP/Ebox publication. The Root owner is the only complete-root adapter.
|
||||
|
||||
The sole mutable pointer to the committed semantic generation belongs to
|
||||
`etaf-generation-authority`. Public handler and Host-property queries read that
|
||||
generation directly. Same-named Runtime hash tables are one-way compatibility
|
||||
mirrors rebuilt from the generation; they neither authorize queries nor write
|
||||
back into it. The migration-only `legacy`, `project`, and `shadow` routes prove
|
||||
projection equivalence and rollback safety without introducing a second
|
||||
committed truth.
|
||||
|
||||
Each Runtime flush records a candidate-aware effect tuple containing the
|
||||
generation id, effect-to-source edges and source versions, plus an immutable
|
||||
semantic-node stamp for candidate input/context/output facts. A repeated tuple
|
||||
|
||||
@ -440,6 +440,13 @@ mounted Component、expr、slot、fragment、raw、inline 和 Root owner 都经
|
||||
replacement;不相交 owner 会合并为一次 TP/Ebox publication。只有 Root owner
|
||||
可以进入 complete-root adapter。
|
||||
|
||||
已提交 semantic generation 的唯一 mutable pointer 由
|
||||
`etaf-generation-authority` 持有。handler 与 Host-prop 等公共查询直接读取该
|
||||
generation;Runtime 中同名 hash table 只是由 generation 单向重建的兼容 mirror,
|
||||
既不能独立授权查询,也不能反向改写 generation。迁移期的
|
||||
`legacy`/`project`/`shadow` 路由只用于证明投影等价与安全回退,不增加第二份
|
||||
committed truth。
|
||||
|
||||
每次 Runtime flush 都记录 candidate-aware effect tuple:其中包含 generation id、
|
||||
effect→source 边和 source version,以及 candidate input/context/output facts 的
|
||||
immutable semantic-node stamp。重复 tuple 会报告有序的 effect/edge path;step
|
||||
|
||||
89
etaf-generation.el
Normal file
89
etaf-generation.el
Normal file
@ -0,0 +1,89 @@
|
||||
;;; etaf-generation.el --- ETAF committed generation authority -*- lexical-binding: t; -*-
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Owns the single mutable pointer to ETAF's committed semantic generation and
|
||||
;; pure construction/comparison of compatibility mirrors. Runtime mirrors are
|
||||
;; projections only; they never authorize semantic queries or publication.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'subr-x)
|
||||
|
||||
(define-error 'etaf-generation-error "Invalid ETAF generation authority")
|
||||
|
||||
(cl-defstruct
|
||||
(etaf-generation-authority
|
||||
(:constructor etaf-generation-authority--create))
|
||||
"Mutable authority for one Runtime's committed generation."
|
||||
generation
|
||||
(token 0))
|
||||
|
||||
(defun etaf-generation-authority-create (&optional generation)
|
||||
"Return fresh authority initially pointing at GENERATION."
|
||||
(etaf-generation-authority--create :generation generation :token 0))
|
||||
|
||||
(defun etaf-generation-authority-current (authority)
|
||||
"Return AUTHORITY's current committed generation."
|
||||
(unless (etaf-generation-authority-p authority)
|
||||
(signal 'wrong-type-argument
|
||||
(list 'etaf-generation-authority-p authority)))
|
||||
(etaf-generation-authority-generation authority))
|
||||
|
||||
(defun etaf-generation-authority-set-current (authority generation)
|
||||
"Set AUTHORITY's current committed GENERATION and return GENERATION.
|
||||
This compatibility mutation does not advance the semantic commit token; the
|
||||
versioned compare-and-swap boundary owns token changes."
|
||||
(unless (etaf-generation-authority-p authority)
|
||||
(signal 'wrong-type-argument
|
||||
(list 'etaf-generation-authority-p authority)))
|
||||
(setf (etaf-generation-authority-generation authority) generation)
|
||||
generation)
|
||||
|
||||
(defun etaf-generation-project-mirror (entries &optional test)
|
||||
"Project immutable contribution ENTRIES into a fresh hash table.
|
||||
TEST defaults to `equal'. Duplicate keys are rejected so a compatibility
|
||||
mirror cannot silently choose a second semantic truth."
|
||||
(unless (proper-list-p entries)
|
||||
(signal 'wrong-type-argument (list 'proper-list-p entries)))
|
||||
(let ((table (make-hash-table :test (or test #'equal)))
|
||||
(missing (make-symbol "etaf-generation-mirror-missing")))
|
||||
(dolist (entry entries)
|
||||
(unless (consp entry)
|
||||
(signal 'etaf-generation-error
|
||||
(list :malformed-mirror-entry entry)))
|
||||
(let ((key (car entry)))
|
||||
(unless (eq (gethash key table missing) missing)
|
||||
(signal 'etaf-generation-error
|
||||
(list :duplicate-mirror-key key)))
|
||||
(puthash (copy-tree key) (copy-tree (cdr entry)) table)))
|
||||
table))
|
||||
|
||||
(defun etaf-generation-project-mirrors (handler-entries host-prop-entries)
|
||||
"Return fresh mirrors from HANDLER-ENTRIES and HOST-PROP-ENTRIES."
|
||||
(list :handlers
|
||||
(etaf-generation-project-mirror handler-entries #'equal)
|
||||
:host-props
|
||||
(etaf-generation-project-mirror host-prop-entries #'equal)))
|
||||
|
||||
(defun etaf-generation-mirror-equal-p (left right)
|
||||
"Return non-nil when hash tables LEFT and RIGHT contain equal facts."
|
||||
(and (hash-table-p left)
|
||||
(hash-table-p right)
|
||||
(= (hash-table-count left) (hash-table-count right))
|
||||
(let ((missing (make-symbol "etaf-generation-mirror-missing"))
|
||||
equal-p)
|
||||
(setq equal-p t)
|
||||
(maphash
|
||||
(lambda (key value)
|
||||
(unless (equal value (gethash key right missing))
|
||||
(setq equal-p nil)))
|
||||
left)
|
||||
equal-p)))
|
||||
|
||||
(provide 'etaf-generation)
|
||||
|
||||
;;; etaf-generation.el ends here
|
||||
121
etaf-runtime.el
121
etaf-runtime.el
@ -15,6 +15,7 @@
|
||||
(require 'etaf-view)
|
||||
(require 'etaf-component)
|
||||
(require 'etaf-reactive)
|
||||
(require 'etaf-generation)
|
||||
(require 'etaf-render-port)
|
||||
(require 'etaf-renderer)
|
||||
(require 'etaf-context)
|
||||
@ -284,7 +285,7 @@ the sequential `etaf--pvec-put' contract."
|
||||
next-resource-id
|
||||
next-effect-id
|
||||
next-semantic-id
|
||||
current-generation
|
||||
generation-authority
|
||||
artifact-registry
|
||||
candidate-artifacts
|
||||
candidate-effects
|
||||
@ -334,6 +335,33 @@ the sequential `etaf--pvec-put' contract."
|
||||
(event-depth 0)
|
||||
dirty-effect-queue-tail)
|
||||
|
||||
(defcustom etaf-generation-mirror-route 'project
|
||||
"Compatibility mirror route used after a committed generation changes.
|
||||
`legacy' preserves incremental Runtime table updates, `project' rebuilds exact
|
||||
mirrors from the committed generation, and `shadow' runs legacy updates before
|
||||
checking them against a fresh generation projection."
|
||||
:type '(choice (const legacy) (const project) (const shadow))
|
||||
:group 'etaf)
|
||||
|
||||
(defun etaf--runtime-generation-authority (runtime)
|
||||
"Return RUNTIME's generation authority, creating its empty owner if needed."
|
||||
(or (etaf-runtime-generation-authority runtime)
|
||||
(setf (etaf-runtime-generation-authority runtime)
|
||||
(etaf-generation-authority-create))))
|
||||
|
||||
(defun etaf-runtime-current-generation (runtime)
|
||||
"Return RUNTIME's uniquely authoritative committed generation."
|
||||
(etaf-generation-authority-current
|
||||
(etaf--runtime-generation-authority runtime)))
|
||||
|
||||
(defun etaf-runtime--set-current-generation (runtime generation)
|
||||
"Set RUNTIME's compatibility generation pointer to GENERATION."
|
||||
(etaf-generation-authority-set-current
|
||||
(etaf--runtime-generation-authority runtime) generation))
|
||||
|
||||
(gv-define-simple-setter etaf-runtime-current-generation
|
||||
etaf-runtime--set-current-generation)
|
||||
|
||||
(defun etaf--theme-paint-face-spec (property value)
|
||||
"Return PROPERTY's TP face spec for resolved paint VALUE, or nil."
|
||||
(pcase property
|
||||
@ -572,6 +600,81 @@ RESOLVED is the current projected paint value."
|
||||
(copy-tree (etaf--generation-index-entries
|
||||
(etaf-runtime-current-generation runtime) 'host-props)))
|
||||
|
||||
(defun etaf--runtime-generation-mirror-projection (generation)
|
||||
"Return exact compatibility mirrors projected from GENERATION."
|
||||
(etaf-generation-project-mirrors
|
||||
(etaf--generation-index-entries generation 'handlers)
|
||||
(etaf--generation-index-entries generation 'host-props)))
|
||||
|
||||
(defun etaf--runtime-install-legacy-generation-mirrors (runtime full-p)
|
||||
"Install RUNTIME candidate mirrors through the legacy FULL-P route."
|
||||
(if full-p
|
||||
(setf (etaf-runtime-handlers runtime)
|
||||
(etaf-runtime-candidate-handlers runtime)
|
||||
(etaf-runtime-host-props runtime)
|
||||
(etaf-runtime-candidate-host-props runtime))
|
||||
(unless (hash-table-p (etaf-runtime-handlers runtime))
|
||||
(setf (etaf-runtime-handlers runtime) (make-hash-table :test #'equal)))
|
||||
(unless (hash-table-p (etaf-runtime-host-props runtime))
|
||||
(setf (etaf-runtime-host-props runtime)
|
||||
(make-hash-table :test #'equal)))
|
||||
(maphash
|
||||
(lambda (host-ref handlers)
|
||||
(puthash host-ref handlers (etaf-runtime-handlers runtime)))
|
||||
(etaf-runtime-candidate-handlers runtime))
|
||||
(maphash
|
||||
(lambda (host-ref props)
|
||||
(puthash host-ref props (etaf-runtime-host-props runtime)))
|
||||
(etaf-runtime-candidate-host-props runtime))))
|
||||
|
||||
(defun etaf--runtime-install-projected-generation-mirrors
|
||||
(runtime projection)
|
||||
"Install detached generation mirror PROJECTION into RUNTIME."
|
||||
(setf (etaf-runtime-handlers runtime) (plist-get projection :handlers)
|
||||
(etaf-runtime-host-props runtime) (plist-get projection :host-props)))
|
||||
|
||||
(defun etaf-runtime-generation-mirrors-consistent-p (runtime)
|
||||
"Return non-nil when RUNTIME mirrors equal its committed generation."
|
||||
(let ((projection
|
||||
(etaf--runtime-generation-mirror-projection
|
||||
(etaf-runtime-current-generation runtime))))
|
||||
(and
|
||||
(etaf-generation-mirror-equal-p
|
||||
(or (etaf-runtime-handlers runtime) (make-hash-table :test #'equal))
|
||||
(plist-get projection :handlers))
|
||||
(etaf-generation-mirror-equal-p
|
||||
(or (etaf-runtime-host-props runtime) (make-hash-table :test #'equal))
|
||||
(plist-get projection :host-props)))))
|
||||
|
||||
(defun etaf--runtime-install-generation-mirrors
|
||||
(runtime generation full-p)
|
||||
"Install RUNTIME compatibility mirrors for committed GENERATION.
|
||||
FULL-P preserves the old route's full-root replacement distinction."
|
||||
(let ((projection (etaf--runtime-generation-mirror-projection generation)))
|
||||
(pcase etaf-generation-mirror-route
|
||||
('legacy
|
||||
(etaf--runtime-install-legacy-generation-mirrors runtime full-p))
|
||||
('project
|
||||
(etaf--runtime-install-projected-generation-mirrors runtime projection))
|
||||
('shadow
|
||||
(etaf--runtime-install-legacy-generation-mirrors runtime full-p)
|
||||
(unless (and
|
||||
(etaf-generation-mirror-equal-p
|
||||
(etaf-runtime-handlers runtime)
|
||||
(plist-get projection :handlers))
|
||||
(etaf-generation-mirror-equal-p
|
||||
(etaf-runtime-host-props runtime)
|
||||
(plist-get projection :host-props)))
|
||||
(signal 'etaf-generation-error
|
||||
(list :compatibility-mirror-drift
|
||||
:generation
|
||||
(and generation
|
||||
(etaf-generation-generation-id generation))))))
|
||||
(_
|
||||
(signal 'etaf-generation-error
|
||||
(list :unknown-mirror-route etaf-generation-mirror-route))))
|
||||
runtime))
|
||||
|
||||
(defun etaf--runtime-build-contribution-indexes (runtime base full-p)
|
||||
"Build RUNTIME immutable generation contributions over BASE.
|
||||
FULL-P means candidate tables describe the complete mounted tree."
|
||||
@ -5592,12 +5695,8 @@ RENDERED-IDENTITIES names the Component render participants."
|
||||
(etaf--runtime-clear-candidate runtime)
|
||||
(signal (car err) (cdr err))))
|
||||
(etaf--runtime-complete-generation runtime candidate-generation)
|
||||
(maphash (lambda (host-ref handlers)
|
||||
(puthash host-ref handlers (etaf-runtime-handlers runtime)))
|
||||
(etaf-runtime-candidate-handlers runtime))
|
||||
(maphash (lambda (host-ref props)
|
||||
(puthash host-ref props (etaf-runtime-host-props runtime)))
|
||||
(etaf-runtime-candidate-host-props runtime))
|
||||
(etaf--runtime-install-generation-mirrors
|
||||
runtime candidate-generation nil)
|
||||
(etaf--runtime-clear-dirty-effects runtime)
|
||||
(unwind-protect
|
||||
(progn
|
||||
@ -5670,11 +5769,9 @@ RENDERED-IDENTITIES names the Component render participants."
|
||||
(list :observer #'etaf--runtime-forward-ebox-report)))
|
||||
(etaf--runtime-participant-publish participant))
|
||||
(etaf--runtime-complete-generation runtime candidate-generation)
|
||||
(etaf--runtime-install-generation-mirrors
|
||||
runtime candidate-generation t)
|
||||
(setf (etaf-runtime-root-node runtime) root-node
|
||||
(etaf-runtime-handlers runtime)
|
||||
(etaf-runtime-candidate-handlers runtime)
|
||||
(etaf-runtime-host-props runtime)
|
||||
(etaf-runtime-candidate-host-props runtime)
|
||||
(etaf-runtime-root-dirty-p runtime) nil)
|
||||
(etaf--runtime-clear-dirty-effects runtime))
|
||||
((error quit)
|
||||
@ -5770,6 +5867,8 @@ backend anchor proof failed; ordinary root turns keep their artifact reuse."
|
||||
:next-resource-id 0
|
||||
:next-effect-id 0
|
||||
:next-semantic-id 1
|
||||
:generation-authority
|
||||
(etaf-generation-authority-create)
|
||||
:root-effect-id 0
|
||||
:root-range-id 1
|
||||
:artifact-registry (make-hash-table :test #'equal)
|
||||
|
||||
1
etaf.el
1
etaf.el
@ -35,6 +35,7 @@
|
||||
(require 'etaf-context)
|
||||
(require 'etaf-resource)
|
||||
(require 'etaf-data)
|
||||
(require 'etaf-generation)
|
||||
(require 'etaf-render-port)
|
||||
(require 'etaf-renderer)
|
||||
(etaf--prefer-local-files)
|
||||
|
||||
127
tests/etaf-generation-tests.el
Normal file
127
tests/etaf-generation-tests.el
Normal file
@ -0,0 +1,127 @@
|
||||
;;; etaf-generation-tests.el --- M3a generation authority gates -*- lexical-binding: t; -*-
|
||||
|
||||
;; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
(require 'ert)
|
||||
(require 'etaf)
|
||||
(require 'etaf-generation)
|
||||
|
||||
(defun etaf-generation-test--view (visible)
|
||||
"Return a root View selected by reactive VISIBLE."
|
||||
(if (etaf-value visible)
|
||||
(etaf-view
|
||||
(text :ref 'generation-target :role 'button
|
||||
:on-press #'ignore "visible"))
|
||||
(etaf-view (text :ref 'generation-other "other"))))
|
||||
|
||||
(ert-deftest etaf-generation-authority-is-runtime-single-source ()
|
||||
"Runtime compatibility access reads and writes one authority object."
|
||||
(let* ((runtime (etaf--runtime-create))
|
||||
(first (etaf--generation-create :generation-id 1))
|
||||
(second (etaf--generation-create :generation-id 2)))
|
||||
(should-not (etaf-runtime-current-generation runtime))
|
||||
(setf (etaf-runtime-current-generation runtime) first)
|
||||
(let ((authority (etaf-runtime-generation-authority runtime)))
|
||||
(should (etaf-generation-authority-p authority))
|
||||
(should (eq first (etaf-generation-authority-current authority)))
|
||||
(should (eq first (etaf-runtime-current-generation runtime)))
|
||||
(setf (etaf-runtime-current-generation runtime) second)
|
||||
(should (eq authority (etaf-runtime-generation-authority runtime)))
|
||||
(should (eq second (etaf-runtime-current-generation runtime)))
|
||||
(should (zerop (etaf-generation-authority-token authority))))))
|
||||
|
||||
(ert-deftest etaf-generation-projection-is-detached-and-rejects-duplicates ()
|
||||
"Compatibility projections copy facts and reject ambiguous keys."
|
||||
(let* ((handlers '((host . ((press . callback)))))
|
||||
(projection
|
||||
(etaf-generation-project-mirrors handlers '((host :role button))))
|
||||
(handler-table (plist-get projection :handlers))
|
||||
(props-table (plist-get projection :host-props)))
|
||||
(setcdr (car handlers) 'mutated)
|
||||
(should (equal (gethash 'host handler-table) '((press . callback))))
|
||||
(should (equal (gethash 'host props-table) '(:role button)))
|
||||
(should-error
|
||||
(etaf-generation-project-mirror '((host . one) (host . two)))
|
||||
:type 'etaf-generation-error)))
|
||||
|
||||
(ert-deftest etaf-generation-mirrors-follow-committed-generation ()
|
||||
"Every commit projects exact mirrors and removes stale Host facts."
|
||||
(let ((buffer-name " *etaf-generation-mirror-test*")
|
||||
(visible (etaf-ref t)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(etaf-mount buffer-name
|
||||
(lambda () (etaf-generation-test--view visible)))
|
||||
(let ((runtime (etaf-runtime-for-buffer buffer-name)))
|
||||
(should (etaf-runtime-generation-mirrors-consistent-p runtime))
|
||||
(should (etaf-runtime-handler-for runtime 'generation-target))
|
||||
(should (gethash 'generation-target
|
||||
(etaf-runtime-handlers runtime)))
|
||||
(setf (etaf-value visible) nil)
|
||||
(should (etaf-runtime-generation-mirrors-consistent-p runtime))
|
||||
(should-not (etaf-runtime-handler-for runtime 'generation-target))
|
||||
(should-not (gethash 'generation-target
|
||||
(etaf-runtime-handlers runtime)))
|
||||
(should (gethash 'generation-other
|
||||
(etaf-runtime-host-props runtime)))))
|
||||
(when-let* ((runtime (etaf-runtime-for-buffer buffer-name)))
|
||||
(etaf-unmount runtime))
|
||||
(when-let* ((buffer (get-buffer buffer-name)))
|
||||
(kill-buffer buffer)))))
|
||||
|
||||
(ert-deftest etaf-generation-query-ignores-compatibility-mirror-drift ()
|
||||
"Corrupting a mirror never changes committed generation queries."
|
||||
(let ((buffer-name " *etaf-generation-query-test*")
|
||||
(visible (etaf-ref t)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(etaf-mount buffer-name
|
||||
(lambda () (etaf-generation-test--view visible)))
|
||||
(let* ((runtime (etaf-runtime-for-buffer buffer-name))
|
||||
(committed
|
||||
(copy-tree
|
||||
(etaf-runtime-handler-for runtime 'generation-target))))
|
||||
(puthash 'generation-target 'corrupt
|
||||
(etaf-runtime-handlers runtime))
|
||||
(should-not (etaf-runtime-generation-mirrors-consistent-p runtime))
|
||||
(should (equal committed
|
||||
(etaf-runtime-handler-for
|
||||
runtime 'generation-target)))
|
||||
(setf (etaf-value visible) nil)
|
||||
(setf (etaf-value visible) t)
|
||||
(should (etaf-runtime-generation-mirrors-consistent-p runtime))))
|
||||
(when-let* ((runtime (etaf-runtime-for-buffer buffer-name)))
|
||||
(etaf-unmount runtime))
|
||||
(when-let* ((buffer (get-buffer buffer-name)))
|
||||
(kill-buffer buffer)))))
|
||||
|
||||
(ert-deftest etaf-generation-shadow-route-proves-legacy-equivalence ()
|
||||
"The shadow route accepts a legacy projection only when facts are equal."
|
||||
(let ((buffer-name " *etaf-generation-shadow-test*")
|
||||
(visible (etaf-ref t))
|
||||
(etaf-generation-mirror-route 'shadow))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(etaf-mount buffer-name
|
||||
(lambda () (etaf-generation-test--view visible)))
|
||||
(setf (etaf-value visible) nil)
|
||||
(let ((runtime (etaf-runtime-for-buffer buffer-name)))
|
||||
(should (etaf-runtime-generation-mirrors-consistent-p runtime))))
|
||||
(when-let* ((runtime (etaf-runtime-for-buffer buffer-name)))
|
||||
(etaf-unmount runtime))
|
||||
(when-let* ((buffer (get-buffer buffer-name)))
|
||||
(kill-buffer buffer)))))
|
||||
|
||||
(ert-deftest etaf-generation-rejects-unknown-mirror-route ()
|
||||
"An unknown compatibility route cannot silently publish mirrors."
|
||||
(let ((runtime (etaf--runtime-create
|
||||
:generation-authority
|
||||
(etaf-generation-authority-create)))
|
||||
(etaf-generation-mirror-route 'unknown))
|
||||
(should-error
|
||||
(etaf--runtime-install-generation-mirrors runtime nil t)
|
||||
:type 'etaf-generation-error)))
|
||||
|
||||
(provide 'etaf-generation-tests)
|
||||
|
||||
;;; etaf-generation-tests.el ends here
|
||||
Loading…
Reference in New Issue
Block a user