Add tests for all but the content syntax parser module

This commit is contained in:
Juno Takano 2025-12-25 23:57:22 -03:00
commit e657eb6513
17 changed files with 1072 additions and 127 deletions

View file

@ -56,3 +56,33 @@ pub async fn not_found() -> Response<Body> {
Some("The page you tried to access could not be found."),
)
}
#[cfg(test)]
mod tests {
use axum::{
http::{StatusCode},
};
use super::*;
#[tokio::test]
async fn not_found() {
let response = super::not_found().await;
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn internal_error() {
assert!(by_code(Some(201), None).status() == 201);
assert!(by_code(Some(304), None).status() == 304);
assert!(by_code(Some(418), None).status() == 418);
assert!(by_code(Some(505), None).status() == 505);
}
#[test]
fn custom_message() {
let pattern = "sibPtt0mvHPWS9HQ0YBQfGu8cUs954LZ";
let body = make_body(Some(501), Some(pattern));
assert!(body.contains(pattern));
assert!(!body.contains(&pattern.chars().rev().collect::<String>()));
}
}

View file

@ -25,11 +25,7 @@ pub async fn file(file_path: &str, content_type: &str) -> Response<Body> {
let header = header::CONTENT_TYPE;
if let Ok(header_value) = HeaderValue::from_str(content_type) {
if let Some(h) = response.headers_mut().insert(header, header_value) {
log!(
"Overwrote existing header {h:?} because a header for the same key existed"
);
}
response.headers_mut().append(header, header_value);
} else {
log!("Failed to create content type header value from {content_type}");
}
@ -43,15 +39,70 @@ pub async fn serial(format: &Format) -> Response<Body> {
let body = serialize_graph(format, &graph);
match *format {
Format::Toml => handlers::raw::make_response(
Format::TOML => handlers::raw::make_response(
&body,
200,
&[(header::CONTENT_TYPE, "text/plain")],
),
Format::Json => handlers::raw::make_response(
Format::JSON => handlers::raw::make_response(
&body,
200,
&[(header::CONTENT_TYPE, "application/json")],
),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn serial_toml() {
let response = serial(&Format::TOML).await;
assert!(response.status() == 200);
}
#[tokio::test]
async fn serial_toml_content_type() {
let response = serial(&Format::TOML).await;
assert!(
response.headers().get(header::CONTENT_TYPE).unwrap()
== "text/plain"
);
}
#[tokio::test]
async fn serial_json_content_type() {
let response = serial(&Format::JSON).await;
assert!(
response.headers().get(header::CONTENT_TYPE).unwrap()
== "application/json"
);
}
#[tokio::test]
async fn file_valid_header() {
let payload = "y1mgMhjeIMFsRNZ1tskP52DfWuvhvbRP";
let response = file("./static/graph.toml", payload).await;
assert_eq!(
response.headers().get(header::CONTENT_TYPE).unwrap(),
payload
);
}
#[tokio::test]
async fn file_invalid_header() {
let response = file("./static/graph.toml", "\n").await;
println!("{response:#?}");
assert!(response.headers().get(header::CONTENT_TYPE).is_none());
}
#[tokio::test]
#[should_panic(
expected = "Failed to read IvnhZhdHb1xDnUw4hYDDNIERoaOojkiu \
contents: No such file or directory (os error 2)"
)]
async fn file_invalid_path() {
drop(file("IvnhZhdHb1xDnUw4hYDDNIERoaOojkiu", "text/plain").await);
}
}

View file

@ -40,3 +40,44 @@ pub async fn node(Path(id): Path<String>) -> Response<Body> {
not_found,
)
}
#[cfg(test)]
mod tests {
use axum::{
http::{HeaderName, StatusCode},
};
use super::*;
#[tokio::test]
async fn syntax() {
let response = node(Path("Syntax".to_string())).await;
assert_eq!(response.status(), StatusCode::OK);
}
#[tokio::test]
async fn syntax_content_type() {
let response = node(Path("Syntax".to_string())).await;
assert!(
response
.headers()
.get(HeaderName::from_static("content-type"),)
.unwrap()
.to_str()
.unwrap()
== "text/html"
);
}
#[tokio::test]
async fn not_found() {
let response = node(Path("InexistentNode".to_string())).await;
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn redirect() {
let response = node(Path("syntax".to_string())).await;
assert_eq!(response.status(), StatusCode::PERMANENT_REDIRECT);
}
}

View file

@ -29,3 +29,38 @@ pub async fn search(Form(query): Form<Query>) -> Redirect {
pub struct Query {
node: String,
}
#[cfg(test)]
mod tests {
use axum::{
http::{StatusCode},
};
use super::*;
#[tokio::test]
async fn search_redirect() {
let query = Form(Query {
node: String::from("duZzBrgCzMhVY15wehxasezsGNatOKIq"),
});
let response = search(query).await;
assert!(response.status_code() == StatusCode::PERMANENT_REDIRECT);
}
#[tokio::test]
async fn about_page_ok() {
let response = page("about.html").await;
assert_eq!(response.status(), StatusCode::OK);
}
#[tokio::test]
async fn tree_page_ok() {
let response = page("tree.html").await;
assert_eq!(response.status(), StatusCode::OK);
}
#[tokio::test]
async fn inexistent_page_error() {
let response = page("HBvcwqT8wLk6hxk1GdvNcEzJ6IiZ2Fod").await;
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
}
}

View file

@ -27,9 +27,39 @@ pub(in crate::router::handlers) fn make_response(
);
}
} else {
log!("Failed to wrap header value {}", header.1);
log!("Failed to create header value from {}", header.1);
}
}
response
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn repeated_header() {
let headers = [
(header::ACCEPT, "Not really"),
(header::ACCEPT, "This again?"),
];
let response = make_response("", 418, &headers);
assert!(response.headers().get_all(header::ACCEPT).iter().count() == 1);
assert_eq!(
response
.headers()
.get(header::ACCEPT)
.unwrap()
.to_str()
.unwrap(),
"This again?",
);
}
#[test]
fn invalid_header() {
let response = make_response("", 418, &[(header::MAX_FORWARDS, "\n")]);
assert!(response.headers().get(header::MAX_FORWARDS).is_none());
}
}

