filter: add unit tests

This commit is contained in:
2025-11-21 15:49:27 +09:00
parent d09ca013d5
commit da31ab75e2

View File

@@ -14,16 +14,27 @@ pub enum CaseSensitivity {
CommandDependent,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ComparisonOperator {
Equal,
NotEqual,
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqual,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Filter {
Not(Box<Filter>),
And(Box<Filter>, Box<Filter>),
EqTag(Tag, String, CaseSensitivity),
Contains(Tag, String, CaseSensitivity),
StartsWith(Tag, String, CaseSensitivity),
PerlRegex(Tag, String),
NegPerlRegex(Tag, String),
// The bool indicates whether the comparison is negated (true for !=, false for ==)
EqTag(Tag, CaseSensitivity, bool),
Contains(Tag, CaseSensitivity, bool),
StartsWith(Tag, CaseSensitivity, bool),
PerlRegex(Tag),
NegPerlRegex(Tag),
EqUri(String),
Base(String),
ModifiedSince(u64),
@@ -37,9 +48,375 @@ pub enum Filter {
bits: Option<u8>,
channels: Option<u8>,
},
PrioCmp(Priority),
PrioCmp(ComparisonOperator, Priority),
}
pub fn parse_filter(parts: &mut SplitWhitespace<'_>) -> Result<Filter, RequestParserError> {
todo!()
// TODO: count parentheses and extract the full filter string
unimplemented!()
}
fn parse_filter_str(string: &str) -> Result<Filter, RequestParserError> {
unimplemented!()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_filter_eq_tag() {
let mut parts = "(artist == 'The Beatles')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::EqTag(
Tag::Artist("The Beatles".to_string()),
CaseSensitivity::CommandDependent,
false,
)
);
let mut parts = "(artist != 'The Beatles')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::EqTag(
Tag::Artist("The Beatles".to_string()),
CaseSensitivity::CommandDependent,
true,
)
);
}
#[test]
fn test_parse_filter_contains() {
let mut parts = "(album contains 'Greatest Hits')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::Contains(
Tag::Album("Greatest Hits".to_string()),
CaseSensitivity::CommandDependent,
false,
),
);
let mut parts = "(album !contains 'Greatest Hits')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::Contains(
Tag::Album("Greatest Hits".to_string()),
CaseSensitivity::CommandDependent,
true,
),
);
}
#[test]
fn test_parse_filter_starts_with() {
let mut parts = "(title starts_with 'Symphony No. ')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::StartsWith(
Tag::Title("Symphony No. ".to_string()),
CaseSensitivity::CommandDependent,
false,
),
);
let mut parts = "(title !starts_with 'Symphony No. ')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::StartsWith(
Tag::Title("Symphony No. ".to_string()),
CaseSensitivity::CommandDependent,
true,
),
);
}
#[test]
fn test_parse_filter_perl_regex_positive() {
let mut parts = "(composer =~ 'Beethoven.*')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::PerlRegex(Tag::Composer("Beethoven.*".to_string())),
);
}
#[test]
fn test_parse_filter_perl_regex_negative() {
let mut parts = "(genre !~ 'Pop.*')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::NegPerlRegex(Tag::Genre("Pop.*".to_string())),
);
}
#[test]
fn test_parse_filter_base() {
let mut parts = "(base 'Rock/Classics')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(filter, Filter::Base("Rock/Classics".to_string()),);
}
#[test]
fn test_parse_filter_modified_since() {
let mut parts = "(modified-since '1622505600')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(filter, Filter::ModifiedSince(1622505600),);
}
#[test]
fn test_parse_filter_audio_added_since() {
let mut parts = "(added-since '1622505600')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(filter, Filter::ModifiedSince(1622505600),);
}
#[test]
fn test_parse_filter_audio_format_eq() {
let mut parts = "(AudioFormat == '44100:16:2')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::AudioFormatEq {
sample_rate: 44100,
bits: 16,
channels: 2,
},
);
}
#[test]
fn test_parse_filter_audio_format_eq_mask() {
let mut parts = "(AudioFormat =~ '44100:*:2')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::AudioFormatEqMask {
sample_rate: Some(44100),
bits: None,
channels: Some(2),
},
);
}
#[test]
fn test_parse_filter_prio_cmp() {
let mut parts = "(prio >= 42)".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::PrioCmp(ComparisonOperator::GreaterThanOrEqual, 42),
);
}
#[test]
fn test_parse_filter_not() {
let mut parts = "(!(artist == 'The Beatles'))".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::Not(Box::new(Filter::EqTag(
Tag::Artist("The Beatles".to_string()),
CaseSensitivity::CommandDependent,
false,
))),
);
}
#[test]
fn test_parse_filter_and() {
let mut parts =
"((artist == 'The Beatles') AND (album == 'Abbey Road'))".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::And(
Box::new(Filter::EqTag(
Tag::Artist("The Beatles".to_string()),
CaseSensitivity::CommandDependent,
false,
)),
Box::new(Filter::EqTag(
Tag::Album("Abbey Road".to_string()),
CaseSensitivity::CommandDependent,
false,
)),
),
);
}
#[test]
fn test_parse_filter_explicitly_case_sensitive() {
let mut parts = "(artist eq_cs 'The Beatles')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::EqTag(
Tag::Artist("The Beatles".to_string()),
CaseSensitivity::CaseSensitive,
false,
),
);
let mut parts = "(artist !eq_cs 'The Beatles')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::EqTag(
Tag::Artist("The Beatles".to_string()),
CaseSensitivity::CaseSensitive,
true,
),
);
let mut parts = "(album contains_cs 'Greatest Hits')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::Contains(
Tag::Album("Greatest Hits".to_string()),
CaseSensitivity::CaseSensitive,
false,
),
);
let mut parts = "(album !contains_cs 'Greatest Hits')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::Contains(
Tag::Album("Greatest Hits".to_string()),
CaseSensitivity::CaseSensitive,
true,
),
);
let mut parts = "(title starts_with_cs 'Symphony No. ')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::StartsWith(
Tag::Title("Symphony No. ".to_string()),
CaseSensitivity::CaseSensitive,
false,
),
);
let mut parts = "(title !starts_with_cs 'Symphony No. ')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::StartsWith(
Tag::Title("Symphony No. ".to_string()),
CaseSensitivity::CaseSensitive,
true,
),
);
}
#[test]
fn test_parse_filter_explicitly_case_insensitive() {
let mut parts = "(artist eq_ci 'The Beatles')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::EqTag(
Tag::Artist("The Beatles".to_string()),
CaseSensitivity::CaseInsensitive,
false,
),
);
let mut parts = "(artist !eq_ci 'The Beatles')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::EqTag(
Tag::Artist("The Beatles".to_string()),
CaseSensitivity::CaseInsensitive,
true,
),
);
let mut parts = "(album contains_ci 'Greatest Hits')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::Contains(
Tag::Album("Greatest Hits".to_string()),
CaseSensitivity::CaseInsensitive,
false,
),
);
let mut parts = "(album !contains_ci 'Greatest Hits')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::Contains(
Tag::Album("Greatest Hits".to_string()),
CaseSensitivity::CaseInsensitive,
true,
),
);
let mut parts = "(title starts_with_ci 'Symphony No. ')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::StartsWith(
Tag::Title("Symphony No. ".to_string()),
CaseSensitivity::CaseInsensitive,
false,
),
);
let mut parts = "(title !starts_with_ci 'Symphony No. ')".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::StartsWith(
Tag::Title("Symphony No. ".to_string()),
CaseSensitivity::CaseInsensitive,
true,
),
);
}
#[test]
fn test_parse_filter_string_escapes() {
let mut parts = "(Artist == \"foo\\'bar\\\"\")".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::EqTag(
Tag::Artist("foo'bar\"".to_string()),
CaseSensitivity::CommandDependent,
false,
),
);
}
#[test]
fn test_parse_filter_excessive_whitespace() {
let mut parts = "(\tartist\n == 'The Beatles' ) ".split_whitespace();
let filter = parse_filter(&mut parts).unwrap();
assert_eq!(
filter,
Filter::EqTag(
Tag::Artist("The Beatles".to_string()),
CaseSensitivity::CommandDependent,
false,
)
);
}
}