From 5958f1551bbe61910b151b40ed0ddb415af6ba14 Mon Sep 17 00:00:00 2001 From: jutty Date: Sat, 10 Jan 2026 05:42:36 -0300 Subject: [PATCH] Expand test coverage --- .justfile | 26 +++- src/router.rs | 1 + src/router/handlers/graph.rs | 6 + src/router/handlers/navigation.rs | 9 ++ src/syntax/content/parser/context.rs | 13 ++ src/syntax/content/parser/context/anchor.rs | 37 ++++++ src/syntax/content/parser/context/list.rs | 24 +++- src/syntax/content/parser/lexeme.rs | 126 +++++++++++++++++-- src/syntax/content/parser/point.rs | 11 ++ src/syntax/content/parser/state.rs | 53 ++++++++ src/syntax/content/parser/token.rs | 3 - src/syntax/content/parser/token/anchor.rs | 55 ++++++-- src/syntax/content/parser/token/bold.rs | 14 +++ src/syntax/content/parser/token/checkbox.rs | 17 +++ src/syntax/content/parser/token/code.rs | 14 +++ src/syntax/content/parser/token/header.rs | 11 ++ src/syntax/content/parser/token/item.rs | 43 +++++++ src/syntax/content/parser/token/linebreak.rs | 13 ++ src/syntax/content/parser/token/list.rs | 18 +++ src/syntax/content/parser/token/literal.rs | 24 ++++ src/syntax/content/parser/token/oblique.rs | 17 +++ src/syntax/content/parser/token/paragraph.rs | 23 ++++ src/syntax/content/parser/token/preformat.rs | 23 ++++ src/syntax/content/parser/token/span.rs | 84 ------------- src/syntax/content/parser/token/strike.rs | 17 +++ src/syntax/content/parser/token/underline.rs | 17 +++ static/graph.toml | 3 + 27 files changed, 593 insertions(+), 109 deletions(-) diff --git a/.justfile b/.justfile index 8f71fc5..f9981d9 100644 --- a/.justfile +++ b/.justfile @@ -45,6 +45,20 @@ quick-assess-run-watch: alias qr := quick-assess-run-watch +[private] +quick-test-cover: + {{ cover_cmd }} --no-report -- --skip 'serial_tests::' + {{ cover_cmd }} --no-report -- --test 'serial_tests::' --test-threads 1 + {{ cover_cmd }} report --html + @{{ cover_cmd }} report | tail -1 | awk '{ print " [ Regions:", $4, "• Functions:", $7, "• Lines:", $10, "]" }' + +# Quickly update coverage reports (inaccurate) +[group: 'assess'] +quick-test-cover-watch: + {{ watch_cmd }} {{ just_cmd }} quick-test-cover + +alias qo := quick-test-cover-watch + # Format all files [group: 'develop'] format: @@ -110,7 +124,7 @@ alias or := cover-report # Open coverage report [group: 'develop'] -cover-open: test-cover +cover-open: {{ cover_cmd }} report --open alias oo := cover-open @@ -176,10 +190,16 @@ test: alias t := test +# Clean test coverage data +[group: 'assess'] +test-cover-clean: + {{ cover_cmd }} clean + +alias oc := test-cover-clean + # Run tests with coverage [group: 'assess'] -test-cover: - {{ cover_cmd }} clean +test-cover: test-cover-clean {{ cover_cmd }} --no-report -- --skip 'serial_tests::' {{ cover_cmd }} --no-report -- --test 'serial_tests::' --test-threads 1 diff --git a/src/router.rs b/src/router.rs index 2c085f0..f35ed97 100644 --- a/src/router.rs +++ b/src/router.rs @@ -117,6 +117,7 @@ mod tests { "/", "/about", "/tree", + "/data", "/node/Syntax", "/static/style.css", "/static/favicon.svg", diff --git a/src/router/handlers/graph.rs b/src/router/handlers/graph.rs index e48ff17..a0b3589 100644 --- a/src/router/handlers/graph.rs +++ b/src/router/handlers/graph.rs @@ -88,4 +88,10 @@ mod tests { let response = node(Path("syntax".to_string())).await; assert_eq!(response.status(), StatusCode::PERMANENT_REDIRECT); } + + #[tokio::test] + async fn docs_redirect() { + let response = node(Path("docs".to_string())).await; + assert_eq!(response.status(), StatusCode::PERMANENT_REDIRECT); + } } diff --git a/src/router/handlers/navigation.rs b/src/router/handlers/navigation.rs index 919c49c..73f39b8 100644 --- a/src/router/handlers/navigation.rs +++ b/src/router/handlers/navigation.rs @@ -76,4 +76,13 @@ mod tests { let response = search(query).await; assert!(response.status_code() == StatusCode::PERMANENT_REDIRECT); } + + #[tokio::test] + async fn dedicated_redirect_endpoint() { + let query = Form(Query { + node: String::from("syNTaX"), + }); + let response = redirect(query).await; + assert!(response.status_code() == StatusCode::PERMANENT_REDIRECT); + } } diff --git a/src/syntax/content/parser/context.rs b/src/syntax/content/parser/context.rs index a94c2fc..aeda3cd 100644 --- a/src/syntax/content/parser/context.rs +++ b/src/syntax/content/parser/context.rs @@ -47,3 +47,16 @@ pub fn close(state: &State, tokens: &mut Vec) { Block::None => (), } } + +#[cfg(test)] +mod tests { + use crate::syntax::content::parser::{context::Block, state::State}; + + #[test] + #[should_panic(expected = "End of input with open list")] + fn open_list_eoi() { + let mut state = State::default(); + state.context.block = Block::List; + super::close(&state, &mut vec![]); + } +} diff --git a/src/syntax/content/parser/context/anchor.rs b/src/syntax/content/parser/context/anchor.rs index 230bad0..077e1f9 100644 --- a/src/syntax/content/parser/context/anchor.rs +++ b/src/syntax/content/parser/context/anchor.rs @@ -207,6 +207,43 @@ mod tests { ); } + #[test] + fn leading_multiword_anchor() { + assert_eq!( + read("interactions are |basic elements| of systems"), + r#"

