1 #![feature(proc_macro_hygiene)] 2 3 #[cfg(feature = "templates")] 4 #[macro_use] extern crate rocket; 5 6 #[cfg(feature = "templates")] 7 mod templates_tests { 8 use std::path::{Path, PathBuf}; 9 10 use rocket::{Rocket, http::RawStr}; 11 use rocket::config::{Config, Environment}; 12 use rocket_contrib::templates::{Template, Metadata}; 13 14 #[get("/<engine>/<name>")] template_check(md: Metadata<'_>, engine: &RawStr, name: &RawStr) -> Option<()>15 fn template_check(md: Metadata<'_>, engine: &RawStr, name: &RawStr) -> Option<()> { 16 match md.contains_template(&format!("{}/{}", engine, name)) { 17 true => Some(()), 18 false => None 19 } 20 } 21 22 #[get("/is_reloading")] is_reloading(md: Metadata<'_>) -> Option<()>23 fn is_reloading(md: Metadata<'_>) -> Option<()> { 24 if md.reloading() { Some(()) } else { None } 25 } 26 template_root() -> PathBuf27 fn template_root() -> PathBuf { 28 Path::new(env!("CARGO_MANIFEST_DIR")).join("tests").join("templates") 29 } 30 rocket() -> Rocket31 fn rocket() -> Rocket { 32 let config = Config::build(Environment::Development) 33 .extra("template_dir", template_root().to_str().expect("template directory")) 34 .expect("valid configuration"); 35 36 rocket::custom(config).attach(Template::fairing()) 37 .mount("/", routes![template_check, is_reloading]) 38 } 39 40 #[cfg(feature = "tera_templates")] 41 mod tera_tests { 42 use super::*; 43 use std::collections::HashMap; 44 use rocket::http::Status; 45 use rocket::local::Client; 46 47 const UNESCAPED_EXPECTED: &'static str 48 = "\nh_start\ntitle: _test_\nh_end\n\n\n<script />\n\nfoot\n"; 49 const ESCAPED_EXPECTED: &'static str 50 = "\nh_start\ntitle: _test_\nh_end\n\n\n<script />\n\nfoot\n"; 51 52 #[test] test_tera_templates()53 fn test_tera_templates() { 54 let rocket = rocket(); 55 let mut map = HashMap::new(); 56 map.insert("title", "_test_"); 57 map.insert("content", "<script />"); 58 59 // Test with a txt file, which shouldn't escape. 60 let template = Template::show(&rocket, "tera/txt_test", &map); 61 assert_eq!(template, Some(UNESCAPED_EXPECTED.into())); 62 63 // Now with an HTML file, which should. 64 let template = Template::show(&rocket, "tera/html_test", &map); 65 assert_eq!(template, Some(ESCAPED_EXPECTED.into())); 66 } 67 68 #[test] test_template_metadata_with_tera()69 fn test_template_metadata_with_tera() { 70 let client = Client::new(rocket()).unwrap(); 71 72 let response = client.get("/tera/txt_test").dispatch(); 73 assert_eq!(response.status(), Status::Ok); 74 75 let response = client.get("/tera/html_test").dispatch(); 76 assert_eq!(response.status(), Status::Ok); 77 78 let response = client.get("/tera/not_existing").dispatch(); 79 assert_eq!(response.status(), Status::NotFound); 80 81 let response = client.get("/hbs/txt_test").dispatch(); 82 assert_eq!(response.status(), Status::NotFound); 83 } 84 } 85 86 #[cfg(feature = "handlebars_templates")] 87 mod handlebars_tests { 88 use super::*; 89 use std::collections::HashMap; 90 use rocket::http::Status; 91 use rocket::local::Client; 92 93 const EXPECTED: &'static str 94 = "Hello _test_!\n\n<main> <script /> hi </main>\nDone.\n\n"; 95 96 #[test] test_handlebars_templates()97 fn test_handlebars_templates() { 98 let rocket = rocket(); 99 let mut map = HashMap::new(); 100 map.insert("title", "_test_"); 101 map.insert("content", "<script /> hi"); 102 103 // Test with a txt file, which shouldn't escape. 104 let template = Template::show(&rocket, "hbs/test", &map); 105 assert_eq!(template, Some(EXPECTED.into())); 106 } 107 108 #[test] test_template_metadata_with_handlebars()109 fn test_template_metadata_with_handlebars() { 110 let client = Client::new(rocket()).unwrap(); 111 112 let response = client.get("/hbs/test").dispatch(); 113 assert_eq!(response.status(), Status::Ok); 114 115 let response = client.get("/hbs/not_existing").dispatch(); 116 assert_eq!(response.status(), Status::NotFound); 117 118 let response = client.get("/tera/test").dispatch(); 119 assert_eq!(response.status(), Status::NotFound); 120 } 121 122 #[test] 123 #[cfg(debug_assertions)] test_template_reload()124 fn test_template_reload() { 125 use std::fs::File; 126 use std::io::Write; 127 use std::thread; 128 use std::time::Duration; 129 130 use rocket::local::Client; 131 132 const RELOAD_TEMPLATE: &str = "hbs/reload"; 133 const INITIAL_TEXT: &str = "initial"; 134 const NEW_TEXT: &str = "reload"; 135 136 fn write_file(path: &Path, text: &str) { 137 let mut file = File::create(path).expect("open file"); 138 file.write_all(text.as_bytes()).expect("write file"); 139 file.sync_all().expect("sync file"); 140 } 141 142 // set up the template before initializing the Rocket instance so 143 // that it will be picked up in the initial loading of templates. 144 let reload_path = template_root().join("hbs").join("reload.txt.hbs"); 145 write_file(&reload_path, INITIAL_TEXT); 146 147 // set up the client. if we can't reload templates, then just quit 148 let client = Client::new(rocket()).unwrap(); 149 let res = client.get("/is_reloading").dispatch(); 150 if res.status() != Status::Ok { 151 return; 152 } 153 154 // verify that the initial content is correct 155 let initial_rendered = Template::show(client.rocket(), RELOAD_TEMPLATE, ()); 156 assert_eq!(initial_rendered, Some(INITIAL_TEXT.into())); 157 158 // write a change to the file 159 write_file(&reload_path, NEW_TEXT); 160 161 for _ in 0..6 { 162 // dispatch any request to trigger a template reload 163 client.get("/").dispatch(); 164 165 // if the new content is correct, we are done 166 let new_rendered = Template::show(client.rocket(), RELOAD_TEMPLATE, ()); 167 if new_rendered == Some(NEW_TEXT.into()) { 168 write_file(&reload_path, INITIAL_TEXT); 169 return; 170 } 171 172 // otherwise, retry a few times, waiting 250ms in between 173 thread::sleep(Duration::from_millis(250)); 174 } 175 176 panic!("failed to reload modified template in 1.5s"); 177 } 178 } 179 } 180