· 5 years ago · Mar 02, 2020, 01:12 AM
1
2 ///Module holding all the structs, enumerations,...
3 pub mod domain {
4
5 use std::string::ToString;
6 use serde::{Serialize, Deserialize};
7
8 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
9 ///Represents a cat
10 pub struct Cat {
11 pub name: String,
12 pub age: u8,
13 pub color: CatColor,
14 pub race: CatRace,
15 }
16 impl Cat {
17 ///Constructor to intialize a new cat
18 pub fn new(name: String, age: u8, color: CatColor, race: CatRace) -> Cat {
19 Cat {
20 name: name,
21 age: age,
22 color: color,
23 race: race,
24 }
25 }
26
27 ///Returns the info of the cat in a String
28 pub fn to_string(&self) -> String {
29 let s = format!("Name: {name}\nAge: {age}\nColor: {color}\nRace: {race}",
30 name = self.name,
31 age = self.age,
32 color = self.color.to_string(),
33 race = self.race.to_string(),
34 );
35
36 s
37 }
38 }
39
40 #[derive(Display, Serialize, Deserialize, Debug, Clone, EnumString, PartialEq)]
41 ///Enumeration of all the possible colors a cat can have
42 pub enum CatColor {
43 Black,
44 White,
45 Orange,
46 Gray,
47 }
48 impl CatColor {
49 pub fn from_u8(value: u8) -> CatColor {
50 match value {
51 1 => CatColor::Black,
52 2 => CatColor::White,
53 3 => CatColor::Orange,
54 4 => CatColor::Gray,
55 _ => {
56 eprintln!("Invalid CatColor selected!");
57 std::process::exit(0);
58 }
59 }
60 }
61
62 }
63
64 #[derive(Display, Serialize, Deserialize, Debug, Clone, EnumString, PartialEq)]
65 ///Enumeration of all the possible races a cat can have
66 pub enum CatRace {
67 Streetcat,
68 AmericanShorthair,
69 BritishShorthair,
70 Bengal,
71 EgyptianMau,
72 }
73 impl CatRace {
74 pub fn from_u8(value: u8) -> CatRace {
75 match value {
76 1 => CatRace::Streetcat,
77 2 => CatRace::AmericanShorthair,
78 3 => CatRace::BritishShorthair,
79 4 => CatRace::Bengal,
80 5 => CatRace::EgyptianMau,
81 _ => {
82 eprintln!("Invalid CatRace selected!");
83 std::process::exit(0);
84 }
85 }
86 }
87 }
88 }
89
90 //Module holding functions necessary for the userinterface
91 pub mod user_interface {
92
93 pub mod display {
94 use std::io;
95
96 ///Function to display the start menu
97 pub fn display_start_menu() {
98 println!("Welcome to the cat database!");
99 println!("1) Add cat");
100 println!("2) View all cats");
101 println!("3) View one cat");
102 println!("4) Delete one cat");
103 }
104
105 ///Function to display add-cat-menu
106 pub fn display_add_cat_menu() {
107 println!("Give all the info about the cat!");
108 }
109
110 ///Function to display view-all-cats-menu
111 pub fn display_view_all_cats_menu() {
112 println!("List of all the cats:");
113 }
114
115 ///Function to display view-one-cat-menu
116 pub fn display_view_one_cat_menu() {
117 println!("Reading a cat...");
118 }
119
120 ///Function to display delete-one-cat-menu
121 pub fn display_delete_one_cat_menu() {
122 println!("Deleting a cat...");
123 }
124
125 ///Function to flush std output
126 pub fn flush() {
127 io::Write::flush(&mut io::stdout()).expect("Flush failed...");
128 }
129 }
130
131 pub mod input {
132 use std::io;
133 use std::io::stdin;
134 use std::str::FromStr;
135
136 ///Function to get user input
137 pub fn get<T: FromStr>() -> T {
138 print!(">");
139 //Flush display
140 io::Write::flush(&mut io::stdout()).expect("Flush failed...");
141
142 //Get input and put it in mutable string
143 let mut input = String::new();
144 stdin()
145 .read_line(&mut input)
146 .expect("No valid input given...");
147
148 match input.trim().parse() {
149 Ok(i) => i,
150 Err(..) => {
151 eprintln!("Corrupted input '{}' given!", input);
152 std::process::exit(0);
153 }
154 }
155 }
156 }
157 }
158
159 //Module to access, read, and write data
160 pub mod data_layer {
161 use std::vec::Vec;
162 use crate::domain::*;
163
164 /// Trait to generalize the different type of data management options
165 pub trait DataManager {
166 /// Add to the database
167 ///
168 /// #Arguments
169 ///
170 /// * 'cat' - A Cat object
171 fn add(&mut self, cat: Cat) -> bool;
172
173 /// Read from the database
174 fn read(&mut self) -> &Vec<Cat>;
175
176 /// Delete specific cat from the database
177 ///
178 /// #Arguments
179 ///
180 /// * 'name' - Name of the cat to delete
181 fn delete(&mut self, name : &String) -> bool;
182
183 /// Read specific cat from the database
184 ///
185 /// #Arguments
186 ///
187 /// * 'name' - Name of the cat to retrieve
188 fn get(&mut self, name : &String) -> Option<&Cat>;
189 }
190
191 //To manage data in memory
192 pub struct MemoryData {
193 cats: Vec<Cat>,
194 }
195 impl MemoryData {
196 pub fn new() -> MemoryData {
197 MemoryData { cats: Vec::new() }
198 }
199 }
200 impl DataManager for MemoryData {
201 fn add(&mut self, cat: Cat) -> bool {
202 self.cats.push(cat);
203 true
204 }
205 fn read(&mut self) -> &Vec<Cat> {
206 &self.cats
207 }
208 fn delete(&mut self, name : &String) -> bool {
209 let length_before_deletion : usize = self.cats.len();
210 self.cats.retain(|cat| &cat.name != name);
211
212 length_before_deletion > self.cats.len()
213 }
214 fn get(&mut self, name : &String) -> Option<&Cat> {
215 self.cats.iter().find(|cat| &cat.name == name)
216 }
217 }
218
219 use std::fs::File;
220 use std::fs::OpenOptions;
221 use std::io::prelude::*;
222 use std::io::SeekFrom;
223 use std::error::Error;
224 //To manage data in file
225 pub struct FileData {
226 path: String,
227 file: File,
228 cats: Vec<Cat>,
229 }
230 impl FileData {
231 pub fn new(file_name : String) -> FileData {
232 let path : String = format!("data/{}", file_name);
233
234 FileData {
235 path: path.to_string(),
236 file: FileData::init_file(&path),
237 cats: Vec::new(),
238 }
239 }
240
241 fn init_file(path : &String) -> File {
242 OpenOptions::new()
243 .create(true)
244 .append(true)
245 .read(true)
246 .open(path)
247 .unwrap()
248 }
249
250 pub fn empty_file(file : &mut File) {
251 file.set_len(0).expect("Failed to empty file...");
252 file.seek(SeekFrom::Start(0)).expect("Failed to empty file...");
253 }
254 }
255 impl DataManager for FileData {
256 //Add cat-data to file
257 fn add (&mut self, cat: Cat) -> bool {
258 //Serialize to JSON String using Serde
259 let mut json : String = serde_json::to_string(&cat).unwrap();
260 if self.read().len() > 0 {
261 json = format!(",{}", json);
262 }
263
264 match self.file.write_all(json.as_bytes()) {
265 Err(err) => {
266 eprintln!("Couldn't write to file '{}:' {}!", self.path, err.description());
267 false
268 }
269 Ok(_) => {
270 println!("Succesfully saved data of cat '{}' in {}...", cat.name, self.path);
271
272 //Re-intializing file to keep data up-to-date while program is running
273 self.file = FileData::init_file(&self.path);
274 true
275 }
276 }
277 }
278
279 //Read all cats saved in file
280 fn read(&mut self) -> &Vec<Cat> {
281 let mut json : String = String::new();
282 self.file.read_to_string(&mut json).expect("Failed to read file...");
283
284 //Re-intialize file to keep data up-to-date while program is running
285 self.file = FileData::init_file(&self.path);
286
287 json = format!("[{}]", json);
288
289 self.cats = serde_json::from_str(&json).unwrap();
290 &self.cats
291 }
292
293 //Delete a specific cat in file
294 fn delete(&mut self, name: &String) -> bool {
295 //Read all cats in a vector except cat matching specified name
296 let mut cats_temp : Vec<Cat> = self.read().to_vec();
297 let length_before_deleting : usize = cats_temp.len();
298 cats_temp.retain(|cat| &cat.name != name);
299
300 //Empty the file
301 FileData::empty_file(&mut self.file);
302
303 //Read all cats from vector back to file using our add-method
304 for cat in cats_temp {
305 self.add(cat);
306 }
307
308 self.cats = self.read().to_vec();
309
310 length_before_deleting > self.cats.len()
311 }
312
313 //Get the cat with the matching name
314 fn get(&mut self, name : &String) -> Option<&Cat> {
315 self.read().iter().find(|cat| &cat.name == name)
316 }
317 }
318
319 //To manage data in MySql-Database
320 pub struct MySQLData {
321 conn : mysql::Pool,
322 cats: Vec<Cat>,
323 }
324 impl MySQLData {
325 /// Use this function to intialize a MySQLData object and initialize a database connection
326 /// with it
327 ///
328 /// #Arguments
329 ///
330 /// * 'database_name' - Name of the database to connect to
331 /// * 'database_user' - Username to use for authentication
332 /// * 'database_pass' - Password to use for authentication
333 ///
334 /// #Example
335 ///
336 /// ```
337 /// let ref mut db = data_layer::MySQLData::new(&String::from("myDatabase"), &String::from("user"), &String::from("pass"));
338 /// ```
339 pub fn new(database_name : &String, database_user : &String, database_pass : &String) -> MySQLData {
340 let mut mysql = MySQLData {
341 conn: MySQLData::init_connection(&String::from(database_name), &String::from(database_user), &String::from(database_pass)).unwrap(),
342 cats: std::vec::Vec::<Cat>::new(),
343 };
344
345 mysql.init_tables();
346 mysql
347
348 }
349
350 /// Function to establish (a pooled) connection with the MySQL database. This connection
351 /// is stored in self.conn
352 ///
353 /// # Arguments
354 ///
355 /// * 'database_name' - Name of the database to connect to
356 /// * 'database_user' - Username to use for authentication
357 /// * 'database_pass' - Password to use for authentication
358 pub fn init_connection(database_name : &String, database_user : &String, database_pass : &String) -> std::result::Result<mysql::Pool, mysql::Error> {
359 //Create connection with database
360 let conn_str : String = format!("mysql://{user}:{pass}@localhost/{name}", user=database_user, pass=database_pass, name=database_name);
361 let conn : std::result::Result<mysql::Pool, mysql::Error> = mysql::Pool::new(conn_str);
362
363 //Check if connection was succesful
364 match conn {
365 Ok(_) => {
366 println!("Connection to {} succesfully made...", database_name);
367 conn
368 },
369 Err(e) => {
370 eprintln!("Connection to {} failed: {}", database_name, e.description());
371 std::process::exit(-1);
372 },
373 }
374 }
375
376 /// Function to create tables needed for this application if they
377 /// don't already exist
378 pub fn init_tables(&mut self) {
379 //Create tables if they don't exist
380 //Table holding all the cat-races we know
381 self.conn.prep_exec(
382 "CREATE TABLE IF NOT EXISTS races (
383 id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
384 race_name varchar(256) NOT NULL
385 )", ()).expect("Failed to create races table...");
386
387 //Table holding all the colours our cats have
388 self.conn.prep_exec("
389 CREATE TABLE IF NOT EXISTS colors (
390 id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
391 color_name varchar(256) NOT NULL
392 )", ()).expect("Failed to create colors table...");
393
394 //Table holding all the info about the cats
395 self.conn.prep_exec(
396 "CREATE TABLE IF NOT EXISTS cats (
397 id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
398 name VARCHAR(256) NOT NULL,
399 age INT,
400 color_id INT,
401 race_id INT,
402 FOREIGN KEY (color_id) REFERENCES colors(id),
403 FOREIGN KEY (race_id) REFERENCES races(id)
404 )", ()).expect("Failed to create cats table...");
405 }
406
407 /// Fill database with some dummy data
408 fn seed(&mut self) {
409 let seed_a : Cat = Cat {
410 name: "Cat A".to_string(),
411 age: 4,
412 race: CatRace::Streetcat,
413 color: CatColor::Black,
414 };
415 let seed_b : Cat = Cat {
416 name: "Cat B".to_string(),
417 age: 1,
418 race: CatRace::AmericanShorthair,
419 color: CatColor::Orange,
420 };
421 let seed_c : Cat = Cat {
422 name: "Cat C".to_string(),
423 age: 1,
424 race: CatRace::Bengal,
425 color: CatColor::Gray,
426 };
427
428 self.add(seed_a);
429 self.add(seed_b);
430 self.add(seed_c);
431 }
432 }
433
434 impl DataManager for MySQLData {
435 fn add(&mut self, cat : Cat) -> bool {
436 //Check if race of cat is already known in database
437 let selected_race_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> =
438 self.conn.prep_exec("SELECT id FROM races WHERE race_name = :race_name", params!("race_name" => cat.race.to_string())).unwrap().collect();
439
440 let mut results : std::vec::Vec<u16> = std::vec::Vec::new();
441 for row in selected_race_rows {
442 results.push(row.unwrap().take("id").unwrap());
443 }
444
445 let race_id : u64;
446 if results.len() == 0 {
447 //Race not yet known in database, so add that first
448 race_id = self.conn.prep_exec("INSERT INTO races (race_name) VALUES (:race_name)", params!("race_name" => cat.race.to_string())).unwrap().last_insert_id();
449 } else {
450 race_id = results[0].into();
451 }
452
453
454 //Check if color of cat is already known in database
455 let selected_color_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> =
456 self.conn.prep_exec("SELECT id from colors WHERE color_name = :color_name", params!("color_name" => cat.color.to_string())).unwrap().collect();
457
458 results = std::vec::Vec::new();
459 for row in selected_color_rows {
460 results.push(row.unwrap().take("id").unwrap());
461 }
462
463 let color_id : u64;
464 if results.len() == 0 {
465 //Color not yet known in database, so add that first
466 color_id = self.conn.prep_exec("INSERT INTO colors (color_name) VALUES (:color_name)", params!("color_name" => cat.color.to_string())).unwrap().last_insert_id();
467 } else {
468 color_id = results[0].into();
469 }
470
471 //Add the cat now
472 let add_query = self.conn.prep_exec("INSERT INTO cats (name, age, color_id, race_id) VALUES (:name, :age, :color_id, :race_id)", params!(
473 "name" => &cat.name,
474 "age" => cat.age,
475 "color_id" => color_id,
476 "race_id" => race_id,
477 ));
478
479 match add_query {
480 Ok(_) => {
481 true
482 },
483 Err(e) => {
484 eprintln!("Error occured while inserting cat in MySQL database: {}", e.description());
485 false
486 },
487 }
488
489 }
490
491 fn read(&mut self) -> &std::vec::Vec<Cat> {
492 self.cats = std::vec::Vec::new();
493
494 let selected_cat_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> =
495 self.conn.prep_exec("SELECT name, age, color_id, race_id FROM cats", ()).unwrap().collect();
496
497 for row in &selected_cat_rows {
498 //Retrieve color name from color-table by color_id
499 let color_id : u64 = row.as_ref().unwrap().get("color_id").unwrap();
500 let mut color : std::vec::Vec<String> = std::vec::Vec::<String>::new();
501 let color_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> = self.conn.prep_exec("SELECT color_name FROM colors WHERE id = :color_id", params!("color_id" => color_id)).unwrap().collect();
502 for subrow in &color_rows {
503 color.push(subrow.as_ref().unwrap().get("color_name").unwrap());
504 }
505
506 //Retrieve race name from race-table by race_id
507 let race_id : u64 = row.as_ref().unwrap().get("race_id").unwrap();
508 let mut race : std::vec::Vec<String> = std::vec::Vec::<String>::new();
509 let race_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> = self.conn.prep_exec("SELECT race_name FROM races WHERE id = :race_id", params!("race_id" => race_id)).unwrap().collect();
510 for subrow in &race_rows {
511 race.push(subrow.as_ref().unwrap().get("race_name").unwrap());
512 }
513
514 let cat : Cat = Cat {
515 name: row.as_ref().unwrap().get("name").unwrap(),
516 age: row.as_ref().unwrap().get("age").unwrap(),
517 color: color[0].parse().unwrap(),
518 race: race[0].parse().unwrap(),
519 };
520
521 self.cats.push(cat);
522 }
523
524 &self.cats
525 }
526 fn delete(&mut self, name : &String) -> bool {
527 let delete_query = self.conn.prep_exec("DELETE FROM cats WHERE name = :name",
528 params!("name" => name));
529
530 match delete_query {
531 Ok(_) => {
532 true
533 },
534 Err(e) => {
535 eprintln!("Failed to delete cat {} from database: {}", name, e.description());
536 false
537 }
538 }
539 }
540 fn get(&mut self, name : &String) -> Option<&Cat> {
541 self.cats = std::vec::Vec::new();
542
543 let selected_cat_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> =
544 self.conn.prep_exec("SELECT name, age, color_id, race_id FROM cats WHERE name = :name", params!("name" => name)).unwrap().collect();
545
546 for row in &selected_cat_rows {
547 //Retrieve color name from color-table by color_id
548 let color_id : u64 = row.as_ref().unwrap().get("color_id").unwrap();
549 let mut color : std::vec::Vec<String> = std::vec::Vec::<String>::new();
550 let color_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> = self.conn.prep_exec("SELECT color_name FROM colors WHERE id = :color_id", params!("color_id" => color_id)).unwrap().collect();
551 for subrow in &color_rows {
552 color.push(subrow.as_ref().unwrap().get("color_name").unwrap());
553 }
554
555 //Retrieve race name from race-table by race_id
556 let race_id : u64 = row.as_ref().unwrap().get("race_id").unwrap();
557 let mut race : std::vec::Vec<String> = std::vec::Vec::<String>::new();
558 let race_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> = self.conn.prep_exec("SELECT race_name FROM races WHERE id = :race_id", params!("race_id" => race_id)).unwrap().collect();
559 for subrow in &race_rows {
560 race.push(subrow.as_ref().unwrap().get("race_name").unwrap());
561 }
562
563 let cat : Cat = Cat {
564 name: row.as_ref().unwrap().get("name").unwrap(),
565 age: row.as_ref().unwrap().get("age").unwrap(),
566 color: color[0].parse().unwrap(),
567 race: race[0].parse().unwrap(),
568 };
569
570 self.cats.push(cat);
571 }
572
573 Some(&self.cats[0])
574 }
575 }
576 }
577
578 //Module holding logic and binding everything together
579 pub mod app {
580 use crate::user_interface;
581 use crate::data_layer;
582 use crate::domain::*;
583
584 //Run the application
585 pub fn run<D: data_layer::DataManager>(db: &mut D) {
586 user_interface::display::display_start_menu();
587 let option: u8 = user_interface::input::get();
588 execute_option(option, db);
589 }
590
591 //Execute the selected option with corresponding function
592 pub fn execute_option<D: data_layer::DataManager>(option: u8, db: &mut D) {
593 match option {
594 1 => {
595 add_cat(db);
596 }
597 2 => {
598 view_all_cats(db);
599 }
600 3 => {
601 view_one_cat(db);
602 }
603 4 => {
604 delete_one_cat(db);
605 }
606 _ => {
607 eprintln!("Invalid option '{}' selected...", option);
608 }
609 }
610
611 println!("\n");
612 }
613
614 //Function to add a cat
615 pub fn add_cat<D: data_layer::DataManager>(db: &mut D) {
616 //Displaying menu header
617 user_interface::display::display_add_cat_menu();
618
619 //Getting al the info
620 println!("Name:");
621 let name: String = user_interface::input::get();
622
623 println!("Age:");
624 let age: u8 = user_interface::input::get();
625
626 println!("Color:\n1) Black 2) White 3) Orange 4) Gray");
627 let color: CatColor = CatColor::from_u8(user_interface::input::get());
628
629 println!("Race:\n1) Streetcat 2) American Shorthair 3) British Shorthair 4) Bengal 5) Egyptian Mau");
630 let race: CatRace = CatRace::from_u8(user_interface::input::get());
631
632 //Create cat object
633 let cat: Cat = Cat::new(name, age, color, race);
634
635 //Save cat object
636 db.add(cat);
637
638 println!("Cat added...");
639 }
640
641 //Function to view all cats
642 pub fn view_all_cats<D: data_layer::DataManager>(db: &mut D) {
643 //Displaying menu header
644 user_interface::display::display_view_all_cats_menu();
645 //user_interface::display::flush();
646 std::io::Write::flush(&mut std::io::stdout()).expect("Flush failed...");
647
648 //Reading, iterating over, and outputting all the cats
649 for cat in db.read() {
650 println!("{}\n", cat.to_string());
651 }
652
653 }
654
655 //Function to view one specific cat
656 pub fn view_one_cat<D: data_layer::DataManager>(db: &mut D) {
657 //Displaying menu header
658 user_interface::display::display_view_one_cat_menu();
659 std::io::Write::flush(&mut std::io::stdout()).expect("Flush failed...");
660
661 //Get name of cat user wants to read
662 println!("Give name of the cat:");
663 let name : String = user_interface::input::get();
664
665 //Get the cat out of data
666 let cat : &Cat = db.get(&name).unwrap();
667
668 //Output cat info
669 println!("{}\n", cat.to_string());
670 }
671
672 //Function to delete one specific cat
673 pub fn delete_one_cat<D: data_layer::DataManager>(db: &mut D) {
674 //Displaying menu header
675 user_interface::display::display_delete_one_cat_menu();
676 std::io::Write::flush(&mut std::io::stdout()).expect("Flush failed...");
677
678 //Get name of the cat user wants to delete
679 println!("Give name of the cat:");
680 let name : String = user_interface::input::get();
681
682 //Delete the cat
683 match db.delete(&name) {
684 true => {
685 println!("{} succesfully deleted!", name);
686 },
687 false => {
688 eprintln!("Error deleting {}!", name);
689 },
690 }
691 }
692 }
693
694 //Unit tests
695 #[cfg(test)]
696 mod tests {
697 use super::*;
698 use super::domain::*;
699 use super::data_layer::DataManager;
700
701 fn get_cat_for_test(cat_letter : String) -> Cat {
702 //Cat objects to perform tests with
703 let cat_a : Cat = Cat::new("Mr. Cat A".to_string(), 1, CatColor::Black, CatRace::Streetcat);
704 let cat_b : Cat = Cat::new("Mr. Cat B".to_string(), 5, CatColor::Orange, CatRace::EgyptianMau);
705 let cat_c : Cat = Cat::new("Mr. Cat C".to_string(), 7, CatColor::Gray, CatRace::BritishShorthair);
706
707 match cat_letter.as_str() {
708 "A" => cat_a,
709 "B" => cat_b,
710 "C" => cat_c,
711 _ => cat_a,
712 }
713 }
714
715 //Testing memory data module
716 #[test]
717 fn test_memory_data() {
718
719 let ref mut mem = data_layer::MemoryData::new();
720
721 //Adding cat_a
722 assert!(mem.add(get_cat_for_test("A".to_string())));
723 assert_eq!(*mem.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("A".to_string()));
724 assert_ne!(*mem.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("B".to_string()));
725
726 //Adding another one
727 assert!(mem.add(get_cat_for_test("B".to_string())));
728 assert_eq!(mem.read().len(), 2);
729
730 //Deleting one
731 assert!(mem.delete(&String::from("Mr. Cat A")));
732 assert_eq!(mem.read().len(), 1);
733
734 assert_eq!(mem.delete(&String::from("Random String")), false);
735 assert_eq!(mem.read().len(), 1);
736
737 assert_eq!(mem.read()[0], get_cat_for_test("B".to_string()));
738 }
739
740 //Testing file data module
741 #[test]
742 fn test_file_data() {
743 let ref mut file = data_layer::FileData::new("cat_test_database.txt".to_string());
744
745 //Adding cat_a
746 assert!(file.add(get_cat_for_test("A".to_string())));
747 assert_eq!(*file.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("A".to_string()));
748 assert_ne!(*file.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("B".to_string()));
749
750 //Adding another one
751 assert!(file.add(get_cat_for_test("B".to_string())));
752 assert_eq!(file.read().len(), 2);
753
754 //Deleting one
755 assert!(file.delete(&String::from("Mr. Cat A")));
756 assert_eq!(file.read().len(), 1);
757
758 assert_eq!(file.delete(&String::from("Random String")), false);
759 assert_eq!(file.read().len(), 1);
760
761 assert_eq!(file.read()[0], get_cat_for_test("B".to_string()));
762 }
763
764 //Testing file data module
765 #[test]
766 fn test_mysql_data() {
767 let ref mut mysql = data_layer::MySQLData::new(&String::from("catdatabase_test"), &String::from("root"), &String::from("toor"));
768
769 //Adding cat_a
770 assert!(mysql.add(get_cat_for_test("A".to_string())));
771 assert_eq!(*mysql.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("A".to_string()));
772 assert_ne!(*mysql.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("B".to_string()));
773
774 //Adding another one
775 assert!(mysql.add(get_cat_for_test("B".to_string())));
776 assert_eq!(mysql.read().len(), 2);
777
778 //Deleting one
779 assert!(mysql.delete(&String::from("Mr. Cat A")));
780 assert_eq!(mysql.read().len(), 1);
781
782 assert_eq!(mysql.delete(&String::from("Random String")), false);
783 assert_eq!(mysql.read().len(), 1);
784
785 assert_eq!(mysql.read()[0], get_cat_for_test("B".to_string()));
786 }
787
788 }
789
790 //Crates
791 extern crate strum;
792 #[macro_use]
793 extern crate strum_macros;
794 extern crate serde;
795 extern crate serde_json;
796
797 #[macro_use]
798 extern crate mysql;
799
800 fn main() {
801 //Initialize database
802 //let ref mut db = data_layer::MySQLData::new(&String::from("catdatabase"), &String::from("root"), &String::from("toor"));
803 //let ref mut db = data_layer::FileData::new("catdatabase.txt".to_string());
804
805 let ref mut db = data_layer::MemoryData::new();
806
807 loop {
808 app::run(db);
809 }
810 }