2023-02-04 14:29:07 -05:00
|
|
|
use super::{DBError, FileData, SessionData};
|
2023-01-22 14:15:34 -05:00
|
|
|
use std::{collections::HashMap, slice, str};
|
2023-01-21 21:46:39 -05:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Databases {
|
|
|
|
db_map: HashMap<String, String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Databases {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
db_map: HashMap::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-04 14:29:07 -05:00
|
|
|
fn test_key(key: &str) -> Result<(), DBError> {
|
|
|
|
match key {
|
|
|
|
"name" => (),
|
|
|
|
_ => return Err(DBError::new(format!("databases do not have a {}", key))),
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-01-27 12:44:26 -05:00
|
|
|
fn add_database(&mut self, name: &str, id: &str) -> Result<String, DBError> {
|
|
|
|
if name.len() == 0 {
|
|
|
|
return Err(DBError::new("database names cannot be empty"));
|
|
|
|
} else if self.db_map.contains_key(name) {
|
|
|
|
return Err(DBError::new("database already exists"));
|
2023-01-21 21:46:39 -05:00
|
|
|
} else {
|
|
|
|
self.db_map.insert(name.to_string(), id.to_string());
|
2023-01-27 12:44:26 -05:00
|
|
|
Ok(id.to_string())
|
2023-01-21 21:46:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_database(&self, name: &str) -> Option<String> {
|
|
|
|
self.db_map.get(name).cloned()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn show(&self) -> Vec<String> {
|
|
|
|
let mut names: Vec<String> = self.db_map.clone().into_keys().collect();
|
|
|
|
names.sort();
|
|
|
|
names
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-22 14:15:34 -05:00
|
|
|
impl FileData<Self> for Databases {
|
|
|
|
fn to_bytes(&self) -> Vec<u8> {
|
|
|
|
let mut output = Vec::new();
|
|
|
|
for (name, id) in self.db_map.iter() {
|
|
|
|
output.append(&mut name.as_bytes().to_vec());
|
|
|
|
output.push(0);
|
|
|
|
output.append(&mut id.as_bytes().to_vec());
|
|
|
|
output.push(0);
|
|
|
|
}
|
|
|
|
output
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from_bytes(data: &mut slice::Iter<u8>) -> Result<Self, DBError> {
|
|
|
|
let mut output = Databases::new();
|
|
|
|
let mut name: Vec<u8> = Vec::new();
|
|
|
|
let mut id: Vec<u8> = Vec::new();
|
|
|
|
let mut get_id = false;
|
|
|
|
let mut letter: u8;
|
|
|
|
loop {
|
|
|
|
match data.next() {
|
|
|
|
Some(a) => letter = a.clone(),
|
|
|
|
None => {
|
|
|
|
if !name.is_empty() {
|
|
|
|
return Err(DBError::new("file corruption"));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if letter == 0 {
|
|
|
|
if get_id {
|
2023-01-27 12:44:26 -05:00
|
|
|
match output
|
|
|
|
.add_database(str::from_utf8(&name).unwrap(), str::from_utf8(&id).unwrap())
|
|
|
|
{
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(err) => {
|
|
|
|
let mut error = DBError::new("file corruption");
|
|
|
|
error.add_source(err);
|
|
|
|
return Err(error);
|
|
|
|
}
|
|
|
|
};
|
2023-01-22 14:15:34 -05:00
|
|
|
name.clear();
|
|
|
|
id.clear();
|
|
|
|
}
|
|
|
|
get_id = !get_id;
|
|
|
|
} else {
|
|
|
|
if get_id {
|
|
|
|
id.push(letter);
|
|
|
|
} else {
|
|
|
|
name.push(letter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(output)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-04 14:29:07 -05:00
|
|
|
impl SessionData for Databases {
|
|
|
|
fn add(&mut self, key: &str, value: &str, data: &str) -> Result<Vec<String>, DBError> {
|
|
|
|
match Self::test_key(key) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(err) => return Err(err),
|
|
|
|
}
|
2023-02-04 23:06:29 -05:00
|
|
|
match self.db_map.get(value) {
|
|
|
|
Some(_) => return Err(DBError::new(format!("database {} already exists", value))),
|
|
|
|
None => (),
|
|
|
|
}
|
2023-02-04 14:29:07 -05:00
|
|
|
self.db_map.insert(value.to_string(), data.to_string());
|
|
|
|
let mut output = Vec::new();
|
|
|
|
output.push(data.to_string());
|
|
|
|
Ok(output)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get(&self, key: &str, value: &str) -> Result<Vec<String>, DBError> {
|
|
|
|
match Self::test_key(key) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(err) => return Err(err),
|
|
|
|
}
|
|
|
|
let mut output = Vec::new();
|
2023-02-04 23:06:29 -05:00
|
|
|
match self.db_map.get(value) {
|
|
|
|
Some(data) => output.push(data.to_string()),
|
|
|
|
None => (),
|
|
|
|
}
|
2023-02-04 14:29:07 -05:00
|
|
|
Ok(output)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn show(&self, keys: Vec<&str>) -> Result<Vec<String>, DBError> {
|
|
|
|
Ok(Vec::new())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-21 21:46:39 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod functions {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn add_entry() {
|
|
|
|
let name = "fred";
|
|
|
|
let id = "123456";
|
|
|
|
let mut dbs = Databases::new();
|
2023-01-27 12:44:26 -05:00
|
|
|
let output = dbs.add_database(name, id).unwrap();
|
|
|
|
assert_eq!(output, id.to_string());
|
2023-01-21 21:46:39 -05:00
|
|
|
}
|
|
|
|
|
2023-01-23 11:05:55 -05:00
|
|
|
#[test]
|
|
|
|
fn add_entry_no_name() {
|
|
|
|
let name = "";
|
|
|
|
let id = "123456";
|
|
|
|
let mut dbs = Databases::new();
|
2023-01-27 12:44:26 -05:00
|
|
|
match dbs.add_database(name, id) {
|
|
|
|
Ok(_) => assert!(false, "There should have been an error"),
|
|
|
|
Err(err) => assert_eq!(err.to_string(), "database names cannot be empty"),
|
|
|
|
}
|
2023-01-23 11:05:55 -05:00
|
|
|
}
|
|
|
|
|
2023-01-21 21:46:39 -05:00
|
|
|
#[test]
|
|
|
|
fn entry_cannot_be_over_written() {
|
|
|
|
let name = "barney";
|
|
|
|
let id = "abcde";
|
|
|
|
let mut dbs = Databases::new();
|
2023-01-27 12:44:26 -05:00
|
|
|
dbs.add_database(name, id).unwrap();
|
|
|
|
match dbs.add_database(name, "09876") {
|
|
|
|
Ok(_) => assert!(false, "There should have been an error"),
|
|
|
|
Err(err) => assert_eq!(err.to_string(), "database already exists"),
|
|
|
|
}
|
2023-01-21 21:46:39 -05:00
|
|
|
let output = dbs.get_database(name);
|
|
|
|
assert_eq!(output, Some(id.to_string()));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn get_bad_database() {
|
|
|
|
let dbs = Databases::new();
|
|
|
|
let output = dbs.get_database("missing");
|
|
|
|
assert_eq!(output, None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_databases() {
|
|
|
|
let mut dbs = Databases::new();
|
2023-01-27 12:44:26 -05:00
|
|
|
dbs.add_database("zebra", "a").unwrap();
|
|
|
|
dbs.add_database("alpha", "a").unwrap();
|
|
|
|
dbs.add_database("charlie", "a").unwrap();
|
|
|
|
dbs.add_database("wilma", "a").unwrap();
|
|
|
|
dbs.add_database("frank", "a").unwrap();
|
2023-01-21 21:46:39 -05:00
|
|
|
let expected = ["alpha", "charlie", "frank", "wilma", "zebra"];
|
|
|
|
let output = dbs.show();
|
|
|
|
assert_eq!(output, expected);
|
|
|
|
}
|
|
|
|
}
|
2023-01-22 14:15:34 -05:00
|
|
|
|
|
|
|
#[cfg(test)]
|
2023-02-04 14:29:07 -05:00
|
|
|
mod file_data {
|
2023-01-22 14:15:34 -05:00
|
|
|
use super::*;
|
2023-01-27 12:44:26 -05:00
|
|
|
use std::error::Error;
|
2023-01-22 14:15:34 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn to_bytes_new() {
|
|
|
|
let dbs = Databases::new();
|
|
|
|
let expected: Vec<u8> = Vec::new();
|
|
|
|
let output = dbs.to_bytes();
|
|
|
|
assert_eq!(output, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn to_bytes_with_database() {
|
|
|
|
let mut dbs = Databases::new();
|
|
|
|
let name = "something";
|
|
|
|
let id = "id";
|
2023-01-27 12:44:26 -05:00
|
|
|
dbs.add_database(name, id).unwrap();
|
2023-01-22 14:15:34 -05:00
|
|
|
let mut expected: Vec<u8> = Vec::new();
|
|
|
|
expected.append(&mut name.as_bytes().to_vec());
|
|
|
|
expected.push(0);
|
|
|
|
expected.append(&mut id.as_bytes().to_vec());
|
|
|
|
expected.push(0);
|
|
|
|
let output = dbs.to_bytes();
|
|
|
|
assert_eq!(output, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_bytes() {
|
|
|
|
let mut dbs = Databases::new();
|
2023-01-27 12:44:26 -05:00
|
|
|
dbs.add_database("one", "1").unwrap();
|
|
|
|
dbs.add_database("two", "2").unwrap();
|
|
|
|
dbs.add_database("three", "3").unwrap();
|
2023-01-22 14:15:34 -05:00
|
|
|
let data = dbs.to_bytes();
|
|
|
|
let mut feed = data.iter();
|
|
|
|
let output = Databases::from_bytes(&mut feed).unwrap();
|
|
|
|
assert_eq!(output.db_map, dbs.db_map);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_bytes_incomplete_name() {
|
|
|
|
let data = "notName".as_bytes();
|
|
|
|
let mut feed = data.iter();
|
|
|
|
match Databases::from_bytes(&mut feed) {
|
|
|
|
Ok(_) => assert!(false, "This should have failed."),
|
|
|
|
Err(err) => assert_eq!(err.to_string(), "file corruption"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_bytes_incomplete_id() {
|
|
|
|
let mut data = "proper".as_bytes().to_vec();
|
|
|
|
data.push(0);
|
|
|
|
data.append(&mut "nope".as_bytes().to_vec());
|
|
|
|
let mut feed = data.iter();
|
|
|
|
match Databases::from_bytes(&mut feed) {
|
|
|
|
Ok(_) => assert!(false, "This should have failed."),
|
|
|
|
Err(err) => assert_eq!(err.to_string(), "file corruption"),
|
|
|
|
}
|
|
|
|
}
|
2023-01-27 12:44:26 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_bytes_handles_error() {
|
|
|
|
let mut data = "duplicate".as_bytes().to_vec();
|
|
|
|
data.push(0);
|
|
|
|
data.append(&mut "first".as_bytes().to_vec());
|
|
|
|
data.push(0);
|
|
|
|
data.append(&mut "duplicate".as_bytes().to_vec());
|
|
|
|
data.push(0);
|
|
|
|
data.append(&mut "second".as_bytes().to_vec());
|
|
|
|
data.push(0);
|
|
|
|
let mut feed = data.iter();
|
|
|
|
match Databases::from_bytes(&mut feed) {
|
|
|
|
Ok(_) => assert!(false, "This should have failed."),
|
|
|
|
Err(err) => {
|
|
|
|
assert_eq!(err.to_string(), "file corruption");
|
|
|
|
assert!(
|
|
|
|
err.source().is_some(),
|
|
|
|
"Should state file corruption cause."
|
|
|
|
);
|
|
|
|
assert_eq!(err.source().unwrap().to_string(), "database already exists")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-01-22 14:15:34 -05:00
|
|
|
}
|
2023-02-04 14:29:07 -05:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod session_data {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn add_new() {
|
|
|
|
let mut dbs = Databases::new();
|
|
|
|
let key = "name";
|
|
|
|
let value = "marvin";
|
|
|
|
let data = "123456";
|
|
|
|
assert_eq!(dbs.add(key, value, data).unwrap(), [data]);
|
|
|
|
let output = dbs.get(key, value).unwrap();
|
|
|
|
assert_eq!(output, [data]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn add_bad_key() {
|
|
|
|
let mut dbs = Databases::new();
|
|
|
|
let key = "sdgfjksg";
|
|
|
|
match dbs.add(key, "fred", "barney") {
|
|
|
|
Ok(_) => assert!(false, "Bad keys should produce an error."),
|
|
|
|
Err(err) => assert_eq!(err.to_string(), format!("databases do not have a {}", key)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn get_bad_key() {
|
|
|
|
let dbs = Databases::new();
|
|
|
|
let key = "bvdfgert";
|
|
|
|
match dbs.get(key, "fred") {
|
|
|
|
Ok(_) => assert!(false, "Bad keys should produce an error."),
|
|
|
|
Err(_) => (),
|
|
|
|
}
|
|
|
|
}
|
2023-02-04 23:06:29 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn unique_names() {
|
|
|
|
let mut dbs = Databases::new();
|
|
|
|
let value = "wilma";
|
|
|
|
dbs.add("name", value, "something").unwrap();
|
|
|
|
match dbs.add("name", value, "overwrite") {
|
|
|
|
Ok(_) => assert!(false, "Duplicate names should produce an error."),
|
|
|
|
Err(err) => assert_eq!(
|
|
|
|
err.to_string(),
|
|
|
|
format!("database {} already exists", value)
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn get_missing() {
|
|
|
|
let dbs = Databases::new();
|
|
|
|
let output = dbs.get("name", "melvin").unwrap();
|
|
|
|
assert_eq!(output, Vec::<String>::new());
|
|
|
|
}
|
2023-02-04 14:29:07 -05:00
|
|
|
}
|