spotify_cli/storage/pins/
pin.rs1use serde::{Deserialize, Serialize};
2
3use super::resource_type::ResourceType;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct Pin {
7 pub resource_type: ResourceType,
8 pub id: String,
9 pub alias: String,
10 pub tags: Vec<String>,
11}
12
13impl Pin {
14 pub fn new(resource_type: ResourceType, id: String, alias: String, tags: Vec<String>) -> Self {
15 Self {
16 resource_type,
17 id,
18 alias,
19 tags,
20 }
21 }
22
23 pub fn extract_id(url_or_id: &str) -> String {
25 if url_or_id.contains("open.spotify.com") {
26 url_or_id
27 .split('/')
28 .next_back()
29 .unwrap_or(url_or_id)
30 .split('?')
31 .next()
32 .unwrap_or(url_or_id)
33 .to_string()
34 } else if url_or_id.contains(':') {
35 url_or_id
36 .split(':')
37 .next_back()
38 .unwrap_or(url_or_id)
39 .to_string()
40 } else {
41 url_or_id.to_string()
42 }
43 }
44
45 pub fn uri(&self) -> String {
47 format!("spotify:{}:{}", self.resource_type.as_str(), self.id)
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn pin_new() {
57 let pin = Pin::new(
58 ResourceType::Track,
59 "track123".to_string(),
60 "favorite".to_string(),
61 vec!["rock".to_string(), "chill".to_string()],
62 );
63 assert_eq!(pin.id, "track123");
64 assert_eq!(pin.alias, "favorite");
65 assert_eq!(pin.tags.len(), 2);
66 }
67
68 #[test]
69 fn pin_uri_track() {
70 let pin = Pin::new(
71 ResourceType::Track,
72 "abc123".to_string(),
73 "test".to_string(),
74 vec![],
75 );
76 assert_eq!(pin.uri(), "spotify:track:abc123");
77 }
78
79 #[test]
80 fn pin_uri_playlist() {
81 let pin = Pin::new(
82 ResourceType::Playlist,
83 "xyz789".to_string(),
84 "test".to_string(),
85 vec![],
86 );
87 assert_eq!(pin.uri(), "spotify:playlist:xyz789");
88 }
89
90 #[test]
91 fn pin_uri_album() {
92 let pin = Pin::new(
93 ResourceType::Album,
94 "album123".to_string(),
95 "test".to_string(),
96 vec![],
97 );
98 assert_eq!(pin.uri(), "spotify:album:album123");
99 }
100
101 #[test]
102 fn extract_id_from_plain_id() {
103 let id = Pin::extract_id("abc123");
104 assert_eq!(id, "abc123");
105 }
106
107 #[test]
108 fn extract_id_from_spotify_uri() {
109 let id = Pin::extract_id("spotify:track:abc123");
110 assert_eq!(id, "abc123");
111 }
112
113 #[test]
114 fn extract_id_from_spotify_url() {
115 let id = Pin::extract_id("https://open.spotify.com/track/abc123");
116 assert_eq!(id, "abc123");
117 }
118
119 #[test]
120 fn extract_id_from_spotify_url_with_query() {
121 let id = Pin::extract_id("https://open.spotify.com/track/abc123?si=xyz");
122 assert_eq!(id, "abc123");
123 }
124
125 #[test]
126 fn pin_serializes_to_json() {
127 let pin = Pin::new(
128 ResourceType::Track,
129 "abc123".to_string(),
130 "test_alias".to_string(),
131 vec!["tag1".to_string()],
132 );
133 let json = serde_json::to_value(&pin).unwrap();
134 assert_eq!(json["id"], "abc123");
135 assert_eq!(json["alias"], "test_alias");
136 }
137
138 #[test]
139 fn pin_deserializes_from_json() {
140 let json = serde_json::json!({
141 "resource_type": "track",
142 "id": "abc123",
143 "alias": "test_alias",
144 "tags": ["tag1", "tag2"]
145 });
146 let pin: Pin = serde_json::from_value(json).unwrap();
147 assert_eq!(pin.id, "abc123");
148 assert_eq!(pin.alias, "test_alias");
149 assert_eq!(pin.tags.len(), 2);
150 }
151}