Repository: servo/html5ever (language: python)

Issue:
tests fail under rust 1.77.1 to build because of rustc-test
`cargo test` fails to build under rust 1.77.1 because of the `rustc-test` transitive dependency on `rustc-serialize`. Looks like this is already [reported upstream](https://github.com/rust-lang/rust/issues/123156), but I expect the whole crate is no longer necessary and the dependency can removed.


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 56e412ad..4d29eba2 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -30,11 +30,6 @@ jobs:
         env:
           RUSTFLAGS: --cfg bench
 
-      - name: Test "rustc-test/capture" feature
-        if: matrix.version == 'nightly'
-        working-directory: rcdom
-        run: cargo test --features "rustc-test/capture"
-
       - name: Cargo test
         if: matrix.version != 'nightly'
         run: cargo test --all
diff --git a/rcdom/Cargo.toml b/rcdom/Cargo.toml
index 2c42d7b7..d59b839b 100644
--- a/rcdom/Cargo.toml
+++ b/rcdom/Cargo.toml
@@ -22,7 +22,6 @@ xml5ever = { version = "0.18", path = "../xml5ever" }
 
 [dev-dependencies]
 serde_json = "1.0"
-rustc-test = "0.3"
 
 [[test]]
 name = "html-tokenizer"
diff --git a/xml5ever/Cargo.toml b/xml5ever/Cargo.toml
index 41a27fc3..cdae3de4 100644
--- a/xml5ever/Cargo.toml
+++ b/xml5ever/Cargo.toml
@@ -22,7 +22,6 @@ markup5ever = {version = "0.12", path = "../markup5ever" }
 
 [dev-dependencies]
 criterion = "0.3"
-rustc-test = "0.3"
 
 [[bench]]
 name = "xml5ever"


Test patch:
diff --git a/rcdom/tests/html-tokenizer.rs b/rcdom/tests/html-tokenizer.rs
index f67caf8f..061effcb 100644
--- a/rcdom/tests/html-tokenizer.rs
+++ b/rcdom/tests/html-tokenizer.rs
@@ -20,7 +20,6 @@ use html5ever::tokenizer::{CommentToken, DoctypeToken, TagToken, Token};
 use html5ever::tokenizer::{Doctype, EndTag, StartTag, Tag};
 use html5ever::tokenizer::{TokenSink, TokenSinkResult, Tokenizer, TokenizerOpts};
 use html5ever::{namespace_url, ns, Attribute, LocalName, QualName};
-use rustc_test::{DynTestFn, DynTestName, TestDesc, TestDescAndFn};
 use serde_json::{Map, Value};
 use std::ffi::OsStr;
 use std::fs::File;
@@ -28,6 +27,12 @@ use std::io::Read;
 use std::path::Path;
 use std::{char, env, mem};
 
+use util::runner::Test;
+
+mod util {
+    pub mod runner;
+}
+
 #[derive(Debug)]
 struct TestError;
 
@@ -334,10 +339,11 @@ fn mk_test(
     expect: Value,
     expect_errors: Vec<Value>,
     opts: TokenizerOpts,
-) -> TestDescAndFn {
-    TestDescAndFn {
-        desc: TestDesc::new(DynTestName(desc)),
-        testfn: DynTestFn(Box::new(move || {
+) -> Test {
+    Test {
+        name: desc,
+        skip: false,
+        test: Box::new(move || {
             // Split up the input at different points to test incremental tokenization.
             let insplits = splits(&input, 3);
             for input in insplits.into_iter() {
@@ -354,11 +360,11 @@ fn mk_test(
                     );
                 }
             }
-        })),
+        }),
     }
 }
 
-fn mk_tests(tests: &mut Vec<TestDescAndFn>, filename: &str, js: &Value) {
+fn mk_tests(tests: &mut Vec<Test>, filename: &str, js: &Value) {
     let obj = js.get_obj();
     let mut input = js.find("input").get_str();
     let mut expect = js.find("output").clone();
@@ -437,7 +443,7 @@ fn mk_tests(tests: &mut Vec<TestDescAndFn>, filename: &str, js: &Value) {
     }
 }
 
-fn tests(src_dir: &Path) -> Vec<TestDescAndFn> {
+fn tests(src_dir: &Path) -> Vec<Test> {
     let mut tests = vec![];
 
     let mut add_test = |path: &Path, mut file: File| {
@@ -474,6 +480,7 @@ fn tests(src_dir: &Path) -> Vec<TestDescAndFn> {
 }
 
 fn main() {
-    let args: Vec<_> = env::args().collect();
-    rustc_test::test_main(&args, tests(Path::new(env!("CARGO_MANIFEST_DIR"))));
+    for test in tests(Path::new(env!("CARGO_MANIFEST_DIR"))) {
+        test.run();
+    }
 }
diff --git a/rcdom/tests/html-tree-builder.rs b/rcdom/tests/html-tree-builder.rs
index d22207d3..1038e58e 100644
--- a/rcdom/tests/html-tree-builder.rs
+++ b/rcdom/tests/html-tree-builder.rs
@@ -8,7 +8,6 @@
 // except according to those terms.
 
 extern crate markup5ever_rcdom as rcdom;
-extern crate rustc_test as test;
 #[macro_use]
 extern crate html5ever;
 
@@ -20,12 +19,16 @@ use std::ffi::OsStr;
 use std::io::BufRead;
 use std::path::Path;
 use std::{env, fs, io, iter, mem};
-use test::{DynTestName, TestDesc, TestDescAndFn, TestFn};
 
 use html5ever::tendril::{StrTendril, TendrilSink};
 use html5ever::{parse_document, parse_fragment, ParseOpts};
 use html5ever::{LocalName, QualName};
 use rcdom::{Handle, NodeData, RcDom};
+use util::runner::Test;
+
+mod util {
+    pub mod runner;
+}
 
 fn parse_tests<It: Iterator<Item = String>>(mut lines: It) -> Vec<HashMap<String, String>> {
     let mut tests = vec![];
@@ -159,7 +162,7 @@ fn serialize(buf: &mut String, indent: usize, handle: Handle) {
 }
 
 fn make_test(
-    tests: &mut Vec<TestDescAndFn>,
+    tests: &mut Vec<Test>,
     ignores: &HashSet<String>,
     filename: &str,
     idx: usize,
@@ -185,7 +188,7 @@ fn make_test_desc_with_scripting_flag(
     name: &str,
     fields: &HashMap<String, String>,
     scripting_enabled: bool,
-) -> TestDescAndFn {
+) -> Test {
     let get_field = |key| {
         let field = fields.get(key).expect("missing field");
         field.trim_end_matches('\n').to_string()
@@ -197,24 +200,22 @@ fn make_test_desc_with_scripting_flag(
     let context = fields
         .get("document-fragment")
         .map(|field| context_name(field.trim_end_matches('\n')));
-    let ignore = ignores.contains(name);
+    let skip = ignores.contains(name);
     let mut name = name.to_owned();
     if scripting_enabled {
         name.push_str(" (scripting enabled)");
     } else {
         name.push_str(" (scripting disabled)");
     };
-    let mut opts: ParseOpts = Default::default();
-    opts.tree_builder.scripting_enabled = scripting_enabled;
 
-    TestDescAndFn {
-        desc: TestDesc {
-            ignore,
-            ..TestDesc::new(DynTestName(name))
-        },
-        testfn: TestFn::dyn_test_fn(move || {
+    Test {
+        name,
+        skip,
+        test: Box::new(move || {
             // Do this here because Tendril isn't Send.
             let data = StrTendril::from_slice(&data);
+            let mut opts: ParseOpts = Default::default();
+            opts.tree_builder.scripting_enabled = scripting_enabled;
             let mut result = String::new();
             match context {
                 None => {
@@ -258,7 +259,7 @@ fn context_name(context: &str) -> QualName {
     }
 }
 
-fn tests(src_dir: &Path, ignores: &HashSet<String>) -> Vec<TestDescAndFn> {
+fn tests(src_dir: &Path, ignores: &HashSet<String>) -> Vec<Test> {
     let mut tests = vec![];
 
     foreach_html5lib_test(
@@ -286,7 +287,6 @@ fn tests(src_dir: &Path, ignores: &HashSet<String>) -> Vec<TestDescAndFn> {
 }
 
 fn main() {
-    let args: Vec<_> = env::args().collect();
     let src_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
     let mut ignores = HashSet::new();
     {
@@ -297,5 +297,7 @@ fn main() {
         }
     }
 
-    test::test_main(&args, tests(src_dir, &ignores));
+    for test in tests(src_dir, &ignores) {
+        test.run();
+    }
 }
diff --git a/rcdom/tests/util/runner.rs b/rcdom/tests/util/runner.rs
new file mode 100644
index 00000000..3f50a7a2
--- /dev/null
+++ b/rcdom/tests/util/runner.rs
@@ -0,0 +1,32 @@
+// Copyright 2024 The html5ever Project Developers. See the
+// COPYRIGHT file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/// Simple container for storing tests for later execution
+pub struct Test {
+    pub name: String,
+    pub skip: bool,
+    pub test: Box<dyn Fn()>,
+}
+
+impl Test {
+    /// Invoke the stored test function
+    ///
+    /// A status message is printed if the wrapped closure completes
+    /// or is marked as skipped. The test should panic to report
+    /// failure.
+    pub fn run(&self) {
+        print!("test {} ...", self.name);
+        if self.skip {
+            println!(" SKIPPED");
+        } else {
+            (self.test)();
+            println!(" ok");
+        }
+    }
+}
diff --git a/rcdom/tests/xml-tokenizer.rs b/rcdom/tests/xml-tokenizer.rs
index cbdf10c3..ddb5d2ec 100644
--- a/rcdom/tests/xml-tokenizer.rs
+++ b/rcdom/tests/xml-tokenizer.rs
@@ -14,8 +14,8 @@ use std::io::Read;
 use std::path::Path;
 use std::{env, mem};
 
-use rustc_test::{DynTestFn, DynTestName, TestDesc, TestDescAndFn};
 use util::find_tests::foreach_xml5lib_test;
+use util::runner::Test;
 
 use markup5ever::buffer_queue::BufferQueue;
 use xml5ever::tendril::{SliceExt, StrTendril};
@@ -28,6 +28,7 @@ use xml5ever::{namespace_url, ns, Attribute, LocalName, QualName};
 
 mod util {
     pub mod find_tests;
+    pub mod runner;
 }
 
 // Return all ways of splitting the string into at most n
@@ -279,15 +280,11 @@ fn json_to_tokens(js: &Value, exact_errors: bool) -> Vec<Token> {
     sink.get_tokens()
 }
 
-fn mk_xml_test(
-    desc: String,
-    input: String,
-    expect: Value,
-    opts: XmlTokenizerOpts,
-) -> TestDescAndFn {
-    TestDescAndFn {
-        desc: TestDesc::new(DynTestName(desc)),
-        testfn: DynTestFn(Box::new(move || {
+fn mk_xml_test(name: String, input: String, expect: Value, opts: XmlTokenizerOpts) -> Test {
+    Test {
+        name,
+        skip: false,
+        test: Box::new(move || {
             // Split up the input at different points to test incremental tokenization.
             let insplits = splits(&input, 3);
             for input in insplits.into_iter() {
@@ -304,11 +301,11 @@ fn mk_xml_test(
                     );
                 }
             }
-        })),
+        }),
     }
 }
 
-fn mk_xml_tests(tests: &mut Vec<TestDescAndFn>, filename: &str, js: &Value) {
+fn mk_xml_tests(tests: &mut Vec<Test>, filename: &str, js: &Value) {
     let input: &str = &js.find("input").get_str();
     let expect = js.find("output");
     let desc = format!("tok: {}: {}", filename, js.find("description").get_str());
@@ -346,7 +343,7 @@ fn mk_xml_tests(tests: &mut Vec<TestDescAndFn>, filename: &str, js: &Value) {
     }
 }
 
-fn tests(src_dir: &Path) -> Vec<TestDescAndFn> {
+fn tests(src_dir: &Path) -> Vec<Test> {
     let mut tests = vec![];
     foreach_xml5lib_test(
         src_dir,
@@ -373,6 +370,7 @@ fn tests(src_dir: &Path) -> Vec<TestDescAndFn> {
 }
 
 fn main() {
-    let args: Vec<_> = env::args().collect();
-    rustc_test::test_main(&args, tests(Path::new(env!("CARGO_MANIFEST_DIR"))));
+    for test in tests(Path::new(env!("CARGO_MANIFEST_DIR"))) {
+        test.run();
+    }
 }
diff --git a/rcdom/tests/xml-tree-builder.rs b/rcdom/tests/xml-tree-builder.rs
index 98365c75..a28040ee 100644
--- a/rcdom/tests/xml-tree-builder.rs
+++ b/rcdom/tests/xml-tree-builder.rs
@@ -9,18 +9,19 @@
 
 use markup5ever::{namespace_url, ns};
 use markup5ever_rcdom::*;
-use rustc_test::{DynTestFn, DynTestName, TestDesc, TestDescAndFn};
 use std::collections::{HashMap, HashSet};
 use std::ffi::OsStr;
 use std::io::BufRead;
 use std::path::Path;
 use std::{env, fs, io, iter, mem};
 use util::find_tests::foreach_xml5lib_test;
+use util::runner::Test;
 use xml5ever::driver::parse_document;
 use xml5ever::tendril::TendrilSink;
 
 mod util {
     pub mod find_tests;
+    pub mod runner;
 }
 
 fn parse_tests<It: Iterator<Item = String>>(mut lines: It) -> Vec<HashMap<String, String>> {
@@ -158,7 +159,7 @@ fn serialize(buf: &mut String, indent: usize, handle: Handle) {
 static IGNORE_SUBSTRS: &[&str] = &["<template"];
 
 fn make_xml_test(
-    tests: &mut Vec<TestDescAndFn>,
+    tests: &mut Vec<Test>,
     ignores: &HashSet<String>,
     filename: &str,
     idx: usize,
@@ -172,14 +173,12 @@ fn make_xml_test(
     let data = get_field("data");
     let expected = get_field("document");
     let name = format!("tb: {}-{}", filename, idx);
-    let ignore = ignores.contains(&name) || IGNORE_SUBSTRS.iter().any(|&ig| data.contains(ig));
+    let skip = ignores.contains(&name) || IGNORE_SUBSTRS.iter().any(|&ig| data.contains(ig));
 
-    tests.push(TestDescAndFn {
-        desc: TestDesc {
-            ignore,
-            ..TestDesc::new(DynTestName(name))
-        },
-        testfn: DynTestFn(Box::new(move || {
+    tests.push(Test {
+        name,
+        skip,
+        test: Box::new(move || {
             let mut result = String::new();
 
             let dom = parse_document(RcDom::default(), Default::default()).one(data.clone());
@@ -196,11 +195,11 @@ fn make_xml_test(
                     data, result, expected
                 );
             }
-        })),
+        }),
     });
 }
 
-fn tests(src_dir: &Path, ignores: &HashSet<String>) -> Vec<TestDescAndFn> {
+fn tests(src_dir: &Path, ignores: &HashSet<String>) -> Vec<Test> {
     let mut tests = vec![];
 
     foreach_xml5lib_test(
@@ -228,7 +227,6 @@ fn tests(src_dir: &Path, ignores: &HashSet<String>) -> Vec<TestDescAndFn> {
 }
 
 fn main() {
-    let args: Vec<_> = env::args().collect();
     let src_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
     let mut ignores = HashSet::new();
     if let Ok(f) = fs::File::open(src_dir.join("data/test/ignore")) {
@@ -238,5 +236,7 @@ fn main() {
         }
     }
 
-    rustc_test::test_main(&args, tests(src_dir, &ignores));
+    for test in tests(src_dir, &ignores) {
+        test.run();
+    }
 }