scim_server/resource/value_objects/
multi_valued.rs

1//! Multi-valued attribute container for SCIM resources.
2//!
3//! This module provides a generic container for handling multi-valued attributes
4//! in SCIM resources, with support for primary value tracking and validation.
5//!
6//! ## Design Principles
7//!
8//! - **Type Safety**: Generic over the contained value type
9//! - **Primary Constraint**: Ensures at most one primary value exists
10//! - **Immutable Operations**: Most operations return new instances
11//! - **SCIM Compliance**: Follows SCIM 2.0 multi-valued attribute patterns
12//!
13//! ## Usage Pattern
14//!
15//! ```rust
16//! use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
17//!
18//! fn main() -> Result<(), Box<dyn std::error::Error>> {
19//!     // Create multi-valued email addresses
20//!     let emails = vec![
21//!         EmailAddress::new_simple("work@example.com".to_string())?,
22//!         EmailAddress::new_simple("personal@example.com".to_string())?,
23//!     ];
24//!
25//!     let multi_emails = MultiValuedAttribute::new(emails)?;
26//!
27//!     // Set primary email
28//!     let with_primary = multi_emails.with_primary(0)?;
29//!
30//!     // Access primary email
31//!     if let Some(primary) = with_primary.primary() {
32//!         println!("Primary email: {}", primary.value());
33//!     }
34//!     Ok(())
35//! }
36//! ```
37
38use crate::error::{ValidationError, ValidationResult};
39use serde::{Deserialize, Serialize};
40use std::fmt;
41
42/// A generic container for multi-valued SCIM attributes.
43///
44/// This type provides type-safe handling of multi-valued attributes with
45/// support for designating one value as primary. It enforces the SCIM
46/// constraint that at most one value can be marked as primary.
47///
48/// # Type Parameters
49///
50/// * `T` - The type of values contained in the multi-valued attribute
51///
52/// # Examples
53///
54/// ```rust
55/// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
56///
57/// fn main() -> Result<(), Box<dyn std::error::Error>> {
58///     let emails = vec![
59///         EmailAddress::new_simple("work@example.com".to_string())?,
60///         EmailAddress::new_simple("personal@example.com".to_string())?,
61///     ];
62///
63///     let multi_emails = MultiValuedAttribute::new(emails)?;
64///     assert_eq!(multi_emails.len(), 2);
65///     assert!(multi_emails.primary().is_none());
66///     Ok(())
67/// }
68/// ```
69#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
70pub struct MultiValuedAttribute<T> {
71    /// The collection of values
72    values: Vec<T>,
73    /// Index of the primary value, if any
74    primary_index: Option<usize>,
75}
76
77impl<T> MultiValuedAttribute<T> {
78    /// Creates a new multi-valued attribute from a collection of values.
79    ///
80    /// # Arguments
81    ///
82    /// * `values` - Vector of values to store
83    ///
84    /// # Returns
85    ///
86    /// * `Ok(MultiValuedAttribute<T>)` - Successfully created multi-valued attribute
87    /// * `Err(ValidationError)` - If the input is invalid (e.g., empty vector)
88    ///
89    /// # Examples
90    ///
91    /// ```rust
92    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
93    ///
94    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
95    ///     let emails = vec![
96    ///         EmailAddress::new_simple("work@example.com".to_string())?,
97    ///         EmailAddress::new_simple("personal@example.com".to_string())?,
98    ///     ];
99    ///     let multi_emails = MultiValuedAttribute::new(emails)?;
100    ///     Ok(())
101    /// }
102    /// ```
103    pub fn new(values: Vec<T>) -> ValidationResult<Self> {
104        if values.is_empty() {
105            return Err(ValidationError::custom(
106                "Multi-valued attribute cannot be empty",
107            ));
108        }
109
110        Ok(Self {
111            values,
112            primary_index: None,
113        })
114    }
115
116    /// Creates a new multi-valued attribute with a single value.
117    ///
118    /// # Arguments
119    ///
120    /// * `value` - Single value to store
121    ///
122    /// # Returns
123    ///
124    /// A multi-valued attribute containing the single value
125    ///
126    /// # Examples
127    ///
128    /// ```rust
129    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
130    ///
131    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
132    ///     let email = EmailAddress::new_simple("user@example.com".to_string())?;
133    ///     let multi_email = MultiValuedAttribute::single(email);
134    ///     assert_eq!(multi_email.len(), 1);
135    ///     Ok(())
136    /// }
137    /// ```
138    pub fn single(value: T) -> Self {
139        Self {
140            values: vec![value],
141            primary_index: None,
142        }
143    }
144
145    /// Creates a new multi-valued attribute with a single primary value.
146    ///
147    /// # Arguments
148    ///
149    /// * `value` - Single value to store as primary
150    ///
151    /// # Returns
152    ///
153    /// A multi-valued attribute containing the single primary value
154    ///
155    /// # Examples
156    ///
157    /// ```rust
158    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
159    ///
160    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
161    ///     let email = EmailAddress::new_simple("primary@example.com".to_string())?;
162    ///     let multi_email = MultiValuedAttribute::single_primary(email);
163    ///     assert!(multi_email.primary().is_some());
164    ///     Ok(())
165    /// }
166    /// ```
167    pub fn single_primary(value: T) -> Self {
168        Self {
169            values: vec![value],
170            primary_index: Some(0),
171        }
172    }
173
174    /// Creates an empty multi-valued attribute for internal use.
175    ///
176    /// This method bypasses validation and is intended for internal use
177    /// where empty collections are temporarily needed during construction.
178    ///
179    /// # Returns
180    ///
181    /// An empty multi-valued attribute
182    pub(crate) fn empty() -> Self {
183        Self {
184            values: Vec::new(),
185            primary_index: None,
186        }
187    }
188
189    /// Returns the number of values in the collection.
190    ///
191    /// # Examples
192    ///
193    /// ```rust
194    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
195    ///
196    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
197    ///     let emails = vec![
198    ///         EmailAddress::new_simple("work@example.com".to_string())?,
199    ///         EmailAddress::new_simple("personal@example.com".to_string())?,
200    ///     ];
201    ///     let multi_attr = MultiValuedAttribute::new(emails)?;
202    ///     assert_eq!(multi_attr.len(), 2);
203    ///     Ok(())
204    /// }
205    /// ```
206    pub fn len(&self) -> usize {
207        self.values.len()
208    }
209
210    /// Returns true if the collection is empty.
211    ///
212    /// # Examples
213    ///
214    /// ```rust
215    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
216    ///
217    /// let multi_attr = MultiValuedAttribute::single(
218    ///     EmailAddress::new_simple("test@example.com".to_string()).unwrap()
219    /// );
220    /// assert!(!multi_attr.is_empty());
221    /// ```
222    pub fn is_empty(&self) -> bool {
223        self.values.is_empty()
224    }
225
226    /// Returns a reference to the primary value, if one is set.
227    ///
228    /// # Returns
229    ///
230    /// * `Some(&T)` - Reference to the primary value
231    /// * `None` - No primary value is set
232    ///
233    /// # Examples
234    ///
235    /// ```rust
236    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
237    ///
238    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
239    ///     let emails = vec![
240    ///         EmailAddress::new_simple("work@example.com".to_string())?,
241    ///         EmailAddress::new_simple("personal@example.com".to_string())?,
242    ///     ];
243    ///     let multi_attr = MultiValuedAttribute::new(emails)?.with_primary(0)?;
244    ///     if let Some(primary) = multi_attr.primary() {
245    ///         println!("Primary value found");
246    ///     }
247    ///     Ok(())
248    /// }
249    /// ```
250    pub fn primary(&self) -> Option<&T> {
251        self.primary_index.and_then(|index| self.values.get(index))
252    }
253
254    /// Returns the index of the primary value, if one is set.
255    ///
256    /// # Returns
257    ///
258    /// * `Some(usize)` - Index of the primary value
259    /// * `None` - No primary value is set
260    pub fn primary_index(&self) -> Option<usize> {
261        self.primary_index
262    }
263
264    /// Returns a reference to all values in the collection.
265    ///
266    /// # Examples
267    ///
268    /// ```rust
269    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
270    ///
271    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
272    ///     let emails = vec![
273    ///         EmailAddress::new_simple("work@example.com".to_string())?,
274    ///         EmailAddress::new_simple("personal@example.com".to_string())?,
275    ///     ];
276    ///     let multi_attr = MultiValuedAttribute::new(emails)?;
277    ///     for value in multi_attr.values() {
278    ///         println!("Value: {:?}", value);
279    ///     }
280    ///     Ok(())
281    /// }
282    /// ```
283    pub fn values(&self) -> &[T] {
284        &self.values
285    }
286
287    /// Returns a reference to the value at the specified index.
288    ///
289    /// # Arguments
290    ///
291    /// * `index` - Index of the value to retrieve
292    ///
293    /// # Returns
294    ///
295    /// * `Some(&T)` - Reference to the value at the index
296    /// * `None` - Index is out of bounds
297    pub fn get(&self, index: usize) -> Option<&T> {
298        self.values.get(index)
299    }
300
301    /// Creates a new multi-valued attribute with the specified value set as primary.
302    ///
303    /// # Arguments
304    ///
305    /// * `index` - Index of the value to set as primary
306    ///
307    /// # Returns
308    ///
309    /// * `Ok(MultiValuedAttribute<T>)` - New instance with primary value set
310    /// * `Err(ValidationError)` - If the index is out of bounds
311    ///
312    /// # Examples
313    ///
314    /// ```rust
315    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
316    ///
317    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
318    ///     let emails = vec![
319    ///         EmailAddress::new_simple("work@example.com".to_string())?,
320    ///         EmailAddress::new_simple("personal@example.com".to_string())?,
321    ///     ];
322    ///     let multi_attr = MultiValuedAttribute::new(emails)?;
323    ///     let with_primary = multi_attr.with_primary(0)?;
324    ///     assert!(with_primary.primary().is_some());
325    ///     Ok(())
326    /// }
327    /// ```
328    pub fn with_primary(mut self, index: usize) -> ValidationResult<Self> {
329        if index >= self.values.len() {
330            return Err(ValidationError::custom(format!(
331                "Primary index {} is out of bounds for collection of size {}",
332                index,
333                self.values.len()
334            )));
335        }
336
337        self.primary_index = Some(index);
338        Ok(self)
339    }
340
341    /// Creates a new multi-valued attribute with no primary value set.
342    ///
343    /// # Examples
344    ///
345    /// ```rust
346    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
347    ///
348    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
349    ///     let emails = vec![
350    ///         EmailAddress::new_simple("work@example.com".to_string())?,
351    ///         EmailAddress::new_simple("personal@example.com".to_string())?,
352    ///     ];
353    ///     let multi_attr = MultiValuedAttribute::new(emails)?.with_primary(0)?;
354    ///     let without_primary = multi_attr.without_primary();
355    ///     assert!(without_primary.primary().is_none());
356    ///     Ok(())
357    /// }
358    /// ```
359    pub fn without_primary(mut self) -> Self {
360        self.primary_index = None;
361        self
362    }
363
364    /// Creates a new multi-valued attribute with an additional value.
365    ///
366    /// # Arguments
367    ///
368    /// * `value` - Value to add to the collection
369    ///
370    /// # Returns
371    ///
372    /// A new multi-valued attribute with the added value
373    ///
374    /// # Examples
375    ///
376    /// ```rust
377    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
378    ///
379    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
380    ///     let emails = vec![
381    ///         EmailAddress::new_simple("work@example.com".to_string())?,
382    ///     ];
383    ///     let multi_attr = MultiValuedAttribute::new(emails)?;
384    ///     let new_email = EmailAddress::new_simple("personal@example.com".to_string())?;
385    ///     let with_value = multi_attr.with_value(new_email);
386    ///     assert_eq!(with_value.len(), 2);
387    ///     Ok(())
388    /// }
389    /// ```
390    pub fn with_value(mut self, value: T) -> Self {
391        self.values.push(value);
392        self
393    }
394
395    /// Creates a new multi-valued attribute with an additional primary value.
396    ///
397    /// This method adds the value and sets it as the primary value.
398    ///
399    /// # Arguments
400    ///
401    /// * `value` - Value to add as primary
402    ///
403    /// # Returns
404    ///
405    /// A new multi-valued attribute with the added primary value
406    ///
407    /// # Examples
408    ///
409    /// ```rust
410    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
411    ///
412    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
413    ///     let emails = vec![
414    ///         EmailAddress::new_simple("work@example.com".to_string())?,
415    ///     ];
416    ///     let multi_attr = MultiValuedAttribute::new(emails)?;
417    ///     let new_email = EmailAddress::new_simple("primary@example.com".to_string())?;
418    ///     let with_primary = multi_attr.with_primary_value(new_email.clone());
419    ///     assert_eq!(with_primary.primary(), Some(&new_email));
420    ///     Ok(())
421    /// }
422    /// ```
423    pub fn with_primary_value(mut self, value: T) -> Self {
424        self.values.push(value);
425        self.primary_index = Some(self.values.len() - 1);
426        self
427    }
428
429    /// Returns an iterator over the values in the collection.
430    ///
431    /// # Examples
432    ///
433    /// ```rust
434    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
435    ///
436    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
437    ///     let emails = vec![
438    ///         EmailAddress::new_simple("work@example.com".to_string())?,
439    ///         EmailAddress::new_simple("personal@example.com".to_string())?,
440    ///     ];
441    ///     let multi_attr = MultiValuedAttribute::new(emails)?;
442    ///     for value in multi_attr.iter() {
443    ///         println!("Value: {:?}", value);
444    ///     }
445    ///     Ok(())
446    /// }
447    /// ```
448    pub fn iter(&self) -> std::slice::Iter<'_, T> {
449        self.values.iter()
450    }
451
452    /// Validates that at most one value is marked as primary.
453    ///
454    /// This method is primarily used internally to ensure invariants
455    /// are maintained during construction and modification.
456    ///
457    /// # Returns
458    ///
459    /// * `Ok(())` - Validation passed
460    /// * `Err(ValidationError)` - Multiple primary values detected
461    pub fn validate_single_primary(&self) -> ValidationResult<()> {
462        if let Some(index) = self.primary_index {
463            if index >= self.values.len() {
464                return Err(ValidationError::custom(
465                    "Primary index points to non-existent value",
466                ));
467            }
468        }
469        Ok(())
470    }
471
472    /// Finds the first value that matches the given predicate.
473    ///
474    /// # Arguments
475    ///
476    /// * `predicate` - Function to test each value
477    ///
478    /// # Returns
479    ///
480    /// * `Some(&T)` - Reference to the first matching value
481    /// * `None` - No value matches the predicate
482    ///
483    /// # Examples
484    ///
485    /// ```rust
486    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
487    ///
488    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
489    ///     let emails = vec![
490    ///         EmailAddress::new_simple("work@example.com".to_string())?,
491    ///         EmailAddress::new_simple("personal@example.com".to_string())?,
492    ///     ];
493    ///     let multi_attr = MultiValuedAttribute::new(emails)?;
494    ///     let found = multi_attr.find(|value| value.value().contains("work"));
495    ///     assert!(found.is_some());
496    ///     Ok(())
497    /// }
498    /// ```
499    pub fn find<P>(&self, predicate: P) -> Option<&T>
500    where
501        P: Fn(&T) -> bool,
502    {
503        self.values.iter().find(|&value| predicate(value))
504    }
505
506    /// Returns all values that satisfy the given predicate.
507    /// Filters values that match the given predicate.
508    ///
509    /// # Arguments
510    ///
511    /// * `predicate` - Function to test each value
512    ///
513    /// # Returns
514    ///
515    /// An iterator over references to matching values
516    ///
517    /// # Examples
518    ///
519    /// ```rust
520    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
521    ///
522    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
523    ///     let emails = vec![
524    ///         EmailAddress::new_simple("work@example.com".to_string())?,
525    ///         EmailAddress::new_simple("personal@example.com".to_string())?,
526    ///     ];
527    ///     let multi_attr = MultiValuedAttribute::new(emails)?;
528    ///     let work_values = multi_attr.filter(|v| v.value().contains("work"));
529    ///     assert_eq!(work_values.len(), 1);
530    ///     Ok(())
531    /// }
532    /// ```
533    pub fn filter<P>(&self, predicate: P) -> Vec<&T>
534    where
535        P: Fn(&T) -> bool,
536    {
537        self.values
538            .iter()
539            .filter(|&value| predicate(value))
540            .collect()
541    }
542
543    /// Converts the multi-valued attribute into a vector of values.
544    ///
545    /// This consumes the multi-valued attribute and returns the underlying vector.
546    ///
547    /// # Examples
548    ///
549    /// ```rust
550    /// use scim_server::resource::value_objects::{MultiValuedAttribute, EmailAddress};
551    ///
552    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
553    ///     let emails = vec![
554    ///         EmailAddress::new_simple("work@example.com".to_string())?,
555    ///         EmailAddress::new_simple("personal@example.com".to_string())?,
556    ///     ];
557    ///     let multi_attr = MultiValuedAttribute::new(emails)?;
558    ///     let values_vec = multi_attr.into_values();
559    ///     assert_eq!(values_vec.len(), 2);
560    ///     Ok(())
561    /// }
562    /// ```
563    pub fn into_values(self) -> Vec<T> {
564        self.values
565    }
566}
567
568impl<T> Default for MultiValuedAttribute<T> {
569    /// Creates an empty multi-valued attribute.
570    ///
571    /// Note: This creates an empty collection which may not be valid
572    /// for all use cases. Use `new()` for validated construction.
573    fn default() -> Self {
574        Self::empty()
575    }
576}
577
578impl<T> From<Vec<T>> for MultiValuedAttribute<T> {
579    /// Creates a multi-valued attribute from a vector of values.
580    ///
581    /// This bypasses validation and should be used carefully.
582    /// Consider using `new()` for validated construction.
583    fn from(values: Vec<T>) -> Self {
584        Self {
585            values,
586            primary_index: None,
587        }
588    }
589}
590
591impl<T> From<T> for MultiValuedAttribute<T> {
592    /// Creates a multi-valued attribute from a single value.
593    fn from(value: T) -> Self {
594        Self::single(value)
595    }
596}
597
598impl<T> IntoIterator for MultiValuedAttribute<T> {
599    type Item = T;
600    type IntoIter = std::vec::IntoIter<T>;
601
602    /// Creates an iterator that yields owned values.
603    fn into_iter(self) -> Self::IntoIter {
604        self.values.into_iter()
605    }
606}
607
608impl<'a, T> IntoIterator for &'a MultiValuedAttribute<T> {
609    type Item = &'a T;
610    type IntoIter = std::slice::Iter<'a, T>;
611
612    /// Creates an iterator that yields borrowed values.
613    fn into_iter(self) -> Self::IntoIter {
614        self.iter()
615    }
616}
617
618impl<T: fmt::Display> fmt::Display for MultiValuedAttribute<T> {
619    /// Formats the multi-valued attribute for display.
620    ///
621    /// Shows the number of values and indicates which one is primary.
622    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
623        match self.primary() {
624            Some(primary) => write!(
625                f,
626                "MultiValuedAttribute({} values, primary: {})",
627                self.len(),
628                primary
629            ),
630            None => write!(f, "MultiValuedAttribute({} values)", self.len()),
631        }
632    }
633}
634
635#[cfg(test)]
636mod tests {
637    use super::*;
638
639    #[derive(Debug, Clone, PartialEq)]
640    struct TestValue {
641        id: String,
642        value_type: String,
643    }
644
645    impl fmt::Display for TestValue {
646        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
647            write!(f, "{}: {}", self.value_type, self.id)
648        }
649    }
650
651    fn create_test_values() -> Vec<TestValue> {
652        vec![
653            TestValue {
654                id: "1".to_string(),
655                value_type: "work".to_string(),
656            },
657            TestValue {
658                id: "2".to_string(),
659                value_type: "home".to_string(),
660            },
661            TestValue {
662                id: "3".to_string(),
663                value_type: "other".to_string(),
664            },
665        ]
666    }
667
668    #[test]
669    fn test_new_valid() {
670        let values = create_test_values();
671        let multi_attr = MultiValuedAttribute::new(values.clone()).unwrap();
672
673        assert_eq!(multi_attr.len(), 3);
674        assert!(!multi_attr.is_empty());
675        assert!(multi_attr.primary().is_none());
676        assert_eq!(multi_attr.values(), &values);
677    }
678
679    #[test]
680    fn test_new_empty_fails() {
681        let result = MultiValuedAttribute::<TestValue>::new(vec![]);
682        assert!(result.is_err());
683        assert!(result.unwrap_err().to_string().contains("cannot be empty"));
684    }
685
686    #[test]
687    fn test_single() {
688        let value = TestValue {
689            id: "1".to_string(),
690            value_type: "work".to_string(),
691        };
692        let multi_attr = MultiValuedAttribute::single(value.clone());
693
694        assert_eq!(multi_attr.len(), 1);
695        assert!(multi_attr.primary().is_none());
696        assert_eq!(multi_attr.get(0), Some(&value));
697    }
698
699    #[test]
700    fn test_single_primary() {
701        let value = TestValue {
702            id: "1".to_string(),
703            value_type: "work".to_string(),
704        };
705        let multi_attr = MultiValuedAttribute::single_primary(value.clone());
706
707        assert_eq!(multi_attr.len(), 1);
708        assert_eq!(multi_attr.primary(), Some(&value));
709        assert_eq!(multi_attr.primary_index(), Some(0));
710    }
711
712    #[test]
713    fn test_with_primary() {
714        let values = create_test_values();
715        let multi_attr = MultiValuedAttribute::new(values.clone())
716            .unwrap()
717            .with_primary(1)
718            .unwrap();
719
720        assert_eq!(multi_attr.primary(), Some(&values[1]));
721        assert_eq!(multi_attr.primary_index(), Some(1));
722    }
723
724    #[test]
725    fn test_with_primary_invalid_index() {
726        let values = create_test_values();
727        let result = MultiValuedAttribute::new(values).unwrap().with_primary(10);
728
729        assert!(result.is_err());
730        assert!(result.unwrap_err().to_string().contains("out of bounds"));
731    }
732
733    #[test]
734    fn test_without_primary() {
735        let values = create_test_values();
736        let multi_attr = MultiValuedAttribute::new(values)
737            .unwrap()
738            .with_primary(0)
739            .unwrap()
740            .without_primary();
741
742        assert!(multi_attr.primary().is_none());
743        assert_eq!(multi_attr.primary_index(), None);
744    }
745
746    #[test]
747    fn test_with_value() {
748        let values = create_test_values();
749        let new_value = TestValue {
750            id: "4".to_string(),
751            value_type: "mobile".to_string(),
752        };
753
754        let multi_attr = MultiValuedAttribute::new(values)
755            .unwrap()
756            .with_value(new_value.clone());
757
758        assert_eq!(multi_attr.len(), 4);
759        assert_eq!(multi_attr.get(3), Some(&new_value));
760    }
761
762    #[test]
763    fn test_with_primary_value() {
764        let values = create_test_values();
765        let new_value = TestValue {
766            id: "4".to_string(),
767            value_type: "mobile".to_string(),
768        };
769
770        let multi_attr = MultiValuedAttribute::new(values)
771            .unwrap()
772            .with_primary_value(new_value.clone());
773
774        assert_eq!(multi_attr.len(), 4);
775        assert_eq!(multi_attr.primary(), Some(&new_value));
776        assert_eq!(multi_attr.primary_index(), Some(3));
777    }
778
779    #[test]
780    fn test_find() {
781        let values = create_test_values();
782        let multi_attr = MultiValuedAttribute::new(values.clone()).unwrap();
783
784        let work_value = multi_attr.find(|v| v.value_type == "work");
785        assert_eq!(work_value, Some(&values[0]));
786
787        let mobile_value = multi_attr.find(|v| v.value_type == "mobile");
788        assert_eq!(mobile_value, None);
789    }
790
791    #[test]
792    fn test_filter() {
793        let values = create_test_values();
794        let multi_attr = MultiValuedAttribute::new(values.clone()).unwrap();
795
796        let work_values = multi_attr.filter(|v| v.value_type == "work");
797        assert_eq!(work_values, vec![&values[0]]);
798
799        let non_work_values = multi_attr.filter(|v| v.value_type != "work");
800        assert_eq!(non_work_values, vec![&values[1], &values[2]]);
801    }
802
803    #[test]
804    fn test_into_values() {
805        let values = create_test_values();
806        let expected = values.clone();
807        let multi_attr = MultiValuedAttribute::new(values).unwrap();
808
809        let extracted_values = multi_attr.into_values();
810        assert_eq!(extracted_values, expected);
811    }
812
813    #[test]
814    fn test_iter() {
815        let values = create_test_values();
816        let multi_attr = MultiValuedAttribute::new(values.clone()).unwrap();
817
818        let collected: Vec<&TestValue> = multi_attr.iter().collect();
819        let expected: Vec<&TestValue> = values.iter().collect();
820        assert_eq!(collected, expected);
821    }
822
823    #[test]
824    fn test_into_iter_owned() {
825        let values = create_test_values();
826        let expected = values.clone();
827        let multi_attr = MultiValuedAttribute::new(values).unwrap();
828
829        let collected: Vec<TestValue> = multi_attr.into_iter().collect();
830        assert_eq!(collected, expected);
831    }
832
833    #[test]
834    fn test_into_iter_borrowed() {
835        let values = create_test_values();
836        let multi_attr = MultiValuedAttribute::new(values.clone()).unwrap();
837
838        let collected: Vec<&TestValue> = (&multi_attr).into_iter().collect();
839        let expected: Vec<&TestValue> = values.iter().collect();
840        assert_eq!(collected, expected);
841    }
842
843    #[test]
844    fn test_validate_single_primary() {
845        let values = create_test_values();
846        let multi_attr = MultiValuedAttribute::new(values)
847            .unwrap()
848            .with_primary(1)
849            .unwrap();
850
851        assert!(multi_attr.validate_single_primary().is_ok());
852    }
853
854    #[test]
855    fn test_validate_single_primary_invalid_index() {
856        let values = create_test_values();
857        let mut multi_attr = MultiValuedAttribute::new(values).unwrap();
858        // Manually set invalid primary index for testing
859        multi_attr.primary_index = Some(10);
860
861        assert!(multi_attr.validate_single_primary().is_err());
862    }
863
864    #[test]
865    fn test_default() {
866        let multi_attr = MultiValuedAttribute::<TestValue>::default();
867        assert!(multi_attr.is_empty());
868        assert_eq!(multi_attr.len(), 0);
869    }
870
871    #[test]
872    fn test_from_vec() {
873        let values = create_test_values();
874        let multi_attr: MultiValuedAttribute<TestValue> =
875            MultiValuedAttribute::from(values.clone());
876
877        assert_eq!(multi_attr.len(), 3);
878        assert_eq!(multi_attr.values(), &values);
879    }
880
881    #[test]
882    fn test_from_single_value() {
883        let value = TestValue {
884            id: "1".to_string(),
885            value_type: "work".to_string(),
886        };
887        let multi_attr = MultiValuedAttribute::from(value.clone());
888
889        assert_eq!(multi_attr.len(), 1);
890        assert_eq!(multi_attr.get(0), Some(&value));
891    }
892
893    #[test]
894    fn test_display() {
895        let values = create_test_values();
896        let multi_attr = MultiValuedAttribute::new(values).unwrap();
897
898        let display_str = format!("{}", multi_attr);
899        assert!(display_str.contains("MultiValuedAttribute(3 values)"));
900
901        let with_primary = multi_attr.with_primary(0).unwrap();
902        let primary_display = format!("{}", with_primary);
903        assert!(primary_display.contains("primary: work: 1"));
904    }
905
906    #[test]
907    fn test_get_valid_index() {
908        let values = create_test_values();
909        let multi_attr = MultiValuedAttribute::new(values.clone()).unwrap();
910
911        assert_eq!(multi_attr.get(0), Some(&values[0]));
912        assert_eq!(multi_attr.get(1), Some(&values[1]));
913        assert_eq!(multi_attr.get(2), Some(&values[2]));
914    }
915
916    #[test]
917    fn test_get_invalid_index() {
918        let values = create_test_values();
919        let multi_attr = MultiValuedAttribute::new(values).unwrap();
920
921        assert_eq!(multi_attr.get(10), None);
922    }
923
924    #[test]
925    fn test_empty() {
926        let multi_attr = MultiValuedAttribute::<TestValue>::empty();
927        assert!(multi_attr.is_empty());
928        assert_eq!(multi_attr.len(), 0);
929        assert!(multi_attr.primary().is_none());
930    }
931}