use super::{ListItemContent, ListItemContents};
use derive_more::{Constructor, From};
use numerals::roman::Roman;
use serde::{Deserialize, Serialize};
#[derive(
Constructor, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize,
)]
pub struct ListItem {
pub item_type: ListItemType,
pub suffix: ListItemSuffix,
pub pos: usize,
pub contents: ListItemContents,
pub attributes: ListItemAttributes,
}
impl ListItem {
pub fn is_unordered(&self) -> bool {
self.item_type.is_unordered()
}
pub fn is_ordered(&self) -> bool {
self.item_type.is_ordered()
}
pub fn to_prefix(&self) -> String {
self.item_type.to_prefix(self.pos, self.suffix)
}
pub fn is_todo(&self) -> bool {
self.attributes.todo_status.is_some()
}
pub fn compute_todo_progress(&self) -> Option<f32> {
self.contents
.iter()
.fold(None, |acc, c| match &c.element {
ListItemContent::InlineContent(_) => acc,
ListItemContent::List(list) => {
let (mut sum, mut count) =
list.items.iter().fold((0.0, 0), |acc, item| {
if let Some(p) =
item.element.compute_todo_progress()
{
(acc.0 + p, acc.1 + 1)
} else {
acc
}
});
if let Some((acc_sum, acc_count)) = acc {
sum += acc_sum;
count += acc_count;
}
if count > 0 {
Some((sum, count))
} else {
None
}
}
})
.map(|(sum, count)| sum / count as f32)
.or_else(|| self.to_todo_progress())
}
#[inline]
fn to_todo_progress(&self) -> Option<f32> {
if self.is_todo() && !self.is_todo_rejected() {
Some(if self.is_todo_partially_complete_1() {
0.25
} else if self.is_todo_partially_complete_2() {
0.5
} else if self.is_todo_partially_complete_3() {
0.75
} else if self.is_todo_complete() {
1.0
} else {
0.0
})
} else {
None
}
}
pub fn is_todo_incomplete(&self) -> bool {
matches!(
self.attributes.todo_status,
Some(ListItemTodoStatus::Incomplete)
)
}
pub fn is_todo_partially_complete(&self) -> bool {
self.is_todo_partially_complete_1()
|| self.is_todo_partially_complete_2()
|| self.is_todo_partially_complete_3()
}
pub fn is_todo_partially_complete_1(&self) -> bool {
matches!(
self.attributes.todo_status,
Some(ListItemTodoStatus::PartiallyComplete1)
)
}
pub fn is_todo_partially_complete_2(&self) -> bool {
matches!(
self.attributes.todo_status,
Some(ListItemTodoStatus::PartiallyComplete2)
)
}
pub fn is_todo_partially_complete_3(&self) -> bool {
matches!(
self.attributes.todo_status,
Some(ListItemTodoStatus::PartiallyComplete3)
)
}
pub fn is_todo_complete(&self) -> bool {
matches!(
self.attributes.todo_status,
Some(ListItemTodoStatus::Complete)
)
}
pub fn is_todo_rejected(&self) -> bool {
matches!(
self.attributes.todo_status,
Some(ListItemTodoStatus::Rejected)
)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ListItemSuffix {
None,
Period,
Paren,
}
impl ListItemSuffix {
pub fn as_char(self) -> Option<char> {
match self {
Self::Period => Some('.'),
Self::Paren => Some(')'),
Self::None => None,
}
}
}
impl Default for ListItemSuffix {
fn default() -> Self {
Self::None
}
}
#[derive(Clone, Debug, From, Eq, PartialEq, Serialize, Deserialize)]
pub enum ListItemType {
Ordered(OrderedListItemType),
Unordered(UnorderedListItemType),
}
impl ListItemType {
pub fn is_ordered(&self) -> bool {
match self {
Self::Ordered(_) => true,
_ => false,
}
}
pub fn is_unordered(&self) -> bool {
match self {
Self::Unordered(_) => true,
_ => false,
}
}
pub fn to_prefix(&self, pos: usize, suffix: ListItemSuffix) -> String {
match self {
Self::Ordered(x) => x.to_prefix(pos, suffix),
Self::Unordered(x) => x.to_prefix(suffix),
}
}
}
impl Default for ListItemType {
fn default() -> Self {
Self::Unordered(UnorderedListItemType::default())
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum UnorderedListItemType {
Hyphen,
Asterisk,
Other(String),
}
impl UnorderedListItemType {
pub fn to_prefix(&self, suffix: ListItemSuffix) -> String {
match &self {
Self::Hyphen => String::from("-"),
Self::Asterisk => String::from("*"),
Self::Other(prefix) => {
let mut base = prefix.to_string();
if let Some(c) = suffix.as_char() {
base.push(c);
}
base
}
}
}
}
impl Default for UnorderedListItemType {
fn default() -> Self {
Self::Hyphen
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum OrderedListItemType {
Number,
Pound,
LowercaseAlphabet,
UppercaseAlphabet,
LowercaseRoman,
UppercaseRoman,
}
impl OrderedListItemType {
pub fn to_prefix(&self, pos: usize, suffix: ListItemSuffix) -> String {
let mut base = match self {
Self::Number => (pos + 1).to_string(),
Self::Pound => String::from("#"),
Self::LowercaseAlphabet => pos_to_alphabet(pos, true),
Self::UppercaseAlphabet => pos_to_alphabet(pos, false),
Self::LowercaseRoman => {
format!("{:x}", Roman::from((pos + 1) as i16))
}
Self::UppercaseRoman => {
format!("{:X}", Roman::from((pos + 1) as i16))
}
};
if let Some(c) = suffix.as_char() {
base.push(c);
}
base
}
}
impl Default for OrderedListItemType {
fn default() -> Self {
Self::Number
}
}
fn pos_to_alphabet(pos: usize, to_lower: bool) -> String {
let mut s = String::new();
let mut i = pos as u32;
let base = if to_lower { 97 } else { 65 };
loop {
let offset = i % 26;
if let Some(c) = std::char::from_u32(base + offset) {
s.push(c);
}
i -= offset;
if i > 0 {
i = (i / 26) - 1;
} else {
break;
}
}
s.chars().rev().collect()
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub enum ListItemTodoStatus {
Incomplete,
PartiallyComplete1,
PartiallyComplete2,
PartiallyComplete3,
Complete,
Rejected,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct ListItemAttributes {
pub todo_status: Option<ListItemTodoStatus>,
}
#[cfg(test)]
mod tests {
use super::super::LE;
use super::*;
macro_rules! unordered_item {
($type:ident, $pos:expr, $content:expr) => {
ListItem::new(
ListItemType::from(UnorderedListItemType::$type),
ListItemSuffix::default(),
$pos,
$content.into(),
Default::default(),
)
};
($type:ident, $pos:expr) => {
ListItem::new(
ListItemType::from(UnorderedListItemType::$type),
ListItemSuffix::default(),
$pos,
vec![].into(),
Default::default(),
)
};
($type:ident) => {
ListItem::new(
ListItemType::from(UnorderedListItemType::$type),
ListItemSuffix::default(),
0,
vec![].into(),
Default::default(),
)
};
}
macro_rules! ordered_item {
($type:ident, $suffix:ident, $pos:expr, $content:expr) => {
ListItem::new(
ListItemType::from(OrderedListItemType::$type),
ListItemSuffix::$suffix,
$pos,
$content.into(),
Default::default(),
)
};
($type:ident, $suffix:ident, $pos:expr) => {
ListItem::new(
ListItemType::from(OrderedListItemType::$type),
ListItemSuffix::$suffix,
$pos,
vec![].into(),
Default::default(),
)
};
($type:ident, $suffix:ident) => {
ListItem::new(
ListItemType::from(OrderedListItemType::$type),
ListItemSuffix::$suffix,
0,
vec![].into(),
Default::default(),
)
};
($type:ident) => {
ListItem::new(
ListItemType::from(OrderedListItemType::$type),
ListItemSuffix::Paren,
0,
vec![].into(),
Default::default(),
)
};
}
macro_rules! other_item {
($value:expr, $suffix:ident, $pos:expr, $content:expr) => {
ListItem::new(
ListItemType::from(UnorderedListItemType::Other($value)),
ListItemSuffix::$suffix,
$pos,
$content.into(),
Default::default(),
)
};
($value:expr, $suffix:ident, $pos:expr) => {
ListItem::new(
ListItemType::from(UnorderedListItemType::Other($value)),
ListItemSuffix::$suffix,
$pos,
vec![].into(),
Default::default(),
)
};
($value:expr, $suffix:ident) => {
ListItem::new(
ListItemType::from(UnorderedListItemType::Other($value)),
ListItemSuffix::$suffix,
0,
vec![].into(),
Default::default(),
)
};
($value:expr) => {
ListItem::new(
ListItemType::from(UnorderedListItemType::Other($value)),
ListItemSuffix::default(),
0,
vec![].into(),
Default::default(),
)
};
() => {
ListItem::new(
ListItemType::from(UnorderedListItemType::Other(String::new())),
ListItemSuffix::default(),
0,
vec![].into(),
Default::default(),
)
};
}
fn todo_list_item(todo_status: ListItemTodoStatus) -> ListItem {
let mut item = ListItem::default();
item.attributes.todo_status = Some(todo_status);
item
}
macro_rules! todo_list_item {
($type:ident) => {
todo_list_item(ListItemTodoStatus::$type)
};
($type:ident, $($child:expr),+) => {
ListItem::new(
Default::default(),
Default::default(),
0,
vec![From::from(super::ListItemContent::List(
super::super::List::new(vec![$($child),+]),
))].into(),
ListItemAttributes {
todo_status: Some(ListItemTodoStatus::$type),
}
)
};
}
fn make_content(text: &str) -> ListItemContents {
let lc_text = LE::from(text.to_string());
vec![LE::from(ListItemContent::InlineContent(lc_text.into()))].into()
}
#[test]
fn is_ordered_should_return_true_if_ordered_prefix() {
assert!(
ordered_item!(Number).is_ordered(),
"Number should be ordered"
);
assert!(
ordered_item!(LowercaseAlphabet).is_ordered(),
"Lowercase alphabet should be ordered"
);
assert!(
ordered_item!(UppercaseAlphabet).is_ordered(),
"Uppercase alphabet should be ordered"
);
assert!(
ordered_item!(LowercaseRoman).is_ordered(),
"Lowercase roman numerals should be ordered"
);
assert!(
ordered_item!(UppercaseRoman).is_ordered(),
"Uppercase roman numerals should be ordered"
);
}
#[test]
fn is_ordered_should_return_false_if_unordered_prefix() {
assert!(
!unordered_item!(Hyphen).is_ordered(),
"Hyphen should not be ordered"
);
assert!(
!unordered_item!(Asterisk).is_ordered(),
"Asterisk should not be ordered"
);
assert!(!other_item!().is_ordered(), "Other should not be ordered");
}
#[test]
fn is_unordered_should_return_true_if_unordered_prefix() {
assert!(
unordered_item!(Hyphen).is_unordered(),
"Hyphen should be unordered"
);
assert!(
unordered_item!(Asterisk).is_unordered(),
"Asterisk should be unordered"
);
assert!(other_item!().is_unordered(), "Other should be unordered");
}
#[test]
fn is_unordered_should_return_false_if_ordered_prefix() {
assert!(
!ordered_item!(Number).is_unordered(),
"Number should not be unordered"
);
assert!(
!ordered_item!(LowercaseAlphabet).is_unordered(),
"Lowercase alphabet should not be unordered"
);
assert!(
!ordered_item!(UppercaseAlphabet).is_unordered(),
"Uppercase alphabet should not be unordered"
);
assert!(
!ordered_item!(LowercaseRoman).is_unordered(),
"Lowercase roman numerals should not be unordered"
);
assert!(
!ordered_item!(UppercaseRoman).is_unordered(),
"Uppercase roman numerals should not be unordered"
);
}
#[test]
fn pos_should_return_internal_position() {
assert_eq!(unordered_item!(Hyphen, 999).pos, 999);
assert_eq!(unordered_item!(Asterisk, 999).pos, 999);
assert_eq!(ordered_item!(Number, Paren, 999).pos, 999);
assert_eq!(ordered_item!(LowercaseAlphabet, Paren, 999).pos, 999);
assert_eq!(ordered_item!(UppercaseAlphabet, Paren, 999).pos, 999);
assert_eq!(ordered_item!(LowercaseRoman, Paren, 999).pos, 999);
assert_eq!(ordered_item!(UppercaseRoman, Paren, 999).pos, 999);
assert_eq!(other_item!(String::new(), None, 999).pos, 999);
}
#[test]
fn contents_should_return_internal_contents() {
assert_eq!(
unordered_item!(Hyphen, 0, make_content("test")).contents,
make_content("test"),
);
assert_eq!(
unordered_item!(Asterisk, 0, make_content("test")).contents,
make_content("test"),
);
assert_eq!(
ordered_item!(Number, Paren, 0, make_content("test")).contents,
make_content("test"),
);
assert_eq!(
ordered_item!(LowercaseAlphabet, Paren, 0, make_content("test"))
.contents,
make_content("test"),
);
assert_eq!(
ordered_item!(UppercaseAlphabet, Paren, 0, make_content("test"))
.contents,
make_content("test"),
);
assert_eq!(
ordered_item!(LowercaseRoman, Paren, 0, make_content("test"))
.contents,
make_content("test"),
);
assert_eq!(
ordered_item!(UppercaseRoman, Paren, 0, make_content("test"))
.contents,
make_content("test"),
);
assert_eq!(
other_item!(String::new(), None, 0, make_content("test")).contents,
make_content("test"),
);
}
#[test]
fn to_prefix_should_return_hyphen_if_hyphen_type() {
assert_eq!(unordered_item!(Hyphen).to_prefix(), "-");
}
#[test]
fn to_prefix_should_return_asterisk_if_asterisk_type() {
assert_eq!(unordered_item!(Asterisk).to_prefix(), "*");
}
#[test]
fn to_prefix_should_return_base_1_position_if_number_type() {
assert_eq!(ordered_item!(Number, Paren, 0).to_prefix(), "1)");
assert_eq!(ordered_item!(Number, Period, 0).to_prefix(), "1.");
assert_eq!(ordered_item!(Number, Paren, 27).to_prefix(), "28)");
assert_eq!(ordered_item!(Number, Period, 27).to_prefix(), "28.");
assert_eq!(ordered_item!(Number, Paren, 704).to_prefix(), "705)");
assert_eq!(ordered_item!(Number, Period, 704).to_prefix(), "705.");
}
#[test]
fn to_prefix_should_return_lowercase_alphabetic_string_if_lowercase_alphabetic_type(
) {
assert_eq!(
ordered_item!(LowercaseAlphabet, Paren, 0).to_prefix(),
"a)"
);
assert_eq!(
ordered_item!(LowercaseAlphabet, Period, 0).to_prefix(),
"a."
);
assert_eq!(
ordered_item!(LowercaseAlphabet, Paren, 27).to_prefix(),
"ab)"
);
assert_eq!(
ordered_item!(LowercaseAlphabet, Period, 27).to_prefix(),
"ab."
);
assert_eq!(
ordered_item!(LowercaseAlphabet, Paren, 730).to_prefix(),
"abc)"
);
assert_eq!(
ordered_item!(LowercaseAlphabet, Period, 730).to_prefix(),
"abc."
);
}
#[test]
fn to_prefix_should_return_uppercase_alphabetic_string_if_uppercase_alphabetic_type(
) {
assert_eq!(
ordered_item!(UppercaseAlphabet, Paren, 0).to_prefix(),
"A)"
);
assert_eq!(
ordered_item!(UppercaseAlphabet, Period, 0).to_prefix(),
"A."
);
assert_eq!(
ordered_item!(UppercaseAlphabet, Paren, 27).to_prefix(),
"AB)"
);
assert_eq!(
ordered_item!(UppercaseAlphabet, Period, 27).to_prefix(),
"AB."
);
assert_eq!(
ordered_item!(UppercaseAlphabet, Paren, 730).to_prefix(),
"ABC)"
);
assert_eq!(
ordered_item!(UppercaseAlphabet, Period, 730).to_prefix(),
"ABC."
);
}
#[test]
fn to_prefix_should_return_lowercase_roman_numeral_string_if_lowercase_roman_numeral_type(
) {
assert_eq!(ordered_item!(LowercaseRoman, Paren, 0).to_prefix(), "i)");
assert_eq!(ordered_item!(LowercaseRoman, Period, 0).to_prefix(), "i.");
assert_eq!(
ordered_item!(LowercaseRoman, Paren, 24).to_prefix(),
"xxv)"
);
assert_eq!(
ordered_item!(LowercaseRoman, Period, 24).to_prefix(),
"xxv."
);
assert_eq!(
ordered_item!(LowercaseRoman, Paren, 704).to_prefix(),
"dccv)"
);
assert_eq!(
ordered_item!(LowercaseRoman, Period, 704).to_prefix(),
"dccv."
);
}
#[test]
fn to_prefix_should_return_uppercase_roman_numeral_string_if_uppercase_roman_numeral_type(
) {
assert_eq!(ordered_item!(UppercaseRoman, Paren, 0).to_prefix(), "I)");
assert_eq!(ordered_item!(UppercaseRoman, Period, 0).to_prefix(), "I.");
assert_eq!(
ordered_item!(UppercaseRoman, Paren, 24).to_prefix(),
"XXV)"
);
assert_eq!(
ordered_item!(UppercaseRoman, Period, 24).to_prefix(),
"XXV."
);
assert_eq!(
ordered_item!(UppercaseRoman, Paren, 704).to_prefix(),
"DCCV)"
);
assert_eq!(
ordered_item!(UppercaseRoman, Period, 704).to_prefix(),
"DCCV."
);
}
#[test]
fn to_prefix_should_return_internal_value_with_suffix_if_other_type() {
assert_eq!(
other_item!("prefix".to_string(), None, 0).to_prefix(),
"prefix"
);
assert_eq!(
other_item!("prefix".to_string(), None, 27).to_prefix(),
"prefix"
);
assert_eq!(
other_item!("prefix".to_string(), None, 99).to_prefix(),
"prefix"
);
assert_eq!(
other_item!("prefix".to_string(), Period, 0).to_prefix(),
"prefix."
);
assert_eq!(
other_item!("prefix".to_string(), Period, 27).to_prefix(),
"prefix."
);
assert_eq!(
other_item!("prefix".to_string(), Period, 99).to_prefix(),
"prefix."
);
assert_eq!(
other_item!("prefix".to_string(), Paren, 0).to_prefix(),
"prefix)"
);
assert_eq!(
other_item!("prefix".to_string(), Paren, 27).to_prefix(),
"prefix)"
);
assert_eq!(
other_item!("prefix".to_string(), Paren, 99).to_prefix(),
"prefix)"
);
}
#[test]
fn is_todo_should_return_true_if_contains_any_todo_attribute() {
assert!(todo_list_item!(Incomplete).is_todo());
assert!(todo_list_item!(PartiallyComplete1).is_todo());
assert!(todo_list_item!(PartiallyComplete2).is_todo());
assert!(todo_list_item!(PartiallyComplete3).is_todo());
assert!(todo_list_item!(Complete).is_todo());
assert!(todo_list_item!(Rejected).is_todo());
}
#[test]
fn is_todo_should_return_false_if_does_not_contain_any_todo_attribute() {
assert!(!ListItem::default().is_todo());
}
#[test]
fn compute_todo_progress_should_use_own_progress_if_no_children() {
assert_eq!(
Some(0.0),
todo_list_item!(Incomplete).compute_todo_progress()
);
assert_eq!(
Some(0.25),
todo_list_item!(PartiallyComplete1).compute_todo_progress()
);
assert_eq!(
Some(0.5),
todo_list_item!(PartiallyComplete2).compute_todo_progress()
);
assert_eq!(
Some(0.75),
todo_list_item!(PartiallyComplete3).compute_todo_progress()
);
assert_eq!(
Some(1.0),
todo_list_item!(Complete).compute_todo_progress()
);
assert_eq!(None, todo_list_item!(Rejected).compute_todo_progress());
assert_eq!(None, ListItem::default().compute_todo_progress());
}
#[test]
fn compute_todo_progress_should_use_children_progress_if_has_children() {
assert_eq!(
todo_list_item!(
Incomplete,
LE::from(todo_list_item!(Rejected)),
LE::from(todo_list_item!(Complete)),
LE::from(todo_list_item!(PartiallyComplete1)),
LE::from(todo_list_item!(PartiallyComplete2)),
LE::from(todo_list_item!(PartiallyComplete3)),
LE::from(todo_list_item!(Incomplete))
)
.compute_todo_progress(),
Some((1.0 + 0.25 + 0.5 + 0.75 + 0.0) / 5.0)
);
}
#[test]
fn compute_todo_progress_should_support_deeper_children() {
assert_eq!(
todo_list_item!(
Incomplete,
LE::from(todo_list_item!(
Rejected,
LE::from(todo_list_item!(Rejected)),
LE::from(todo_list_item!(Complete)),
LE::from(todo_list_item!(PartiallyComplete1)),
LE::from(todo_list_item!(PartiallyComplete2)),
LE::from(todo_list_item!(PartiallyComplete3)),
LE::from(todo_list_item!(Incomplete))
))
)
.compute_todo_progress(),
Some((1.0 + 0.25 + 0.5 + 0.75 + 0.0) / 5.0)
);
}
#[test]
fn is_todo_incomplete_should_return_true_if_is_incomplete() {
assert!(todo_list_item!(Incomplete).is_todo_incomplete());
}
#[test]
fn is_todo_incomplete_should_return_false_if_not_incomplete() {
assert!(!todo_list_item!(PartiallyComplete1).is_todo_incomplete());
assert!(!todo_list_item!(PartiallyComplete2).is_todo_incomplete());
assert!(!todo_list_item!(PartiallyComplete3).is_todo_incomplete());
assert!(!todo_list_item!(Complete).is_todo_incomplete());
assert!(!todo_list_item!(Rejected).is_todo_incomplete());
assert!(!ListItem::default().is_todo_incomplete());
}
#[test]
fn is_todo_partially_complete_should_return_true_if_is_any_partially_complete(
) {
assert!(
todo_list_item!(PartiallyComplete1).is_todo_partially_complete()
);
assert!(
todo_list_item!(PartiallyComplete2).is_todo_partially_complete()
);
assert!(
todo_list_item!(PartiallyComplete3).is_todo_partially_complete()
);
}
#[test]
fn is_todo_partially_complete_should_return_false_if_not_all_partially_completes(
) {
assert!(!todo_list_item!(Incomplete).is_todo_partially_complete());
assert!(!todo_list_item!(Complete).is_todo_partially_complete());
assert!(!todo_list_item!(Rejected).is_todo_partially_complete());
assert!(!ListItem::default().is_todo_partially_complete());
}
#[test]
fn is_todo_partially_complete_1_should_return_true_if_is_partially_complete_1(
) {
assert!(
todo_list_item!(PartiallyComplete1).is_todo_partially_complete_1()
);
}
#[test]
fn is_todo_partially_complete_1_should_return_false_if_not_partially_complete_1(
) {
assert!(!todo_list_item!(Incomplete).is_todo_partially_complete_1());
assert!(
!todo_list_item!(PartiallyComplete2).is_todo_partially_complete_1()
);
assert!(
!todo_list_item!(PartiallyComplete3).is_todo_partially_complete_1()
);
assert!(!todo_list_item!(Complete).is_todo_partially_complete_1());
assert!(!todo_list_item!(Rejected).is_todo_partially_complete_1());
assert!(!ListItem::default().is_todo_partially_complete_1());
}
#[test]
fn is_todo_partially_complete_2_should_return_true_if_is_partially_complete_2(
) {
assert!(
todo_list_item!(PartiallyComplete2).is_todo_partially_complete_2()
);
}
#[test]
fn is_todo_partially_complete_2_should_return_false_if_not_partially_complete_2(
) {
assert!(!todo_list_item!(Incomplete).is_todo_partially_complete_2());
assert!(
!todo_list_item!(PartiallyComplete1).is_todo_partially_complete_2()
);
assert!(
!todo_list_item!(PartiallyComplete3).is_todo_partially_complete_2()
);
assert!(!todo_list_item!(Complete).is_todo_partially_complete_2());
assert!(!todo_list_item!(Rejected).is_todo_partially_complete_2());
assert!(!ListItem::default().is_todo_partially_complete_2());
}
#[test]
fn is_todo_partially_complete_3_should_return_true_if_is_partially_complete_3(
) {
assert!(
todo_list_item!(PartiallyComplete3).is_todo_partially_complete_3()
);
}
#[test]
fn is_todo_partially_complete_3_should_return_false_if_not_partially_complete_3(
) {
assert!(!todo_list_item!(Incomplete).is_todo_partially_complete_3());
assert!(
!todo_list_item!(PartiallyComplete1).is_todo_partially_complete_3()
);
assert!(
!todo_list_item!(PartiallyComplete2).is_todo_partially_complete_3()
);
assert!(!todo_list_item!(Complete).is_todo_partially_complete_3());
assert!(!todo_list_item!(Rejected).is_todo_partially_complete_3());
assert!(!ListItem::default().is_todo_partially_complete_3());
}
#[test]
fn is_todo_complete_should_return_true_if_is_complete() {
assert!(todo_list_item!(Complete).is_todo_complete());
}
#[test]
fn is_todo_complete_should_return_false_if_not_complete() {
assert!(!todo_list_item!(Incomplete).is_todo_complete());
assert!(!todo_list_item!(PartiallyComplete1).is_todo_complete());
assert!(!todo_list_item!(PartiallyComplete2).is_todo_complete());
assert!(!todo_list_item!(PartiallyComplete3).is_todo_complete());
assert!(!todo_list_item!(Rejected).is_todo_complete());
assert!(!ListItem::default().is_todo_complete());
}
#[test]
fn is_todo_rejected_should_return_true_if_is_rejected() {
assert!(todo_list_item!(Rejected).is_todo_rejected());
}
#[test]
fn is_todo_rejected_should_return_false_if_not_rejected() {
assert!(!todo_list_item!(Incomplete).is_todo_rejected());
assert!(!todo_list_item!(PartiallyComplete1).is_todo_rejected());
assert!(!todo_list_item!(PartiallyComplete2).is_todo_rejected());
assert!(!todo_list_item!(PartiallyComplete3).is_todo_rejected());
assert!(!todo_list_item!(Complete).is_todo_rejected());
assert!(!ListItem::default().is_todo_rejected());
}
}