//! ## Serializer //! //! `serializer` is the module which provides the serializer/deserializer for bookmarks /* * * Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * * TermSCP is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * TermSCP is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with TermSCP. If not, see . * */ use super::{SerializerError, SerializerErrorKind, UserHosts}; use std::io::{Read, Write}; pub struct BookmarkSerializer {} impl BookmarkSerializer { /// ### serialize /// /// Serialize `UserHosts` into TOML and write content to writable pub fn serialize( &self, mut writable: Box, hosts: &UserHosts, ) -> Result<(), SerializerError> { // Serialize content let data: String = match toml::ser::to_string(hosts) { Ok(dt) => dt, Err(err) => { return Err(SerializerError::new_ex( SerializerErrorKind::SerializationError, err.to_string(), )) } }; // Write file match writable.write_all(data.as_bytes()) { Ok(_) => Ok(()), Err(err) => Err(SerializerError::new_ex( SerializerErrorKind::IoError, err.to_string(), )), } } /// ### deserialize /// /// Read data from readable and deserialize its content as TOML pub fn deserialize(&self, mut readable: Box) -> Result { // Read file content let mut data: String = String::new(); if let Err(err) = readable.read_to_string(&mut data) { return Err(SerializerError::new_ex( SerializerErrorKind::IoError, err.to_string(), )); } // Deserialize match toml::de::from_str(data.as_str()) { Ok(hosts) => Ok(hosts), Err(err) => Err(SerializerError::new_ex( SerializerErrorKind::SyntaxError, err.to_string(), )), } } } // Tests #[cfg(test)] mod tests { use super::super::Bookmark; use super::*; use std::collections::HashMap; use std::io::{Seek, SeekFrom}; #[test] fn test_bookmarks_serializer_deserialize_ok() { let toml_file: tempfile::NamedTempFile = create_good_toml(); toml_file.as_file().sync_all().unwrap(); toml_file.as_file().seek(SeekFrom::Start(0)).unwrap(); // Parse let deserializer: BookmarkSerializer = BookmarkSerializer {}; let hosts = deserializer.deserialize(Box::new(toml_file)); assert!(hosts.is_ok()); let hosts: UserHosts = hosts.ok().unwrap(); // Verify hosts // Verify recents assert_eq!(hosts.recents.len(), 1); let host: &Bookmark = hosts.recents.get("ISO20201215T094000Z").unwrap(); assert_eq!(host.address, String::from("172.16.104.10")); assert_eq!(host.port, 22); assert_eq!(host.protocol, String::from("SCP")); assert_eq!(host.username, String::from("root")); assert_eq!(host.password, None); // Verify bookmarks assert_eq!(hosts.bookmarks.len(), 3); let host: &Bookmark = hosts.bookmarks.get("raspberrypi2").unwrap(); assert_eq!(host.address, String::from("192.168.1.31")); assert_eq!(host.port, 22); assert_eq!(host.protocol, String::from("SFTP")); assert_eq!(host.username, String::from("root")); assert_eq!(*host.password.as_ref().unwrap(), String::from("mypassword")); let host: &Bookmark = hosts.bookmarks.get("msi-estrem").unwrap(); assert_eq!(host.address, String::from("192.168.1.30")); assert_eq!(host.port, 22); assert_eq!(host.protocol, String::from("SFTP")); assert_eq!(host.username, String::from("cvisintin")); assert_eq!(*host.password.as_ref().unwrap(), String::from("mysecret")); let host: &Bookmark = hosts.bookmarks.get("aws-server-prod1").unwrap(); assert_eq!(host.address, String::from("51.23.67.12")); assert_eq!(host.port, 21); assert_eq!(host.protocol, String::from("FTPS")); assert_eq!(host.username, String::from("aws001")); assert_eq!(host.password, None); } #[test] fn test_bookmarks_serializer_deserialize_nok() { let toml_file: tempfile::NamedTempFile = create_bad_toml(); toml_file.as_file().sync_all().unwrap(); toml_file.as_file().seek(SeekFrom::Start(0)).unwrap(); // Parse let deserializer: BookmarkSerializer = BookmarkSerializer {}; assert!(deserializer.deserialize(Box::new(toml_file)).is_err()); } #[test] fn test_bookmarks_serializer_serialize() { let mut bookmarks: HashMap = HashMap::with_capacity(2); // Push two samples bookmarks.insert( String::from("raspberrypi2"), Bookmark { address: String::from("192.168.1.31"), port: 22, protocol: String::from("SFTP"), username: String::from("root"), password: None, }, ); bookmarks.insert( String::from("msi-estrem"), Bookmark { address: String::from("192.168.1.30"), port: 4022, protocol: String::from("SFTP"), username: String::from("cvisintin"), password: Some(String::from("password")), }, ); let mut recents: HashMap = HashMap::with_capacity(1); recents.insert( String::from("ISO20201215T094000Z"), Bookmark { address: String::from("192.168.1.254"), port: 3022, protocol: String::from("SCP"), username: String::from("omar"), password: Some(String::from("aaa")), }, ); let tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap(); // Serialize let deserializer: BookmarkSerializer = BookmarkSerializer {}; let hosts: UserHosts = UserHosts { bookmarks, recents }; assert!(deserializer.serialize(Box::new(tmpfile), &hosts).is_ok()); } fn create_good_toml() -> tempfile::NamedTempFile { // Write let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap(); let file_content: &str = r#" [bookmarks] raspberrypi2 = { address = "192.168.1.31", port = 22, protocol = "SFTP", username = "root", password = "mypassword" } msi-estrem = { address = "192.168.1.30", port = 22, protocol = "SFTP", username = "cvisintin", password = "mysecret" } aws-server-prod1 = { address = "51.23.67.12", port = 21, protocol = "FTPS", username = "aws001" } [recents] ISO20201215T094000Z = { address = "172.16.104.10", port = 22, protocol = "SCP", username = "root" } "#; tmpfile.write_all(file_content.as_bytes()).unwrap(); //write!(tmpfile, "[bookmarks]\nraspberrypi2 = {{ address = \"192.168.1.31\", port = 22, protocol = \"SFTP\", username = \"root\" }}\nmsi-estrem = {{ address = \"192.168.1.30\", port = 22, protocol = \"SFTP\", username = \"cvisintin\" }}\naws-server-prod1 = {{ address = \"51.23.67.12\", port = 21, protocol = \"FTPS\", username = \"aws001\" }}\n\n[recents]\nISO20201215T094000Z = {{ address = \"172.16.104.10\", port = 22, protocol = \"SCP\", username = \"root\" }}\n"); tmpfile } fn create_bad_toml() -> tempfile::NamedTempFile { // Write let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap(); let file_content: &str = r#" [bookmarks] raspberrypi2 = { address = "192.168.1.31", port = 22, protocol = "SFTP", username = "root"} msi-estrem = { address = "192.168.1.30", port = 22, protocol = "SFTP" } aws-server-prod1 = { address = "51.23.67.12", port = 21, protocol = "FTPS", username = "aws001" } [recents] ISO20201215T094000Z = { address = "172.16.104.10", protocol = "SCP", username = "root", port = 22 } "#; tmpfile.write_all(file_content.as_bytes()).unwrap(); tmpfile } }