gift_wrap.rs (8310B)
1 mod common; 2 #[path = "../src/test_fixtures.rs"] 3 mod test_fixtures; 4 5 use common::{AUTHOR, EVENT_ID, EVENT_SIG}; 6 use radroots_event::envelope::kind::{KIND_GIFT_WRAP, KIND_MESSAGE}; 7 use radroots_event::social::gift_wrap::{GiftWrap, GiftWrapRecipient}; 8 9 use radroots_event_codec::decode::EventParseError; 10 use radroots_event_codec::decode::gift_wrap::{ 11 data_from_event, gift_wrap_from_tags, parsed_from_event, 12 }; 13 use radroots_event_codec::encode::EventEncodeError; 14 use radroots_event_codec::encode::gift_wrap::{ 15 gift_wrap_build_tags, to_wire_parts, to_wire_parts_with_kind, 16 }; 17 use test_fixtures::RELAY_PRIMARY_WSS; 18 19 fn sample_gift_wrap() -> GiftWrap { 20 GiftWrap { 21 recipient: GiftWrapRecipient { 22 public_key: "pubkey".to_string(), 23 relay_url: Some(RELAY_PRIMARY_WSS.to_string()), 24 }, 25 content: "encrypted".to_string(), 26 expiration: Some(1700000000), 27 } 28 } 29 30 #[test] 31 fn gift_wrap_build_tags_requires_recipient() { 32 let mut gift_wrap = sample_gift_wrap(); 33 gift_wrap.recipient.public_key = " ".to_string(); 34 35 let err = gift_wrap_build_tags(&gift_wrap).unwrap_err(); 36 assert!(matches!( 37 err, 38 EventEncodeError::EmptyRequiredField("recipient.public_key") 39 )); 40 } 41 42 #[test] 43 fn gift_wrap_to_wire_parts_sets_kind_content_and_tags() { 44 let gift_wrap = sample_gift_wrap(); 45 let parts = to_wire_parts(&gift_wrap).unwrap(); 46 47 assert_eq!(parts.kind, KIND_GIFT_WRAP); 48 assert_eq!(parts.content, "encrypted"); 49 assert_eq!( 50 parts.tags, 51 vec![ 52 vec![ 53 "p".to_string(), 54 "pubkey".to_string(), 55 RELAY_PRIMARY_WSS.to_string() 56 ], 57 vec!["expiration".to_string(), "1700000000".to_string()], 58 ] 59 ); 60 } 61 62 #[test] 63 fn gift_wrap_from_tags_rejects_wrong_kind() { 64 let gift_wrap = sample_gift_wrap(); 65 let parts = to_wire_parts(&gift_wrap).unwrap(); 66 67 let err = gift_wrap_from_tags(KIND_MESSAGE, &parts.tags, &parts.content).unwrap_err(); 68 assert!(matches!( 69 err, 70 EventParseError::InvalidKind { 71 expected: "1059", 72 got: KIND_MESSAGE 73 } 74 )); 75 } 76 77 #[test] 78 fn gift_wrap_from_tags_requires_p_tag() { 79 let err = gift_wrap_from_tags(KIND_GIFT_WRAP, &[], "payload").unwrap_err(); 80 assert!(matches!(err, EventParseError::MissingTag("p"))); 81 82 let err = gift_wrap_from_tags(KIND_GIFT_WRAP, &[vec!["p".to_string()]], "payload").unwrap_err(); 83 assert!(matches!(err, EventParseError::InvalidTag("p"))); 84 } 85 86 #[test] 87 fn gift_wrap_from_tags_rejects_invalid_expiration_and_relay() { 88 let err = gift_wrap_from_tags( 89 KIND_GIFT_WRAP, 90 &[ 91 vec![ 92 "p".to_string(), 93 "pubkey".to_string(), 94 RELAY_PRIMARY_WSS.to_string(), 95 ], 96 vec!["expiration".to_string(), " ".to_string()], 97 ], 98 "payload", 99 ) 100 .unwrap_err(); 101 assert!(matches!(err, EventParseError::InvalidTag("expiration"))); 102 103 let err = gift_wrap_from_tags( 104 KIND_GIFT_WRAP, 105 &[ 106 vec![ 107 "p".to_string(), 108 "pubkey".to_string(), 109 RELAY_PRIMARY_WSS.to_string(), 110 ], 111 vec!["expiration".to_string(), "invalid".to_string()], 112 ], 113 "payload", 114 ) 115 .unwrap_err(); 116 assert!(matches!( 117 err, 118 EventParseError::InvalidNumber("expiration", _) 119 )); 120 121 let err = gift_wrap_from_tags( 122 KIND_GIFT_WRAP, 123 &[vec!["p".to_string(), "pubkey".to_string(), " ".to_string()]], 124 "payload", 125 ) 126 .unwrap_err(); 127 assert!(matches!(err, EventParseError::InvalidTag("p"))); 128 } 129 130 #[test] 131 fn gift_wrap_metadata_and_index_from_event_roundtrip() { 132 let gift_wrap = sample_gift_wrap(); 133 let parts = to_wire_parts(&gift_wrap).unwrap(); 134 135 let metadata = data_from_event( 136 "id".to_string(), 137 "author".to_string(), 138 11, 139 parts.kind, 140 parts.content.clone(), 141 parts.tags.clone(), 142 ) 143 .unwrap(); 144 assert_eq!(metadata.id, "id"); 145 assert_eq!(metadata.author, "author"); 146 assert_eq!(metadata.published_at, 11); 147 assert_eq!( 148 metadata.data.recipient.public_key, 149 gift_wrap.recipient.public_key 150 ); 151 assert_eq!( 152 metadata.data.recipient.relay_url, 153 gift_wrap.recipient.relay_url 154 ); 155 assert_eq!(metadata.data.content, gift_wrap.content); 156 assert_eq!(metadata.data.expiration, gift_wrap.expiration); 157 158 let index = parsed_from_event( 159 EVENT_ID.to_string(), 160 AUTHOR.to_string(), 161 11, 162 parts.kind, 163 parts.content, 164 parts.tags, 165 EVENT_SIG.to_string(), 166 ) 167 .unwrap(); 168 assert_eq!(index.event.kind_u32(), KIND_GIFT_WRAP); 169 assert_eq!(index.event.signature_hex(), EVENT_SIG); 170 assert_eq!(index.data.data.recipient.public_key, "pubkey"); 171 } 172 173 #[test] 174 fn gift_wrap_build_tags_handles_optional_expiration_and_invalid_relay() { 175 let mut gift_wrap = sample_gift_wrap(); 176 gift_wrap.expiration = None; 177 let tags = gift_wrap_build_tags(&gift_wrap).unwrap(); 178 assert_eq!( 179 tags, 180 vec![vec![ 181 "p".to_string(), 182 "pubkey".to_string(), 183 RELAY_PRIMARY_WSS.to_string() 184 ]] 185 ); 186 187 let mut gift_wrap = sample_gift_wrap(); 188 gift_wrap.recipient.relay_url = Some(" ".to_string()); 189 let err = gift_wrap_build_tags(&gift_wrap).unwrap_err(); 190 assert!(matches!( 191 err, 192 EventEncodeError::EmptyRequiredField("recipient.relay_url") 193 )); 194 195 let mut gift_wrap = sample_gift_wrap(); 196 gift_wrap.recipient.relay_url = None; 197 let tags = gift_wrap_build_tags(&gift_wrap).unwrap(); 198 assert_eq!(tags[0], vec!["p".to_string(), "pubkey".to_string()]); 199 } 200 201 #[test] 202 fn gift_wrap_to_wire_parts_requires_content_and_accepts_default_kind() { 203 let mut gift_wrap = sample_gift_wrap(); 204 gift_wrap.content = " ".to_string(); 205 let err = to_wire_parts(&gift_wrap).unwrap_err(); 206 assert!(matches!( 207 err, 208 EventEncodeError::EmptyRequiredField("content") 209 )); 210 211 let parts = to_wire_parts_with_kind(&sample_gift_wrap(), KIND_GIFT_WRAP).unwrap(); 212 assert_eq!(parts.kind, KIND_GIFT_WRAP); 213 assert_eq!(parts.content, "encrypted"); 214 215 let mut gift_wrap = sample_gift_wrap(); 216 gift_wrap.recipient.public_key = " ".to_string(); 217 let err = to_wire_parts(&gift_wrap).unwrap_err(); 218 assert!(matches!( 219 err, 220 EventEncodeError::EmptyRequiredField("recipient.public_key") 221 )); 222 } 223 224 #[test] 225 fn gift_wrap_to_wire_parts_with_kind_rejects_wrong_kind() { 226 let err = to_wire_parts_with_kind(&sample_gift_wrap(), KIND_MESSAGE).unwrap_err(); 227 assert!(matches!(err, EventEncodeError::InvalidKind(KIND_MESSAGE))); 228 } 229 230 #[test] 231 fn gift_wrap_from_tags_handles_missing_expiration_and_rejects_empty_fields() { 232 let parsed = gift_wrap_from_tags( 233 KIND_GIFT_WRAP, 234 &[vec!["p".to_string(), "pubkey".to_string()]], 235 "payload", 236 ) 237 .unwrap(); 238 assert_eq!(parsed.recipient.public_key, "pubkey"); 239 assert!(parsed.recipient.relay_url.is_none()); 240 assert!(parsed.expiration.is_none()); 241 242 let err = gift_wrap_from_tags( 243 KIND_GIFT_WRAP, 244 &[vec!["p".to_string(), " ".to_string()]], 245 "payload", 246 ) 247 .unwrap_err(); 248 assert!(matches!(err, EventParseError::InvalidTag("p"))); 249 250 let err = gift_wrap_from_tags( 251 KIND_GIFT_WRAP, 252 &[vec!["p".to_string(), "pubkey".to_string()]], 253 " ", 254 ) 255 .unwrap_err(); 256 assert!(matches!(err, EventParseError::InvalidTag("content"))); 257 } 258 259 #[test] 260 fn gift_wrap_metadata_and_index_propagate_parse_errors() { 261 let tags = vec![vec!["p".to_string(), "pubkey".to_string()]]; 262 let err = data_from_event( 263 "id".to_string(), 264 "author".to_string(), 265 11, 266 KIND_GIFT_WRAP, 267 " ".to_string(), 268 tags.clone(), 269 ) 270 .unwrap_err(); 271 assert!(matches!(err, EventParseError::InvalidTag("content"))); 272 273 let err = parsed_from_event( 274 "id".to_string(), 275 "author".to_string(), 276 11, 277 KIND_GIFT_WRAP, 278 " ".to_string(), 279 tags, 280 "sig".to_string(), 281 ) 282 .unwrap_err(); 283 assert!(matches!(err, EventParseError::InvalidTag("content"))); 284 }