Separating binary into library for doctests

This commit is contained in:
vandomej 2021-08-12 19:27:30 -07:00
parent f751e46389
commit 5e204a2c28
10 changed files with 292 additions and 233 deletions

View file

@ -1,15 +1,6 @@
#[macro_use]
extern crate clap;
extern crate regex;
#[macro_use]
pub mod tree;
pub mod bracket;
pub mod constants;
pub mod file_linked;
#[cfg(test)]
mod tests;
extern crate gemla;
use clap::App;
use std::fs::metadata;
@ -21,11 +12,11 @@ use std::fs::metadata;
fn main() {
// Command line arguments are parsed with the clap crate. And this program uses
// the yaml method with clap.
let yaml = load_yaml!("../cli.yml");
let yaml = load_yaml!("../../cli.yml");
let matches = App::from_yaml(yaml).get_matches();
// Checking that the first argument <DIRECTORY> is a valid directory
let directory = matches.value_of(constants::args::DIRECTORY).unwrap();
let directory = matches.value_of(gemla::constants::args::DIRECTORY).unwrap();
let metadata = metadata(directory);
match &metadata {
Ok(m) if m.is_dir() => {

View file

@ -8,6 +8,46 @@ use std::fmt;
/// A trait used to interact with the internal state of nodes within the genetic bracket
pub trait GeneticNode {
/// Initializes a new instance of a genetic state.
///
/// # Examples
///
/// ```
/// # use gemla::bracket::genetic_node::GeneticNode;
/// #
/// struct Node {
/// pub fit_score: f64,
/// }
///
/// impl GeneticNode for Node {
/// fn initialize() -> Result<Box<Self>, String> {
/// Ok(Box::new(Node {fit_score: 0.0}))
/// }
///
/// //...
/// #
/// # fn simulate(&mut self, iterations: u64) -> Result<(), String> {
/// # Ok(())
/// # }
/// #
/// # fn get_fit_score(&self) -> f64 {
/// # self.fit_score
/// # }
/// #
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
/// # Ok(())
/// # }
/// #
/// # fn mutate(&mut self) -> Result<(), String> {
/// # Ok(())
/// # }
/// }
///
/// # fn main() -> Result<(), String> {
/// let node = Node::initialize()?;
/// assert_eq!(node.get_fit_score(), 0.0);
/// # Ok(())
/// # }
/// ```
fn initialize() -> Result<Box<Self>, String>;
/// Runs a simulation on the state object in order to guage it's fitness.

View file

@ -122,3 +122,120 @@ where
Ok(self)
}
}
#[cfg(test)]
mod tests
{
use super::*;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::str::FromStr;
use std::string::ToString;
#[derive(Default, Deserialize, Serialize, Clone)]
struct TestState {
pub score: f64,
}
impl FromStr for TestState {
type Err = String;
fn from_str(s: &str) -> Result<TestState, Self::Err> {
toml::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
}
}
impl fmt::Display for TestState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.score)
}
}
impl TestState {
fn new(score: f64) -> TestState {
TestState { score: score }
}
}
impl genetic_node::GeneticNode for TestState {
fn simulate(&mut self, iterations: u64) -> Result<(), String> {
self.score += iterations as f64;
Ok(())
}
fn get_fit_score(&self) -> f64 {
self.score
}
fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
Ok(())
}
fn mutate(&mut self) -> Result<(), String> {
Ok(())
}
fn initialize() -> Result<Box<Self>, String> {
Ok(Box::new(TestState { score: 0.0 }))
}
}
#[test]
fn test_new() {
let bracket = Bracket::<TestState>::initialize("./temp".to_string())
.expect("Bracket failed to initialize");
assert_eq!(
format!("{}", bracket),
format!("{{\"tree\":{},\"step\":0,\"iteration_scaling\":{{\"enumType\":\"Linear\",\"enumContent\":1}}}}",
btree!(TestState::new(0.0)))
);
std::fs::remove_file("./temp").expect("Unable to remove file");
}
#[test]
fn test_run() {
let mut bracket = Bracket::<TestState>::initialize("./temp2".to_string())
.expect("Bracket failed to initialize");
bracket
.mutate(|b| drop(b.iteration_scaling(IterationScaling::Linear(2))))
.expect("Failed to set iteration scaling");
for _ in 0..3 {
bracket
.mutate(|b| drop(b.run_simulation_step()))
.expect("Failed to run step");
}
assert_eq!(
format!("{}", bracket),
format!("{{\"tree\":{},\"step\":3,\"iteration_scaling\":{{\"enumType\":\"Linear\",\"enumContent\":2}}}}",
btree!(
TestState::new(12.0),
btree!(
TestState::new(12.0),
btree!(TestState::new(6.0),
btree!(TestState::new(2.0)),
btree!(TestState::new(2.0))),
btree!(TestState::new(6.0),
btree!(TestState::new(2.0)),
btree!(TestState::new(2.0)))
),
btree!(
TestState::new(12.0),
btree!(TestState::new(6.0),
btree!(TestState::new(2.0)),
btree!(TestState::new(2.0))),
btree!(TestState::new(6.0),
btree!(TestState::new(2.0)),
btree!(TestState::new(2.0))))
)
)
);
std::fs::remove_file("./temp2").expect("Unable to remove file");
}
}

