#![allow(missing_docs)]
use md_codec::test_vectors as manifest;
use assert_cmd::Command;
fn encode(template: &str) -> String {
let out = Command::cargo_bin("md")
.unwrap()
.args(["encode", template])
.output()
.unwrap();
String::from_utf8(out.stdout)
.unwrap()
.lines()
.next()
.unwrap()
.to_string()
}
fn decode(phrase: &str) -> String {
let out = Command::cargo_bin("md")
.unwrap()
.args(["decode", phrase])
.output()
.unwrap();
String::from_utf8(out.stdout)
.unwrap()
.lines()
.next()
.unwrap()
.to_string()
}
#[test]
fn round_trip_each_manifest_entry() {
for v in manifest::MANIFEST {
if v.force_chunked {
continue;
} let phrase = encode(v.template);
let back = decode(&phrase);
assert_eq!(
back, v.template,
"round-trip mismatch for {}: got {} want {}",
v.name, back, v.template
);
}
}
fn encode_with_path(template: &str, path: &str) -> String {
let out = Command::cargo_bin("md")
.unwrap()
.args(["encode", template, "--path", path])
.output()
.unwrap();
String::from_utf8(out.stdout)
.unwrap()
.lines()
.next()
.unwrap()
.to_string()
}
#[test]
fn tap_two_leaf_round_trips() {
let template = "tr(@0/<0;1>/*,{pk(@1/<0;1>/*),pk(@2/<0;1>/*)})";
let phrase = encode_with_path(template, "48'/0'/0'/2'");
assert!(
phrase.starts_with("md1"),
"encode produced phrase: {phrase}"
);
let decoded = decode(&phrase);
assert_eq!(decoded, template, "round-trip mismatch");
}
#[test]
fn tap_four_leaf_balanced_round_trips() {
let template =
"tr(@0/<0;1>/*,{{pk(@1/<0;1>/*),pk(@2/<0;1>/*)},{pk(@3/<0;1>/*),pk(@4/<0;1>/*)}})";
let phrase = encode_with_path(template, "48'/0'/0'/2'");
assert!(phrase.starts_with("md1"));
let decoded = decode(&phrase);
assert_eq!(decoded, template);
}
#[test]
fn tap_three_leaf_unbalanced_round_trips() {
let template = "tr(@0/<0;1>/*,{pk(@1/<0;1>/*),{pk(@2/<0;1>/*),pk(@3/<0;1>/*)}})";
let phrase = encode_with_path(template, "48'/0'/0'/2'");
assert!(phrase.starts_with("md1"));
let decoded = decode(&phrase);
assert_eq!(decoded, template);
}
#[test]
fn reencode_round_trip_curated_shapes() {
let cases: &[(&str, &str, Option<&str>)] = &[
(
"inheritance_andor_or_i_pkh",
"wsh(andor(pkh(@0/<0;1>/*),after(1200000),or_i(and_v(v:pkh(@1/<0;1>/*),older(4032)),and_v(v:pkh(@2/<0;1>/*),older(32768)))))",
Some("48'/0'/0'/2'"),
),
(
"wsh_and_v_v_pkh_older",
"wsh(and_v(v:pkh(@0/<0;1>/*),older(144)))",
Some("48'/0'/0'/2'"),
),
(
"wsh_or_i_pkh_pkh",
"wsh(or_i(pkh(@0/<0;1>/*),pkh(@1/<0;1>/*)))",
Some("48'/0'/0'/2'"),
),
(
"tap_leaf_and_v_v_pkh_older",
"tr(@0/<0;1>/*,and_v(v:pkh(@1/<0;1>/*),older(144)))",
Some("48'/0'/0'/2'"),
),
];
for (name, template, path) in cases {
let phrase = match path {
Some(p) => encode_with_path(template, p),
None => encode(template),
};
assert!(
phrase.starts_with("md1"),
"[{name}] encode produced non-md1 phrase: {phrase}"
);
let decoded = decode(&phrase);
let phrase_again = match path {
Some(p) => encode_with_path(&decoded, p),
None => encode(&decoded),
};
assert_eq!(
phrase, phrase_again,
"[{name}] re-encode of decoded text produced a different phrase: \
original={phrase}, decoded={decoded}, re-encoded={phrase_again}"
);
}
}
#[test]
fn reencode_round_trip_each_manifest_entry() {
for v in manifest::MANIFEST {
if v.force_chunked {
continue;
}
let phrase = encode(v.template);
let decoded = decode(&phrase);
let phrase_again = encode(&decoded);
assert_eq!(
phrase, phrase_again,
"[{}] re-encode of decoded text produced a different phrase: \
original={phrase}, decoded={decoded}, re-encoded={phrase_again}",
v.name
);
}
}
#[test]
fn wsh_pkh_shorthand_collapse_round_trips() {
let template = "wsh(pkh(@0/<0;1>/*))";
let phrase = encode_with_path(template, "84'/0'/0'");
assert!(
phrase.starts_with("md1"),
"encode produced phrase: {phrase}"
);
let decoded = decode(&phrase);
assert_eq!(decoded, template, "round-trip mismatch");
let phrase_again = encode_with_path(&decoded, "84'/0'/0'");
assert_eq!(
phrase, phrase_again,
"re-encode of decoded text produced a different phrase: \
original={phrase}, decoded={decoded}, re-encoded={phrase_again}"
);
}
#[test]
fn tr_tap_leaf_bare_pk_round_trip() {
let template = "tr(@0/<0;1>/*,pk(@1/<0;1>/*))";
let phrase = encode_with_path(template, "48'/0'/0'/2'");
assert!(
phrase.starts_with("md1"),
"encode produced phrase: {phrase}"
);
let decoded = decode(&phrase);
assert_eq!(decoded, template, "round-trip mismatch");
let phrase_again = encode_with_path(&decoded, "48'/0'/0'/2'");
assert_eq!(
phrase, phrase_again,
"re-encode of decoded text produced a different phrase: \
original={phrase}, decoded={decoded}, re-encoded={phrase_again}"
);
}