Skip to content

Commit

Permalink
Update run_tests functionality and fix associated bugs
Browse files Browse the repository at this point in the history
The run_tests function and related code were significantly revised and updated. The function now supports more flexible feature testing including feature combination depth and the ability to easily specify which Rust channels should be used for testing. The function now uses ThreadPoolBuilder and Former, and its error handling has been improved. TestsArgs struct was included for handling command line arguments.
  • Loading branch information
Barsik-sus committed Feb 13, 2024
1 parent 0848d88 commit aeeeb3d
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 152 deletions.
36 changes: 33 additions & 3 deletions module/move/willbe/src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ mod private
use crate::*;

use std::{ fmt::Formatter, path::Path };
use std::collections::{ BTreeSet, HashSet };

use process::CmdReport;
use wtools::error::Result;
use former::Former;
use wtools::iter::Itertools;

///
/// Assemble the local package into a distributable tarball.
Expand Down Expand Up @@ -67,7 +69,7 @@ mod private
}

/// The `Channel` enum represents different release channels for rust.
#[ derive( Debug, Default, Copy, Clone ) ]
#[ derive( Debug, Default, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd ) ]
pub enum Channel
{
/// Represents the stable release channel.
Expand Down Expand Up @@ -104,7 +106,7 @@ mod private
#[ default( false ) ]
with_all_features : bool,
/// Specifies a list of features to be enabled in the test.
enable_features : Vec< String >,
enable_features : BTreeSet< String >,
}

impl TestArgs
Expand All @@ -115,7 +117,7 @@ mod private
.into_iter()
.chain( if self.with_default_features { None } else { Some( "--no-default-features".into() ) } )
.chain( if self.with_all_features { Some( "--all-features".into() ) } else { None } )
.chain( if self.enable_features.is_empty() { None } else { Some([ "--features".into(), self.enable_features.join( "," ) ]) }.into_iter().flatten() )
.chain( if self.enable_features.is_empty() { None } else { Some([ "--features".into(), self.enable_features.iter().join( "," ) ]) }.into_iter().flatten() )
.collect()
}
}
Expand Down Expand Up @@ -156,6 +158,31 @@ mod private
process::start2_sync( program, args, path )
}
}

/// Retrieves a list of available channels.
///
/// This function takes a path and returns a `Result` with a vector of strings representing the available channels.
pub fn available_channels< P >( path : P ) -> Result< HashSet< Channel > >
where
P : AsRef< Path >,
{
let ( program, args ) = ( "rustup", [ "toolchain", "list" ] );
let report = process::start2_sync( program, args, path )?;

let list = report
.out
.lines()
.map( | l | l.split_once( '-' ).unwrap().0 )
.filter_map( | c | match c
{
"stable" => Some( Channel::Stable ),
"nightly" => Some( Channel::Nightly ),
_ => None
} )
.collect();

Ok( list )
}
}

//
Expand All @@ -164,7 +191,10 @@ crate::mod_interface!
{
protected use package;
protected use publish;

protected use Channel;
protected use TestArgs;
protected use test;

protected use available_channels;
}
16 changes: 9 additions & 7 deletions module/move/willbe/src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,16 @@ pub( crate ) mod private
.form();

let run_tests_command = wca::Command::former()
.hint( "Run tests in a specified crate" )
.long_hint( "Run tests in a specified crate" )
.hint( "execute tests in specific packages" )
.long_hint( "this command runs tests in designated packages based on the provided path. It allows for inclusion and exclusion of features, testing on different Rust version channels, parallel execution, and feature combination settings." )
.phrase("tests.run")
.subject( "A path to directories with packages.", Type::Path, true )
.property( "nightly", "Run tests on nightly. Default is false.", Type::Bool, true )
.property( "exclude", "List of features to exclude.", Type::List( Type::String.into(), ',' ), true )
.property( "include", "List of features to include.", Type::List( Type::String.into(), ',' ), true )
.property( "parallel", "Run tests with different a set of features in parallel. Default is false.", Type::Bool, true )
.subject( "A path to directories with packages. If no path is provided, the current directory is used.", Type::Path, true )
.property( "with_stable", "Specifies whether or not to run tests on stable Rust version. Default is `true`", Type::Bool, true )
.property( "with_nightly", "Specifies whether or not to run tests on nightly Rust version. Default is `false`.", Type::Bool, true )
.property( "parallel", "Indicates if tests with different feature sets should be run in parallel. Default is `true`.", Type::Bool, true )
.property( "power", "Defines the depth of feature combination testing. Default is `1`.", Type::Number, true )
.property( "include", "A list of features to include in testing. Separate multiple features by comma.", Type::List( Type::String.into(), ',' ), true )
.property( "exclude", "A list of features to exclude from testing. Separate multiple features by comma.", Type::List( Type::String.into(), ',' ), true )
.form();