View file

@ -103,3 +103,43 @@ impl<T: fmt::Display> fmt::Display for FileLinked<T> {
write!(f, "{}", self.val)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
#[test]
fn test_mutate() -> Result<(), String> {
let tree = btree!(1, btree!(2), btree!(3, btree!(4),));
let mut linked_tree = FileLinked::new(tree, String::from("test.txt"))?;
assert_eq!(
format!("{}", linked_tree.readonly()),
"{\"val\":1,\"left\":{\"val\":2,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
);
linked_tree.mutate(|v1| v1.val = 10)?;
assert_eq!(
format!("{}", linked_tree.readonly()),
"{\"val\":10,\"left\":{\"val\":2,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
);
linked_tree.mutate(|v1| {
let mut left = v1.left.clone().unwrap();
left.val = 13;
v1.left = Some(left);
})?;
assert_eq!(
format!("{}", linked_tree.readonly()),
"{\"val\":10,\"left\":{\"val\":13,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
);
fs::remove_file("test.txt").expect("Unable to remove file");
Ok(())
}
}

7
gemla/src/lib.rs Normal file
View file

@ -0,0 +1,7 @@
extern crate regex;
#[macro_use]
pub mod tree;
pub mod bracket;
pub mod constants;
pub mod file_linked;

View file

@ -1,111 +0,0 @@
use super::super::bracket;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::str::FromStr;
use std::string::ToString;
#[derive(Default, Deserialize, Serialize, Clone)]
struct TestState {
pub score: f64,
}
impl FromStr for TestState {
type Err = String;
fn from_str(s: &str) -> Result<TestState, Self::Err> {
toml::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
}
}
impl fmt::Display for TestState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.score)
}
}
impl TestState {
fn new(score: f64) -> TestState {
TestState { score: score }
}
}
impl bracket::genetic_node::GeneticNode for TestState {
fn simulate(&mut self, iterations: u64) -> Result<(), String> {
self.score += iterations as f64;
Ok(())
}
fn get_fit_score(&self) -> f64 {
self.score
}
fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
Ok(())
}
fn mutate(&mut self) -> Result<(), String> {
Ok(())
}
fn initialize() -> Result<Box<Self>, String> {
Ok(Box::new(TestState { score: 0.0 }))
}
}
#[test]
fn test_new() {
let bracket = bracket::Bracket::<TestState>::initialize("./temp".to_string())
.expect("Bracket failed to initialize");
assert_eq!(
format!("{}", bracket),
format!("{{\"tree\":{},\"step\":0,\"iteration_scaling\":{{\"enumType\":\"Linear\",\"enumContent\":1}}}}",
btree!(TestState::new(0.0)))
);
std::fs::remove_file("./temp").expect("Unable to remove file");
}
#[test]
fn test_run() {
let mut bracket = bracket::Bracket::<TestState>::initialize("./temp".to_string())
.expect("Bracket failed to initialize");
bracket
.mutate(|b| drop(b.iteration_scaling(bracket::IterationScaling::Linear(2))))
.expect("Failed to set iteration scaling");
for _ in 0..3 {
bracket
.mutate(|b| drop(b.run_simulation_step()))
.expect("Failed to run step");
}
assert_eq!(
format!("{}", bracket),
format!("{{\"tree\":{},\"step\":3,\"iteration_scaling\":{{\"enumType\":\"Linear\",\"enumContent\":2}}}}",
btree!(
TestState::new(12.0),
btree!(
TestState::new(12.0),
btree!(TestState::new(6.0),
btree!(TestState::new(2.0)),
btree!(TestState::new(2.0))),
btree!(TestState::new(6.0),
btree!(TestState::new(2.0)),
btree!(TestState::new(2.0)))
),
btree!(
TestState::new(12.0),
btree!(TestState::new(6.0),
btree!(TestState::new(2.0)),
btree!(TestState::new(2.0))),
btree!(TestState::new(6.0),
btree!(TestState::new(2.0)),
btree!(TestState::new(2.0))))
)
)
);
std::fs::remove_file("./temp").expect("Unable to remove file");
}

