Преглед изворни кода

Merge branch 'types-bug-parsing' of cesar/nostr-prototype into main

Cesar Rodas пре 2 месеци
родитељ
комит
c9591ec165

+ 3 - 3
crates/relayer/src/relayer.rs

@@ -411,9 +411,10 @@ mod test {
         (relayer, stopper)
     }
 
-    fn get_note_with_custom_tags(tags: Vec<Tag>) -> Event {
+    fn get_note_with_custom_tags(tags: serde_json::Value) -> Event {
         let account = Account::default();
         let content = Content::ShortTextNote("".to_owned());
+        let tags: Vec<Tag> = serde_json::from_value(tags).expect("valid tags");
         account.sign_content(tags, content, None).expect("valid")
     }
 
@@ -471,8 +472,7 @@ mod test {
         let relayer = Relayer::new(Some(get_db(true).await), None).expect("valid relayer");
         let (connection, mut recv) = Connection::new_local_connection();
 
-        let note =
-            get_note_with_custom_tags(vec![Tag::Unknown("f".to_owned(), vec!["foo".to_owned()])]);
+        let note = get_note_with_custom_tags(json!([["f", "foo"]]));
 
         let _ = relayer
             .process_request_from_client(&connection, note.clone().into())

+ 2 - 1
crates/storage/memory/src/lib.rs

@@ -4,6 +4,7 @@ use nostr_rs_types::types::{Event, Filter};
 use std::{
     cmp::min,
     collections::{BTreeMap, VecDeque},
+    ops::Deref,
     sync::{
         atomic::{AtomicUsize, Ordering},
         Arc,
@@ -97,7 +98,7 @@ impl Storage for Memory {
             for event_tags in event
                 .tags()
                 .iter()
-                .filter_map(|tag| tag.clone().into_bytes())
+                .filter_map(|tag| tag.deref().clone().into_bytes())
             {
                 indexes
                     .tags

+ 1 - 1
crates/storage/rocksdb/src/lib.rs

@@ -155,7 +155,7 @@ impl Storage for RocksDb {
         );
 
         for tag in event.tags().iter() {
-            if let Some(tag) = tag.clone().into_bytes() {
+            if let Some(tag) = tag.deref().clone().into_bytes() {
                 let tag_id = secondary_index.index_by(&tag);
                 buffer.put_cf(
                     &self.reference_to_cf_handle(ReferenceType::Tags)?,

+ 1 - 1
crates/types/src/client/subscribe.rs

@@ -9,7 +9,7 @@ use serde_json::Value;
 use std::collections::VecDeque;
 
 static ALL_EVENTS_PREFIX: Lazy<String> = Lazy::new(|| {
-    let mut prefix = [0u8; 4];
+    let mut prefix = [0u8; 8];
     rand::thread_rng().fill_bytes(&mut prefix);
     prefix.encode_hex::<String>()
 });

+ 1 - 1
crates/types/src/lib.rs

@@ -30,7 +30,7 @@ mod regression {
                 let event: Event = serde_json::from_str(line).unwrap_or_else(|_| {
                     panic!("Failed to parse: {}", line);
                 });
-                assert!(event.is_valid().is_ok(), "Failed to parse: {}", line);
+                assert!(event.is_valid().is_ok(), "Failed to validate: {}", line);
             });
     }
 }

+ 12 - 7
crates/types/src/types/content/mod.rs

@@ -94,13 +94,18 @@ impl Content {
             Kind::EncryptedDirectMessages => {
                 let parts = content.split("?iv=").collect::<Vec<&str>>();
                 if parts.len() == 2 {
-                    let encrypted_message = general_purpose::STANDARD.decode(parts[0])?;
-                    let iv = general_purpose::STANDARD.decode(parts[1])?;
-
-                    Ok(Self::EncryptedDirectMessage(EncryptedData {
-                        encrypted_message,
-                        iv,
-                    }))
+                    Ok(general_purpose::STANDARD
+                        .decode(parts[0])
+                        .and_then(|encrypted_message| {
+                            general_purpose::STANDARD
+                                .decode(parts[1])
+                                .map(|iv| EncryptedData {
+                                    encrypted_message,
+                                    iv,
+                                })
+                        })
+                        .map(|data| Self::EncryptedDirectMessage(data))
+                        .unwrap_or_else(|_| Self::Unparsed(Kind::Unknown(4), content.to_owned())))
                 } else {
                     Ok(Self::Unparsed(Kind::Unknown(4), content.to_owned()))
                 }

+ 133 - 178
crates/types/src/types/tag.rs

@@ -8,11 +8,13 @@ use super::{filter::TagValue, Id};
 use chrono::{DateTime, Utc};
 use serde::{
     de::{self, Deserialize, Deserializer},
-    ser::{self, SerializeSeq, Serializer},
+    ser::{self, Serializer},
 };
+use serde_json::from_value;
 use std::{
     collections::VecDeque,
     fmt::{self, Display},
+    ops::Deref,
 };
 use url::Url;
 
@@ -30,8 +32,6 @@ pub enum Marker {
     Unknown(String),
 }
 
-type ParsedUrl = (Option<Url>, String);
-
 impl Display for Marker {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(
@@ -69,6 +69,7 @@ pub enum RelayAccessType {
     Both,
 }
 
+#[derive(Debug, PartialEq, Eq, Clone)]
 /// Tags are how events relates to each other.
 ///
 /// So far, there are two standard tags, Events and Public Key. This an event
@@ -77,14 +78,25 @@ pub enum RelayAccessType {
 ///
 /// Any non standard tag will be parsed as Unknown with a vector of strings as
 /// their parameters
+pub struct Tag(TagType, Vec<serde_json::Value>);
+
+impl Deref for Tag {
+    type Target = TagType;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
 #[derive(Debug, PartialEq, Eq, Clone)]
-pub enum Tag {
+/// Inner tag type
+pub enum TagType {
     /// Tag another event
-    Event(Id, Option<ParsedUrl>, Option<Marker>),
+    Event(Id, Option<Url>, Option<Marker>),
     /// Tag another public key
-    PubKey(Id, Option<ParsedUrl>, Option<String>),
+    PubKey(Id, Option<Url>, Option<String>),
     /// Tag a relay
-    Relay(ParsedUrl, RelayAccessType),
+    Relay(Url, RelayAccessType),
     /// Tag a hashtag
     Hashtag(String),
     /// Tag with an external content id
@@ -102,12 +114,32 @@ pub enum Tag {
     /// Image - NIP-23, NIP-52, NIP-58
     Image(Url, Option<String>),
     /// Zap Goal - NIP-75
-    ZapGoal(Id, Option<ParsedUrl>),
+    ZapGoal(Id, Option<Url>),
     /// Weird, supported nonetheless
     Empty,
 }
 
-impl Tag {
+impl ser::Serialize for Tag {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        self.1.serialize(serializer)
+    }
+}
+
+impl<'de> Deserialize<'de> for Tag {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let raw_tag: Vec<serde_json::Value> = Deserialize::deserialize(deserializer)?;
+        let tag = from_value(raw_tag.clone().into()).map_err(de::Error::custom)?;
+        Ok(Self(tag, raw_tag))
+    }
+}
+
+impl TagType {
     /// Is the tag a public key?
     pub fn is_pubkey(&self) -> bool {
         matches!(self, Self::PubKey(_, _, _))
@@ -121,30 +153,32 @@ impl Tag {
     /// Get the identifier for the tag
     pub fn get_identifier(&self) -> &str {
         match self {
-            Tag::Event(_, _, _) => "e",
-            Tag::PubKey(_, _, _) => "p",
-            Tag::Relay(_, _) => "r",
-            Tag::Hashtag(_) => "t",
-            Tag::Title(_) => "title",
-            Tag::Encrypted => "encrypted",
-            Tag::Image(_, _) => "image",
-            Tag::ZapGoal(_, _) => "goal",
-            Tag::Expiration(_) => "expiration",
-            Tag::ExternalContentId(_, _) => "i",
-            Tag::Unknown(u, _) | Tag::UnknownJson(u, _) => u,
-            Tag::Empty => "",
+            Self::Event(_, _, _) => "e",
+            Self::PubKey(_, _, _) => "p",
+            Self::Relay(_, _) => "r",
+            Self::Hashtag(_) => "t",
+            Self::Title(_) => "title",
+            Self::Encrypted => "encrypted",
+            Self::Image(_, _) => "image",
+            Self::ZapGoal(_, _) => "goal",
+            Self::Expiration(_) => "expiration",
+            Self::ExternalContentId(_, _) => "i",
+            Self::Unknown(u, _) | Self::UnknownJson(u, _) => u,
+            Self::Empty => "",
         }
     }
 
     /// Get the indexable value of the tag
     pub fn get_indexable_value(&self) -> Option<TagValue> {
         match self {
-            Tag::Event(event, _, _) => Some(TagValue::Id(event.clone())),
-            Tag::PubKey(key, _, _) => Some(TagValue::Id(key.clone())),
-            Tag::ExternalContentId(id, _) => Some(TagValue::String(id.clone())),
-            Tag::Hashtag(content) | Tag::Title(content) => Some(TagValue::String(content.clone())),
-            Tag::Relay((_, url), _) => Some(TagValue::String(url.to_string())),
-            Tag::Unknown(_, args) => {
+            Self::Event(event, _, _) => Some(TagValue::Id(event.clone())),
+            Self::PubKey(key, _, _) => Some(TagValue::Id(key.clone())),
+            Self::ExternalContentId(id, _) => Some(TagValue::String(id.clone())),
+            Self::Hashtag(content) | Self::Title(content) => {
+                Some(TagValue::String(content.clone()))
+            }
+            Self::Relay(url, _) => Some(TagValue::String(url.to_string())),
+            Self::Unknown(_, args) => {
                 let value = args.first().cloned().unwrap_or_default();
                 Some(
                     value
@@ -154,9 +188,9 @@ impl Tag {
                         .unwrap_or_else(|_| TagValue::String(value)),
                 )
             }
-            Tag::ZapGoal(event, _) => Some(TagValue::Id(event.clone())),
-            Tag::Image(image_url, _) => Some(TagValue::String(image_url.to_string())),
-            Tag::UnknownJson(_, _) | Tag::Empty | Tag::Encrypted | Tag::Expiration(_) => None,
+            Self::ZapGoal(event, _) => Some(TagValue::Id(event.clone())),
+            Self::Image(image_url, _) => Some(TagValue::String(image_url.to_string())),
+            Self::UnknownJson(_, _) | Self::Empty | Self::Encrypted | Self::Expiration(_) => None,
         }
     }
 
@@ -171,86 +205,7 @@ impl Tag {
     }
 }
 
-impl ser::Serialize for Tag {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: Serializer,
-    {
-        let mut seq = serializer.serialize_seq(Some(2))?;
-        seq.serialize_element(self.get_identifier())?;
-
-        match self {
-            Tag::Encrypted => {}
-            Tag::Expiration(date) => {
-                seq.serialize_element(&date.timestamp().to_string())?;
-            }
-            Tag::Event(event, relayer_url, marker) => {
-                seq.serialize_element(&event.to_string())?;
-                if let Some((_, relayer)) = relayer_url {
-                    seq.serialize_element(&relayer)?;
-                    if let Some(marker) = &marker {
-                        seq.serialize_element(&marker.to_string())?;
-                    }
-                }
-            }
-            Tag::ZapGoal(event, relayer_url) => {
-                seq.serialize_element(&event.to_string())?;
-                if let Some((_, relayer)) = relayer_url {
-                    seq.serialize_element(&relayer)?;
-                }
-            }
-            Tag::ExternalContentId(content, url) => {
-                seq.serialize_element(content)?;
-                if let Some(url) = url {
-                    seq.serialize_element(url)?;
-                }
-            }
-            Tag::Hashtag(content) | Tag::Title(content) => {
-                seq.serialize_element(content)?;
-            }
-            Tag::PubKey(key, relayer_url, pet_name) => {
-                seq.serialize_element(&key.to_string())?;
-                if let Some((_, relayer)) = relayer_url {
-                    seq.serialize_element(&relayer)?;
-                    if let Some(pet_name) = &pet_name {
-                        seq.serialize_element(pet_name)?;
-                    }
-                }
-            }
-            Tag::Relay((_, url), access) => {
-                seq.serialize_element(url)?;
-
-                if let Some(access) = match access {
-                    RelayAccessType::Read => Some("read"),
-                    RelayAccessType::Write => Some("write"),
-                    RelayAccessType::Both => None,
-                } {
-                    seq.serialize_element(access)?;
-                }
-            }
-            Tag::UnknownJson(_, extra) => {
-                for extra in extra.iter() {
-                    seq.serialize_element(extra)?;
-                }
-            }
-            Tag::Unknown(_, extra) => {
-                for extra in extra.iter() {
-                    seq.serialize_element(extra)?;
-                }
-            }
-            Tag::Image(image, dimensions) => {
-                seq.serialize_element(image)?;
-                if let Some(dimensions) = dimensions {
-                    seq.serialize_element(dimensions)?;
-                }
-            }
-            Tag::Empty => unreachable!(),
-        }
-        seq.end()
-    }
-}
-
-impl<'de> Deserialize<'de> for Tag {
+impl<'de> Deserialize<'de> for TagType {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
         D: Deserializer<'de>,
@@ -263,7 +218,7 @@ impl<'de> Deserialize<'de> for Tag {
         {
             // If any of the parts is not a string, do not attempt to parse it
             // and instead return as a Tag::UnknownJson
-            return Ok(Tag::UnknownJson(
+            return Ok(Self::UnknownJson(
                 parts.pop_front().unwrap_or_default().to_string(),
                 parts.into_iter().collect(),
             ));
@@ -275,35 +230,44 @@ impl<'de> Deserialize<'de> for Tag {
             .collect();
 
         match parts.len() {
-            0 => return Ok(Tag::Empty),
+            0 => return Ok(Self::Empty),
             1 => {
                 let tag_name = parts.pop_front().unwrap_or_default();
                 if tag_name.as_str() == "encrypted" {
-                    return Ok(Tag::Encrypted);
+                    return Ok(Self::Encrypted);
                 }
-                return Ok(Tag::Unknown(tag_name, vec![]));
+                return Ok(Self::Unknown(tag_name, vec![]));
             }
             _ => {}
         }
 
         let tag_type = parts.pop_front().unwrap_or_default();
-        let default = Tag::Unknown(tag_type.clone(), parts.clone().into());
+        let default = Self::Unknown(tag_type.clone(), parts.clone().into());
 
         let tag: Result<_, D::Error> = match tag_type.as_str() {
             "e" | "goal" | "p" => parts
                 .pop_front()
                 .ok_or_else::<D::Error, _>(|| de::Error::custom("missing argument"))
-                .and_then(|id| id.parse().map_err(de::Error::custom))
-                .map(|id| {
-                    let relayer_url = parts.pop_front().map(|value| (value.parse().ok(), value));
+                .and_then(|input| {
+                    let mut id = [0u8; 32];
+                    hex::decode_to_slice(input, &mut id)
+                        .map_err(de::Error::custom)
+                        .map(|_| Id(id))
+                })
+                .and_then(|id| {
+                    let relayer_url = parts
+                        .pop_front()
+                        .map(|value| value.parse::<Url>())
+                        .transpose()
+                        .map_err(de::Error::custom);
 
                     let extra = parts.pop_front();
-                    match tag_type.as_str() {
-                        "e" => Tag::Event(id, relayer_url, extra.map(|x| x.as_str().into())),
-                        "goal" => Tag::ZapGoal(id, relayer_url),
-                        "p" => Tag::PubKey(id, relayer_url, extra),
+                    relayer_url.map(|relayer_url| match tag_type.as_str() {
+                        "e" => Self::Event(id, relayer_url, extra.map(|x| x.as_str().into())),
+                        "goal" => Self::ZapGoal(id, relayer_url),
+                        "p" => Self::PubKey(id, relayer_url, extra),
                         _ => unreachable!(),
-                    }
+                    })
                 }),
             "expiration" => {
                 let timestamp = parts
@@ -313,16 +277,16 @@ impl<'de> Deserialize<'de> for Tag {
                     .map_err(|_| de::Error::custom("invalid timestamp"))?;
 
                 DateTime::<Utc>::from_timestamp(timestamp, 0)
-                    .map(Tag::Expiration)
+                    .map(Self::Expiration)
                     .ok_or_else(|| de::Error::custom("invalid timestamp"))
             }
             "title" => parts
                 .pop_front()
-                .map(Tag::Title)
+                .map(Self::Title)
                 .ok_or_else(|| de::Error::custom("missing argument")),
             "t" => parts
                 .pop_front()
-                .map(Tag::Hashtag)
+                .map(Self::Hashtag)
                 .ok_or_else(|| de::Error::custom("missing argument")),
             "i" => {
                 let external_id = parts
@@ -334,7 +298,7 @@ impl<'de> Deserialize<'de> for Tag {
                     .transpose();
 
                 if let Ok(external_id) = external_id {
-                    url.map(|url| Tag::ExternalContentId(external_id, url))
+                    url.map(|url| Self::ExternalContentId(external_id, url))
                 } else {
                     Err(de::Error::custom("invalid external id"))
                 }
@@ -343,11 +307,7 @@ impl<'de> Deserialize<'de> for Tag {
                 let url = parts
                     .pop_front()
                     .ok_or_else::<D::Error, _>(|| de::Error::custom("missing url"))
-                    .and_then(|url| {
-                        url.parse::<Url>()
-                            .map_err(de::Error::custom)
-                            .map(|parsed_url| (Some(parsed_url), url))
-                    });
+                    .and_then(|url| url.parse::<Url>().map_err(de::Error::custom));
 
                 let access = parts
                     .pop_front()
@@ -359,7 +319,7 @@ impl<'de> Deserialize<'de> for Tag {
                     .unwrap_or(Ok(RelayAccessType::Both));
 
                 if let Ok(url) = url {
-                    access.map(|access| Tag::Relay(url, access))
+                    access.map(|access| TagType::Relay(url, access))
                 } else {
                     Err(de::Error::custom("invalid url"))
                 }
@@ -421,32 +381,33 @@ mod test {
         ]
         .into_iter()
         .map(|x| serde_json::from_value(x).unwrap())
-        .collect::<Vec<Tag>>();
+        .collect::<Vec<TagType>>();
 
         let expected = vec![
-            Tag::Unknown("p".to_owned(), vec![String::from("d45a98f8988")]),
-            Tag::PubKey(
+            TagType::Unknown("p".to_owned(), vec![String::from("d45a98f8988")]),
+            TagType::PubKey(
                 "d45a98f898820258a3313f5cb14f5fe8a9263437931ac6309f23ae0324833f39"
                     .parse()
                     .unwrap(),
                 None,
                 None,
             ),
-            Tag::PubKey(
-                "8fe53b37518e3dbe9bab26d912292001d8b882de9456b7b08b615f912dc8bf4a"
-                    .parse()
-                    .unwrap(),
-                Some((None, "".to_owned())),
-                Some("mention".to_owned()),
+            TagType::Unknown(
+                "p".to_owned(),
+                vec![
+                    "8fe53b37518e3dbe9bab26d912292001d8b882de9456b7b08b615f912dc8bf4a".to_owned(),
+                    "".to_owned(),
+                    "mention".to_owned(),
+                ],
             ),
-            Tag::Event(
+            TagType::Event(
                 "eb278e983fcedbb0d143c4250c879d078d037586c5dca8e1cf1a104f9846a460"
                     .parse()
                     .unwrap(),
                 None,
                 None,
             ),
-            Tag::PubKey(
+            TagType::PubKey(
                 "2bda4f03446bc1c6ff00594e350a1e7ec57fb9cdc4a7b52694223d56ce0599e9"
                     .parse()
                     .unwrap(),
@@ -462,11 +423,8 @@ mod test {
     fn test_relay() {
         let json = json!(["r", "https://example.com/", "read"]);
         assert_eq!(
-            Tag::Relay(
-                (
-                    Some("https://example.com".parse().expect("valid url")),
-                    "https://example.com/".to_owned()
-                ),
+            TagType::Relay(
+                "https://example.com".parse().expect("valid url"),
                 RelayAccessType::Read
             ),
             serde_json::from_value(json).expect("valid json"),
@@ -474,11 +432,8 @@ mod test {
 
         let json = json!(["r", "https://example.com", "write"]);
         assert_eq!(
-            Tag::Relay(
-                (
-                    Some("https://example.com".parse().expect("valid url")),
-                    "https://example.com".to_owned()
-                ),
+            TagType::Relay(
+                "https://example.com".parse().expect("valid url"),
                 RelayAccessType::Write
             ),
             serde_json::from_value(json).expect("valid json"),
@@ -486,11 +441,8 @@ mod test {
 
         let json = json!(["r", "https://example.com"]);
         assert_eq!(
-            Tag::Relay(
-                (
-                    Some("https://example.com".parse().expect("valid url")),
-                    "https://example.com".to_owned()
-                ),
+            TagType::Relay(
+                "https://example.com".parse().expect("valid url"),
                 RelayAccessType::Both,
             ),
             serde_json::from_value(json).expect("valid json"),
@@ -501,7 +453,7 @@ mod test {
     fn test_relay_invalid_url() {
         let json = json!(["r", "example.com", "read"]);
         assert_eq!(
-            Tag::Unknown(
+            TagType::Unknown(
                 "r".to_string(),
                 vec!["example.com".to_string(), "read".to_string()],
             ),
@@ -521,8 +473,8 @@ mod test {
         ];
 
         for json in json {
-            let tag: Tag = serde_json::from_value(json).expect("valid");
-            assert!(matches!(tag, Tag::Unknown(_, _)));
+            let tag: TagType = serde_json::from_value(json).expect("valid");
+            assert!(matches!(tag, TagType::Unknown(_, _)));
         }
     }
 
@@ -530,7 +482,7 @@ mod test {
     fn test_relay_invalid_access() {
         let json = json!(["r", "https://example.com", "invalid"]);
         assert_eq!(
-            Tag::Unknown(
+            TagType::Unknown(
                 "r".to_string(),
                 vec!["https://example.com".to_string(), "invalid".to_string()],
             ),
@@ -542,7 +494,7 @@ mod test {
     fn hashtag() {
         let json = json!(["t", "rust"]);
         assert_eq!(
-            Tag::Hashtag("rust".to_string()),
+            TagType::Hashtag("rust".to_string()),
             serde_json::from_value(json).expect("valid json"),
         );
     }
@@ -551,7 +503,7 @@ mod test {
     fn title() {
         let json = json!(["title", "Rust"]);
         assert_eq!(
-            Tag::Title("Rust".to_string()),
+            TagType::Title("Rust".to_string()),
             serde_json::from_value(json).expect("valid json"),
         );
     }
@@ -560,13 +512,13 @@ mod test {
     fn external_content_id() {
         let json = json!(["i", "123"]);
         assert_eq!(
-            serde_json::from_value::<Tag>(json).expect("valid"),
-            Tag::ExternalContentId("123".to_string(), None,),
+            serde_json::from_value::<TagType>(json).expect("valid"),
+            TagType::ExternalContentId("123".to_string(), None,),
         );
         let json = json!(["i", "123", "https://example.com"]);
         assert_eq!(
-            serde_json::from_value::<Tag>(json).expect("valid"),
-            Tag::ExternalContentId(
+            serde_json::from_value::<TagType>(json).expect("valid"),
+            TagType::ExternalContentId(
                 "123".to_string(),
                 Some("https://example.com".parse().expect("valid url"))
             ),
@@ -577,8 +529,8 @@ mod test {
     fn external_content_id_invalid_args() {
         let json = json!(["i", "123", "https://example.com", "unexpected"]);
         assert_eq!(
-            serde_json::from_value::<Tag>(json).expect("valid"),
-            Tag::Unknown(
+            serde_json::from_value::<TagType>(json).expect("valid"),
+            TagType::Unknown(
                 "i".to_owned(),
                 vec![
                     "123".to_owned(),
@@ -592,15 +544,18 @@ mod test {
     #[test]
     fn encrypted_tag() {
         let json = json!(["encrypted"]);
-        assert_eq!(Tag::Encrypted, serde_json::from_value(json).expect("valid"));
+        assert_eq!(
+            TagType::Encrypted,
+            serde_json::from_value(json).expect("valid")
+        );
     }
 
     #[test]
     fn external_content_id_invalid_url() {
         let json = json!(["i", "123", "facebook.com"]);
         assert_eq!(
-            serde_json::from_value::<Tag>(json).expect("valid"),
-            Tag::Unknown(
+            serde_json::from_value::<TagType>(json).expect("valid"),
+            TagType::Unknown(
                 "i".to_owned(),
                 vec!["123".to_owned(), "facebook.com".to_owned()]
             ),
@@ -614,8 +569,8 @@ mod test {
             "d45a98f898820258a3313f5cb14f5fe8a9263437931ac6309f23ae0324833f39"
         ]);
         assert_eq!(
-            serde_json::from_value::<Tag>(json).expect("valid"),
-            Tag::ZapGoal(
+            serde_json::from_value::<TagType>(json).expect("valid"),
+            TagType::ZapGoal(
                 "d45a98f898820258a3313f5cb14f5fe8a9263437931ac6309f23ae0324833f39"
                     .parse()
                     .unwrap(),
@@ -628,8 +583,8 @@ mod test {
     fn timestamp() {
         let json = json!(["expiration", "1678682368"]);
         assert_eq!(
-            serde_json::from_value::<Tag>(json).expect("valid"),
-            Tag::Expiration(DateTime::<Utc>::from_timestamp(1678682368, 0).unwrap()),
+            serde_json::from_value::<TagType>(json).expect("valid"),
+            TagType::Expiration(DateTime::<Utc>::from_timestamp(1678682368, 0).unwrap()),
         );
     }
 }

Разлика између датотеке није приказан због своје велике величине
+ 5 - 1
crates/types/tests/regression_parsing.json


Неке датотеке нису приказане због велике количине промена