git_bot_feedback/
output_variable.rs1use std::fmt::Display;
2
3use crate::error::OutputVariableError;
4
5#[derive(Debug, Clone)]
13pub struct OutputVariable {
14 pub name: String,
16
17 pub value: String,
19}
20
21impl OutputVariable {
22 pub fn validate(&self) -> Result<(), OutputVariableError> {
27 let name = self.name.trim();
28 if name.is_empty() {
29 return Err(OutputVariableError::NameIsEmpty);
30 }
31 for (i, c) in name.chars().enumerate() {
32 if i == 0 && c.is_ascii_digit() {
33 return Err(OutputVariableError::NameStartsWithNumber(name.to_string()));
34 }
35 if !(c.is_ascii_alphanumeric() || c == '_' || c == '-') {
36 return Err(OutputVariableError::NameContainsNonPrintableCharacters(
37 name.to_string(),
38 ));
39 }
40 }
41 let value = self.value.trim();
42 if !value
43 .chars()
44 .all(|c| c.is_ascii_alphanumeric() || c.is_ascii_punctuation() || !c.is_ascii_control())
45 {
46 return Err(OutputVariableError::ValueContainsNonPrintableCharacters(
47 value.to_string(),
48 ));
49 }
50 Ok(())
51 }
52}
53
54impl Display for OutputVariable {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 write!(f, "{}={}", self.name.trim(), self.value.trim())
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 #![allow(clippy::unwrap_used)]
63
64 use super::{OutputVariable, OutputVariableError};
65
66 #[test]
67 fn empty_name() {
68 let var = OutputVariable {
69 name: " ".to_string(),
70 value: "value".to_string(),
71 };
72 assert_eq!(var.validate(), Err(OutputVariableError::NameIsEmpty));
73 }
74
75 #[test]
76 fn name_starts_with_number() {
77 let var = OutputVariable {
78 name: "1var".to_string(),
79 value: "value".to_string(),
80 };
81 assert_eq!(
82 var.validate(),
83 Err(OutputVariableError::NameStartsWithNumber(
84 "1var".to_string()
85 ))
86 );
87 }
88
89 #[test]
90 fn name_contains_non_printable_characters() {
91 let var = OutputVariable {
92 name: "var\nname".to_string(),
93 value: "value".to_string(),
94 };
95 assert_eq!(
96 var.validate(),
97 Err(OutputVariableError::NameContainsNonPrintableCharacters(
98 "var\nname".to_string()
99 ))
100 );
101 }
102
103 #[test]
104 fn value_contains_non_printable_characters() {
105 let var = OutputVariable {
106 name: "var".to_string(),
107 value: "(val)\nline2".to_string(),
108 };
109 assert_eq!(
110 var.validate(),
111 Err(OutputVariableError::ValueContainsNonPrintableCharacters(
112 "(val)\nline2".to_string()
113 ))
114 );
115 }
116
117 #[test]
118 fn valid_variable() {
119 OutputVariable {
120 name: " VAR_NAME ".to_string(),
121 value: " value -(123) ".to_string(),
122 }
123 .validate()
124 .unwrap();
125 }
126}