LibWeb+headless-browser: Replace ref-test manifest with link tags
Each ref test now links to its reference page with a link tag, in the same format as WPT: `<link rel="match" href="reference-page.html" />` The reference pages have all been moved into a separate `reference/` dir so that we can just treat every file in `ref/` as a test. There's no filter to only look at .html files, because we also have a .svg file in there, and there may be other formats we want to use too. But it's not too hard to add one if we need it.
|  | @ -1,3 +1,4 @@ | |||
| <link rel="match" href="reference/border-radius-shrink-zero-sized-box-ref.html" /> | ||||
| <style> | ||||
|   #test { | ||||
|     background-color: red; | ||||
|  |  | |||
|  | @ -1,4 +1,6 @@ | |||
| <!DOCTYPE html><style type="text/css"> | ||||
| <!DOCTYPE html> | ||||
| <link rel="match" href="reference/clip-abspos-children-ref.html" /> | ||||
| <style type="text/css"> | ||||
|     * { | ||||
|         background-color: white; | ||||
|     } | ||||
|  |  | |||
|  | @ -1,4 +1,6 @@ | |||
| <!DOCTYPE html><style type="text/css"> | ||||
| <!DOCTYPE html> | ||||
| <link rel="match" href="reference/clip-ref.html" /> | ||||
| <style type="text/css"> | ||||
|     * { | ||||
|         background-color: white; | ||||
|     } | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| <link rel="match" href="reference/css-any-link-selector-ref.html" /> | ||||
| <style> | ||||
|     :any-link { | ||||
|         color: orange; | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <!doctype html> | ||||
| <link rel="match" href="reference/css-attr-ref.html" /> | ||||
| <style> | ||||
|     .foo::before { | ||||
|         content: attr(bar); | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <!doctype html> | ||||
| <link rel="match" href="reference/css-attr-ref.html" /> | ||||
| <style> | ||||
|     .foo::before { | ||||
|         content: attr(bar, "Well, hello friends!"); | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <!doctype html> | ||||
| <link rel="match" href="reference/css-attr-typed-ref.html" /> | ||||
| <style> | ||||
|     div { | ||||
|         width: 100px; | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <!doctype html> | ||||
| <link rel="match" href="reference/css-attr-typed-ref.html" /> | ||||
| <style> | ||||
|     div { | ||||
|         width: 100px; | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <html> | ||||
| <link rel="match" href="reference/css-gradient-currentcolor-ref.html" /> | ||||
| <style> | ||||
|     div { | ||||
|         color: green; | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <link rel="match" href="reference/css-gradients-ref.html" /> | ||||
| <style> | ||||
|   body { | ||||
|     background-color: white; | ||||
|  |  | |||
|  | @ -1,4 +1,6 @@ | |||
| <!doctype html><style> | ||||
| <!doctype html> | ||||
| <link rel="match" href="reference/css-invalid-var-ref.html" /> | ||||
| <style> | ||||
|     div { | ||||
|         color: red; | ||||
|         color: var(--wat); | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <html lang="en"> | ||||
| <link rel="match" href="reference/css-lang-selector-ref.html" /> | ||||
| <style> | ||||
|     div { | ||||
|         width: 100px; | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| <link rel="match" href="reference/css-local-link-selector-ref.html" /> | ||||
| <style> | ||||
|     :local-link { | ||||
|         color: orange; | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| <link rel="match" href="reference/css-placeholder-shown-selector-ref.html" /> | ||||
| <style> | ||||
| :placeholder-shown { | ||||
|     background-color: yellow; | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| <link rel="match" href="reference/css-read-only-read-write-selectors-ref.html" /> | ||||
| <style> | ||||
|     body :read-write { | ||||
|         background-color: green; | ||||
|  |  | |||
|  | @ -1,4 +1,6 @@ | |||
| <!doctype html><style type="text/css"> | ||||
| <!doctype html> | ||||
| <link rel="match" href="reference/grid-items-painting-order-ref.html" /> | ||||
| <style type="text/css"> | ||||
| body { display: grid; } | ||||
| .foo { | ||||
|     grid-area: 1 / 1 / auto / auto; | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <!doctype html> | ||||
| <link rel="match" href="reference/img-srcset-viewport-relative-sizes-ref.html" /> | ||||
| <img | ||||
|     sizes="100vw" | ||||
|     srcset=" | ||||
|  |  | |||
|  | @ -1,4 +1,6 @@ | |||
| <!doctype html><style type="text/css"> | ||||
| <!doctype html> | ||||
| <link rel="match" href="reference/item-with-negative-z-index-ref.html" /> | ||||
| <style type="text/css"> | ||||
| body { display: grid; } | ||||
| .foo { | ||||
|     outline: 1px solid black; | ||||
|  |  | |||
|  | @ -1,27 +0,0 @@ | |||
| { | ||||
|     "clip.html": "clip-ref.html", | ||||
|     "clip-abspos-children.html": "clip-abspos-children-ref.html", | ||||
|     "css-any-link-selector.html": "css-any-link-selector-ref.html", | ||||
|     "css-attr-basic.html": "css-attr-ref.html", | ||||
|     "css-attr-fallback.html": "css-attr-ref.html", | ||||
|     "css-attr-typed.html": "css-attr-typed-ref.html", | ||||
|     "css-attr-typed-fallback.html": "css-attr-typed-ref.html", | ||||
|     "css-gradient-currentcolor.html": "css-gradient-currentcolor-ref.html", | ||||
|     "css-gradients.html": "css-gradients-ref.html", | ||||
|     "css-invalid-var.html": "css-invalid-var-ref.html", | ||||
|     "css-lang-selector.html": "css-lang-selector-ref.html", | ||||
|     "css-local-link-selector.html": "css-local-link-selector-ref.html", | ||||
|     "css-placeholder-shown-selector.html": "css-placeholder-shown-selector-ref.html", | ||||
|     "css-read-only-read-write-selectors.html": "css-read-only-read-write-selectors-ref.html", | ||||
|     "grid-items-painting-order.html": "grid-items-painting-order-ref.html", | ||||
|     "img-srcset-viewport-relative-sizes.html": "img-srcset-viewport-relative-sizes-ref.html", | ||||
|     "item-with-negative-z-index.html": "item-with-negative-z-index-ref.html", | ||||
|     "opacity-stacking.html": "opacity-stacking-ref.html", | ||||
|     "separate-borders-inline-table.html": "separate-borders-ref.html", | ||||
|     "square-flex.html": "square-ref.html", | ||||
|     "svg-gradient-spreadMethod.html": "svg-gradient-spreadMethod-ref.html", | ||||
|     "svg-radialGradient.html": "svg-radialGradient-ref.html", | ||||
|     "svg-symbol.html": "svg-symbol-ref.html", | ||||
|     "border-radius-shrink-zero-sized-box.html": "border-radius-shrink-zero-sized-box-ref.html", | ||||
|     "svg-file-matches-html-file.svg": "svg-file-matches-html-file.html" | ||||
| } | ||||
|  | @ -1,3 +1,4 @@ | |||
| <link rel="match" href="reference/opacity-stacking-ref.html" /> | ||||
| <style> | ||||
|   body { | ||||
|     background-color: white; | ||||
|  |  | |||
| Before Width: | Height: | Size: 317 KiB After Width: | Height: | Size: 317 KiB | 
| Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB | 
| Before Width: | Height: | Size: 861 KiB After Width: | Height: | Size: 861 KiB | 
| Before Width: | Height: | Size: 183 B After Width: | Height: | Size: 183 B | 
|  | @ -1,3 +1,4 @@ | |||
| <link rel="match" href="reference/separate-borders-ref.html" /> | ||||
| <style type="text/css"> | ||||
|     td { | ||||
|         border: 5px solid blue; | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| <link rel="match" href="reference/square-ref.html" /> | ||||
| <style> | ||||
|     .box { | ||||
|         display: flex; | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> | ||||
|   <link rel="match" href="reference/svg-file-matches-html-file.html" /> | ||||
|   <defs> | ||||
|     <g id="10"> | ||||
|       <rect width="50" height="50" fill="#555555"></rect> | ||||
|  |  | |||
| Before Width: | Height: | Size: 214 B After Width: | Height: | Size: 286 B | 
|  | @ -1,3 +1,4 @@ | |||
| <link rel="match" href="reference/svg-gradient-spreadMethod-ref.html" /> | ||||
| <style> | ||||
|   * { | ||||
|     margin: 0; | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| <link rel="match" href="reference/svg-radialGradient-ref.html" /> | ||||
| <style> | ||||
|   * { | ||||
|     margin: 0; | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| <link rel="match" href="reference/svg-symbol-ref.html" /> | ||||
| <svg><symbol id="dot" width="500" height="500" viewBox="0 0 2 10"> | ||||
| <circle fill="green" cx="1" cy="1" r="1"/> | ||||
| <circle fill="blue" cx="1.5" cy="1" r="1"/> | ||||
|  |  | |||
| Before Width: | Height: | Size: 183 B After Width: | Height: | Size: 241 B | 
|  | @ -2,6 +2,7 @@ | |||
|  * Copyright (c) 2022, Dex♪ <dexes.ttp@gmail.com> | ||||
|  * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org> | ||||
|  * Copyright (c) 2023, Andreas Kling <kling@serenityos.org> | ||||
|  * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org> | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
|  | @ -19,6 +20,7 @@ | |||
| #include <AK/Vector.h> | ||||
| #include <LibCore/ArgsParser.h> | ||||
| #include <LibCore/DirIterator.h> | ||||
| #include <LibCore/Directory.h> | ||||
| #include <LibCore/EventLoop.h> | ||||
| #include <LibCore/File.h> | ||||
| #include <LibCore/Timer.h> | ||||
|  | @ -241,7 +243,7 @@ static ErrorOr<TestResult> run_dump_test(HeadlessWebContentView& view, StringVie | |||
|     return TestResult::Fail; | ||||
| } | ||||
| 
 | ||||
| static ErrorOr<TestResult> run_ref_test(HeadlessWebContentView& view, StringView input_path, StringView expectation_path, int timeout_in_milliseconds = 15000) | ||||
| static ErrorOr<TestResult> run_ref_test(HeadlessWebContentView& view, StringView input_path, int timeout_in_milliseconds = 15000) | ||||
| { | ||||
|     Core::EventLoop loop; | ||||
|     bool did_timeout = false; | ||||
|  | @ -252,7 +254,6 @@ static ErrorOr<TestResult> run_ref_test(HeadlessWebContentView& view, StringView | |||
|     })); | ||||
| 
 | ||||
|     view.load(URL::create_with_file_scheme(TRY(FileSystem::real_path(input_path)).to_deprecated_string())); | ||||
|     auto expectation_real_path = TRY(FileSystem::real_path(expectation_path)).to_deprecated_string(); | ||||
| 
 | ||||
|     RefPtr<Gfx::Bitmap> actual_screenshot, expectation_screenshot; | ||||
|     view.on_load_finish = [&](auto const&) { | ||||
|  | @ -261,7 +262,7 @@ static ErrorOr<TestResult> run_ref_test(HeadlessWebContentView& view, StringView | |||
|             loop.quit(0); | ||||
|         } else { | ||||
|             actual_screenshot = view.take_screenshot(); | ||||
|             view.load(URL::create_with_file_scheme(expectation_real_path)); | ||||
|             view.debug_request("load-reference-page"); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|  | @ -287,7 +288,7 @@ static ErrorOr<TestResult> run_test(HeadlessWebContentView& view, StringView inp | |||
|     case TestMode::Layout: | ||||
|         return run_dump_test(view, input_path, expectation_path, mode); | ||||
|     case TestMode::Ref: | ||||
|         return run_ref_test(view, input_path, expectation_path); | ||||
|         return run_ref_test(view, input_path); | ||||
|     default: | ||||
|         VERIFY_NOT_REACHED(); | ||||
|     } | ||||
|  | @ -322,22 +323,12 @@ static ErrorOr<void> collect_dump_tests(Vector<Test>& tests, StringView path, St | |||
| 
 | ||||
| static ErrorOr<void> collect_ref_tests(Vector<Test>& tests, StringView path) | ||||
| { | ||||
|     auto manifest_path = TRY(String::formatted("{}/manifest.json", path)); | ||||
|     auto manifest_file_or_error = Core::File::open(manifest_path, Core::File::OpenMode::Read); | ||||
|     if (manifest_file_or_error.is_error()) { | ||||
|         warnln("Failed opening '{}': {}", manifest_path, manifest_file_or_error.error()); | ||||
|         return manifest_file_or_error.release_error(); | ||||
|     } | ||||
| 
 | ||||
|     auto manifest_file = manifest_file_or_error.release_value(); | ||||
|     auto manifest = TRY(String::from_utf8(StringView(TRY(manifest_file->read_until_eof()).bytes()))); | ||||
|     auto manifest_json = TRY(JsonParser(manifest).parse()); | ||||
|     TRY(manifest_json.as_object().try_for_each_member([&](DeprecatedString const& key, AK::JsonValue const& value) -> ErrorOr<void> { | ||||
|         TRY(String::from_deprecated_string(key)); | ||||
|         auto input_path = TRY(String::formatted("{}/{}", path, key)); | ||||
|         auto expectation_path = TRY(String::formatted("{}/{}", path, value.to_deprecated_string())); | ||||
|         tests.append({ input_path, expectation_path, TestMode::Ref, {} }); | ||||
|         return {}; | ||||
|     TRY(Core::Directory::for_each_entry(path, Core::DirIterator::SkipDots, [&](Core::DirectoryEntry const& entry, Core::Directory const&) -> ErrorOr<IterationDecision> { | ||||
|         if (entry.type == Core::DirectoryEntry::Type::Directory) | ||||
|             return IterationDecision::Continue; | ||||
|         auto input_path = TRY(FileSystem::real_path(TRY(String::formatted("{}/{}", path, entry.name)))); | ||||
|         tests.append({ move(input_path), {}, TestMode::Ref, {} }); | ||||
|         return IterationDecision::Continue; | ||||
|     })); | ||||
| 
 | ||||
|     return {}; | ||||
|  |  | |||
 Sam Atkins
						Sam Atkins