use std::{
fs::File,
io::{
Cursor,
Read,
Stdin,
},
};
use anyhow::{
anyhow,
Result,
};
#[derive(Debug, PartialEq, Eq)]
pub enum VMReaderType {
Stdin,
File,
Mock,
Unknown,
}
pub trait VMReader {
fn read(&mut self) -> Result<u8> {
Ok(0)
}
fn get_vmreader_type(&self) -> VMReaderType {
VMReaderType::Unknown
}
}
#[derive(Debug, Default)]
pub struct MockReader {
pub data: Cursor<Vec<u8>>,
}
impl VMReader for MockReader {
fn read(&mut self) -> Result<u8> {
let mut buffer = [0u8; 1];
self.data.read_exact(&mut buffer)?;
if buffer[0] <= 128 {
Ok(buffer[0])
} else {
Err(anyhow!("Byte is not within the ASCII range"))
}
}
fn get_vmreader_type(&self) -> VMReaderType {
VMReaderType::Mock
}
}
impl VMReader for Stdin {
fn read(&mut self) -> Result<u8> {
let mut buffer = [0u8; 1];
self.read_exact(&mut buffer)?;
if buffer[0] <= 128 {
Ok(buffer[0])
} else {
Err(anyhow!("Byte is not within the ASCII range"))
}
}
fn get_vmreader_type(&self) -> VMReaderType {
VMReaderType::Stdin
}
}
impl VMReader for File {
fn read(&mut self) -> Result<u8> {
let mut buffer = [0u8; 1];
self.read_exact(&mut buffer)?;
if buffer[0] <= 128 {
Ok(buffer[0])
} else {
Err(anyhow!("Byte is not within the ASCII range"))
}
}
fn get_vmreader_type(&self) -> VMReaderType {
VMReaderType::File
}
}
#[cfg(test)]
mod tests {
use std::io::{
Cursor,
Write,
};
use tempfile::NamedTempFile;
use super::*;
struct DefaultReader;
impl VMReader for DefaultReader {}
#[test]
fn test_default_trait() {
let mut reader = DefaultReader;
let read_value = reader.read().unwrap();
assert_eq!(read_value, 0);
assert_eq!(reader.get_vmreader_type(), VMReaderType::Unknown);
}
#[test]
fn test_read_from_stdin() {
let mut stdin = Cursor::new("A".as_bytes());
let mut buffer = [0u8; 1];
stdin.read_exact(&mut buffer).unwrap();
assert_eq!(buffer[0], 65);
}
#[test]
fn test_read_from_file() {
let mut temp_file = NamedTempFile::new().unwrap();
temp_file.write_all("A".as_bytes()).unwrap();
let mut file = temp_file.reopen().unwrap();
let read_value = VMReader::read(&mut file).unwrap();
assert_eq!(read_value, 65);
temp_file.close().unwrap();
}
#[test]
fn test_read_from_mock() {
let mut mock = MockReader {
data: Cursor::new("A".as_bytes().to_vec()),
};
let read_value = mock.read().unwrap();
assert_eq!(read_value, 65);
}
#[test]
fn test_get_vmreader_type() {
let stdin = std::io::stdin();
let temp_file = NamedTempFile::new().unwrap();
let file = temp_file.reopen().unwrap();
let mock = MockReader {
data: Cursor::new("A".as_bytes().to_vec()),
};
let default = DefaultReader;
assert_eq!(stdin.get_vmreader_type(), VMReaderType::Stdin);
assert_eq!(file.get_vmreader_type(), VMReaderType::File);
assert_eq!(mock.get_vmreader_type(), VMReaderType::Mock);
assert_eq!(default.get_vmreader_type(), VMReaderType::Unknown);
temp_file.close().unwrap();
}
}