pub mod icon;
use icon::*;
use crate::dat_error::DATError;
use crate::dat_file::{check_type, DATFile};
use crate::dat_type::DATType;
use crate::high_level::{AsBytes, Validate};
use crate::section::{as_section_vec, read_section, read_section_content, Section, SectionData};
use std::path::Path;
pub const EXPECTED_ITEM_COUNT: usize = 100;
pub const SECTION_TAG_TITLE: &str = "T";
pub const SECTION_TAG_ICON: &str = "I";
pub const SECTION_TAG_KEY: &str = "K";
pub const SECTION_TAG_LINE: &str = "L";
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Macro {
pub icon_key: String,
pub icon_id: String,
pub lines: Vec<String>,
pub title: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MacroData<'a> {
pub icon_key: &'a str,
pub icon_id: &'a str,
pub lines: Vec<&'a str>,
pub title: &'a str,
}
impl From<&MacroData<'_>> for Macro {
fn from(x: &MacroData) -> Self {
Macro {
icon_key: x.icon_key.to_owned(),
icon_id: x.icon_id.to_owned(),
lines: x.lines.iter().map(|item| String::from(*item)).collect(),
title: x.title.to_owned(),
}
}
}
impl AsBytes for Macro {
fn as_bytes(&self) -> Result<Vec<u8>, DATError> {
let sections = self.as_sections()?;
let mut byte_vec = Vec::<u8>::new();
for section in sections.into_iter() {
let mut sec_bytes = Vec::<u8>::from(section);
byte_vec.append(&mut sec_bytes);
}
Ok(byte_vec)
}
}
impl Validate for Macro {
fn validate(&self) -> Option<DATError> {
if self.title.len() > 20 {
return Some(DATError::Overflow("Title is longer than 20 characters."));
}
if macro_icon_from_key_and_id(&self.icon_key, &self.icon_id).is_none() {
return Some(DATError::InvalidInput("Macro icon is invalid."));
}
if self.lines.len() < 15 {
return Some(DATError::Underflow("Macro has fewer than 15 lines."));
}
if self.lines.len() > 15 {
return Some(DATError::Overflow("Macro has more than 15 lines."));
}
for line in self.lines.iter() {
if line.len() > 180 {
return Some(DATError::Overflow("Line is longer than 180 characters."));
}
}
None
}
}
impl<'a> From<&'a Macro> for MacroData<'a> {
fn from(x: &'a Macro) -> Self {
MacroData {
icon_key: &x.icon_key,
icon_id: &x.icon_id,
lines: x.lines.iter().map(String::as_str).collect(),
title: &x.title,
}
}
}
impl AsBytes for MacroData<'_> {
fn as_bytes(&self) -> Result<Vec<u8>, DATError> {
let sections = self.as_section_data()?;
let mut byte_vec = Vec::<u8>::new();
for section in sections.into_iter() {
let mut sec_bytes = Vec::<u8>::from(section);
byte_vec.append(&mut sec_bytes);
}
Ok(byte_vec)
}
}
impl Validate for MacroData<'_> {
fn validate(&self) -> Option<DATError> {
if self.title.len() > 20 {
return Some(DATError::Overflow("Title is longer than 20 characters."));
}
if macro_icon_from_key_and_id(&self.icon_key, &self.icon_id).is_none() {
return Some(DATError::InvalidInput("Macro icon is invalid."));
}
if self.lines.len() < 15 {
return Some(DATError::Underflow("Macro has fewer than 15 lines."));
}
if self.lines.len() > 15 {
return Some(DATError::Overflow("Macro has more than 15 lines."));
}
for line in self.lines.iter() {
if line.len() > 180 {
return Some(DATError::Overflow("Line is longer than 180 characters."));
}
}
None
}
}
impl Macro {
pub fn as_sections(&self) -> Result<Vec<Section>, DATError> {
let mut sec_vec = vec![
Section::new(SECTION_TAG_TITLE.to_owned(), String::from(&self.title))?,
Section::new(SECTION_TAG_ICON.to_owned(), String::from(&self.icon_id))?,
Section::new(SECTION_TAG_KEY.to_owned(), String::from(&self.icon_key))?,
];
for line in self.lines.iter() {
sec_vec.push(Section::new(SECTION_TAG_LINE.to_owned(), String::from(line))?);
}
Ok(sec_vec)
}
pub fn change_icon(&mut self, icon: MacroIcon) {
let (key, id) = macro_icon_to_key_and_id(&icon);
self.icon_key = key.to_owned();
self.icon_id = id.to_owned();
}
pub fn from_sections(sections: Vec<Section>) -> Result<Macro, DATError> {
let res_macro = Self::from_sections_unsafe(sections)?;
if let Some(validation_err) = res_macro.validate() {
Err(validation_err)
} else {
Ok(res_macro)
}
}
pub fn from_sections_unsafe(sections: Vec<Section>) -> Result<Macro, DATError> {
if sections.len() < 4 {
return Err(DATError::InvalidInput("Macros require a minimum of 4 sections."));
}
if sections[0].tag != SECTION_TAG_TITLE {
return Err(DATError::InvalidInput("First section was not a Title (T) section."));
}
let title = String::from(§ions[0].content);
if sections[1].tag != SECTION_TAG_ICON {
return Err(DATError::InvalidInput("Second section was not a Icon (I) section."));
}
let icon_id = String::from(§ions[1].content);
if sections[2].tag != SECTION_TAG_KEY {
return Err(DATError::InvalidInput("Third section was not a Key (K) section."));
}
let icon_key = String::from(§ions[2].content);
let mut lines = Vec::<String>::new();
for line in sections[3..].iter() {
if line.tag != SECTION_TAG_LINE {
return Err(DATError::InvalidInput("Non-line (L) section in lines block."));
}
lines.push(line.content.to_owned());
}
Ok(Macro {
icon_key,
icon_id,
lines,
title,
})
}
pub fn get_icon(&self) -> Option<MacroIcon> {
macro_icon_from_key_and_id(&self.icon_key, &self.icon_id)
}
pub fn new(title: String, lines: Vec<String>, icon: MacroIcon) -> Result<Macro, DATError> {
let (icon_key, icon_id) = macro_icon_to_key_and_id(&icon);
let mut padded_lines = lines.clone();
if lines.len() < 15 {
for line in std::iter::repeat(String::new()).take(15 - lines.len()) {
padded_lines.push(line);
}
}
let res_macro = Macro {
icon_id: icon_id.to_owned(),
icon_key: icon_key.to_owned(),
lines: padded_lines,
title,
};
match res_macro.validate() {
Some(err) => Err(err),
None => Ok(res_macro),
}
}
}
impl<'a> MacroData<'a> {
pub fn as_section_data(&self) -> Result<Vec<SectionData>, DATError> {
let mut sec_vec = vec![
SectionData::new(SECTION_TAG_TITLE, self.title)?,
SectionData::new(SECTION_TAG_ICON, self.icon_id)?,
SectionData::new(SECTION_TAG_KEY, self.icon_key)?,
];
for line in self.lines.iter() {
sec_vec.push(SectionData::new(SECTION_TAG_LINE, line)?);
}
Ok(sec_vec)
}
pub fn change_icon(&mut self, icon: &'a MacroIcon) {
let (key, id) = macro_icon_to_key_and_id(&icon);
self.icon_key = key;
self.icon_id = id;
}
pub fn from_section_data(sections: Vec<SectionData>) -> Result<MacroData, DATError> {
let res_macro = Self::from_section_data_unsafe(sections)?;
if let Some(validation_err) = res_macro.validate() {
Err(validation_err)
} else {
Ok(res_macro)
}
}
pub fn from_section_data_unsafe(sections: Vec<SectionData>) -> Result<MacroData, DATError> {
if sections.len() < 4 {
return Err(DATError::InvalidInput("Macros require a minimum of 4 sections."));
}
if sections[0].tag != SECTION_TAG_TITLE {
return Err(DATError::InvalidInput("First section was not a Title (T) section."));
}
let title = sections[0].content;
if sections[1].tag != SECTION_TAG_ICON {
return Err(DATError::InvalidInput("Second section was not a Icon (I) section."));
}
let icon_id = sections[1].content;
if sections[2].tag != SECTION_TAG_KEY {
return Err(DATError::InvalidInput("Third section was not a Key (K) section."));
}
let icon_key = sections[2].content;
let mut lines = Vec::<&str>::new();
for line in sections[3..].iter() {
if line.tag != "L" {
return Err(DATError::InvalidInput("Non-line (L) section in lines block."));
}
lines.push(line.content);
}
Ok(MacroData {
icon_key,
icon_id,
lines,
title,
})
}
pub fn get_icon(&self) -> Option<MacroIcon> {
macro_icon_from_key_and_id(&self.icon_key, &self.icon_id)
}
pub fn new(title: &'a str, lines: Vec<&'a str>, icon: &'a MacroIcon) -> Result<MacroData<'a>, DATError> {
let (icon_key, icon_id) = macro_icon_to_key_and_id(&icon);
let mut padded_lines = lines.clone();
if lines.len() < 15 {
for line in std::iter::repeat("").take(15 - lines.len()) {
padded_lines.push(line);
}
}
let res_macro = MacroData {
icon_id,
icon_key,
lines: padded_lines,
title,
};
match res_macro.validate() {
Some(err) => Err(err),
None => Ok(res_macro),
}
}
}
pub fn as_macro(bytes: &[u8]) -> Result<MacroData, DATError> {
let sec_vec = as_section_vec(bytes)?;
MacroData::from_section_data_unsafe(sec_vec)
}
pub fn as_macro_vec(bytes: &[u8]) -> Result<Vec<MacroData>, DATError> {
let sections = as_section_vec(bytes)?;
let mut macro_vec = Vec::<MacroData>::new();
let mut sec_vec = Vec::<SectionData>::new();
for next_section in sections.into_iter() {
if next_section.tag == SECTION_TAG_TITLE {
if !sec_vec.is_empty() {
macro_vec.push(MacroData::from_section_data_unsafe(sec_vec)?);
}
sec_vec = Vec::<SectionData>::new();
}
sec_vec.push(next_section);
}
if !sec_vec.is_empty() {
macro_vec.push(MacroData::from_section_data_unsafe(sec_vec)?);
}
Ok(macro_vec)
}
pub fn as_writeable_bytes(macros: &[MacroData]) -> Result<Vec<u8>, DATError> {
let mut padded_macro_vec = macros.to_vec();
let macros_len = macros.len();
if macros_len > EXPECTED_ITEM_COUNT {
return Err(DATError::Overflow(
"A valid macro file cannot contain more than 100 macros.",
));
}
if macros_len < EXPECTED_ITEM_COUNT {
let mut padding = vec![MacroData::new("", vec![""; 15], &MacroIcon::NoIcon)?; EXPECTED_ITEM_COUNT - macros_len];
padded_macro_vec.append(&mut padding);
}
for macro_item in padded_macro_vec.iter() {
if let Some(err) = macro_item.validate() {
return Err(err);
}
}
as_writeable_bytes_unsafe(&padded_macro_vec)
}
pub fn as_writeable_bytes_unsafe(macros: &[MacroData]) -> Result<Vec<u8>, DATError> {
let mut res_vec = Vec::<u8>::new();
for macro_item in macros.iter() {
let mut macro_bytes = macro_item.as_bytes()?;
res_vec.append(&mut macro_bytes);
}
Ok(res_vec)
}
pub fn read_macro(dat_file: &mut DATFile) -> Result<Macro, DATError> {
if dat_file.file_type() != DATType::Macro {
Err(DATError::IncorrectType(
"Attempted to read a macro from a non-macro file.",
))
} else {
Ok(read_macro_unsafe(dat_file)?)
}
}
pub fn read_macro_content<P: AsRef<Path>>(path: P) -> Result<Vec<Macro>, DATError> {
if check_type(&path)? != DATType::Macro {
Err(DATError::IncorrectType(
"Attempted to read a macro from a non-macro file.",
))
} else {
Ok(read_macro_content_unsafe(path)?)
}
}
pub fn read_macro_unsafe(dat_file: &mut DATFile) -> Result<Macro, DATError> {
let title_sec = read_section(dat_file)?;
let mut sec_vec = vec![title_sec];
loop {
let next_section = match read_section(dat_file) {
Ok(next_section) => next_section,
Err(err) => match err {
DATError::EndOfFile(_) => break,
_ => return Err(err),
},
};
if next_section.tag == SECTION_TAG_TITLE {
break;
}
sec_vec.push(next_section);
}
Macro::from_sections_unsafe(sec_vec)
}
pub fn read_macro_content_unsafe<P: AsRef<Path>>(path: P) -> Result<Vec<Macro>, DATError> {
let sections = read_section_content(path)?;
let mut macro_vec = Vec::<Macro>::new();
let mut sec_vec = Vec::<Section>::new();
for next_section in sections.into_iter() {
if next_section.tag == SECTION_TAG_TITLE {
if !sec_vec.is_empty() {
macro_vec.push(Macro::from_sections_unsafe(sec_vec)?);
}
sec_vec = Vec::<Section>::new();
}
sec_vec.push(next_section);
}
if !sec_vec.is_empty() {
macro_vec.push(Macro::from_sections_unsafe(sec_vec)?);
}
Ok(macro_vec)
}
pub fn to_writeable_bytes(macros: &[Macro]) -> Result<Vec<u8>, DATError> {
let mut padded_macro_vec = macros.to_vec();
let macros_len = macros.len();
if macros_len > EXPECTED_ITEM_COUNT {
return Err(DATError::Overflow(
"A valid macro file cannot contain more than 100 macros.",
));
}
if macros_len < EXPECTED_ITEM_COUNT {
let mut padding = vec![
Macro::new("".to_owned(), vec!["".to_owned(); 15], MacroIcon::NoIcon)?;
EXPECTED_ITEM_COUNT - macros_len
];
padded_macro_vec.append(&mut padding);
}
for macro_item in padded_macro_vec.iter() {
if let Some(err) = macro_item.validate() {
return Err(err);
}
}
to_writeable_bytes_unsafe(&padded_macro_vec)
}
pub fn to_writeable_bytes_unsafe(macros: &[Macro]) -> Result<Vec<u8>, DATError> {
let mut res_vec = Vec::<u8>::new();
for macro_item in macros.iter() {
let mut macro_bytes = macro_item.as_bytes()?;
res_vec.append(&mut macro_bytes);
}
Ok(res_vec)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dat_file::read_content;
const TEST_FILE_PATH: &str = "./resources/TEST_MACRO.DAT";
#[test]
fn test_as_macro() -> Result<(), String> {
let mut dat_file = match DATFile::open(TEST_FILE_PATH) {
Ok(dat_file) => dat_file,
Err(err) => return Err(format!("Error opening file: {}", err)),
};
let a_macro = match read_macro(&mut dat_file) {
Ok(a_macro) => a_macro,
Err(err) => return Err(format!("Error reading test macro: {}", err)),
};
let macro_bytes = match a_macro.as_bytes() {
Ok(macro_bytes) => macro_bytes,
Err(err) => return Err(format!("Error converting test macro to bytes: {}", err)),
};
match as_macro(¯o_bytes) {
Ok(macro_data) => {
assert_eq!(macro_data.title, "0");
assert_eq!(macro_data.lines[0], "DefaultIcon");
assert_eq!(macro_data.get_icon().unwrap(), MacroIcon::DefaultIcon);
Ok(())
}
Err(err) => Err(format!("Error: {}", err)),
}
}
#[test]
fn test_as_macro_vec() -> Result<(), String> {
let macro_bytes = match read_content(TEST_FILE_PATH) {
Ok(macro_bytes) => macro_bytes,
Err(err) => return Err(format!("Error opening file: {}", err)),
};
match as_macro_vec(¯o_bytes) {
Ok(macro_data) => {
assert_eq!(macro_data[0].title, "0");
assert_eq!(macro_data[0].lines[0], "DefaultIcon");
assert_eq!(macro_data[0].get_icon().unwrap(), MacroIcon::DefaultIcon);
assert_eq!(macro_data.len(), EXPECTED_ITEM_COUNT);
Ok(())
}
Err(err) => Err(format!("Error: {}", err)),
}
}
#[test]
fn test_as_writeable_bytes() -> Result<(), String> {
let macro_bytes = match read_content(TEST_FILE_PATH) {
Ok(macro_bytes) => macro_bytes,
Err(err) => return Err(format!("Error opening file: {}", err)),
};
let macro_vec = match as_macro_vec(¯o_bytes) {
Ok(macro_vec) => macro_vec,
Err(err) => return Err(format!("Error vectorizing macros: {}", err)),
};
match as_writeable_bytes(¯o_vec) {
Ok(bytes) => Ok(assert_eq!(bytes, macro_bytes)),
Err(err) => Err(format!("Error: {}", err)),
}
}
#[test]
fn test_as_writeable_bytes_padding() -> Result<(), String> {
let macro_bytes = match read_content(TEST_FILE_PATH) {
Ok(macro_bytes) => macro_bytes,
Err(err) => return Err(format!("Error opening file: {}", err)),
};
let macro_vec = match as_macro_vec(¯o_bytes) {
Ok(macro_vec) => macro_vec,
Err(err) => return Err(format!("Error vectorizing macros: {}", err)),
};
let bytes = match as_writeable_bytes(¯o_vec[..50]) {
Ok(bytes) => bytes,
Err(err) => return Err(format!("Error converting to bytes: {}", err)),
};
match as_macro_vec(&bytes) {
Ok(output_vec) => Ok(assert_eq!(output_vec.len(), EXPECTED_ITEM_COUNT)),
Err(err) => Err(format!("Error: {}", err)),
}
}
#[test]
fn test_as_writeable_bytes_error_count() -> Result<(), String> {
let macro_bytes = match read_content(TEST_FILE_PATH) {
Ok(macro_bytes) => macro_bytes,
Err(err) => return Err(format!("Error opening file: {}", err)),
};
let mut macro_vec = match as_macro_vec(¯o_bytes) {
Ok(macro_vec) => macro_vec,
Err(err) => return Err(format!("Error vectorizing macros: {}", err)),
};
macro_vec.push(MacroData::new("", vec![""; 15], &MacroIcon::NoIcon).unwrap());
match as_writeable_bytes(¯o_vec) {
Ok(_) => Err("No error returned.".to_owned()),
Err(err) => match err {
DATError::Overflow(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
}
}
#[test]
fn test_read_macro() -> Result<(), String> {
let mut dat_file = match DATFile::open(TEST_FILE_PATH) {
Ok(dat_file) => dat_file,
Err(err) => return Err(format!("Error opening file: {}", err)),
};
match read_macro(&mut dat_file) {
Ok(a_macro) => {
assert_eq!(a_macro.title, "0");
assert_eq!(a_macro.lines[0], "DefaultIcon");
assert_eq!(a_macro.get_icon().unwrap(), MacroIcon::DefaultIcon);
Ok(())
}
Err(err) => Err(format!("Error: {}", err)),
}
}
#[test]
fn test_read_macro_content() -> Result<(), String> {
match read_macro_content(TEST_FILE_PATH) {
Ok(macro_vec) => {
assert_eq!(macro_vec[0].title, "0");
assert_eq!(macro_vec[0].lines[0], "DefaultIcon");
assert_eq!(macro_vec[0].get_icon().unwrap(), MacroIcon::DefaultIcon);
assert_eq!(macro_vec.len(), EXPECTED_ITEM_COUNT);
Ok(())
}
Err(err) => Err(format!("Error: {}", err)),
}
}
#[test]
fn test_to_writeable_bytes() -> Result<(), String> {
let raw_bytes = match read_content(TEST_FILE_PATH) {
Ok(macro_bytes) => macro_bytes,
Err(err) => return Err(format!("Error reading file: {}", err)),
};
let macro_vec = match read_macro_content(TEST_FILE_PATH) {
Ok(macro_vec) => macro_vec,
Err(err) => return Err(format!("Error reading macros: {}", err)),
};
match to_writeable_bytes(¯o_vec) {
Ok(bytes) => Ok(assert_eq!(bytes, raw_bytes)),
Err(err) => Err(format!("Error: {}", err)),
}
}
#[test]
fn test_to_writeable_bytes_padding() -> Result<(), String> {
let macro_vec = match read_macro_content(TEST_FILE_PATH) {
Ok(macro_vec) => macro_vec,
Err(err) => return Err(format!("Error reading macros: {}", err)),
};
let bytes = match to_writeable_bytes(¯o_vec[..50]) {
Ok(bytes) => bytes,
Err(err) => return Err(format!("Error converting to bytes: {}", err)),
};
match as_macro_vec(&bytes) {
Ok(output_vec) => Ok(assert_eq!(output_vec.len(), EXPECTED_ITEM_COUNT)),
Err(err) => Err(format!("Error: {}", err)),
}
}
#[test]
fn test_to_writeable_bytes_error_count() -> Result<(), String> {
let mut macro_vec = match read_macro_content(TEST_FILE_PATH) {
Ok(macro_vec) => macro_vec,
Err(err) => return Err(format!("Error vectorizing macros: {}", err)),
};
macro_vec.push(Macro::new(String::new(), vec![String::new(); 15], MacroIcon::NoIcon).unwrap());
match to_writeable_bytes(¯o_vec) {
Ok(_) => Err("No error returned.".to_owned()),
Err(err) => match err {
DATError::Overflow(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
}
}
#[test]
fn test_macrodata_change_icon() -> Result<(), String> {
let mut a_macro = MacroData::new("Title", vec!["Line"; 15], &MacroIcon::DefaultIcon).unwrap();
assert_eq!(a_macro.get_icon().unwrap(), MacroIcon::DefaultIcon);
a_macro.change_icon(&MacroIcon::SymbolCheck);
assert_eq!(a_macro.get_icon().unwrap(), MacroIcon::SymbolCheck);
Ok(())
}
#[test]
fn test_macrodata_from_sectiondata() -> Result<(), String> {
let mut sec_vec = vec![
SectionData::new("T", "Title").unwrap(),
SectionData::new("I", "0000000").unwrap(),
SectionData::new("K", "000").unwrap(),
];
let mut line_vec = vec![SectionData::new("L", "Line").unwrap(); 15];
sec_vec.append(&mut line_vec);
match MacroData::from_section_data(sec_vec) {
Ok(a_macro) => {
assert_eq!(a_macro.title, "Title");
assert_eq!(a_macro.lines[0], "Line");
assert_eq!(a_macro.get_icon().unwrap(), MacroIcon::NoIcon);
Ok(())
}
Err(err) => Err(format!("Error: {}", err)),
}
}
#[test]
fn test_macrodata_from_sectiondata_error_title() -> Result<(), String> {
let mut sec_vec = vec![
SectionData::new("I", "0000000").unwrap(),
SectionData::new("K", "000").unwrap(),
];
let mut line_vec = vec![SectionData::new("L", "Line").unwrap(); 15];
sec_vec.append(&mut line_vec);
match MacroData::from_section_data(sec_vec) {
Ok(_) => Err("No error returned.".to_owned()),
Err(err) => match err {
DATError::InvalidInput(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
}
}
#[test]
fn test_macrodata_from_sectiondata_error_icon_id() -> Result<(), String> {
let mut sec_vec = vec![
SectionData::new("T", "Title").unwrap(),
SectionData::new("K", "000").unwrap(),
];
let mut line_vec = vec![SectionData::new("L", "Line").unwrap(); 15];
sec_vec.append(&mut line_vec);
match MacroData::from_section_data(sec_vec) {
Ok(_) => Err("No error returned.".to_owned()),
Err(err) => match err {
DATError::InvalidInput(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
}
}
#[test]
fn test_macrodata_from_sectiondata_error_icon_key() -> Result<(), String> {
let mut sec_vec = vec![
SectionData::new("T", "Title").unwrap(),
SectionData::new("I", "0000000").unwrap(),
];
let mut line_vec = vec![SectionData::new("L", "Line").unwrap(); 15];
sec_vec.append(&mut line_vec);
match MacroData::from_section_data(sec_vec) {
Ok(_) => Err("No error returned.".to_owned()),
Err(err) => match err {
DATError::InvalidInput(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
}
}
#[test]
fn test_macrodata_from_sectiondata_error_no_lines() -> Result<(), String> {
let sec_vec = vec![
SectionData::new("T", "Title").unwrap(),
SectionData::new("I", "0000000").unwrap(),
SectionData::new("K", "000").unwrap(),
];
match MacroData::from_section_data(sec_vec) {
Ok(_) => Err("No error returned.".to_owned()),
Err(err) => match err {
DATError::InvalidInput(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
}
}
#[test]
fn test_macrodata_from_sectiondata_error_lines_interrupted() -> Result<(), String> {
let mut sec_vec = vec![
SectionData::new("T", "Title").unwrap(),
SectionData::new("I", "0000000").unwrap(),
SectionData::new("K", "000").unwrap(),
];
let mut line_vec = vec![SectionData::new("L", "Line").unwrap(); 15];
line_vec[1].tag = "I";
sec_vec.append(&mut line_vec);
match MacroData::from_section_data(sec_vec) {
Ok(_) => Err("No error returned.".to_owned()),
Err(err) => match err {
DATError::InvalidInput(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
}
}
#[test]
fn test_macrodata_get_icon() -> Result<(), String> {
let a_macro = MacroData::new("Title", vec!["Line"; 15], &MacroIcon::DefaultIcon).unwrap();
assert_eq!(a_macro.get_icon().unwrap(), MacroIcon::DefaultIcon);
Ok(())
}
#[test]
fn test_macrodata_get_icon_none() -> Result<(), String> {
let a_macro = MacroData {
icon_id: "1231234",
icon_key: "XYZ",
lines: vec![""; 15],
title: "Title",
};
Ok(assert!(a_macro.get_icon().is_none()))
}
#[test]
fn test_macrodata_new() -> Result<(), String> {
match MacroData::new("Title", vec!["Line"; 15], &MacroIcon::SymbolCheck) {
Ok(a_macro) => {
assert_eq!(a_macro.title, "Title");
assert_eq!(a_macro.lines[0], "Line");
let (icon_key, icon_id) = macro_icon_to_key_and_id(&MacroIcon::SymbolCheck);
assert_eq!(a_macro.icon_id, icon_id);
assert_eq!(a_macro.icon_key, icon_key);
Ok(())
}
Err(err) => Err(format!("Error building macro: {}", err)),
}
}
#[test]
fn test_macrodata_validate() -> Result<(), String> {
let a_macro = MacroData::new("Title", vec!["Line"; 15], &MacroIcon::DefaultIcon).unwrap();
Ok(assert!(a_macro.validate().is_none()))
}
#[test]
fn test_macrodata_validate_error_title() -> Result<(), String> {
let a_macro = MacroData {
icon_id: "0000000",
icon_key: "000",
lines: vec![""; 15],
title: &std::iter::repeat("X").take(21).collect::<String>(),
};
match a_macro.validate() {
Some(err) => match err {
DATError::Overflow(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
None => Err("No error returned.".to_owned()),
}
}
#[test]
fn test_macrodata_validate_error_icon() -> Result<(), String> {
let a_macro = MacroData {
icon_id: "0000000",
icon_key: "XYZ",
lines: vec![""; 15],
title: "",
};
match a_macro.validate() {
Some(err) => match err {
DATError::InvalidInput(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
None => Err("No error returned.".to_owned()),
}
}
#[test]
fn test_macro_validate_error_line_len() -> Result<(), String> {
let long_line = std::iter::repeat("X").take(181).collect::<String>();
let a_macro = MacroData {
icon_id: "0000000",
icon_key: "000",
lines: vec![&long_line; 15],
title: "",
};
match a_macro.validate() {
Some(err) => match err {
DATError::Overflow(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
None => Err("No error returned.".to_owned()),
}
}
#[test]
fn test_macrodata_validate_error_line_count_high() -> Result<(), String> {
let a_macro = MacroData {
icon_id: "0000000",
icon_key: "000",
lines: vec![""; 16],
title: "",
};
match a_macro.validate() {
Some(err) => match err {
DATError::Overflow(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
None => Err("No error returned.".to_owned()),
}
}
#[test]
fn test_macrodata_validate_error_line_count_low() -> Result<(), String> {
let a_macro = MacroData {
icon_id: "0000000",
icon_key: "000",
lines: vec![""; 14],
title: "",
};
match a_macro.validate() {
Some(err) => match err {
DATError::Underflow(_) => Ok(()),
_ => Err(format!("Incorrect error: {}", err)),
},
None => Err("No error returned.".to_owned()),
}
}
}