profile.rs (6408B)
1 #![cfg(feature = "serde_json")] 2 3 use radroots_events::{ 4 kinds::{KIND_POST, KIND_PROFILE}, 5 profile::{ 6 RADROOTS_PROFILE_TYPE_TAG_ANY, RADROOTS_PROFILE_TYPE_TAG_COOP, 7 RADROOTS_PROFILE_TYPE_TAG_FARM, RADROOTS_PROFILE_TYPE_TAG_KEY, 8 RADROOTS_PROFILE_TYPE_TAG_RADROOTSD, RadrootsProfileType, 9 }, 10 }; 11 use radroots_events_codec::error::EventParseError; 12 use radroots_events_codec::profile::decode::{ 13 data_from_event, parsed_from_event, profile_from_content, 14 }; 15 16 #[test] 17 fn profile_from_content_parses_bot_boolean() { 18 let content = r#"{"name":"alice","bot":true}"#; 19 let profile = profile_from_content(content).unwrap(); 20 21 assert_eq!(profile.name, "alice"); 22 assert_eq!(profile.bot.as_deref(), Some("true")); 23 } 24 25 #[test] 26 fn profile_from_content_parses_bot_string() { 27 let content = r#"{"name":"alice","bot":"false"}"#; 28 let profile = profile_from_content(content).unwrap(); 29 30 assert_eq!(profile.name, "alice"); 31 assert_eq!(profile.bot.as_deref(), Some("false")); 32 } 33 34 #[test] 35 fn profile_from_content_parses_optional_metadata_and_ignores_invalid_scalars() { 36 let content = r#"{"name":"alice","display_name":"Alice","nip05":"alice@example.test","about":"farm account","website":"https://farm.example.test","picture":"https://farm.example.test/pic.png","banner":"https://farm.example.test/banner.png","lud06":"lnurl1farm","lud16":"alice@example.test","bot":12}"#; 37 let profile = profile_from_content(content).unwrap(); 38 39 assert_eq!(profile.name, "alice"); 40 assert_eq!(profile.display_name.as_deref(), Some("Alice")); 41 assert_eq!(profile.nip05.as_deref(), Some("alice@example.test")); 42 assert_eq!(profile.about.as_deref(), Some("farm account")); 43 assert_eq!( 44 profile.website.as_deref(), 45 Some("https://farm.example.test") 46 ); 47 assert_eq!( 48 profile.picture.as_deref(), 49 Some("https://farm.example.test/pic.png") 50 ); 51 assert_eq!( 52 profile.banner.as_deref(), 53 Some("https://farm.example.test/banner.png") 54 ); 55 assert_eq!(profile.lud06.as_deref(), Some("lnurl1farm")); 56 assert_eq!(profile.lud16.as_deref(), Some("alice@example.test")); 57 assert_eq!(profile.bot, None); 58 } 59 60 #[test] 61 fn profile_from_content_rejects_missing_name() { 62 let content = r#"{"display_name":"alice"}"#; 63 let err = profile_from_content(content).unwrap_err(); 64 assert!(matches!(err, EventParseError::InvalidJson("name"))); 65 } 66 67 #[test] 68 fn profile_from_content_rejects_non_object_json() { 69 let err = profile_from_content("[]").unwrap_err(); 70 assert!(matches!(err, EventParseError::InvalidJson("content"))); 71 } 72 73 #[test] 74 fn profile_from_content_rejects_invalid_json() { 75 let err = profile_from_content("{").unwrap_err(); 76 assert!(matches!(err, EventParseError::InvalidJson("content"))); 77 } 78 79 #[test] 80 fn profile_metadata_rejects_wrong_kind() { 81 let err = data_from_event( 82 "id".to_string(), 83 "author".to_string(), 84 1, 85 1, 86 "{\"name\":\"alice\"}".to_string(), 87 Vec::new(), 88 ) 89 .unwrap_err(); 90 91 assert!(matches!( 92 err, 93 EventParseError::InvalidKind { 94 expected: "0", 95 got: KIND_POST 96 } 97 )); 98 } 99 100 #[test] 101 fn profile_metadata_reads_profile_type_tag() { 102 let metadata = data_from_event( 103 "id".to_string(), 104 "author".to_string(), 105 1, 106 0, 107 "{\"name\":\"alice\"}".to_string(), 108 vec![vec![ 109 RADROOTS_PROFILE_TYPE_TAG_KEY.to_string(), 110 RADROOTS_PROFILE_TYPE_TAG_FARM.to_string(), 111 ]], 112 ) 113 .expect("metadata"); 114 115 assert_eq!(metadata.data.profile_type, Some(RadrootsProfileType::Farm)); 116 } 117 118 #[test] 119 fn profile_metadata_reads_profile_type_any_tag() { 120 let metadata = data_from_event( 121 "id".to_string(), 122 "author".to_string(), 123 1, 124 0, 125 "{\"name\":\"alice\"}".to_string(), 126 vec![vec![ 127 RADROOTS_PROFILE_TYPE_TAG_KEY.to_string(), 128 RADROOTS_PROFILE_TYPE_TAG_ANY.to_string(), 129 ]], 130 ) 131 .expect("metadata"); 132 133 assert_eq!(metadata.data.profile_type, Some(RadrootsProfileType::Any)); 134 } 135 136 #[test] 137 fn profile_metadata_reads_profile_type_radrootsd_tag() { 138 let metadata = data_from_event( 139 "id".to_string(), 140 "author".to_string(), 141 1, 142 0, 143 "{\"name\":\"alice\"}".to_string(), 144 vec![vec![ 145 RADROOTS_PROFILE_TYPE_TAG_KEY.to_string(), 146 RADROOTS_PROFILE_TYPE_TAG_RADROOTSD.to_string(), 147 ]], 148 ) 149 .expect("metadata"); 150 151 assert_eq!( 152 metadata.data.profile_type, 153 Some(RadrootsProfileType::Radrootsd) 154 ); 155 } 156 157 #[test] 158 fn profile_metadata_ignores_short_unknown_and_unrelated_profile_type_tags() { 159 let metadata = data_from_event( 160 "id".to_string(), 161 "author".to_string(), 162 1, 163 KIND_PROFILE, 164 "{\"name\":\"alice\"}".to_string(), 165 vec![ 166 vec![RADROOTS_PROFILE_TYPE_TAG_KEY.to_string()], 167 vec![ 168 RADROOTS_PROFILE_TYPE_TAG_KEY.to_string(), 169 "radroots:type:unknown".to_string(), 170 ], 171 vec!["x".to_string(), RADROOTS_PROFILE_TYPE_TAG_COOP.to_string()], 172 vec![ 173 RADROOTS_PROFILE_TYPE_TAG_KEY.to_string(), 174 RADROOTS_PROFILE_TYPE_TAG_COOP.to_string(), 175 ], 176 ], 177 ) 178 .expect("metadata"); 179 180 assert_eq!(metadata.data.profile_type, Some(RadrootsProfileType::Coop)); 181 } 182 183 #[test] 184 fn profile_parsed_event_preserves_wire_event_and_decoded_data() { 185 let parsed = parsed_from_event( 186 "event-id".to_string(), 187 "author-pubkey".to_string(), 188 42, 189 KIND_PROFILE, 190 "{\"name\":\"alice\"}".to_string(), 191 vec![vec![ 192 RADROOTS_PROFILE_TYPE_TAG_KEY.to_string(), 193 RADROOTS_PROFILE_TYPE_TAG_FARM.to_string(), 194 ]], 195 "event-sig".to_string(), 196 ) 197 .expect("parsed profile"); 198 199 assert_eq!(parsed.event.id, "event-id"); 200 assert_eq!(parsed.event.author, "author-pubkey"); 201 assert_eq!(parsed.event.created_at, 42); 202 assert_eq!(parsed.event.kind, KIND_PROFILE); 203 assert_eq!(parsed.event.content, "{\"name\":\"alice\"}"); 204 assert_eq!(parsed.event.sig, "event-sig"); 205 assert_eq!(parsed.data.data.profile.name, "alice"); 206 assert_eq!( 207 parsed.data.data.profile_type, 208 Some(RadrootsProfileType::Farm) 209 ); 210 }