|
|
@@ -12,11 +12,11 @@ extern crate rustc_serialize;
|
|
|
extern crate test;
|
|
|
extern crate url;
|
|
|
|
|
|
-use rustc_serialize::json::Json;
|
|
|
-use url::{Url, Position};
|
|
|
+use rustc_serialize::json::{self, Json};
|
|
|
+use url::{Url, quirks};
|
|
|
|
|
|
|
|
|
-fn run_parsing(input: String, base: String, expected: Result<ParsingTestCase, ()>) {
|
|
|
+fn run_parsing(input: String, base: String, expected: Result<ExpectedAttributes, ()>) {
|
|
|
let base = match Url::parse(&base) {
|
|
|
Ok(base) => base,
|
|
|
Err(message) => panic!("Error parsing base {:?}: {}", base, message)
|
|
|
@@ -41,30 +41,24 @@ fn run_parsing(input: String, base: String, expected: Result<ParsingTestCase, ()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- assert_eq!(expected.href, url.as_str());
|
|
|
- if let Some(expected_origin) = expected.origin {
|
|
|
- assert_eq!(expected_origin, url.origin().unicode_serialization());
|
|
|
+ macro_rules! assert_attributes {
|
|
|
+ ($($attr: ident)+) => {
|
|
|
+ {
|
|
|
+ $(
|
|
|
+ assert_eq!(expected.$attr, quirks::$attr(&url));
|
|
|
+ )+;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- assert_eq!(expected.protocol, &url.as_str()[..url.scheme().len() + ":".len()]);
|
|
|
- assert_eq!(expected.username, url.username());
|
|
|
- assert_eq!(expected.password, url.password().unwrap_or(""));
|
|
|
- assert_eq!(expected.host, &url[Position::BeforeHost..Position::AfterPort]);
|
|
|
- assert_eq!(expected.hostname, url.host_str().unwrap_or(""));
|
|
|
- assert_eq!(expected.port, &url[Position::BeforePort..Position::AfterPort]);
|
|
|
- assert_eq!(expected.pathname, url.path());
|
|
|
- assert_eq!(expected.search, trim(&url[Position::AfterPath..Position::AfterQuery]));
|
|
|
- assert_eq!(expected.hash, trim(&url[Position::AfterQuery..]));
|
|
|
-}
|
|
|
|
|
|
-fn trim(s: &str) -> &str {
|
|
|
- if s.len() == 1 {
|
|
|
- ""
|
|
|
- } else {
|
|
|
- s
|
|
|
+ assert_attributes!(href protocol username password host hostname port pathname search hash);
|
|
|
+
|
|
|
+ if let Some(expected_origin) = expected.origin {
|
|
|
+ assert_eq!(expected_origin, quirks::origin(&url));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-struct ParsingTestCase {
|
|
|
+struct ExpectedAttributes {
|
|
|
href: String,
|
|
|
origin: Option<String>,
|
|
|
protocol: String,
|
|
|
@@ -78,32 +72,56 @@ struct ParsingTestCase {
|
|
|
hash: String,
|
|
|
}
|
|
|
|
|
|
+trait JsonExt {
|
|
|
+ fn take(&mut self, key: &str) -> Option<Json>;
|
|
|
+ fn object(self) -> json::Object;
|
|
|
+ fn string(self) -> String;
|
|
|
+ fn take_string(&mut self, key: &str) -> String;
|
|
|
+}
|
|
|
+
|
|
|
+impl JsonExt for Json {
|
|
|
+ fn take(&mut self, key: &str) -> Option<Json> {
|
|
|
+ self.as_object_mut().unwrap().remove(key)
|
|
|
+ }
|
|
|
+
|
|
|
+ fn object(self) -> json::Object {
|
|
|
+ if let Json::Object(o) = self { o } else { panic!("Not a Json::Object") }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn string(self) -> String {
|
|
|
+ if let Json::String(s) = self { s } else { panic!("Not a Json::String") }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn take_string(&mut self, key: &str) -> String {
|
|
|
+ self.take(key).unwrap().string()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
fn collect_parsing<F: FnMut(String, test::TestFn)>(add_test: &mut F) {
|
|
|
// Copied form https://github.com/w3c/web-platform-tests/blob/master/url/
|
|
|
- let json = Json::from_str(include_str!("urltestdata.json"))
|
|
|
+ let mut json = Json::from_str(include_str!("urltestdata.json"))
|
|
|
.expect("JSON parse error in urltestdata.json");
|
|
|
- for entry in json.as_array().unwrap() {
|
|
|
+ for entry in json.as_array_mut().unwrap() {
|
|
|
if entry.is_string() {
|
|
|
continue // ignore comments
|
|
|
}
|
|
|
- let string = |key| entry.find(key).unwrap().as_string().unwrap().to_owned();
|
|
|
- let base = string("base");
|
|
|
- let input = string("input");
|
|
|
+ let base = entry.take_string("base");
|
|
|
+ let input = entry.take_string("input");
|
|
|
let expected = if entry.find("failure").is_some() {
|
|
|
Err(())
|
|
|
} else {
|
|
|
- Ok(ParsingTestCase {
|
|
|
- href: string("href"),
|
|
|
- origin: entry.find("origin").map(|j| j.as_string().unwrap().to_owned()),
|
|
|
- protocol: string("protocol"),
|
|
|
- username: string("username"),
|
|
|
- password: string("password"),
|
|
|
- host: string("host"),
|
|
|
- hostname: string("hostname"),
|
|
|
- port: string("port"),
|
|
|
- pathname: string("pathname"),
|
|
|
- search: string("search"),
|
|
|
- hash: string("hash"),
|
|
|
+ Ok(ExpectedAttributes {
|
|
|
+ href: entry.take_string("href"),
|
|
|
+ origin: entry.take("origin").map(Json::string),
|
|
|
+ protocol: entry.take_string("protocol"),
|
|
|
+ username: entry.take_string("username"),
|
|
|
+ password: entry.take_string("password"),
|
|
|
+ host: entry.take_string("host"),
|
|
|
+ hostname: entry.take_string("hostname"),
|
|
|
+ port: entry.take_string("port"),
|
|
|
+ pathname: entry.take_string("pathname"),
|
|
|
+ search: entry.take_string("search"),
|
|
|
+ hash: entry.take_string("hash"),
|
|
|
})
|
|
|
};
|
|
|
add_test(format!("{:?} @ base {:?}", input, base),
|
|
|
@@ -111,6 +129,48 @@ fn collect_parsing<F: FnMut(String, test::TestFn)>(add_test: &mut F) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+fn collect_setters<F>(add_test: &mut F) where F: FnMut(String, test::TestFn) {
|
|
|
+ let mut json = Json::from_str(include_str!("setters_tests.json"))
|
|
|
+ .expect("JSON parse error in setters_tests.json");
|
|
|
+
|
|
|
+ macro_rules! setter {
|
|
|
+ ($attr: expr, $setter: ident) => {{
|
|
|
+ let mut tests = json.take($attr).unwrap();
|
|
|
+ for mut test in tests.as_array_mut().unwrap().drain(..) {
|
|
|
+ let comment = test.take("comment").map(Json::string).unwrap_or(String::new());
|
|
|
+ let href = test.take_string("href");
|
|
|
+ let new_value = test.take_string("new_value");
|
|
|
+ let name = format!("{:?}.{} = {:?} {}", href, $attr, new_value, comment);
|
|
|
+ let mut expected = test.take("expected").unwrap();
|
|
|
+ add_test(name, test::TestFn::dyn_test_fn(move || {
|
|
|
+ let mut url = Url::parse(&href).unwrap();
|
|
|
+ let _ = quirks::$setter(&mut url, &new_value);
|
|
|
+ assert_attributes!(url, expected,
|
|
|
+ href protocol username password host hostname port pathname search hash);
|
|
|
+ }))
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ }
|
|
|
+ macro_rules! assert_attributes {
|
|
|
+ ($url: expr, $expected: expr, $($attr: ident)+) => {
|
|
|
+ $(
|
|
|
+ if let Some(value) = $expected.take(stringify!($attr)) {
|
|
|
+ assert_eq!(quirks::$attr(&$url), value.string())
|
|
|
+ }
|
|
|
+ )+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ setter!("protocol", set_protocol);
|
|
|
+ setter!("username", set_username);
|
|
|
+ setter!("password", set_password);
|
|
|
+ setter!("hostname", set_hostname);
|
|
|
+ setter!("host", set_host);
|
|
|
+ setter!("port", set_port);
|
|
|
+ setter!("pathname", set_pathname);
|
|
|
+ setter!("search", set_search);
|
|
|
+ setter!("hash", set_hash);
|
|
|
+}
|
|
|
+
|
|
|
fn main() {
|
|
|
let mut tests = Vec::new();
|
|
|
{
|
|
|
@@ -125,6 +185,7 @@ fn main() {
|
|
|
})
|
|
|
};
|
|
|
collect_parsing(&mut add_one);
|
|
|
+ collect_setters(&mut add_one);
|
|
|
}
|
|
|
test::test_main(&std::env::args().collect::<Vec<_>>(), tests)
|
|
|
}
|