+ // Malformed: truncated in length
+ assert_eq!(
+ "lno1pt7s".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: truncated after length
+ assert_eq!(
+ "lno1pgpq".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: truncated in description
+ assert_eq!(
+ "lno1pgpyz".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: invalid offer_chains length
+ assert_eq!(
+ "lno1qgqszzs9g9xyjs69zcssyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsz".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: truncated currency UTF-8
+ assert_eq!(
+ "lno1qcqcqzs9g9xyjs69zcssyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsz".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: invalid currency UTF-8
+ assert_eq!(
+ "lno1qcpgqsg2q4q5cj2rg5tzzqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqg".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: truncated description UTF-8
+ assert_eq!(
+ "lno1pgqcq93pqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqy".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)),
+ );
+
+ // Malformed: invalid description UTF-8
+ assert_eq!(
+ "lno1pgpgqsgkyypqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)),
+ );
+
+ // Malformed: truncated offer_paths
+ assert_eq!(
+ "lno1pgz5znzfgdz3qqgpzcssyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsz".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: zero num_hops in blinded_path
+ assert_eq!(
+ "lno1pgz5znzfgdz3qqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsqzcssyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsz".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: truncated onionmsg_hop in blinded_path
+ assert_eq!(
+ "lno1pgz5znzfgdz3qqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqspqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqgkyypqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: bad first_node_id in blinded_path
+ assert_eq!(
+ "lno1pgz5znzfgdz3qqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqspqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqgqzcssyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsz".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: bad blinding in blinded_path
+ assert_eq!(
+ "lno1pgz5znzfgdz3qqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcpqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqgqzcssyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsz".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: bad blinded_node_id in onionmsg_hop
+ assert_eq!(
+ "lno1pgz5znzfgdz3qqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqspqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqgqzcssyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsz".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::ShortRead)),
+ );
+
+ // Malformed: truncated issuer UTF-8
+ assert_eq!(
+ "lno1pgz5znzfgdz3yqvqzcssyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsz".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)),
+ );
+
+ // Malformed: invalid issuer UTF-8
+ assert_eq!(
+ "lno1pgz5znzfgdz3yq5qgytzzqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqg".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)),
+ );
+
+ // Malformed: invalid offer_node_id
+ assert_eq!(
+ "lno1pgz5znzfgdz3vggzqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvps".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)),
+ );
+
+ // Contains type >= 80
+ assert_eq!(
+ "lno1pgz5znzfgdz3vggzqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgp9qgr0u2xq4dh3kdevrf4zg6hx8a60jv0gxe0ptgyfc6xkryqqqqqqqq".parse::<Offer>(),
+ Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)),
+ );
+
+ // TODO: Resolved in spec https://github.com/lightning/bolts/pull/798/files#r1334851959
+ // Contains unknown feature 22
+ assert!(
+ "lno1pgx9getnwss8vetrw3hhyucvqdqqqqqkyypwa3eyt44h6txtxquqh7lz5djge4afgfjn7k4rgrkuag0jsd5xvxg".parse::<Offer>().is_ok()
+ );
+
+ // Missing offer_description
+ assert_eq!(
+ "lno1zcss9mk8y3wkklfvevcrszlmu23kfrxh49px20665dqwmn4p72pksese".parse::<Offer>(),
+ Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingDescription)),
+ );
+
+ // Missing offer_node_id"
+ assert_eq!(
+ "lno1pgx9getnwss8vetrw3hhyuc".parse::<Offer>(),
+ Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey)),
+ );