diff --git a/Cargo.toml b/Cargo.toml index e6a350c2..24b899c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,11 @@ [workspace] resolver = "2" -members = ["crates/tuono", "crates/tuono_lib", "crates/tuono_lib_macros"] +members = [ + "crates/tuono", + "crates/tuono_internal", + "crates/tuono_lib", + "crates/tuono_lib_macros" +] exclude = [ "apps/documentation", "examples/with-mdx", diff --git a/crates/tuono_internal/Cargo.toml b/crates/tuono_internal/Cargo.toml new file mode 100644 index 00000000..280cef19 --- /dev/null +++ b/crates/tuono_internal/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "tuono_internal" +version = "0.17.3" +edition = "2021" +authors = ["V. Ageno "] +description = "Superfast React fullstack framework" +homepage = "https://tuono.dev" +keywords = [ "react", "typescript", "fullstack", "web", "ssr"] +repository = "https://github.com/tuono-labs/tuono" +readme = "../../README.md" +license-file = "../../LICENSE.md" +categories = ["web-programming"] +include = [ + "src/*.rs", + "Cargo.toml" +] + + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.137" + +[dev-dependencies] +fs_extra = "1.3.0" +tempfile = "3.14.0" +assert_cmd = "2.0.16" +serial_test = "0.10.0" diff --git a/crates/tuono_internal/README.md b/crates/tuono_internal/README.md new file mode 100644 index 00000000..0d24d8d1 --- /dev/null +++ b/crates/tuono_internal/README.md @@ -0,0 +1,4 @@ +# tuono_internal + +This crate is a collection of internal utilities for the Tuono project. It is +not intended for use outside of the project. diff --git a/crates/tuono_internal/src/config.rs b/crates/tuono_internal/src/config.rs new file mode 100644 index 00000000..3340f9fc --- /dev/null +++ b/crates/tuono_internal/src/config.rs @@ -0,0 +1,24 @@ +use serde::Deserialize; +use std::fs::read_to_string; +use std::io; +use std::path::PathBuf; + +#[derive(Deserialize)] +pub struct ServerConfig { + pub host: String, + pub port: u16, +} + +#[derive(Deserialize)] +pub struct Config { + pub server: ServerConfig, +} + +impl Config { + pub fn get() -> io::Result { + let config_file = read_to_string(PathBuf::from_iter([".tuono", "config", "config.json"]))?; + + serde_json::from_str(&config_file) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + } +} diff --git a/crates/tuono_internal/src/lib.rs b/crates/tuono_internal/src/lib.rs new file mode 100644 index 00000000..ef68c369 --- /dev/null +++ b/crates/tuono_internal/src/lib.rs @@ -0,0 +1 @@ +pub mod config; diff --git a/crates/tuono_internal/tests/config.rs b/crates/tuono_internal/tests/config.rs new file mode 100644 index 00000000..35e668e1 --- /dev/null +++ b/crates/tuono_internal/tests/config.rs @@ -0,0 +1,50 @@ +mod utils; +use serial_test::serial; +use std::io::ErrorKind; +use tuono_internal::config::Config; +use utils::TempTuonoProject; + +#[test] +#[serial] +fn should_correctly_read_the_config_file() { + let folder = TempTuonoProject::new(); + + folder.add_file_with_content( + "./.tuono/config/config.json", + r#"{ "server": {"host": "localhost", "port": 3000}}"#, + ); + + let config = Config::get(); + + assert!(config.is_ok()); + + let config = config.unwrap(); + assert_eq!(config.server.host, "localhost"); + assert_eq!(config.server.port, 3000); +} + +#[test] +#[serial] +fn should_fail_if_the_file_does_not_exist() { + TempTuonoProject::new(); + + let config = Config::get(); + + assert!(config.is_err()); + + assert_eq!(config.err().unwrap().kind(), ErrorKind::NotFound); +} + +#[test] +#[serial] +fn should_fail_if_the_file_is_not_json() { + let folder = TempTuonoProject::new(); + + folder.add_file_with_content("./.tuono/config/config.json", "INVALID JSON"); + + let config = Config::get(); + + assert!(config.is_err()); + + assert_eq!(config.err().unwrap().kind(), ErrorKind::InvalidData); +} diff --git a/crates/tuono_internal/tests/utils.rs b/crates/tuono_internal/tests/utils.rs new file mode 100644 index 00000000..da591559 --- /dev/null +++ b/crates/tuono_internal/tests/utils.rs @@ -0,0 +1,49 @@ +use fs_extra::dir::create_all; +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +use tempfile::{tempdir, TempDir}; + +#[derive(Debug)] +pub struct TempTuonoProject { + original_dir: PathBuf, + #[allow(dead_code)] + // Required for dropping the temp_dir when this struct drops + temp_dir: TempDir, +} + +impl TempTuonoProject { + pub fn new() -> Self { + let original_dir = env::current_dir().expect("Failed to read current_dir"); + let temp_dir = tempdir().expect("Failed to create temp_dir"); + + env::set_current_dir(temp_dir.path()).expect("Failed to change current dir into temp_dir"); + + TempTuonoProject { + original_dir, + temp_dir, + } + } + + pub fn add_file_with_content<'a>(&self, path: &'a str, content: &'a str) { + let path = PathBuf::from(path); + create_all( + path.parent().expect("File path does not have any parent"), + false, + ) + .expect("Failed to create parent file directories"); + + let mut file = File::create(path).expect("Failed to create the file"); + file.write_all(content.as_bytes()) + .expect("Failed to write into the file"); + } +} + +impl Drop for TempTuonoProject { + fn drop(&mut self) { + // Set back the current dir in the previous state + env::set_current_dir(self.original_dir.to_owned()) + .expect("Failed to restore the original directory."); + } +}