View file

@ -27,14 +27,9 @@ pub(in crate::router::handlers) fn render(
error_message: Option<String>,
) -> (String, u16) {
// TODO just return an Option/String> here
let tera = match tera::Tera::new(concat!(
env!("CARGO_MANIFEST_DIR"),
"/templates/**/*"
)) {
let tera = match tera::Tera::new("./templates/**/*") {
Ok(t) => t,
Err(e) => {
let early_error_message = format!("{e:#?}");
log!("{}", early_error_message);
return (emergency_wrap(&e), 500);
},
};
@ -73,7 +68,8 @@ pub(in crate::router::handlers) fn render(
}
}
fn emergency_wrap(message: &tera::Error) -> String {
fn emergency_wrap(error: &tera::Error) -> String {
log!("{error:#?}");
format!(
r#"<!DOCTYPE html>
<html>
@ -93,7 +89,7 @@ fn emergency_wrap(message: &tera::Error) -> String {
<h2><strong>Early Pre-Templating Error</strong></h2>
<p>This normally indicates a malformed template.</p>
<pre>
{message}
{error:#?}
</pre>
<p>
If you haven't modified templates, plese consider
@ -104,3 +100,104 @@ fn emergency_wrap(message: &tera::Error) -> String {
"#
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn by_filename_forced_error() {
let response =
by_filename("index.html", &tera::Context::new(), 418, None, true);
assert_eq!(response.status(), 418);
}
#[test]
fn by_filename_index() {
let response =
by_filename("index.html", &tera::Context::new(), 418, None, false);
assert_eq!(response.status(), 200);
}
#[test]
fn by_filename_file_not_found() {
let response = by_filename(
"bwbl3BnWsluIgbO2NV9t3vtihwcjuF6t",
&tera::Context::new(),
418,
None,
false,
);
assert_eq!(response.status(), 500);
}
#[test]
fn by_filename_empty() {
let response = by_filename("", &tera::Context::new(), 418, None, false);
assert_eq!(response.status(), 500);
}
#[test]
fn render_with_context() {
let payload = "dBgIw8DnNHxJojiXzu445qUC4UpxwZCy";
let mut context = tera::Context::new();
let node = crate::types::Node::new(Some(payload.to_string()));
let graph = crate::syntax::serial::populate_graph();
context.insert("node", &node);
context.insert("text", &crate::syntax::content::parse(&node.text));
context.insert("incoming", &graph.incoming.get(&node.id));
context.insert("config", &graph.meta.config.parse_text());
let (body, status) = render("node.html", &context, None);
assert_eq!(status, 200);
assert!(body.matches(payload).count() == 1);
}
#[test]
fn render_custom_error_message() {
let payload = "dBgIw8DnNHxJojiXzu445qUC4UpxwZCy";
let (body, status) = render(
"ObH9jYUl4wMhUNcXnuqwVVzHoqx4ufyN",
&tera::Context::new(),
Some(payload.to_string()),
);
assert_eq!(status, 500);
assert!(body.matches(payload).count() == 1);
}
#[test]
fn render_empty() {
let (body, status) = render(
"R8D1pxwHZDxcH5SMjR7rZEnIzmpkiHkH",
&tera::Context::new(),
None,
);
assert_eq!(status, 500);
assert!(body.matches("Template render failed").count() == 1);
}
#[test]
fn render_not_found() {
let payload = "OL6kb9qHe7Iwr7wFIRKUTeFhF34BRsQo";
let (body, status) = render(payload, &tera::Context::new(), None);
assert!(body.matches("TemplateNotFound").count() > 0);
assert!(body.matches(payload).count() > 0);
assert_eq!(status, 500);
}
#[test]
fn render_bad_context() {
let (body, status) = render("node.html", &tera::Context::new(), None);
assert!(body.matches("Template render failed.").count() > 0);
assert_eq!(status, 500);
}
#[test]
fn emergency_wrap_custom_message() {
let payload = "JLaTtsnd2IFukIOvqFNymeuiaS6nMaUc";
let error = tera::Error::msg(payload);
let html = emergency_wrap(&error);
assert!(html.matches(payload).count() == 1);
}
}