near_token/trait_impls/
from_str.rs1use crate::{NearToken, NearTokenError, ONE_NEAR};
2
3impl std::str::FromStr for NearToken {
4 type Err = NearTokenError;
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(|| NearTokenError::InvalidTokenUnit(s.to_owned()))?,
10 );
11 let unit_precision = match unit {
12 "YN" | "YNEAR" | "YOCTONEAR" => 1,
13 "NEAR" | "N" => ONE_NEAR,
14 _ => return Err(NearTokenError::InvalidTokenUnit(s.to_owned())),
15 };
16 Ok(NearToken::from_yoctonear(
17 crate::utils::parse_decimal_number(value.trim(), unit_precision)
18 .map_err(NearTokenError::InvalidTokensAmount)?,
19 ))
20 }
21}
22
23#[cfg(test)]
24mod test {
25 use std::str::FromStr;
26
27 use crate::{DecimalNumberParsingError, NearToken, NearTokenError};
28
29 #[test]
30 fn parse_decimal_number() {
31 let data = "0.123456 near";
32 let gas: Result<NearToken, NearTokenError> = FromStr::from_str(data);
33 assert_eq!(
34 gas.unwrap(),
35 NearToken::from_yoctonear(123456000000000000000000)
36 );
37 }
38 #[test]
39 fn parse_number_with_decimal_part() {
40 let data = "11.123456 near";
41 let gas: Result<NearToken, NearTokenError> = FromStr::from_str(data);
42 assert_eq!(
43 gas.unwrap(),
44 NearToken::from_yoctonear(11123456000000000000000000)
45 );
46 }
47
48 #[test]
49 fn parse_yocto_number() {
50 let data = "123456 YN";
51 let gas: Result<NearToken, NearTokenError> = FromStr::from_str(data);
52 assert_eq!(gas.unwrap(), NearToken::from_yoctonear(123456));
53 }
54
55 #[test]
56 fn doubledot() {
57 let data = "1.1.1 Near";
58 let gas: Result<NearToken, NearTokenError> = FromStr::from_str(data);
59 assert_eq!(
60 gas,
61 Err(NearTokenError::InvalidTokensAmount(
62 DecimalNumberParsingError::InvalidNumber("1.1.1".to_owned())
63 ))
64 )
65 }
66
67 #[test]
68 fn space_after_dot() {
69 let data = "1. 0 near";
70 let gas: Result<NearToken, NearTokenError> = FromStr::from_str(data);
71 assert_eq!(
72 gas,
73 Err(NearTokenError::InvalidTokensAmount(
74 DecimalNumberParsingError::InvalidNumber("1. 0".to_owned())
75 ))
76 )
77 }
78
79 #[test]
80 fn incorect_currency() {
81 let data = "0 pas";
82 let gas: Result<NearToken, NearTokenError> = FromStr::from_str(data);
83 assert_eq!(gas, Err(NearTokenError::InvalidTokenUnit(data.to_owned())))
84 }
85
86 #[test]
87 fn without_currency() {
88 let data = "0";
89 let gas: Result<NearToken, NearTokenError> = FromStr::from_str(data);
90 assert_eq!(gas, Err(NearTokenError::InvalidTokenUnit("0".to_owned())))
91 }
92
93 #[test]
94 fn invalid_whole() {
95 let data = "-1 Near";
96 let gas: Result<NearToken, NearTokenError> = FromStr::from_str(data);
97 assert_eq!(
98 gas,
99 Err(NearTokenError::InvalidTokensAmount(
100 DecimalNumberParsingError::InvalidNumber("-1".to_owned())
101 ))
102 )
103 }
104
105 #[test]
106 fn test_from_str_f64_gas_without_int() {
107 let near_gas = NearToken::from_str(".055 ynear").unwrap_err();
108 assert_eq!(
109 near_gas,
110 NearTokenError::InvalidTokensAmount(DecimalNumberParsingError::InvalidNumber(
111 ".055".to_string()
112 ))
113 );
114 }
115
116 #[test]
117 fn test_from_str_without_unit() {
118 let near_gas = NearToken::from_str("100").unwrap_err();
119 assert_eq!(
120 near_gas,
121 NearTokenError::InvalidTokenUnit("100".to_string())
122 );
123 }
124
125 #[test]
126 fn test_from_str_incorrect_unit() {
127 let near_gas = NearToken::from_str("100 UAH").unwrap_err();
128 assert_eq!(
129 near_gas,
130 NearTokenError::InvalidTokenUnit("100 UAH".to_string())
131 );
132 }
133
134 #[test]
135 fn test_from_str_invalid_double_dot() {
136 let near_gas = NearToken::from_str("100.55.").unwrap_err();
137 assert_eq!(
138 near_gas,
139 NearTokenError::InvalidTokenUnit("100.55.".to_string())
140 );
141 }
142
143 #[test]
144 fn test_from_str_large_fractional_part() {
145 let near_gas = NearToken::from_str("100.1111122222333 ynear").unwrap_err(); assert_eq!(
147 near_gas,
148 NearTokenError::InvalidTokensAmount(DecimalNumberParsingError::LongFractional(
149 "1111122222333".to_string()
150 ))
151 );
152 }
153}