cc_audit/types/
newtypes.rs1use serde::{Deserialize, Serialize};
4use std::fmt;
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(transparent)]
11pub struct GitRef(String);
12
13impl GitRef {
14 pub fn new(s: impl Into<String>) -> Self {
16 Self(s.into())
17 }
18
19 pub fn as_str(&self) -> &str {
21 &self.0
22 }
23
24 pub fn into_inner(self) -> String {
26 self.0
27 }
28}
29
30impl Default for GitRef {
31 fn default() -> Self {
32 Self("HEAD".to_string())
33 }
34}
35
36impl From<&str> for GitRef {
37 fn from(s: &str) -> Self {
38 Self(s.to_string())
39 }
40}
41
42impl From<String> for GitRef {
43 fn from(s: String) -> Self {
44 Self(s)
45 }
46}
47
48impl AsRef<str> for GitRef {
49 fn as_ref(&self) -> &str {
50 &self.0
51 }
52}
53
54impl fmt::Display for GitRef {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 write!(f, "{}", self.0)
57 }
58}
59
60#[derive(Clone, Serialize, Deserialize)]
64#[serde(transparent)]
65pub struct AuthToken(String);
66
67impl AuthToken {
68 pub fn new(s: impl Into<String>) -> Self {
70 Self(s.into())
71 }
72
73 pub fn as_str(&self) -> &str {
75 &self.0
76 }
77
78 pub fn into_inner(self) -> String {
80 self.0
81 }
82
83 pub fn is_empty(&self) -> bool {
85 self.0.is_empty()
86 }
87}
88
89impl fmt::Debug for AuthToken {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 if self.0.is_empty() {
92 write!(f, "AuthToken(empty)")
93 } else {
94 write!(f, "AuthToken(***)")
95 }
96 }
97}
98
99impl From<&str> for AuthToken {
100 fn from(s: &str) -> Self {
101 Self(s.to_string())
102 }
103}
104
105impl From<String> for AuthToken {
106 fn from(s: String) -> Self {
107 Self(s)
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
115#[serde(transparent)]
116pub struct RuleId(String);
117
118impl RuleId {
119 pub fn new(s: impl Into<String>) -> Self {
121 Self(s.into())
122 }
123
124 pub fn as_str(&self) -> &str {
126 &self.0
127 }
128
129 pub fn into_inner(self) -> String {
131 self.0
132 }
133}
134
135impl From<&str> for RuleId {
136 fn from(s: &str) -> Self {
137 Self(s.to_string())
138 }
139}
140
141impl From<String> for RuleId {
142 fn from(s: String) -> Self {
143 Self(s)
144 }
145}
146
147impl AsRef<str> for RuleId {
148 fn as_ref(&self) -> &str {
149 &self.0
150 }
151}
152
153impl fmt::Display for RuleId {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 write!(f, "{}", self.0)
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
161#[serde(transparent)]
162pub struct FileHash(String);
163
164impl FileHash {
165 pub fn new(s: impl Into<String>) -> Self {
167 Self(s.into())
168 }
169
170 pub fn as_str(&self) -> &str {
172 &self.0
173 }
174
175 pub fn into_inner(self) -> String {
177 self.0
178 }
179}
180
181impl From<&str> for FileHash {
182 fn from(s: &str) -> Self {
183 Self(s.to_string())
184 }
185}
186
187impl From<String> for FileHash {
188 fn from(s: String) -> Self {
189 Self(s)
190 }
191}
192
193impl AsRef<str> for FileHash {
194 fn as_ref(&self) -> &str {
195 &self.0
196 }
197}
198
199impl fmt::Display for FileHash {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 write!(f, "{}", self.0)
202 }
203}
204
205#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
207#[serde(transparent)]
208pub struct ServerName(String);
209
210impl ServerName {
211 pub fn new(s: impl Into<String>) -> Self {
213 Self(s.into())
214 }
215
216 pub fn as_str(&self) -> &str {
218 &self.0
219 }
220}
221
222impl From<&str> for ServerName {
223 fn from(s: &str) -> Self {
224 Self(s.to_string())
225 }
226}
227
228impl From<String> for ServerName {
229 fn from(s: String) -> Self {
230 Self(s)
231 }
232}
233
234impl fmt::Display for ServerName {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 write!(f, "{}", self.0)
237 }
238}
239
240#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
242#[serde(transparent)]
243pub struct CommandArgs(Vec<String>);
244
245impl CommandArgs {
246 pub fn new(args: impl IntoIterator<Item = impl Into<String>>) -> Self {
248 Self(args.into_iter().map(Into::into).collect())
249 }
250
251 pub fn as_slice(&self) -> &[String] {
253 &self.0
254 }
255
256 pub fn join(&self, sep: &str) -> String {
258 self.0.join(sep)
259 }
260
261 pub fn is_empty(&self) -> bool {
263 self.0.is_empty()
264 }
265
266 pub fn len(&self) -> usize {
268 self.0.len()
269 }
270}
271
272impl From<Vec<String>> for CommandArgs {
273 fn from(args: Vec<String>) -> Self {
274 Self(args)
275 }
276}
277
278impl<'a> From<&'a [&'a str]> for CommandArgs {
279 fn from(args: &'a [&'a str]) -> Self {
280 Self(args.iter().map(|s| s.to_string()).collect())
281 }
282}
283
284#[derive(Debug, Clone)]
286pub struct CompiledPattern {
287 pattern: regex::Regex,
288 source: String,
289}
290
291impl CompiledPattern {
292 pub fn new(pattern: &str) -> Result<Self, regex::Error> {
294 let regex = regex::Regex::new(pattern)?;
295 Ok(Self {
296 pattern: regex,
297 source: pattern.to_string(),
298 })
299 }
300
301 pub fn is_match(&self, text: &str) -> bool {
303 self.pattern.is_match(text)
304 }
305
306 pub fn as_str(&self) -> &str {
308 &self.source
309 }
310
311 pub fn regex(&self) -> ®ex::Regex {
313 &self.pattern
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320
321 #[test]
322 fn test_git_ref_default() {
323 assert_eq!(GitRef::default().as_str(), "HEAD");
324 }
325
326 #[test]
327 fn test_git_ref_from_str() {
328 let ref1: GitRef = "main".into();
329 assert_eq!(ref1.as_str(), "main");
330
331 let ref2 = GitRef::from("develop");
332 assert_eq!(ref2.as_str(), "develop");
333 }
334
335 #[test]
336 fn test_git_ref_display() {
337 let git_ref = GitRef::new("v1.0.0");
338 assert_eq!(format!("{}", git_ref), "v1.0.0");
339 }
340
341 #[test]
342 fn test_auth_token_debug_hides_value() {
343 let token = AuthToken::new("secret123");
344 let debug = format!("{:?}", token);
345 assert!(!debug.contains("secret123"));
346 assert!(debug.contains("***"));
347 }
348
349 #[test]
350 fn test_auth_token_empty_debug() {
351 let token = AuthToken::new("");
352 let debug = format!("{:?}", token);
353 assert!(debug.contains("empty"));
354 }
355
356 #[test]
357 fn test_rule_id_display() {
358 let id = RuleId::new("PE-001");
359 assert_eq!(format!("{}", id), "PE-001");
360 }
361
362 #[test]
363 fn test_rule_id_equality() {
364 let id1 = RuleId::new("EX-001");
365 let id2 = RuleId::new("EX-001");
366 let id3 = RuleId::new("EX-002");
367 assert_eq!(id1, id2);
368 assert_ne!(id1, id3);
369 }
370
371 #[test]
372 fn test_file_hash_from_string() {
373 let hash = FileHash::new("abc123def456");
374 assert_eq!(hash.as_str(), "abc123def456");
375 }
376
377 #[test]
378 fn test_into_inner() {
379 let git_ref = GitRef::new("main");
380 assert_eq!(git_ref.into_inner(), "main".to_string());
381
382 let rule_id = RuleId::new("PE-001");
383 assert_eq!(rule_id.into_inner(), "PE-001".to_string());
384 }
385
386 #[test]
387 fn test_server_name() {
388 let name = ServerName::new("my-server");
389 assert_eq!(name.as_str(), "my-server");
390 assert_eq!(format!("{}", name), "my-server");
391 }
392
393 #[test]
394 fn test_command_args() {
395 let args = CommandArgs::new(["arg1", "arg2", "arg3"]);
396 assert_eq!(args.len(), 3);
397 assert_eq!(args.join(" "), "arg1 arg2 arg3");
398 assert!(!args.is_empty());
399 }
400
401 #[test]
402 fn test_command_args_empty() {
403 let args = CommandArgs::default();
404 assert!(args.is_empty());
405 assert_eq!(args.len(), 0);
406 }
407
408 #[test]
409 fn test_compiled_pattern() {
410 let pattern = CompiledPattern::new(r"hello\s+world").unwrap();
411 assert!(pattern.is_match("hello world"));
412 assert!(!pattern.is_match("helloworld"));
413 assert_eq!(pattern.as_str(), r"hello\s+world");
414 }
415
416 #[test]
417 fn test_compiled_pattern_invalid() {
418 let result = CompiledPattern::new(r"[invalid");
419 assert!(result.is_err());
420 }
421}