1 parent
beae94e932
commit
de4d70970c
51 files changed
+4034
-421
No files matched your search
Regular → Executable
+71
@@ -999,6 +999,18 @@ require(
|
||||
and 'savePreference("skinGradients"' in bindings_js,
|
||||
"style gradients have their own persisted Appearance switch",
|
||||
)
|
||||
gradient_css = read("src/web/css/59-skin-gradients.css")
|
||||
require(
|
||||
"59-skin-gradients.css" in css_manifest
|
||||
and css_manifest.index("58-skin-immersive.css") < css_manifest.index("59-skin-gradients.css") < css_manifest.index("60-responsive.css"),
|
||||
"style gradient layer loads after the immersive rules",
|
||||
)
|
||||
require(
|
||||
all(f"var(--grad-{layer})" in gradient_css for layer in ("backdrop", "appbar", "toolbar", "sidebar", "selected", "primary"))
|
||||
and ':root[data-skin-gradients="true"]:not([data-interface-skin="rustbox"])[data-theme] .appbar' in gradient_css
|
||||
and "data-skin-depth" not in gradient_css.split("/* Consumers", 1)[-1].split("{", 1)[0],
|
||||
"style gradients apply to every predefined style except RustBox at any style depth",
|
||||
)
|
||||
# Every gradient in the stylesheets must sit in a rule scoped to the switch.
|
||||
ungated_gradients = []
|
||||
for css_name in css_manifest:
|
||||
@@ -1010,6 +1022,65 @@ for css_name in css_manifest:
|
||||
if 'data-skin-gradients="true"' not in selector:
|
||||
ungated_gradients.append(f"{css_name}: {selector.strip()[:60]}")
|
||||
require(not ungated_gradients, "every stylesheet gradient is gated by the style-gradients switch" + (f" (ungated: {'; '.join(ungated_gradients[:5])})" if ungated_gradients else ""))
|
||||
for _, dialect in MIGRATION_DIALECTS:
|
||||
require(all(column in read(f"migrations/{dialect}/schema.sql") and column in read(f"src/queries/{dialect}/queries.rs") for column in ("theme_light_from", "theme_dark_from", "account_color")), f"{dialect} fresh schema and display query include the theme schedule and account colour")
|
||||
try:
|
||||
conn = sqlite3.connect(":memory:")
|
||||
conn.executescript("CREATE TABLE u_prod__display_preferences (id INTEGER PRIMARY KEY, theme TEXT NOT NULL DEFAULT 'system'); INSERT INTO u_prod__display_preferences(id) VALUES(1); CREATE TABLE u_prod__calendar_events (id TEXT PRIMARY KEY, reminder_minutes INTEGER); INSERT INTO u_prod__calendar_events(id, reminder_minutes) VALUES('e1', 15); CREATE TABLE u_prod__calendar_settings (id INTEGER PRIMARY KEY); INSERT INTO u_prod__calendar_settings(id) VALUES(1);")
|
||||
conn.executescript(read("migrations/sqlite/V054__theme_schedule_account_color_and_reminders.sql").replace("{{p}}", "u_prod__"))
|
||||
require(conn.execute("SELECT theme_light_from, theme_dark_from, account_color FROM u_prod__display_preferences WHERE id=1").fetchone() == ("07:00", "19:00", ""), "SQLite V054 adds the theme schedule and account colour with defaults")
|
||||
require(conn.execute("SELECT reminder_minutes, reminder_extra_minutes FROM u_prod__calendar_events WHERE id='e1'").fetchone() == (15, None), "SQLite V054 adds an optional second calendar reminder and keeps existing reminders")
|
||||
require(conn.execute("SELECT default_reminder_minutes, default_extra_reminder_minutes FROM u_prod__calendar_settings WHERE id=1").fetchone() == (None, None), "SQLite V054 adds empty default reminders for new events")
|
||||
conn.close()
|
||||
except Exception as exc:
|
||||
errors.append(f"SQLite V054 migration execution failed: {exc}")
|
||||
require(
|
||||
'"schedule"' in display_prefs_rs and 'value="schedule"' in index_html and "function scheduledTheme(" in prefs_js
|
||||
and 'id="pref-account-color"' in index_html and 'html[data-account-color="true"] .appbar::before' in read("src/web/css/50-settings.css"),
|
||||
"time-of-day theme and per-account colour are wired end to end",
|
||||
)
|
||||
for _, dialect in MIGRATION_DIALECTS:
|
||||
queries_text = read(f"src/queries/{dialect}/queries.rs")
|
||||
require(
|
||||
"reminder_extra_minutes" in read(f"migrations/{dialect}/schema.sql") and "reminder_extra_minutes" in queries_text
|
||||
and "default_extra_reminder_minutes" in queries_text,
|
||||
f"{dialect} schema and calendar queries include the second reminder and reminder defaults",
|
||||
)
|
||||
calendar_js = read("src/web/js/71-calendar.js")
|
||||
require(
|
||||
'id="calendar-reminder-extra"' in index_html and 'id="calendar-default-reminder"' in index_html
|
||||
and "reminder_extra_minutes: reminderSelectValue(" in calendar_js
|
||||
and "calendarReminderTrigger(event, minutes)" in read("src/web/js/80-settings-realtime.js"),
|
||||
"calendar events support a second reminder (e.g. one day before) with defaults for new events",
|
||||
)
|
||||
require("function updateContrastWarning(" in prefs_js and 'id="pref-contrast-warning"' in index_html, "custom colours show a live contrast warning")
|
||||
sieve_js = read("src/web/js/90-sieve.js")
|
||||
sieve_apply_js = read("src/web/js/91-sieve-apply.js")
|
||||
filters_rs = read("src/routes/filters.rs")
|
||||
require(
|
||||
'.route("/filters/match", post(filters::match_filter_handler))' in read("src/routes/mod.rs")
|
||||
and "async fn search_uids(" in read("src/imap/client.rs")
|
||||
and "async fn search_uids(" in read("src/imap/mock.rs")
|
||||
and all("pub mod db_filter_match" in read(f"src/queries/{d}/queries.rs") for d in ("sqlite", "mysql", "pgsql")),
|
||||
"filters: POST /filters/match is routed and backed by IMAP UID SEARCH on every client",
|
||||
)
|
||||
require(
|
||||
"fn bounds(" in filters_rs and "fn resolve_matches(" in filters_rs and "uncertain" in filters_rs and "#[cfg(test)]" in filters_rs,
|
||||
"filters: apply-now matching uses upper/lower IMAP bounds, decides the gap from the cache and reports uncertain messages",
|
||||
)
|
||||
require(
|
||||
"91-sieve-apply.js" in read("src/web/js/manifest.txt")
|
||||
and 'id="sieve-apply-check"' in index_html and 'id="sieve-apply-run"' in index_html
|
||||
and "function runParsedSieveRuleNow(" in sieve_apply_js and "function alwaysMoveFromSender(" in sieve_apply_js
|
||||
and "function ensureSieveTargetFolders(" in sieve_apply_js and 'id="sieve-templates"' in index_html,
|
||||
"filters: apply now, per-rule run now, templates, missing-folder creation and 'always move from this sender' are wired",
|
||||
)
|
||||
require(
|
||||
'id="sieve-builder-exceptions"' in index_html and "function splitSieveExceptions(" in sieve_js
|
||||
and all(f'"{kind}"' in sieve_js for kind in ("to-only", "cc-only", "size-over", "size-under", "has-attachment", "priority-high"))
|
||||
and '"label"' in sieve_js and '"trash"' in sieve_js,
|
||||
"filters: exceptions, new conditions (To/Cc only, size, attachment, priority) and label/trash actions round-trip through the editor",
|
||||
)
|
||||
mysql_text_literal_defaults = re.findall(r"^\s*(\w+)\s+TEXT(?:\s+NOT NULL)?\s+DEFAULT\s+'", read("migrations/mysql/schema.sql") + "\n" + "\n".join(read(f"migrations/mysql/{name}") for _, name in MIGRATIONS["mysql"]), re.M)
|
||||
require(not mysql_text_literal_defaults, "MySQL TEXT columns use expression defaults" + (f" (literal: {', '.join(mysql_text_literal_defaults)})" if mysql_text_literal_defaults else ""))
|
||||
|
||||
|
||||
Reference in new issue
Block a user