Adding format to select between normal, clean and JSON. This needs some refactor

This commit is contained in:
2023-06-13 18:38:32 +02:00
parent 9978e1553b
commit 8a3e5783c2
10 changed files with 507 additions and 306 deletions
+357
View File
@@ -0,0 +1,357 @@
use serde::{Deserialize, Serialize};
use crate::{
current_weather_output_model::CurrentWeatherOutputModel,
data_format::DataFormat,
speed_unit::{speed_to_unit_string, SpeedUnit},
temp_unit::{temp_to_unit_string, TempUnit},
};
#[derive(Serialize, Deserialize, Debug)]
pub struct CurrentWeatherOutput {
pub format: DataFormat,
pub temperature_unit: TempUnit,
pub speed_unit: SpeedUnit,
pub data: CurrentWeatherOutputModel,
}
impl CurrentWeatherOutput {
pub fn new(
format: DataFormat,
temperature_unit: TempUnit,
speed_unit: SpeedUnit,
) -> CurrentWeatherOutput {
CurrentWeatherOutput {
format,
temperature_unit,
speed_unit,
data: CurrentWeatherOutputModel::new(),
}
}
pub fn to_string(&self) -> String {
if DataFormat::JSON == self.format {
serde_json::to_string(&self.data).unwrap()
} else {
let mut string_vec: Vec<String> = Vec::new();
if DataFormat::Normal == self.format {
string_vec.push(self.create_header());
} else {
if self.data.latitude.is_some() {
string_vec.push(self.data.latitude.unwrap().to_string())
}
if self.data.longitude.is_some() {
string_vec.push(self.data.longitude.unwrap().to_string())
}
if self.data.city.is_some() {
string_vec.push(self.data.city.clone().unwrap().to_string())
}
}
let is_day = self.extract_day();
if is_day.is_some() {
string_vec.push(is_day.unwrap());
}
let temperature = self.extract_temperature();
if temperature.is_some() {
string_vec.push(temperature.unwrap());
}
let windspeed = self.extract_wind_speed();
if windspeed.is_some() {
string_vec.push(windspeed.unwrap());
}
let winddirection = self.extract_wind_direction();
if winddirection.is_some() {
string_vec.push(winddirection.unwrap());
}
if DataFormat::Normal == self.format
&& self.data.latitude.is_some()
&& self.data.longitude.is_some()
{
string_vec.push(format!(
"{}, {}",
self.parse_simple_data(
&self.data.latitude.unwrap().to_string(),
"Latitude",
None
),
self.parse_simple_data(
&self.data.longitude.unwrap().to_string(),
"Longitude",
None
)
));
}
if DataFormat::Clean == self.format {
let final_string = string_vec.join(",");
final_string
} else {
string_vec.push(self.create_footer());
string_vec.join("\n")
}
}
}
fn create_header(&self) -> String {
let mut title_header: Vec<String> = Vec::new();
title_header.push(String::from("=== Current weather"));
if self.data.city.is_some() {
title_header.push(String::from("for"));
title_header.push(self.data.city.clone().unwrap());
}
title_header.push(String::from("==="));
title_header.join(" ")
}
fn create_footer(&self) -> String {
String::from("=== Weather data by Open-Meteo.com ===")
}
fn extract_day(&self) -> Option<String> {
if self.data.is_day.is_some() {
let day = self.data.is_day.unwrap();
if day == 1 {
Some(self.parse_custom_data(&day.to_string(), "Day"))
} else {
Some(self.parse_custom_data(&day.to_string(), "Night"))
}
} else {
None
}
}
fn extract_temperature(&self) -> Option<String> {
if self.data.temperature.is_some() {
let temperature = self.data.temperature.unwrap();
Some(self.parse_simple_data(
&temperature.to_string(),
"Temperature",
Some(temp_to_unit_string(&self.temperature_unit).as_str()),
))
} else {
None
}
}
fn extract_wind_speed(&self) -> Option<String> {
if self.data.windspeed.is_some() {
let windspeed = self.data.windspeed.unwrap();
Some(self.parse_simple_data(
&windspeed.to_string(),
"Wind speed",
Some(format!(" {}", speed_to_unit_string(&self.speed_unit)).as_str()),
))
} else {
None
}
}
fn extract_wind_direction(&self) -> Option<String> {
if self.data.winddirection.is_some() {
let winddirection = self.data.winddirection.unwrap();
Some(self.parse_simple_data(&winddirection.to_string(), "Wind direction", Some("°")))
} else {
None
}
}
fn parse_custom_data(&self, data: &str, custom: &str) -> String {
if self.format == DataFormat::Clean {
format!("{data}")
} else {
format!("{custom}")
}
}
fn parse_simple_data(&self, data: &str, descriptor: &str, end_text: Option<&str>) -> String {
if self.format == DataFormat::Clean {
format!("{data}")
} else {
let end_text = end_text.unwrap_or("");
format!("{descriptor}: {data}{end_text}")
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::speed_unit::SpeedUnit;
use crate::temp_unit::TempUnit;
#[test]
fn clean_all_data() {
let data = CurrentWeatherOutputModel {
latitude: Some(5.0),
longitude: Some(-5.0),
city: Some("TestCity".to_string()),
is_day: Some(1),
temperature: Some(12.5),
windspeed: Some(7.0),
winddirection: Some(90.0),
};
let output = CurrentWeatherOutput {
format: DataFormat::Clean,
temperature_unit: TempUnit::Celsius,
speed_unit: SpeedUnit::Kmh,
data,
};
assert_eq!(output.to_string(), "5,-5,TestCity,1,12.5,7,90");
}
#[test]
fn clean_data() {
let data = CurrentWeatherOutputModel {
latitude: None,
longitude: None,
city: None,
is_day: Some(1),
temperature: Some(15.5),
windspeed: Some(12.2),
winddirection: None,
};
let output = CurrentWeatherOutput {
format: DataFormat::Clean,
temperature_unit: TempUnit::Celsius,
speed_unit: SpeedUnit::Kmh,
data,
};
assert_eq!(output.to_string(), "1,15.5,12.2");
}
#[test]
fn full_normal_data() {
let data = CurrentWeatherOutputModel {
latitude: Some(5.0),
longitude: Some(-5.0),
city: Some("TestCity".to_string()),
is_day: Some(0),
temperature: Some(22.0),
windspeed: Some(15.5),
winddirection: Some(118.0),
};
let output = CurrentWeatherOutput {
format: DataFormat::Normal,
temperature_unit: TempUnit::Celsius,
speed_unit: SpeedUnit::Kmh,
data,
};
let result = output.to_string();
assert!(result.contains("Night"));
assert!(result.contains("Temperature: 22°C"));
assert!(result.contains("Wind speed: 15.5 km/h"));
assert!(result.contains("Wind direction: 118°"));
assert!(result.contains("Latitude: 5"));
assert!(result.contains("Longitude: -5"));
assert!(result.contains("TestCity"));
assert!(result.contains("Open-Meteo.com"));
}
#[test]
fn normal_data() {
let data = CurrentWeatherOutputModel {
latitude: None,
longitude: None,
city: None,
is_day: Some(1),
temperature: Some(55.0),
windspeed: Some(11.5),
winddirection: None,
};
let output = CurrentWeatherOutput {
format: DataFormat::Normal,
temperature_unit: TempUnit::Fahrenheit,
speed_unit: SpeedUnit::Mph,
data,
};
let result = output.to_string();
assert!(result.contains("Day"));
assert!(result.contains("Temperature: 55°F"));
assert!(result.contains("Wind speed: 11.5 mp/h"));
assert!(!result.contains("Wind direction: 125°"));
assert!(!result.contains("Latitude: 12.15"));
assert!(!result.contains("Longitude: 0.235"));
assert!(!result.contains("Nocity"));
assert!(result.contains("Open-Meteo.com"));
}
#[test]
fn full_json_data() {
let data = CurrentWeatherOutputModel {
latitude: Some(5.0),
longitude: Some(-5.0),
city: Some("TestCity".to_string()),
is_day: Some(0),
temperature: Some(22.0),
windspeed: Some(15.5),
winddirection: Some(118.0),
};
let output = CurrentWeatherOutput {
format: DataFormat::JSON,
temperature_unit: TempUnit::Celsius,
speed_unit: SpeedUnit::Kmh,
data,
};
let result = output.to_string();
assert!(result.contains("\"latitude\":5"));
assert!(result.contains("\"longitude\":-5"));
assert!(result.contains("\"city\":\"TestCity\""));
assert!(result.contains("\"is_day\":0"));
assert!(result.contains("\"temperature\":22"));
assert!(result.contains("\"windspeed\":15.5"));
assert!(result.contains("\"winddirection\":118"));
}
#[test]
fn json_data() {
let data = CurrentWeatherOutputModel {
latitude: None,
longitude: None,
city: None,
is_day: Some(1),
temperature: Some(55.0),
windspeed: Some(11.5),
winddirection: None,
};
let output = CurrentWeatherOutput {
format: DataFormat::JSON,
temperature_unit: TempUnit::Fahrenheit,
speed_unit: SpeedUnit::Mph,
data,
};
let result = output.to_string();
assert!(!result.contains("\"latitude\":12.15"));
assert!(!result.contains("\"longitude\":-0.235"));
assert!(!result.contains("\"city\":\"NoCity\""));
assert!(result.contains("\"is_day\":1"));
assert!(result.contains("\"temperature\":55"));
assert!(result.contains("\"windspeed\":11.5"));
assert!(!result.contains("\"winddirection\":125"));
}
}