150 lines
4.8 KiB
Rust
150 lines
4.8 KiB
Rust
|
|
use std::error::Error;
|
||
|
|
use std::fmt;
|
||
|
|
|
||
|
|
#[derive(PartialEq, Debug)]
|
||
|
|
pub enum MessageError {
|
||
|
|
EmptyResponse,
|
||
|
|
HeaderMissingValueCount,
|
||
|
|
HeaderValueCountIncorrectFormat(String),
|
||
|
|
MalformedValueReceived(String),
|
||
|
|
ValueNotFound(String, Vec<String>),
|
||
|
|
}
|
||
|
|
|
||
|
|
impl fmt::Display for MessageError {
|
||
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||
|
|
let message = match *self {
|
||
|
|
Self::EmptyResponse => "Got an empty response".to_string(),
|
||
|
|
Self::HeaderMissingValueCount => "Value count not found in the header".to_string(),
|
||
|
|
Self::HeaderValueCountIncorrectFormat(ref val) => {
|
||
|
|
format!("String could not be parsed as value count: {}", val)
|
||
|
|
}
|
||
|
|
Self::MalformedValueReceived(ref val) => {
|
||
|
|
format!("Could not parse value as float: {}", val)
|
||
|
|
}
|
||
|
|
Self::ValueNotFound(ref name, ref values) => format!(
|
||
|
|
"Value not found in the received values: {} in [{}]",
|
||
|
|
name,
|
||
|
|
values.join(", ")
|
||
|
|
),
|
||
|
|
};
|
||
|
|
|
||
|
|
f.write_str(&message)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Error for MessageError {}
|
||
|
|
|
||
|
|
pub fn create_request_message(value: String) -> String {
|
||
|
|
format!("GETVAL {}", value)
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn parse_response_message(resp: String, name: String) -> Result<f32, MessageError> {
|
||
|
|
let mut lines = resp.split_terminator("\n");
|
||
|
|
let header = lines.next().ok_or(MessageError::EmptyResponse)?;
|
||
|
|
let num_values_raw = header
|
||
|
|
.split(" ")
|
||
|
|
.next()
|
||
|
|
.ok_or(MessageError::HeaderMissingValueCount)?;
|
||
|
|
let num_values = num_values_raw
|
||
|
|
.parse::<i32>()
|
||
|
|
.map_err(|_| MessageError::HeaderValueCountIncorrectFormat(num_values_raw.to_string()))?;
|
||
|
|
|
||
|
|
if num_values < 0 {
|
||
|
|
Err(MessageError::ValueNotFound(name, vec![]))
|
||
|
|
} else {
|
||
|
|
let mut values: Vec<String> = vec![];
|
||
|
|
|
||
|
|
for line in lines {
|
||
|
|
let mut line_segment = line.split("=");
|
||
|
|
if let Some(val_name) = line_segment.next() {
|
||
|
|
if val_name == name
|
||
|
|
&& let Some(val_raw) = line_segment.next()
|
||
|
|
{
|
||
|
|
return val_raw.parse::<f32>().map_err(|_| {
|
||
|
|
MessageError::MalformedValueReceived(num_values_raw.to_string())
|
||
|
|
});
|
||
|
|
}
|
||
|
|
values.push(val_name.to_string());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Err(MessageError::ValueNotFound(name, values))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(test)]
|
||
|
|
mod tests {
|
||
|
|
use super::*;
|
||
|
|
|
||
|
|
macro_rules! assert_almost_equal {
|
||
|
|
($a:expr, $b:expr, $eps:expr) => {
|
||
|
|
assert!(($a - $b).abs() < $eps);
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_create_request() {
|
||
|
|
assert_eq!(
|
||
|
|
create_request_message("some/value".to_string()),
|
||
|
|
"GETVAL some/value",
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_parse_response_message_simple() {
|
||
|
|
let resp = vec!["1 Value found", "value=4.5"].join("\n");
|
||
|
|
let result = parse_response_message(resp, "value".to_string());
|
||
|
|
assert_almost_equal!(result.unwrap(), 4.5, 0.1);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_parse_response_message_exponential() {
|
||
|
|
let resp = vec!["1 Value found", "value=4.514824e+02"].join("\n");
|
||
|
|
let result = parse_response_message(resp, "value".to_string());
|
||
|
|
assert_almost_equal!(result.unwrap(), 451.4824, 0.1);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_parse_response_message_multiple_values() {
|
||
|
|
let resp = vec!["3 Values found", "v1=4.514824e+09", "v2=1.234", "v3=0.1"].join("\n");
|
||
|
|
let result = parse_response_message(resp, "v2".to_string());
|
||
|
|
assert_almost_equal!(result.unwrap(), 1.234, 0.1);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_parse_response_message_multiple_values_not_found() {
|
||
|
|
let resp = vec!["3 Values found", "v1=4.514824e+09", "v2=1.234", "v3=0.1"].join("\n");
|
||
|
|
let result = parse_response_message(resp, "v10".to_string());
|
||
|
|
assert!(result.is_err());
|
||
|
|
assert_eq!(
|
||
|
|
result,
|
||
|
|
Err(MessageError::ValueNotFound(
|
||
|
|
"v10".to_string(),
|
||
|
|
vec!["v1".to_string(), "v2".to_string(), "v3".to_string()]
|
||
|
|
))
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_parse_response_message_no_values() {
|
||
|
|
let resp = "0 Values found".to_string();
|
||
|
|
let result = parse_response_message(resp, "value".to_string());
|
||
|
|
assert!(result.is_err());
|
||
|
|
assert_eq!(
|
||
|
|
result,
|
||
|
|
Err(MessageError::ValueNotFound("value".to_string(), vec![]))
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_parse_response_message_field_not_found() {
|
||
|
|
let resp = "-1 Type `loadx' is unknown.".to_string();
|
||
|
|
let result = parse_response_message(resp, "value".to_string());
|
||
|
|
assert!(result.is_err());
|
||
|
|
assert_eq!(
|
||
|
|
result,
|
||
|
|
Err(MessageError::ValueNotFound("value".to_string(), vec![]))
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|