use serde::{Deserialize, Serialize};
use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct LineTypes {
pub code: bool,
pub tests: bool,
pub examples: bool,
pub docs: bool,
pub comments: bool,
pub blanks: bool,
pub total: bool,
}
impl Default for LineTypes {
fn default() -> Self {
Self {
code: true,
tests: true,
examples: false,
docs: true,
comments: false,
blanks: false,
total: true,
}
}
}
impl LineTypes {
pub fn new() -> Self {
Self {
code: false,
tests: false,
examples: false,
docs: false,
comments: false,
blanks: false,
total: true, }
}
pub fn everything() -> Self {
Self {
code: true,
tests: true,
examples: true,
docs: true,
comments: true,
blanks: true,
total: true,
}
}
pub fn none() -> Self {
Self {
code: false,
tests: false,
examples: false,
docs: false,
comments: false,
blanks: false,
total: false,
}
}
pub fn code_only() -> Self {
Self::new().with_code()
}
pub fn tests_only() -> Self {
Self::new().with_tests()
}
pub fn examples_only() -> Self {
Self::new().with_examples()
}
pub fn logic_only() -> Self {
Self {
code: true,
tests: true,
examples: true,
docs: false,
comments: false,
blanks: false,
total: true,
}
}
pub fn with_code(mut self) -> Self {
self.code = true;
self
}
pub fn with_tests(mut self) -> Self {
self.tests = true;
self
}
pub fn with_examples(mut self) -> Self {
self.examples = true;
self
}
pub fn with_docs(mut self) -> Self {
self.docs = true;
self
}
pub fn with_comments(mut self) -> Self {
self.comments = true;
self
}
pub fn with_blanks(mut self) -> Self {
self.blanks = true;
self
}
pub fn with_total(mut self) -> Self {
self.total = true;
self
}
pub fn without_total(mut self) -> Self {
self.total = false;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum Aggregation {
#[default]
Total,
ByCrate,
ByModule,
ByFile,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum OrderBy {
#[default]
Label,
Code,
Tests,
Examples,
Docs,
Comments,
Blanks,
Total,
}
impl FromStr for OrderBy {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"label" | "name" | "path" => Ok(OrderBy::Label),
"code" => Ok(OrderBy::Code),
"tests" | "test" => Ok(OrderBy::Tests),
"examples" | "example" => Ok(OrderBy::Examples),
"docs" | "doc" => Ok(OrderBy::Docs),
"comments" | "comment" => Ok(OrderBy::Comments),
"blanks" | "blank" => Ok(OrderBy::Blanks),
"total" => Ok(OrderBy::Total),
_ => Err(format!("Unknown order field: {}", s)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum OrderDirection {
#[default]
Ascending,
Descending,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Ordering {
pub by: OrderBy,
pub direction: OrderDirection,
}
impl Default for Ordering {
fn default() -> Self {
Self {
by: OrderBy::Label,
direction: OrderDirection::Ascending,
}
}
}
impl Ordering {
pub fn by_label() -> Self {
Self::default()
}
pub fn by_code() -> Self {
Self {
by: OrderBy::Code,
direction: OrderDirection::Descending,
}
}
pub fn by_tests() -> Self {
Self {
by: OrderBy::Tests,
direction: OrderDirection::Descending,
}
}
pub fn by_total() -> Self {
Self {
by: OrderBy::Total,
direction: OrderDirection::Descending,
}
}
pub fn ascending(mut self) -> Self {
self.direction = OrderDirection::Ascending;
self
}
pub fn descending(mut self) -> Self {
self.direction = OrderDirection::Descending;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_line_types_default() {
let lt = LineTypes::default();
assert!(lt.code);
assert!(lt.tests);
assert!(!lt.examples); assert!(lt.docs);
assert!(!lt.comments); assert!(!lt.blanks); assert!(lt.total);
}
#[test]
fn test_line_types_none() {
let lt = LineTypes::none();
assert!(!lt.code);
assert!(!lt.tests);
assert!(!lt.examples);
assert!(!lt.docs);
assert!(!lt.comments);
assert!(!lt.blanks);
assert!(!lt.total);
}
#[test]
fn test_line_types_everything() {
let lt = LineTypes::everything();
assert!(lt.code);
assert!(lt.tests);
assert!(lt.examples);
assert!(lt.docs);
assert!(lt.comments);
assert!(lt.blanks);
assert!(lt.total);
}
#[test]
fn test_line_types_builder() {
let lt = LineTypes::new().with_code().with_tests();
assert!(lt.code);
assert!(lt.tests);
assert!(!lt.examples);
assert!(!lt.docs);
assert!(!lt.comments);
assert!(!lt.blanks);
assert!(lt.total); }
#[test]
fn test_line_types_code_only() {
let lt = LineTypes::code_only();
assert!(lt.code);
assert!(!lt.tests);
assert!(!lt.examples);
assert!(!lt.docs);
assert!(!lt.comments);
assert!(!lt.blanks);
assert!(lt.total); }
#[test]
fn test_line_types_logic_only() {
let lt = LineTypes::logic_only();
assert!(lt.code);
assert!(lt.tests);
assert!(lt.examples);
assert!(!lt.docs);
assert!(!lt.comments);
assert!(!lt.blanks);
assert!(lt.total);
}
#[test]
fn test_ordering_default() {
let ordering = Ordering::default();
assert_eq!(ordering.by, OrderBy::Label);
assert_eq!(ordering.direction, OrderDirection::Ascending);
}
#[test]
fn test_ordering_by_code() {
let ordering = Ordering::by_code();
assert_eq!(ordering.by, OrderBy::Code);
assert_eq!(ordering.direction, OrderDirection::Descending);
}
#[test]
fn test_ordering_direction_builder() {
let ordering = Ordering::by_total().ascending();
assert_eq!(ordering.by, OrderBy::Total);
assert_eq!(ordering.direction, OrderDirection::Ascending);
}
#[test]
fn test_order_by_from_str() {
assert_eq!(OrderBy::from_str("code").unwrap(), OrderBy::Code);
assert_eq!(OrderBy::from_str("tests").unwrap(), OrderBy::Tests);
assert_eq!(OrderBy::from_str("total").unwrap(), OrderBy::Total);
assert_eq!(OrderBy::from_str("label").unwrap(), OrderBy::Label);
assert_eq!(OrderBy::from_str("docs").unwrap(), OrderBy::Docs);
assert_eq!(OrderBy::from_str("comments").unwrap(), OrderBy::Comments);
assert_eq!(OrderBy::from_str("blanks").unwrap(), OrderBy::Blanks);
assert!(OrderBy::from_str("invalid").is_err());
}
}