#![allow(dead_code)]
use std::collections::HashSet;
#[derive(Debug, Clone, Default)]
pub struct SceneTags {
tags: HashSet<String>,
}
impl SceneTags {
#[must_use]
pub fn new() -> Self {
Self {
tags: HashSet::new(),
}
}
pub fn add_tag(&mut self, tag: &str) {
self.tags.insert(tag.to_lowercase());
}
#[must_use]
pub fn has_tag(&self, tag: &str) -> bool {
self.tags.contains(&tag.to_lowercase())
}
#[must_use]
pub fn len(&self) -> usize {
self.tags.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.tags.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &str> {
self.tags.iter().map(String::as_str)
}
}
#[derive(Debug, Clone)]
pub struct SceneMetadata {
pub outdoor: bool,
pub daylight: bool,
pub location: String,
pub tags: SceneTags,
}
impl SceneMetadata {
#[must_use]
pub fn new(outdoor: bool, daylight: bool, location: impl Into<String>) -> Self {
Self {
outdoor,
daylight,
location: location.into(),
tags: SceneTags::new(),
}
}
#[must_use]
pub fn is_outdoor(&self) -> bool {
self.outdoor
}
#[must_use]
pub fn is_daylight(&self) -> bool {
self.daylight
}
}
impl Default for SceneMetadata {
fn default() -> Self {
Self::new(false, true, "unknown")
}
}
#[derive(Debug, Clone, Default)]
pub struct SceneKeywords {
keywords: HashSet<String>,
}
impl SceneKeywords {
#[must_use]
pub fn new() -> Self {
Self {
keywords: HashSet::new(),
}
}
pub fn add(&mut self, kw: &str) {
self.keywords.insert(kw.to_lowercase());
}
pub fn merge(&mut self, other: &SceneKeywords) {
for kw in &other.keywords {
self.keywords.insert(kw.clone());
}
}
#[must_use]
pub fn contains(&self, keyword: &str) -> bool {
self.keywords.contains(&keyword.to_lowercase())
}
#[must_use]
pub fn len(&self) -> usize {
self.keywords.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.keywords.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add_and_has_tag() {
let mut tags = SceneTags::new();
tags.add_tag("Action");
assert!(tags.has_tag("action"));
assert!(tags.has_tag("ACTION"));
}
#[test]
fn test_has_tag_false() {
let tags = SceneTags::new();
assert!(!tags.has_tag("drama"));
}
#[test]
fn test_len_empty() {
let tags = SceneTags::new();
assert_eq!(tags.len(), 0);
assert!(tags.is_empty());
}
#[test]
fn test_len_after_adds() {
let mut tags = SceneTags::new();
tags.add_tag("a");
tags.add_tag("b");
tags.add_tag("A"); assert_eq!(tags.len(), 2);
}
#[test]
fn test_iter_yields_all_tags() {
let mut tags = SceneTags::new();
tags.add_tag("x");
tags.add_tag("y");
let collected: Vec<&str> = tags.iter().collect();
assert_eq!(collected.len(), 2);
}
#[test]
fn test_is_outdoor_true() {
let meta = SceneMetadata::new(true, true, "park");
assert!(meta.is_outdoor());
}
#[test]
fn test_is_outdoor_false() {
let meta = SceneMetadata::new(false, true, "studio");
assert!(!meta.is_outdoor());
}
#[test]
fn test_is_daylight_true() {
let meta = SceneMetadata::new(true, true, "beach");
assert!(meta.is_daylight());
}
#[test]
fn test_is_daylight_false() {
let meta = SceneMetadata::new(false, false, "nightclub");
assert!(!meta.is_daylight());
}
#[test]
fn test_default_metadata() {
let meta = SceneMetadata::default();
assert!(!meta.is_outdoor());
assert!(meta.is_daylight());
assert_eq!(meta.location, "unknown");
}
#[test]
fn test_metadata_tags_integration() {
let mut meta = SceneMetadata::new(true, true, "forest");
meta.tags.add_tag("nature");
assert!(meta.tags.has_tag("nature"));
}
#[test]
fn test_keywords_add_and_contains() {
let mut kw = SceneKeywords::new();
kw.add("Sunset");
assert!(kw.contains("sunset"));
assert!(kw.contains("SUNSET"));
}
#[test]
fn test_keywords_merge() {
let mut kw1 = SceneKeywords::new();
kw1.add("alpha");
let mut kw2 = SceneKeywords::new();
kw2.add("beta");
kw2.add("gamma");
kw1.merge(&kw2);
assert_eq!(kw1.len(), 3);
assert!(kw1.contains("alpha"));
assert!(kw1.contains("beta"));
assert!(kw1.contains("gamma"));
}
#[test]
fn test_keywords_merge_deduplicates() {
let mut kw1 = SceneKeywords::new();
kw1.add("shared");
let mut kw2 = SceneKeywords::new();
kw2.add("SHARED");
kw1.merge(&kw2);
assert_eq!(kw1.len(), 1);
}
#[test]
fn test_keywords_is_empty() {
let kw = SceneKeywords::new();
assert!(kw.is_empty());
}
}