nu_analytics/core/models/
degree.rs

1//! Degree model
2
3use serde::{Deserialize, Serialize};
4
5/// Represents a degree program
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub struct Degree {
8    /// Degree name (e.g., "Computer Science")
9    pub name: String,
10
11    /// Degree type (e.g., "BS", "BA", "MS")
12    pub degree_type: String,
13
14    /// CIP code (Classification of Instructional Programs)
15    pub cip_code: String,
16
17    /// System type ("semester" or "quarter")
18    pub system_type: String,
19}
20
21impl Degree {
22    /// Create a new degree
23    ///
24    /// # Arguments
25    /// * `name` - Degree name
26    /// * `degree_type` - Degree type (BS, BA, etc.)
27    /// * `cip_code` - CIP code
28    /// * `system_type` - System type ("semester" or "quarter")
29    #[must_use]
30    pub const fn new(
31        name: String,
32        degree_type: String,
33        cip_code: String,
34        system_type: String,
35    ) -> Self {
36        Self {
37            name,
38            degree_type,
39            cip_code,
40            system_type,
41        }
42    }
43
44    /// Check if this degree uses a quarter system
45    #[must_use]
46    pub fn is_quarter_system(&self) -> bool {
47        self.system_type.to_lowercase().contains("quarter")
48    }
49
50    /// Get the complexity scaling factor based on system type
51    ///
52    /// Quarter systems scale complexity by 2/3 compared to semester systems
53    #[must_use]
54    pub fn complexity_scale_factor(&self) -> f64 {
55        if self.is_quarter_system() {
56            2.0 / 3.0
57        } else {
58            1.0
59        }
60    }
61
62    /// Get a unique identifier for this degree
63    ///
64    /// # Returns
65    /// A string combining name and type (e.g., "BS Computer Science")
66    #[must_use]
67    pub fn id(&self) -> String {
68        format!("{} {}", self.degree_type, self.name)
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_degree_creation() {
78        let degree = Degree::new(
79            "Computer Science".to_string(),
80            "BS".to_string(),
81            "11.0701".to_string(),
82            "semester".to_string(),
83        );
84
85        assert_eq!(degree.name, "Computer Science");
86        assert_eq!(degree.degree_type, "BS");
87        assert_eq!(degree.cip_code, "11.0701");
88        assert_eq!(degree.system_type, "semester");
89    }
90
91    #[test]
92    fn test_degree_id() {
93        let degree = Degree::new(
94            "Computer Science".to_string(),
95            "BS".to_string(),
96            "11.0701".to_string(),
97            "semester".to_string(),
98        );
99
100        assert_eq!(degree.id(), "BS Computer Science");
101    }
102
103    #[test]
104    fn test_different_degree_types() {
105        let bs = Degree::new(
106            "Computer Science".to_string(),
107            "BS".to_string(),
108            "11.0701".to_string(),
109            "semester".to_string(),
110        );
111
112        let ba = Degree::new(
113            "Computer Science".to_string(),
114            "BA".to_string(),
115            "11.0701".to_string(),
116            "semester".to_string(),
117        );
118
119        assert_ne!(bs, ba);
120        assert_ne!(bs.id(), ba.id());
121    }
122
123    #[test]
124    fn test_custom_degree_type() {
125        let degree = Degree::new(
126            "Data Science".to_string(),
127            "Master of Science".to_string(),
128            "30.7001".to_string(),
129            "semester".to_string(),
130        );
131
132        assert_eq!(degree.degree_type, "Master of Science");
133        assert_eq!(degree.id(), "Master of Science Data Science");
134    }
135
136    #[test]
137    fn test_quarter_system() {
138        let degree = Degree::new(
139            "Computer Science".to_string(),
140            "BS".to_string(),
141            "11.0701".to_string(),
142            "quarter".to_string(),
143        );
144
145        assert!(degree.is_quarter_system());
146        assert!((degree.complexity_scale_factor() - 2.0 / 3.0).abs() < f64::EPSILON);
147    }
148
149    #[test]
150    fn test_semester_system() {
151        let degree = Degree::new(
152            "Computer Science".to_string(),
153            "BS".to_string(),
154            "11.0701".to_string(),
155            "semester".to_string(),
156        );
157
158        assert!(!degree.is_quarter_system());
159        assert!((degree.complexity_scale_factor() - 1.0).abs() < f64::EPSILON);
160    }
161}