wpt.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. // Copyright 2013-2014 The rust-url developers.
  2. //
  3. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  4. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  5. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  6. // option. This file may not be copied, modified, or distributed
  7. // except according to those terms.
  8. //! Data-driven tests imported from web-platform-tests
  9. use serde_json::Value;
  10. use std::collections::HashMap;
  11. use std::fmt::Write;
  12. #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
  13. use std::sync::Mutex;
  14. use url::Url;
  15. // https://rustwasm.github.io/wasm-bindgen/wasm-bindgen-test/usage.html
  16. #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
  17. use wasm_bindgen_test::{console_log, wasm_bindgen_test, wasm_bindgen_test_configure};
  18. #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
  19. wasm_bindgen_test_configure!(run_in_browser);
  20. // wpt has its own test driver, but we shoe-horn this into wasm_bindgen_test
  21. // which will discard stdout and stderr. So, we make println! go to
  22. // console.log(), so we see failures that do not result in panics.
  23. #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
  24. static PRINT_BUF: Mutex<Option<String>> = Mutex::new(None);
  25. #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
  26. macro_rules! print {
  27. ($($arg:tt)*) => {
  28. let v = format!($($arg)*);
  29. {
  30. let mut buf = PRINT_BUF.lock().unwrap();
  31. if let Some(buf) = buf.as_mut() {
  32. buf.push_str(&v);
  33. } else {
  34. *buf = Some(v);
  35. }
  36. }
  37. };
  38. }
  39. #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
  40. macro_rules! println {
  41. () => {
  42. let buf = PRINT_BUF.lock().unwrap().take();
  43. match buf {
  44. Some(buf) => console_log!("{buf}"),
  45. None => console_log!(""),
  46. }
  47. };
  48. ($($arg:tt)*) => {
  49. let buf = PRINT_BUF.lock().unwrap().take();
  50. match buf {
  51. Some(buf) => {
  52. let v = format!($($arg)*);
  53. console_log!("{buf}{v}");
  54. },
  55. None => console_log!($($arg)*),
  56. }
  57. }
  58. }
  59. #[derive(Debug, serde::Deserialize)]
  60. struct UrlTest {
  61. input: String,
  62. base: Option<String>,
  63. #[serde(flatten)]
  64. result: UrlTestResult,
  65. }
  66. #[derive(Debug, serde::Deserialize)]
  67. #[serde(untagged)]
  68. #[allow(clippy::large_enum_variant)]
  69. enum UrlTestResult {
  70. Ok(UrlTestOk),
  71. Fail(UrlTestFail),
  72. }
  73. #[derive(Debug, serde::Deserialize)]
  74. struct UrlTestOk {
  75. href: String,
  76. protocol: String,
  77. username: String,
  78. password: String,
  79. host: String,
  80. hostname: String,
  81. port: String,
  82. pathname: String,
  83. search: String,
  84. hash: String,
  85. }
  86. #[derive(Debug, serde::Deserialize)]
  87. struct UrlTestFail {
  88. failure: bool,
  89. }
  90. #[derive(Debug, serde::Deserialize)]
  91. struct SetterTest {
  92. href: String,
  93. new_value: String,
  94. expected: SetterTestExpected,
  95. }
  96. #[derive(Debug, serde::Deserialize)]
  97. struct SetterTestExpected {
  98. href: Option<String>,
  99. protocol: Option<String>,
  100. username: Option<String>,
  101. password: Option<String>,
  102. host: Option<String>,
  103. hostname: Option<String>,
  104. port: Option<String>,
  105. pathname: Option<String>,
  106. search: Option<String>,
  107. hash: Option<String>,
  108. }
  109. #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)]
  110. fn main() {
  111. let mut filter = None;
  112. let mut args = std::env::args().skip(1);
  113. while filter.is_none() {
  114. if let Some(arg) = args.next() {
  115. if arg == "--test-threads" {
  116. args.next();
  117. continue;
  118. }
  119. filter = Some(arg);
  120. } else {
  121. break;
  122. }
  123. }
  124. let mut expected_failures = include_str!("expected_failures.txt")
  125. .lines()
  126. .collect::<Vec<_>>();
  127. let mut errors = vec![];
  128. // Copied from https://github.com/web-platform-tests/wpt/blob/master/url/
  129. let url_json: Vec<Value> = serde_json::from_str(include_str!("urltestdata.json"))
  130. .expect("JSON parse error in urltestdata.json");
  131. let url_tests = url_json
  132. .into_iter()
  133. .filter(|val| val.is_object())
  134. .map(|val| serde_json::from_value::<UrlTest>(val).expect("parsing failed"))
  135. .collect::<Vec<_>>();
  136. let setter_json: HashMap<String, Value> =
  137. serde_json::from_str(include_str!("setters_tests.json"))
  138. .expect("JSON parse error in setters_tests.json");
  139. let setter_tests = setter_json
  140. .into_iter()
  141. .filter(|(k, _)| k != "comment")
  142. .map(|(k, v)| {
  143. let test = serde_json::from_value::<Vec<SetterTest>>(v).expect("parsing failed");
  144. (k, test)
  145. })
  146. .collect::<HashMap<_, _>>();
  147. for url_test in url_tests {
  148. let mut name = format!("<{}>", url_test.input.escape_default());
  149. if let Some(base) = &url_test.base {
  150. write!(&mut name, " against <{}>", base.escape_default()).unwrap();
  151. }
  152. if should_skip(&name, filter.as_deref()) {
  153. continue;
  154. }
  155. print!("{} ... ", name);
  156. let res = run_url_test(url_test);
  157. report(name, res, &mut errors, &mut expected_failures);
  158. }
  159. for (kind, tests) in setter_tests {
  160. for test in tests {
  161. let name = format!(
  162. "<{}> set {} to <{}>",
  163. test.href.escape_default(),
  164. kind,
  165. test.new_value.escape_default()
  166. );
  167. if should_skip(&name, filter.as_deref()) {
  168. continue;
  169. }
  170. print!("{} ... ", name);
  171. let res = run_setter_test(&kind, test);
  172. report(name, res, &mut errors, &mut expected_failures);
  173. }
  174. }
  175. println!();
  176. println!("====================");
  177. println!();
  178. if !errors.is_empty() {
  179. println!("errors:");
  180. println!();
  181. for (name, err) in errors {
  182. println!(" name: {}", name);
  183. println!(" err: {}", err);
  184. println!();
  185. }
  186. std::process::exit(1);
  187. } else {
  188. println!("all tests passed");
  189. }
  190. if !expected_failures.is_empty() && filter.is_none() {
  191. println!();
  192. println!("====================");
  193. println!();
  194. println!("tests were expected to fail but did not run:");
  195. println!();
  196. for name in expected_failures {
  197. println!(" {}", name);
  198. }
  199. println!();
  200. println!("if these tests were removed, update expected_failures.txt");
  201. println!();
  202. std::process::exit(1);
  203. }
  204. }
  205. fn should_skip(name: &str, filter: Option<&str>) -> bool {
  206. match filter {
  207. Some(filter) => !name.contains(filter),
  208. None => false,
  209. }
  210. }
  211. fn report(
  212. name: String,
  213. res: Result<(), String>,
  214. errors: &mut Vec<(String, String)>,
  215. expected_failures: &mut Vec<&str>,
  216. ) {
  217. let expected_failure = expected_failures.contains(&&*name);
  218. expected_failures.retain(|&s| s != &*name);
  219. match res {
  220. Ok(()) => {
  221. if expected_failure {
  222. println!("🟠 (unexpected success)");
  223. errors.push((name, "unexpected success".to_string()));
  224. } else {
  225. println!("✅");
  226. }
  227. }
  228. Err(err) => {
  229. if expected_failure {
  230. println!("✅ (expected fail)");
  231. } else {
  232. println!("❌");
  233. errors.push((name, err));
  234. }
  235. }
  236. }
  237. }
  238. fn run_url_test(
  239. UrlTest {
  240. base,
  241. input,
  242. result,
  243. }: UrlTest,
  244. ) -> Result<(), String> {
  245. let base = match base {
  246. Some(base) => {
  247. let base =
  248. Url::parse(&base).map_err(|e| format!("errored while parsing base: {}", e))?;
  249. Some(base)
  250. }
  251. None => None,
  252. };
  253. let res = Url::options()
  254. .base_url(base.as_ref())
  255. .parse(&input)
  256. .map_err(|e| format!("errored while parsing input: {}", e));
  257. match result {
  258. UrlTestResult::Ok(ok) => check_url_ok(res, ok),
  259. UrlTestResult::Fail(fail) => {
  260. assert!(fail.failure);
  261. if res.is_ok() {
  262. return Err("expected failure, but parsed successfully".to_string());
  263. }
  264. Ok(())
  265. }
  266. }
  267. }
  268. fn check_url_ok(res: Result<Url, String>, ok: UrlTestOk) -> Result<(), String> {
  269. let url = match res {
  270. Ok(url) => url,
  271. Err(err) => {
  272. return Err(format!("expected success, but errored: {:?}", err));
  273. }
  274. };
  275. let href = url::quirks::href(&url);
  276. if href != ok.href {
  277. return Err(format!("expected href {:?}, but got {:?}", ok.href, href));
  278. }
  279. let protocol = url::quirks::protocol(&url);
  280. if protocol != ok.protocol {
  281. return Err(format!(
  282. "expected protocol {:?}, but got {:?}",
  283. ok.protocol, protocol
  284. ));
  285. }
  286. let username = url::quirks::username(&url);
  287. if username != ok.username {
  288. return Err(format!(
  289. "expected username {:?}, but got {:?}",
  290. ok.username, username
  291. ));
  292. }
  293. let password = url::quirks::password(&url);
  294. if password != ok.password {
  295. return Err(format!(
  296. "expected password {:?}, but got {:?}",
  297. ok.password, password
  298. ));
  299. }
  300. let host = url::quirks::host(&url);
  301. if host != ok.host {
  302. return Err(format!("expected host {:?}, but got {:?}", ok.host, host));
  303. }
  304. let hostname = url::quirks::hostname(&url);
  305. if hostname != ok.hostname {
  306. return Err(format!(
  307. "expected hostname {:?}, but got {:?}",
  308. ok.hostname, hostname
  309. ));
  310. }
  311. let port = url::quirks::port(&url);
  312. if port != ok.port {
  313. return Err(format!("expected port {:?}, but got {:?}", ok.port, port));
  314. }
  315. let pathname = url::quirks::pathname(&url);
  316. if pathname != ok.pathname {
  317. return Err(format!(
  318. "expected pathname {:?}, but got {:?}",
  319. ok.pathname, pathname
  320. ));
  321. }
  322. let search = url::quirks::search(&url);
  323. if search != ok.search {
  324. return Err(format!(
  325. "expected search {:?}, but got {:?}",
  326. ok.search, search
  327. ));
  328. }
  329. let hash = url::quirks::hash(&url);
  330. if hash != ok.hash {
  331. return Err(format!("expected hash {:?}, but got {:?}", ok.hash, hash));
  332. }
  333. Ok(())
  334. }
  335. fn run_setter_test(
  336. kind: &str,
  337. SetterTest {
  338. href,
  339. new_value,
  340. expected,
  341. }: SetterTest,
  342. ) -> Result<(), String> {
  343. let mut url = Url::parse(&href).map_err(|e| format!("errored while parsing href: {}", e))?;
  344. match kind {
  345. "protocol" => {
  346. url::quirks::set_protocol(&mut url, &new_value).ok();
  347. }
  348. "username" => {
  349. url::quirks::set_username(&mut url, &new_value).ok();
  350. }
  351. "password" => {
  352. url::quirks::set_password(&mut url, &new_value).ok();
  353. }
  354. "host" => {
  355. url::quirks::set_host(&mut url, &new_value).ok();
  356. }
  357. "hostname" => {
  358. url::quirks::set_hostname(&mut url, &new_value).ok();
  359. }
  360. "port" => {
  361. url::quirks::set_port(&mut url, &new_value).ok();
  362. }
  363. "pathname" => url::quirks::set_pathname(&mut url, &new_value),
  364. "search" => url::quirks::set_search(&mut url, &new_value),
  365. "hash" => url::quirks::set_hash(&mut url, &new_value),
  366. _ => {
  367. return Err(format!("unknown setter kind: {:?}", kind));
  368. }
  369. }
  370. if let Some(expected_href) = expected.href {
  371. let href = url::quirks::href(&url);
  372. if href != expected_href {
  373. return Err(format!(
  374. "expected href {:?}, but got {:?}",
  375. expected_href, href
  376. ));
  377. }
  378. }
  379. if let Some(expected_protocol) = expected.protocol {
  380. let protocol = url::quirks::protocol(&url);
  381. if protocol != expected_protocol {
  382. return Err(format!(
  383. "expected protocol {:?}, but got {:?}",
  384. expected_protocol, protocol
  385. ));
  386. }
  387. }
  388. if let Some(expected_username) = expected.username {
  389. let username = url::quirks::username(&url);
  390. if username != expected_username {
  391. return Err(format!(
  392. "expected username {:?}, but got {:?}",
  393. expected_username, username
  394. ));
  395. }
  396. }
  397. if let Some(expected_password) = expected.password {
  398. let password = url::quirks::password(&url);
  399. if password != expected_password {
  400. return Err(format!(
  401. "expected password {:?}, but got {:?}",
  402. expected_password, password
  403. ));
  404. }
  405. }
  406. if let Some(expected_host) = expected.host {
  407. let host = url::quirks::host(&url);
  408. if host != expected_host {
  409. return Err(format!(
  410. "expected host {:?}, but got {:?}",
  411. expected_host, host
  412. ));
  413. }
  414. }
  415. if let Some(expected_hostname) = expected.hostname {
  416. let hostname = url::quirks::hostname(&url);
  417. if hostname != expected_hostname {
  418. return Err(format!(
  419. "expected hostname {:?}, but got {:?}",
  420. expected_hostname, hostname
  421. ));
  422. }
  423. }
  424. if let Some(expected_port) = expected.port {
  425. let port = url::quirks::port(&url);
  426. if port != expected_port {
  427. return Err(format!(
  428. "expected port {:?}, but got {:?}",
  429. expected_port, port
  430. ));
  431. }
  432. }
  433. if let Some(expected_pathname) = expected.pathname {
  434. let pathname = url::quirks::pathname(&url);
  435. if pathname != expected_pathname {
  436. return Err(format!(
  437. "expected pathname {:?}, but got {:?}",
  438. expected_pathname, pathname
  439. ));
  440. }
  441. }
  442. if let Some(expected_search) = expected.search {
  443. let search = url::quirks::search(&url);
  444. if search != expected_search {
  445. return Err(format!(
  446. "expected search {:?}, but got {:?}",
  447. expected_search, search
  448. ));
  449. }
  450. }
  451. if let Some(expected_hash) = expected.hash {
  452. let hash = url::quirks::hash(&url);
  453. if hash != expected_hash {
  454. return Err(format!(
  455. "expected hash {:?}, but got {:?}",
  456. expected_hash, hash
  457. ));
  458. }
  459. }
  460. Ok(())
  461. }