unc_gas/trait_impls/
from_str.rs

1use crate::{UncGas, UncGasError, ONE_GIGA_GAS, ONE_TERA_GAS};
2
3impl std::str::FromStr for UncGas {
4    type Err = UncGasError;
5    fn from_str(s: &str) -> Result<Self, Self::Err> {
6        let uppercase_s = s.trim().to_ascii_uppercase();
7        let (value, unit) = uppercase_s.split_at(
8            s.find(|c: char| c.is_ascii_alphabetic())
9                .ok_or_else(|| UncGasError::IncorrectUnit(s.to_owned()))?,
10        );
11        let unit_precision = match unit {
12            "TGAS" | "TERAGAS" => ONE_TERA_GAS,
13            "GIGAGAS" | "GGAS" => ONE_GIGA_GAS,
14            _ => return Err(UncGasError::IncorrectUnit(s.to_owned())),
15        };
16        Ok(UncGas::from_gas(
17            crate::utils::parse_decimal_number(value.trim(), unit_precision)
18                .map_err(UncGasError::IncorrectNumber)?,
19        ))
20    }
21}
22
23#[cfg(test)]
24mod test {
25    use std::str::FromStr;
26
27    use crate::{DecimalNumberParsingError, UncGas, UncGasError};
28
29    #[test]
30    fn doubledot() {
31        let data = "1.1.1 TeraGas";
32        let gas: Result<UncGas, UncGasError> = FromStr::from_str(data);
33        assert_eq!(
34            gas,
35            Err(UncGasError::IncorrectNumber(
36                DecimalNumberParsingError::InvalidNumber("1.1.1".to_owned())
37            ))
38        )
39    }
40
41    #[test]
42    fn space_after_dot() {
43        let data = "1. 0 TeraGas";
44        let gas: Result<UncGas, UncGasError> = FromStr::from_str(data);
45        assert_eq!(
46            gas,
47            Err(UncGasError::IncorrectNumber(
48                DecimalNumberParsingError::InvalidNumber("1. 0".to_owned())
49            ))
50        )
51    }
52
53    #[test]
54    fn decimal_tgas() {
55        let data = "0.5 TGas";
56        let gas: Result<UncGas, UncGasError> = FromStr::from_str(data);
57        assert_eq!(gas, Ok(UncGas::from_ggas(500)))
58    }
59
60    #[test]
61    fn incorect_currency() {
62        let data = "0 pas";
63        let gas: Result<UncGas, UncGasError> = FromStr::from_str(data);
64        assert_eq!(gas, Err(UncGasError::IncorrectUnit(data.to_owned())))
65    }
66
67    #[test]
68    fn without_currency() {
69        let data = "0";
70        let gas: Result<UncGas, UncGasError> = FromStr::from_str(data);
71        assert_eq!(gas, Err(UncGasError::IncorrectUnit("0".to_owned())))
72    }
73
74    #[test]
75    fn invalid_whole() {
76        let data = "-1 TeraGas";
77        let gas: Result<UncGas, UncGasError> = FromStr::from_str(data);
78        assert_eq!(
79            gas,
80            Err(UncGasError::IncorrectNumber(
81                DecimalNumberParsingError::InvalidNumber("-1".to_owned())
82            ))
83        )
84    }
85
86    #[test]
87    fn test_from_str_f64_gas_without_int() {
88        let unc_gas = UncGas::from_str(".055ggas").unwrap_err();
89        assert_eq!(
90            unc_gas,
91            UncGasError::IncorrectNumber(DecimalNumberParsingError::InvalidNumber(
92                ".055".to_string()
93            ))
94        );
95    }
96
97    #[test]
98    fn test_from_str_without_unit() {
99        let unc_gas = UncGas::from_str("100").unwrap_err();
100        assert_eq!(unc_gas, UncGasError::IncorrectUnit("100".to_string()));
101    }
102
103    #[test]
104    fn test_from_str_incorrect_unit() {
105        let unc_gas = UncGas::from_str("100 UAH").unwrap_err();
106        assert_eq!(unc_gas, UncGasError::IncorrectUnit("100 UAH".to_string()));
107    }
108
109    #[test]
110    fn test_from_str_invalid_double_dot() {
111        let unc_gas = UncGas::from_str("100.55.").unwrap_err();
112        assert_eq!(unc_gas, UncGasError::IncorrectUnit("100.55.".to_string()));
113    }
114
115    #[test]
116    fn test_from_str_large_fractional_part() {
117        let unc_gas = UncGas::from_str("100.1111122222333 ggas").unwrap_err(); // 13 digits after "."
118        assert_eq!(
119            unc_gas,
120            UncGasError::IncorrectNumber(DecimalNumberParsingError::LongFractional(
121                "1111122222333".to_string()
122            ))
123        );
124    }
125
126    #[test]
127    fn test_from_str_large_int_part() {
128        let unc_gas = UncGas::from_str("200123456789123.0 tgas").unwrap_err();
129        assert_eq!(
130            unc_gas,
131            UncGasError::IncorrectNumber(DecimalNumberParsingError::LongWhole(
132                "200123456789123".to_string()
133            ))
134        );
135    }
136
137    #[test]
138    fn test_from_str_negative_value() {
139        let unc_gas = UncGas::from_str("-100 ggas").unwrap_err();
140        assert_eq!(
141            unc_gas,
142            UncGasError::IncorrectNumber(DecimalNumberParsingError::InvalidNumber(
143                "-100".to_string()
144            ))
145        );
146    }
147
148    #[test]
149    fn unc_gas_from_str_currency_tgas() {
150        assert_eq!(
151            UncGas::from_str("10 tgas").unwrap(),
152            UncGas::from_gas(10_000_000_000_000) // 14 digits
153        );
154        assert_eq!(
155            UncGas::from_str("10.055TERAGAS").unwrap(),
156            UncGas::from_gas(10_055_000_000_000) // 14 digits
157        );
158    }
159
160    #[test]
161    fn unc_gas_from_str_currency_gigagas() {
162        assert_eq!(
163            UncGas::from_str("10 gigagas").unwrap(),
164            UncGas::from_gas(10_000_000_000) // 11 digits
165        );
166        assert_eq!(
167            UncGas::from_str("10GGAS ").unwrap(),
168            UncGas::from_gas(10_000_000_000) // 11 digits
169        );
170    }
171
172    #[test]
173    fn unc_gas_from_str_f64_tgas() {
174        assert_eq!(
175            UncGas::from_str("0.000001 tgas").unwrap(),
176            UncGas::from_gas(1_000_000) // 7 digits
177        );
178    }
179}