All checks were successful
ci / fast (linux) (push) Successful in 7m14s
Column widths are determined by <col> elements and first-row cells only, ignoring content in subsequent rows for faster, more predictable layout. Falls back to auto layout when table has no explicit width. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1285 lines
28 KiB
Rust
1285 lines
28 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::{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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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())
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
#[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");
|
|
}
|