gtin_validate/gtin8/
mod.rs1use utils;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum FixError {
8 NonAsciiString,
10 TooLong,
12 CheckDigitIncorrect,
14}
15
16pub fn check(code: &str) -> bool {
28 if code.len() != 8 {
29 return false;
30 }
31 if !utils::is_ascii_numeric(code) {
32 return false;
33 }
34
35 let bytes = code.as_bytes();
37 let check = utils::compute_check_digit(bytes);
38 if check != bytes[7] - 48 {
39 return false;
40 }
41
42 true
43}
44
45pub fn fix(code: &str) -> Result<String, FixError> {
78 let mut fixed = code.trim().to_string();
79
80 if !fixed.is_ascii() {
81 return Err(FixError::NonAsciiString);
82 }
83 if fixed.len() > 8 {
84 return Err(FixError::TooLong);
85 }
86 fixed = utils::zero_pad(fixed, 8);
87 if !check(&fixed) {
88 return Err(FixError::CheckDigitIncorrect);
89 }
90
91 Ok(fixed)
92}
93
94#[cfg(test)]
95mod tests {
96 use super::check;
97 use super::fix;
98 use super::FixError;
99
100 #[test]
101 fn check_valid() {
102 assert_eq!(check("00000000"), true);
103 assert_eq!(check("49137712"), true);
104 assert_eq!(check("44196318"), true);
105 }
106
107 #[test]
108 fn check_invalid_length() {
109 assert_eq!(check("0000000"), false); assert_eq!(check("734289412"), false); }
112
113 #[test]
114 fn check_non_ascii() {
115 assert_eq!(check("❤"), false);
116 }
117
118 #[test]
119 fn check_non_numeric() {
120 assert_eq!(check("a"), false);
121 assert_eq!(check("abcdabcd"), false); assert_eq!(check("0000000a"), false); }
124
125 #[test]
126 fn check_invalid_check_digit() {
127 assert_eq!(check("00000001"), false);
128 assert_eq!(check("00000002"), false);
129 assert_eq!(check("00000003"), false);
130 assert_eq!(check("00000004"), false);
131 assert_eq!(check("00000005"), false);
132 assert_eq!(check("00000006"), false);
133 assert_eq!(check("00000007"), false);
134 assert_eq!(check("00000008"), false);
135 assert_eq!(check("00000009"), false);
136 }
137
138 #[test]
139 fn check_static_data() {
140 assert_eq!(check("14567810"), true); assert_eq!(check("1456781"), false); assert_eq!(check("14567811"), false); }
144
145 #[test]
146 fn fix_non_ascii() {
147 assert!(fix("❤").is_err());
148 }
149
150 #[test]
151 fn fix_too_long() {
152 assert_eq!(fix("000000000"), Err(FixError::TooLong));
153 }
154
155 #[test]
156 fn fix_incorrect_check_digit() {
157 assert_eq!(fix("14567813"), Err(FixError::CheckDigitIncorrect));
158 }
159
160 #[test]
161 fn fix_needs_zero_padding() {
162 assert!(fix("0").is_ok());
163 assert_eq!(fix("0").unwrap(), "00000000");
164 assert_eq!(fix("9944220").unwrap(), "09944220");
165 }
166
167 proptest! {
168 #[test]
169 fn doesnt_crash(ref s in ".*") {
170 check(s);
171 }
172 }
173}