diff --git a/Cargo.lock b/Cargo.lock
index abb4aed..c6f61e6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -44,6 +44,12 @@ dependencies = [
"regex-automata",
]
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
[[package]]
name = "clap"
version = "4.0.7"
@@ -81,6 +87,19 @@ dependencies = [
"os_str_bytes",
]
+[[package]]
+name = "console"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
+dependencies = [
+ "encode_unicode",
+ "lazy_static",
+ "libc",
+ "terminal_size",
+ "winapi",
+]
+
[[package]]
name = "difflib"
version = "0.4.0"
@@ -99,6 +118,12 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+[[package]]
+name = "encode_unicode"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+
[[package]]
name = "hard-xml"
version = "1.13.0"
@@ -138,6 +163,19 @@ dependencies = [
"libc",
]
+[[package]]
+name = "insta"
+version = "1.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581d4e3314cae4536e5d22ffd23189d4a374696c5ef733eadafae0ed273fd303"
+dependencies = [
+ "console",
+ "lazy_static",
+ "linked-hash-map",
+ "similar",
+ "yaml-rust",
+]
+
[[package]]
name = "itertools"
version = "0.10.5"
@@ -171,6 +209,12 @@ version = "0.2.134"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb"
+[[package]]
+name = "linked-hash-map"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+
[[package]]
name = "memchr"
version = "2.5.0"
@@ -198,9 +242,11 @@ version = "1.1.4"
dependencies = [
"assert_cmd",
"clap",
+ "insta",
"opml",
"serde",
"serde_json",
+ "test-case",
]
[[package]]
@@ -321,6 +367,12 @@ dependencies = [
"serde",
]
+[[package]]
+name = "similar"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62ac7f900db32bf3fd12e0117dd3dc4da74bc52ebaac97f39668446d89694803"
+
[[package]]
name = "strsim"
version = "0.10.0"
@@ -347,12 +399,44 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "terminal_size"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
[[package]]
name = "termtree"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
+[[package]]
+name = "test-case"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07aea929e9488998b64adc414c29fe5620398f01c2e3f58164122b17e567a6d5"
+dependencies = [
+ "test-case-macros",
+]
+
+[[package]]
+name = "test-case-macros"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c95968eedc6fc4f5c21920e0f4264f78ec5e4c56bb394f319becc1a5830b3e54"
+dependencies = [
+ "cfg-if",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "thiserror"
version = "1.0.37"
@@ -430,3 +514,12 @@ name = "xmlparser"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
+
+[[package]]
+name = "yaml-rust"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
+dependencies = [
+ "linked-hash-map",
+]
diff --git a/opml_cli/Cargo.toml b/opml_cli/Cargo.toml
index 2fd548f..a000fd9 100644
--- a/opml_cli/Cargo.toml
+++ b/opml_cli/Cargo.toml
@@ -32,3 +32,5 @@ features = ["derive"]
[dev-dependencies]
assert_cmd = "2.0.4"
+insta = "1.21.0"
+test-case = "2.2.1"
diff --git a/opml_cli/tests/cli.rs b/opml_cli/tests/cli.rs
new file mode 100644
index 0000000..aa1255e
--- /dev/null
+++ b/opml_cli/tests/cli.rs
@@ -0,0 +1,25 @@
+use {
+ assert_cmd::Command, insta::assert_display_snapshot, test_case::test_case,
+};
+
+const SAMPLE: &str = "tests/sample.opml";
+
+#[test_case(&["--file", SAMPLE, "--json"], "json" ; "json")]
+#[test_case(&["--file", SAMPLE, "--json-pretty"], "json_pretty" ; "json_pretty")]
+#[test_case(&["--file", SAMPLE, "--rss"], "rss" ; "rss")]
+fn test_valid(args: &[&str], name: &str) {
+ let mut cmd = Command::cargo_bin("opml").unwrap();
+ let assert = cmd.args(args).assert().success().code(0);
+ let output = String::from_utf8(assert.get_output().stdout.clone()).unwrap();
+ assert_display_snapshot!(name, output);
+}
+
+#[test_case(&["--rss"], "missing_file" ; "missing_file")]
+#[test_case(&["--file", SAMPLE], "missing_format" ; "missing_format")]
+#[test_case(&["--rss", "--json"], "multiple_formats" ; "multiple_formats")]
+fn test_invalid(args: &[&'static str], name: &str) {
+ let mut cmd = Command::cargo_bin("opml").unwrap();
+ let assert = cmd.args(args).assert().failure().code(2);
+ let output = String::from_utf8(assert.get_output().stderr.clone()).unwrap();
+ assert_display_snapshot!(name, output);
+}
diff --git a/opml_cli/tests/invalid.rs b/opml_cli/tests/invalid.rs
deleted file mode 100644
index 06be6a2..0000000
--- a/opml_cli/tests/invalid.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use std::fs::read_to_string;
-
-use assert_cmd::Command;
-
-const SAMPLE: &str = "tests/samples/youtube.opml";
-
-#[test]
-fn test_missing_file() {
- let mut cmd = Command::cargo_bin("opml").unwrap();
- let assert = cmd.args(&["--rss"]).assert();
-
- assert
- .failure()
- .code(1)
- .stderr(read_to_string("tests/snapshots/missing-file.txt").unwrap());
-}
-
-#[test]
-fn test_missing_format() {
- let mut cmd = Command::cargo_bin("opml").unwrap();
- let assert = cmd.args(&["--file", SAMPLE]).assert();
-
- assert
- .failure()
- .code(1)
- .stderr(read_to_string("tests/snapshots/missing-format.txt").unwrap());
-}
diff --git a/opml_cli/tests/sample.opml b/opml_cli/tests/sample.opml
new file mode 100644
index 0000000..4c5d221
--- /dev/null
+++ b/opml_cli/tests/sample.opml
@@ -0,0 +1,9 @@
+
+
+ Rust Feeds
+
+
+
+
+
+
diff --git a/opml_cli/tests/samples/youtube.opml b/opml_cli/tests/samples/youtube.opml
deleted file mode 100644
index 96a17be..0000000
--- a/opml_cli/tests/samples/youtube.opml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/opml_cli/tests/snapshots/cli__json.snap b/opml_cli/tests/snapshots/cli__json.snap
new file mode 100644
index 0000000..ccf00e5
--- /dev/null
+++ b/opml_cli/tests/snapshots/cli__json.snap
@@ -0,0 +1,6 @@
+---
+source: opml_cli/tests/cli.rs
+expression: output
+---
+{"version":"2.0","head":{"title":"Rust Feeds","date_created":null,"date_modified":null,"owner_name":null,"owner_email":null,"owner_id":null,"docs":null,"expansion_state":null,"vert_scroll_state":null,"window_top":null,"window_left":null,"window_bottom":null,"window_right":null},"body":{"outlines":[{"text":"Rust Blog","type":null,"is_comment":null,"is_breakpoint":null,"created":null,"category":null,"outlines":[],"xml_url":"https://blog.rust-lang.org/feed.xml","description":null,"html_url":null,"language":null,"title":null,"version":null,"url":null},{"text":"Inside Rust","type":null,"is_comment":null,"is_breakpoint":null,"created":null,"category":null,"outlines":[],"xml_url":"https://blog.rust-lang.org/inside-rust/feed.xml","description":null,"html_url":null,"language":null,"title":null,"version":null,"url":null}]}}
+
diff --git a/opml_cli/tests/snapshots/cli__json_pretty.snap b/opml_cli/tests/snapshots/cli__json_pretty.snap
new file mode 100644
index 0000000..192abe1
--- /dev/null
+++ b/opml_cli/tests/snapshots/cli__json_pretty.snap
@@ -0,0 +1,59 @@
+---
+source: opml_cli/tests/cli.rs
+expression: output
+---
+{
+ "version": "2.0",
+ "head": {
+ "title": "Rust Feeds",
+ "date_created": null,
+ "date_modified": null,
+ "owner_name": null,
+ "owner_email": null,
+ "owner_id": null,
+ "docs": null,
+ "expansion_state": null,
+ "vert_scroll_state": null,
+ "window_top": null,
+ "window_left": null,
+ "window_bottom": null,
+ "window_right": null
+ },
+ "body": {
+ "outlines": [
+ {
+ "text": "Rust Blog",
+ "type": null,
+ "is_comment": null,
+ "is_breakpoint": null,
+ "created": null,
+ "category": null,
+ "outlines": [],
+ "xml_url": "https://blog.rust-lang.org/feed.xml",
+ "description": null,
+ "html_url": null,
+ "language": null,
+ "title": null,
+ "version": null,
+ "url": null
+ },
+ {
+ "text": "Inside Rust",
+ "type": null,
+ "is_comment": null,
+ "is_breakpoint": null,
+ "created": null,
+ "category": null,
+ "outlines": [],
+ "xml_url": "https://blog.rust-lang.org/inside-rust/feed.xml",
+ "description": null,
+ "html_url": null,
+ "language": null,
+ "title": null,
+ "version": null,
+ "url": null
+ }
+ ]
+ }
+}
+
diff --git a/opml_cli/tests/snapshots/cli__missing_file.snap b/opml_cli/tests/snapshots/cli__missing_file.snap
new file mode 100644
index 0000000..a281937
--- /dev/null
+++ b/opml_cli/tests/snapshots/cli__missing_file.snap
@@ -0,0 +1,13 @@
+---
+source: opml_cli/tests/cli.rs
+expression: output
+---
+error: The following required arguments were not provided:
+ --file
+ --json
+ --json-pretty
+
+Usage: opml --file --json --json-pretty --rss
+
+For more information try '--help'
+
diff --git a/opml_cli/tests/snapshots/cli__missing_format.snap b/opml_cli/tests/snapshots/cli__missing_format.snap
new file mode 100644
index 0000000..5be2b3f
--- /dev/null
+++ b/opml_cli/tests/snapshots/cli__missing_format.snap
@@ -0,0 +1,13 @@
+---
+source: opml_cli/tests/cli.rs
+expression: output
+---
+error: The following required arguments were not provided:
+ --json
+ --json-pretty
+ --rss
+
+Usage: opml --file --json --json-pretty --rss
+
+For more information try '--help'
+
diff --git a/opml_cli/tests/snapshots/cli__multiple_formats.snap b/opml_cli/tests/snapshots/cli__multiple_formats.snap
new file mode 100644
index 0000000..ec77117
--- /dev/null
+++ b/opml_cli/tests/snapshots/cli__multiple_formats.snap
@@ -0,0 +1,10 @@
+---
+source: opml_cli/tests/cli.rs
+expression: output
+---
+error: The argument '--rss' cannot be used with '--json'
+
+Usage: opml --file --json --json-pretty --rss
+
+For more information try '--help'
+
diff --git a/opml_cli/tests/snapshots/cli__rss.snap b/opml_cli/tests/snapshots/cli__rss.snap
new file mode 100644
index 0000000..752a01d
--- /dev/null
+++ b/opml_cli/tests/snapshots/cli__rss.snap
@@ -0,0 +1,9 @@
+---
+source: opml_cli/tests/cli.rs
+expression: output
+---
+Rust Blog
+https://blog.rust-lang.org/feed.xml
+Inside Rust
+https://blog.rust-lang.org/inside-rust/feed.xml
+
diff --git a/opml_cli/tests/snapshots/json-pretty.json b/opml_cli/tests/snapshots/json-pretty.json
deleted file mode 100644
index 4dd1971..0000000
--- a/opml_cli/tests/snapshots/json-pretty.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "version": "1.1",
- "head": null,
- "body": {
- "outlines": [
- {
- "text": "YouTube Subscriptions",
- "type": null,
- "is_comment": null,
- "is_breakpoint": null,
- "created": null,
- "category": null,
- "outlines": [
- {
- "text": "A YouTube Channel",
- "type": "rss",
- "is_comment": null,
- "is_breakpoint": null,
- "created": null,
- "category": null,
- "outlines": [],
- "xml_url": "https://www.youtube.com/feeds/videos.xml?channel_id=abcdefghijklmnopqrstuvwxyz1",
- "description": null,
- "html_url": null,
- "language": null,
- "title": "A YouTube Channel",
- "version": null,
- "url": null
- },
- {
- "text": "Another YouTube Channel",
- "type": "rss",
- "is_comment": null,
- "is_breakpoint": null,
- "created": null,
- "category": null,
- "outlines": [],
- "xml_url": "https://www.youtube.com/feeds/videos.xml?channel_id=abcdefghijklmnopqrstuvwxyz2",
- "description": null,
- "html_url": null,
- "language": null,
- "title": "Another YouTube Channel",
- "version": null,
- "url": null
- }
- ],
- "xml_url": null,
- "description": null,
- "html_url": null,
- "language": null,
- "title": "YouTube Subscriptions",
- "version": null,
- "url": null
- }
- ]
- }
-}
diff --git a/opml_cli/tests/snapshots/json.json b/opml_cli/tests/snapshots/json.json
deleted file mode 100644
index 993e28c..0000000
--- a/opml_cli/tests/snapshots/json.json
+++ /dev/null
@@ -1 +0,0 @@
-{"version":"1.1","head":null,"body":{"outlines":[{"text":"YouTube Subscriptions","type":null,"is_comment":null,"is_breakpoint":null,"created":null,"category":null,"outlines":[{"text":"A YouTube Channel","type":"rss","is_comment":null,"is_breakpoint":null,"created":null,"category":null,"outlines":[],"xml_url":"https://www.youtube.com/feeds/videos.xml?channel_id=abcdefghijklmnopqrstuvwxyz1","description":null,"html_url":null,"language":null,"title":"A YouTube Channel","version":null,"url":null},{"text":"Another YouTube Channel","type":"rss","is_comment":null,"is_breakpoint":null,"created":null,"category":null,"outlines":[],"xml_url":"https://www.youtube.com/feeds/videos.xml?channel_id=abcdefghijklmnopqrstuvwxyz2","description":null,"html_url":null,"language":null,"title":"Another YouTube Channel","version":null,"url":null}],"xml_url":null,"description":null,"html_url":null,"language":null,"title":"YouTube Subscriptions","version":null,"url":null}]}}
diff --git a/opml_cli/tests/snapshots/missing-file.txt b/opml_cli/tests/snapshots/missing-file.txt
deleted file mode 100644
index 22f0c2c..0000000
--- a/opml_cli/tests/snapshots/missing-file.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-error: The following required arguments were not provided:
- --file
-
-USAGE:
- opml --file <--json|--json-pretty|--rss>
-
-For more information try --help
diff --git a/opml_cli/tests/snapshots/missing-format.txt b/opml_cli/tests/snapshots/missing-format.txt
deleted file mode 100644
index de0ec80..0000000
--- a/opml_cli/tests/snapshots/missing-format.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-error: The following required arguments were not provided:
- <--json|--json-pretty|--rss>
-
-USAGE:
- opml [FLAGS] --file <--json|--json-pretty|--rss>
-
-For more information try --help
diff --git a/opml_cli/tests/snapshots/rss.txt b/opml_cli/tests/snapshots/rss.txt
deleted file mode 100644
index 0bc2bb0..0000000
--- a/opml_cli/tests/snapshots/rss.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-A YouTube Channel
-https://www.youtube.com/feeds/videos.xml?channel_id=abcdefghijklmnopqrstuvwxyz1
-Another YouTube Channel
-https://www.youtube.com/feeds/videos.xml?channel_id=abcdefghijklmnopqrstuvwxyz2
diff --git a/opml_cli/tests/valid.rs b/opml_cli/tests/valid.rs
deleted file mode 100644
index 1012d9c..0000000
--- a/opml_cli/tests/valid.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-use std::fs::read_to_string;
-
-use assert_cmd::Command;
-
-const SAMPLE: &str = "tests/samples/youtube.opml";
-
-#[test]
-fn test_valid_rss() {
- let mut cmd = Command::cargo_bin("opml").unwrap();
- let assert = cmd.args(&["--file", SAMPLE, "--rss"]).assert();
-
- assert
- .success()
- .code(0)
- .stdout(read_to_string("tests/snapshots/rss.txt").unwrap());
-}
-
-#[test]
-fn test_valid_json() {
- let mut cmd = Command::cargo_bin("opml").unwrap();
- let assert = cmd.args(&["--file", SAMPLE, "--json"]).assert();
-
- assert
- .success()
- .code(0)
- .stdout(read_to_string("tests/snapshots/json.json").unwrap());
-}
-
-#[test]
-fn test_valid_json_pretty() {
- let mut cmd = Command::cargo_bin("opml").unwrap();
- let assert = cmd.args(&["--file", SAMPLE, "--json-pretty"]).assert();
-
- assert
- .success()
- .code(0)
- .stdout(read_to_string("tests/snapshots/json-pretty.json").unwrap());
-}