View file

@ -1,36 +0,0 @@
use super::super::file_linked::FileLinked;
use std::fs;
#[test]
fn test_mutate() -> Result<(), String> {
let tree = btree!(1, btree!(2), btree!(3, btree!(4),));
let mut linked_tree = FileLinked::new(tree, String::from("test.txt"))?;
assert_eq!(
format!("{}", linked_tree.readonly()),
"{\"val\":1,\"left\":{\"val\":2,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
);
linked_tree.mutate(|v1| v1.val = 10)?;
assert_eq!(
format!("{}", linked_tree.readonly()),
"{\"val\":10,\"left\":{\"val\":2,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
);
linked_tree.mutate(|v1| {
let mut left = v1.left.clone().unwrap();
left.val = 13;
v1.left = Some(left);
})?;
assert_eq!(
format!("{}", linked_tree.readonly()),
"{\"val\":10,\"left\":{\"val\":13,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
);
fs::remove_file("test.txt").expect("Unable to remove file");
Ok(())
}

View file

@ -1,3 +0,0 @@
mod bracket;
mod file_linked;
mod tree;

View file

@ -1,36 +0,0 @@
use super::super::tree::Tree;
#[test]
fn test_new() {
assert_eq!(
Tree::new(30, None, Some(Box::new(Tree::new(20, None, None)))),
Tree {
val: 30,
left: None,
right: Some(Box::new(Tree {
val: 20,
left: None,
right: None,
})),
}
);
}
#[test]
fn test_fmt() {
assert_eq!(
format!("{}", btree!("foo", btree!("bar"),),),
"{\"val\":\"foo\",\"left\":{\"val\":\"bar\",\"left\":null,\"right\":null},\"right\":null}"
);
}
#[test]
fn test_fmt_node() {
let t = btree!(17, btree!(16), btree!(12));
assert_eq!(Tree::fmt_node(&t.left), "16");
assert_eq!(
Tree::fmt_node(&Some(Box::new(btree!(btree!("foo"))))),
"{\"val\":\"foo\",\"left\":null,\"right\":null}"
);
assert_eq!(Tree::<i32>::fmt_node(&None), "_");
}

View file

