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()); -}