From 04a2d84afa5349d3bfde60a7581ad1ab4334ed10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roger=20D=C3=ADaz=20Vi=C3=B1olas?= Date: Tue, 8 Feb 2022 21:38:46 +0100 Subject: [PATCH] Rustfmt --- src/compilation/compiler.rs | 79 ++++++++++++++------ src/compilation/mod.rs | 2 +- src/compilation/template.rs | 83 ++++++++++++++------- src/config.rs | 60 ++++++++------- src/fetch/connection_manager.rs | 24 +++--- src/fetch/credentials.rs | 16 ++-- src/fetch/download.rs | 18 +++-- src/fetch/mod.rs | 43 +++++++---- src/fetch/unzip.rs | 22 +++--- src/lib.rs | 74 ++++++++++++++----- src/main.rs | 2 +- src/problem.rs | 125 +++++++++++++++++++------------- src/test_utils.rs | 15 ++-- src/testing/diff_display.rs | 77 +++++++++++++++----- src/testing/mod.rs | 4 +- src/testing/test.rs | 62 ++++++++++++---- src/testing/testsuite.rs | 32 +++++--- src/ux.rs | 58 +++++++++++---- 18 files changed, 535 insertions(+), 261 deletions(-) diff --git a/src/compilation/compiler.rs b/src/compilation/compiler.rs index 59d5dfc..76fe1fa 100644 --- a/src/compilation/compiler.rs +++ b/src/compilation/compiler.rs @@ -1,16 +1,25 @@ -use std::{fmt, io, path, process}; use crate::{debug, problem}; +use std::{fmt, io, path, process}; pub static P1XX: Compiler = Compiler { command: "g++", - flags1: &["-D_JUDGE_", "-DNDEBUG", "-O2", "-Wall", "-Wextra", "-Werror", "-Wno-sign-compare", "-Wshadow"], - flags2: &["-D_JUDGE_", "-DNDEBUG", "-O2"] + flags1: &[ + "-D_JUDGE_", + "-DNDEBUG", + "-O2", + "-Wall", + "-Wextra", + "-Werror", + "-Wno-sign-compare", + "-Wshadow", + ], + flags2: &["-D_JUDGE_", "-DNDEBUG", "-O2"], }; pub struct Compiler<'a> { command: &'a str, - flags1: &'a[&'a str], - flags2: &'a[&'a str] + flags1: &'a [&'a str], + flags2: &'a [&'a str], } pub enum CompilationError { @@ -19,7 +28,7 @@ pub enum CompilationError { OutputIsADir, ExecutionError(io::Error), CompilerError(String), - MissingOutput + MissingOutput, } impl fmt::Display for CompilationError { @@ -29,15 +38,17 @@ impl fmt::Display for CompilationError { CompilationError::SourceIsADir => write!(f, "Source is a directory!"), CompilationError::OutputIsADir => write!(f, "Output is a directory!"), CompilationError::ExecutionError(e) => write!(f, "Command execution error: {}", e), - CompilationError::CompilerError(stderr) => write!(f, "The compiler raised an error:\n{}", stderr), - CompilationError::MissingOutput => write!(f, "Can't find the compiler output!") + CompilationError::CompilerError(stderr) => { + write!(f, "The compiler raised an error:\n{}", stderr) + } + CompilationError::MissingOutput => write!(f, "Can't find the compiler output!"), } } } pub struct CompileProcessError { pub pass: u8, - pub error: CompilationError + pub error: CompilationError, } impl fmt::Display for CompileProcessError { @@ -48,11 +59,17 @@ impl fmt::Display for CompileProcessError { enum CompilationType { Object, - Binary + Binary, } impl Compiler<'_> { - fn run(&self, source: &path::Path, output: &path::Path, compilation_type: CompilationType, flags: &[&str]) -> Result<(), CompilationError>{ + fn run( + &self, + source: &path::Path, + output: &path::Path, + compilation_type: CompilationType, + flags: &[&str], + ) -> Result<(), CompilationError> { if !source.exists() { Err(CompilationError::SourceDoesNotExist) } else if source.is_dir() { @@ -61,12 +78,13 @@ impl Compiler<'_> { Err(CompilationError::OutputIsADir) } else { let mut command = process::Command::new(&self.command); - command.args(flags) + command + .args(flags) .args(["-o", output.to_string_lossy().as_ref()]); match compilation_type { CompilationType::Object => command.args(["-c", source.to_string_lossy().as_ref()]), - CompilationType::Binary => command.arg(source.to_string_lossy().to_string()) + CompilationType::Binary => command.arg(source.to_string_lossy().to_string()), }; debug!("Running command: {:?}", command); @@ -79,24 +97,42 @@ impl Compiler<'_> { Err(CompilationError::MissingOutput) } } else { - Err(CompilationError::CompilerError(String::from_utf8_lossy(&command.stderr).to_string())) + Err(CompilationError::CompilerError( + String::from_utf8_lossy(&command.stderr).to_string(), + )) } } } - fn compile_first_pass(&self, source: &path::Path, output: &path::Path) -> Result<(), CompilationError> { + fn compile_first_pass( + &self, + source: &path::Path, + output: &path::Path, + ) -> Result<(), CompilationError> { self.run(source, output, CompilationType::Object, self.flags1) } - fn compile_and_link_first_pass(&self, source: &path::Path, output: &path::Path) -> Result<(), CompilationError> { + fn compile_and_link_first_pass( + &self, + source: &path::Path, + output: &path::Path, + ) -> Result<(), CompilationError> { self.run(source, output, CompilationType::Binary, self.flags1) } - fn compile_and_link_second_pass(&self, source: &path::Path, output: &path::Path) -> Result<(), CompilationError> { + fn compile_and_link_second_pass( + &self, + source: &path::Path, + output: &path::Path, + ) -> Result<(), CompilationError> { self.run(source, output, CompilationType::Binary, self.flags2) } - pub fn compile_problem(&self, problem: &problem::Problem, generated_source: &path::Path) -> Result<(), CompileProcessError>{ + pub fn compile_problem( + &self, + problem: &problem::Problem, + generated_source: &path::Path, + ) -> Result<(), CompileProcessError> { debug!("Running the first pass compilation (P1++ checks)"); if problem.has_main { let output = problem.tmp_dir.join("main.x"); @@ -104,10 +140,11 @@ impl Compiler<'_> { } else { let output = problem.tmp_dir.join("main.o"); self.compile_first_pass(problem.source.as_path(), output.as_path()) - }.map_err(|error| CompileProcessError {pass: 1, error})?; + } + .map_err(|error| CompileProcessError { pass: 1, error })?; debug!("Running the second pass compilation (G++ binary)"); self.compile_and_link_second_pass(generated_source, problem.output.as_path()) - .map_err(|error| CompileProcessError {pass: 2, error}) + .map_err(|error| CompileProcessError { pass: 2, error }) } -} \ No newline at end of file +} diff --git a/src/compilation/mod.rs b/src/compilation/mod.rs index 7b7eee9..70b8121 100644 --- a/src/compilation/mod.rs +++ b/src/compilation/mod.rs @@ -1,6 +1,6 @@ mod compiler; mod template; +pub use compiler::CompilationError as Error; pub use compiler::P1XX; pub use template::generate_main; -pub use compiler::CompilationError as Error; \ No newline at end of file diff --git a/src/compilation/template.rs b/src/compilation/template.rs index a3205cb..cc4dda4 100644 --- a/src/compilation/template.rs +++ b/src/compilation/template.rs @@ -1,25 +1,31 @@ use crate::{debug, problem}; -use std::{env, io, path, fs, fmt}; use std::io::Write; +use std::{env, fmt, fs, io, path}; macro_rules! get_template { ($template:expr) => { - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/", $template)) - } + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/templates/", + $template + )) + }; } fn apply_normal_template(original: &str) -> String { - format!(get_template!("normal.cc.in"), - original=original, - stub=get_template!("stub.cc.in") + format!( + get_template!("normal.cc.in"), + original = original, + stub = get_template!("stub.cc.in") ) } fn apply_nomain_template(original: &str, main: &str) -> String { - format!(get_template!("nomain.cc.in"), - original=original, - stub=get_template!("stub.cc.in"), - main=main + format!( + get_template!("nomain.cc.in"), + original = original, + stub = get_template!("stub.cc.in"), + main = main ) } @@ -28,17 +34,21 @@ pub enum Error { ErrorCreatingFile(io::Error), CantReadSources(io::Error), CantReadDownloadedMain(io::Error), - ErrorWritingFile(io::Error) + ErrorWritingFile(io::Error), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Error::ErrorCreatingTmpFolder(e) => write!(f, "Couldn't create a temporal folder: {}", e), + Error::ErrorCreatingTmpFolder(e) => { + write!(f, "Couldn't create a temporal folder: {}", e) + } Error::ErrorCreatingFile(e) => write!(f, "Couldn't create the file: {}", e), Error::CantReadSources(e) => write!(f, "Couldn't read your sources: {}", e), - Error::CantReadDownloadedMain(e) => write!(f, "Couldn't read the downloaded sources: {}", e), - Error::ErrorWritingFile(e) => write!(f, "Unable to write the file: {}", e) + Error::CantReadDownloadedMain(e) => { + write!(f, "Couldn't read the downloaded sources: {}", e) + } + Error::ErrorWritingFile(e) => write!(f, "Unable to write the file: {}", e), } } } @@ -47,7 +57,7 @@ impl From for crate::Error { fn from(e: Error) -> Self { crate::Error { description: format!("Couldn't generate a main.cc file to compile: {}", e), - exitcode: exitcode::DATAERR + exitcode: exitcode::DATAERR, } } } @@ -58,12 +68,11 @@ pub fn generate_main(problem: &problem::Problem) -> Result debug!("Creating {}...", generated_main_path.to_string_lossy()); fs::create_dir_all(generated_main_path.parent().unwrap()) .map_err(Error::ErrorCreatingTmpFolder)?; - let mut generated_main = fs::File::create(&generated_main_path) - .map_err(Error::ErrorCreatingFile)?; + let mut generated_main = + fs::File::create(&generated_main_path).map_err(Error::ErrorCreatingFile)?; debug!("Reading {}...", problem.source.to_string_lossy()); - let original = fs::read_to_string(problem.source.as_path()) - .map_err(Error::CantReadSources)?; + let original = fs::read_to_string(problem.source.as_path()).map_err(Error::CantReadSources)?; debug!("Generating contents..."); let generated_main_contents = if problem.has_main { @@ -74,8 +83,12 @@ pub fn generate_main(problem: &problem::Problem) -> Result apply_nomain_template(original.as_str(), main.as_str()) }; - debug!("Writing contents to {}...", generated_main_path.to_string_lossy()); - generated_main.write_all(generated_main_contents.as_ref()) + debug!( + "Writing contents to {}...", + generated_main_path.to_string_lossy() + ); + generated_main + .write_all(generated_main_contents.as_ref()) .map_err(Error::ErrorWritingFile)?; Ok(generated_main_path) } @@ -87,17 +100,31 @@ mod test { #[test] fn apply_normal_template_test() { let original = "// I'M THE ORIGINAL ONE"; - let expected_output = env::current_dir().unwrap().join("tests").join("resources").join("normal.cc"); - - assert_eq!(apply_normal_template(original), fs::read_to_string(expected_output).unwrap()); + let expected_output = env::current_dir() + .unwrap() + .join("tests") + .join("resources") + .join("normal.cc"); + + assert_eq!( + apply_normal_template(original), + fs::read_to_string(expected_output).unwrap() + ); } #[test] fn apply_nomain_template_test() { let original = "// I'M THE ORIGINAL ONE"; let main = "// I'M THE MAIN ONE"; - let expected_output = env::current_dir().unwrap().join("tests").join("resources").join("nomain.cc"); - - assert_eq!(apply_nomain_template(original, main), fs::read_to_string(expected_output).unwrap()); + let expected_output = env::current_dir() + .unwrap() + .join("tests") + .join("resources") + .join("nomain.cc"); + + assert_eq!( + apply_nomain_template(original, main), + fs::read_to_string(expected_output).unwrap() + ); } -} \ No newline at end of file +} diff --git a/src/config.rs b/src/config.rs index 5e34b2d..f4e5c8f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,7 @@ +use crate::{debug, fetch, ux}; +use configparser::ini; use core::fmt; use std::{env, fs, io, path}; -use configparser::ini; -use crate::{debug, fetch, ux}; #[derive(Debug)] pub enum Error { @@ -9,17 +9,23 @@ pub enum Error { CantCreateCacheDir(io::Error), CantCreateTmpDir(io::Error), UnknownProblemDir(io::Error), - CantCreateConfigFile(io::Error) + CantCreateConfigFile(io::Error), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { match self { - Error::CantCreateConfigDir(e) => write!(f, "Unable to create a directory for configuration: {}", e), - Error::CantCreateCacheDir(e) => write!(f, "Unable to create a directory for program cache: {}", e), - Error::CantCreateTmpDir(e) => write!(f, "Unable to create a directory for temporal files: {}", e), + Error::CantCreateConfigDir(e) => { + write!(f, "Unable to create a directory for configuration: {}", e) + } + Error::CantCreateCacheDir(e) => { + write!(f, "Unable to create a directory for program cache: {}", e) + } + Error::CantCreateTmpDir(e) => { + write!(f, "Unable to create a directory for temporal files: {}", e) + } Error::UnknownProblemDir(e) => write!(f, "Can't determine the problem dir: {}", e), - Error::CantCreateConfigFile(e) => write!(f, "Can't create the config file: {}", e) + Error::CantCreateConfigFile(e) => write!(f, "Can't create the config file: {}", e), } } } @@ -28,7 +34,7 @@ impl From for crate::Error { fn from(e: Error) -> Self { crate::Error { description: format!("Error preparing the program: {}", e), - exitcode: exitcode::IOERR + exitcode: exitcode::IOERR, } } } @@ -40,19 +46,24 @@ pub struct Config { pub config_dir: path::PathBuf, pub cache_dir: path::PathBuf, pub tmp_dir: path::PathBuf, - pub credentials: Option + pub credentials: Option, } impl Config { pub fn generate() -> Result { let dirs = directories::ProjectDirs::from("com", "rdvdev2", "advocat"); let (config_dir, cache_dir) = if let Some(dirs) = dirs { - (dirs.config_dir().to_path_buf(), dirs.cache_dir().to_path_buf()) + ( + dirs.config_dir().to_path_buf(), + dirs.cache_dir().to_path_buf(), + ) } else { - (env::temp_dir().join("advocat-config"), env::temp_dir().join("advocat-cache")) + ( + env::temp_dir().join("advocat-config"), + env::temp_dir().join("advocat-cache"), + ) }; - let problem_dir = env::current_dir() - .map_err(Error::UnknownProblemDir)?; + let problem_dir = env::current_dir().map_err(Error::UnknownProblemDir)?; let mut config = Config { log_level: ux::LogLevel::Info, @@ -60,16 +71,13 @@ impl Config { config_dir, cache_dir, tmp_dir: env::temp_dir().join("advocat"), - credentials: None + credentials: None, }; debug!("Creating directories"); - fs::create_dir_all(config.config_dir.as_path()) - .map_err(Error::CantCreateConfigDir)?; - fs::create_dir_all(config.cache_dir.as_path()) - .map_err(Error::CantCreateCacheDir)?; - fs::create_dir_all(config.tmp_dir.as_path()) - .map_err(Error::CantCreateTmpDir)?; + fs::create_dir_all(config.config_dir.as_path()).map_err(Error::CantCreateConfigDir)?; + fs::create_dir_all(config.cache_dir.as_path()).map_err(Error::CantCreateCacheDir)?; + fs::create_dir_all(config.tmp_dir.as_path()).map_err(Error::CantCreateTmpDir)?; debug!("Loading config file"); config.load_config_file()?; @@ -79,7 +87,7 @@ impl Config { for arg in args { match arg.as_str() { "-d" | "--debug" => config.log_level = ux::LogLevel::Debug, - "-h" | "--help" => todo!("Add a help message"), + "-h" | "--help" => {} // TODO: Add a help message _ => {} } } @@ -91,8 +99,7 @@ impl Config { let config_file_path = self.config_dir.join("config.ini"); if !config_file_path.is_file() { - fs::File::create(config_file_path.as_path()) - .map_err(Error::CantCreateConfigFile)?; + fs::File::create(config_file_path.as_path()).map_err(Error::CantCreateConfigFile)?; } let config_file = ini::Ini::new().load(config_file_path.as_path()); @@ -103,11 +110,14 @@ impl Config { let password = auth.get("password"); if let (Some(Some(email)), Some(Some(password))) = (email, password) { - self.credentials = Some(fetch::Credentials::new(email.as_bytes(), password.as_bytes())); + self.credentials = Some(fetch::Credentials::new( + email.as_bytes(), + password.as_bytes(), + )); } } } Ok(()) } -} \ No newline at end of file +} diff --git a/src/fetch/connection_manager.rs b/src/fetch/connection_manager.rs index 6b82f27..3b8f9b6 100644 --- a/src/fetch/connection_manager.rs +++ b/src/fetch/connection_manager.rs @@ -1,13 +1,13 @@ -use std::{fmt, fs, io, path}; -use std::io::Write; -use curl::easy; -use crate::{config, debug, warning}; use crate::fetch::credentials; +use crate::{config, debug, warning}; +use curl::easy; +use std::io::Write; +use std::{fmt, fs, io, path}; pub enum Error { CurlError(curl::Error), IoError(io::Error), - AuthError + AuthError, } impl fmt::Display for Error { @@ -15,7 +15,7 @@ impl fmt::Display for Error { match self { Error::CurlError(e) => write!(f, "Connection error: {}", e), Error::IoError(e) => write!(f, "IO error: {}", e), - Error::AuthError => write!(f, "The requested content isn't publicly available") + Error::AuthError => write!(f, "The requested content isn't publicly available"), } } } @@ -33,7 +33,7 @@ impl From for Error { } pub struct ConnectionManager { - handle: easy::Easy + handle: easy::Easy, } impl ConnectionManager { @@ -69,7 +69,8 @@ impl ConnectionManager { let mut file = fs::File::create(path)?; self.handle.url(url)?; - self.handle.write_function(move |data| file.write(data).or(Ok(0)))?; + self.handle + .write_function(move |data| file.write(data).or(Ok(0)))?; self.handle.perform()?; if let Some(content_type) = self.handle.content_type()? { @@ -82,7 +83,10 @@ impl ConnectionManager { Ok(()) } - fn try_to_authenticate(&mut self, credentials: &credentials::Credentials) -> Result { + fn try_to_authenticate( + &mut self, + credentials: &credentials::Credentials, + ) -> Result { if let Some(form) = credentials.build_form() { debug!("Attempting to authenticate"); self.handle.url("https://jutge.org/")?; @@ -113,4 +117,4 @@ impl ConnectionManager { Ok(!String::from_utf8_lossy(&response).contains("Did you sign in?")) } -} \ No newline at end of file +} diff --git a/src/fetch/credentials.rs b/src/fetch/credentials.rs index be55322..95fa802 100644 --- a/src/fetch/credentials.rs +++ b/src/fetch/credentials.rs @@ -3,22 +3,28 @@ use curl::easy; #[derive(Clone)] pub struct Credentials { email: Vec, - password: Vec + password: Vec, } impl Credentials { pub fn new(email: &[u8], password: &[u8]) -> Credentials { Credentials { email: Vec::from(email), - password: Vec::from(password) + password: Vec::from(password), } } pub fn build_form(&self) -> Option { let mut form = easy::Form::new(); - form.part("email").contents(self.email.as_slice()).add().ok()?; - form.part("password").contents(self.password.as_slice()).add().ok()?; + form.part("email") + .contents(self.email.as_slice()) + .add() + .ok()?; + form.part("password") + .contents(self.password.as_slice()) + .add() + .ok()?; form.part("submit").contents(b"").add().ok()?; Some(form) @@ -34,4 +40,4 @@ mod test { let credentials = Credentials::new(b"me@example.com", b"1234"); assert!(credentials.build_form().is_some()); } -} \ No newline at end of file +} diff --git a/src/fetch/download.rs b/src/fetch/download.rs index 19bf5dc..0b6b617 100644 --- a/src/fetch/download.rs +++ b/src/fetch/download.rs @@ -1,7 +1,10 @@ -use crate::{debug, problem, ux}; use crate::fetch::{connection_manager, unzip}; +use crate::{debug, problem, ux}; -pub fn download_problem_zip(problem: &problem::Problem, connection: &mut connection_manager::ConnectionManager) -> (ux::TaskStatus, Option) { +pub fn download_problem_zip( + problem: &problem::Problem, + connection: &mut connection_manager::ConnectionManager, +) -> (ux::TaskStatus, Option) { let path = problem.work_dir.join("problem.zip"); if path.is_file() { @@ -18,7 +21,10 @@ pub fn download_problem_zip(problem: &problem::Problem, connection: &mut connect } } -pub fn download_problem_main(problem: &problem::Problem, connection: &mut connection_manager::ConnectionManager) -> (ux::TaskStatus, Option) { +pub fn download_problem_main( + problem: &problem::Problem, + connection: &mut connection_manager::ConnectionManager, +) -> (ux::TaskStatus, Option) { let path = problem.work_dir.join("main.cc"); if problem.has_main || path.is_file() { @@ -30,7 +36,7 @@ pub fn download_problem_main(problem: &problem::Problem, connection: &mut connec } else { match connection.get_file(&problem.main_cc_url, &path) { Ok(()) => (ux::TaskStatus::Done, None), - Err(e) => (ux::TaskStatus::Fail, Some(e)) + Err(e) => (ux::TaskStatus::Fail, Some(e)), } } } @@ -48,7 +54,7 @@ pub fn unzip_problem_tests(problem: &problem::Problem) -> (ux::TaskStatus, Optio } else { match unzip::unzip_samples(&zip_path, &tests_path) { Ok(()) => (ux::TaskStatus::Done, None), - Err(e) => (ux::TaskStatus::Fail, Some(e)) + Err(e) => (ux::TaskStatus::Fail, Some(e)), } } -} \ No newline at end of file +} diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index 0e03421..fc9f5da 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -1,32 +1,43 @@ -use std::fmt; use crate::{config, error, problem, ux, warning}; +use std::fmt; -mod download; mod connection_manager; mod credentials; +mod download; mod unzip; -pub use credentials::Credentials as Credentials; +pub use credentials::Credentials; -pub fn fetch_resources(problem: &problem::Problem, config: &config::Config) -> Result<(bool, bool, bool), crate::Error> { - let mut connection = connection_manager::ConnectionManager::new(config) - .map_err(|e| crate::Error { +pub fn fetch_resources( + problem: &problem::Problem, + config: &config::Config, +) -> Result<(bool, bool, bool), crate::Error> { + let mut connection = + connection_manager::ConnectionManager::new(config).map_err(|e| crate::Error { description: format!("Couldn't start the connection manager: {}", e), - exitcode: exitcode::IOERR + exitcode: exitcode::IOERR, })?; - let zip = execute_task("Downloading problem zip", || download::download_problem_zip(problem, &mut connection)); - let main_cc = execute_task("Downloading problem main.cc", || download::download_problem_main(problem, &mut connection)); - let tests = execute_task("Extracting tests", || download::unzip_problem_tests(problem)); + let zip = execute_task("Downloading problem zip", || { + download::download_problem_zip(problem, &mut connection) + }); + let main_cc = execute_task("Downloading problem main.cc", || { + download::download_problem_main(problem, &mut connection) + }); + let tests = execute_task("Extracting tests", || { + download::unzip_problem_tests(problem) + }); if !zip { warning!("Unable to retrieve tests!"); } if !main_cc { - return Err( crate::Error { - description: String::from("Unable to retrieve the main.cc file, which is required to compile your binary!"), - exitcode: exitcode::IOERR + return Err(crate::Error { + description: String::from( + "Unable to retrieve the main.cc file, which is required to compile your binary!", + ), + exitcode: exitcode::IOERR, }); } @@ -38,8 +49,8 @@ pub fn fetch_resources(problem: &problem::Problem, config: &config::Config) -> R } fn execute_task(name: &str, mut task: T) -> bool - where - T: FnMut() -> (ux::TaskStatus, Option) +where + T: FnMut() -> (ux::TaskStatus, Option), { ux::show_task_status(name, ux::TaskType::Fetch, &ux::TaskStatus::InProgress); let (status, err) = task(); @@ -49,4 +60,4 @@ fn execute_task(name: &str, mut task: T) -> bool error!("The task [{}] returned the following error: {}", name, err); } status.is_ok() -} \ No newline at end of file +} diff --git a/src/fetch/unzip.rs b/src/fetch/unzip.rs index 5c50b58..3917f2d 100644 --- a/src/fetch/unzip.rs +++ b/src/fetch/unzip.rs @@ -1,11 +1,11 @@ -use std::{fmt, fs, io, path}; use crate::debug; +use std::{fmt, fs, io, path}; pub enum Error { CantReadFile(io::Error), CantCreateFile(io::Error), CantInflateFile(io::Error), - ZipError(zip::result::ZipError) + ZipError(zip::result::ZipError), } impl fmt::Display for Error { @@ -14,18 +14,20 @@ impl fmt::Display for Error { Error::CantReadFile(e) => write!(f, "Couldn't read the file: {}", e), Error::CantCreateFile(e) => write!(f, "Couldn't create a file: {}", e), Error::CantInflateFile(e) => write!(f, "Couldn't inflate a file: {}", e), - Error::ZipError(e) => write!(f, "Zip raised an error: {:?}", e) + Error::ZipError(e) => write!(f, "Zip raised an error: {:?}", e), } } } pub fn unzip_samples(zip_path: &path::Path, output_folder: &path::Path) -> Result<(), Error> { - debug!("Unzipping {} to {}", zip_path.to_string_lossy(), output_folder.to_string_lossy()); + debug!( + "Unzipping {} to {}", + zip_path.to_string_lossy(), + output_folder.to_string_lossy() + ); - let zip_file = fs::File::open(zip_path) - .map_err(Error::CantReadFile)?; - let mut archive = zip::ZipArchive::new(zip_file) - .map_err(Error::ZipError)?; + let zip_file = fs::File::open(zip_path).map_err(Error::CantReadFile)?; + let mut archive = zip::ZipArchive::new(zip_file).map_err(Error::ZipError)?; debug!("Creating output folder {}", output_folder.to_string_lossy()); fs::create_dir_all(output_folder).map_err(Error::CantCreateFile)?; @@ -34,7 +36,7 @@ pub fn unzip_samples(zip_path: &path::Path, output_folder: &path::Path) -> Resul let mut file = archive.by_index(i).unwrap(); let outpath = match filter_samples(&file) { Some(path) => output_folder.join(path), - None => continue + None => continue, }; if file.is_dir() { @@ -67,4 +69,4 @@ fn filter_samples(zip_file: &zip::read::ZipFile) -> Option { } else { None } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index e2dfbe9..ff08179 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,20 +1,20 @@ +use crate::problem::Problem; use std::{env, fmt, ops, path}; use termion::{color, style}; -use crate::problem::Problem; -mod problem; -pub mod ux; -mod testing; mod compilation; -mod fetch; mod config; +mod fetch; +mod problem; +mod testing; +pub mod ux; #[cfg(test)] mod test_utils; pub struct Error { description: String, - exitcode: exitcode::ExitCode + exitcode: exitcode::ExitCode, } impl fmt::Display for Error { @@ -35,7 +35,12 @@ pub fn run() -> Result { let config = config::Config::generate()?; ux::set_global_log_level(config.log_level); - info!("{} v{} by {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_AUTHORS")); + info!( + "{} v{} by {}", + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION"), + env!("CARGO_PKG_AUTHORS") + ); debug!("Debug mode ON: Consider decreasing the log level to get quieter output."); debug!("Generating problem details..."); @@ -43,10 +48,14 @@ pub fn run() -> Result { debug!("Done! Problem details: {:?}", problem); let (_zip, _main_cc, tests) = fetch::fetch_resources(&problem, &config)?; - + let tests = [ - load_tests("jutge.org", problem.work_dir.join("samples").as_path(), !tests), - load_tests("user", problem.source.parent().unwrap(), false) + load_tests( + "jutge.org", + problem.work_dir.join("samples").as_path(), + !tests, + ), + load_tests("user", problem.source.parent().unwrap(), false), ]; debug!("Generating sources..."); @@ -59,12 +68,19 @@ pub fn run() -> Result { Ok(show_veredict(binary, passed_tests, total_tests)) } -fn load_tests(name: &str, dir: &path::Path, ignore_missing_dir: bool) -> Option { +fn load_tests( + name: &str, + dir: &path::Path, + ignore_missing_dir: bool, +) -> Option { debug!("Loading {} tests...", name); match testing::TestSuite::from_dir(name, dir) { Err(testing::Error::PathDoesntExist) if ignore_missing_dir => None, - Err(e) => { error!("Error loading {} tests: {}", name, e); None }, - Ok(testsuite) => Some(testsuite) + Err(e) => { + error!("Error loading {} tests: {}", name, e); + None + } + Ok(testsuite) => Some(testsuite), } } @@ -76,21 +92,28 @@ fn execute_compiler(problem: &Problem, generated_sources: &path::Path) -> bool { Ok(()) => { ux::show_task_status(TASK, ux::TaskType::Test, &ux::TaskStatus::Pass); true - }, + } Err(e) => { ux::show_task_status(TASK, ux::TaskType::Test, &ux::TaskStatus::Fail); match e.error { compilation::Error::CompilerError(stderr) => { - ux::show_task_output(format!("Compilation output (pass {})", e.pass).as_str(), &stderr); + ux::show_task_output( + format!("Compilation output (pass {})", e.pass).as_str(), + &stderr, + ); } - _ => error!("Compilation failed unexpectedly: {}", e) + _ => error!("Compilation failed unexpectedly: {}", e), } false } } } -fn run_tests(testsuites: &[Option], binary: &path::Path, skip_tests: bool) -> (usize, usize) { +fn run_tests( + testsuites: &[Option], + binary: &path::Path, + skip_tests: bool, +) -> (usize, usize) { let mut passed: usize = 0; let mut total: usize = 0; @@ -110,13 +133,24 @@ fn show_veredict(compiles: bool, passed: usize, total: usize) -> i32 { print!("{}Your code compiles but you should test it before sumbitting. Try to add some tests to the folder.", color::Fg(color::LightYellow)); exitcode::OK } else if passed != total { - print!("{}DON'T submit your code to jutge.org!", color::Fg(color::Red)); + print!( + "{}DON'T submit your code to jutge.org!", + color::Fg(color::Red) + ); exitcode::DATAERR } else { - print!("{}You're ready to submit your code to jutge.org!", color::Fg(color::Green)); + print!( + "{}You're ready to submit your code to jutge.org!", + color::Fg(color::Green) + ); exitcode::OK }; - println!(" ({} out of {} tests passed){}", passed, total, style::Reset); + println!( + " ({} out of {} tests passed){}", + passed, + total, + style::Reset + ); code } diff --git a/src/main.rs b/src/main.rs index 4b3e5c0..b60e37b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ -use std::process; use advocat::error; +use std::process; fn main() -> ! { let exitcode = match advocat::run() { diff --git a/src/problem.rs b/src/problem.rs index 8482b66..7583cb4 100644 --- a/src/problem.rs +++ b/src/problem.rs @@ -1,10 +1,10 @@ use core::fmt; -use std::path; use std::fs; use std::io; +use std::path; -use regex::Regex; use crate::{config, debug}; +use regex::Regex; #[derive(Debug)] pub struct Problem { @@ -15,7 +15,7 @@ pub struct Problem { pub tmp_dir: path::PathBuf, pub has_main: bool, pub zip_url: String, - pub main_cc_url: String + pub main_cc_url: String, } #[derive(Debug)] @@ -25,7 +25,7 @@ pub enum Error { BadPathFormat, BadId(IdError), BadSource(SourceError), - CantCreateWorkDir(io::Error) + CantCreateWorkDir(io::Error), } impl fmt::Display for Error { @@ -36,7 +36,9 @@ impl fmt::Display for Error { Error::BadPathFormat => write!(f, "The path ends in \"..\"!"), Error::BadId(e) => write!(f, "Problem id is wrong: {}", e), Error::BadSource(e) => write!(f, "Problem with main.cc: {}", e), - Error::CantCreateWorkDir(e) => write!(f, "Can't create a working dir for the program: {}", e) + Error::CantCreateWorkDir(e) => { + write!(f, "Can't create a working dir for the program: {}", e) + } } } } @@ -44,17 +46,16 @@ impl fmt::Display for Error { impl From for crate::Error { fn from(e: Error) -> Self { let exitcode = match e { - Error::NonExistingPath | - Error::NonDirectoryPath | - Error::BadPathFormat | - Error::CantCreateWorkDir(_) => exitcode::OSERR, - Error::BadId(_) | - Error::BadSource(_) => exitcode::DATAERR + Error::NonExistingPath + | Error::NonDirectoryPath + | Error::BadPathFormat + | Error::CantCreateWorkDir(_) => exitcode::OSERR, + Error::BadId(_) | Error::BadSource(_) => exitcode::DATAERR, }; crate::Error { description: format!("Couldn't detect your problem: {}", e), - exitcode + exitcode, } } } @@ -62,14 +63,14 @@ impl From for crate::Error { #[derive(PartialEq, Debug)] pub enum IdError { InvalidId, - UnsupportedType(char) + UnsupportedType(char), } impl fmt::Display for IdError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { IdError::InvalidId => write!(f, "The problem id is invalid!"), - IdError::UnsupportedType(_) => write!(f, "The problem type is unsupported!") + IdError::UnsupportedType(_) => write!(f, "The problem type is unsupported!"), } } } @@ -78,7 +79,7 @@ impl fmt::Display for IdError { pub enum SourceError { NonExistingPath, NonFilePath, - CantRead(io::Error) + CantRead(io::Error), } impl fmt::Display for SourceError { @@ -86,7 +87,7 @@ impl fmt::Display for SourceError { match self { SourceError::NonExistingPath => write!(f, "File doesn't exist!"), SourceError::NonFilePath => write!(f, "Not a file!"), - SourceError::CantRead(e) => write!(f, "Error reading contents: {}", e) + SourceError::CantRead(e) => write!(f, "Error reading contents: {}", e), } } } @@ -99,22 +100,22 @@ impl Problem { return Err(Error::NonDirectoryPath); } - let id: String = config.problem_dir.file_name() + let id: String = config + .problem_dir + .file_name() .ok_or(Error::BadPathFormat)? - .to_string_lossy().into(); - let id = verify_id(id) - .map_err(Error::BadId)?; + .to_string_lossy() + .into(); + let id = verify_id(id).map_err(Error::BadId)?; let source = config.problem_dir.join("main.cc"); let output = config.problem_dir.join("main.x"); let work_dir = config.cache_dir.join(&id); let tmp_dir = config.tmp_dir.join(&id); - fs::create_dir_all(work_dir.as_path()) - .map_err(Error::CantCreateWorkDir)?; + fs::create_dir_all(work_dir.as_path()).map_err(Error::CantCreateWorkDir)?; - let has_main = file_has_main(&source) - .map_err(Error::BadSource)?; + let has_main = file_has_main(&source).map_err(Error::BadSource)?; let problem_url = format!("https://jutge.org/problems/{}", id); let zip_url = format!("{}/zip", problem_url); @@ -128,7 +129,7 @@ impl Problem { tmp_dir, has_main, zip_url, - main_cc_url + main_cc_url, }) } } @@ -153,8 +154,7 @@ fn file_has_main(path: &path::Path) -> Result { } else if !path.is_file() { Err(SourceError::NonFilePath) } else { - let contents = fs::read_to_string(path) - .map_err(SourceError::CantRead)?; + let contents = fs::read_to_string(path).map_err(SourceError::CantRead)?; debug!("Done reading {}", path.to_string_lossy()); let re = Regex::new(r"int\s+main\s*(\s*)").unwrap(); Ok(re.is_match(&contents)) @@ -170,74 +170,101 @@ mod test { fn generate_public_problem() { let p = test_utils::get_problem("P00000_xx"); assert_eq!(p.id, "P00000_xx"); - assert_eq!(p.source, test_utils::get_tests_folder().join("problems/P00000_xx/main.cc")); - assert_eq!(p.output, test_utils::get_tests_folder().join("problems/P00000_xx/main.x")); + assert_eq!( + p.source, + test_utils::get_tests_folder().join("problems/P00000_xx/main.cc") + ); + assert_eq!( + p.output, + test_utils::get_tests_folder().join("problems/P00000_xx/main.x") + ); assert!(!p.work_dir.to_string_lossy().is_empty()); assert!(p.has_main); assert_eq!(p.zip_url, "https://jutge.org/problems/P00000_xx/zip"); - assert_eq!(p.main_cc_url, "https://jutge.org/problems/P00000_xx/main/cc"); // Irrelevant, but still tested + assert_eq!( + p.main_cc_url, + "https://jutge.org/problems/P00000_xx/main/cc" + ); // Irrelevant, but still tested } #[test] fn generate_public_nomain_problem() { let p = test_utils::get_problem("P00001_xx"); assert_eq!(p.id, "P00001_xx"); - assert_eq!(p.source, test_utils::get_tests_folder().join("problems/P00001_xx/main.cc")); - assert_eq!(p.output, test_utils::get_tests_folder().join("problems/P00001_xx/main.x")); + assert_eq!( + p.source, + test_utils::get_tests_folder().join("problems/P00001_xx/main.cc") + ); + assert_eq!( + p.output, + test_utils::get_tests_folder().join("problems/P00001_xx/main.x") + ); assert!(!p.work_dir.to_string_lossy().is_empty()); assert!(!p.has_main); assert_eq!(p.zip_url, "https://jutge.org/problems/P00001_xx/zip"); - assert_eq!(p.main_cc_url, "https://jutge.org/problems/P00001_xx/main/cc"); + assert_eq!( + p.main_cc_url, + "https://jutge.org/problems/P00001_xx/main/cc" + ); } #[test] fn generate_private_nomain_problem() { let p = test_utils::get_problem("X00000_xx"); assert_eq!(p.id, "X00000_xx"); - assert_eq!(p.source, test_utils::get_tests_folder().join("problems/X00000_xx/main.cc")); - assert_eq!(p.output, test_utils::get_tests_folder().join("problems/X00000_xx/main.x")); + assert_eq!( + p.source, + test_utils::get_tests_folder().join("problems/X00000_xx/main.cc") + ); + assert_eq!( + p.output, + test_utils::get_tests_folder().join("problems/X00000_xx/main.x") + ); assert!(!p.work_dir.to_string_lossy().is_empty()); assert!(!p.has_main); assert_eq!(p.zip_url, "https://jutge.org/problems/X00000_xx/zip"); - assert_eq!(p.main_cc_url, "https://jutge.org/problems/X00000_xx/main/cc"); + assert_eq!( + p.main_cc_url, + "https://jutge.org/problems/X00000_xx/main/cc" + ); } #[test] fn generate_problem_non_existing() { match test_utils::try_get_problem("foobar") { - Err(Error::NonExistingPath) => {}, - _ => panic!() + Err(Error::NonExistingPath) => {} + _ => panic!(), } } #[test] fn generate_problem_non_directory() { match test_utils::try_get_problem("P00000_xx/main.cc") { - Err(Error::NonDirectoryPath) => {}, - _ => panic!() + Err(Error::NonDirectoryPath) => {} + _ => panic!(), } } #[test] fn generate_problem_bad_format() { match test_utils::try_get_problem("..") { - Err(Error::BadPathFormat) => {}, - _ => panic!() + Err(Error::BadPathFormat) => {} + _ => panic!(), } } #[test] fn generate_problem_bad_id() { match test_utils::try_get_problem("") { - Err(Error::BadId(_)) => {}, - _ => panic!() + Err(Error::BadId(_)) => {} + _ => panic!(), } } #[test] fn generate_problem_bad_main() { match test_utils::try_get_problem("P99999_xx") { - Err(Error::BadSource(_)) => {}, - _ => panic!() + Err(Error::BadSource(_)) => {} + _ => panic!(), } } @@ -284,7 +311,7 @@ mod test { fn has_main_non_existent() { match test_has_main("foobar") { Err(SourceError::NonExistingPath) => {} - _ => panic!() + _ => panic!(), } } @@ -292,7 +319,7 @@ mod test { fn has_main_non_file() { match test_has_main("problems") { Err(SourceError::NonFilePath) => {} - _ => panic!() + _ => panic!(), } } -} \ No newline at end of file +} diff --git a/src/test_utils.rs b/src/test_utils.rs index 70ef017..9a17d51 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -1,17 +1,20 @@ -use std::{env, fs, ops}; -use std::path; -use crate::{config, problem}; use crate::config::Config; +use crate::{config, problem}; +use std::path; +use std::{env, fs, ops}; static mut CONFIG: Option = None; pub struct SelfCleaningTmp { - dir: path::PathBuf + dir: path::PathBuf, } impl SelfCleaningTmp { pub fn new(module: &str, test_name: &str) -> SelfCleaningTmp { - let dir = env::temp_dir().join("advocat-test").join(module).join(test_name); + let dir = env::temp_dir() + .join("advocat-test") + .join(module) + .join(test_name); fs::create_dir_all(&dir).expect("Unable to get a temporal directory"); SelfCleaningTmp { dir } } @@ -52,4 +55,4 @@ pub fn try_get_problem(id: &str) -> Result { pub fn get_problem(id: &str) -> problem::Problem { try_get_problem(id).expect("Couldn't generate a problem struct for the test") -} \ No newline at end of file +} diff --git a/src/testing/diff_display.rs b/src/testing/diff_display.rs index 6b2c997..fb114b2 100644 --- a/src/testing/diff_display.rs +++ b/src/testing/diff_display.rs @@ -1,17 +1,27 @@ -use termion::color; use crate::ux; +use termion::color; pub struct DiffDisplay { text: String, side_width: usize, left_color: &'static dyn color::Color, - right_color: &'static dyn color::Color + right_color: &'static dyn color::Color, } impl DiffDisplay { - pub fn new(left_title: &str, right_title: &str, left_color: &'static dyn color::Color, right_color: &'static dyn color::Color) -> Self { + pub fn new( + left_title: &str, + right_title: &str, + left_color: &'static dyn color::Color, + right_color: &'static dyn color::Color, + ) -> Self { let side_width = ((ux::get_terminal_width() - 7) / 2) as usize; - let mut dd = DiffDisplay { text: String::new(), side_width, left_color, right_color }; + let mut dd = DiffDisplay { + text: String::new(), + side_width, + left_color, + right_color, + }; dd.draw_horizontal_line('╭', '┬', '╮'); dd.write_centered_row(left_title, right_title); dd.draw_horizontal_line('├', '┼', '┤'); @@ -19,8 +29,18 @@ impl DiffDisplay { } fn draw_horizontal_line(&mut self, left: char, mid: char, right: char) { - self.text.push_str(format!("{l}─{:─^w$}─{m}─{:─^w$}─{r}\n", "", "", - l = left, m = mid, r = right, w = self.side_width).as_str()); + self.text.push_str( + format!( + "{l}─{:─^w$}─{m}─{:─^w$}─{r}\n", + "", + "", + l = left, + m = mid, + r = right, + w = self.side_width + ) + .as_str(), + ); } pub fn end(&mut self) { @@ -30,19 +50,40 @@ impl DiffDisplay { fn write_centered_row(&mut self, left: &str, right: &str) { let left = self.trim_line(left); let right = self.trim_line(right); - self.text.push_str(format!("│ {l:^w$} │ {r:^w$} │\n", - l = left, r = right, w = self.side_width).as_str()); + self.text.push_str( + format!( + "│ {l:^w$} │ {r:^w$} │\n", + l = left, + r = right, + w = self.side_width + ) + .as_str(), + ); } - fn write_row(&mut self, left: &str, mid: char, right: &str, left_color: &dyn color::Color, right_color: &dyn color::Color) { + fn write_row( + &mut self, + left: &str, + mid: char, + right: &str, + left_color: &dyn color::Color, + right_color: &dyn color::Color, + ) { let left = self.trim_line(left); let right = self.trim_line(right); - self.text.push_str(format!("│ {lc}{l:w$}{nc} {m} {rc}{r:w$}{nc} │\n", - l = left, m = mid, r = right, - lc = color::Fg(left_color), - rc = color::Fg(right_color), - nc = color::Fg(color::Reset), - w = self.side_width).as_str()); + self.text.push_str( + format!( + "│ {lc}{l:w$}{nc} {m} {rc}{r:w$}{nc} │\n", + l = left, + m = mid, + r = right, + lc = color::Fg(left_color), + rc = color::Fg(right_color), + nc = color::Fg(color::Reset), + w = self.side_width + ) + .as_str(), + ); } pub fn write_left(&mut self, left: &str) { @@ -61,12 +102,12 @@ impl DiffDisplay { if line.len() <= self.side_width { line.to_owned() } else { - let line = &line[0..self.side_width-3]; + let line = &line[0..self.side_width - 3]; line.to_owned() + "..." } } - + pub fn build(self) -> String { self.text } -} \ No newline at end of file +} diff --git a/src/testing/mod.rs b/src/testing/mod.rs index be39cc8..32f1035 100644 --- a/src/testing/mod.rs +++ b/src/testing/mod.rs @@ -1,6 +1,6 @@ +mod diff_display; mod test; mod testsuite; -mod diff_display; +pub use testsuite::Error; pub use testsuite::TestSuite; -pub use testsuite::Error as Error; \ No newline at end of file diff --git a/src/testing/test.rs b/src/testing/test.rs index 4eb35be..3a536f8 100644 --- a/src/testing/test.rs +++ b/src/testing/test.rs @@ -1,25 +1,29 @@ -use std::{fs, io, path, process}; +use crate::testing::diff_display; +use crate::{debug, ux}; use std::io::Write; +use std::{fs, io, path, process}; use termion::color; -use crate::{debug, ux}; -use crate::testing::diff_display; pub struct Test { inputs: String, - outputs: String + outputs: String, } pub struct TestResult { pub status: ux::TaskStatus, pub error: Option, - pub diff: String + pub diff: String, } impl Test { pub fn from_files(input_file: &path::Path, output_file: &path::Path) -> Option { if let Ok(inputs) = fs::read_to_string(input_file) { if let Ok(outputs) = fs::read_to_string(output_file) { - debug!("Found test: {} => {}", input_file.to_string_lossy(), output_file.to_string_lossy()); + debug!( + "Found test: {} => {}", + input_file.to_string_lossy(), + output_file.to_string_lossy() + ); return Some(Test { inputs, outputs }); } } @@ -36,21 +40,39 @@ impl Test { let mut process = match process { Ok(p) => p, - Err(e) => return TestResult { status: ux::TaskStatus::Fail, error: Some(e), diff: String::new() } + Err(e) => { + return TestResult { + status: ux::TaskStatus::Fail, + error: Some(e), + diff: String::new(), + } + } }; debug!("Sending inputs"); match process.stdin.take() { - Some(mut stdin) => if let Err(e) = stdin.write(self.inputs.as_bytes()) { - return TestResult { status: ux::TaskStatus::Fail, error: Some(e), diff: String::new() } - }, - None => debug!("The input pipe was closed by the program!") + Some(mut stdin) => { + if let Err(e) = stdin.write(self.inputs.as_bytes()) { + return TestResult { + status: ux::TaskStatus::Fail, + error: Some(e), + diff: String::new(), + }; + } + } + None => debug!("The input pipe was closed by the program!"), }; debug!("Waiting for the program to end"); let output = match process.wait_with_output() { Ok(o) => o, - Err(e) => return TestResult { status: ux::TaskStatus::Fail, error: Some(e), diff: String::new() } + Err(e) => { + return TestResult { + status: ux::TaskStatus::Fail, + error: Some(e), + diff: String::new(), + } + } }; debug!("Capturing output"); @@ -63,15 +85,23 @@ impl Test { } else { ux::TaskStatus::Fail }; - TestResult { status, error: None, diff } + TestResult { + status, + error: None, + diff, + } } } fn parse_diff(diff: Vec>) -> (bool, String) { debug!("Parsing diff"); let mut pass = true; - let mut dd = - diff_display::DiffDisplay::new("Expected output", "Your output", &color::Green, &color::Red); + let mut dd = diff_display::DiffDisplay::new( + "Expected output", + "Your output", + &color::Green, + &color::Red, + ); for line in diff { match line { @@ -91,4 +121,4 @@ fn parse_diff(diff: Vec>) -> (bool, String) { dd.end(); (pass, dd.build()) -} \ No newline at end of file +} diff --git a/src/testing/testsuite.rs b/src/testing/testsuite.rs index 2510c37..375f8d7 100644 --- a/src/testing/testsuite.rs +++ b/src/testing/testsuite.rs @@ -1,15 +1,15 @@ +use crate::testing::test; +use crate::{error, ux}; use std::fmt; -use std::path; use std::fs; use std::io; +use std::path; use termion::style; -use crate::{error, ux}; -use crate::testing::test; pub enum Error { PathDoesntExist, PathIsNotADir, - CantReadDir(io::Error) + CantReadDir(io::Error), } impl fmt::Display for Error { @@ -17,14 +17,14 @@ impl fmt::Display for Error { match self { Error::PathDoesntExist => write!(f, "The tests path doesn't exist!"), Error::PathIsNotADir => write!(f, "The tests path isn't a directory!"), - Error::CantReadDir(e) => write!(f, "Couldn't read the tests directory: {}", e) + Error::CantReadDir(e) => write!(f, "Couldn't read the tests directory: {}", e), } } } pub struct TestSuite { name: String, - tests: Vec + tests: Vec, } impl TestSuite { @@ -34,18 +34,23 @@ impl TestSuite { } else if !dir.is_dir() { Err(Error::PathIsNotADir) } else { - let mut suite = TestSuite { name: name.to_owned(), tests: Vec::new() }; + let mut suite = TestSuite { + name: name.to_owned(), + tests: Vec::new(), + }; let mut input_files: Vec = fs::read_dir(dir) .map_err(Error::CantReadDir)? .flatten() .filter(|f| f.path().extension().unwrap_or_else(|| "".as_ref()) == "inp") .collect(); input_files.sort_by_key(|a| a.file_name()); - input_files.iter() + input_files + .iter() .map(|inp| (inp.path(), inp.path().with_extension("cor"))) - .for_each(|(inp, out)| + .for_each(|(inp, out)| { if let Some(test) = test::Test::from_files(inp.as_path(), out.as_path()) { suite.tests.push(test); + } }); Ok(suite) @@ -55,7 +60,7 @@ impl TestSuite { pub fn run(&self, binary: &path::Path, should_skip: bool) -> usize { let mut pass_count: usize = 0; for (i, test) in self.tests.iter().enumerate() { - let test_name = format!("{} test {}", self.name, i+1); + let test_name = format!("{} test {}", self.name, i + 1); if should_skip { ux::show_task_status(&test_name, ux::TaskType::Test, &ux::TaskStatus::SkipBad); } else { @@ -67,7 +72,10 @@ impl TestSuite { } else if result.status.is_ok() { pass_count += 1; } else { - ux::show_task_output("Test diff", format!("{}{}", style::Reset, result.diff).as_str()); + ux::show_task_output( + "Test diff", + format!("{}{}", style::Reset, result.diff).as_str(), + ); } } } @@ -78,4 +86,4 @@ impl TestSuite { pub fn count(&self) -> usize { self.tests.len() } -} \ No newline at end of file +} diff --git a/src/ux.rs b/src/ux.rs index 6046c17..59e230c 100644 --- a/src/ux.rs +++ b/src/ux.rs @@ -3,20 +3,21 @@ use std::io::Write; use termion::{color, style}; #[derive(PartialEq, PartialOrd, Clone, Copy)] -pub enum LogLevel { Debug, Info, Warning, Error } +pub enum LogLevel { + Debug, + Info, + Warning, + Error, +} static mut GLOBAL_LOG_LEVEL: LogLevel = LogLevel::Info; pub fn set_global_log_level(level: LogLevel) { - unsafe { - GLOBAL_LOG_LEVEL = level - } + unsafe { GLOBAL_LOG_LEVEL = level } } pub fn get_global_log_level() -> LogLevel { - unsafe { - GLOBAL_LOG_LEVEL - } + unsafe { GLOBAL_LOG_LEVEL } } pub fn print_message(level: LogLevel, msg: String) { @@ -24,8 +25,22 @@ pub fn print_message(level: LogLevel, msg: String) { x if x < get_global_log_level() => (), LogLevel::Debug => eprintln!(":: {}{}{}", style::Italic, msg, style::Reset), LogLevel::Info => println!("{}", msg), - LogLevel::Warning => eprintln!("{}{}WARNING: {}{}{}", color::Fg(color::LightYellow), style::Bold, msg, style::NoBold, style::Reset), - LogLevel::Error => eprintln!("{}{}ERROR: {}{}{}", color::Fg(color::Red), style::Bold, msg, style::NoBold, style::Reset) + LogLevel::Warning => eprintln!( + "{}{}WARNING: {}{}{}", + color::Fg(color::LightYellow), + style::Bold, + msg, + style::NoBold, + style::Reset + ), + LogLevel::Error => eprintln!( + "{}{}ERROR: {}{}{}", + color::Fg(color::Red), + style::Bold, + msg, + style::NoBold, + style::Reset + ), } } @@ -54,21 +69,34 @@ macro_rules! error { ($($msg:tt)*) => ($crate::ux::print_message($crate::ux::LogLevel::Error, format!($($msg)*))) } -pub enum TaskType { Fetch, Test } +pub enum TaskType { + Fetch, + Test, +} #[derive(PartialEq, Debug)] -pub enum TaskStatus { Done, Pass, SkipGood, SkipBad, Fail, InProgress } +pub enum TaskStatus { + Done, + Pass, + SkipGood, + SkipBad, + Fail, + InProgress, +} impl TaskStatus { pub fn is_ok(&self) -> bool { - matches!(self, TaskStatus::Done | TaskStatus::Pass | TaskStatus::SkipGood) + matches!( + self, + TaskStatus::Done | TaskStatus::Pass | TaskStatus::SkipGood + ) } } pub fn show_task_status(name: &str, task_type: TaskType, task_status: &TaskStatus) { let name = match task_type { TaskType::Fetch => name.to_owned() + "... ", - TaskType::Test => name.to_uppercase() + ": " + TaskType::Test => name.to_uppercase() + ": ", }; print!("{}{}", color::Fg(color::Yellow), name); @@ -97,6 +125,6 @@ pub fn show_task_output(title: &str, contents: &str) { pub fn get_terminal_width() -> u16 { match terminal_size::terminal_size() { None => 100, - Some((width, _)) => width.0 + Some((width, _)) => width.0, } -} \ No newline at end of file +}