interactions are basic elements of systems

"# + ); + } + + #[test] + fn explicit_end_of_destination() { + assert_eq!( + read("interactions are |basic elements|BasicElements| of systems"), + r#"

interactions are basic elements of systems

"# + ); + } + + #[test] + fn explicit_end_of_external_destination() { + assert_eq!( + read("this |anchor example|https://example.com| is external"), + r#"

this anchor example is external

"# + ); + } + + #[test] + fn anchor_destination_at_eoi() { + assert_eq!(read("a |b c|d"), r#"

a b c

"#); + } + + #[test] + fn external_anchor_destination_at_eoi() { + assert_eq!( + read("a b|https://example.com"), + r#"

a b

"# + ); + } + #[test] fn nonleading_plural_anchor_at_eoi() { assert_eq!( diff --git a/src/syntax/content/parser/context/list.rs b/src/syntax/content/parser/context/list.rs index 0b70fb7..13e4141 100644 --- a/src/syntax/content/parser/context/list.rs +++ b/src/syntax/content/parser/context/list.rs @@ -85,7 +85,12 @@ pub fn parse( #[cfg(test)] mod tests { - use crate::{syntax::content::parser, types::Graph}; + use crate::{ + syntax::content::parser::{ + self, context::list::parse, lexeme::Lexeme, state::State, + }, + types::{Config, Graph}, + }; fn read(input: &str) -> String { parser::read(input, &Graph::new(None).meta.config) @@ -260,4 +265,21 @@ mod tests { \n\n" ); } + + #[test] + #[should_panic( + expected = "List context parser called to handle non-list context" + )] + fn bad_context() { + let mut state = State::default(); + let lexemes = Lexeme::collect(&["a", "b", "c"].map(str::to_string)); + let config = Config::default(); + parse( + &Lexeme::default(), + &mut state, + &mut vec![], + &mut lexemes.iter().peekable(), + &config, + ); + } } diff --git a/src/syntax/content/parser/lexeme.rs b/src/syntax/content/parser/lexeme.rs index 648c6fb..9f6267a 100644 --- a/src/syntax/content/parser/lexeme.rs +++ b/src/syntax/content/parser/lexeme.rs @@ -196,7 +196,7 @@ impl Lexeme { text: last.clone(), next: String::default(), third: String::default(), - first: false, + first: segments.is_empty(), last: true, }; @@ -241,12 +241,12 @@ impl fmt::Display for Lexeme { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use crate::dev::wrap; - let properties = if self.first { - "[F] " + let properties = if self.last && self.first { + "[S] " } else if self.last { "[L] " - } else if self.last && self.first { - "[FL] " + } else if self.first { + "[F] " } else { "" }; @@ -254,11 +254,11 @@ impl fmt::Display for Lexeme { let next_display = if self.last { " " } else if self.third.is_empty() { - &format!("-> {} -! EOI", wrap(&self.next)) + &format!(" -> {} ", wrap(&self.next)) } else { - &format!("-> {} -> {}", wrap(&self.next), wrap(&self.third)) + &format!(" -> {} -> {}", wrap(&self.next), wrap(&self.third)) }; - write!(f, "Lx {}{} {}", properties, wrap(&self.text), next_display) + write!(f, "Lx {}{}{}", properties, wrap(&self.text), next_display) } } @@ -319,4 +319,114 @@ mod tests { let lexeme = Lexeme::new(payload, "", ""); assert_eq!(lexeme.count_char('j'), 3); } + + #[test] + fn mutate_text() { + let mut lexeme = Lexeme::new("b71Je", "I6y3i", "LC8na"); + lexeme.mutate_text("qkjjK2"); + assert_eq!(lexeme.text(), "qkjjK2"); + } + + #[test] + fn third_as_char() { + let lexeme_a = Lexeme::new("1", "2", "3"); + assert_eq!(lexeme_a.third_as_char().unwrap(), '3'); + let lexeme_c = Lexeme::new("a", "b", ""); + assert!(lexeme_c.third_as_char().is_none()); + } + + #[test] + fn match_third_char() { + let lexeme = Lexeme::new("1", "2", "3"); + assert!(lexeme.match_third_char('3')); + } + + #[test] + fn match_next_either_char() { + let lexeme = Lexeme::new("1", "2", "3"); + assert!(lexeme.match_next_either_char('x', '2')); + assert!(lexeme.match_next_either_char('2', 'x')); + } + + #[test] + fn match_triple() { + let lexeme = Lexeme::new("1", "2", "3"); + assert!(lexeme.match_char_triple('1', '2', '3')); + } + + #[test] + fn is_punctuation() { + let delimiters = Delimiters::default(); + let mut lexemes: Vec = vec![]; + for p in delimiters.punctuation { + lexemes.push(Lexeme::new(&p.to_string(), "", "")); + } + for lexeme in lexemes { + assert!(lexeme.is_punctuation()); + } + } + + #[test] + fn is_next_punctuation() { + let delimiters = Delimiters::default(); + let mut lexemes: Vec = vec![]; + for p in delimiters.punctuation { + lexemes.push(Lexeme::new("", &p.to_string(), "")); + } + for lexeme in lexemes { + assert!(lexeme.is_next_punctuation()); + } + } + + #[test] + fn match_last_char() { + let lexeme = Lexeme::new("qYBWuNX", "", ""); + assert!(lexeme.match_last_char('X')); + } + + #[test] + fn match_next_last_char() { + let lexeme = Lexeme::new("", "teDAqVx", ""); + assert!(lexeme.match_next_first_char('t')); + } + + #[test] + fn display() { + let input = ["pcdA", "o32X", "kz2i", "79Lz"].map(str::to_string); + let lexemes = Lexeme::collect(&input); + + let first = lexemes.first().unwrap(); + let second = lexemes.get(1).unwrap(); + let third = lexemes.get(2).unwrap(); + let last = lexemes.last().unwrap(); + + assert_eq!( + format!("{first}"), + String::from("Lx [F] pcdA -> o32X -> kz2i"), + "first" + ); + assert_eq!( + format!("{second}"), + String::from("Lx o32X -> kz2i -> 79Lz"), + "second" + ); + assert_eq!( + format!("{third}"), + String::from("Lx kz2i -> 79Lz "), + "third" + ); + assert_eq!( + format!("{last}"), + String::from("Lx [L] 79Lz "), + "last" + ); + + let input_single = ["9fOC"].map(str::to_string); + + let lexemes_single = Lexeme::collect(&input_single); + let single = lexemes_single.first().unwrap(); + println!("{single:#?}"); + assert!(input_single.to_vec().len() == 1); + assert_eq!(format!("{single}"), "Lx [S] 9fOC "); + } } diff --git a/src/syntax/content/parser/point.rs b/src/syntax/content/parser/point.rs index 9d9b10d..aaf5a11 100644 --- a/src/syntax/content/parser/point.rs +++ b/src/syntax/content/parser/point.rs @@ -103,4 +103,15 @@ mod tests { fn trailing_oblique_with_newline() { assert_eq!(read("see _acks_\n"), "

