Repository: rust-lang/annotate-snippets-rs
Pull request #201 (2025-04-28 17:34:21)

Migrate fixture tests
Compared to source code based tests, the benefits of using toml to specify tests haven't felt worth it to me recently. That, combined with the fixture tests mostly being about the colored output, made me realize that we should probably get rid of the toml fixtures. So I went ahead and did just that. I am happy with the changes, with the only caveat being that the test names all have `::case` at the end.
```
test ann_eof::case ... ok
test ann_insertion::case ... ok
test ann_removed_nl::case ... ok
test ann_multiline2::case ... ok
test ensure_emoji_highlight_width::case ... ok
test ann_multiline::case ... ok
test fold_bad_origin_line::case ... ok
test issue_9::case ... ok
test fold_leading::case ... ok
test fold_ann_multiline::case ... ok
test fold_trailing::case ... ok
test strip_line_char::case ... ok
test strip_line::case ... ok
test multiple_annotations::case ... ok
test simple::case ... ok
test strip_line_non_ws::case ... ok
```


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 8838e31..e643134 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,48 +2,19 @@
 # It is not intended for manual editing.
 version = 3
 
-[[package]]
-name = "aho-corasick"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
-dependencies = [
- "memchr",
-]
-
 [[package]]
 name = "annotate-snippets"
 version = "0.11.5"
 dependencies = [
  "annotate-snippets",
- "anstream 0.6.18",
+ "anstream",
  "anstyle",
- "difference",
  "divan",
- "glob",
  "memchr",
- "serde",
  "snapbox",
- "toml",
- "tryfn",
  "unicode-width 0.2.0",
 ]
 
-[[package]]
-name = "anstream"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
-dependencies = [
- "anstyle",
- "anstyle-parse",
- "anstyle-query",
- "anstyle-wincon 1.0.2",
- "colorchoice",
- "is-terminal",
- "utf8parse",
-]
-
 [[package]]
 name = "anstream"
 version = "0.6.18"
@@ -53,7 +24,7 @@ dependencies = [
  "anstyle",
  "anstyle-parse",
  "anstyle-query",
- "anstyle-wincon 3.0.6",
+ "anstyle-wincon",
  "colorchoice",
  "is_terminal_polyfill",
  "utf8parse",
@@ -98,23 +69,13 @@ version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bbbf0bf947d663010f0b4132f28ca08da9151f3b9035fa7578a38de521c1d1aa"
 dependencies = [
- "anstream 0.6.18",
+ "anstream",
  "anstyle",
  "anstyle-lossy",
  "html-escape",
  "unicode-width 0.1.13",
 ]
 
-[[package]]
-name = "anstyle-wincon"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c"
-dependencies = [
- "anstyle",
- "windows-sys 0.48.0",
-]
-
 [[package]]
 name = "anstyle-wincon"
 version = "3.0.6"
@@ -131,16 +92,6 @@ version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
-[[package]]
-name = "bstr"
-version = "1.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
-dependencies = [
- "memchr",
- "serde",
-]
-
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
@@ -154,8 +105,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fb690e81c7840c0d7aade59f242ea3b41b9bc27bcd5997890e7702ae4b32e487"
 dependencies = [
  "clap_builder",
- "clap_derive",
- "once_cell",
 ]
 
 [[package]]
@@ -164,25 +113,11 @@ version = "4.3.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5ed2e96bc16d8d740f6f48d663eddf4b8a0983e79210fd55479b7bcd0a69860e"
 dependencies = [
- "anstream 0.3.2",
  "anstyle",
  "clap_lex",
- "strsim",
  "terminal_size",
 ]
 
-[[package]]
-name = "clap_derive"
-version = "4.3.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn",
-]
-
 [[package]]
 name = "clap_lex"
 version = "0.5.0"
@@ -201,12 +136,6 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af"
 
-[[package]]
-name = "difference"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
-
 [[package]]
 name = "divan"
 version = "0.1.17"
@@ -232,12 +161,6 @@ dependencies = [
  "syn",
 ]
 
-[[package]]
-name = "equivalent"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
-
 [[package]]
 name = "errno"
 version = "0.3.9"
@@ -248,15 +171,6 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
-[[package]]
-name = "escape8259"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba4f4911e3666fcd7826997b4745c8224295a6f3072f1418c3067b97a67557ee"
-dependencies = [
- "rustversion",
-]
-
 [[package]]
 name = "escargot"
 version = "0.5.13"
@@ -269,37 +183,6 @@ dependencies = [
  "serde_json",
 ]
 
-[[package]]
-name = "glob"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
-
-[[package]]
-name = "globset"
-version = "0.4.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
-dependencies = [
- "aho-corasick",
- "bstr",
- "log",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
-
-[[package]]
-name = "heck"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
-
 [[package]]
 name = "hermit-abi"
 version = "0.3.9"
@@ -315,33 +198,6 @@ dependencies = [
  "utf8-width",
 ]
 
-[[package]]
-name = "ignore"
-version = "0.4.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
-dependencies = [
- "globset",
- "lazy_static",
- "log",
- "memchr",
- "regex",
- "same-file",
- "thread_local",
- "walkdir",
- "winapi-util",
-]
-
-[[package]]
-name = "indexmap"
-version = "2.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
-dependencies = [
- "equivalent",
- "hashbrown",
-]
-
 [[package]]
 name = "io-lifetimes"
 version = "1.0.11"
@@ -379,30 +235,12 @@ version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
 [[package]]
 name = "libc"
 version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
-[[package]]
-name = "libtest-mimic"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc0bda45ed5b3a2904262c1bb91e526127aa70e7ef3758aba2ef93cf896b9b58"
-dependencies = [
- "clap",
- "escape8259",
- "termcolor",
- "threadpool",
-]
-
 [[package]]
 name = "linux-raw-sys"
 version = "0.3.8"
@@ -427,16 +265,6 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
 
-[[package]]
-name = "num_cpus"
-version = "1.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
-dependencies = [
- "hermit-abi",
- "libc",
-]
-
 [[package]]
 name = "once_cell"
 version = "1.19.0"
@@ -471,41 +299,12 @@ dependencies = [
  "proc-macro2",
 ]
 
-[[package]]
-name = "regex"
-version = "1.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
 [[package]]
 name = "regex-lite"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
 
-[[package]]
-name = "regex-syntax"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
-
 [[package]]
 name = "rustix"
 version = "0.37.27"
@@ -520,27 +319,12 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
-[[package]]
-name = "rustversion"
-version = "1.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
-
 [[package]]
 name = "ryu"
 version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
-[[package]]
-name = "same-file"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
-dependencies = [
- "winapi-util",
-]
-
 [[package]]
 name = "serde"
 version = "1.0.219"
@@ -572,15 +356,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "serde_spanned"
-version = "0.6.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
-dependencies = [
- "serde",
-]
-
 [[package]]
 name = "similar"
 version = "2.5.0"
@@ -593,7 +368,7 @@ version = "0.6.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "96dcfc4581e3355d70ac2ee14cfdf81dce3d85c85f1ed9e2c1d3013f53b3436b"
 dependencies = [
- "anstream 0.6.18",
+ "anstream",
  "anstyle",
  "anstyle-svg",
  "escargot",
@@ -613,15 +388,9 @@ version = "0.3.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af"
 dependencies = [
- "anstream 0.6.18",
+ "anstream",
 ]
 
-[[package]]
-name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
 [[package]]
 name = "syn"
 version = "2.0.86"
@@ -633,15 +402,6 @@ dependencies = [
  "unicode-ident",
 ]
 
-[[package]]
-name = "termcolor"
-version = "1.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
-dependencies = [
- "winapi-util",
-]
-
 [[package]]
 name = "terminal_size"
 version = "0.2.6"
@@ -652,70 +412,6 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
-[[package]]
-name = "thread_local"
-version = "1.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
-dependencies = [
- "cfg-if",
- "once_cell",
-]
-
-[[package]]
-name = "threadpool"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
-dependencies = [
- "num_cpus",
-]
-
-[[package]]
-name = "toml"
-version = "0.8.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
-dependencies = [
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_edit",
-]
-
-[[package]]
-name = "toml_datetime"
-version = "0.6.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "toml_edit"
-version = "0.22.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
-dependencies = [
- "indexmap",
- "serde",
- "serde_spanned",
- "toml_datetime",
- "winnow",
-]
-
-[[package]]
-name = "tryfn"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fe242ee9e646acec9ab73a5c540e8543ed1b107f0ce42be831e0775d423c396"
-dependencies = [
- "ignore",
- "libtest-mimic",
- "snapbox",
-]
-
 [[package]]
 name = "unicode-ident"
 version = "1.0.12"
@@ -755,25 +451,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "walkdir"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
-dependencies = [
- "same-file",
- "winapi-util",
-]
-
-[[package]]
-name = "winapi-util"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
-dependencies = [
- "windows-sys 0.52.0",
-]
-
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
@@ -921,12 +598,3 @@ name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
-[[package]]
-name = "winnow"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1"
-dependencies = [
- "memchr",
-]
diff --git a/Cargo.toml b/Cargo.toml
index f30c64f..8434567 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -123,22 +123,13 @@ unicode-width = "0.2.0"
 [dev-dependencies]
 annotate-snippets = { path = ".", features = ["testing-colors"] }
 anstream = "0.6.13"
-difference = "2.0.0"
 divan = "0.1.14"
-glob = "0.3.1"
-serde = { version = "1.0.199", features = ["derive"] }
 snapbox = { version = "0.6.0", features = ["diff", "term-svg", "cmd", "examples"] }
-toml = "0.8.0"
-tryfn = "0.2.1"
 
 [[bench]]
 name = "bench"
 harness = false
 
-[[test]]
-name = "fixtures"
-harness = false
-
 [features]
 default = []
 simd = ["memchr"]


Test patch:
diff --git a/tests/color/ann_eof.rs b/tests/color/ann_eof.rs
new file mode 100644
index 0000000..00e34b1
--- /dev/null
+++ b/tests/color/ann_eof.rs
@@ -0,0 +1,18 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let input = Level::ERROR.header("expected `.`, `=`").group(
+        Group::new().element(
+            Snippet::source("asdf")
+                .origin("Cargo.toml")
+                .line_start(1)
+                .annotation(AnnotationKind::Primary.span(4..4).label("")),
+        ),
+    );
+    let expected = file!["ann_eof.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/ann_eof.svg b/tests/color/ann_eof.term.svg
similarity index 100%
rename from tests/fixtures/color/ann_eof.svg
rename to tests/color/ann_eof.term.svg
diff --git a/tests/color/ann_insertion.rs b/tests/color/ann_insertion.rs
new file mode 100644
index 0000000..802a0c7
--- /dev/null
+++ b/tests/color/ann_insertion.rs
@@ -0,0 +1,18 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let input = Level::ERROR.header("expected `.`, `=`").group(
+        Group::new().element(
+            Snippet::source("asf")
+                .origin("Cargo.toml")
+                .line_start(1)
+                .annotation(AnnotationKind::Primary.span(2..2).label("'d' belongs here")),
+        ),
+    );
+    let expected = file!["ann_insertion.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/ann_insertion.svg b/tests/color/ann_insertion.term.svg
similarity index 100%
rename from tests/fixtures/color/ann_insertion.svg
rename to tests/color/ann_insertion.term.svg
diff --git a/tests/color/ann_multiline.rs b/tests/color/ann_multiline.rs
new file mode 100644
index 0000000..4b561ed
--- /dev/null
+++ b/tests/color/ann_multiline.rs
@@ -0,0 +1,31 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#"                        if let DisplayLine::Source {
+                            ref mut inline_marks,
+                        } = body[body_idx]
+"#;
+
+    let input = Level::ERROR
+        .header("pattern does not mention fields `lineno`, `content`")
+        .id("E0027")
+        .group(
+            Group::new().element(
+                Snippet::source(source)
+                    .origin("src/display_list.rs")
+                    .line_start(139)
+                    .fold(false)
+                    .annotation(
+                        AnnotationKind::Primary
+                            .span(31..128)
+                            .label("missing fields `lineno`, `content`"),
+                    ),
+            ),
+        );
+    let expected = file!["ann_multiline.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/ann_multiline.svg b/tests/color/ann_multiline.term.svg
similarity index 100%
rename from tests/fixtures/color/ann_multiline.svg
rename to tests/color/ann_multiline.term.svg
diff --git a/tests/color/ann_multiline2.rs b/tests/color/ann_multiline2.rs
new file mode 100644
index 0000000..9996fa9
--- /dev/null
+++ b/tests/color/ann_multiline2.rs
@@ -0,0 +1,31 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#"This is an example
+of an edge case of an annotation overflowing
+to exactly one character on next line.
+"#;
+
+    let input = Level::ERROR
+        .header("spacing error found")
+        .id("E####")
+        .group(
+            Group::new().element(
+                Snippet::source(source)
+                    .origin("foo.txt")
+                    .line_start(26)
+                    .fold(false)
+                    .annotation(
+                        AnnotationKind::Primary
+                            .span(11..19)
+                            .label("this should not be on separate lines"),
+                    ),
+            ),
+        );
+    let expected = file!["ann_multiline2.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/ann_multiline2.svg b/tests/color/ann_multiline2.term.svg
similarity index 100%
rename from tests/fixtures/color/ann_multiline2.svg
rename to tests/color/ann_multiline2.term.svg
diff --git a/tests/color/ann_removed_nl.rs b/tests/color/ann_removed_nl.rs
new file mode 100644
index 0000000..45a6462
--- /dev/null
+++ b/tests/color/ann_removed_nl.rs
@@ -0,0 +1,18 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let input = Level::ERROR.header("expected `.`, `=`").group(
+        Group::new().element(
+            Snippet::source("asdf")
+                .origin("Cargo.toml")
+                .line_start(1)
+                .annotation(AnnotationKind::Primary.span(4..5).label("")),
+        ),
+    );
+    let expected = file!["ann_removed_nl.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/ann_removed_nl.svg b/tests/color/ann_removed_nl.term.svg
similarity index 100%
rename from tests/fixtures/color/ann_removed_nl.svg
rename to tests/color/ann_removed_nl.term.svg
diff --git a/tests/color/ensure_emoji_highlight_width.rs b/tests/color/ensure_emoji_highlight_width.rs
new file mode 100644
index 0000000..b239784
--- /dev/null
+++ b/tests/color/ensure_emoji_highlight_width.rs
@@ -0,0 +1,24 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#""haha this isn't a valid name 🐛" = { package = "libc", version = "0.1" }
+"#;
+
+    let input = Level::ERROR.header("invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)")
+        .group(
+            Group::new()
+                .element(
+                    Snippet::source(source)
+                        .origin("<file>")
+                        .line_start(7)
+                        .annotation(AnnotationKind::Primary.span(0..35).label(""))
+                )
+            )
+;
+    let expected = file!["ensure_emoji_highlight_width.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/ensure-emoji-highlight-width.svg b/tests/color/ensure_emoji_highlight_width.term.svg
similarity index 100%
rename from tests/fixtures/color/ensure-emoji-highlight-width.svg
rename to tests/color/ensure_emoji_highlight_width.term.svg
diff --git a/tests/color/fold_ann_multiline.rs b/tests/color/fold_ann_multiline.rs
new file mode 100644
index 0000000..3995b68
--- /dev/null
+++ b/tests/color/fold_ann_multiline.rs
@@ -0,0 +1,50 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#") -> Option<String> {
+    for ann in annotations {
+        match (ann.range.0, ann.range.1) {
+            (None, None) => continue,
+            (Some(start), Some(end)) if start > end_index || end < start_index => continue,
+            (Some(start), Some(end)) if start >= start_index && end <= end_index => {
+                let label = if let Some(ref label) = ann.label {
+                    format!(" {}", label)
+                } else {
+                    String::from("")
+                };
+
+                return Some(format!(
+                    "{}{}{}",
+                    " ".repeat(start - start_index),
+                    "^".repeat(end - start),
+                    label
+                ));
+            }
+            _ => continue,
+        }
+    }
+"#;
+
+    let input = Level::ERROR.header("mismatched types").id("E0308").group(
+        Group::new().element(
+            Snippet::source(source)
+                .origin("src/format.rs")
+                .line_start(51)
+                .fold(true)
+                .annotation(AnnotationKind::Context.span(5..19).label(
+                    "expected `std::option::Option<std::string::String>` because of return type",
+                ))
+                .annotation(
+                    AnnotationKind::Primary
+                        .span(22..766)
+                        .label("expected enum `std::option::Option`, found ()"),
+                ),
+        ),
+    );
+    let expected = file!["fold_ann_multiline.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/fold_ann_multiline.svg b/tests/color/fold_ann_multiline.term.svg
similarity index 100%
rename from tests/fixtures/color/fold_ann_multiline.svg
rename to tests/color/fold_ann_multiline.term.svg
diff --git a/tests/color/fold_bad_origin_line.rs b/tests/color/fold_bad_origin_line.rs
new file mode 100644
index 0000000..1a21a5e
--- /dev/null
+++ b/tests/color/fold_bad_origin_line.rs
@@ -0,0 +1,24 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#"
+
+invalid syntax
+"#;
+
+    let input = Level::ERROR.header("").group(
+        Group::new().element(
+            Snippet::source(source)
+                .origin("path/to/error.rs")
+                .line_start(1)
+                .fold(true)
+                .annotation(AnnotationKind::Context.span(2..16).label("error here")),
+        ),
+    );
+    let expected = file!["fold_bad_origin_line.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/fold_bad_origin_line.svg b/tests/color/fold_bad_origin_line.term.svg
similarity index 100%
rename from tests/fixtures/color/fold_bad_origin_line.svg
rename to tests/color/fold_bad_origin_line.term.svg
diff --git a/tests/color/fold_leading.rs b/tests/color/fold_leading.rs
new file mode 100644
index 0000000..93ba499
--- /dev/null
+++ b/tests/color/fold_leading.rs
@@ -0,0 +1,35 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#"[workspace]
+
+[package]
+name = "hello"
+version = "1.0.0"
+license = "MIT"
+rust-version = "1.70"
+edition = "2021"
+
+[lints]
+workspace = 20
+"#;
+
+    let input = Level::ERROR
+        .header("invalid type: integer `20`, expected a bool")
+        .id("E0308")
+        .group(
+            Group::new().element(
+                Snippet::source(source)
+                    .origin("Cargo.toml")
+                    .line_start(1)
+                    .fold(true)
+                    .annotation(AnnotationKind::Primary.span(132..134).label("")),
+            ),
+        );
+    let expected = file!["fold_leading.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/fold_leading.svg b/tests/color/fold_leading.term.svg
similarity index 100%
rename from tests/fixtures/color/fold_leading.svg
rename to tests/color/fold_leading.term.svg
diff --git a/tests/color/fold_trailing.rs b/tests/color/fold_trailing.rs
new file mode 100644
index 0000000..f86ade7
--- /dev/null
+++ b/tests/color/fold_trailing.rs
@@ -0,0 +1,34 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#"lints = 20
+
+[workspace]
+
+[package]
+name = "hello"
+version = "1.0.0"
+license = "MIT"
+rust-version = "1.70"
+edition = "2021"
+"#;
+
+    let input = Level::ERROR
+        .header("invalid type: integer `20`, expected a lints table")
+        .id("E0308")
+        .group(
+            Group::new().element(
+                Snippet::source(source)
+                    .origin("Cargo.toml")
+                    .line_start(1)
+                    .fold(true)
+                    .annotation(AnnotationKind::Primary.span(8..10).label("")),
+            ),
+        );
+    let expected = file!["fold_trailing.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/fold_trailing.svg b/tests/color/fold_trailing.term.svg
similarity index 100%
rename from tests/fixtures/color/fold_trailing.svg
rename to tests/color/fold_trailing.term.svg
diff --git a/tests/color/issue_9.rs b/tests/color/issue_9.rs
new file mode 100644
index 0000000..2accd2f
--- /dev/null
+++ b/tests/color/issue_9.rs
@@ -0,0 +1,31 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let input = Level::ERROR.header("expected one of `.`, `;`, `?`, or an operator, found `for`")
+        .group(
+            Group::new()
+                .element(
+                    Snippet::source("let x = vec![1];")
+                        .origin("/code/rust/src/test/ui/annotate-snippet/suggestion.rs")
+                        .line_start(4)
+                        .annotation(AnnotationKind::Context.span(4..5).label("move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait"))
+                )
+                .element(
+                    Snippet::source("let y = x;")
+                        .line_start(7)
+                        .annotation(AnnotationKind::Context.span(8..9).label("value moved here"))
+                )
+                .element(
+                    Snippet::source("x;")
+                        .line_start(9)
+                        .annotation(AnnotationKind::Primary.span(0..1).label("value used here after move"))
+                )
+            )
+;
+    let expected = file!["issue_9.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/issue_9.svg b/tests/color/issue_9.term.svg
similarity index 100%
rename from tests/fixtures/color/issue_9.svg
rename to tests/color/issue_9.term.svg
diff --git a/tests/color/main.rs b/tests/color/main.rs
new file mode 100644
index 0000000..f954bb7
--- /dev/null
+++ b/tests/color/main.rs
@@ -0,0 +1,16 @@
+mod ann_eof;
+mod ann_insertion;
+mod ann_multiline;
+mod ann_multiline2;
+mod ann_removed_nl;
+mod ensure_emoji_highlight_width;
+mod fold_ann_multiline;
+mod fold_bad_origin_line;
+mod fold_leading;
+mod fold_trailing;
+mod issue_9;
+mod multiple_annotations;
+mod simple;
+mod strip_line;
+mod strip_line_char;
+mod strip_line_non_ws;
diff --git a/tests/color/multiple_annotations.rs b/tests/color/multiple_annotations.rs
new file mode 100644
index 0000000..b568b91
--- /dev/null
+++ b/tests/color/multiple_annotations.rs
@@ -0,0 +1,42 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#"fn add_title_line(result: &mut Vec<String>, main_annotation: Option<&Annotation>) {
+    if let Some(annotation) = main_annotation {
+        result.push(format_title_line(
+            &annotation.annotation_type,
+            None,
+            &annotation.label,
+        ));
+    }
+}
+"#;
+
+    let input = Level::ERROR.header("").group(
+        Group::new().element(
+            Snippet::source(source)
+                .line_start(96)
+                .annotation(
+                    AnnotationKind::Primary
+                        .span(100..110)
+                        .label("Variable defined here"),
+                )
+                .annotation(
+                    AnnotationKind::Primary
+                        .span(184..194)
+                        .label("Referenced here"),
+                )
+                .annotation(
+                    AnnotationKind::Primary
+                        .span(243..253)
+                        .label("Referenced again here"),
+                ),
+        ),
+    );
+    let expected = file!["multiple_annotations.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/multiple_annotations.svg b/tests/color/multiple_annotations.term.svg
similarity index 100%
rename from tests/fixtures/color/multiple_annotations.svg
rename to tests/color/multiple_annotations.term.svg
diff --git a/tests/color/simple.rs b/tests/color/simple.rs
new file mode 100644
index 0000000..35e83d3
--- /dev/null
+++ b/tests/color/simple.rs
@@ -0,0 +1,34 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#"        })
+
+        for line in &self.body {
+"#;
+
+    let input = Level::ERROR
+        .header("expected one of `.`, `;`, `?`, or an operator, found `for`")
+        .group(
+            Group::new().element(
+                Snippet::source(source)
+                    .origin("src/format_color.rs")
+                    .line_start(169)
+                    .annotation(
+                        AnnotationKind::Primary
+                            .span(20..23)
+                            .label("unexpected token"),
+                    )
+                    .annotation(
+                        AnnotationKind::Context
+                            .span(10..11)
+                            .label("expected one of `.`, `;`, `?`, or an operator here"),
+                    ),
+            ),
+        );
+    let expected = file!["simple.term.svg"];
+    let renderer = Renderer::styled();
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/simple.svg b/tests/color/simple.term.svg
similarity index 100%
rename from tests/fixtures/color/simple.svg
rename to tests/color/simple.term.svg
diff --git a/tests/color/strip_line.rs b/tests/color/strip_line.rs
new file mode 100644
index 0000000..fd1ba58
--- /dev/null
+++ b/tests/color/strip_line.rs
@@ -0,0 +1,24 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#"                                                                                                                                                                                    let _: () = 42;"#;
+
+    let input = Level::ERROR.header("mismatched types").id("E0308").group(
+        Group::new().element(
+            Snippet::source(source)
+                .origin("$DIR/whitespace-trimming.rs")
+                .line_start(4)
+                .annotation(
+                    AnnotationKind::Primary
+                        .span(192..194)
+                        .label("expected (), found integer"),
+                ),
+        ),
+    );
+    let expected = file!["strip_line.term.svg"];
+    let renderer = Renderer::styled().anonymized_line_numbers(true);
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/strip_line.svg b/tests/color/strip_line.term.svg
similarity index 100%
rename from tests/fixtures/color/strip_line.svg
rename to tests/color/strip_line.term.svg
diff --git a/tests/color/strip_line_char.rs b/tests/color/strip_line_char.rs
new file mode 100644
index 0000000..df609e2
--- /dev/null
+++ b/tests/color/strip_line_char.rs
@@ -0,0 +1,24 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#"                                                                                                                                                                                    let _: () = 42ñ"#;
+
+    let input = Level::ERROR.header("mismatched types").id("E0308").group(
+        Group::new().element(
+            Snippet::source(source)
+                .origin("$DIR/whitespace-trimming.rs")
+                .line_start(4)
+                .annotation(
+                    AnnotationKind::Primary
+                        .span(192..194)
+                        .label("expected (), found integer"),
+                ),
+        ),
+    );
+    let expected = file!["strip_line_char.term.svg"];
+    let renderer = Renderer::styled().anonymized_line_numbers(true);
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/strip_line_char.svg b/tests/color/strip_line_char.term.svg
similarity index 100%
rename from tests/fixtures/color/strip_line_char.svg
rename to tests/color/strip_line_char.term.svg
diff --git a/tests/color/strip_line_non_ws.rs b/tests/color/strip_line_non_ws.rs
new file mode 100644
index 0000000..f82d369
--- /dev/null
+++ b/tests/color/strip_line_non_ws.rs
@@ -0,0 +1,30 @@
+use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
+
+use snapbox::{assert_data_eq, file};
+
+#[test]
+fn case() {
+    let source = r#"	let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = ();
+"#;
+
+    let input = Level::ERROR.header("mismatched types").id("E0308").group(
+        Group::new().element(
+            Snippet::source(source)
+                .origin("$DIR/non-whitespace-trimming.rs")
+                .line_start(4)
+                .annotation(
+                    AnnotationKind::Primary
+                        .span(237..239)
+                        .label("expected `()`, found integer"),
+                )
+                .annotation(
+                    AnnotationKind::Primary
+                        .span(232..234)
+                        .label("expected due to this"),
+                ),
+        ),
+    );
+    let expected = file!["strip_line_non_ws.term.svg"];
+    let renderer = Renderer::styled().anonymized_line_numbers(true);
+    assert_data_eq!(renderer.render(input), expected);
+}
diff --git a/tests/fixtures/color/strip_line_non_ws.svg b/tests/color/strip_line_non_ws.term.svg
similarity index 100%
rename from tests/fixtures/color/strip_line_non_ws.svg
rename to tests/color/strip_line_non_ws.term.svg
diff --git a/tests/fixtures/color/ann_eof.toml b/tests/fixtures/color/ann_eof.toml
deleted file mode 100644
index ef711de..0000000
--- a/tests/fixtures/color/ann_eof.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[message]
-level = "Error"
-header = "expected `.`, `=`"
-
-[[message.sections]]
-type = "Cause"
-source = "asdf"
-line_start = 1
-origin = "Cargo.toml"
-annotations = [
-  { label = "", kind = "Primary", range = [4, 4] },
-]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/ann_insertion.toml b/tests/fixtures/color/ann_insertion.toml
deleted file mode 100644
index 30af1bf..0000000
--- a/tests/fixtures/color/ann_insertion.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[message]
-level = "Error"
-header = "expected `.`, `=`"
-
-[[message.sections]]
-type = "Cause"
-source = "asf"
-line_start = 1
-origin = "Cargo.toml"
-annotations = [
-    { label = "'d' belongs here", kind = "Primary", range = [2, 2] }
-]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/ann_multiline.toml b/tests/fixtures/color/ann_multiline.toml
deleted file mode 100644
index 2a5f206..0000000
--- a/tests/fixtures/color/ann_multiline.toml
+++ /dev/null
@@ -1,21 +0,0 @@
-[message]
-level = "Error"
-id = "E0027"
-header = "pattern does not mention fields `lineno`, `content`"
-
-[[message.sections]]
-type = "Cause"
-source = """
-                        if let DisplayLine::Source {
-                            ref mut inline_marks,
-                        } = body[body_idx]
-"""
-line_start = 139
-origin = "src/display_list.rs"
-fold = false
-annotations = [
-    { label = "missing fields `lineno`, `content`", kind = "Primary", range = [31, 128] }
-]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/ann_multiline2.toml b/tests/fixtures/color/ann_multiline2.toml
deleted file mode 100644
index 854b38a..0000000
--- a/tests/fixtures/color/ann_multiline2.toml
+++ /dev/null
@@ -1,21 +0,0 @@
-[message]
-level = "Error"
-id = "E####"
-header = "spacing error found"
-
-[[message.sections]]
-type = "Cause"
-source = """
-This is an example
-of an edge case of an annotation overflowing
-to exactly one character on next line.
-"""
-line_start = 26
-origin = "foo.txt"
-fold = false
-annotations = [
-    { label = "this should not be on separate lines", kind = "Primary", range = [11, 19] },
-]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/ann_removed_nl.toml b/tests/fixtures/color/ann_removed_nl.toml
deleted file mode 100644
index 6ffeb7a..0000000
--- a/tests/fixtures/color/ann_removed_nl.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[message]
-level = "Error"
-header = "expected `.`, `=`"
-
-[[message.sections]]
-type = "Cause"
-source = "asdf"
-line_start = 1
-origin = "Cargo.toml"
-annotations = [
-    { label = "", kind = "Primary", range = [4, 5] },
-]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/ensure-emoji-highlight-width.toml b/tests/fixtures/color/ensure-emoji-highlight-width.toml
deleted file mode 100644
index 669959f..0000000
--- a/tests/fixtures/color/ensure-emoji-highlight-width.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[message]
-header = "invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)"
-level = "Error"
-
-
-[[message.sections]]
-type = "Cause"
-source = """
-"haha this isn't a valid name 🐛" = { package = "libc", version = "0.1" }
-"""
-line_start = 7
-origin = "<file>"
-annotations = [
-    { label = "", kind = "Primary", range = [0, 35] },
-]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/fold_ann_multiline.toml b/tests/fixtures/color/fold_ann_multiline.toml
deleted file mode 100644
index 2cee27d..0000000
--- a/tests/fixtures/color/fold_ann_multiline.toml
+++ /dev/null
@@ -1,41 +0,0 @@
-[message]
-level = "Error"
-id = "E0308"
-header = "mismatched types"
-
-[[message.sections]]
-type = "Cause"
-source = """
-) -> Option<String> {
-    for ann in annotations {
-        match (ann.range.0, ann.range.1) {
-            (None, None) => continue,
-            (Some(start), Some(end)) if start > end_index || end < start_index => continue,
-            (Some(start), Some(end)) if start >= start_index && end <= end_index => {
-                let label = if let Some(ref label) = ann.label {
-                    format!(" {}", label)
-                } else {
-                    String::from("")
-                };
-
-                return Some(format!(
-                    "{}{}{}",
-                    " ".repeat(start - start_index),
-                    "^".repeat(end - start),
-                    label
-                ));
-            }
-            _ => continue,
-        }
-    }
-"""
-line_start = 51
-origin = "src/format.rs"
-fold = true
-annotations = [
-    { label = "expected `std::option::Option<std::string::String>` because of return type", kind = "Context", range = [5, 19] },
-    { label = "expected enum `std::option::Option`, found ()", kind = "Primary", range = [22, 766] },
-]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/fold_bad_origin_line.toml b/tests/fixtures/color/fold_bad_origin_line.toml
deleted file mode 100644
index 2fab2d6..0000000
--- a/tests/fixtures/color/fold_bad_origin_line.toml
+++ /dev/null
@@ -1,20 +0,0 @@
-[message]
-level = "Error"
-header = ""
-
-[[message.sections]]
-type = "Cause"
-source = """
-
-
-invalid syntax
-"""
-line_start = 1
-origin = "path/to/error.rs"
-fold = true
-annotations = [
-    { label = "error here", kind = "Context", range = [2,16] },
-]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/fold_leading.toml b/tests/fixtures/color/fold_leading.toml
deleted file mode 100644
index 0ef043c..0000000
--- a/tests/fixtures/color/fold_leading.toml
+++ /dev/null
@@ -1,29 +0,0 @@
-[message]
-level = "Error"
-id = "E0308"
-header = "invalid type: integer `20`, expected a bool"
-
-[[message.sections]]
-type = "Cause"
-source = """
-[workspace]
-
-[package]
-name = "hello"
-version = "1.0.0"
-license = "MIT"
-rust-version = "1.70"
-edition = "2021"
-
-[lints]
-workspace = 20
-"""
-line_start = 1
-origin = "Cargo.toml"
-fold = true
-annotations = [
-    { label = "", kind = "Primary", range = [132, 134] },
-]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/fold_trailing.toml b/tests/fixtures/color/fold_trailing.toml
deleted file mode 100644
index 91e4ab4..0000000
--- a/tests/fixtures/color/fold_trailing.toml
+++ /dev/null
@@ -1,28 +0,0 @@
-[message]
-level = "Error"
-id = "E0308"
-header = "invalid type: integer `20`, expected a lints table"
-
-[[message.sections]]
-type = "Cause"
-source = """
-lints = 20
-
-[workspace]
-
-[package]
-name = "hello"
-version = "1.0.0"
-license = "MIT"
-rust-version = "1.70"
-edition = "2021"
-"""
-line_start = 1
-origin = "Cargo.toml"
-fold = true
-annotations = [
-    { label = "", kind = "Primary", range = [8, 10] },
-]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/issue_9.toml b/tests/fixtures/color/issue_9.toml
deleted file mode 100644
index f423915..0000000
--- a/tests/fixtures/color/issue_9.toml
+++ /dev/null
@@ -1,34 +0,0 @@
-[message]
-level = "Error"
-header = "expected one of `.`, `;`, `?`, or an operator, found `for`"
-
-[[message.sections]]
-type = "Cause"
-source = "let x = vec![1];"
-line_start = 4
-origin = "/code/rust/src/test/ui/annotate-snippet/suggestion.rs"
-[[message.sections.annotations]]
-label = "move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait"
-kind = "Context"
-range = [4, 5]
-
-[[message.sections]]
-type = "Cause"
-source = "let y = x;"
-line_start = 7
-[[message.sections.annotations]]
-label = "value moved here"
-kind = "Context"
-range = [8, 9]
-
-[[message.sections]]
-type = "Cause"
-source = "x;"
-line_start = 9
-[[message.sections.annotations]]
-label = "value used here after move"
-kind = "Primary"
-range = [0, 1]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/multiple_annotations.toml b/tests/fixtures/color/multiple_annotations.toml
deleted file mode 100644
index 367c53e..0000000
--- a/tests/fixtures/color/multiple_annotations.toml
+++ /dev/null
@@ -1,33 +0,0 @@
-[message]
-level = "Error"
-header = ""
-
-[[message.sections]]
-type = "Cause"
-source = """
-fn add_title_line(result: &mut Vec<String>, main_annotation: Option<&Annotation>) {
-    if let Some(annotation) = main_annotation {
-        result.push(format_title_line(
-            &annotation.annotation_type,
-            None,
-            &annotation.label,
-        ));
-    }
-}
-"""
-line_start = 96
-[[message.sections.annotations]]
-label = "Variable defined here"
-kind = "Primary"
-range = [100, 110]
-[[message.sections.annotations]]
-label = "Referenced here"
-kind = "Primary"
-range = [184, 194]
-[[message.sections.annotations]]
-label = "Referenced again here"
-kind = "Primary"
-range = [243, 253]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/simple.toml b/tests/fixtures/color/simple.toml
deleted file mode 100644
index d5a3647..0000000
--- a/tests/fixtures/color/simple.toml
+++ /dev/null
@@ -1,23 +0,0 @@
-[message]
-level = "Error"
-header = "expected one of `.`, `;`, `?`, or an operator, found `for`"
-
-[[message.sections]]
-type = "Cause"
-source = """
-        })
-
-        for line in &self.body {"""
-line_start = 169
-origin = "src/format_color.rs"
-[[message.sections.annotations]]
-label = "unexpected token"
-kind = "Primary"
-range = [20, 23]
-[[message.sections.annotations]]
-label = "expected one of `.`, `;`, `?`, or an operator here"
-kind = "Context"
-range = [10, 11]
-
-[renderer]
-color = true
diff --git a/tests/fixtures/color/strip_line.toml b/tests/fixtures/color/strip_line.toml
deleted file mode 100644
index 18a7805..0000000
--- a/tests/fixtures/color/strip_line.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[message]
-level = "Error"
-id = "E0308"
-header = "mismatched types"
-
-[[message.sections]]
-type = "Cause"
-source = "                                                                                                                                                                                    let _: () = 42;"
-line_start = 4
-origin = "$DIR/whitespace-trimming.rs"
-
-[[message.sections.annotations]]
-label = "expected (), found integer"
-kind = "Primary"
-range = [192, 194]
-
-[renderer]
-color = true
-anonymized_line_numbers = true
diff --git a/tests/fixtures/color/strip_line_char.toml b/tests/fixtures/color/strip_line_char.toml
deleted file mode 100644
index 3174ced..0000000
--- a/tests/fixtures/color/strip_line_char.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[message]
-level = "Error"
-id = "E0308"
-header = "mismatched types"
-
-[[message.sections]]
-type = "Cause"
-source = "                                                                                                                                                                                    let _: () = 42ñ"
-line_start = 4
-origin = "$DIR/whitespace-trimming.rs"
-
-[[message.sections.annotations]]
-label = "expected (), found integer"
-kind = "Primary"
-range = [192, 194]
-
-[renderer]
-color = true
-anonymized_line_numbers = true
diff --git a/tests/fixtures/color/strip_line_non_ws.toml b/tests/fixtures/color/strip_line_non_ws.toml
deleted file mode 100644
index b7844ec..0000000
--- a/tests/fixtures/color/strip_line_non_ws.toml
+++ /dev/null
@@ -1,27 +0,0 @@
-[message]
-level = "Error"
-id = "E0308"
-header = "mismatched types"
-
-[[message.sections]]
-type = "Cause"
-source = """
-	let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = ();
-"""
-line_start = 4
-origin = "$DIR/non-whitespace-trimming.rs"
-
-[[message.sections.annotations]]
-label = "expected `()`, found integer"
-kind = "Primary"
-range = [237, 239]
-
-[[message.sections.annotations]]
-label = "expected due to this"
-kind = "Primary"
-range = [232, 234]
-
-
-[renderer]
-anonymized_line_numbers = true
-color = true
diff --git a/tests/fixtures/deserialize.rs b/tests/fixtures/deserialize.rs
deleted file mode 100644
index 2042966..0000000
--- a/tests/fixtures/deserialize.rs
+++ /dev/null
@@ -1,217 +0,0 @@
-use serde::Deserialize;
-use std::ops::Range;
-
-use annotate_snippets::renderer::DEFAULT_TERM_WIDTH;
-use annotate_snippets::{
-    Annotation, AnnotationKind, Element, Group, Level, Message, Patch, Renderer, Snippet,
-};
-
-#[derive(Deserialize)]
-pub(crate) struct Fixture {
-    #[serde(default)]
-    pub(crate) renderer: RendererDef,
-    pub(crate) message: MessageDef,
-}
-
-#[derive(Deserialize)]
-pub struct MessageDef {
-    pub level: LevelDef,
-    pub header: String,
-    #[serde(default)]
-    pub id: Option<String>,
-    #[serde(default)]
-    pub sections: Vec<ElementDef>,
-}
-
-impl<'a> From<&'a MessageDef> for Message<'a> {
-    fn from(val: &'a MessageDef) -> Self {
-        let MessageDef {
-            level,
-            header,
-            id,
-            sections,
-        } = val;
-        let mut message = Level::from(level).header(header);
-        if let Some(id) = id {
-            message = message.id(id);
-        }
-
-        message = message.group(Group::new().elements(sections.iter().map(|s| match s {
-            ElementDef::Title(title) => {
-                Element::Title(Level::from(&title.level).title(&title.title))
-            }
-            ElementDef::Cause(cause) => Element::Cause(Snippet::from(cause)),
-            ElementDef::Suggestion(suggestion) => Element::Suggestion(Snippet::from(suggestion)),
-        })));
-        message
-    }
-}
-
-#[derive(Deserialize)]
-#[serde(tag = "type")]
-pub enum ElementDef {
-    Title(TitleDef),
-    Cause(SnippetAnnotationDef),
-    Suggestion(SnippetPatchDef),
-}
-
-impl<'a> From<&'a ElementDef> for Element<'a> {
-    fn from(val: &'a ElementDef) -> Self {
-        match val {
-            ElementDef::Title(title) => {
-                Element::Title(Level::from(&title.level).title(&title.title))
-            }
-            ElementDef::Cause(cause) => Element::Cause(Snippet::from(cause)),
-            ElementDef::Suggestion(suggestion) => Element::Suggestion(Snippet::from(suggestion)),
-        }
-    }
-}
-
-#[derive(Deserialize)]
-pub struct TitleDef {
-    pub title: String,
-    pub level: LevelDef,
-}
-
-#[derive(Deserialize)]
-pub struct SnippetAnnotationDef {
-    pub(crate) origin: Option<String>,
-    pub(crate) line_start: usize,
-    pub(crate) source: String,
-    pub(crate) annotations: Vec<AnnotationDef>,
-    #[serde(default)]
-    pub(crate) fold: bool,
-}
-
-impl<'a> From<&'a SnippetAnnotationDef> for Snippet<'a, Annotation<'a>> {
-    fn from(val: &'a SnippetAnnotationDef) -> Self {
-        let SnippetAnnotationDef {
-            origin,
-            line_start,
-            source,
-            annotations,
-            fold,
-        } = val;
-        let mut snippet = Snippet::source(source).line_start(*line_start).fold(*fold);
-        if let Some(origin) = origin {
-            snippet = snippet.origin(origin);
-        }
-        snippet = snippet.annotations(annotations.iter().map(Into::into));
-        snippet
-    }
-}
-
-#[derive(Deserialize)]
-pub struct AnnotationDef {
-    pub range: Range<usize>,
-    pub label: String,
-    #[serde(with = "AnnotationKindDef")]
-    pub kind: AnnotationKind,
-}
-
-impl<'a> From<&'a AnnotationDef> for Annotation<'a> {
-    fn from(val: &'a AnnotationDef) -> Self {
-        let AnnotationDef { range, label, kind } = val;
-        kind.span(range.start..range.end).label(label)
-    }
-}
-
-#[allow(dead_code)]
-#[derive(Deserialize)]
-#[serde(remote = "AnnotationKind")]
-enum AnnotationKindDef {
-    Primary,
-    Context,
-}
-
-#[derive(Deserialize)]
-pub struct SnippetPatchDef {
-    pub(crate) origin: Option<String>,
-    pub(crate) line_start: usize,
-    pub(crate) source: String,
-    pub(crate) patches: Vec<PatchDef>,
-    #[serde(default)]
-    pub(crate) fold: bool,
-}
-
-impl<'a> From<&'a SnippetPatchDef> for Snippet<'a, Patch<'a>> {
-    fn from(val: &'a SnippetPatchDef) -> Self {
-        let SnippetPatchDef {
-            origin,
-            line_start,
-            source,
-            patches,
-            fold,
-        } = val;
-        let mut snippet = Snippet::source(source).line_start(*line_start).fold(*fold);
-        if let Some(origin) = origin {
-            snippet = snippet.origin(origin);
-        }
-        snippet = snippet.patches(patches.iter().map(Into::into));
-        snippet
-    }
-}
-
-#[derive(Deserialize)]
-pub struct PatchDef {
-    pub range: Range<usize>,
-    pub replacement: String,
-}
-
-impl<'a> From<&'a PatchDef> for Patch<'a> {
-    fn from(val: &'a PatchDef) -> Self {
-        let PatchDef { range, replacement } = val;
-        Patch::new(range.start..range.end, replacement)
-    }
-}
-
-#[allow(dead_code)]
-#[derive(Clone, Copy, Deserialize)]
-pub enum LevelDef {
-    Error,
-    Warning,
-    Info,
-    Note,
-    Help,
-}
-
-impl<'a> From<&'a LevelDef> for Level<'a> {
-    fn from(val: &'a LevelDef) -> Self {
-        match val {
-            LevelDef::Error => Level::ERROR,
-            LevelDef::Warning => Level::WARNING,
-            LevelDef::Info => Level::INFO,
-            LevelDef::Note => Level::NOTE,
-            LevelDef::Help => Level::HELP,
-        }
-    }
-}
-
-#[derive(Default, Deserialize)]
-pub struct RendererDef {
-    #[serde(default)]
-    anonymized_line_numbers: bool,
-    #[serde(default)]
-    term_width: Option<usize>,
-    #[serde(default)]
-    color: bool,
-}
-
-impl From<RendererDef> for Renderer {
-    fn from(val: RendererDef) -> Self {
-        let RendererDef {
-            anonymized_line_numbers,
-            term_width,
-            color,
-        } = val;
-
-        let renderer = if color {
-            Renderer::styled()
-        } else {
-            Renderer::plain()
-        };
-        renderer
-            .anonymized_line_numbers(anonymized_line_numbers)
-            .term_width(term_width.unwrap_or(DEFAULT_TERM_WIDTH))
-    }
-}
diff --git a/tests/fixtures/main.rs b/tests/fixtures/main.rs
deleted file mode 100644
index 2708262..0000000
--- a/tests/fixtures/main.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-mod deserialize;
-
-use crate::deserialize::Fixture;
-use annotate_snippets::{Message, Renderer};
-use snapbox::data::DataFormat;
-use snapbox::Data;
-use std::error::Error;
-
-fn main() {
-    #[cfg(not(windows))]
-    tryfn::Harness::new("tests/fixtures/", setup, test)
-        .select(["*/*.toml"])
-        .test();
-}
-
-fn setup(input_path: std::path::PathBuf) -> tryfn::Case {
-    let parent = input_path
-        .parent()
-        .unwrap()
-        .file_name()
-        .unwrap()
-        .to_str()
-        .unwrap();
-    let file_name = input_path.file_name().unwrap().to_str().unwrap();
-    let name = format!("{parent}/{file_name}");
-    let expected = Data::read_from(&input_path.with_extension("svg"), None);
-    tryfn::Case {
-        name,
-        fixture: input_path,
-        expected,
-    }
-}
-
-fn test(input_path: &std::path::Path) -> Result<Data, Box<dyn Error>> {
-    let src = std::fs::read_to_string(input_path)?;
-    let fixture: Fixture = toml::from_str(&src)?;
-    let renderer: Renderer = fixture.renderer.into();
-    let message: Message<'_> = (&fixture.message).into();
-
-    let actual = renderer.render(message);
-    Ok(Data::from(actual).coerce_to(DataFormat::TermSvg))
-}