feedparser_rs/compat/
mod.rs

1//! Compatibility utilities for feedparser API
2//!
3//! This module provides utilities to ensure API compatibility with
4//! Python's feedparser library.
5
6use crate::types::FeedVersion;
7
8/// Normalize feed type string to Python feedparser format
9///
10/// Converts version enum to Python feedparser-compatible string format:
11/// - "RSS 2.0" -> "rss20"
12/// - "Atom 1.0" -> "atom10"
13/// - etc.
14///
15/// # Arguments
16///
17/// * `version` - Feed version to normalize
18///
19/// # Returns
20///
21/// Normalized version string compatible with Python feedparser
22///
23/// # Examples
24///
25/// ```
26/// use feedparser_rs::{compat::normalize_version, FeedVersion};
27///
28/// assert_eq!(normalize_version(FeedVersion::Rss20), "rss20");
29/// assert_eq!(normalize_version(FeedVersion::Atom10), "atom10");
30/// assert_eq!(normalize_version(FeedVersion::Unknown), "");
31/// ```
32#[must_use]
33pub fn normalize_version(version: FeedVersion) -> String {
34    version.as_str().to_string()
35}
36
37/// Convert duration in seconds to HH:MM:SS format
38///
39/// Formats duration for display in podcast feeds and other contexts
40/// where human-readable time format is needed.
41///
42/// # Arguments
43///
44/// * `seconds` - Duration in seconds
45///
46/// # Returns
47///
48/// Duration string in HH:MM:SS format
49///
50/// # Examples
51///
52/// ```
53/// use feedparser_rs::compat::format_duration;
54///
55/// assert_eq!(format_duration(0), "0:00:00");
56/// assert_eq!(format_duration(90), "0:01:30");
57/// assert_eq!(format_duration(3661), "1:01:01");
58/// assert_eq!(format_duration(36000), "10:00:00");
59/// ```
60#[must_use]
61pub fn format_duration(seconds: u32) -> String {
62    let hours = seconds / 3600;
63    let minutes = (seconds % 3600) / 60;
64    let secs = seconds % 60;
65    format!("{hours}:{minutes:02}:{secs:02}")
66}
67
68/// Check if a string is a valid feed version identifier
69///
70/// Validates whether a version string matches one of the known
71/// feed format versions supported by feedparser.
72///
73/// # Arguments
74///
75/// * `version` - Version string to validate
76///
77/// # Returns
78///
79/// `true` if version is valid, `false` otherwise
80///
81/// # Examples
82///
83/// ```
84/// use feedparser_rs::compat::is_valid_version;
85///
86/// assert!(is_valid_version("rss20"));
87/// assert!(is_valid_version("atom10"));
88/// assert!(is_valid_version("json11"));
89/// assert!(!is_valid_version("invalid"));
90/// assert!(!is_valid_version(""));
91/// ```
92#[must_use]
93pub fn is_valid_version(version: &str) -> bool {
94    matches!(
95        version,
96        "rss090"
97            | "rss091"
98            | "rss092"
99            | "rss10"
100            | "rss20"
101            | "atom03"
102            | "atom10"
103            | "json10"
104            | "json11"
105    )
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn test_normalize_version() {
114        assert_eq!(normalize_version(FeedVersion::Rss20), "rss20");
115        assert_eq!(normalize_version(FeedVersion::Rss10), "rss10");
116        assert_eq!(normalize_version(FeedVersion::Atom10), "atom10");
117        assert_eq!(normalize_version(FeedVersion::Atom03), "atom03");
118        assert_eq!(normalize_version(FeedVersion::JsonFeed10), "json10");
119        assert_eq!(normalize_version(FeedVersion::JsonFeed11), "json11");
120        assert_eq!(normalize_version(FeedVersion::Unknown), "");
121    }
122
123    #[test]
124    fn test_format_duration_zero() {
125        assert_eq!(format_duration(0), "0:00:00");
126    }
127
128    #[test]
129    fn test_format_duration_seconds_only() {
130        assert_eq!(format_duration(30), "0:00:30");
131        assert_eq!(format_duration(59), "0:00:59");
132    }
133
134    #[test]
135    fn test_format_duration_minutes() {
136        assert_eq!(format_duration(60), "0:01:00");
137        assert_eq!(format_duration(90), "0:01:30");
138        assert_eq!(format_duration(150), "0:02:30");
139        assert_eq!(format_duration(3599), "0:59:59");
140    }
141
142    #[test]
143    fn test_format_duration_hours() {
144        assert_eq!(format_duration(3600), "1:00:00");
145        assert_eq!(format_duration(3661), "1:01:01");
146        assert_eq!(format_duration(7200), "2:00:00");
147        assert_eq!(format_duration(36000), "10:00:00");
148    }
149
150    #[test]
151    fn test_format_duration_large() {
152        assert_eq!(format_duration(86399), "23:59:59");
153        assert_eq!(format_duration(86400), "24:00:00");
154        assert_eq!(format_duration(90061), "25:01:01");
155    }
156
157    #[test]
158    fn test_is_valid_version_valid() {
159        assert!(is_valid_version("rss090"));
160        assert!(is_valid_version("rss091"));
161        assert!(is_valid_version("rss092"));
162        assert!(is_valid_version("rss10"));
163        assert!(is_valid_version("rss20"));
164        assert!(is_valid_version("atom03"));
165        assert!(is_valid_version("atom10"));
166        assert!(is_valid_version("json10"));
167        assert!(is_valid_version("json11"));
168    }
169
170    #[test]
171    fn test_is_valid_version_invalid() {
172        assert!(!is_valid_version(""));
173        assert!(!is_valid_version("invalid"));
174        assert!(!is_valid_version("rss30"));
175        assert!(!is_valid_version("atom20"));
176        assert!(!is_valid_version("RSS20")); // Case sensitive
177        assert!(!is_valid_version("json12"));
178        assert!(!is_valid_version("rdf"));
179    }
180
181    #[test]
182    fn test_is_valid_version_edge_cases() {
183        assert!(!is_valid_version(" rss20"));
184        assert!(!is_valid_version("rss20 "));
185        assert!(!is_valid_version("rss 20"));
186    }
187}