see acks

"); } + + #[test] + fn underline() { + assert_eq!(read("__u__"), "

u

"); + } + + #[test] + fn checkbox() { + assert_eq!(read("[ ]"), r#"

"#); + assert_eq!(read("[x]"), r#"

"#); + } } diff --git a/src/syntax/content/parser/state.rs b/src/syntax/content/parser/state.rs index 69318a7..bd620c8 100644 --- a/src/syntax/content/parser/state.rs +++ b/src/syntax/content/parser/state.rs @@ -94,3 +94,56 @@ impl Default for State { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn anchor_buffer_display() { + let buffer = AnchorBuffer::default(); + println!("{buffer:#?}"); + println!("{buffer}"); + assert_eq!( + format!("{buffer}"), + "AnchorBuffer [] >> Anchor -> " + ); + } + + #[test] + fn anchor_buffer_display_with_text_set() { + let mut buffer = AnchorBuffer::default(); + buffer.text = String::from("mX8Z7yWmsK"); + println!("{buffer:#?}"); + println!("{buffer}"); + assert_eq!( + format!("{buffer}"), + r#"AnchorBuffer [text: "mX8Z7yWmsK"] >> Anchor -> "# + ); + } + + #[test] + fn anchor_buffer_display_with_destination_set() { + let mut buffer = AnchorBuffer::default(); + buffer.destination = String::from("VP2aqGngAq"); + println!("{buffer:#?}"); + println!("{buffer}"); + assert_eq!( + format!("{buffer}"), + r#"AnchorBuffer [, dest: "VP2aqGngAq"] >> Anchor -> "# + ); + } + + #[test] + fn anchor_buffer_display_with_text_and_destination_set() { + let mut buffer = AnchorBuffer::default(); + buffer.text = String::from("ECJrzgkBHg"); + buffer.destination = String::from("9dy6gQ2g3E"); + println!("{buffer:#?}"); + println!("{buffer}"); + assert_eq!( + format!("{buffer}"), + r#"AnchorBuffer [text: "ECJrzgkBHg", dest: "9dy6gQ2g3E"] >> Anchor -> "# + ); + } +} diff --git a/src/syntax/content/parser/token.rs b/src/syntax/content/parser/token.rs index 9cead7c..c02f937 100644 --- a/src/syntax/content/parser/token.rs +++ b/src/syntax/content/parser/token.rs @@ -31,7 +31,6 @@ pub enum Token { Oblique(oblique::Oblique), Paragraph(paragraph::Paragraph), PreFormat(preformat::PreFormat), - Span(span::Span), Underline(underline::Underline), } @@ -51,7 +50,6 @@ impl Token { Token::Oblique(ref d) => d.render(), Token::Paragraph(ref d) => d.render(), Token::PreFormat(ref d) => d.render(), - Token::Span(ref d) => d.render(), Token::Underline(ref d) => d.render(), } } @@ -73,7 +71,6 @@ impl std::fmt::Display for Token { Token::Oblique(ref d) => format!("{d}"), Token::Paragraph(ref d) => format!("{d}"), Token::PreFormat(ref d) => format!("{d}"), - Token::Span(ref d) => format!("{d}"), Token::Underline(ref d) => format!("{d}"), }; diff --git a/src/syntax/content/parser/token/anchor.rs b/src/syntax/content/parser/token/anchor.rs index 51dcf59..d079ac6 100644 --- a/src/syntax/content/parser/token/anchor.rs +++ b/src/syntax/content/parser/token/anchor.rs @@ -45,15 +45,22 @@ impl std::fmt::Display for Anchor { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { use crate::dev::wrap; + let wrapped_text = wrap(&self.text); + let display_text = if wrapped_text.is_empty() { + "" + } else { + wrapped_text.as_str() + }; + let display_destination = match self.destination { Some(ref destination) => { if destination.is_empty() { - "" + String::from("") } else { - destination + format!("{destination:?}") } }, - None => "", + None => String::from(""), }; let mut tail = String::default(); @@ -68,13 +75,7 @@ impl std::fmt::Display for Anchor { tail.push_str(" +External"); } - write!( - f, - "Anchor {:?} -> {:?}{}", - wrap(&self.text), - display_destination, - tail - ) + write!(f, "Anchor {display_text} -> {display_destination}{tail}") } } @@ -107,6 +108,8 @@ impl Anchor { #[cfg(test)] mod tests { + use crate::syntax::content::parser::token::Token; + use super::*; #[test] @@ -133,4 +136,36 @@ mod tests { let anchor = Anchor::default(); drop(anchor.render()); } + + #[test] + fn token_display() { + let mut anchor = Anchor::default(); + assert_eq!( + format!("{}", Token::Anchor(anchor.clone())), + "Tk:Anchor -> ", + ); + + anchor.text = String::from("FsJAt RTggA"); + assert_eq!( + format!("{}", Token::Anchor(anchor.clone())), + "Tk:Anchor 'FsJAt RTggA' -> ", + ); + + anchor.text = String::from("wPVo1 0OmYm"); + anchor.destination = Some(String::from("M1UEp 1gbfr")); + assert_eq!( + format!("{}", Token::Anchor(anchor.clone())), + r#"Tk:Anchor 'wPVo1 0OmYm' -> "M1UEp 1gbfr""#, + ); + + anchor.balanced = true; + anchor.leading = true; + anchor.external = true; + + assert_eq!( + format!("{}", Token::Anchor(anchor.clone())), + "Tk:Anchor 'wPVo1 0OmYm' -> \"M1UEp 1gbfr\" \ + +Leading +Balanced +External", + ); + } } diff --git a/src/syntax/content/parser/token/bold.rs b/src/syntax/content/parser/token/bold.rs index 09902f2..15f2ec2 100644 --- a/src/syntax/content/parser/token/bold.rs +++ b/src/syntax/content/parser/token/bold.rs @@ -40,6 +40,8 @@ impl std::fmt::Display for Bold { #[cfg(test)] mod tests { + use crate::syntax::content::parser::token::Token; + use super::*; #[test] @@ -58,4 +60,16 @@ mod tests { fn lex() { Bold::lex(&Lexeme::default()); } + + #[test] + fn token_display() { + let mut bold = Bold::new(true); + assert_eq!(format!("{}", Token::Bold(bold.clone())), "Tk:Bold [open]"); + + bold.open = false; + assert_eq!( + format!("{}", Token::Bold(bold.clone())), + "Tk:Bold [closed]" + ); + } } diff --git a/src/syntax/content/parser/token/checkbox.rs b/src/syntax/content/parser/token/checkbox.rs index 290432d..e875e49 100644 --- a/src/syntax/content/parser/token/checkbox.rs +++ b/src/syntax/content/parser/token/checkbox.rs @@ -44,6 +44,8 @@ impl std::fmt::Display for CheckBox { #[cfg(test)] mod tests { + use crate::syntax::content::parser::token::Token; + use super::*; #[test] @@ -54,4 +56,19 @@ mod tests { let code_closed = CheckBox::new(false); assert_eq!(code_closed.render(), r#""#); } + + #[test] + fn token_display() { + let mut checkbox = CheckBox::new(true); + assert_eq!( + format!("{}", Token::CheckBox(checkbox.clone())), + "Tk:CheckBox [checked]" + ); + + checkbox.checked = false; + assert_eq!( + format!("{}", Token::CheckBox(checkbox.clone())), + "Tk:CheckBox [empty]" + ); + } } diff --git a/src/syntax/content/parser/token/code.rs b/src/syntax/content/parser/token/code.rs index 24a44f1..5ffd868 100644 --- a/src/syntax/content/parser/token/code.rs +++ b/src/syntax/content/parser/token/code.rs @@ -40,6 +40,8 @@ impl std::fmt::Display for Code { #[cfg(test)] mod tests { + use crate::syntax::content::parser::token::Token; + use super::*; #[test] @@ -58,4 +60,16 @@ mod tests { fn lex() { Code::lex(&Lexeme::default()); } + + #[test] + fn token_display() { + let mut code = Code::new(true); + assert_eq!(format!("{}", Token::Code(code.clone())), "Tk:Code [open]"); + + code.open = false; + assert_eq!( + format!("{}", Token::Code(code.clone())), + "Tk:Code [closed]" + ); + } } diff --git a/src/syntax/content/parser/token/header.rs b/src/syntax/content/parser/token/header.rs index f4845a6..8b35161 100644 --- a/src/syntax/content/parser/token/header.rs +++ b/src/syntax/content/parser/token/header.rs @@ -191,6 +191,8 @@ impl Display for Level { #[cfg(test)] mod tests { + use crate::syntax::content::parser::token::Token; + use super::*; #[test] @@ -285,4 +287,13 @@ mod tests { header.render(); } + + #[test] + fn token_display() { + let header = Header::from_u8(2, false, None); + assert_eq!( + format!("{}", Token::Header(header)), + "Tk:Header [closed L2]" + ); + } } diff --git a/src/syntax/content/parser/token/item.rs b/src/syntax/content/parser/token/item.rs index 1c94318..3741520 100644 --- a/src/syntax/content/parser/token/item.rs +++ b/src/syntax/content/parser/token/item.rs @@ -43,3 +43,46 @@ impl std::fmt::Display for Item { ) } } + +#[cfg(test)] +mod tests { + use crate::syntax::content::parser::token::Token; + + use super::*; + + #[test] + #[should_panic( + expected = "Items should only be rendered by a list's render method" + )] + fn render() { + let item = Item::new("aCNuZwwzrt", None); + item.render(); + } + + #[test] + fn probe() { + let lexeme = Lexeme::new("bOa", "2R6", "4Mp"); + assert!(!Item::probe(&lexeme)); + } + + #[test] + #[should_panic(expected = "Attempt to lex an item directly from a lexeme")] + fn lex() { + let lexeme = Lexeme::new("8kbX", "Qzqu", "iDpg"); + Item::lex(&lexeme); + } + + #[test] + fn token_display() { + let mut item = Item::new("dRMy4", Some(4)); + assert_eq!( + format!("{}", Token::Item(item.clone())), + "Tk:Item [D4] dRMy4" + ); + item.depth = None; + assert_eq!( + format!("{}", Token::Item(item.clone())), + "Tk:Item [] dRMy4" + ); + } +} diff --git a/src/syntax/content/parser/token/linebreak.rs b/src/syntax/content/parser/token/linebreak.rs index fedbd7f..8c05284 100644 --- a/src/syntax/content/parser/token/linebreak.rs +++ b/src/syntax/content/parser/token/linebreak.rs @@ -24,3 +24,16 @@ impl std::fmt::Display for LineBreak { write!(f, "LineBreak") } } + +#[cfg(test)] +mod tests { + use crate::syntax::content::parser::token::Token; + + use super::*; + + #[test] + fn token_display() { + let linebreak = LineBreak::default(); + assert_eq!(format!("{}", Token::LineBreak(linebreak)), "Tk:LineBreak"); + } +} diff --git a/src/syntax/content/parser/token/list.rs b/src/syntax/content/parser/token/list.rs index 7130282..a71f7bc 100644 --- a/src/syntax/content/parser/token/list.rs +++ b/src/syntax/content/parser/token/list.rs @@ -90,6 +90,8 @@ impl std::fmt::Display for List { #[cfg(test)] mod tests { + use crate::syntax::content::parser::token::Token; + use super::*; #[test] @@ -164,4 +166,20 @@ mod tests { \n\n" ); } + + #[test] + fn token_display() { + let list = List::new(false); + assert_eq!( + format!("{}", Token::List(list.clone())), + "Tk:List [0 unordered items]" + ); + } + + #[test] + #[should_panic(expected = "Attempt to lex a List directly from a lexeme")] + fn lex() { + let lexeme = Lexeme::new("SL6PX", "6xsNB", "oeAHa"); + List::lex(&lexeme); + } } diff --git a/src/syntax/content/parser/token/literal.rs b/src/syntax/content/parser/token/literal.rs index 9e63bae..23d65b1 100644 --- a/src/syntax/content/parser/token/literal.rs +++ b/src/syntax/content/parser/token/literal.rs @@ -26,3 +26,27 @@ impl std::fmt::Display for Literal { write!(f, "Literal {}", crate::dev::wrap(&self.text)) } } + +#[cfg(test)] +mod tests { + use crate::syntax::content::parser::token::Token; + + use super::*; + + #[test] + fn token_display() { + let mut literal = Literal { + text: String::from("MYpDT"), + }; + assert_eq!( + format!("{}", Token::Literal(literal.clone())), + "Tk:Literal MYpDT" + ); + + literal.text = String::from("TjY02"); + assert_eq!( + format!("{}", Token::Literal(literal.clone())), + "Tk:Literal TjY02" + ); + } +} diff --git a/src/syntax/content/parser/token/oblique.rs b/src/syntax/content/parser/token/oblique.rs index 03c49d4..b776bf6 100644 --- a/src/syntax/content/parser/token/oblique.rs +++ b/src/syntax/content/parser/token/oblique.rs @@ -40,6 +40,8 @@ impl std::fmt::Display for Oblique { #[cfg(test)] mod tests { + use crate::syntax::content::parser::token::Token; + use super::*; #[test] @@ -58,4 +60,19 @@ mod tests { fn lex() { Oblique::lex(&Lexeme::default()); } + + #[test] + fn token_display() { + let mut oblique = Oblique::new(true); + assert_eq!( + format!("{}", Token::Oblique(oblique.clone())), + "Tk:Oblique [open]" + ); + + oblique.open = false; + assert_eq!( + format!("{}", Token::Oblique(oblique.clone())), + "Tk:Oblique [closed]" + ); + } } diff --git a/src/syntax/content/parser/token/paragraph.rs b/src/syntax/content/parser/token/paragraph.rs index 0713ca3..500fb43 100644 --- a/src/syntax/content/parser/token/paragraph.rs +++ b/src/syntax/content/parser/token/paragraph.rs @@ -58,6 +58,8 @@ impl std::fmt::Display for Paragraph { #[cfg(test)] mod tests { + use crate::syntax::content::parser::token::Token; + use super::*; #[test] @@ -74,4 +76,25 @@ mod tests { let p = Paragraph::lex(&Lexeme::default()); drop(p.render()); } + + #[test] + fn token_display() { + let mut paragraph = Paragraph::new(true); + assert_eq!( + format!("{}", Token::Paragraph(paragraph.clone())), + "Tk:Paragraph [open]" + ); + + paragraph.open = Some(false); + assert_eq!( + format!("{}", Token::Paragraph(paragraph.clone())), + "Tk:Paragraph [closed]" + ); + + paragraph.open = None; + assert_eq!( + format!("{}", Token::Paragraph(paragraph.clone())), + "Tk:Paragraph [unknown]" + ); + } } diff --git a/src/syntax/content/parser/token/preformat.rs b/src/syntax/content/parser/token/preformat.rs index d46285d..e2ee75d 100644 --- a/src/syntax/content/parser/token/preformat.rs +++ b/src/syntax/content/parser/token/preformat.rs @@ -50,6 +50,8 @@ impl Parseable for PreFormat { #[cfg(test)] mod tests { + use crate::syntax::content::parser::token::Token; + use super::*; #[test] @@ -72,4 +74,25 @@ mod tests { let from_non_empty_lexeme = PreFormat::lex(&Lexeme::default()); from_non_empty_lexeme.render(); } + + #[test] + fn token_display() { + let mut preformat = PreFormat::new(true); + assert_eq!( + format!("{}", Token::PreFormat(preformat.clone())), + "Tk:PreFormat [open]" + ); + + preformat.open = Some(false); + assert_eq!( + format!("{}", Token::PreFormat(preformat.clone())), + "Tk:PreFormat [closed]" + ); + + preformat.open = None; + assert_eq!( + format!("{}", Token::PreFormat(preformat.clone())), + "Tk:PreFormat [unknown]" + ); + } } diff --git a/src/syntax/content/parser/token/span.rs b/src/syntax/content/parser/token/span.rs index be6e911..8b13789 100644 --- a/src/syntax/content/parser/token/span.rs +++ b/src/syntax/content/parser/token/span.rs @@ -1,85 +1 @@ -use crate::syntax::content::{Parseable, parser::lexeme::Lexeme}; -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Span { - open: Option, -} - -impl Span { - pub fn new(open: bool) -> Span { - Span { open: Some(open) } - } -} - -impl Parseable for Span { - fn probe(_lexeme: &Lexeme) -> bool { - // there is no lexeme for span - false - } - - fn lex(_lexeme: &Lexeme) -> Span { - Span { open: None } - } - - fn render(&self) -> String { - if let Some(open) = self.open { - if open { - "".to_owned() - } else { - "".to_owned() - } - } else { - panic!("Attempt to render a span tag while open state is unknown") - } - } -} - -impl std::fmt::Display for Span { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let display_open_state = match self.open { - Some(ref open_state) => { - if *open_state { - "open" - } else { - "closed" - } - }, - None => "unknown", - }; - write!(f, "Span [{display_open_state}]") - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn probe() { - assert!(!Span::probe(&Lexeme::default())); - } - - #[test] - fn lex() { - let span = Span::lex(&Lexeme::default()); - assert!(span.open.is_none()); - } - - #[test] - fn render() { - let open_span = Span::new(true); - assert_eq!(open_span.render(), ""); - - let closed_span = Span::new(false); - assert_eq!(closed_span.render(), ""); - } - - #[test] - #[should_panic( - expected = "Attempt to render a span tag while open state is unknown" - )] - fn render_unknown_open_state() { - let open_span = Span::lex(&Lexeme::default()); - drop(open_span.render()); - } -} diff --git a/src/syntax/content/parser/token/strike.rs b/src/syntax/content/parser/token/strike.rs index f0e6e94..a13c868 100644 --- a/src/syntax/content/parser/token/strike.rs +++ b/src/syntax/content/parser/token/strike.rs @@ -37,6 +37,8 @@ impl std::fmt::Display for Strike { #[cfg(test)] mod tests { + use crate::syntax::content::parser::token::Token; + use super::*; #[test] @@ -55,4 +57,19 @@ mod tests { fn lex() { Strike::lex(&Lexeme::default()); } + + #[test] + fn token_display() { + let mut strike = Strike::new(true); + assert_eq!( + format!("{}", Token::Strike(strike.clone())), + "Tk:Strike [open]" + ); + + strike.open = false; + assert_eq!( + format!("{}", Token::Strike(strike.clone())), + "Tk:Strike [closed]" + ); + } } diff --git a/src/syntax/content/parser/token/underline.rs b/src/syntax/content/parser/token/underline.rs index 539d207..a9a1d14 100644 --- a/src/syntax/content/parser/token/underline.rs +++ b/src/syntax/content/parser/token/underline.rs @@ -40,6 +40,8 @@ impl std::fmt::Display for Underline { #[cfg(test)] mod tests { + use crate::syntax::content::parser::token::Token; + use super::*; #[test] @@ -58,4 +60,19 @@ mod tests { fn lex() { Underline::lex(&Lexeme::default()); } + + #[test] + fn token_display() { + let mut underline = Underline::new(true); + assert_eq!( + format!("{}", Token::Underline(underline.clone())), + "Tk:Underline [open]" + ); + + underline.open = false; + assert_eq!( + format!("{}", Token::Underline(underline.clone())), + "Tk:Underline [closed]" + ); + } } diff --git a/static/graph.toml b/static/graph.toml index 33c6f7f..a67c91d 100644 --- a/static/graph.toml +++ b/static/graph.toml @@ -83,6 +83,9 @@ kind = "contrast" This will create a connection from the node with ID `Realism` to a node with ID `Surrealism` and add the "contrast" kind to the connection. See |Connections| for the existing kinds and how they affect your graph. """ +[nodes.docs] +redirect = "Documentation" + [nodes.Node] # foo text = """ A node is defined in your graph file starting with a table header of the form: