diff --git a/src/config.rs b/src/config.rs index 618d29b..66c0121 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,6 +7,18 @@ pub const CACHE_LOCATION_ENV_NAME: &str = "CURRENCY_CACHE"; pub const REST_ENDPOINT: &str = "https://v6.exchangerate-api.com/v6/"; pub const REST_ENDPOINT_ENV_NAME: &str = "CURRENCY_ENDPOINT"; +#[cfg(not(windows))] +#[macro_export] +macro_rules! main_separator{ + ()=>{"/"} +} + +#[cfg(windows)] +#[macro_export] +macro_rules! main_separator{ + ()=>{r#"\"#} +} + pub fn get_endpoint() -> String { let ret: String; match var_os(REST_ENDPOINT_ENV_NAME) { diff --git a/src/exchange.rs b/src/exchange.rs index c0dfb3c..aafedbc 100644 --- a/src/exchange.rs +++ b/src/exchange.rs @@ -1,6 +1,12 @@ use crate::*; use rust_decimal::prelude::*; use rusty_money::{iso::find, ExchangeRate, Money}; +pub struct Result { + pub from: String, + pub to: String, + pub rate: String +} + pub fn update_rate(code: &String) { if cache::get_next_update(code).expect("Error getting next update time from cache") <= config::get_current_time() @@ -32,7 +38,7 @@ pub fn get_rate(code_from: &String, code_to: &String) -> String { cache::get_rate(code_from, code_to).expect("Error when getting cached rate") } -pub fn convert_value(code_from: &String, code_to: &String, value: &String) { +pub fn convert_value(code_from: &String, code_to: &String, value: &String) -> Result{ if value.parse::().is_err() { panic!("{} is not a number!", value); } @@ -49,13 +55,22 @@ pub fn convert_value(code_from: &String, code_to: &String, value: &String) { let rate = Decimal::from_str(&text_rate).unwrap(); let dec_amount = Decimal::from_str(&value).unwrap(); let from_money = Money::from_decimal(dec_amount, from_currency.unwrap()); - println!("Input: {}", from_money.to_string()); + let mut ret: Result = Result { from: String::new(), to: String::new(), rate: String::new()}; + ret.from = from_money.to_string(); if code_from != code_to { let ex = ExchangeRate::new(from_currency.unwrap(), to_currency.unwrap(), rate).unwrap(); let result = ex.convert(from_money).expect("Error while conversion"); - println!("Equals: {}", result.to_string()) + ret.to = result.to_string(); } else { - println!("Equals: {}", from_money.to_string()) + ret.to = from_money.to_string(); } - println!("Exchange rate: {}", text_rate); + ret.rate = text_rate; + ret +} + +pub fn print_result(res:Result) +{ + println!("Input: {}", res.from); + println!("Equals: {}", res.to); + println!("Exchange rate: {}", res.rate); } diff --git a/src/main.rs b/src/main.rs index 3b4d274..0bddf86 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,8 +6,9 @@ use crate::{ }; use cache::check_code; use clap::Parser; -use exchange::convert_value; +use exchange::{convert_value, print_result}; mod cache; +#[macro_use] mod config; mod exchange; mod requests; @@ -149,11 +150,11 @@ fn main() -> Result> { } // Do conversion else if all_args { - convert_value( + print_result(convert_value( &args.currency_from.unwrap().to_uppercase(), &args.currency_to.unwrap().to_uppercase(), &args.value.unwrap(), - ) + )) } } else { interactive()?; @@ -229,7 +230,7 @@ fn interactive() -> Result<(), Box> { amount_check = true } } - convert_value(&code_from, &code_to, &amount); + print_result(convert_value(&code_from, &code_to, &amount)); Ok(()) } diff --git a/src/mock_data/EUR.json b/src/mock_data/EUR.json new file mode 100644 index 0000000..679e289 --- /dev/null +++ b/src/mock_data/EUR.json @@ -0,0 +1,174 @@ +{ + "result":"success", + "documentation":"https://www.exchangerate-api.com/docs", + "terms_of_use":"https://www.exchangerate-api.com/terms", + "time_last_update_unix":9710115202, + "time_last_update_utc":"Mon, 11 Mar 2024 00:00:02 +0000", + "time_next_update_unix":9710201602, + "time_next_update_utc":"Tue, 12 Mar 2024 00:00:02 +0000", + "base_code":"EUR", + "conversion_rates":{ + "EUR":1, + "AED":4.0174, + "AFN":77.8033, + "ALL":103.8965, + "AMD":441.3486, + "ANG":1.9581, + "AOA":916.4497, + "ARS":926.2817, + "AUD":1.6516, + "AWG":1.9581, + "AZN":1.8657, + "BAM":1.9558, + "BBD":2.1879, + "BDT":120.0383, + "BGN":1.9558, + "BHD":0.4113, + "BIF":3133.0525, + "BMD":1.0939, + "BND":1.4555, + "BOB":7.5517, + "BRL":5.4464, + "BSD":1.0939, + "BTN":90.4531, + "BWP":14.8818, + "BYN":3.5644, + "BZD":2.1879, + "CAD":1.4749, + "CDF":2918.3304, + "CHF":0.9601, + "CLP":1063.6631, + "CNY":7.8719, + "COP":4263.4620, + "CRC":558.2374, + "CUP":26.2542, + "CVE":110.2650, + "CZK":25.3140, + "DJF":194.4136, + "DKK":7.4592, + "DOP":64.3298, + "DZD":147.1853, + "EGP":53.8762, + "ERN":16.4089, + "ETB":61.8454, + "FJD":2.4353, + "FKP":0.8517, + "FOK":7.4584, + "GBP":0.8517, + "GEL":2.8958, + "GGP":0.8517, + "GHS":14.0309, + "GIP":0.8517, + "GMD":73.6023, + "GNF":9338.5306, + "GTQ":8.5240, + "GYD":229.0840, + "HKD":8.5559, + "HNL":27.0534, + "HRK":7.5345, + "HTG":144.9711, + "HUF":393.8966, + "IDR":17055.4230, + "ILS":3.9109, + "IMP":0.8517, + "INR":90.4608, + "IQD":1434.2222, + "IRR":47677.2587, + "ISK":148.9097, + "JEP":0.8517, + "JMD":169.4343, + "JOD":0.7756, + "JPY":160.7470, + "KES":153.2918, + "KGS":97.7998, + "KHR":4415.8947, + "KID":1.6517, + "KMF":491.9678, + "KRW":1443.4442, + "KWD":0.3356, + "KYD":0.9116, + "KZT":488.8080, + "LAK":22577.8376, + "LBP":97906.3579, + "LKR":335.9549, + "LRD":210.0248, + "LSL":20.5239, + "LYD":5.2682, + "MAD":10.9830, + "MDL":19.3215, + "MGA":4923.5797, + "MKD":61.6250, + "MMK":2758.8095, + "MNT":3702.6659, + "MOP":8.8121, + "MRU":43.6990, + "MUR":49.9605, + "MVR":16.8281, + "MWK":1847.0688, + "MXN":18.3946, + "MYR":5.1260, + "MZN":69.8725, + "NAD":20.5239, + "NGN":1744.5884, + "NIO":40.2282, + "NOK":11.4055, + "NPR":144.7250, + "NZD":1.7702, + "OMR":0.4206, + "PAB":1.0939, + "PEN":4.0463, + "PGK":4.1468, + "PHP":60.8094, + "PKR":303.6570, + "PLN":4.3011, + "PYG":7982.6316, + "QAR":3.9819, + "RON":4.9691, + "RSD":117.1890, + "RUB":99.5103, + "RWF":1421.5514, + "SAR":4.1022, + "SBD":9.2641, + "SCR":15.2996, + "SDG":489.2245, + "SEK":11.1744, + "SGD":1.4556, + "SHP":0.8517, + "SLE":24.7957, + "SLL":24792.7905, + "SOS":624.9683, + "SRD":39.1380, + "SSP":1771.0433, + "STN":24.5000, + "SYP":14093.9030, + "SZL":20.5239, + "THB":38.7913, + "TJS":11.9130, + "TMT":3.8250, + "TND":3.3870, + "TOP":2.5474, + "TRY":34.9983, + "TTD":7.4859, + "TVD":1.6517, + "TWD":34.3843, + "TZS":2799.5448, + "UAH":41.6349, + "UGX":4262.9019, + "USD":1.0940, + "UYU":42.4586, + "UZS":13457.2217, + "VES":39.6085, + "VND":26943.1432, + "VUV":131.5070, + "WST":2.9573, + "XAF":655.9570, + "XCD":2.9536, + "XDR":0.8182, + "XOF":655.9570, + "XPF":119.3320, + "YER":273.7272, + "ZAR":20.5180, + "ZMW":26.6550, + "ZWL":18142.9905 + } +} diff --git a/src/mock_data/PLN.json b/src/mock_data/PLN.json new file mode 100644 index 0000000..12d2d64 --- /dev/null +++ b/src/mock_data/PLN.json @@ -0,0 +1,174 @@ +{ + "result":"success", + "documentation":"https://www.exchangerate-api.com/docs", + "terms_of_use":"https://www.exchangerate-api.com/terms", + "time_last_update_unix":9710115202, + "time_last_update_utc":"Mon, 11 Mar 2024 00:00:02 +0000", + "time_next_update_unix":9710201602, + "time_next_update_utc":"Tue, 12 Mar 2024 00:00:02 +0000", + "base_code":"PLN", + "conversion_rates":{ + "PLN":1, + "AED":0.9349, + "AFN":18.0857, + "ALL":24.1505, + "AMD":102.0573, + "ANG":0.4557, + "AOA":213.0162, + "ARS":215.5602, + "AUD":0.3836, + "AWG":0.4557, + "AZN":0.4316, + "BAM":0.4548, + "BBD":0.5091, + "BDT":27.8881, + "BGN":0.4548, + "BHD":0.09572, + "BIF":729.3636, + "BMD":0.2546, + "BND":0.3386, + "BOB":1.7552, + "BRL":1.2653, + "BSD":0.2546, + "BTN":21.0250, + "BWP":3.4593, + "BYN":0.8276, + "BZD":0.5091, + "CAD":0.3429, + "CDF":680.8352, + "CHF":0.2232, + "CLP":247.2152, + "CNY":1.8310, + "COP":991.3096, + "CRC":129.7703, + "CUP":6.1098, + "CVE":25.6390, + "CZK":5.8862, + "DJF":45.2431, + "DKK":1.7338, + "DOP":14.9494, + "DZD":34.2052, + "EGP":12.5094, + "ERN":3.8186, + "ETB":14.3815, + "EUR":0.2325, + "FJD":0.5661, + "FKP":0.1980, + "FOK":1.7341, + "GBP":0.1979, + "GEL":0.6739, + "GGP":0.1980, + "GHS":3.2614, + "GIP":0.1980, + "GMD":17.1273, + "GNF":2172.5662, + "GTQ":1.9812, + "GYD":53.2856, + "HKD":1.9876, + "HNL":6.2868, + "HRK":1.7519, + "HTG":33.7206, + "HUF":91.6758, + "IDR":3957.9699, + "ILS":0.9080, + "IMP":0.1980, + "INR":21.0288, + "IQD":333.5727, + "IRR":10637.7983, + "ISK":34.5965, + "JEP":0.1980, + "JMD":39.4267, + "JOD":0.1805, + "JPY":37.3659, + "KES":36.0382, + "KGS":22.6208, + "KHR":1027.6742, + "KID":0.3837, + "KMF":114.3932, + "KRW":334.9777, + "KWD":0.07794, + "KYD":0.2121, + "KZT":113.5868, + "LAK":5249.3437, + "LBP":22784.3363, + "LKR":78.2262, + "LRD":48.8336, + "LSL":4.7767, + "LYD":1.2256, + "MAD":2.5534, + "MDL":4.4917, + "MGA":1147.6219, + "MKD":14.2949, + "MMK":532.6586, + "MNT":860.3638, + "MOP":2.0473, + "MRU":10.1598, + "MUR":11.6342, + "MVR":3.9116, + "MWK":429.4239, + "MXN":4.2770, + "MYR":1.1908, + "MZN":16.2472, + "NAD":4.7767, + "NGN":404.4242, + "NIO":9.3493, + "NOK":2.6544, + "NPR":33.6400, + "NZD":0.4113, + "OMR":0.09788, + "PAB":0.2546, + "PEN":0.9412, + "PGK":0.9640, + "PHP":14.1280, + "PKR":71.0217, + "PYG":1855.0446, + "QAR":0.9266, + "RON":1.1539, + "RSD":27.2179, + "RUB":23.1125, + "RWF":328.8698, + "SAR":0.9547, + "SBD":2.1480, + "SCR":3.4650, + "SDG":116.7421, + "SEK":2.5977, + "SGD":0.3386, + "SHP":0.1980, + "SLE":5.7110, + "SLL":5711.0223, + "SOS":145.3672, + "SRD":9.0953, + "SSP":405.9258, + "STN":5.6968, + "SYP":3276.5541, + "SZL":4.7767, + "THB":8.9999, + "TJS":2.7664, + "TMT":0.8834, + "TND":0.7872, + "TOP":0.5871, + "TRY":8.1349, + "TTD":1.7177, + "TVD":0.3837, + "TWD":7.9900, + "TZS":650.1478, + "UAH":9.6665, + "UGX":989.2600, + "USD":0.2546, + "UYU":9.8694, + "UZS":3174.8793, + "VES":9.2142, + "VND":6256.9273, + "VUV":30.3033, + "WST":0.6912, + "XAF":152.5242, + "XCD":0.6873, + "XDR":0.1900, + "XOF":152.5242, + "XPF":27.7473, + "YER":63.6136, + "ZAR":4.7721, + "ZMW":6.1910, + "ZWL":4237.2881 + } +} diff --git a/src/mock_data/codes.json b/src/mock_data/codes.json new file mode 100644 index 0000000..5acfcc7 --- /dev/null +++ b/src/mock_data/codes.json @@ -0,0 +1 @@ +{"result":"success","documentation":"https://www.exchangerate-api.com/docs","terms_of_use":"https://www.exchangerate-api.com/terms","supported_codes":[["EUR","Euro"], ["PLN","Polish Z\u0142oty"]]} diff --git a/src/requests.rs b/src/requests.rs index 427cffa..d9948b5 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -30,58 +30,108 @@ struct Err { } pub fn get_rates(code: &String) -> Result { - let response = reqwest::blocking::get(format!( - "{}{}{}{}", - get_endpoint(), - get_api_key().expect("Error when getting api key from cache"), - "/latest/", - code.to_uppercase() - ))?; - if response.status().is_success() { - let response: ConversionRates = - serde_json::from_str(&response.text()?).expect("Error when deserializng"); + if !cfg!(test) { + let response = reqwest::blocking::get(format!( + "{}{}{}{}", + get_endpoint(), + get_api_key().expect("Error when getting api key from cache"), + "/latest/", + code.to_uppercase() + ))?; + if response.status().is_success() { + let response: ConversionRates = + serde_json::from_str(&response.text()?).expect("Error when deserializng"); + cache::add_rates( + response.time_next_update_unix, + &response.base_code, + &response.conversion_rates, + ) + .expect("Error while caching response"); + return Ok(Status::OK); + } else { + let err: Err = + serde_json::from_str(&response.text()?).expect("Error when deserializng"); + if err.error_type == "invalid-key" { + return Ok(Status::INVALID); + } else if err.error_type == "quota-reached" { + return Ok(Status::LIMIT); + } + } + + Ok(Status::ERROR) + } + // TEST + else { + let response: ConversionRates = match code.as_str() { + "PLN" => serde_json::from_str(include_str!(concat!( + ".", + crate::main_separator!(), + "mock_data", + crate::main_separator!(), + "PLN.json" + ))) + .expect("Error when deserializng"), + "EUR" => serde_json::from_str(include_str!(concat!( + ".", + crate::main_separator!(), + "mock_data", + crate::main_separator!(), + "EUR.json" + ))) + .expect("Error when deserializng"), + _ => { + panic!("Unknown code") + } + }; cache::add_rates( response.time_next_update_unix, &response.base_code, &response.conversion_rates, ) .expect("Error while caching response"); - return Ok(Status::OK); - } else { - let err: Err = - serde_json::from_str(&response.text()?).expect("Error when deserializng"); - if err.error_type == "invalid-key" { - return Ok(Status::INVALID); - } else if err.error_type == "quota-reached" { - return Ok(Status::LIMIT); - } + Ok(Status::OK) } - - Ok(Status::ERROR) } pub fn get_currencies() -> Result { - let response = reqwest::blocking::get(format!( - "{}{}{}", - get_endpoint(), - get_api_key().expect("Error when getting api key from cache"), - "/codes" - ))?; - if response.status().is_success() { - let codes: CurrencyCodes = - serde_json::from_str(&response.text()?).expect("Error when deserializng"); + if !cfg!(test) { + let response = reqwest::blocking::get(format!( + "{}{}{}", + get_endpoint(), + get_api_key().expect("Error when getting api key from cache"), + "/codes" + ))?; + if response.status().is_success() { + let codes: CurrencyCodes = + serde_json::from_str(&response.text()?).expect("Error when deserializng"); + for code in codes.supported_codes { + cache::add_code(code).expect("Error when adding code to cache"); + } + return Ok(Status::OK); + } else { + let err: Err = + serde_json::from_str(&response.text()?).expect("Error when deserializng"); + if err.error_type == "invalid-key" { + return Ok(Status::INVALID); + } else if err.error_type == "quota-reached" { + return Ok(Status::LIMIT); + } + } + + Ok(Status::ERROR) + } + //TEST + else { + let codes: CurrencyCodes = serde_json::from_str(include_str!(concat!( + ".", + crate::main_separator!(), + "mock_data", + crate::main_separator!(), + "codes.json" + ))) + .expect("Error when deserializng"); for code in codes.supported_codes { cache::add_code(code).expect("Error when adding code to cache"); } return Ok(Status::OK); - } else { - let err: Err = - serde_json::from_str(&response.text()?).expect("Error when deserializng"); - if err.error_type == "invalid-key" { - return Ok(Status::INVALID); - } else if err.error_type == "quota-reached" { - return Ok(Status::LIMIT); - } } - - Ok(Status::ERROR) } diff --git a/src/tests.rs b/src/tests.rs index 003b9ef..fbb3847 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -18,11 +18,12 @@ fn setup_test() { .expect("Something went wrong when setting api key"); cache::add_code(["PLN".to_string(), "Polish zloty".to_string()]) .expect("Something went wrong when adding code"); + requests::get_currencies().expect("Something went wrong when getting currencies"); + requests::get_rates(&"PLN".to_string()).expect("Something went wrong when getting rates"); let mut rates: std::collections::HashMap = std::collections::HashMap::new(); rates.insert("USD".to_string(), serde_json::json!(0.2546)); - rates.insert("EUR".to_string(), serde_json::json!(0.2325)); cache::add_rates(99710201602, &"PLN".to_string(), &rates).expect("Error seting rates"); }); } @@ -50,10 +51,6 @@ fn test_cache_get_rates() { cache::get_rate(&"PLN".to_string(), &"USD".to_string()).expect("Error getting rates"), "0.2546" ); - assert_eq!( - cache::get_rate(&"PLN".to_string(), &"EUR".to_string()).expect("Error getting rates"), - "0.2325" - ); } #[test] @@ -63,8 +60,23 @@ fn test_cache_check_exchange() { assert!( cache::check_exchange(&"PLN".to_string(), &"USD".to_string()).expect("Error while checking exchange") ); - assert!( - cache::check_exchange(&"PLN".to_string(), &"EUR".to_string()).expect("Error while checking exchange") - ); } +#[test] +fn test_exchange_convert_value() { + setup_test(); + let result = exchange::convert_value(&"PLN".to_string(), &"EUR".to_string(), &"100".to_string()); + assert_eq!( + result.rate, "0.2325".to_string() + ); + assert_eq!( + result.from, "100zł".to_string() + ); + assert_eq!( + result.to, "€23,25".to_string() + ); + +} + + +