Add <base href> support with resolve_base_url() wired before all resource loading, document.baseURI JS API (falling back to "about:blank" per spec), image format verification golden tests (PNG/JPEG/GIF/WebP/SVG for both <img> and CSS background-image), and aspect ratio preservation tests. Code review fixes: baseURI spec compliance, restyle path no longer overwrites <base href> URL, added CSS background-image format tests and base URL integration tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1786 lines
42 KiB
Rust
1786 lines
42 KiB
Rust
//! Golden tests for the rendering pipeline.
|
|
//!
|
|
//! These tests compare the output of the rendering pipeline against
|
|
//! expected "golden" files. If the output differs, the test fails.
|
|
//!
|
|
//! To update golden files when intentionally changing output:
|
|
//! ```
|
|
//! for f in tests/goldens/fixtures/*.html; do
|
|
//! cargo run -p app_browser -- --render "$f" --output-dir tests/goldens/expected
|
|
//! done
|
|
//! ```
|
|
|
|
use std::fs;
|
|
use std::path::{Path, PathBuf};
|
|
|
|
// Re-export pipeline for tests
|
|
mod pipeline_test {
|
|
use display_list::build_display_list;
|
|
use html::HtmlParser;
|
|
use image::{ImagePipeline, ImageStore};
|
|
use layout::LayoutEngine;
|
|
use std::collections::HashMap;
|
|
use std::path::Path;
|
|
use style::{BackgroundImage, Display, StyleContext};
|
|
|
|
pub fn run_pipeline(html: &str) -> (String, String) {
|
|
let html_parser = HtmlParser::new();
|
|
let style_context = StyleContext::new();
|
|
let layout_engine = LayoutEngine::new_proportional();
|
|
|
|
let document = html_parser.parse(html);
|
|
// Include UA stylesheet first (lowest priority), then author stylesheets
|
|
let stylesheets = style_context.extract_stylesheets(&document);
|
|
let inline_styles = style_context.extract_inline_styles(&document);
|
|
let computed_styles = style_context.compute_styles(
|
|
&document,
|
|
&stylesheets,
|
|
&inline_styles,
|
|
Some(&css::Viewport::new(800.0, 600.0)),
|
|
);
|
|
|
|
let layout_tree = layout_engine.layout(&document, &computed_styles, 800.0, 600.0);
|
|
let display_list = build_display_list(&layout_tree);
|
|
|
|
(layout_tree.dump(), display_list.dump())
|
|
}
|
|
|
|
/// Run the pipeline with image loading from a fixture directory.
|
|
/// Resolves `<img src="...">` and `<object data="...">` paths relative to `fixture_dir`.
|
|
/// `data:` URIs are loaded via the network stack.
|
|
pub fn run_pipeline_with_images(html: &str, fixture_dir: &Path) -> (String, String) {
|
|
let html_parser = HtmlParser::new();
|
|
let style_context = StyleContext::new();
|
|
let layout_engine = LayoutEngine::new_proportional();
|
|
let image_pipeline = ImagePipeline::new();
|
|
|
|
let document = html_parser.parse(html);
|
|
let stylesheets = style_context.extract_stylesheets(&document);
|
|
let inline_styles = style_context.extract_inline_styles(&document);
|
|
let computed_styles = style_context.compute_styles(
|
|
&document,
|
|
&stylesheets,
|
|
&inline_styles,
|
|
Some(&css::Viewport::new(800.0, 600.0)),
|
|
);
|
|
|
|
// Load images from <img> elements
|
|
let mut image_store = ImageStore::new();
|
|
let mut image_map = HashMap::new();
|
|
|
|
for node_id in document.get_elements_by_tag_name("img") {
|
|
// Skip display:none elements
|
|
if let Some(styles) = computed_styles.get(&node_id) {
|
|
if styles.display == Display::None {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if let Some(src) = document.get_attribute(node_id, "src") {
|
|
let image_path = fixture_dir.join(src);
|
|
if let Ok(bytes) = std::fs::read(&image_path) {
|
|
if let Ok(decoded) = image_pipeline.decode(&bytes, None) {
|
|
let img_id = image_store.insert(decoded);
|
|
image_map.insert(node_id, img_id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Load images from <object> elements' data attributes
|
|
let network = net::NetworkStack::new();
|
|
for node_id in document.get_elements_by_tag_name("object") {
|
|
if let Some(styles) = computed_styles.get(&node_id) {
|
|
if styles.display == Display::None {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if let Some(data) = document.get_attribute(node_id, "data") {
|
|
let bytes_and_mime = if data.starts_with("data:") {
|
|
// data: URIs — use network stack
|
|
shared::BrowserUrl::parse(data)
|
|
.ok()
|
|
.and_then(|url| network.load_sync(&url).ok())
|
|
.filter(|resp| resp.is_success())
|
|
.map(|resp| (resp.body, Some(resp.content_type.mime_type())))
|
|
} else {
|
|
// File path — read from fixture directory
|
|
let image_path = fixture_dir.join(data);
|
|
std::fs::read(&image_path).ok().map(|b| (b, None))
|
|
};
|
|
|
|
if let Some((bytes, mime)) = bytes_and_mime {
|
|
// Skip non-image MIME types — fall through to child fallback
|
|
if let Some(ref m) = mime {
|
|
if !m.starts_with("image/") && m != "application/octet-stream" {
|
|
continue;
|
|
}
|
|
}
|
|
if let Ok(decoded) = image_pipeline.decode(&bytes, mime.as_deref()) {
|
|
let img_id = image_store.insert(decoded);
|
|
image_map.insert(node_id, img_id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Load images from CSS background-image: url(...) properties.
|
|
// Iterate in document order (not HashMap order) for deterministic image IDs.
|
|
for node_id in document.iter_elements() {
|
|
if let Some(styles) = computed_styles.get(&node_id) {
|
|
if let BackgroundImage::Url(ref url) = styles.background_image {
|
|
// Skip if already loaded (multiple elements may share the same URL)
|
|
if image_store.get_by_url(url).is_some() {
|
|
continue;
|
|
}
|
|
let image_path = fixture_dir.join(url);
|
|
if let Ok(bytes) = std::fs::read(&image_path) {
|
|
if let Ok(decoded) = image_pipeline.decode(&bytes, None) {
|
|
image_store.insert_url(url, decoded);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let layout_tree = layout_engine.layout_with_images(
|
|
&document,
|
|
&computed_styles,
|
|
800.0,
|
|
600.0,
|
|
&image_map,
|
|
&image_store,
|
|
);
|
|
let display_list = build_display_list(&layout_tree);
|
|
|
|
(layout_tree.dump(), display_list.dump())
|
|
}
|
|
|
|
/// Run the pipeline with iframe support using `app_browser::Pipeline`.
|
|
///
|
|
/// Unlike `run_pipeline`, this uses the full `Pipeline::run_with_url()` path
|
|
/// which calls `fetch_and_render_iframes()`, so `<iframe srcdoc="...">` content
|
|
/// is actually parsed, styled, laid out, and rendered into the display list.
|
|
pub fn run_pipeline_with_iframes(html: &str, fixture_dir: &Path) -> (String, String) {
|
|
let base_url =
|
|
shared::BrowserUrl::parse(&format!("file://{}/_", fixture_dir.to_str().unwrap()))
|
|
.unwrap();
|
|
let network = net::NetworkStack::new();
|
|
let mut pipeline = app_browser::Pipeline::new(800.0, 600.0);
|
|
let result = pipeline.run_with_url(html, &base_url, &network).unwrap();
|
|
(result.layout_dump, result.display_list_dump)
|
|
}
|
|
}
|
|
|
|
fn get_goldens_dir() -> PathBuf {
|
|
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/goldens")
|
|
}
|
|
|
|
fn compare_golden_outputs(
|
|
fixture_name: &str,
|
|
actual_layout: &str,
|
|
actual_dl: &str,
|
|
expected_dir: &Path,
|
|
) {
|
|
let expected_layout_path = expected_dir.join(format!("{}.layout.txt", fixture_name));
|
|
let expected_dl_path = expected_dir.join(format!("{}.dl.txt", fixture_name));
|
|
|
|
let expected_layout = fs::read_to_string(&expected_layout_path)
|
|
.unwrap_or_else(|e| panic!("Failed to read {}: {}", expected_layout_path.display(), e));
|
|
let expected_dl = fs::read_to_string(&expected_dl_path)
|
|
.unwrap_or_else(|e| panic!("Failed to read {}: {}", expected_dl_path.display(), e));
|
|
|
|
// Auto-update mode: set UPDATE_GOLDENS=1 to write actual outputs as new expected
|
|
if std::env::var("UPDATE_GOLDENS").is_ok()
|
|
&& (actual_layout != expected_layout || actual_dl != expected_dl)
|
|
{
|
|
fs::write(&expected_layout_path, actual_layout).unwrap();
|
|
fs::write(&expected_dl_path, actual_dl).unwrap();
|
|
eprintln!("Updated golden files for {}", fixture_name);
|
|
return;
|
|
}
|
|
|
|
if actual_layout != expected_layout {
|
|
panic!(
|
|
"Layout mismatch for {}!\n\
|
|
=== Expected ===\n{}\n\
|
|
=== Actual ===\n{}\n",
|
|
fixture_name, expected_layout, actual_layout
|
|
);
|
|
}
|
|
|
|
if actual_dl != expected_dl {
|
|
panic!(
|
|
"Display list mismatch for {}!\n\
|
|
=== Expected ===\n{}\n\
|
|
=== Actual ===\n{}\n",
|
|
fixture_name, expected_dl, actual_dl
|
|
);
|
|
}
|
|
}
|
|
|
|
fn run_golden_test(fixture_name: &str) {
|
|
let goldens_dir = get_goldens_dir();
|
|
let fixtures_dir = goldens_dir.join("fixtures");
|
|
let expected_dir = goldens_dir.join("expected");
|
|
|
|
let html_path = fixtures_dir.join(format!("{}.html", fixture_name));
|
|
let html = fs::read_to_string(&html_path)
|
|
.unwrap_or_else(|e| panic!("Failed to read {}: {}", html_path.display(), e));
|
|
|
|
let (actual_layout, actual_dl) = pipeline_test::run_pipeline(&html);
|
|
compare_golden_outputs(fixture_name, &actual_layout, &actual_dl, &expected_dir);
|
|
}
|
|
|
|
fn run_golden_test_with_images(fixture_name: &str) {
|
|
let goldens_dir = get_goldens_dir();
|
|
let fixtures_dir = goldens_dir.join("fixtures");
|
|
let expected_dir = goldens_dir.join("expected");
|
|
|
|
let html_path = fixtures_dir.join(format!("{}.html", fixture_name));
|
|
let html = fs::read_to_string(&html_path)
|
|
.unwrap_or_else(|e| panic!("Failed to read {}: {}", html_path.display(), e));
|
|
|
|
let (actual_layout, actual_dl) = pipeline_test::run_pipeline_with_images(&html, &fixtures_dir);
|
|
compare_golden_outputs(fixture_name, &actual_layout, &actual_dl, &expected_dir);
|
|
}
|
|
|
|
fn run_golden_test_with_iframes(fixture_name: &str) {
|
|
let goldens_dir = get_goldens_dir();
|
|
let fixtures_dir = goldens_dir.join("fixtures");
|
|
let expected_dir = goldens_dir.join("expected");
|
|
|
|
let html_path = fixtures_dir.join(format!("{}.html", fixture_name));
|
|
let html = fs::read_to_string(&html_path)
|
|
.unwrap_or_else(|e| panic!("Failed to read {}: {}", html_path.display(), e));
|
|
|
|
let (actual_layout, actual_dl) = pipeline_test::run_pipeline_with_iframes(&html, &fixtures_dir);
|
|
compare_golden_outputs(fixture_name, &actual_layout, &actual_dl, &expected_dir);
|
|
}
|
|
|
|
#[test]
|
|
fn golden_001_empty() {
|
|
run_golden_test("001-empty");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_002_single_div() {
|
|
run_golden_test("002-single-div");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_003_nested_divs() {
|
|
run_golden_test("003-nested-divs");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_004_text_content() {
|
|
run_golden_test("004-text-content");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_005_inline_style() {
|
|
run_golden_test("005-inline-style");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_006_style_tag() {
|
|
run_golden_test("006-style-tag");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_007_class_selector() {
|
|
run_golden_test("007-class-selector");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_008_id_selector() {
|
|
run_golden_test("008-id-selector");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_009_margin_padding() {
|
|
run_golden_test("009-margin-padding");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_010_block_layout() {
|
|
run_golden_test("010-block-layout");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_011_width_height() {
|
|
run_golden_test("011-width-height");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_012_background_color() {
|
|
run_golden_test("012-background-color");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_013_border_color() {
|
|
run_golden_test("013-border-color");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_014_border_style_none() {
|
|
run_golden_test("014-border-style-none");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_015_border_shorthand() {
|
|
run_golden_test("015-border-shorthand");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_016_border_per_side() {
|
|
run_golden_test("016-border-per-side");
|
|
}
|
|
|
|
// Phase 1B: Inline Layout Tests
|
|
|
|
#[test]
|
|
fn golden_017_inline_span() {
|
|
run_golden_test("017-inline-span");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_018_multiple_inline() {
|
|
run_golden_test("018-multiple-inline");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_019_text_wrapping() {
|
|
run_golden_test("019-text-wrapping");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_020_mixed_content() {
|
|
run_golden_test("020-mixed-content");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_021_nested_inline() {
|
|
run_golden_test("021-nested-inline");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_022_inline_background_border() {
|
|
run_golden_test("022-inline-background-border");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_023_nested_inline_styles() {
|
|
run_golden_test("023-nested-inline-styles");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_024_inline_border_wrap() {
|
|
run_golden_test("024-inline-border-wrap");
|
|
}
|
|
|
|
// Phase 1D: Golden Test Expansion (Edge Cases)
|
|
|
|
#[test]
|
|
fn golden_025_empty_inline() {
|
|
run_golden_test("025-empty-inline");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_026_whitespace_only_inline() {
|
|
run_golden_test("026-whitespace-only-inline");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_027_unbreakable_long_word() {
|
|
run_golden_test("027-unbreakable-long-word");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_028_inline_at_block_start() {
|
|
run_golden_test("028-inline-at-block-start");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_029_inline_at_block_end() {
|
|
run_golden_test("029-inline-at-block-end");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_030_adjacent_inline_no_space() {
|
|
run_golden_test("030-adjacent-inline-no-space");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_031_different_border_widths() {
|
|
run_golden_test("031-different-border-widths");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_032_full_box_model() {
|
|
run_golden_test("032-full-box-model");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_033_zero_width_border() {
|
|
run_golden_test("033-zero-width-border");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_034_deeply_nested_inline() {
|
|
run_golden_test("034-deeply-nested-inline");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_035_multiple_blocks_interrupting() {
|
|
run_golden_test("035-multiple-blocks-interrupting");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_036_empty_nested_inline() {
|
|
run_golden_test("036-empty-nested-inline");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_037_entities() {
|
|
run_golden_test("037-entities");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_038_inline_link() {
|
|
run_golden_test("038-inline-link");
|
|
}
|
|
|
|
// Phase 2: Navigation Milestone Tests
|
|
|
|
#[test]
|
|
fn golden_039_anchor_link() {
|
|
run_golden_test("039-anchor-link");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_040_multiple_anchors() {
|
|
run_golden_test("040-multiple-anchors");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_041_anchor_with_style() {
|
|
run_golden_test("041-anchor-with-style");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_042_nested_anchor() {
|
|
run_golden_test("042-nested-anchor");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_043_heading_levels() {
|
|
run_golden_test("043-heading-levels");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_044_paragraph_text() {
|
|
run_golden_test("044-paragraph-text");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_045_mixed_headings_para() {
|
|
run_golden_test("045-mixed-headings-para");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_046_list_like_divs() {
|
|
run_golden_test("046-list-like-divs");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_047_wide_content() {
|
|
run_golden_test("047-wide-content");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_048_tall_content() {
|
|
run_golden_test("048-tall-content");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_049_test2() {
|
|
run_golden_test("049-css-width-percentage");
|
|
}
|
|
|
|
// Milestone 3: Expand CSS for Real Pages - Phase 1: Selector Validation
|
|
|
|
#[test]
|
|
fn golden_050_descendant_deep() {
|
|
run_golden_test("050-descendant-deep");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_051_child_vs_descendant() {
|
|
run_golden_test("051-child-vs-descendant");
|
|
}
|
|
|
|
// Milestone 3: Phase 2 - Position Relative/Absolute
|
|
|
|
#[test]
|
|
fn golden_052_position_relative() {
|
|
run_golden_test("052-position-relative");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_053_position_relative_offset() {
|
|
run_golden_test("053-position-relative-offset");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_054_position_absolute() {
|
|
run_golden_test("054-position-absolute");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_055_absolute_in_relative() {
|
|
run_golden_test("055-absolute-in-relative");
|
|
}
|
|
|
|
// Milestone 3: Phase 3 - Stacking Contexts & Z-Index
|
|
|
|
#[test]
|
|
fn golden_056_z_index_basic() {
|
|
run_golden_test("056-z-index-basic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_057_z_index_negative() {
|
|
run_golden_test("057-z-index-negative");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_058_stacking_context() {
|
|
run_golden_test("058-stacking-context");
|
|
}
|
|
|
|
// Milestone 3: Phase 4 - Overflow & Clipping
|
|
|
|
#[test]
|
|
fn golden_059_overflow_hidden() {
|
|
run_golden_test("059-overflow-hidden");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_060_overflow_nested() {
|
|
run_golden_test("060-overflow-nested");
|
|
}
|
|
|
|
// Milestone 3: Phase 5 - Flexbox Layout
|
|
|
|
#[test]
|
|
fn golden_061_flex_row() {
|
|
run_golden_test("061-flex-row");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_062_flex_column() {
|
|
run_golden_test("062-flex-column");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_063_flex_justify() {
|
|
run_golden_test("063-flex-justify");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_064_flex_align() {
|
|
run_golden_test("064-flex-align");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_065_flex_grow() {
|
|
run_golden_test("065-flex-grow");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_066_flex_gap() {
|
|
run_golden_test("066-flex-gap");
|
|
}
|
|
|
|
// Phase 3: white-space property and <pre> tag support
|
|
|
|
#[test]
|
|
fn golden_067_pre_basic() {
|
|
run_golden_test("067-pre-basic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_068_pre_whitespace() {
|
|
run_golden_test("068-pre-whitespace");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_069_white_space_pre_css() {
|
|
run_golden_test("069-white-space-pre-css");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_070_white_space_nowrap() {
|
|
run_golden_test("070-white-space-nowrap");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_071_white_space_pre_wrap() {
|
|
run_golden_test("071-white-space-pre-wrap");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_072_white_space_pre_line() {
|
|
run_golden_test("072-white-space-pre-line");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_073_pre_tabs() {
|
|
run_golden_test("073-pre-tabs");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_074_pre_empty() {
|
|
run_golden_test("074-pre-empty");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_075_pre_nested_inline() {
|
|
run_golden_test("075-pre-nested-inline");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_076_pre_override_css() {
|
|
run_golden_test("076-pre-override-css");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_077_pre_multiple_newlines() {
|
|
run_golden_test("077-pre-multiple-newlines");
|
|
}
|
|
|
|
// Phase: Table Layout Support
|
|
|
|
#[test]
|
|
fn golden_078_table_basic() {
|
|
run_golden_test("078-table-basic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_079_table_headers() {
|
|
run_golden_test("079-table-headers");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_080_table_sections() {
|
|
run_golden_test("080-table-sections");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_081_table_colspan() {
|
|
run_golden_test("081-table-colspan");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_082_table_rowspan() {
|
|
run_golden_test("082-table-rowspan");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_083_table_mixed_spans() {
|
|
run_golden_test("083-table-mixed-spans");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_084_table_column_widths() {
|
|
run_golden_test("084-table-column-widths");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_085_table_cell_padding() {
|
|
run_golden_test("085-table-cell-padding");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_086_table_backgrounds() {
|
|
run_golden_test("086-table-backgrounds");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_087_table_width() {
|
|
run_golden_test("087-table-width");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_088_table_nested() {
|
|
run_golden_test("088-table-nested");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_089_table_text_wrap() {
|
|
run_golden_test("089-table-text-wrap");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_090_table_empty_cells() {
|
|
run_golden_test("090-table-empty-cells");
|
|
}
|
|
|
|
// XML/XHTML compatibility
|
|
|
|
#[test]
|
|
fn golden_091_xml_processing_instructions() {
|
|
run_golden_test("091-xml-processing-instructions");
|
|
}
|
|
|
|
// HTML parsing edge cases
|
|
|
|
#[test]
|
|
fn golden_092_unquoted_attr_with_slash() {
|
|
run_golden_test("092-unquoted-attr-with-slash");
|
|
}
|
|
|
|
// Border styles: dashed, dotted, CSS variables
|
|
|
|
#[test]
|
|
fn golden_093_dashed_borders() {
|
|
run_golden_test("093-dashed-borders");
|
|
}
|
|
|
|
// Table cell vertical-align
|
|
|
|
#[test]
|
|
fn golden_094_table_vertical_align() {
|
|
run_golden_test("094-table-vertical-align");
|
|
}
|
|
|
|
// CSS Feature Expansion: min/max dimensions, position: fixed, inline-block
|
|
|
|
#[test]
|
|
fn golden_095_max_width() {
|
|
run_golden_test("095-max-width");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_096_min_height() {
|
|
run_golden_test("096-min-height");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_097_position_fixed() {
|
|
run_golden_test("097-position-fixed");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_098_inline_block_basic() {
|
|
run_golden_test("098-inline-block-basic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_099_min_max_width_conflict() {
|
|
run_golden_test("099-min-max-width-conflict");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_100_fixed_nested() {
|
|
run_golden_test("100-fixed-nested");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_101_inline_block_wrapping() {
|
|
run_golden_test("101-inline-block-wrapping");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_102_inline_block_padding_margin() {
|
|
run_golden_test("102-inline-block-padding-margin");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_103_max_width_percentage() {
|
|
run_golden_test("103-max-width-percentage");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_104_fixed_with_scroll() {
|
|
run_golden_test("104-fixed-with-scroll");
|
|
}
|
|
|
|
// CSS Float Layout
|
|
|
|
#[test]
|
|
fn golden_105_float_left_basic() {
|
|
run_golden_test("105-float-left-basic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_106_float_right_basic() {
|
|
run_golden_test("106-float-right-basic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_107_float_multiple_left() {
|
|
run_golden_test("107-float-multiple-left");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_108_float_clear_left() {
|
|
run_golden_test("108-float-clear-left");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_109_float_clear_both() {
|
|
run_golden_test("109-float-clear-both");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_110_float_overflow_contain() {
|
|
run_golden_test("110-float-overflow-contain");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_111_float_no_parent_expand() {
|
|
run_golden_test("111-float-no-parent-expand");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_112_float_inline_wrap() {
|
|
run_golden_test("112-float-inline-wrap");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_113_float_drop_below() {
|
|
run_golden_test("113-float-drop-below");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_114_float_with_margin() {
|
|
run_golden_test("114-float-with-margin");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_115_float_with_padding_border() {
|
|
run_golden_test("115-float-with-padding-border");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_116_float_percentage_width() {
|
|
run_golden_test("116-float-percentage-width");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_117_float_next_to_inline_block() {
|
|
run_golden_test("117-float-next-to-inline-block");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_118_float_with_clear_on_float() {
|
|
run_golden_test("118-float-with-clear-on-float");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_119_float_empty() {
|
|
run_golden_test("119-float-empty");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_120_float_mixed_left_right() {
|
|
run_golden_test("120-float-mixed-left-right");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_121_float_nested_bfc() {
|
|
run_golden_test("121-float-nested-bfc");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_122_float_with_text_content() {
|
|
run_golden_test("122-float-with-text-content");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_123_float_stacking_multiple_heights() {
|
|
run_golden_test("123-float-stacking-multiple-heights");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_124_float_clear_right() {
|
|
run_golden_test("124-float-clear-right");
|
|
}
|
|
|
|
// Milestone 4: Image Support
|
|
|
|
#[test]
|
|
fn golden_125_img_basic() {
|
|
run_golden_test_with_images("125-img-basic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_126_img_width_attr() {
|
|
run_golden_test_with_images("126-img-width-attr");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_127_img_height_attr() {
|
|
run_golden_test_with_images("127-img-height-attr");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_128_img_both_attrs() {
|
|
run_golden_test_with_images("128-img-both-attrs");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_129_img_css_width() {
|
|
run_golden_test_with_images("129-img-css-width");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_130_img_css_both() {
|
|
run_golden_test_with_images("130-img-css-both");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_131_img_in_div() {
|
|
run_golden_test_with_images("131-img-in-div");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_132_img_inline() {
|
|
run_golden_test_with_images("132-img-inline");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_133_img_missing_src() {
|
|
run_golden_test_with_images("133-img-missing-src");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_134_img_broken_src() {
|
|
run_golden_test_with_images("134-img-broken-src");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_135_img_with_border() {
|
|
run_golden_test_with_images("135-img-with-border");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_136_img_display_block() {
|
|
run_golden_test_with_images("136-img-display-block");
|
|
}
|
|
|
|
// Milestone 5: Font Properties
|
|
|
|
#[test]
|
|
fn golden_137_font_weight_bold() {
|
|
run_golden_test("137-font-weight-bold");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_138_font_style_italic() {
|
|
run_golden_test("138-font-style-italic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_139_font_family_monospace() {
|
|
run_golden_test("139-font-family-monospace");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_140_mixed_font_styles() {
|
|
run_golden_test("140-mixed-font-styles");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_141_heading_font_weight() {
|
|
run_golden_test("141-heading-font-weight");
|
|
}
|
|
|
|
// Regression: Image inside inline wrapper (e.g., <font><img></font>)
|
|
|
|
#[test]
|
|
fn golden_142_img_in_inline_wrapper() {
|
|
run_golden_test_with_images("142-img-in-inline-wrapper");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_143_img_link_in_table() {
|
|
run_golden_test_with_images("143-img-link-in-table");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_144_grid_fixed_columns() {
|
|
run_golden_test("144-grid-fixed-columns");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_145_grid_fr_units() {
|
|
run_golden_test("145-grid-fr-units");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_146_grid_gap() {
|
|
run_golden_test("146-grid-gap");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_147_grid_explicit_placement() {
|
|
run_golden_test("147-grid-explicit-placement");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_148_grid_span() {
|
|
run_golden_test("148-grid-span");
|
|
}
|
|
|
|
// Float children positioning fix
|
|
|
|
#[test]
|
|
fn golden_149_float_right_with_block_children() {
|
|
run_golden_test("149-float-right-with-block-children");
|
|
}
|
|
|
|
// Flex container Y positioning + CSS min() in grid templates
|
|
|
|
#[test]
|
|
fn golden_150_flex_nav_in_grid() {
|
|
run_golden_test("150-flex-nav-in-grid");
|
|
}
|
|
|
|
// Grid items with explicit column but auto row should not overlap earlier rows
|
|
|
|
#[test]
|
|
fn golden_151_grid_explicit_col_auto_row() {
|
|
run_golden_test("151-grid-explicit-col-auto-row");
|
|
}
|
|
|
|
// Negative grid line numbers: 1/-1 spans all columns, 2/-1 spans last two
|
|
|
|
#[test]
|
|
fn golden_152_grid_negative_line_numbers() {
|
|
run_golden_test("152-grid-negative-line-numbers");
|
|
}
|
|
|
|
// List marker support
|
|
|
|
#[test]
|
|
fn golden_153_unordered_list() {
|
|
run_golden_test("153-unordered-list");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_154_ordered_list() {
|
|
run_golden_test("154-ordered-list");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_155_ordered_list_start() {
|
|
run_golden_test("155-ordered-list-start");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_156_nested_lists() {
|
|
run_golden_test("156-nested-lists");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_157_ordered_list_type() {
|
|
run_golden_test("157-ordered-list-type");
|
|
}
|
|
|
|
// Table with caption regression: captions must not cause row groups to be
|
|
// wrapped in anonymous blocks (which hides them from the table layout algorithm)
|
|
|
|
#[test]
|
|
fn golden_158_table_with_caption() {
|
|
run_golden_test("158-table-with-caption");
|
|
}
|
|
|
|
// Flexbox comprehensive tests
|
|
|
|
#[test]
|
|
fn golden_159_flex_wrap() {
|
|
run_golden_test("159-flex-wrap");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_160_flex_direction_reverse() {
|
|
run_golden_test("160-flex-direction-reverse");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_161_flex_align_self() {
|
|
run_golden_test("161-flex-align-self");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_162_flex_shorthand() {
|
|
run_golden_test("162-flex-shorthand");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_163_flex_order() {
|
|
run_golden_test("163-flex-order");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_164_inline_flex() {
|
|
run_golden_test("164-inline-flex");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_165_justify_content_space_evenly() {
|
|
run_golden_test("165-justify-content-space-evenly");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_166_box_sizing() {
|
|
run_golden_test("166-box-sizing");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_167_box_sizing_comprehensive() {
|
|
run_golden_test("167-box-sizing-comprehensive");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_168_bootstrap_fixed_top() {
|
|
run_golden_test("168-bootstrap-fixed-top");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_169_img_svg_basic() {
|
|
run_golden_test_with_images("169-img-svg-basic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_171_center_element_block() {
|
|
run_golden_test("171-center-element-block");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_172_line_height_var() {
|
|
run_golden_test("172-line-height-var");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_173_table_anonymous_row() {
|
|
run_golden_test("173-table-anonymous-row");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_174_object_fallback() {
|
|
run_golden_test_with_images("174-object-fallback");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_175_object_data_uri() {
|
|
run_golden_test_with_images("175-object-data-uri");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_176_object_fallback_chain() {
|
|
run_golden_test_with_images("176-object-fallback-chain");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_177_z_index_deep_stacking() {
|
|
run_golden_test("177-z-index-deep-stacking");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_178_z_index_tree_order() {
|
|
run_golden_test("178-z-index-tree-order");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_179_z_index_overflow_clip() {
|
|
run_golden_test("179-z-index-overflow-clip");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_180_absolute_shrink_to_fit() {
|
|
run_golden_test("180-absolute-shrink-to-fit");
|
|
}
|
|
|
|
// Border-radius support
|
|
|
|
#[test]
|
|
fn golden_181_border_radius_basic() {
|
|
run_golden_test("181-border-radius-basic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_182_border_radius_per_corner() {
|
|
run_golden_test("182-border-radius-per-corner");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_183_border_radius_circle() {
|
|
run_golden_test("183-border-radius-circle");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_184_border_radius_clamping() {
|
|
run_golden_test("184-border-radius-clamping");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_185_border_radius_no_border() {
|
|
run_golden_test("185-border-radius-no-border");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_186_negative_margin_auto_height() {
|
|
run_golden_test("186-negative-margin-auto-height");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_187_table_anonymous_objects() {
|
|
run_golden_test("187-table-anonymous-objects");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_188_object_non_image_mime_fallback() {
|
|
run_golden_test_with_images("188-object-non-image-mime-fallback");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_189_table_col_width() {
|
|
run_golden_test("189-table-col-width");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_190_table_colgroup() {
|
|
run_golden_test("190-table-colgroup");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_191_table_col_span() {
|
|
run_golden_test("191-table-col-span");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_192_float_stacking_context() {
|
|
run_golden_test("192-float-stacking-context");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_193_abspos_inline_ifc() {
|
|
run_golden_test("193-abspos-inline-ifc");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_194_float_right_stacking_context() {
|
|
run_golden_test("194-float-right-stacking-context");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_195_abspos_inline_ifc_with_offset() {
|
|
run_golden_test("195-abspos-inline-ifc-with-offset");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_199_text_transform() {
|
|
run_golden_test("199-text-transform");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_200_table_layout_fixed() {
|
|
run_golden_test("200-table-layout-fixed");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_201_table_layout_fixed_first_row() {
|
|
run_golden_test("201-table-layout-fixed-first-row");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_202_table_layout_fixed_col() {
|
|
run_golden_test("202-table-layout-fixed-col");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_203_table_layout_fixed_auto_width() {
|
|
run_golden_test("203-table-layout-fixed-auto-width");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_204_table_layout_fixed_colspan_first_row() {
|
|
// colspan > 1 in the first row: the spanning cell's width hint must be
|
|
// ignored for fixed layout; columns fall back to equal distribution.
|
|
run_golden_test("204-table-layout-fixed-colspan-first-row");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_205_table_layout_fixed_percentage_first_row() {
|
|
// Percentage widths on first-row cells are resolved against the table
|
|
// content width, not the containing block.
|
|
run_golden_test("205-table-layout-fixed-percentage-first-row");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_206_table_layout_fixed_all_explicit() {
|
|
// All columns have explicit widths that don't sum to the table width:
|
|
// the implementation scales them proportionally to fill.
|
|
run_golden_test("206-table-layout-fixed-all-explicit");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_207_content_attr() {
|
|
// CSS attr() function in content: resolves the element's href attribute and
|
|
// appends it after the link text via ::after.
|
|
run_golden_test("207-content-attr");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_208_flex_row_auto_height() {
|
|
// Flex row container with height:auto must expand to contain children
|
|
// whose height comes from their own block children (F-001 regression).
|
|
run_golden_test("208-flex-row-auto-height");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_209_margin_collapse_parent_first_child() {
|
|
run_golden_test("209-margin-collapse-parent-first-child");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_210_margin_collapse_parent_last_child() {
|
|
run_golden_test("210-margin-collapse-parent-last-child");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_211_margin_collapse_nested_chain() {
|
|
run_golden_test("211-margin-collapse-nested-chain");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_212_margin_collapse_min_height() {
|
|
run_golden_test("212-margin-collapse-min-height");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_213_z_index_negative() {
|
|
run_golden_test("213-z-index-negative");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_214_z_index_positioned_auto_tree_order() {
|
|
run_golden_test("214-z-index-positioned-auto-tree-order");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_215_z_index_interleaved_positioned() {
|
|
run_golden_test("215-z-index-interleaved-positioned");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_216_z_index_nested_atomicity() {
|
|
// Atomicity: child z-index:999 inside parent z-index:1 must NOT paint above sibling z-index:2
|
|
run_golden_test("216-z-index-nested-atomicity");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_217_z_index_three_level_nesting() {
|
|
run_golden_test("217-z-index-three-level-nesting");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_218_z_index_zero_step6() {
|
|
// z-index:0 stacking contexts must paint at step 6, not step 7
|
|
run_golden_test("218-z-index-zero-step6");
|
|
}
|
|
|
|
// Tests 219 and 220 replaced by stacking_order_tests.rs integration tests
|
|
// that assert paint-order invariants programmatically instead of relying
|
|
// on golden file snapshots.
|
|
|
|
#[test]
|
|
fn golden_222_abspos_auto_offset_static() {
|
|
// §10.3.7: Both left and right auto — uses static position
|
|
run_golden_test("222-abspos-auto-offset-static");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_223_abspos_left_auto_right_specified() {
|
|
// §10.3.7: Left auto, right specified — position from right
|
|
run_golden_test("223-abspos-left-auto-right-specified");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_224_abspos_overconstrained() {
|
|
// §10.3.7: Over-constrained (left+width+right) and auto-margin centering
|
|
run_golden_test("224-abspos-overconstrained");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_225_clip_rect() {
|
|
// §11.1.2: clip: rect() on absolute and fixed elements
|
|
run_golden_test("225-clip-rect");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_226_abspos_containing_block_chains() {
|
|
// §10.1: Containing block chains with padding edge verification
|
|
run_golden_test("226-abspos-containing-block-chains");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_227_counter_basic() {
|
|
// §12.4: counter-reset, counter-increment, counter() in content
|
|
run_golden_test("227-counter-basic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_228_counters_nested() {
|
|
// §12.4.1: Nested counters with counters() function and separator
|
|
run_golden_test("228-counters-nested");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_229_counter_upper_roman() {
|
|
// §12.4.2: counter() with upper-roman list-style-type
|
|
run_golden_test("229-counter-upper-roman");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_230_quote_keywords() {
|
|
// §12.3: open-quote/close-quote keywords in content
|
|
run_golden_test("230-quote-keywords");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_231_table_caption_side_bottom() {
|
|
// §17.4: caption-side: bottom places caption below table rows
|
|
run_golden_test("231-table-caption-side-bottom");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_232_table_empty_cells_hide() {
|
|
// §17.6.1.1: empty-cells: hide suppresses borders/backgrounds for empty cells
|
|
run_golden_test("232-table-empty-cells-hide");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_233_table_collapsed_groove_ridge() {
|
|
// §17.6.2: collapsed borders with groove, ridge, outset styles
|
|
run_golden_test("233-table-collapsed-groove-ridge");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_234_table_fixed_collapsed() {
|
|
// §17.5.2.1 + §17.6.2: table-layout: fixed with border-collapse: collapse
|
|
run_golden_test("234-table-fixed-collapsed");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_235_list_style_position_inside() {
|
|
// §12.6.3: list-style-position: inside places marker within content flow
|
|
run_golden_test("235-list-style-position-inside");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_236_list_style_position_outside() {
|
|
// §12.6.3: list-style-position: outside places marker in margin area
|
|
run_golden_test("236-list-style-position-outside");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_237_counter_reset_increment() {
|
|
// §12.4: counter-reset + counter-increment with content: counter()
|
|
run_golden_test("237-counter-reset-increment");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_238_nested_counters() {
|
|
// §12.4.1: nested counter scoping with counters() separator
|
|
run_golden_test("238-nested-counters");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_239_counter_with_list_style() {
|
|
// §12.4: counters with list-style-type formatting (upper-roman)
|
|
run_golden_test("239-counter-with-list-style");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_240_list_style_image() {
|
|
// §12.6.2: list-style-image with fallback to list-style-type
|
|
run_golden_test("240-list-style-image");
|
|
}
|
|
|
|
// Story 1.7: Backgrounds — CSS 2.1 §14.2
|
|
|
|
#[test]
|
|
fn golden_241_background_image_url() {
|
|
// §14.2.1: background-image: url() with no-repeat
|
|
run_golden_test_with_images("241-background-image-url");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_242_background_repeat_modes() {
|
|
// §14.2.2: all 4 background-repeat values with visible tiling
|
|
run_golden_test_with_images("242-background-repeat-modes");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_243_background_position_keywords() {
|
|
// §14.2.1: background-position with keyword values
|
|
run_golden_test_with_images("243-background-position-keywords");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_244_background_position_percentage() {
|
|
// §14.2.1: background-position with percentage values
|
|
run_golden_test_with_images("244-background-position-percentage");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_245_background_attachment_fixed() {
|
|
// §14.2.1: background-attachment: fixed (viewport-relative)
|
|
run_golden_test_with_images("245-background-attachment-fixed");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_246_background_shorthand() {
|
|
// §14.2.1: full background shorthand with all components
|
|
run_golden_test_with_images("246-background-shorthand");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_247_background_gradient() {
|
|
// linear-gradient() background
|
|
run_golden_test("247-background-gradient");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_248_background_canvas() {
|
|
// §14.2: root element background covering canvas with image
|
|
run_golden_test_with_images("248-background-canvas");
|
|
}
|
|
|
|
// Border styles and outline (CSS 2.1 §8.5.3, §18.4)
|
|
|
|
#[test]
|
|
fn golden_249_border_style_double() {
|
|
run_golden_test("249-border-style-double");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_250_border_style_3d() {
|
|
run_golden_test("250-border-style-3d");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_251_border_style_mixed() {
|
|
run_golden_test("251-border-style-mixed");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_252_outline_basic() {
|
|
run_golden_test("252-outline-basic");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_253_outline_offset() {
|
|
run_golden_test("253-outline-offset");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_254_outline_styles() {
|
|
run_golden_test("254-outline-styles");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_260_font_shorthand_complete() {
|
|
run_golden_test("260-font-shorthand-complete");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_261_font_variant_small_caps() {
|
|
run_golden_test("261-font-variant-small-caps");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_262_ex_units() {
|
|
run_golden_test("262-ex-units");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_263_overflow_scroll() {
|
|
run_golden_test("263-overflow-scroll");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_264_overflow_auto_overflow() {
|
|
run_golden_test("264-overflow-auto-overflow");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_265_overflow_auto_no_overflow() {
|
|
run_golden_test("265-overflow-auto-no-overflow");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_266_overflow_positioned_children() {
|
|
run_golden_test("266-overflow-positioned-children");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_267_overflow_abspos_escape() {
|
|
run_golden_test("267-overflow-abspos-escape");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_268_media_screen_applies() {
|
|
run_golden_test("268-media-screen-applies");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_269_media_print_ignored() {
|
|
run_golden_test("269-media-print-ignored");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_275_rcdata_rawtext_states() {
|
|
run_golden_test("275-rcdata-rawtext-states");
|
|
}
|
|
|
|
// HTML tree builder insertion mode tests
|
|
|
|
#[test]
|
|
fn golden_276_insertion_mode_transitions() {
|
|
run_golden_test("276-insertion-mode-transitions");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_277_implicit_element_creation() {
|
|
run_golden_test("277-implicit-element-creation");
|
|
}
|
|
|
|
// HTML tree builder adoption agency and foster parenting
|
|
|
|
#[test]
|
|
fn golden_278_adoption_agency() {
|
|
run_golden_test("278-adoption-agency");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_279_foster_parenting() {
|
|
run_golden_test("279-foster-parenting");
|
|
}
|
|
|
|
// iframe support (uses run_golden_test_with_iframes to exercise the full
|
|
// iframe rendering pipeline including srcdoc parsing and style isolation)
|
|
|
|
#[test]
|
|
fn golden_280_iframe_srcdoc() {
|
|
run_golden_test_with_iframes("280-iframe-srcdoc");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_281_iframe_dimensions() {
|
|
run_golden_test_with_iframes("281-iframe-dimensions");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_282_iframe_style_isolation() {
|
|
run_golden_test_with_iframes("282-iframe-style-isolation");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_283_iframe_default_size() {
|
|
run_golden_test_with_iframes("283-iframe-default-size");
|
|
}
|
|
|
|
// Image format rendering verification (Story 2.9)
|
|
|
|
#[test]
|
|
fn golden_284_img_png_format() {
|
|
run_golden_test_with_images("284-img-png-format");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_285_img_jpeg_format() {
|
|
run_golden_test_with_images("285-img-jpeg-format");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_286_img_gif_format() {
|
|
run_golden_test_with_images("286-img-gif-format");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_287_img_webp_format() {
|
|
run_golden_test_with_images("287-img-webp-format");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_288_img_svg_format() {
|
|
run_golden_test_with_images("288-img-svg-format");
|
|
}
|
|
|
|
// Image aspect ratio preservation (Story 2.9)
|
|
|
|
#[test]
|
|
fn golden_289_img_aspect_ratio_width_only() {
|
|
run_golden_test_with_images("289-img-aspect-ratio-width-only");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_290_img_aspect_ratio_height_only() {
|
|
run_golden_test_with_images("290-img-aspect-ratio-height-only");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_291_img_aspect_ratio_both_attrs() {
|
|
run_golden_test_with_images("291-img-aspect-ratio-both-attrs");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_292_img_aspect_ratio_css_width() {
|
|
run_golden_test_with_images("292-img-aspect-ratio-css-width");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_293_img_aspect_ratio_max_width() {
|
|
run_golden_test_with_images("293-img-aspect-ratio-max-width");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_294_img_intrinsic_size() {
|
|
run_golden_test_with_images("294-img-intrinsic-size");
|
|
}
|
|
|
|
// CSS background-image format rendering verification (Story 2.9)
|
|
|
|
#[test]
|
|
fn golden_295_bg_img_png_format() {
|
|
run_golden_test_with_images("295-bg-img-png-format");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_296_bg_img_jpeg_format() {
|
|
run_golden_test_with_images("296-bg-img-jpeg-format");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_297_bg_img_gif_format() {
|
|
run_golden_test_with_images("297-bg-img-gif-format");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_298_bg_img_webp_format() {
|
|
run_golden_test_with_images("298-bg-img-webp-format");
|
|
}
|
|
|
|
#[test]
|
|
fn golden_299_bg_img_svg_format() {
|
|
run_golden_test_with_images("299-bg-img-svg-format");
|
|
}
|