let generate_workflow = wca::Command::former()
Expand Down
69 changes: 60 additions & 9 deletions module/move/willbe/src/command/run_tests.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,59 @@
/// Internal namespace.
mod private
{
use crate::*;

use std::collections::HashSet;
use std::path::PathBuf;

use crate::{ wtools, endpoint, path };

use wca::{ Args, Props };
use wtools::error::Result;
use path::AbsolutePath;
use endpoint::run_tests::TestsArgs;
use former::Former;
use cargo::Channel;

#[ derive( Former ) ]
struct RunTestsProperties
{
#[ default( true ) ]
with_stable : bool,
#[ default( false ) ]
with_nightly : bool,
#[ default( true ) ]
parallel : bool,
#[ default( 1u32 ) ]
power : u32,
include : Vec< String >,
exclude : Vec< String >,
}

/// run tests in specified crate
/// run tests in specified crate
pub fn run_tests( ( args, properties ) : ( Args, Props ) ) -> Result< () >
{
let path : PathBuf = args.get_owned( 0 ).unwrap_or_else( || "./".into() );
let path = path::canonicalize(path)?;
let nightly = properties.get_owned( "nightly" ).unwrap_or( false );
let exclude_features_list = properties.get_owned( "exclude" ).unwrap_or_else( || Vec::new() ).into();
let include_features_list = properties.get_owned( "include" ).unwrap_or_else( || Vec::new() ).into();
let parallel = properties.get_owned( "parallel" ).unwrap_or( false );
let path = AbsolutePath::try_from( path )?;
let RunTestsProperties { with_stable, with_nightly, parallel, power, include, exclude } = properties.try_into()?;

let crate_dir = CrateDir::try_from( path )?;

let mut channels = HashSet::new();
if with_stable { channels.insert( Channel::Stable ); }
if with_nightly { channels.insert( Channel::Nightly ); }

let args = TestsArgs::former()
.dir( crate_dir )
.parallel( parallel)
.channels( channels )
.power( power )
.exclude_features( exclude )
.include_features( include )
.form();

match endpoint::run_tests( &path, nightly, exclude_features_list, include_features_list, parallel )
match endpoint::run_tests( args )
{
core::result::Result::Ok( report ) =>
Ok( report ) =>
{
println!( "{report} ");
}
Expand All @@ -32,6 +65,24 @@ mod private

Ok(())
}

impl TryFrom< Props > for RunTestsProperties
{
type Error = wtools::error::for_app::Error;
fn try_from( value : Props ) -> Result< Self, Self::Error >
{
let mut this = Self::former();

this = if let Some( v ) = value.get_owned( "with_stable" ) { this.with_stable::< bool >( v ) } else { this };
this = if let Some( v ) = value.get_owned( "with_nightly" ) { this.with_nightly::< bool >( v ) } else { this };
this = if let Some( v ) = value.get_owned( "parallel" ) { this.parallel::< bool >( v ) } else { this };
this = if let Some( v ) = value.get_owned( "power" ) { this.power::< u32 >( v ) } else { this };
this = if let Some( v ) = value.get_owned( "include" ) { this.include::< Vec< String > >( v ) } else { this };
this = if let Some( v ) = value.get_owned( "exclude" ) { this.exclude::< Vec< String > >( v ) } else { this };

Ok( this.form() )
}
}
}

crate::mod_interface!
Expand Down
Loading

0 comments on commit aeeeb3d

Please sign in to comment.