mod fixture;
mod todo_domain {
pub struct NewTodo {
pub subject: String,
}
}
mod todo_repository {
use crate::todo_domain::NewTodo;
use output_tracker::non_threadsafe::Error as OtError;
use output_tracker::non_threadsafe::OutputSubject;
use output_tracker::non_threadsafe::OutputTracker;
#[derive(thiserror::Error, Debug)]
#[error("failed to access the database")]
pub struct DbError {
pub message: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TodoEntity {
pub subject: String,
}
pub struct TodoRepository {
db: Box<dyn DbAccess>,
todo_subject: OutputSubject<TodoEntity>,
}
impl TodoRepository {
#[allow(dead_code)]
pub fn new() -> Self {
Self {
db: Box::new(RealDb),
todo_subject: OutputSubject::new(),
}
}
pub fn nulled() -> Self {
Self {
db: Box::new(NulledDb),
todo_subject: OutputSubject::new(),
}
}
pub fn track_todos(&self) -> Result<OutputTracker<TodoEntity>, OtError> {
self.todo_subject.create_tracker()
}
pub fn insert(&self, new_todo: NewTodo) -> Result<(), DbError> {
let todo_entity = TodoEntity {
subject: new_todo.subject,
};
let result = self.db.insert_todo(todo_entity.clone());
result.inspect(|()| {
_ = self.todo_subject.emit(todo_entity);
})
}
}
#[allow(dead_code)]
struct RealDb;
impl DbAccess for RealDb {
fn insert_todo(&self, _todo_entity: TodoEntity) -> Result<(), DbError> {
unimplemented!("not implemented for the example")
}
}
trait DbAccess {
fn insert_todo(&self, todo_entity: TodoEntity) -> Result<(), DbError>;
}
struct NulledDb;
impl DbAccess for NulledDb {
fn insert_todo(&self, _todo_entity: TodoEntity) -> Result<(), DbError> {
Ok(())
}
}
}
use crate::todo_domain::NewTodo;
use crate::todo_repository::{TodoEntity, TodoRepository};
use asserting::prelude::*;
#[test]
fn insert_new_todo_item_into_repository() {
let todo_repo = TodoRepository::nulled();
let todo_tracker = todo_repo
.track_todos()
.unwrap_or_else(|err| panic!("could not create todo tracker: {err}"));
let inserted = todo_repo.insert(NewTodo {
subject: "remember the milk".into(),
});
assert_that!(inserted).is_ok();
let inserted_todos = todo_tracker
.output()
.unwrap_or_else(|err| panic!("could not read output of todo tracker: {err}"));
assert_that!(inserted_todos).contains_exactly([TodoEntity {
subject: "remember the milk".into(),
}]);
}