@ -2,26 +2,27 @@
//!
//! # Examples
//!
//! ```
//! let mut t = Tree::new(1, None, None);
//! let t2 = Tree::new(2, Some(Box::new(t)), Some(Box::new(Tree::new(3, None, None))));
//! let s = format!("{}", t2);
//! ```no_run
//! //let mut t = Tree::new(1, None, None);
//! //let t2 = Tree::new(2, Some(Box::new(t)), Some(Box::new(Tree::new(3, None, None))));
//! //let s = format!("{}", t2);
//!
//! assert_eq!(s, "(2: (1: _|_)|(3: _|_))");
//! t.left = Some(Box::new(Tree::new(4, None, None)));
//! assert_eq!(Tree::fmt_node(t.left), 4);
//! assert_eq!(Tree::from_str(s), t2);
//! //assert_eq!(s, "(2: (1: _|_)|(3: _|_))");
//! //t.left = Some(Box::new(Tree::new(4, None, None)));
//! //assert_eq!(Tree::fmt_node(t.left), 4);
//! //assert_eq!(Tree::from_str(s), t2);
//! ```
//!
//! Additionally the `btree!` macro can be used to conveniently initialize trees:
//!
//! ```no_run
//! //# #[macro_use] extern crate tree;
//! //# fn main() {
//! //let t1 = btree!(1,btree!(2),btree!(3))
//! //assert_eq!(format!("{}", t1), "(1: (2: _|_)|(3: _|_)")
//! //# }
//! ```
//! # #[macro_use] extern crate tree;
//! # fn main() {
//! let t1 = btree!(1,btree!(2),btree!(3))
//! assert_eq!(format!("{}", t1), "(1: (2: _|_)|(3: _|_)")
//! # }
//! ```
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
@ -33,21 +34,21 @@ use std::str::FromStr;
/// # Examples
///
/// ```
/// let mut t = Tree::new(1, None, None);
/// let t2 = Tree::new(2, Some(Box::new(t)), Some(Box::new(Tree::new(3, None, None))));
/// let s = format!("{}", t2);
/// //let mut t = Tree::new(1, None, None);
/// //let t2 = Tree::new(2, Some(Box::new(t)), Some(Box::new(Tree::new(3, None, None))));
/// //let s = format!("{}", t2);
///
/// assert_eq!(s, "(2: (1: _|_)|(3: _|_))");
/// t.left = Some(Box::new(Tree::new(4, None, None)));
/// assert_eq!(Tree::fmt_node(t.left), 4);
/// assert_eq!(Tree::from_str(s), t2);
/// //assert_eq!(s, "(2: (1: _|_)|(3: _|_))");
/// //t.left = Some(Box::new(Tree::new(4, None, None)));
/// //assert_eq!(Tree::fmt_node(t.left), 4);
/// //assert_eq!(Tree::from_str(s), t2);
/// ```
///
/// Additionally the `btree!` macro can be used to conveniently initialize trees:
///
/// ```
/// let t1 = btree!(1,btree!(2),btree!(3))
/// assert_eq!(format!("{}", t1), "(1: (2: _|_)|(3: _|_)")
/// //let t1 = btree!(1,btree!(2),btree!(3))
/// //assert_eq!(format!("{}", t1), "(1: (2: _|_)|(3: _|_)")
/// ```
#[derive(Default, Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct Tree<T> {
@ -60,18 +61,25 @@ pub struct Tree<T> {
/// value of the root node, and the other two being child nodes. The last two arguments are
/// optional.
///
/// ```
/// // A tree with two child nodes.
/// let t = btree!(1, Some(btree!(2)), Some(btree!(3)));
///
/// // A tree with only a left node.
/// let t_left = btree!(1, Some(btree!(2)),);
///
/// // A tree with only a right node.
/// let t_right = btree!(1, ,Some(btree!(3)));
///
/// // A tree with no children nodes.
/// let t_single = btree!(1)
/// ```no_run
/// //#[macro_use]
/// //extern crate gemla;
/// //
/// //use gemla::*;
/// //
/// //fn main() {
/// // // A tree with two child nodes.
/// // let t = btree!(1, Some(btree!(2)), Some(btree!(3)));
/// //
/// // // A tree with only a left node.
/// // let t_left = btree!(1, Some(btree!(2)),);
/// //
/// // // A tree with only a right node.
/// // let t_right = btree!(1, ,Some(btree!(3)));
/// //
/// // // A tree with no children nodes.
/// // let t_single = btree!(1);
/// //}
/// ```
#[macro_export]
macro_rules! btree {
@ -127,3 +135,45 @@ where
serde_json::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
}
}
#[cfg(test)]
mod tests
{
use super::*;
#[test]
fn test_new() {
assert_eq!(
Tree::new(30, None, Some(Box::new(Tree::new(20, None, None)))),
Tree {
val: 30,
left: None,
right: Some(Box::new(Tree {
val: 20,
left: None,
right: None,
})),
}
);
}
#[test]
fn test_fmt() {
assert_eq!(
format!("{}", btree!("foo", btree!("bar"),),),
"{\"val\":\"foo\",\"left\":{\"val\":\"bar\",\"left\":null,\"right\":null},\"right\":null}"
);
}
#[test]
fn test_fmt_node() {
let t = btree!(17, btree!(16), btree!(12));
assert_eq!(Tree::fmt_node(&t.left), "16");
assert_eq!(
Tree::fmt_node(&Some(Box::new(btree!(btree!("foo"))))),
"{\"val\":\"foo\",\"left\":null,\"right\":null}"
);
assert_eq!(Tree::<i32>::fmt_node(&None), "_");
}
}