From 62a36bb73ddfd841a4f09e07b33457bf33ae64da Mon Sep 17 00:00:00 2001 From: "Dotan J. Nahum" Date: Wed, 13 Nov 2024 23:37:20 +0200 Subject: [PATCH] lint --- loco-new/src/bin/main.rs | 11 +- loco-new/src/generator/executer/filesystem.rs | 1 + loco-new/src/generator/executer/mod.rs | 5 +- loco-new/src/generator/mod.rs | 9 +- loco-new/src/generator/template.rs | 13 +- loco-new/src/lib.rs | 1 - loco-new/src/settings.rs | 30 +-- loco-new/src/wizard.rs | 212 ++++++++++++++++-- loco-new/src/wizard_opts.rs | 173 -------------- loco-new/tests/assertion/string.rs | 7 +- loco-new/tests/assertion/toml.rs | 27 ++- loco-new/tests/assertion/yaml.rs | 53 +++-- loco-new/tests/templates/asset.rs | 7 +- loco-new/tests/templates/background.rs | 7 +- loco-new/tests/templates/db.rs | 7 +- loco-new/tests/templates/module_name.rs | 7 +- 16 files changed, 294 insertions(+), 276 deletions(-) delete mode 100644 loco-new/src/wizard_opts.rs diff --git a/loco-new/src/bin/main.rs b/loco-new/src/bin/main.rs index be2c534bb..1bc78449e 100644 --- a/loco-new/src/bin/main.rs +++ b/loco-new/src/bin/main.rs @@ -10,7 +10,7 @@ use duct::cmd; use loco::{ generator::{executer, extract_default_template, Generator}, settings::Settings, - wizard, wizard_opts, Result, + wizard, Result, }; use tracing::level_filters::LevelFilter; use tracing_subscriber::EnvFilter; @@ -41,15 +41,15 @@ enum Commands { /// DB Provider #[arg(long)] - db: Option, + db: Option, /// Background worker configuration #[arg(long)] - bg: Option, + bg: Option, /// Assets serving configuration #[arg(long)] - assets: Option, + assets: Option, /// Allows create loco starter in target git repository #[arg(short, long)] @@ -57,6 +57,7 @@ enum Commands { }, } +#[allow(clippy::cognitive_complexity)] fn main() -> Result<()> { let cli = Cli::parse(); tracing_subscriber::fmt() @@ -94,7 +95,7 @@ fn main() -> Result<()> { tracing::debug!(dir = %to.display(), "creating application directory"); std::fs::create_dir_all(&to)?; - let args = wizard_opts::ArgsPlaceholder { db, bg, assets }; + let args = wizard::ArgsPlaceholder { db, bg, assets }; let user_selection = wizard::start(&args)?; let generator_tmp_folder = extract_default_template()?; diff --git a/loco-new/src/generator/executer/filesystem.rs b/loco-new/src/generator/executer/filesystem.rs index 1f7c744e8..0c6411b02 100644 --- a/loco-new/src/generator/executer/filesystem.rs +++ b/loco-new/src/generator/executer/filesystem.rs @@ -136,6 +136,7 @@ impl Executer for FileSystem { self.render_and_rename_template_file(&copied_path, settings) } + #[allow(clippy::cognitive_complexity)] fn copy_template_dir(&self, directory_path: &Path, settings: &Settings) -> super::Result<()> { let source_path = self.source_dir.join(directory_path); let target_path = self.target_dir.join(directory_path); diff --git a/loco-new/src/generator/executer/mod.rs b/loco-new/src/generator/executer/mod.rs index f6da8975e..fdd8318b4 100644 --- a/loco-new/src/generator/executer/mod.rs +++ b/loco-new/src/generator/executer/mod.rs @@ -1,7 +1,4 @@ -//! This module defines error handling and the [`Executer`] trait for file and -//! template operations within the application. It includes custom error types -//! for handling different failure scenarios, including file system and template -//! processing errors. +//! This module defines error handling and the [`Executer`] trait use crate::settings::Settings; mod filesystem; diff --git a/loco-new/src/generator/mod.rs b/loco-new/src/generator/mod.rs index 16713f939..3fde04784 100644 --- a/loco-new/src/generator/mod.rs +++ b/loco-new/src/generator/mod.rs @@ -1,7 +1,5 @@ //! This module defines the `Generator` struct, which is responsible for -//! executing scripted commands for file and template operations. It integrates -//! with an executor to perform file manipulations and uses a scripting engine -//! to run custom scripts based on application settings. +//! executing scripted commands use std::path::{Path, PathBuf}; pub mod executer; @@ -112,6 +110,11 @@ impl Generator { Ok(()) } + /// Creates a single file in the specified path. + /// + /// # Errors + /// + /// Returns an error if the file copy operation fails. pub fn create_file( &mut self, path: &str, diff --git a/loco-new/src/generator/template.rs b/loco-new/src/generator/template.rs index d8d1b78ee..1c5afb309 100644 --- a/loco-new/src/generator/template.rs +++ b/loco-new/src/generator/template.rs @@ -1,16 +1,16 @@ //! This module defines a `Template` struct for handling template files. -//! It includes methods to identify template files, render templates -//! with injected settings, and modify file paths by stripping specific extensions. -use crate::settings::Settings; -use rand::{distributions::Alphanumeric, rngs::StdRng, Rng, SeedableRng}; -use std::sync::{Arc, Mutex}; use std::{ collections::HashMap, path::{Path, PathBuf}, + sync::{Arc, Mutex}, }; + +use rand::{distributions::Alphanumeric, rngs::StdRng, Rng, SeedableRng}; use tera::{Context, Tera}; +use crate::settings::Settings; + const TEMPLATE_EXTENSION: &str = "t"; fn generate_random_string(rng: &mut R, length: u64) -> String { @@ -44,7 +44,8 @@ impl Template { rng: Arc::new(Mutex::new(rng)), } } - /// Checks if the provided file path has a ".t" extension, marking it as a template. + /// Checks if the provided file path has a ".t" extension, marking it as a + /// template. /// /// Returns `true` if the file has a ".t" extension, otherwise `false`. #[must_use] diff --git a/loco-new/src/lib.rs b/loco-new/src/lib.rs index ae8cc39e8..4cf08ce39 100644 --- a/loco-new/src/lib.rs +++ b/loco-new/src/lib.rs @@ -1,7 +1,6 @@ pub mod generator; pub mod settings; pub mod wizard; -pub mod wizard_opts; pub type Result = std::result::Result; diff --git a/loco-new/src/settings.rs b/loco-new/src/settings.rs index 83e1f5aff..1e6649162 100644 --- a/loco-new/src/settings.rs +++ b/loco-new/src/settings.rs @@ -6,7 +6,10 @@ use heck::ToSnakeCase; use rhai::{CustomType, TypeBuilder}; use serde::{Deserialize, Serialize}; -use crate::{wizard, wizard_opts, LOCO_VERSION}; +use crate::{ + wizard::{self, AssetsOption, BackgroundOption, DBOption}, + LOCO_VERSION, +}; /// Represents general application settings. #[derive(Serialize, Deserialize, Clone, Debug, CustomType)] @@ -24,10 +27,10 @@ pub struct Settings { pub loco_version_text: String, } -impl From for Option { - fn from(db_option: wizard_opts::DBOption) -> Self { +impl From for Option { + fn from(db_option: DBOption) -> Self { match db_option { - wizard_opts::DBOption::None => None, + DBOption::None => None, _ => Some(Db { kind: db_option.clone(), endpoint: db_option.endpoint_config().to_string(), @@ -36,19 +39,19 @@ impl From for Option { } } -impl From for Option { - fn from(bg: wizard_opts::BackgroundOption) -> Self { +impl From for Option { + fn from(bg: BackgroundOption) -> Self { match bg { - wizard_opts::BackgroundOption::None => None, + BackgroundOption::None => None, _ => Some(Background { kind: bg }), } } } -impl From for Option { - fn from(asset: wizard_opts::AssetsOption) -> Self { +impl From for Option { + fn from(asset: AssetsOption) -> Self { match asset { - wizard_opts::AssetsOption::None => None, + AssetsOption::None => None, _ => Some(Asset { kind: asset }), } } @@ -89,6 +92,7 @@ impl Settings { } impl Default for Settings { fn default() -> Self { + #[allow(clippy::default_trait_access)] Self { package_name: Default::default(), module_name: Default::default(), @@ -118,20 +122,20 @@ fn get_loco_version_text() -> String { /// Database configuration settings. #[derive(Serialize, Deserialize, Clone, Debug, Default, CustomType)] pub struct Db { - pub kind: wizard_opts::DBOption, + pub kind: DBOption, pub endpoint: String, } /// Background processing configuration. #[derive(Serialize, Deserialize, Clone, Debug, Default, CustomType)] pub struct Background { - pub kind: wizard_opts::BackgroundOption, + pub kind: BackgroundOption, } /// Asset configuration settings. #[derive(Serialize, Deserialize, Clone, Debug, Default, CustomType)] pub struct Asset { - pub kind: wizard_opts::AssetsOption, + pub kind: AssetsOption, } #[derive(Serialize, Deserialize, Clone, Debug, Default, CustomType)] diff --git a/loco-new/src/wizard.rs b/loco-new/src/wizard.rs index 3b3c52461..7aecc5c77 100644 --- a/loco-new/src/wizard.rs +++ b/loco-new/src/wizard.rs @@ -1,19 +1,188 @@ //! This module provides interactive utilities for setting up application //! configurations based on user input. +use clap::ValueEnum; +use colored::Colorize; use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select}; -use strum::IntoEnumIterator; +use serde::{Deserialize, Serialize}; +use strum::{Display, EnumIter, IntoEnumIterator}; -use crate::{ - wizard_opts::{self, AssetsOption, BackgroundOption, DBOption}, - Error, -}; +use crate::Error; + +#[derive( + Debug, Clone, Deserialize, Serialize, EnumIter, Display, Default, PartialEq, Eq, ValueEnum, +)] +pub enum Template { + #[default] + #[strum(to_string = "Saas App with server side rendering")] + SaasServerSideRendering, + #[strum(to_string = "Saas App with client side rendering")] + SaasClientSideRendering, + #[strum(to_string = "Rest API (with DB and user auth)")] + RestApi, + #[strum(to_string = "lightweight-service (minimal, only controllers and views)")] + Lightweight, + #[strum(to_string = "Advanced")] + Advanced, +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +pub enum OptionsList { + #[serde(rename = "db")] + DB, + #[serde(rename = "bg")] + Background, + #[serde(rename = "assets")] + Assets, +} + +#[derive( + Debug, Clone, Deserialize, Serialize, EnumIter, Display, Default, PartialEq, Eq, ValueEnum, +)] +pub enum DBOption { + #[default] + #[serde(rename = "sqlite")] + Sqlite, + #[serde(rename = "pg")] + Postgres, + #[serde(rename = "none")] + None, +} + +impl DBOption { + #[must_use] + pub const fn enable(&self) -> bool { + !matches!(self, Self::None) + } + + #[must_use] + pub fn user_message(&self) -> Option { + match self { + Self::Postgres => Some(format!( + "{}: You've selected `{}` as your DB provider (you should have a postgres \ + instance to connect to)", + "database".underline(), + "postgres".yellow() + )), + Self::Sqlite | Self::None => None, + } + } + + #[must_use] + pub const fn endpoint_config(&self) -> &str { + match self { + Self::Sqlite => "sqlite://loco_app.sqlite?mode=rwc", + Self::Postgres => "postgres://loco:loco@localhost:5432/loco_app", + Self::None => "", + } + } +} + +#[derive( + Debug, Clone, Deserialize, Serialize, EnumIter, Display, Default, PartialEq, Eq, ValueEnum, +)] +pub enum BackgroundOption { + #[default] + #[strum(to_string = "Async (in-process tokio async tasks)")] + #[serde(rename = "BackgroundAsync")] + Async, + #[strum(to_string = "Queue (standalone workers using Redis)")] + #[serde(rename = "BackgroundQueue")] + Queue, + #[strum(to_string = "Blocking (run tasks in foreground)")] + #[serde(rename = "ForegroundBlocking")] + Blocking, + #[strum(to_string = "None")] + #[serde(rename = "none")] + None, +} + +impl BackgroundOption { + #[must_use] + pub const fn enable(&self) -> bool { + !matches!(self, Self::None) + } + + #[must_use] + pub fn user_message(&self) -> Option { + match self { + Self::Queue => Some(format!( + "{}: You've selected `{}` for your background worker configuration (you should \ + have a Redis/valkey instance to connect to)", + "workers".underline(), + "queue".yellow() + )), + Self::Blocking => Some(format!( + "{}: You've selected `{}` for your background worker configuration. Your workers \ + configuration will BLOCK REQUESTS until a task is done.", + "workers".underline(), + "blocking".yellow() + )), + Self::Async | Self::None => None, + } + } + + #[must_use] + pub const fn prompt_view(&self) -> &str { + match self { + Self::Async => "Async", + Self::Queue => "BackgroundQueue", + Self::Blocking => "ForegroundBlocking", + Self::None => "None", + } + } +} + +#[derive( + Debug, Clone, Deserialize, Serialize, EnumIter, Display, Default, PartialEq, Eq, ValueEnum, +)] +pub enum AssetsOption { + #[default] + #[strum(to_string = "Server (configures server-rendered views)")] + #[serde(rename = "server")] + Serverside, + #[strum(to_string = "Client (configures assets for frontend serving)")] + #[serde(rename = "client")] + Clientside, + #[strum(to_string = "None")] + #[serde(rename = "none")] + None, +} + +impl AssetsOption { + #[must_use] + pub const fn enable(&self) -> bool { + !matches!(self, Self::None) + } + + #[must_use] + pub fn user_message(&self) -> Option { + match self { + Self::Clientside => Some(format!( + "{}: You've selected `{}` for your asset serving configuration.\n\nNext step, \ + build your frontend:\n $ cd {}\n $ npm install && npm run build\n", + "assets".underline(), + "clientside".yellow(), + "frontend/".yellow() + )), + Self::Serverside | Self::None => None, + } + } +} + +#[derive(Debug, Clone, Default)] +/// Represents internal placeholders to be replaced. +pub struct ArgsPlaceholder { + pub db: Option, + pub bg: Option, + pub assets: Option, +} /// Holds the user's configuration selections. pub struct Selections { - pub db: wizard_opts::DBOption, - pub background: wizard_opts::BackgroundOption, - pub asset: wizard_opts::AssetsOption, + pub db: DBOption, + pub background: BackgroundOption, + pub asset: AssetsOption, } impl Selections { @@ -35,7 +204,6 @@ impl Selections { /// Prompts the user to enter an application name, with optional pre-set name /// input. Validates the name to ensure compliance with required naming rules. -/// Returns the validated name or an error if validation fails. /// /// # Errors /// when could not show user selection @@ -125,34 +293,34 @@ where /// /// # Errors /// when could not show user selection or user chose not continue -pub fn start(args: &wizard_opts::ArgsPlaceholder) -> crate::Result { +pub fn start(args: &ArgsPlaceholder) -> crate::Result { let template = select_option( "❯ What would you like to build?", - &wizard_opts::Template::iter().collect::>(), + &Template::iter().collect::>(), )?; match template { - wizard_opts::Template::Lightweight => Ok(Selections { + Template::Lightweight => Ok(Selections { db: DBOption::None, background: BackgroundOption::None, asset: AssetsOption::None, }), - wizard_opts::Template::RestApi => Ok(Selections { + Template::RestApi => Ok(Selections { db: select_db(args)?, background: select_background(args)?, asset: AssetsOption::None, }), - wizard_opts::Template::SaasServerSideRendering => Ok(Selections { + Template::SaasServerSideRendering => Ok(Selections { db: select_db(args)?, background: select_background(args)?, asset: AssetsOption::Serverside, }), - wizard_opts::Template::SaasClientSideRendering => Ok(Selections { + Template::SaasClientSideRendering => Ok(Selections { db: select_db(args)?, background: select_background(args)?, asset: AssetsOption::Clientside, }), - wizard_opts::Template::Advanced => Ok(Selections { + Template::Advanced => Ok(Selections { db: select_db(args)?, background: select_background(args)?, asset: select_asset(args)?, @@ -162,13 +330,13 @@ pub fn start(args: &wizard_opts::ArgsPlaceholder) -> crate::Result { /// Prompts the user to select a database option if none is provided in the /// arguments. -fn select_db(args: &wizard_opts::ArgsPlaceholder) -> crate::Result { +fn select_db(args: &ArgsPlaceholder) -> crate::Result { let dboption = if let Some(dboption) = args.db.clone() { dboption } else { select_option( "❯ Select a DB Provider", - &wizard_opts::DBOption::iter().collect::>(), + &DBOption::iter().collect::>(), )? }; Ok(dboption) @@ -176,13 +344,13 @@ fn select_db(args: &wizard_opts::ArgsPlaceholder) -> crate::Result { /// Prompts the user to select a background worker option if none is provided in /// the arguments. -fn select_background(args: &wizard_opts::ArgsPlaceholder) -> crate::Result { +fn select_background(args: &ArgsPlaceholder) -> crate::Result { let bgopt = if let Some(bgopt) = args.bg.clone() { bgopt } else { select_option( "❯ Select your background worker type", - &wizard_opts::BackgroundOption::iter().collect::>(), + &BackgroundOption::iter().collect::>(), )? }; Ok(bgopt) @@ -190,13 +358,13 @@ fn select_background(args: &wizard_opts::ArgsPlaceholder) -> crate::Result crate::Result { +fn select_asset(args: &ArgsPlaceholder) -> crate::Result { let assetopt = if let Some(assetopt) = args.assets.clone() { assetopt } else { select_option( "❯ Select an asset serving configuration", - &wizard_opts::AssetsOption::iter().collect::>(), + &AssetsOption::iter().collect::>(), )? }; Ok(assetopt) diff --git a/loco-new/src/wizard_opts.rs b/loco-new/src/wizard_opts.rs deleted file mode 100644 index c6dd3e78d..000000000 --- a/loco-new/src/wizard_opts.rs +++ /dev/null @@ -1,173 +0,0 @@ -use clap::ValueEnum; -use colored::Colorize; -use serde::{Deserialize, Serialize}; -use strum::{Display, EnumIter}; - -#[derive( - Debug, Clone, Deserialize, Serialize, EnumIter, Display, Default, PartialEq, Eq, ValueEnum, -)] -pub enum Template { - #[default] - #[strum(to_string = "Saas App with server side rendering")] - SaasServerSideRendering, - #[strum(to_string = "Saas App with client side rendering")] - SaasClientSideRendering, - #[strum(to_string = "Rest API (with DB and user auth)")] - RestApi, - #[strum(to_string = "lightweight-service (minimal, only controllers and views)")] - Lightweight, - #[strum(to_string = "Advanced")] - Advanced, -} - -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] -pub enum OptionsList { - #[serde(rename = "db")] - DB, - #[serde(rename = "bg")] - Background, - #[serde(rename = "assets")] - Assets, -} - -#[derive( - Debug, Clone, Deserialize, Serialize, EnumIter, Display, Default, PartialEq, Eq, ValueEnum, -)] -pub enum DBOption { - #[default] - #[serde(rename = "sqlite")] - Sqlite, - #[serde(rename = "pg")] - Postgres, - #[serde(rename = "none")] - None, -} - -impl DBOption { - #[must_use] - pub const fn enable(&self) -> bool { - !matches!(self, Self::None) - } - - #[must_use] - pub fn user_message(&self) -> Option { - match self { - Self::Postgres => Some(format!( - "{}: You've selected `{}` as your DB provider (you should have a postgres \ - instance to connect to)", - "database".underline(), - "postgres".yellow() - )), - Self::Sqlite | Self::None => None, - } - } - - #[must_use] - pub const fn endpoint_config(&self) -> &str { - match self { - Self::Sqlite => "sqlite://loco_app.sqlite?mode=rwc", - Self::Postgres => "postgres://loco:loco@localhost:5432/loco_app", - Self::None => "", - } - } -} - -#[derive( - Debug, Clone, Deserialize, Serialize, EnumIter, Display, Default, PartialEq, Eq, ValueEnum, -)] -pub enum BackgroundOption { - #[default] - #[strum(to_string = "Async (in-process tokio async tasks)")] - #[serde(rename = "BackgroundAsync")] - Async, - #[strum(to_string = "Queue (standalone workers using Redis)")] - #[serde(rename = "BackgroundQueue")] - Queue, - #[strum(to_string = "Blocking (run tasks in foreground)")] - #[serde(rename = "ForegroundBlocking")] - Blocking, - #[strum(to_string = "None")] - #[serde(rename = "none")] - None, -} - -impl BackgroundOption { - #[must_use] - pub const fn enable(&self) -> bool { - !matches!(self, Self::None) - } - - #[must_use] - pub fn user_message(&self) -> Option { - match self { - Self::Queue => Some(format!( - "{}: You've selected `{}` for your background worker configuration (you should \ - have a Redis/valkey instance to connect to)", - "workers".underline(), - "queue".yellow() - )), - Self::Blocking => Some(format!( - "{}: You've selected `{}` for your background worker configuration. Your workers \ - configuration will BLOCK REQUESTS until a task is done.", - "workers".underline(), - "blocking".yellow() - )), - Self::Async | Self::None => None, - } - } - - #[must_use] - pub const fn prompt_view(&self) -> &str { - match self { - Self::Async => "Async", - Self::Queue => "BackgroundQueue", - Self::Blocking => "ForegroundBlocking", - Self::None => "None", - } - } -} - -#[derive( - Debug, Clone, Deserialize, Serialize, EnumIter, Display, Default, PartialEq, Eq, ValueEnum, -)] -pub enum AssetsOption { - #[default] - #[strum(to_string = "Server (configures server-rendered views)")] - #[serde(rename = "server")] - Serverside, - #[strum(to_string = "Client (configures assets for frontend serving)")] - #[serde(rename = "client")] - Clientside, - #[strum(to_string = "None")] - #[serde(rename = "none")] - None, -} - -impl AssetsOption { - #[must_use] - pub const fn enable(&self) -> bool { - !matches!(self, Self::None) - } - - #[must_use] - pub fn user_message(&self) -> Option { - match self { - Self::Clientside => Some(format!( - "{}: You've selected `{}` for your asset serving configuration.\n\nNext step, \ - build your frontend:\n $ cd {}\n $ npm install && npm run build\n", - "assets".underline(), - "clientside".yellow(), - "frontend/".yellow() - )), - Self::Serverside | Self::None => None, - } - } -} - -#[derive(Debug, Clone, Default)] -/// Represents internal placeholders to be replaced. -pub struct ArgsPlaceholder { - pub db: Option, - pub bg: Option, - pub assets: Option, -} diff --git a/loco-new/tests/assertion/string.rs b/loco-new/tests/assertion/string.rs index 167203d15..bc148ce60 100644 --- a/loco-new/tests/assertion/string.rs +++ b/loco-new/tests/assertion/string.rs @@ -1,3 +1,4 @@ +#![allow(clippy::missing_panics_doc)] use regex::Regex; pub fn assert_line_regex(content: &str, expected: &str) { @@ -6,7 +7,8 @@ pub fn assert_line_regex(content: &str, expected: &str) { // Use assert! to check the regex match and panic if it fails assert!( re.is_match(content), - "Assertion failed: The content did not match the expected string. Expected: '{expected}', content:\n{content}" + "Assertion failed: The content did not match the expected string. Expected: '{expected}', \ + content:\n{content}" ); } @@ -14,6 +16,7 @@ pub fn assert_str_not_exists(content: &str, expected: &str) { // Use assert! to check the regex match and panic if it fails assert!( !content.contains(expected), - "Assertion failed: The content matched the unexpected string. Expected string to not exist: '{expected}', content in:\n{content}", + "Assertion failed: The content matched the unexpected string. Expected string to not \ + exist: '{expected}', content in:\n{content}", ); } diff --git a/loco-new/tests/assertion/toml.rs b/loco-new/tests/assertion/toml.rs index c1abd1dfb..3c068e1de 100644 --- a/loco-new/tests/assertion/toml.rs +++ b/loco-new/tests/assertion/toml.rs @@ -1,6 +1,9 @@ +#![allow(clippy::missing_panics_doc)] use std::path::PathBuf; + use toml::Value; +#[must_use] pub fn load(path: PathBuf) -> toml::Value { let s = std::fs::read_to_string(path).expect("could not open file"); toml::from_str(&s).expect("invalid toml content") @@ -29,33 +32,36 @@ pub fn assert_path_is_empty_array(toml: &Value, path: &[&str]) { ); } -/// Assert that the value at the specified path is an array and matches the expected array. +/// Assert that the value at the specified path is an array and matches the +/// expected array. pub fn assert_path_value_eq_array(toml: &Value, path: &[&str], expected: &[Value]) { let expected_value = Value::Array(expected.to_vec()); assert_path_value_eq(toml, path, &expected_value); } -/// Assert that a TOML value contains a specific key path and that it matches the expected value. +/// Assert that a TOML value contains a specific key path and that it matches +/// the expected value. pub fn assert_path_value_eq(toml: &Value, path: &[&str], expected: &Value) { let actual = get_value_at_path(toml, path); assert!( actual == Some(expected), - "Assertion failed: Path {path:?} does not match expected value. Expected: {expected:?}, Actual: {actual:?}" + "Assertion failed: Path {path:?} does not match expected value. Expected: {expected:?}, \ + Actual: {actual:?}" ); } -/// Assert that a TOML value contains a specific path, and that the value is an object (table). +/// Assert that a TOML value contains a specific path, and that the value is an +/// object (table). pub fn assert_path_is_object(toml: &Value, path: &[&str]) { let actual = get_value_at_path(toml, path).unwrap(); assert!( matches!(actual, Value::Table(_)), - "Assertion failed: Path {:?} is not an object. Actual value: {:?}", - path, - actual + "Assertion failed: Path {path:?} is not an object. Actual value: {actual:?}" ); } /// Helper function to concatenate keys of a nested table to form a string. +#[must_use] pub fn get_keys_concatenated_as_string(toml: &Value, path: &[&str]) -> Option { let value_at_path = get_value_at_path(toml, path)?; if let Value::Table(table) = value_at_path { @@ -69,7 +75,8 @@ pub fn get_keys_concatenated_as_string(toml: &Value, path: &[&str]) -> Option(toml: &'a Value, path: &[&str]) -> Option<&'a Value> { let mut current = toml; for &key in path { diff --git a/loco-new/tests/assertion/yaml.rs b/loco-new/tests/assertion/yaml.rs index f93f7dc66..202529b2d 100644 --- a/loco-new/tests/assertion/yaml.rs +++ b/loco-new/tests/assertion/yaml.rs @@ -1,7 +1,9 @@ +#![allow(clippy::missing_panics_doc)] use std::{fs::File, io::BufReader, path::PathBuf}; use serde_yaml::Value; +#[must_use] pub fn load(path: PathBuf) -> serde_yaml::Value { let file = File::open(path).expect("could not open file"); let reader = BufReader::new(file); @@ -13,13 +15,15 @@ pub fn assert_path_value_eq_string(yml: &Value, path: &[&str], expected: &str) { assert_path_value_eq(yml, path, &expected_value); } -/// Asserts that the YAML value at the specified path is equal to the expected boolean value. +/// Asserts that the YAML value at the specified path is equal to the expected +/// boolean value. pub fn assert_path_value_eq_bool(yml: &Value, path: &[&str], expected: bool) { let expected_value = Value::Bool(expected); assert_path_value_eq(yml, path, &expected_value); } -/// Asserts that the YAML value at the specified path is equal to the expected number value. +/// Asserts that the YAML value at the specified path is equal to the expected +/// number value. pub fn assert_path_value_eq_int(yml: &Value, path: &[&str], expected: i64) { let expected_value = Value::Number(serde_yaml::Number::from(expected)); assert_path_value_eq(yml, path, &expected_value); @@ -30,12 +34,14 @@ pub fn assert_path_value_eq_float(yml: &Value, path: &[&str], expected: f64) { assert_path_value_eq(yml, path, &expected_value); } -/// Asserts that the YAML mapping at the specified path contains the expected number of keys. +/// Asserts that the YAML mapping at the specified path contains the expected +/// number of keys. pub fn assert_path_key_count(yml: &Value, path: &[&str], expected_count: usize) { let actual = get_value_at_path(yml, path).expect("Path not found in YAML structure"); assert!( matches!(actual, Value::Mapping(map) if map.len() == expected_count), - "Assertion failed: Path {:?} does not contain the expected number of keys. Expected: {}, Actual: {}", + "Assertion failed: Path {:?} does not contain the expected number of keys. Expected: {}, \ + Actual: {}", path, expected_count, match actual { @@ -45,35 +51,37 @@ pub fn assert_path_key_count(yml: &Value, path: &[&str], expected_count: usize) ); } -/// Assert that a YAML value contains a specific key path and that it matches the expected value. +/// Assert that a YAML value contains a specific key path and that it matches +/// the expected value. pub fn assert_path_value_eq(yml: &Value, path: &[&str], expected: &Value) { let actual = get_value_at_path(yml, path); assert!( actual == Some(expected), - "Assertion failed: Path {path:?} does not match expected value. Expected: {expected:?}, Actual: {actual:?}" + "Assertion failed: Path {path:?} does not match expected value. Expected: {expected:?}, \ + Actual: {actual:?}" ); } -// pub fn assert_path_value_eq_mapping(yml: &Value, path: &[&str], expected: &serde_yaml::Mapping) { -// let actual = get_value_at_path(yml, path).unwrap(); -// assert!( +// pub fn assert_path_value_eq_mapping(yml: &Value, path: &[&str], expected: +// &serde_yaml::Mapping) { let actual = get_value_at_path(yml, +// path).unwrap(); assert!( // matches!(actual, Value::Mapping(map) if map == expected), -// "Assertion failed: Path {path:?} does not match expected mapping. Expected: {expected:?}, Actual: {actual:?}" -// ); +// "Assertion failed: Path {path:?} does not match expected mapping. +// Expected: {expected:?}, Actual: {actual:?}" ); // } -/// Assert that a YAML value contains a specific path, and that the value is an object. +/// Assert that a YAML value contains a specific path, and that the value is an +/// object. pub fn assert_path_is_object(yml: &Value, path: &[&str]) { let actual = get_value_at_path(yml, path).unwrap(); assert!( matches!(actual, Value::Mapping(_)), - "Assertion failed: Path {:?} is not an object. Actual value: {:?}", - path, - actual + "Assertion failed: Path {path:?} is not an object. Actual value: {actual:?}" ); } /// Helper function to concatenate keys of a nested mapping to form a string. +#[must_use] pub fn get_keys_concatenated_as_string(yml: &Value, path: &[&str]) -> Option { let value_at_path = get_value_at_path(yml, path)?; if let Value::Mapping(map) = value_at_path { @@ -89,7 +97,8 @@ pub fn get_keys_concatenated_as_string(yml: &Value, path: &[&str]) -> Option(yml: &'a Value, path: &[&str]) -> Option<&'a Value> { let mut current = yml; for &key in path { match current { Value::Mapping(map) => { - current = map.get(&Value::String(key.to_string()))?; + current = map.get(Value::String(key.to_string()))?; } Value::Sequence(seq) => match key.parse::() { Ok(index) => current = seq.get(index)?, diff --git a/loco-new/tests/templates/asset.rs b/loco-new/tests/templates/asset.rs index 87aa19979..03ea18128 100644 --- a/loco-new/tests/templates/asset.rs +++ b/loco-new/tests/templates/asset.rs @@ -1,9 +1,8 @@ -use super::*; +use loco::{settings, wizard::AssetsOption}; +use rstest::rstest; +use super::*; use crate::assertion; -use loco::settings; -use loco::wizard_opts::AssetsOption; -use rstest::rstest; pub fn run_generator(asset: AssetsOption) -> TestGenerator { let settings = settings::Settings { diff --git a/loco-new/tests/templates/background.rs b/loco-new/tests/templates/background.rs index c55498983..adcab5cba 100644 --- a/loco-new/tests/templates/background.rs +++ b/loco-new/tests/templates/background.rs @@ -1,9 +1,8 @@ -use super::*; +use loco::{settings, wizard::BackgroundOption}; +use rstest::rstest; +use super::*; use crate::assertion; -use loco::settings; -use loco::wizard_opts::BackgroundOption; -use rstest::rstest; pub fn run_generator(background: BackgroundOption) -> TestGenerator { let settings = settings::Settings { diff --git a/loco-new/tests/templates/db.rs b/loco-new/tests/templates/db.rs index d2399cf9b..6fc166407 100644 --- a/loco-new/tests/templates/db.rs +++ b/loco-new/tests/templates/db.rs @@ -1,9 +1,8 @@ -use super::*; +use loco::{settings, wizard::DBOption}; +use rstest::rstest; +use super::*; use crate::assertion; -use loco::settings; -use loco::wizard_opts::DBOption; -use rstest::rstest; pub fn run_generator(db: DBOption) -> TestGenerator { let settings = settings::Settings { diff --git a/loco-new/tests/templates/module_name.rs b/loco-new/tests/templates/module_name.rs index 46a24698c..2b015617c 100644 --- a/loco-new/tests/templates/module_name.rs +++ b/loco-new/tests/templates/module_name.rs @@ -1,9 +1,8 @@ -use super::*; +use loco::{settings, wizard::DBOption}; +use rstest::rstest; +use super::*; use crate::assertion; -use loco::settings; -use loco::wizard_opts::DBOption; -use rstest::rstest; pub fn run_generator() -> TestGenerator { let settings = settings::Settings {