Skip to content

Commit

Permalink
add unit test for citations
Browse files Browse the repository at this point in the history
  • Loading branch information
ElenaKrippner committed Dec 15, 2023
1 parent 7119efa commit d706ee8
Show file tree
Hide file tree
Showing 7 changed files with 565 additions and 12 deletions.
87 changes: 87 additions & 0 deletions commons/src/config/locale.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,90 @@ pub mod clap {
})
}
}

#[cfg(test)]
mod tests {
use crate::config::locale::serde::{hashmap, multiple};
use icu_locid::{locale, Locale};
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use std::str::FromStr;

#[derive(Serialize, Deserialize)]
struct LocalesStruct {
#[serde(with = "multiple")]
locales: HashSet<Locale>,
}

#[derive(Serialize, Deserialize)]
struct LocalePathBufStruct {
#[serde(with = "hashmap")]
map: HashMap<Locale, PathBuf>,
}

#[test]
fn serialize_multiple() {
let mut locales = HashSet::new();
locales.insert(locale!("de"));
locales.insert(locale!("en"));

let locales_struct = LocalesStruct { locales };

let actual = serde_yaml::to_string(&locales_struct).unwrap();
assert!(
actual == "---\nlocales:\n - en\n - de\n"
|| actual == "---\nlocales:\n - de\n - en\n"
);
}

#[test]
fn deserialize_multiple() {
let serialized = "locales:\n - en\n - de";
let actual: LocalesStruct = serde_yaml::from_str(serialized).unwrap();

let locales_vec: Vec<Locale> = actual.locales.into_iter().collect();
assert_eq!(locales_vec.len(), 2);
assert_ne!(locales_vec[0], locales_vec[1]);
assert!(locales_vec[0] == locale!("de") || locales_vec[0] == locale!("en"));
assert!(locales_vec[1] == locale!("de") || locales_vec[1] == locale!("en"));
}

#[test]
fn serialize_hashmap() {
let mut map = HashMap::new();
map.insert(locale!("de"), PathBuf::from_str("path/to/de").unwrap());
map.insert(locale!("en"), PathBuf::from_str("path/to/en").unwrap());

let locale_pathbuf_struct = LocalePathBufStruct { map };

let actual = serde_yaml::to_string(&locale_pathbuf_struct).unwrap();
assert!(
actual == "---\nmap:\n en: path/to/en\n de: path/to/de\n"
|| actual == "---\nmap:\n de: path/to/de\n en: path/to/en\n"
);
}

#[test]
fn deserialize_hashmap() {
let serialized = "map:\n de: path/to/de\n en: path/to/en";
let actual: LocalePathBufStruct = serde_yaml::from_str(serialized).unwrap();

let locales_map: Vec<(Locale, PathBuf)> = actual.map.into_iter().collect();

assert_eq!(locales_map.len(), 2);
assert_ne!(locales_map[0], locales_map[1]);
assert!(
(locales_map[0].0 == locale!("de")
&& locales_map[0].1 == PathBuf::from_str("path/to/de").unwrap())
|| (locales_map[0].0 == locale!("en")
&& locales_map[0].1 == PathBuf::from_str("path/to/en").unwrap())
);
assert!(
(locales_map[1].0 == locale!("de")
&& locales_map[1].1 == PathBuf::from_str("path/to/de").unwrap())
|| (locales_map[1].0 == locale!("en")
&& locales_map[1].1 == PathBuf::from_str("path/to/en").unwrap())
);
}
}
5 changes: 2 additions & 3 deletions commons/src/config/preamble.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,8 @@ impl ConfigFns for Citedata {
fn merge(&mut self, other: Self) {
self.style.replace_none(other.style);
self.references.extend(other.references);
for locale_path_buf in self.csl_locales.clone() {
self.citation_locales
.insert(locale_path_buf.0, locale_path_buf.1);
for (locale, pathbuf) in self.csl_locales.clone() {
self.citation_locales.insert(locale, pathbuf);
}
for locale_path_buf in other.csl_locales.clone() {
self.citation_locales
Expand Down
77 changes: 71 additions & 6 deletions render/src/html/citeproc/csl_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,16 @@ csl_files!(

pub fn get_style_string(path: PathBuf) -> String {
if path.is_file() {
match fs::read_to_string(&path) {
Ok(csl_style) => {
return csl_style;
}
return match fs::read_to_string(&path) {
Ok(csl_style) => csl_style,
Err(_) => {
log!(
GeneralWarning::FileRead,
format!("Could not read style file: '{:?}'", path.clone()),
);
return IEEE.to_string();
IEEE.to_string()
}
}
};
}
match path.to_str().unwrap_or("ieee") {
"american-medical-association" => AMERICAN_MEDICAL_ASSOCIATION.to_string(),
Expand All @@ -101,3 +99,70 @@ pub fn get_style_string(path: PathBuf) -> String {
}
}
}

#[cfg(test)]
mod tests {
use crate::html::citeproc::csl_files::{get_locale_string, get_style_string};
use std::collections::HashMap;
use std::path::PathBuf;
use std::str::FromStr;
use unimarkup_commons::config::icu_locid::locale;

#[test]
fn get_locale_string_not_in_hashmap() {
let mut map = HashMap::new();
map.insert(locale!("fr"), PathBuf::from_str("path/to/fr").unwrap());
let actual = get_locale_string(locale!("de-DE"), map);
assert!(actual.contains("xml:lang=\"de-DE\""));
}

#[test]
fn get_locale_string_path_not_found() {
let mut map = HashMap::new();
map.insert(
locale!("de-DE"),
PathBuf::from_str("invalid/path/to/de-DE").unwrap(),
);
let actual = get_locale_string(locale!("de-DE"), map);
assert!(actual.contains("xml:lang=\"de-DE\""));
}

#[test]
fn get_locale_string_from_path() {
let mut map = HashMap::new();
map.insert(
locale!("nl-NL"),
PathBuf::from_str("./src/html/citeproc/test_files/locales-nl-NL.xml").unwrap(),
);
let actual = get_locale_string(locale!("nl-NL"), map);
assert!(actual.contains("xml:lang=\"nl-NL\""));
}

#[test]
fn get_locale_string_default() {
let map = HashMap::new();
let actual = get_locale_string(locale!("nl-NL"), map);
assert!(actual.contains("xml:lang=\"en-US\""));
}

#[test]
fn get_style_string_file_found() {
let path = PathBuf::from_str("./csl_styles/apa.csl").unwrap();
let actual = get_style_string(path);
assert!(actual.contains("<title>American Psychological Association 7th edition</title>"));
}

#[test]
fn get_style_string_file_not_found() {
let path = PathBuf::from_str("invalid/path/file.csl").unwrap();
let actual = get_style_string(path);
assert!(actual.contains("<title>IEEE</title>"));
}

#[test]
fn get_style_string_no_file() {
let path = PathBuf::from_str("harvard-cite-them-right").unwrap();
let actual = get_style_string(path);
assert!(actual.contains("<title>Cite Them Right 12th edition - Harvard</title>"));
}
}
156 changes: 153 additions & 3 deletions render/src/html/citeproc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ impl CiteprocWrapper {
}
}

#[cfg(test)]
pub fn new_with_path(path: &str) -> Result<CiteprocWrapper, CiteError> {
match import(path) {
Ok(module) => Ok(CiteprocWrapper { module }),
Err(_err) => Err(CiteError::ModuleImportError),
}
}

// returns the citation strings to be placed inline in the same order as the citation_ids
// the CitationItems have to have the same order that they should appear in the output, because this considers
// disambiguation and short forms of citations if the same entry was cited before
Expand Down Expand Up @@ -85,9 +93,6 @@ fn get_csl_string(references: &HashSet<PathBuf>) -> String {
);
}
}
let mut citation_data: CslData =
serde_json::from_str::<CslData>(&citation_string).unwrap();
citation_items.append(&mut citation_data.items);
} else {
log!(
GeneralWarning::FileRead,
Expand All @@ -100,3 +105,148 @@ fn get_csl_string(references: &HashSet<PathBuf>) -> String {
};
serde_json::ser::to_string_pretty(&csl_data).unwrap()
}

#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use unimarkup_commons::config::icu_locid::locale;

#[test]
fn test_no_footnotes() {
let mut under_test =
CiteprocWrapper::new_with_path("./src/html/citeproc/js/citeproc_adapter.js").unwrap();
let mut citation_paths: HashSet<PathBuf> = HashSet::new();
citation_paths.insert(
PathBuf::from_str("./src/html/citeproc/test_files/citation_items.csl").unwrap(),
);
let doc_locale = locale!("de-DE");
let mut citation_locales: HashMap<Locale, PathBuf> = HashMap::new();
citation_locales.insert(
locale!("de-DE"),
PathBuf::from_str("./csl_locales/locales-de-DE.xml").unwrap(),
);
let style_id = PathBuf::from_str("./csl_styles/apa.csl").unwrap();
let serde_result = serde_json::to_value(vec![vec!["id-1"], vec!["id-1", "id-2"]]).unwrap();
let for_pagedjs = false;
let actual_citations = under_test.get_citation_strings(
&citation_paths,
doc_locale,
citation_locales,
style_id,
&[serde_result],
for_pagedjs,
);

assert!(actual_citations.is_ok(), "A cite error occurred");
let unwrapped_actual = actual_citations.unwrap();
assert_eq!(unwrapped_actual.len(), 2);
assert!(unwrapped_actual[0].starts_with("<a href"));
assert!(!unwrapped_actual[0].starts_with("<a href=\"#footnote"));
assert!(unwrapped_actual[1].starts_with("<a href"));
assert!(!unwrapped_actual[1].starts_with("<a href=\"#footnote"));

let actual_footnotes = under_test.get_footnotes();
assert!(actual_footnotes.unwrap().is_empty());

let actual_bibliography = under_test.get_bibliography().unwrap();
assert!(!actual_bibliography.is_empty());
assert!(actual_bibliography.starts_with("<div class=\"csl-bib-body\""));
}

#[test]
fn test_footnotes() {
let mut under_test =
CiteprocWrapper::new_with_path("./src/html/citeproc/js/citeproc_adapter.js").unwrap();
let mut citation_paths: HashSet<PathBuf> = HashSet::new();
citation_paths.insert(
PathBuf::from_str("./src/html/citeproc/test_files/citation_items.csl").unwrap(),
);
let doc_locale = locale!("de-DE");
let mut citation_locales: HashMap<Locale, PathBuf> = HashMap::new();
citation_locales.insert(
locale!("de-DE"),
PathBuf::from_str("./csl_locales/locales-de-DE.xml").unwrap(),
);
let style_id = PathBuf::from_str("./csl_styles/chicago-fullnote-bibliography.csl").unwrap();
let serde_result = serde_json::to_value(vec![vec!["id-1"], vec!["id-1", "id-2"]]).unwrap();
let for_pagedjs = false;
let actual_citations = under_test.get_citation_strings(
&citation_paths,
doc_locale,
citation_locales,
style_id,
&[serde_result],
for_pagedjs,
);

assert!(actual_citations.is_ok(), "A cite error occurred");
let unwrapped_actual = actual_citations.unwrap();
assert_eq!(unwrapped_actual.len(), 2);
assert!(unwrapped_actual[0].starts_with("<a href=\"#footnote"));
assert!(unwrapped_actual[1].starts_with("<a href=\"#footnote"));

let actual_footnotes = under_test.get_footnotes().unwrap();
assert!(!actual_footnotes.is_empty());
assert!(actual_footnotes.starts_with("<div"));

let actual_bibliography = under_test.get_bibliography().unwrap();
assert!(!actual_bibliography.is_empty());
assert!(actual_bibliography.starts_with("<div class=\"csl-bib-body\""));
}

#[test]
fn test_for_pagedjs() {
let mut under_test =
CiteprocWrapper::new_with_path("./src/html/citeproc/js/citeproc_adapter.js").unwrap();
let mut citation_paths: HashSet<PathBuf> = HashSet::new();
citation_paths.insert(
PathBuf::from_str("./src/html/citeproc/test_files/citation_items.csl").unwrap(),
);
let doc_locale = locale!("de-DE");
let mut citation_locales: HashMap<Locale, PathBuf> = HashMap::new();
citation_locales.insert(
locale!("de-DE"),
PathBuf::from_str("./csl_locales/locales-de-DE.xml").unwrap(),
);
let style_id = PathBuf::from_str("./csl_styles/chicago-fullnote-bibliography.csl").unwrap();
let serde_result = serde_json::to_value(vec![vec!["id-1"], vec!["id-1", "id-2"]]).unwrap();
let for_pagedjs = true;
let actual_citations = under_test.get_citation_strings(
&citation_paths,
doc_locale,
citation_locales,
style_id,
&[serde_result],
for_pagedjs,
);

assert!(actual_citations.is_ok(), "A cite error occurred");
let unwrapped_actual = actual_citations.unwrap();
assert_eq!(unwrapped_actual.len(), 2);
assert!(unwrapped_actual[0].starts_with("<span className=\"footnote\""));
assert!(unwrapped_actual[1].starts_with("<span className=\"footnote\""));

let actual_footnotes = under_test.get_footnotes().unwrap();
assert!(actual_footnotes.is_empty());

let actual_bibliography = under_test.get_bibliography().unwrap();
assert!(!actual_bibliography.is_empty());
assert!(actual_bibliography.starts_with("<div class=\"csl-bib-body\""));
}

#[test]
fn test_get_csl_string_two_files() {
let mut paths = HashSet::new();
paths.insert(
PathBuf::from_str("./src/html/citeproc/test_files/citation_items.csl").unwrap(),
);
paths.insert(
PathBuf::from_str("./src/html/citeproc/test_files/citation_items2.csl").unwrap(),
);
let actual_string = get_csl_string(&paths);
let actual_object: CslData = serde_json::from_str(&actual_string).unwrap();

assert_eq!(actual_object.items.len(), 8);
}
}
Loading

0 comments on commit d706ee8

Please sign in to comment.