mirror of
https://github.com/ricoriedel/wipe.git
synced 2024-11-17 21:46:39 +00:00
Add trait for mocking
This commit is contained in:
parent
e6e1c6fb25
commit
84cbe22ce7
123
src/color/factory.rs
Normal file
123
src/color/factory.rs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
use clap::ArgEnum;
|
||||||
|
use crossterm::style::Color::*;
|
||||||
|
use rand::Rng;
|
||||||
|
use rand::prelude::IteratorRandom;
|
||||||
|
use crate::color::{ColorSampler, SimpleColorSampler};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, ArgEnum)]
|
||||||
|
pub enum ColorEnum {
|
||||||
|
Red,
|
||||||
|
Green,
|
||||||
|
Blue,
|
||||||
|
LightRed,
|
||||||
|
LightGreen,
|
||||||
|
LightBlue,
|
||||||
|
White,
|
||||||
|
Rainbow
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ColorSamplerFactory {
|
||||||
|
/// Creates the requested color.
|
||||||
|
/// # Arguments
|
||||||
|
/// * `color`: The color type.
|
||||||
|
fn create(&self, colors: ColorEnum) -> Box<dyn ColorSampler>;
|
||||||
|
|
||||||
|
/// Chooses a random color color.
|
||||||
|
/// If none is provided, a random one of all available is chosen.
|
||||||
|
/// # Arguments
|
||||||
|
/// * `options`: A list of all options.
|
||||||
|
/// * `rng`: The number generator.
|
||||||
|
fn choose(&self, options: Vec<ColorEnum>, rng: &mut impl Rng) -> ColorEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SimpleColorSamplerFactory;
|
||||||
|
|
||||||
|
impl SimpleColorSamplerFactory {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColorSamplerFactory for SimpleColorSamplerFactory {
|
||||||
|
fn create(&self, colors: ColorEnum) -> Box<dyn ColorSampler> {
|
||||||
|
match colors {
|
||||||
|
ColorEnum::Red => Box::new(SimpleColorSampler::new(vec![Yellow, DarkYellow, Red])),
|
||||||
|
ColorEnum::Green => Box::new(SimpleColorSampler::new(vec![Cyan, DarkGreen, Green])),
|
||||||
|
ColorEnum::Blue => Box::new(SimpleColorSampler::new(vec![Magenta, DarkBlue, Blue])),
|
||||||
|
ColorEnum::LightRed => Box::new(SimpleColorSampler::new(vec![White, Yellow, Red])),
|
||||||
|
ColorEnum::LightGreen => Box::new(SimpleColorSampler::new(vec![White, Cyan, Green])),
|
||||||
|
ColorEnum::LightBlue => Box::new(SimpleColorSampler::new(vec![White, Blue, Magenta])),
|
||||||
|
ColorEnum::White => Box::new(SimpleColorSampler::new(vec![Black, Grey, White])),
|
||||||
|
ColorEnum::Rainbow => Box::new(SimpleColorSampler::new(vec![Magenta, Blue, Green, Yellow, Red]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose(&self, mut options: Vec<ColorEnum>, rng: &mut impl Rng) -> ColorEnum {
|
||||||
|
if options.is_empty() {
|
||||||
|
options.push(ColorEnum::Red);
|
||||||
|
options.push(ColorEnum::Green);
|
||||||
|
options.push(ColorEnum::Blue);
|
||||||
|
options.push(ColorEnum::LightRed);
|
||||||
|
options.push(ColorEnum::LightGreen);
|
||||||
|
options.push(ColorEnum::LightBlue);
|
||||||
|
options.push(ColorEnum::White);
|
||||||
|
options.push(ColorEnum::Rainbow);
|
||||||
|
}
|
||||||
|
options.into_iter().choose_stable(rng).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use rand::rngs::mock::StepRng;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create() {
|
||||||
|
let factory = SimpleColorSamplerFactory::new();
|
||||||
|
|
||||||
|
factory.create(ColorEnum::Red);
|
||||||
|
factory.create(ColorEnum::Green);
|
||||||
|
factory.create(ColorEnum::Blue);
|
||||||
|
factory.create(ColorEnum::LightRed);
|
||||||
|
factory.create(ColorEnum::LightGreen);
|
||||||
|
factory.create(ColorEnum::LightBlue);
|
||||||
|
factory.create(ColorEnum::White);
|
||||||
|
factory.create(ColorEnum::Rainbow);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn choose_from_all() {
|
||||||
|
let rng = &mut StepRng::new(0, 1);
|
||||||
|
|
||||||
|
let factory = SimpleColorSamplerFactory::new();
|
||||||
|
|
||||||
|
assert!(matches!(factory.choose(Vec::new(), rng), ColorEnum::Rainbow));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn choose_from_options() {
|
||||||
|
let rng = &mut StepRng::new(0, 1);
|
||||||
|
let options = vec![ColorEnum::Blue];
|
||||||
|
|
||||||
|
let factory = SimpleColorSamplerFactory::new();
|
||||||
|
|
||||||
|
assert!(matches!(factory.choose(options, rng), ColorEnum::Blue));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn enum_copy() {
|
||||||
|
let color = ColorEnum::Green;
|
||||||
|
let copy = color;
|
||||||
|
|
||||||
|
assert!(matches!(copy, ColorEnum::Green))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn enum_clone() {
|
||||||
|
let color = ColorEnum::Green;
|
||||||
|
let copy = color.clone();
|
||||||
|
|
||||||
|
assert!(matches!(copy, ColorEnum::Green))
|
||||||
|
}
|
||||||
|
}
|
58
src/color/mod.rs
Normal file
58
src/color/mod.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
pub mod factory;
|
||||||
|
|
||||||
|
use crossterm::style::Color;
|
||||||
|
use crossterm::style::Color::*;
|
||||||
|
|
||||||
|
/// A collection of colors.
|
||||||
|
pub trait ColorSampler {
|
||||||
|
/// Gets a color for the given fill.
|
||||||
|
/// # Arguments
|
||||||
|
/// * `fill`: `0 <= fill` and `fill < 1`
|
||||||
|
fn sample(&self, fill: f32) -> Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SimpleColorSampler {
|
||||||
|
values: Vec<Color>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleColorSampler {
|
||||||
|
pub fn new(values: Vec<Color>) -> Self {
|
||||||
|
Self { values }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColorSampler for SimpleColorSampler {
|
||||||
|
fn sample(&self, fill: f32) -> Color {
|
||||||
|
let index = self.values.len() as f32 * fill;
|
||||||
|
|
||||||
|
assert!(index >= 0.0);
|
||||||
|
|
||||||
|
self.values[index as usize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample() {
|
||||||
|
let sampler = SimpleColorSampler::new(vec![Red, Yellow, Green]);
|
||||||
|
|
||||||
|
assert_eq!(Red, sampler.sample(0.1));
|
||||||
|
assert_eq!(Yellow, sampler.sample(0.4));
|
||||||
|
assert_eq!(Green, sampler.sample(0.7));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn sample_index_negative() {
|
||||||
|
SimpleColorSampler::new(Vec::new()).sample(-0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn sample_index_equals_one() {
|
||||||
|
SimpleColorSampler::new(Vec::new()).sample(1.0);
|
||||||
|
}
|
||||||
|
}
|
106
src/pallet.rs
106
src/pallet.rs
@ -1,106 +0,0 @@
|
|||||||
use crossterm::style::Color;
|
|
||||||
use crossterm::style::Color::*;
|
|
||||||
use rand::prelude::IteratorRandom;
|
|
||||||
use rand::Rng;
|
|
||||||
use clap::ArgEnum;
|
|
||||||
|
|
||||||
/// A collection of colors.
|
|
||||||
pub struct Pallet {
|
|
||||||
values: Vec<Color>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pallet {
|
|
||||||
pub fn new(values: Vec<Color>) -> Self {
|
|
||||||
Self { values }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn red() -> Pallet {
|
|
||||||
Pallet::new(vec![Yellow, DarkYellow, Red])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn red_light() -> Pallet {
|
|
||||||
Pallet::new(vec![White, Yellow, Red])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn green() -> Pallet {
|
|
||||||
Pallet::new(vec![Cyan, DarkGreen, Green])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn green_light() -> Pallet {
|
|
||||||
Pallet::new(vec![White, Cyan, Green])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blue() -> Pallet {
|
|
||||||
Pallet::new(vec![Magenta, DarkBlue, Blue])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blue_light() -> Pallet {
|
|
||||||
Pallet::new(vec![White, Magenta, Blue])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn white() -> Pallet {
|
|
||||||
Pallet::new(vec![Black, Grey, White])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rainbow() -> Pallet {
|
|
||||||
Pallet::new(vec![Magenta, Blue, Green, Yellow, Red])
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a color for the given fill.
|
|
||||||
/// # Arguments
|
|
||||||
/// * `fill`: `0 <= fill` and `fill < 1`
|
|
||||||
pub fn sample(&self, fill: f32) -> Color {
|
|
||||||
let pos = self.values.len() as f32 * fill;
|
|
||||||
let index = pos as usize;
|
|
||||||
|
|
||||||
self.values[index]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, ArgEnum)]
|
|
||||||
pub enum PalletEnum {
|
|
||||||
Red,
|
|
||||||
RedLight,
|
|
||||||
Green,
|
|
||||||
GreenLight,
|
|
||||||
Blue,
|
|
||||||
BlueLight,
|
|
||||||
White,
|
|
||||||
Rainbow
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Chooses a random color pallet.
|
|
||||||
/// If none is provided, a random one of all available is chosen.
|
|
||||||
/// # Arguments
|
|
||||||
/// * `options`: A list of all options.
|
|
||||||
/// * `rng`: The number generator.
|
|
||||||
pub fn choose_pallet(mut options: Vec<PalletEnum>, rng: &mut impl Rng) -> PalletEnum {
|
|
||||||
if options.is_empty() {
|
|
||||||
options.push(PalletEnum::Red);
|
|
||||||
options.push(PalletEnum::RedLight);
|
|
||||||
options.push(PalletEnum::Green);
|
|
||||||
options.push(PalletEnum::GreenLight);
|
|
||||||
options.push(PalletEnum::Blue);
|
|
||||||
options.push(PalletEnum::BlueLight);
|
|
||||||
options.push(PalletEnum::White);
|
|
||||||
options.push(PalletEnum::Rainbow);
|
|
||||||
}
|
|
||||||
options.into_iter().choose(rng).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates the requested pallet.
|
|
||||||
/// # Arguments
|
|
||||||
/// * `pallet`: The pallet type.
|
|
||||||
pub fn create_pallet(pallet: PalletEnum) -> Pallet {
|
|
||||||
match pallet {
|
|
||||||
PalletEnum::Red => Pallet::red(),
|
|
||||||
PalletEnum::RedLight => Pallet::red_light(),
|
|
||||||
PalletEnum::Green => Pallet::green(),
|
|
||||||
PalletEnum::GreenLight => Pallet::green_light(),
|
|
||||||
PalletEnum::Blue => Pallet::blue(),
|
|
||||||
PalletEnum::BlueLight => Pallet::blue_light(),
|
|
||||||
PalletEnum::White => Pallet::white(),
|
|
||||||
PalletEnum::Rainbow => Pallet::rainbow()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user