You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

712 lines
26KB

  1. use std::collections::HashMap;
  2. use serde_derive::Serialize;
  3. use slotmap::DefaultKey;
  4. use tera::{Context, Tera};
  5. use config::{Config, Taxonomy as TaxonomyConfig};
  6. use errors::{bail, Error, Result};
  7. use utils::templates::render_template;
  8. use crate::content::SerializingPage;
  9. use crate::library::Library;
  10. use crate::sorting::sort_pages_by_date;
  11. use utils::slugs::maybe_slugify_paths;
  12. #[derive(Debug, Clone, PartialEq, Serialize)]
  13. pub struct SerializedTaxonomyItem<'a> {
  14. name: &'a str,
  15. slug: &'a str,
  16. permalink: &'a str,
  17. pages: Vec<SerializingPage<'a>>,
  18. }
  19. impl<'a> SerializedTaxonomyItem<'a> {
  20. pub fn from_item(item: &'a TaxonomyItem, library: &'a Library) -> Self {
  21. let mut pages = vec![];
  22. for key in &item.pages {
  23. let page = library.get_page_by_key(*key);
  24. pages.push(page.to_serialized_basic(library));
  25. }
  26. SerializedTaxonomyItem {
  27. name: &item.name,
  28. slug: &item.slug,
  29. permalink: &item.permalink,
  30. pages,
  31. }
  32. }
  33. }
  34. /// A taxonomy with all its pages
  35. #[derive(Debug, Clone, PartialEq)]
  36. pub struct TaxonomyItem {
  37. pub name: String,
  38. pub slug: String,
  39. pub permalink: String,
  40. pub pages: Vec<DefaultKey>,
  41. }
  42. impl TaxonomyItem {
  43. pub fn new(
  44. name: &str,
  45. taxonomy: &TaxonomyConfig,
  46. config: &Config,
  47. keys: Vec<DefaultKey>,
  48. library: &Library,
  49. ) -> Self {
  50. // Taxonomy are almost always used for blogs so we filter by dates
  51. // and it's not like we can sort things across sections by anything other
  52. // than dates
  53. let data = keys
  54. .iter()
  55. .map(|k| {
  56. if let Some(page) = library.pages().get(*k) {
  57. (k, page.meta.datetime, page.permalink.as_ref())
  58. } else {
  59. unreachable!("Sorting got an unknown page")
  60. }
  61. })
  62. .collect();
  63. let (mut pages, ignored_pages) = sort_pages_by_date(data);
  64. let slug = maybe_slugify_paths(name, config.slugify_paths);
  65. let permalink = if taxonomy.lang != config.default_language {
  66. config.make_permalink(&format!("/{}/{}/{}", taxonomy.lang, taxonomy.name, slug))
  67. } else {
  68. config.make_permalink(&format!("/{}/{}", taxonomy.name, slug))
  69. };
  70. // We still append pages without dates at the end
  71. pages.extend(ignored_pages);
  72. TaxonomyItem { name: name.to_string(), permalink, slug, pages }
  73. }
  74. pub fn serialize<'a>(&'a self, library: &'a Library) -> SerializedTaxonomyItem<'a> {
  75. SerializedTaxonomyItem::from_item(self, library)
  76. }
  77. }
  78. #[derive(Debug, Clone, PartialEq, Serialize)]
  79. pub struct SerializedTaxonomy<'a> {
  80. kind: &'a TaxonomyConfig,
  81. items: Vec<SerializedTaxonomyItem<'a>>,
  82. }
  83. impl<'a> SerializedTaxonomy<'a> {
  84. pub fn from_taxonomy(taxonomy: &'a Taxonomy, library: &'a Library) -> Self {
  85. let items: Vec<SerializedTaxonomyItem> =
  86. taxonomy.items.iter().map(|i| SerializedTaxonomyItem::from_item(i, library)).collect();
  87. SerializedTaxonomy { kind: &taxonomy.kind, items }
  88. }
  89. }
  90. /// All different taxonomies we have and their content
  91. #[derive(Debug, Clone, PartialEq)]
  92. pub struct Taxonomy {
  93. pub kind: TaxonomyConfig,
  94. // this vec is sorted by the count of item
  95. pub items: Vec<TaxonomyItem>,
  96. }
  97. impl Taxonomy {
  98. fn new(
  99. kind: TaxonomyConfig,
  100. config: &Config,
  101. items: HashMap<String, Vec<DefaultKey>>,
  102. library: &Library,
  103. ) -> Taxonomy {
  104. let mut sorted_items = vec![];
  105. for (name, pages) in items {
  106. sorted_items.push(TaxonomyItem::new(&name, &kind, config, pages, library));
  107. }
  108. sorted_items.sort_by(|a, b| a.name.cmp(&b.name));
  109. Taxonomy { kind, items: sorted_items }
  110. }
  111. pub fn len(&self) -> usize {
  112. self.items.len()
  113. }
  114. pub fn is_empty(&self) -> bool {
  115. self.len() == 0
  116. }
  117. pub fn render_term(
  118. &self,
  119. item: &TaxonomyItem,
  120. tera: &Tera,
  121. config: &Config,
  122. library: &Library,
  123. ) -> Result<String> {
  124. let mut context = Context::new();
  125. context.insert("config", config);
  126. context.insert("lang", &self.kind.lang);
  127. context.insert("term", &SerializedTaxonomyItem::from_item(item, library));
  128. context.insert("taxonomy", &self.kind);
  129. context.insert(
  130. "current_url",
  131. &config.make_permalink(&format!("{}/{}", self.kind.name, item.slug)),
  132. );
  133. context.insert("current_path", &format!("/{}/{}", self.kind.name, item.slug));
  134. render_template(&format!("{}/single.html", self.kind.name), tera, context, &config.theme)
  135. .map_err(|e| {
  136. Error::chain(format!("Failed to render single term {} page.", self.kind.name), e)
  137. })
  138. }
  139. pub fn render_all_terms(
  140. &self,
  141. tera: &Tera,
  142. config: &Config,
  143. library: &Library,
  144. ) -> Result<String> {
  145. let mut context = Context::new();
  146. context.insert("config", config);
  147. let terms: Vec<SerializedTaxonomyItem> =
  148. self.items.iter().map(|i| SerializedTaxonomyItem::from_item(i, library)).collect();
  149. context.insert("terms", &terms);
  150. context.insert("taxonomy", &self.kind);
  151. context.insert("current_url", &config.make_permalink(&self.kind.name));
  152. context.insert("current_path", &self.kind.name);
  153. render_template(&format!("{}/list.html", self.kind.name), tera, context, &config.theme)
  154. .map_err(|e| {
  155. Error::chain(format!("Failed to render a list of {} page.", self.kind.name), e)
  156. })
  157. }
  158. pub fn to_serialized<'a>(&'a self, library: &'a Library) -> SerializedTaxonomy<'a> {
  159. SerializedTaxonomy::from_taxonomy(self, library)
  160. }
  161. }
  162. pub fn find_taxonomies(config: &Config, library: &Library) -> Result<Vec<Taxonomy>> {
  163. let taxonomies_def = {
  164. let mut m = HashMap::new();
  165. for t in &config.taxonomies {
  166. m.insert(format!("{}-{}", t.name, t.lang), t);
  167. }
  168. m
  169. };
  170. let mut all_taxonomies = HashMap::new();
  171. for (key, page) in library.pages() {
  172. for (name, val) in &page.meta.taxonomies {
  173. let taxo_key = format!("{}-{}", name, page.lang);
  174. if taxonomies_def.contains_key(&taxo_key) {
  175. all_taxonomies.entry(taxo_key.clone()).or_insert_with(HashMap::new);
  176. for v in val {
  177. all_taxonomies
  178. .get_mut(&taxo_key)
  179. .unwrap()
  180. .entry(v.to_string())
  181. .or_insert_with(|| vec![])
  182. .push(key);
  183. }
  184. } else {
  185. bail!(
  186. "Page `{}` has taxonomy `{}` which is not defined in config.toml",
  187. page.file.path.display(),
  188. name
  189. );
  190. }
  191. }
  192. }
  193. let mut taxonomies = vec![];
  194. for (name, taxo) in all_taxonomies {
  195. taxonomies.push(Taxonomy::new(taxonomies_def[&name].clone(), config, taxo, library));
  196. }
  197. Ok(taxonomies)
  198. }
  199. #[cfg(test)]
  200. mod tests {
  201. use super::*;
  202. use std::collections::HashMap;
  203. use crate::content::Page;
  204. use crate::library::Library;
  205. use config::{Config, Language, Taxonomy as TaxonomyConfig};
  206. #[test]
  207. fn can_make_taxonomies() {
  208. let mut config = Config::default();
  209. let mut library = Library::new(2, 0, false);
  210. config.taxonomies = vec![
  211. TaxonomyConfig {
  212. name: "categories".to_string(),
  213. lang: config.default_language.clone(),
  214. ..TaxonomyConfig::default()
  215. },
  216. TaxonomyConfig {
  217. name: "tags".to_string(),
  218. lang: config.default_language.clone(),
  219. ..TaxonomyConfig::default()
  220. },
  221. TaxonomyConfig {
  222. name: "authors".to_string(),
  223. lang: config.default_language.clone(),
  224. ..TaxonomyConfig::default()
  225. },
  226. ];
  227. let mut page1 = Page::default();
  228. let mut taxo_page1 = HashMap::new();
  229. taxo_page1.insert("tags".to_string(), vec!["rust".to_string(), "db".to_string()]);
  230. taxo_page1.insert("categories".to_string(), vec!["Programming tutorials".to_string()]);
  231. page1.meta.taxonomies = taxo_page1;
  232. page1.lang = config.default_language.clone();
  233. library.insert_page(page1);
  234. let mut page2 = Page::default();
  235. let mut taxo_page2 = HashMap::new();
  236. taxo_page2.insert("tags".to_string(), vec!["rust".to_string(), "js".to_string()]);
  237. taxo_page2.insert("categories".to_string(), vec!["Other".to_string()]);
  238. page2.meta.taxonomies = taxo_page2;
  239. page2.lang = config.default_language.clone();
  240. library.insert_page(page2);
  241. let mut page3 = Page::default();
  242. let mut taxo_page3 = HashMap::new();
  243. taxo_page3.insert("tags".to_string(), vec!["js".to_string()]);
  244. taxo_page3.insert("authors".to_string(), vec!["Vincent Prouillet".to_string()]);
  245. page3.meta.taxonomies = taxo_page3;
  246. page3.lang = config.default_language.clone();
  247. library.insert_page(page3);
  248. let taxonomies = find_taxonomies(&config, &library).unwrap();
  249. let (tags, categories, authors) = {
  250. let mut t = None;
  251. let mut c = None;
  252. let mut a = None;
  253. for x in taxonomies {
  254. match x.kind.name.as_ref() {
  255. "tags" => t = Some(x),
  256. "categories" => c = Some(x),
  257. "authors" => a = Some(x),
  258. _ => unreachable!(),
  259. }
  260. }
  261. (t.unwrap(), c.unwrap(), a.unwrap())
  262. };
  263. assert_eq!(tags.items.len(), 3);
  264. assert_eq!(categories.items.len(), 2);
  265. assert_eq!(authors.items.len(), 1);
  266. assert_eq!(tags.items[0].name, "db");
  267. assert_eq!(tags.items[0].slug, "db");
  268. assert_eq!(tags.items[0].permalink, "http://a-website.com/tags/db/");
  269. assert_eq!(tags.items[0].pages.len(), 1);
  270. assert_eq!(tags.items[1].name, "js");
  271. assert_eq!(tags.items[1].slug, "js");
  272. assert_eq!(tags.items[1].permalink, "http://a-website.com/tags/js/");
  273. assert_eq!(tags.items[1].pages.len(), 2);
  274. assert_eq!(tags.items[2].name, "rust");
  275. assert_eq!(tags.items[2].slug, "rust");
  276. assert_eq!(tags.items[2].permalink, "http://a-website.com/tags/rust/");
  277. assert_eq!(tags.items[2].pages.len(), 2);
  278. assert_eq!(categories.items[0].name, "Other");
  279. assert_eq!(categories.items[0].slug, "other");
  280. assert_eq!(categories.items[0].permalink, "http://a-website.com/categories/other/");
  281. assert_eq!(categories.items[0].pages.len(), 1);
  282. assert_eq!(categories.items[1].name, "Programming tutorials");
  283. assert_eq!(categories.items[1].slug, "programming-tutorials");
  284. assert_eq!(
  285. categories.items[1].permalink,
  286. "http://a-website.com/categories/programming-tutorials/"
  287. );
  288. assert_eq!(categories.items[1].pages.len(), 1);
  289. }
  290. #[test]
  291. fn can_make_slugified_taxonomies() {
  292. let mut config = Config::default();
  293. let mut library = Library::new(2, 0, false);
  294. config.taxonomies = vec![
  295. TaxonomyConfig {
  296. name: "categories".to_string(),
  297. lang: config.default_language.clone(),
  298. ..TaxonomyConfig::default()
  299. },
  300. TaxonomyConfig {
  301. name: "tags".to_string(),
  302. lang: config.default_language.clone(),
  303. ..TaxonomyConfig::default()
  304. },
  305. TaxonomyConfig {
  306. name: "authors".to_string(),
  307. lang: config.default_language.clone(),
  308. ..TaxonomyConfig::default()
  309. },
  310. ];
  311. let mut page1 = Page::default();
  312. let mut taxo_page1 = HashMap::new();
  313. taxo_page1.insert("tags".to_string(), vec!["rust".to_string(), "db".to_string()]);
  314. taxo_page1.insert("categories".to_string(), vec!["Programming tutorials".to_string()]);
  315. page1.meta.taxonomies = taxo_page1;
  316. page1.lang = config.default_language.clone();
  317. library.insert_page(page1);
  318. let mut page2 = Page::default();
  319. let mut taxo_page2 = HashMap::new();
  320. taxo_page2.insert("tags".to_string(), vec!["rust".to_string(), "js".to_string()]);
  321. taxo_page2.insert("categories".to_string(), vec!["Other".to_string()]);
  322. page2.meta.taxonomies = taxo_page2;
  323. page2.lang = config.default_language.clone();
  324. library.insert_page(page2);
  325. let mut page3 = Page::default();
  326. let mut taxo_page3 = HashMap::new();
  327. taxo_page3.insert("tags".to_string(), vec!["js".to_string()]);
  328. taxo_page3.insert("authors".to_string(), vec!["Vincent Prouillet".to_string()]);
  329. page3.meta.taxonomies = taxo_page3;
  330. page3.lang = config.default_language.clone();
  331. library.insert_page(page3);
  332. let taxonomies = find_taxonomies(&config, &library).unwrap();
  333. let (tags, categories, authors) = {
  334. let mut t = None;
  335. let mut c = None;
  336. let mut a = None;
  337. for x in taxonomies {
  338. match x.kind.name.as_ref() {
  339. "tags" => t = Some(x),
  340. "categories" => c = Some(x),
  341. "authors" => a = Some(x),
  342. _ => unreachable!(),
  343. }
  344. }
  345. (t.unwrap(), c.unwrap(), a.unwrap())
  346. };
  347. assert_eq!(tags.items.len(), 3);
  348. assert_eq!(categories.items.len(), 2);
  349. assert_eq!(authors.items.len(), 1);
  350. assert_eq!(tags.items[0].name, "db");
  351. assert_eq!(tags.items[0].slug, "db");
  352. assert_eq!(tags.items[0].permalink, "http://a-website.com/tags/db/");
  353. assert_eq!(tags.items[0].pages.len(), 1);
  354. assert_eq!(tags.items[1].name, "js");
  355. assert_eq!(tags.items[1].slug, "js");
  356. assert_eq!(tags.items[1].permalink, "http://a-website.com/tags/js/");
  357. assert_eq!(tags.items[1].pages.len(), 2);
  358. assert_eq!(tags.items[2].name, "rust");
  359. assert_eq!(tags.items[2].slug, "rust");
  360. assert_eq!(tags.items[2].permalink, "http://a-website.com/tags/rust/");
  361. assert_eq!(tags.items[2].pages.len(), 2);
  362. assert_eq!(categories.items[0].name, "Other");
  363. assert_eq!(categories.items[0].slug, "other");
  364. assert_eq!(categories.items[0].permalink, "http://a-website.com/categories/other/");
  365. assert_eq!(categories.items[0].pages.len(), 1);
  366. assert_eq!(categories.items[1].name, "Programming tutorials");
  367. assert_eq!(categories.items[1].slug, "programming-tutorials");
  368. assert_eq!(
  369. categories.items[1].permalink,
  370. "http://a-website.com/categories/programming-tutorials/"
  371. );
  372. assert_eq!(categories.items[1].pages.len(), 1);
  373. }
  374. #[test]
  375. fn errors_on_unknown_taxonomy() {
  376. let mut config = Config::default();
  377. let mut library = Library::new(2, 0, false);
  378. config.taxonomies = vec![TaxonomyConfig {
  379. name: "authors".to_string(),
  380. lang: config.default_language.clone(),
  381. ..TaxonomyConfig::default()
  382. }];
  383. let mut page1 = Page::default();
  384. let mut taxo_page1 = HashMap::new();
  385. taxo_page1.insert("tags".to_string(), vec!["rust".to_string(), "db".to_string()]);
  386. page1.meta.taxonomies = taxo_page1;
  387. page1.lang = config.default_language.clone();
  388. library.insert_page(page1);
  389. let taxonomies = find_taxonomies(&config, &library);
  390. assert!(taxonomies.is_err());
  391. let err = taxonomies.unwrap_err();
  392. // no path as this is created by Default
  393. assert_eq!(
  394. format!("{}", err),
  395. "Page `` has taxonomy `tags` which is not defined in config.toml"
  396. );
  397. }
  398. #[test]
  399. fn can_make_taxonomies_in_multiple_languages() {
  400. let mut config = Config::default();
  401. config.languages.push(Language { rss: false, code: "fr".to_string(), search: false });
  402. let mut library = Library::new(2, 0, true);
  403. config.taxonomies = vec![
  404. TaxonomyConfig {
  405. name: "categories".to_string(),
  406. lang: config.default_language.clone(),
  407. ..TaxonomyConfig::default()
  408. },
  409. TaxonomyConfig {
  410. name: "tags".to_string(),
  411. lang: config.default_language.clone(),
  412. ..TaxonomyConfig::default()
  413. },
  414. TaxonomyConfig {
  415. name: "auteurs".to_string(),
  416. lang: "fr".to_string(),
  417. ..TaxonomyConfig::default()
  418. },
  419. TaxonomyConfig {
  420. name: "tags".to_string(),
  421. lang: "fr".to_string(),
  422. ..TaxonomyConfig::default()
  423. },
  424. ];
  425. let mut page1 = Page::default();
  426. let mut taxo_page1 = HashMap::new();
  427. taxo_page1.insert("tags".to_string(), vec!["rust".to_string(), "db".to_string()]);
  428. taxo_page1.insert("categories".to_string(), vec!["Programming tutorials".to_string()]);
  429. page1.meta.taxonomies = taxo_page1;
  430. page1.lang = config.default_language.clone();
  431. library.insert_page(page1);
  432. let mut page2 = Page::default();
  433. let mut taxo_page2 = HashMap::new();
  434. taxo_page2.insert("tags".to_string(), vec!["rust".to_string()]);
  435. taxo_page2.insert("categories".to_string(), vec!["Other".to_string()]);
  436. page2.meta.taxonomies = taxo_page2;
  437. page2.lang = config.default_language.clone();
  438. library.insert_page(page2);
  439. let mut page3 = Page::default();
  440. page3.lang = "fr".to_string();
  441. let mut taxo_page3 = HashMap::new();
  442. taxo_page3.insert("tags".to_string(), vec!["rust".to_string()]);
  443. taxo_page3.insert("auteurs".to_string(), vec!["Vincent Prouillet".to_string()]);
  444. page3.meta.taxonomies = taxo_page3;
  445. library.insert_page(page3);
  446. let taxonomies = find_taxonomies(&config, &library).unwrap();
  447. let (tags, categories, authors) = {
  448. let mut t = None;
  449. let mut c = None;
  450. let mut a = None;
  451. for x in taxonomies {
  452. match x.kind.name.as_ref() {
  453. "tags" => {
  454. if x.kind.lang == "en" {
  455. t = Some(x)
  456. }
  457. }
  458. "categories" => c = Some(x),
  459. "auteurs" => a = Some(x),
  460. _ => unreachable!(),
  461. }
  462. }
  463. (t.unwrap(), c.unwrap(), a.unwrap())
  464. };
  465. assert_eq!(tags.items.len(), 2);
  466. assert_eq!(categories.items.len(), 2);
  467. assert_eq!(authors.items.len(), 1);
  468. assert_eq!(tags.items[0].name, "db");
  469. assert_eq!(tags.items[0].slug, "db");
  470. assert_eq!(tags.items[0].permalink, "http://a-website.com/tags/db/");
  471. assert_eq!(tags.items[0].pages.len(), 1);
  472. assert_eq!(tags.items[1].name, "rust");
  473. assert_eq!(tags.items[1].slug, "rust");
  474. assert_eq!(tags.items[1].permalink, "http://a-website.com/tags/rust/");
  475. assert_eq!(tags.items[1].pages.len(), 2);
  476. assert_eq!(authors.items[0].name, "Vincent Prouillet");
  477. assert_eq!(authors.items[0].slug, "vincent-prouillet");
  478. assert_eq!(
  479. authors.items[0].permalink,
  480. "http://a-website.com/fr/auteurs/vincent-prouillet/"
  481. );
  482. assert_eq!(authors.items[0].pages.len(), 1);
  483. assert_eq!(categories.items[0].name, "Other");
  484. assert_eq!(categories.items[0].slug, "other");
  485. assert_eq!(categories.items[0].permalink, "http://a-website.com/categories/other/");
  486. assert_eq!(categories.items[0].pages.len(), 1);
  487. assert_eq!(categories.items[1].name, "Programming tutorials");
  488. assert_eq!(categories.items[1].slug, "programming-tutorials");
  489. assert_eq!(
  490. categories.items[1].permalink,
  491. "http://a-website.com/categories/programming-tutorials/"
  492. );
  493. assert_eq!(categories.items[1].pages.len(), 1);
  494. }
  495. #[test]
  496. fn can_make_utf8_taxonomies() {
  497. let mut config = Config::default();
  498. config.slugify_paths = false;
  499. config.languages.push(Language {
  500. rss: false,
  501. code: "fr".to_string(),
  502. ..Language::default()
  503. });
  504. let mut library = Library::new(2, 0, true);
  505. config.taxonomies = vec![TaxonomyConfig {
  506. name: "catégories".to_string(),
  507. lang: "fr".to_string(),
  508. ..TaxonomyConfig::default()
  509. }];
  510. let mut page = Page::default();
  511. page.lang = "fr".to_string();
  512. let mut taxo_page = HashMap::new();
  513. taxo_page.insert("catégories".to_string(), vec!["Écologie".to_string()]);
  514. page.meta.taxonomies = taxo_page;
  515. library.insert_page(page);
  516. let taxonomies = find_taxonomies(&config, &library).unwrap();
  517. let categories = &taxonomies[0];
  518. assert_eq!(categories.items.len(), 1);
  519. assert_eq!(categories.items[0].name, "Écologie");
  520. assert_eq!(categories.items[0].permalink, "http://a-website.com/fr/catégories/Écologie/");
  521. assert_eq!(categories.items[0].pages.len(), 1);
  522. }
  523. #[test]
  524. fn can_make_slugified_taxonomies_in_multiple_languages() {
  525. let mut config = Config::default();
  526. config.slugify_paths = true;
  527. config.languages.push(Language {
  528. rss: false,
  529. code: "fr".to_string(),
  530. ..Language::default()
  531. });
  532. let mut library = Library::new(2, 0, true);
  533. config.taxonomies = vec![
  534. TaxonomyConfig {
  535. name: "categories".to_string(),
  536. lang: config.default_language.clone(),
  537. ..TaxonomyConfig::default()
  538. },
  539. TaxonomyConfig {
  540. name: "tags".to_string(),
  541. lang: config.default_language.clone(),
  542. ..TaxonomyConfig::default()
  543. },
  544. TaxonomyConfig {
  545. name: "auteurs".to_string(),
  546. lang: "fr".to_string(),
  547. ..TaxonomyConfig::default()
  548. },
  549. TaxonomyConfig {
  550. name: "tags".to_string(),
  551. lang: "fr".to_string(),
  552. ..TaxonomyConfig::default()
  553. },
  554. ];
  555. let mut page1 = Page::default();
  556. let mut taxo_page1 = HashMap::new();
  557. taxo_page1.insert("tags".to_string(), vec!["rust".to_string(), "db".to_string()]);
  558. taxo_page1.insert("categories".to_string(), vec!["Programming tutorials".to_string()]);
  559. page1.meta.taxonomies = taxo_page1;
  560. page1.lang = config.default_language.clone();
  561. library.insert_page(page1);
  562. let mut page2 = Page::default();
  563. let mut taxo_page2 = HashMap::new();
  564. taxo_page2.insert("tags".to_string(), vec!["rust".to_string()]);
  565. taxo_page2.insert("categories".to_string(), vec!["Other".to_string()]);
  566. page2.meta.taxonomies = taxo_page2;
  567. page2.lang = config.default_language.clone();
  568. library.insert_page(page2);
  569. let mut page3 = Page::default();
  570. page3.lang = "fr".to_string();
  571. let mut taxo_page3 = HashMap::new();
  572. taxo_page3.insert("tags".to_string(), vec!["rust".to_string()]);
  573. taxo_page3.insert("auteurs".to_string(), vec!["Vincent Prouillet".to_string()]);
  574. page3.meta.taxonomies = taxo_page3;
  575. library.insert_page(page3);
  576. let taxonomies = find_taxonomies(&config, &library).unwrap();
  577. let (tags, categories, authors) = {
  578. let mut t = None;
  579. let mut c = None;
  580. let mut a = None;
  581. for x in taxonomies {
  582. match x.kind.name.as_ref() {
  583. "tags" => {
  584. if x.kind.lang == "en" {
  585. t = Some(x)
  586. }
  587. }
  588. "categories" => c = Some(x),
  589. "auteurs" => a = Some(x),
  590. _ => unreachable!(),
  591. }
  592. }
  593. (t.unwrap(), c.unwrap(), a.unwrap())
  594. };
  595. assert_eq!(tags.items.len(), 2);
  596. assert_eq!(categories.items.len(), 2);
  597. assert_eq!(authors.items.len(), 1);
  598. assert_eq!(tags.items[0].name, "db");
  599. assert_eq!(tags.items[0].slug, "db");
  600. assert_eq!(tags.items[0].permalink, "http://a-website.com/tags/db/");
  601. assert_eq!(tags.items[0].pages.len(), 1);
  602. assert_eq!(tags.items[1].name, "rust");
  603. assert_eq!(tags.items[1].slug, "rust");
  604. assert_eq!(tags.items[1].permalink, "http://a-website.com/tags/rust/");
  605. assert_eq!(tags.items[1].pages.len(), 2);
  606. assert_eq!(authors.items[0].name, "Vincent Prouillet");
  607. assert_eq!(authors.items[0].slug, "vincent-prouillet");
  608. assert_eq!(
  609. authors.items[0].permalink,
  610. "http://a-website.com/fr/auteurs/vincent-prouillet/"
  611. );
  612. assert_eq!(authors.items[0].pages.len(), 1);
  613. assert_eq!(categories.items[0].name, "Other");
  614. assert_eq!(categories.items[0].slug, "other");
  615. assert_eq!(categories.items[0].permalink, "http://a-website.com/categories/other/");
  616. assert_eq!(categories.items[0].pages.len(), 1);
  617. assert_eq!(categories.items[1].name, "Programming tutorials");
  618. assert_eq!(categories.items[1].slug, "programming-tutorials");
  619. assert_eq!(
  620. categories.items[1].permalink,
  621. "http://a-website.com/categories/programming-tutorials/"
  622. );
  623. assert_eq!(categories.items[1].pages.len(), 1);
  624. }
  625. }