зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #5574 - Move unit tests to their own crates, cut time by 96% (from servo:unit-tests); r=jack
On my laptop, running `./mach test-unit` goes from about 11 minutes to 22 seconds, when run after `./mach build`. Fix #5291. Source-Repo: https://github.com/servo/servo Source-Revision: 017d1053617f6769d7f355e4a97d52ae67e53d1c --HG-- rename : servo/components/net/test.jpeg => servo/tests/unit/net/test.jpeg rename : servo/components/script/tests.rs => servo/tests/unit/script/size_of.rs
This commit is contained in:
Родитель
5cfb1364bd
Коммит
5b41ccfb98
|
@ -127,163 +127,3 @@ pub fn fixed_to_rounded_int(before: int, f: i32) -> int {
|
|||
-((half - f) >> before as uint) as int
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_compress_none() {
|
||||
let test_strs = [
|
||||
" foo bar",
|
||||
"foo bar ",
|
||||
"foo\n bar",
|
||||
"foo \nbar",
|
||||
" foo bar \nbaz",
|
||||
"foo bar baz",
|
||||
"foobarbaz\n\n",
|
||||
];
|
||||
|
||||
let mode = CompressionMode::CompressNone;
|
||||
for &test in test_strs.iter() {
|
||||
let mut new_line_pos = vec![];
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(trimmed_str.as_slice(), test)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_discard_newline() {
|
||||
let test_strs = [
|
||||
(" foo bar",
|
||||
" foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("foo\n bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo \nbar",
|
||||
"foo bar"),
|
||||
|
||||
(" foo bar \nbaz",
|
||||
" foo bar baz"),
|
||||
|
||||
("foo bar baz",
|
||||
"foo bar baz"),
|
||||
|
||||
("foobarbaz\n\n",
|
||||
"foobarbaz"),
|
||||
];
|
||||
|
||||
let mode = CompressionMode::DiscardNewline;
|
||||
for &(test, oracle) in test_strs.iter() {
|
||||
let mut new_line_pos = vec![];
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(trimmed_str.as_slice(), oracle)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_compress_whitespace() {
|
||||
let test_strs = [
|
||||
(" foo bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("foo\n bar",
|
||||
"foo\n bar"),
|
||||
|
||||
("foo \nbar",
|
||||
"foo \nbar"),
|
||||
|
||||
(" foo bar \nbaz",
|
||||
"foo bar \nbaz"),
|
||||
|
||||
("foo bar baz",
|
||||
"foo bar baz"),
|
||||
|
||||
("foobarbaz\n\n",
|
||||
"foobarbaz\n\n"),
|
||||
];
|
||||
|
||||
let mode = CompressionMode::CompressWhitespace;
|
||||
for &(test, oracle) in test_strs.iter() {
|
||||
let mut new_line_pos = vec![];
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(&*trimmed_str, oracle)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_compress_whitespace_newline() {
|
||||
let test_strs = vec![
|
||||
(" foo bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("foo\n bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo \nbar",
|
||||
"foo bar"),
|
||||
|
||||
(" foo bar \nbaz",
|
||||
"foo bar baz"),
|
||||
|
||||
("foo bar baz",
|
||||
"foo bar baz"),
|
||||
|
||||
("foobarbaz\n\n",
|
||||
"foobarbaz "),
|
||||
];
|
||||
|
||||
let mode = CompressionMode::CompressWhitespaceNewline;
|
||||
for &(test, oracle) in test_strs.iter() {
|
||||
let mut new_line_pos = vec![];
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(&*trimmed_str, oracle)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_compress_whitespace_newline_no_incoming() {
|
||||
let test_strs = [
|
||||
(" foo bar",
|
||||
" foo bar"),
|
||||
|
||||
("\nfoo bar",
|
||||
" foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("foo\n bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo \nbar",
|
||||
"foo bar"),
|
||||
|
||||
(" foo bar \nbaz",
|
||||
" foo bar baz"),
|
||||
|
||||
("foo bar baz",
|
||||
"foo bar baz"),
|
||||
|
||||
("foobarbaz\n\n",
|
||||
"foobarbaz "),
|
||||
];
|
||||
|
||||
let mode = CompressionMode::CompressWhitespaceNewline;
|
||||
for &(test, oracle) in test_strs.iter() {
|
||||
let mut new_line_pos = vec![];
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(test, mode, false, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(trimmed_str.as_slice(), oracle)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ impl Cookie {
|
|||
}
|
||||
|
||||
// http://tools.ietf.org/html/rfc6265#section-5.1.4
|
||||
fn default_path(request_path: &str) -> &str {
|
||||
pub fn default_path(request_path: &str) -> &str {
|
||||
// Step 2
|
||||
if request_path.is_empty() || !request_path.starts_with("/") {
|
||||
return "/";
|
||||
|
@ -166,77 +166,3 @@ impl Cookie {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_domain_match() {
|
||||
assert!(Cookie::domain_match("foo.com", "foo.com"));
|
||||
assert!(Cookie::domain_match("bar.foo.com", "foo.com"));
|
||||
assert!(Cookie::domain_match("baz.bar.foo.com", "foo.com"));
|
||||
|
||||
assert!(!Cookie::domain_match("bar.foo.com", "bar.com"));
|
||||
assert!(!Cookie::domain_match("bar.com", "baz.bar.com"));
|
||||
assert!(!Cookie::domain_match("foo.com", "bar.com"));
|
||||
|
||||
assert!(!Cookie::domain_match("bar.com", "bbar.com"));
|
||||
assert!(Cookie::domain_match("235.132.2.3", "235.132.2.3"));
|
||||
assert!(!Cookie::domain_match("235.132.2.3", "1.1.1.1"));
|
||||
assert!(!Cookie::domain_match("235.132.2.3", ".2.3"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_path() {
|
||||
assert!(&*Cookie::default_path("/foo/bar/baz/") == "/foo/bar/baz");
|
||||
assert!(&*Cookie::default_path("/foo/bar/baz") == "/foo/bar");
|
||||
assert!(&*Cookie::default_path("/foo/") == "/foo");
|
||||
assert!(&*Cookie::default_path("/foo") == "/");
|
||||
assert!(&*Cookie::default_path("/") == "/");
|
||||
assert!(&*Cookie::default_path("") == "/");
|
||||
assert!(&*Cookie::default_path("foo") == "/");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_cookie_constructor() {
|
||||
use net_traits::CookieSource;
|
||||
|
||||
let url = &Url::parse("http://example.com/foo").unwrap();
|
||||
|
||||
let gov_url = &Url::parse("http://gov.ac/foo").unwrap();
|
||||
// cookie name/value test
|
||||
assert!(cookie_rs::Cookie::parse(" baz ").is_err());
|
||||
assert!(cookie_rs::Cookie::parse(" = bar ").is_err());
|
||||
assert!(cookie_rs::Cookie::parse(" baz = ").is_ok());
|
||||
|
||||
// cookie domains test
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain = ").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_some());
|
||||
let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
|
||||
assert!(&**cookie.cookie.domain.as_ref().unwrap() == "example.com");
|
||||
|
||||
// cookie public domains test
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain = gov.ac").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_none());
|
||||
assert!(Cookie::new_wrapped(cookie, gov_url, CookieSource::HTTP).is_some());
|
||||
|
||||
// cookie domain matching test
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Domain = bazample.com").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_some());
|
||||
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; HttpOnly").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::NonHTTP).is_none());
|
||||
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
|
||||
let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
|
||||
assert!(cookie.cookie.value.as_slice() == "bar");
|
||||
assert!(cookie.cookie.name.as_slice() == "baz");
|
||||
assert!(cookie.cookie.secure);
|
||||
assert!(cookie.cookie.path.as_ref().unwrap().as_slice() == "/foo/bar/");
|
||||
assert!(cookie.cookie.domain.as_ref().unwrap().as_slice() == "example.com");
|
||||
assert!(cookie.host_only);
|
||||
|
||||
let u = &Url::parse("http://example.com/foobar").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("foobar=value;path=/").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, u, CookieSource::HTTP).is_some());
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ impl CookieStorage {
|
|||
self.cookies.push(cookie);
|
||||
}
|
||||
|
||||
fn cookie_comparator(a: &Cookie, b: &Cookie) -> Ordering {
|
||||
pub fn cookie_comparator(a: &Cookie, b: &Cookie) -> Ordering {
|
||||
let a_path_len = a.cookie.path.as_ref().map(|p| p.len()).unwrap_or(0);
|
||||
let b_path_len = b.cookie.path.as_ref().map(|p| p.len()).unwrap_or(0);
|
||||
match a_path_len.cmp(&b_path_len) {
|
||||
|
@ -115,21 +115,3 @@ impl CookieStorage {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sort_order() {
|
||||
use cookie_rs;
|
||||
let url = &Url::parse("http://example.com/foo").unwrap();
|
||||
let a_wrapped = cookie_rs::Cookie::parse("baz=bar; Path=/foo/bar/").unwrap();
|
||||
let a = Cookie::new_wrapped(a_wrapped.clone(), url, CookieSource::HTTP).unwrap();
|
||||
let a_prime = Cookie::new_wrapped(a_wrapped, url, CookieSource::HTTP).unwrap();
|
||||
let b = cookie_rs::Cookie::parse("baz=bar;Path=/foo/bar/baz/").unwrap();
|
||||
let b = Cookie::new_wrapped(b, url, CookieSource::HTTP).unwrap();
|
||||
|
||||
assert!(b.cookie.path.as_ref().unwrap().len() > a.cookie.path.as_ref().unwrap().len());
|
||||
assert!(CookieStorage::cookie_comparator(&a, &b) == Ordering::Greater);
|
||||
assert!(CookieStorage::cookie_comparator(&b, &a) == Ordering::Less);
|
||||
assert!(CookieStorage::cookie_comparator(&a, &a_prime) == Ordering::Less);
|
||||
assert!(CookieStorage::cookie_comparator(&a_prime, &a) == Ordering::Greater);
|
||||
assert!(CookieStorage::cookie_comparator(&a, &a) == Ordering::Equal);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ pub fn factory(load_data: LoadData, _classifier: Arc<MIMEClassifier>) {
|
|||
load(load_data)
|
||||
}
|
||||
|
||||
fn load(load_data: LoadData) {
|
||||
pub fn load(load_data: LoadData) {
|
||||
let start_chan = load_data.consumer;
|
||||
let url = load_data.url;
|
||||
assert!(&*url.scheme == "data");
|
||||
|
@ -81,71 +81,3 @@ fn load(load_data: LoadData) {
|
|||
progress_chan.send(Done(Ok(()))).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn assert_parse(url: &'static str,
|
||||
content_type: Option<(String, String)>,
|
||||
charset: Option<String>,
|
||||
data: Option<Vec<u8>>) {
|
||||
use std::sync::mpsc::channel;
|
||||
use url::Url;
|
||||
|
||||
let (start_chan, start_port) = channel();
|
||||
load(LoadData::new(Url::parse(url).unwrap(), start_chan));
|
||||
|
||||
let response = start_port.recv().unwrap();
|
||||
assert_eq!(&response.metadata.content_type, &content_type);
|
||||
assert_eq!(&response.metadata.charset, &charset);
|
||||
|
||||
let progress = response.progress_port.recv().unwrap();
|
||||
|
||||
match data {
|
||||
None => {
|
||||
assert_eq!(progress, Done(Err("invalid data uri".to_string())));
|
||||
}
|
||||
Some(dat) => {
|
||||
assert_eq!(progress, Payload(dat));
|
||||
assert_eq!(response.progress_port.recv().unwrap(), Done(Ok(())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_invalid() {
|
||||
assert_parse("data:", None, None, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain() {
|
||||
assert_parse("data:,hello%20world", None, None, Some(b"hello world".iter().map(|&x| x).collect()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain_ct() {
|
||||
assert_parse("data:text/plain,hello",
|
||||
Some(("text".to_string(), "plain".to_string())), None, Some(b"hello".iter().map(|&x| x).collect()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain_charset() {
|
||||
assert_parse("data:text/plain;charset=latin1,hello",
|
||||
Some(("text".to_string(), "plain".to_string())), Some("latin1".to_string()), Some(b"hello".iter().map(|&x| x).collect()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn base64() {
|
||||
assert_parse("data:;base64,C62+7w==", None, None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn base64_ct() {
|
||||
assert_parse("data:application/octet-stream;base64,C62+7w==",
|
||||
Some(("application".to_string(), "octet-stream".to_string())), None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn base64_charset() {
|
||||
assert_parse("data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
|
||||
Some(("text".to_string(), "plain".to_string())), Some("koi8-r".to_string()),
|
||||
Some(vec!(0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4)));
|
||||
}
|
||||
|
|
|
@ -420,578 +420,3 @@ pub fn spawn_listener<F, A>(f: F) -> Sender<A>
|
|||
});
|
||||
setup_port.recv().unwrap()
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use net_traits::image_cache_task::ImageResponseMsg::*;
|
||||
use net_traits::image_cache_task::Msg::*;
|
||||
|
||||
use resource_task::start_sending;
|
||||
use net_traits::{ControlMsg, Metadata, ProgressMsg, ResourceTask};
|
||||
use net_traits::image_cache_task::{ImageCacheTask, ImageResponseMsg, Msg};
|
||||
use net_traits::ProgressMsg::{Payload, Done};
|
||||
use profile::time;
|
||||
use std::sync::mpsc::{Sender, channel, Receiver};
|
||||
use url::Url;
|
||||
use util::taskpool::TaskPool;
|
||||
|
||||
static TEST_IMAGE: &'static [u8] = include_bytes!("test.jpeg");
|
||||
|
||||
pub fn test_image_bin() -> Vec<u8> {
|
||||
TEST_IMAGE.iter().map(|&x| x).collect()
|
||||
}
|
||||
|
||||
trait ImageCacheTaskHelper {
|
||||
fn wait_for_store(&self) -> Receiver<()>;
|
||||
fn wait_for_store_prefetched(&self) -> Receiver<()>;
|
||||
}
|
||||
|
||||
impl ImageCacheTaskHelper for ImageCacheTask {
|
||||
fn wait_for_store(&self) -> Receiver<()> {
|
||||
let (chan, port) = channel();
|
||||
self.send(Msg::WaitForStore(chan));
|
||||
port
|
||||
}
|
||||
|
||||
fn wait_for_store_prefetched(&self) -> Receiver<()> {
|
||||
let (chan, port) = channel();
|
||||
self.send(Msg::WaitForStorePrefetched(chan));
|
||||
port
|
||||
}
|
||||
}
|
||||
|
||||
trait Closure {
|
||||
fn invoke(&self, _response: Sender<ProgressMsg>) { }
|
||||
}
|
||||
struct DoesNothing;
|
||||
impl Closure for DoesNothing { }
|
||||
|
||||
struct JustSendOK {
|
||||
url_requested_chan: Sender<()>,
|
||||
}
|
||||
impl Closure for JustSendOK {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
self.url_requested_chan.send(());
|
||||
response.send(Done(Ok(())));
|
||||
}
|
||||
}
|
||||
|
||||
struct SendTestImage;
|
||||
impl Closure for SendTestImage {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
response.send(Payload(test_image_bin()));
|
||||
response.send(Done(Ok(())));
|
||||
}
|
||||
}
|
||||
|
||||
struct SendBogusImage;
|
||||
impl Closure for SendBogusImage {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
response.send(Payload(vec!()));
|
||||
response.send(Done(Ok(())));
|
||||
}
|
||||
}
|
||||
|
||||
struct SendTestImageErr;
|
||||
impl Closure for SendTestImageErr {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
response.send(Payload(test_image_bin()));
|
||||
response.send(Done(Err("".to_string())));
|
||||
}
|
||||
}
|
||||
|
||||
struct WaitSendTestImage {
|
||||
wait_port: Receiver<()>,
|
||||
}
|
||||
impl Closure for WaitSendTestImage {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
// Don't send the data until after the client requests
|
||||
// the image
|
||||
self.wait_port.recv().unwrap();
|
||||
response.send(Payload(test_image_bin()));
|
||||
response.send(Done(Ok(())));
|
||||
}
|
||||
}
|
||||
|
||||
struct WaitSendTestImageErr {
|
||||
wait_port: Receiver<()>,
|
||||
}
|
||||
impl Closure for WaitSendTestImageErr {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
// Don't send the data until after the client requests
|
||||
// the image
|
||||
self.wait_port.recv().unwrap();
|
||||
response.send(Payload(test_image_bin()));
|
||||
response.send(Done(Err("".to_string())));
|
||||
}
|
||||
}
|
||||
|
||||
fn mock_resource_task<T: Closure + Send + 'static>(on_load: Box<T>) -> ResourceTask {
|
||||
spawn_listener(move |port: Receiver<ControlMsg>| {
|
||||
loop {
|
||||
match port.recv().unwrap() {
|
||||
ControlMsg::Load(response) => {
|
||||
let chan = start_sending(response.consumer, Metadata::default(
|
||||
Url::parse("file:///fake").unwrap()));
|
||||
on_load.invoke(chan);
|
||||
}
|
||||
ControlMsg::Exit => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn profiler() -> time::ProfilerChan {
|
||||
time::Profiler::create(None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_exit_on_request() {
|
||||
let mock_resource_task = mock_resource_task(box DoesNothing);
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn should_panic_if_unprefetched_image_is_requested() {
|
||||
let mock_resource_task = mock_resource_task(box DoesNothing);
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let (chan, port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, chan));
|
||||
port.recv().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_request_url_from_resource_task_on_prefetch() {
|
||||
let (url_requested_chan, url_requested) = channel();
|
||||
|
||||
let mock_resource_task = mock_resource_task(box JustSendOK { url_requested_chan: url_requested_chan});
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url));
|
||||
url_requested.recv().unwrap();
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
|
||||
let (url_requested_chan, url_requested) = channel();
|
||||
|
||||
let mock_resource_task = mock_resource_task(box JustSendOK { url_requested_chan: url_requested_chan});
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Prefetch(url));
|
||||
url_requested.recv().unwrap();
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
match url_requested.try_recv() {
|
||||
Err(_) => (),
|
||||
Ok(_) => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_image_not_ready_if_data_has_not_arrived() {
|
||||
let (wait_chan, wait_port) = channel();
|
||||
|
||||
let mock_resource_task = mock_resource_task(box WaitSendTestImage{wait_port: wait_port});
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
assert!(response_port.recv().unwrap() == ImageResponseMsg::ImageNotReady);
|
||||
wait_chan.send(());
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_decoded_image_data_if_data_has_arrived() {
|
||||
let mock_resource_task = mock_resource_task(box SendTestImage);
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageReady(_) => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_decoded_image_data_for_multiple_requests() {
|
||||
let mock_resource_task = mock_resource_task(box SendTestImage);
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
for _ in range(0u32, 2u32) {
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url.clone(), response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageReady(_) => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_request_image_from_resource_task_if_image_is_already_available() {
|
||||
let (image_bin_sent_chan, image_bin_sent) = channel();
|
||||
|
||||
let (resource_task_exited_chan, resource_task_exited) = channel();
|
||||
|
||||
let mock_resource_task = spawn_listener(move |port: Receiver<ControlMsg>| {
|
||||
loop {
|
||||
match port.recv().unwrap() {
|
||||
ControlMsg::Load(response) => {
|
||||
let chan = start_sending(response.consumer, Metadata::default(
|
||||
Url::parse("file:///fake").unwrap()));
|
||||
chan.send(Payload(test_image_bin()));
|
||||
chan.send(Done(Ok(())));
|
||||
image_bin_sent_chan.send(());
|
||||
}
|
||||
ControlMsg::Exit => {
|
||||
resource_task_exited_chan.send(());
|
||||
break
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
image_bin_sent.recv().unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
|
||||
resource_task_exited.recv().unwrap();
|
||||
|
||||
// Our resource task should not have received another request for the image
|
||||
// because it's already cached
|
||||
match image_bin_sent.try_recv() {
|
||||
Err(_) => (),
|
||||
Ok(_) => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
|
||||
let (image_bin_sent_chan, image_bin_sent) = channel();
|
||||
|
||||
let (resource_task_exited_chan, resource_task_exited) = channel();
|
||||
let mock_resource_task = spawn_listener(move |port: Receiver<ControlMsg>| {
|
||||
loop {
|
||||
match port.recv().unwrap() {
|
||||
ControlMsg::Load(response) => {
|
||||
let chan = start_sending(response.consumer, Metadata::default(
|
||||
Url::parse("file:///fake").unwrap()));
|
||||
chan.send(Payload(test_image_bin()));
|
||||
chan.send(Done(Err("".to_string())));
|
||||
image_bin_sent_chan.send(());
|
||||
}
|
||||
ControlMsg::Exit => {
|
||||
resource_task_exited_chan.send(());
|
||||
break
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
image_bin_sent.recv().unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
|
||||
resource_task_exited.recv().unwrap();
|
||||
|
||||
// Our resource task should not have received another request for the image
|
||||
// because it's already cached
|
||||
match image_bin_sent.try_recv() {
|
||||
Err(_) => (),
|
||||
Ok(_) => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_failed_if_image_bin_cannot_be_fetched() {
|
||||
let mock_resource_task = mock_resource_task(box SendTestImageErr);
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store_prefetched();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageFailed => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_fetched() {
|
||||
let mock_resource_task = mock_resource_task(box SendTestImageErr);
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store_prefetched();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url.clone(), response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageFailed => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
// And ask again, we should get the same response
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageFailed => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_failed_if_image_decode_fails() {
|
||||
let mock_resource_task = mock_resource_task(box SendBogusImage);
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
// Make the request
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageFailed => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_image_on_wait_if_image_is_already_loaded() {
|
||||
let mock_resource_task = mock_resource_task(box SendTestImage);
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::WaitForImage(url, response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageReady(..) => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_image_on_wait_if_image_is_not_yet_loaded() {
|
||||
let (wait_chan, wait_port) = channel();
|
||||
|
||||
let mock_resource_task = mock_resource_task(box WaitSendTestImage {wait_port: wait_port});
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::WaitForImage(url, response_chan));
|
||||
|
||||
wait_chan.send(());
|
||||
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageReady(..) => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_image_failed_on_wait_if_image_fails_to_load() {
|
||||
let (wait_chan, wait_port) = channel();
|
||||
|
||||
let mock_resource_task = mock_resource_task(box WaitSendTestImageErr{wait_port: wait_port});
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::WaitForImage(url, response_chan));
|
||||
|
||||
wait_chan.send(());
|
||||
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageFailed => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_cache_should_wait_for_images() {
|
||||
let mock_resource_task = mock_resource_task(box SendTestImage);
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new_sync(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageReady(_) => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@ use util::task::spawn_named;
|
|||
|
||||
use hyper::header::UserAgent;
|
||||
use hyper::header::{Header, SetCookie};
|
||||
#[cfg(test)]
|
||||
use url::Url;
|
||||
|
||||
use std::borrow::ToOwned;
|
||||
use std::boxed;
|
||||
|
@ -227,174 +225,3 @@ impl ResourceManager {
|
|||
loader.invoke((load_data, self.mime_classifier.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exit() {
|
||||
let resource_task = new_resource_task(None);
|
||||
resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_scheme() {
|
||||
let resource_task = new_resource_task(None);
|
||||
let (start_chan, start) = channel();
|
||||
let url = Url::parse("bogus://whatever").unwrap();
|
||||
resource_task.send(ControlMsg::Load(LoadData::new(url, start_chan)));
|
||||
let response = start.recv().unwrap();
|
||||
match response.progress_port.recv().unwrap() {
|
||||
ProgressMsg::Done(result) => { assert!(result.is_err()) }
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile() {
|
||||
let mock_hosts_file_content = "127.0.0.1 foo.bar.com\n127.0.0.2 servo.test.server";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(2, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.2".to_owned(), *hosts_table.get(&"servo.test.server".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_malformed_hostsfile() {
|
||||
let mock_hosts_file_content = "malformed file\n127.0.0.1 foo.bar.com\nservo.test.server 127.0.0.1";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(1, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_line_comment() {
|
||||
let mock_hosts_file_content = "# this is a line comment\n127.0.0.1 foo.bar.com\n# anothercomment";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(1, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_end_of_line_comment() {
|
||||
let mock_hosts_file_content = "127.0.0.1 foo.bar.com # line ending comment\n127.0.0.2 servo.test.server #comment";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(2, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.2".to_owned(), *hosts_table.get(&"servo.test.server".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_2_hostnames_for_1_address() {
|
||||
let mock_hosts_file_content = "127.0.0.1 foo.bar.com baz.bar.com";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(2, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"baz.bar.com".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_4_hostnames_for_1_address() {
|
||||
let mock_hosts_file_content = "127.0.0.1 moz.foo.com moz.bar.com moz.baz.com moz.moz.com";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(4, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"moz.foo.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"moz.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"moz.baz.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"moz.moz.com".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_tabs_instead_spaces() {
|
||||
let mock_hosts_file_content = "127.0.0.1\tfoo.bar.com\n127.0.0.2\tservo.test.server";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(2, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.2".to_owned(), *hosts_table.get(&"servo.test.server".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_valid_ipv4_addresses()
|
||||
{
|
||||
let mock_hosts_file_content = "255.255.255.255 foo.bar.com\n169.0.1.201 servo.test.server\n192.168.5.0 servo.foo.com";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(3, (*hosts_table).len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_invalid_ipv4_addresses()
|
||||
{
|
||||
let mock_hosts_file_content = "256.255.255.255 foo.bar.com\n169.0.1000.201 servo.test.server \
|
||||
\n192.168.5.500 servo.foo.com\n192.abc.100.2 test.servo.com";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(0, (*hosts_table).len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_valid_ipv6_addresses()
|
||||
{
|
||||
let mock_hosts_file_content = "2001:0db8:0000:0000:0000:ff00:0042:8329 foo.bar.com\n\
|
||||
2001:db8:0:0:0:ff00:42:8329 moz.foo.com\n\
|
||||
2001:db8::ff00:42:8329 foo.moz.com moz.moz.com\n\
|
||||
0000:0000:0000:0000:0000:0000:0000:0001 bar.moz.com\n\
|
||||
::1 foo.bar.baz baz.foo.com\n\
|
||||
2001:0DB8:85A3:0042:1000:8A2E:0370:7334 baz.bar.moz\n\
|
||||
2002:0DB8:85A3:0042:1000:8A2E:0370:7334/96 baz2.bar.moz\n\
|
||||
2002:0DB8:85A3:0042:1000:8A2E:0370:7334/128 baz3.bar.moz\n\
|
||||
:: unspecified.moz.com\n\
|
||||
::/128 unspecified.address.com";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(12, (*hosts_table).len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_invalid_ipv6_addresses()
|
||||
{
|
||||
let mock_hosts_file_content = "12001:0db8:0000:0000:0000:ff00:0042:8329 foo.bar.com\n\
|
||||
2001:zdb8:0:0:0:gg00:42:t329 moz.foo.com\n\
|
||||
2001:db8::ff00:42:8329:1111:1111:42 foo.moz.com moz.moz.com\n\
|
||||
2002:0DB8:85A3:0042:1000:8A2E:0370:7334/1289 baz3.bar.moz";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(0, (*hosts_table).len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_end_of_line_whitespace()
|
||||
{
|
||||
let mock_hosts_file_content = "127.0.0.1 foo.bar.com \n\
|
||||
2001:db8:0:0:0:ff00:42:8329 moz.foo.com\n \
|
||||
127.0.0.2 servo.test.server ";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(3, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("2001:db8:0:0:0:ff00:42:8329".to_owned(), *hosts_table.get(&"moz.foo.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.2".to_owned(), *hosts_table.get(&"servo.test.server".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replace_hosts() {
|
||||
use std::net::TcpListener;
|
||||
|
||||
let mut host_table_box = box HashMap::new();
|
||||
host_table_box.insert("foo.bar.com".to_owned(), "127.0.0.1".to_owned());
|
||||
host_table_box.insert("servo.test.server".to_owned(), "127.0.0.2".to_owned());
|
||||
|
||||
let host_table: *mut HashMap<String, String> = unsafe {
|
||||
boxed::into_raw(host_table_box)
|
||||
};
|
||||
|
||||
//Start the TCP server
|
||||
let mut listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let port = listener.socket_addr().unwrap().port();
|
||||
|
||||
//Start the resource task and make a request to our TCP server
|
||||
let resource_task = new_resource_task(None);
|
||||
let (start_chan, _) = channel();
|
||||
let url = Url::parse(&format!("http://foo.bar.com:{}", port)).unwrap();
|
||||
resource_task.send(ControlMsg::Load(replace_hosts(LoadData::new(url, start_chan), host_table)));
|
||||
|
||||
match listener.accept() {
|
||||
Ok(..) => assert!(true, "received request"),
|
||||
Err(_) => assert!(false, "error")
|
||||
}
|
||||
|
||||
resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,3 @@ pub mod script_task;
|
|||
mod timers;
|
||||
pub mod textinput;
|
||||
mod devtools;
|
||||
|
||||
#[cfg(all(test, target_pointer_width = "64"))]
|
||||
mod tests;
|
||||
|
|
|
@ -15,18 +15,18 @@ use std::default::Default;
|
|||
use std::num::SignedInt;
|
||||
|
||||
#[derive(Copy, PartialEq)]
|
||||
enum Selection {
|
||||
pub enum Selection {
|
||||
Selected,
|
||||
NotSelected
|
||||
}
|
||||
|
||||
#[jstraceable]
|
||||
#[derive(Copy)]
|
||||
struct TextPoint {
|
||||
pub struct TextPoint {
|
||||
/// 0-based line number
|
||||
line: usize,
|
||||
pub line: usize,
|
||||
/// 0-based column number
|
||||
index: usize,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
/// Encapsulated state for handling keyboard input in a single or multiline text input control.
|
||||
|
@ -35,7 +35,7 @@ pub struct TextInput {
|
|||
/// Current text input content, split across lines without trailing '\n'
|
||||
lines: Vec<DOMString>,
|
||||
/// Current cursor input point
|
||||
edit_point: TextPoint,
|
||||
pub edit_point: TextPoint,
|
||||
/// Beginning of selection range with edit_point as end that can span multiple lines.
|
||||
selection_begin: Option<TextPoint>,
|
||||
/// Is this a multiline input?
|
||||
|
@ -67,7 +67,7 @@ pub enum Lines {
|
|||
|
||||
/// The direction in which to delete a character.
|
||||
#[derive(PartialEq)]
|
||||
enum DeleteDir {
|
||||
pub enum DeleteDir {
|
||||
Forward,
|
||||
Backward
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ impl TextInput {
|
|||
}
|
||||
|
||||
/// Remove a character at the current editing point
|
||||
fn delete_char(&mut self, dir: DeleteDir) {
|
||||
pub fn delete_char(&mut self, dir: DeleteDir) {
|
||||
if self.selection_begin.is_none() {
|
||||
self.adjust_horizontal(if dir == DeleteDir::Forward {
|
||||
1
|
||||
|
@ -111,14 +111,14 @@ impl TextInput {
|
|||
}
|
||||
|
||||
/// Insert a character at the current editing point
|
||||
fn insert_char(&mut self, ch: char) {
|
||||
pub fn insert_char(&mut self, ch: char) {
|
||||
if self.selection_begin.is_none() {
|
||||
self.selection_begin = Some(self.edit_point);
|
||||
}
|
||||
self.replace_selection(ch.to_string());
|
||||
}
|
||||
|
||||
fn get_sorted_selection(&self) -> (TextPoint, TextPoint) {
|
||||
pub fn get_sorted_selection(&self) -> (TextPoint, TextPoint) {
|
||||
let begin = self.selection_begin.unwrap();
|
||||
let end = self.edit_point;
|
||||
|
||||
|
@ -129,7 +129,7 @@ impl TextInput {
|
|||
}
|
||||
}
|
||||
|
||||
fn replace_selection(&mut self, insert: String) {
|
||||
pub fn replace_selection(&mut self, insert: String) {
|
||||
let (begin, end) = self.get_sorted_selection();
|
||||
self.clear_selection();
|
||||
|
||||
|
@ -166,13 +166,13 @@ impl TextInput {
|
|||
}
|
||||
|
||||
/// Return the length of the current line under the editing point.
|
||||
fn current_line_length(&self) -> usize {
|
||||
pub fn current_line_length(&self) -> usize {
|
||||
self.lines[self.edit_point.line].chars().count()
|
||||
}
|
||||
|
||||
/// Adjust the editing point position by a given of lines. The resulting column is
|
||||
/// as close to the original column position as possible.
|
||||
fn adjust_vertical(&mut self, adjust: isize, select: Selection) {
|
||||
pub fn adjust_vertical(&mut self, adjust: isize, select: Selection) {
|
||||
if !self.multiline {
|
||||
return;
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ impl TextInput {
|
|||
/// Adjust the editing point position by a given number of columns. If the adjustment
|
||||
/// requested is larger than is available in the current line, the editing point is
|
||||
/// adjusted vertically and the process repeats with the remaining adjustment requested.
|
||||
fn adjust_horizontal(&mut self, adjust: isize, select: Selection) {
|
||||
pub fn adjust_horizontal(&mut self, adjust: isize, select: Selection) {
|
||||
if select == Selection::Selected {
|
||||
if self.selection_begin.is_none() {
|
||||
self.selection_begin = Some(self.edit_point);
|
||||
|
@ -244,7 +244,7 @@ impl TextInput {
|
|||
}
|
||||
|
||||
/// Deal with a newline input.
|
||||
fn handle_return(&mut self) -> KeyReaction {
|
||||
pub fn handle_return(&mut self) -> KeyReaction {
|
||||
if !self.multiline {
|
||||
return KeyReaction::TriggerDefaultAction;
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ impl TextInput {
|
|||
}
|
||||
|
||||
/// Select all text in the input control.
|
||||
fn select_all(&mut self) {
|
||||
pub fn select_all(&mut self) {
|
||||
self.selection_begin = Some(TextPoint {
|
||||
line: 0,
|
||||
index: 0,
|
||||
|
@ -264,7 +264,7 @@ impl TextInput {
|
|||
}
|
||||
|
||||
/// Remove the current selection.
|
||||
fn clear_selection(&mut self) {
|
||||
pub fn clear_selection(&mut self) {
|
||||
self.selection_begin = None;
|
||||
}
|
||||
|
||||
|
@ -361,159 +361,3 @@ impl TextInput {
|
|||
self.edit_point.index = min(self.edit_point.index, self.current_line_length());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_delete_char() {
|
||||
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
textinput.delete_char(DeleteDir::Backward);
|
||||
assert_eq!(textinput.get_content(), "acdefg");
|
||||
|
||||
textinput.delete_char(DeleteDir::Forward);
|
||||
assert_eq!(textinput.get_content(), "adefg");
|
||||
|
||||
textinput.adjust_horizontal(2, Selection::Selected);
|
||||
textinput.delete_char(DeleteDir::Forward);
|
||||
assert_eq!(textinput.get_content(), "afg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_insert_char() {
|
||||
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
textinput.insert_char('a');
|
||||
assert_eq!(textinput.get_content(), "abacdefg");
|
||||
|
||||
textinput.adjust_horizontal(2, Selection::Selected);
|
||||
textinput.insert_char('b');
|
||||
assert_eq!(textinput.get_content(), "ababefg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_get_sorted_selection() {
|
||||
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(2, Selection::Selected);
|
||||
let (begin, end) = textinput.get_sorted_selection();
|
||||
assert_eq!(begin.index, 2);
|
||||
assert_eq!(end.index, 4);
|
||||
|
||||
textinput.clear_selection();
|
||||
|
||||
textinput.adjust_horizontal(-2, Selection::Selected);
|
||||
let (begin, end) = textinput.get_sorted_selection();
|
||||
assert_eq!(begin.index, 2);
|
||||
assert_eq!(end.index, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_replace_selection() {
|
||||
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(2, Selection::Selected);
|
||||
|
||||
textinput.replace_selection("xyz".to_owned());
|
||||
assert_eq!(textinput.get_content(), "abxyzefg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_current_line_length() {
|
||||
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
assert_eq!(textinput.current_line_length(), 3);
|
||||
|
||||
textinput.adjust_vertical(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.current_line_length(), 2);
|
||||
|
||||
textinput.adjust_vertical(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.current_line_length(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_adjust_vertical() {
|
||||
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
textinput.adjust_horizontal(3, Selection::NotSelected);
|
||||
textinput.adjust_vertical(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
|
||||
textinput.adjust_vertical(-1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
|
||||
textinput.adjust_vertical(2, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 2);
|
||||
assert_eq!(textinput.edit_point.index, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_adjust_horizontal() {
|
||||
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
textinput.adjust_horizontal(4, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
|
||||
textinput.adjust_horizontal(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 1);
|
||||
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 2);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
|
||||
textinput.adjust_horizontal(-1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_handle_return() {
|
||||
let mut single_line_textinput = TextInput::new(Lines::Single, "abcdef".to_owned());
|
||||
single_line_textinput.adjust_horizontal(3, Selection::NotSelected);
|
||||
single_line_textinput.handle_return();
|
||||
assert_eq!(single_line_textinput.get_content(), "abcdef");
|
||||
|
||||
let mut multi_line_textinput = TextInput::new(Lines::Multiple, "abcdef".to_owned());
|
||||
multi_line_textinput.adjust_horizontal(3, Selection::NotSelected);
|
||||
multi_line_textinput.handle_return();
|
||||
assert_eq!(multi_line_textinput.get_content(), "abc\ndef");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_select_all() {
|
||||
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
|
||||
textinput.select_all();
|
||||
assert_eq!(textinput.edit_point.line, 2);
|
||||
assert_eq!(textinput.edit_point.index, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_get_content() {
|
||||
let single_line_textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
|
||||
assert_eq!(single_line_textinput.get_content(), "abcdefg");
|
||||
|
||||
let multi_line_textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
assert_eq!(multi_line_textinput.get_content(), "abc\nde\nf");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_set_content() {
|
||||
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
assert_eq!(textinput.get_content(), "abc\nde\nf");
|
||||
|
||||
textinput.set_content("abc\nf".to_owned());
|
||||
assert_eq!(textinput.get_content(), "abc\nf");
|
||||
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
textinput.adjust_horizontal(3, Selection::Selected);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 3);
|
||||
textinput.set_content("de".to_owned());
|
||||
assert_eq!(textinput.get_content(), "de");
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ dependencies = [
|
|||
"profile 0.0.1",
|
||||
"script 0.0.1",
|
||||
"time 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unit_tests 0.0.1",
|
||||
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"util 0.0.1",
|
||||
"webdriver_server 0.0.1",
|
||||
|
@ -921,6 +922,26 @@ name = "unicase"
|
|||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unit_tests"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"cookie 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cssparser 0.2.0 (git+https://github.com/servo/rust-cssparser)",
|
||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||
"gfx 0.0.1",
|
||||
"net 0.0.1",
|
||||
"net_traits 0.0.1",
|
||||
"profile 0.0.1",
|
||||
"script 0.0.1",
|
||||
"selectors 0.1.0 (git+https://github.com/servo/rust-selectors)",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||
"string_cache_plugin 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||
"style 0.0.1",
|
||||
"url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"util 0.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "0.2.23"
|
||||
|
|
|
@ -16,6 +16,9 @@ test = false
|
|||
doc = false
|
||||
bench = false
|
||||
|
||||
[dev-dependencies.unit_tests]
|
||||
path = "../../tests/unit"
|
||||
|
||||
[[test]]
|
||||
name = "reftest"
|
||||
path = "../../tests/reftest.rs"
|
||||
|
|
|
@ -13,7 +13,7 @@ use values::specified;
|
|||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct MediaQueryList {
|
||||
media_queries: Vec<MediaQuery>
|
||||
pub media_queries: Vec<MediaQuery>
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Debug)]
|
||||
|
@ -71,9 +71,9 @@ pub enum Qualifier {
|
|||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct MediaQuery {
|
||||
qualifier: Option<Qualifier>,
|
||||
media_type: MediaQueryType,
|
||||
expressions: Vec<Expression>,
|
||||
pub qualifier: Option<Qualifier>,
|
||||
pub media_type: MediaQueryType,
|
||||
pub expressions: Vec<Expression>,
|
||||
}
|
||||
|
||||
impl MediaQuery {
|
||||
|
@ -227,418 +227,3 @@ impl MediaQueryList {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use geom::size::TypedSize2D;
|
||||
use util::geometry::Au;
|
||||
use stylesheets::{iter_stylesheet_media_rules, iter_stylesheet_style_rules, Stylesheet};
|
||||
use stylesheets::Origin;
|
||||
use super::*;
|
||||
use url::Url;
|
||||
use values::specified;
|
||||
use std::borrow::ToOwned;
|
||||
|
||||
fn test_media_rule<F>(css: &str, callback: F) where F: Fn(&MediaQueryList, &str) {
|
||||
let url = Url::parse("http://localhost").unwrap();
|
||||
let stylesheet = Stylesheet::from_str(css, url, Origin::Author);
|
||||
let mut rule_count: int = 0;
|
||||
iter_stylesheet_media_rules(&stylesheet, |rule| {
|
||||
rule_count += 1;
|
||||
callback(&rule.media_queries, css);
|
||||
});
|
||||
assert!(rule_count > 0);
|
||||
}
|
||||
|
||||
fn media_query_test(device: &Device, css: &str, expected_rule_count: int) {
|
||||
let url = Url::parse("http://localhost").unwrap();
|
||||
let ss = Stylesheet::from_str(css, url, Origin::Author);
|
||||
let mut rule_count: int = 0;
|
||||
iter_stylesheet_style_rules(&ss, device, |_| rule_count += 1);
|
||||
assert!(rule_count == expected_rule_count, css.to_owned());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_empty() {
|
||||
test_media_rule("@media { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_screen() {
|
||||
test_media_rule("@media screen { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media only screen { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Only), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not screen { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_print() {
|
||||
test_media_rule("@media print { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media only print { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Only), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not print { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_unknown() {
|
||||
test_media_rule("@media fridge { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media only glass { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Only), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not wood { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_all() {
|
||||
test_media_rule("@media all { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media only all { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Only), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not all { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_or() {
|
||||
test_media_rule("@media screen, print { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 2, css.to_owned());
|
||||
let q0 = &list.media_queries[0];
|
||||
assert!(q0.qualifier == None, css.to_owned());
|
||||
assert!(q0.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q0.expressions.len() == 0, css.to_owned());
|
||||
|
||||
let q1 = &list.media_queries[1];
|
||||
assert!(q1.qualifier == None, css.to_owned());
|
||||
assert!(q1.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q1.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_default_expressions() {
|
||||
test_media_rule("@media (min-width: 100px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 1, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
|
||||
test_media_rule("@media (max-width: 43px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 1, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(43))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_expressions() {
|
||||
test_media_rule("@media screen and (min-width: 100px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q.expressions.len() == 1, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
|
||||
test_media_rule("@media print and (max-width: 43px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q.expressions.len() == 1, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(43))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
|
||||
test_media_rule("@media fridge and (max-width: 52px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.expressions.len() == 1, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(52))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_multiple_expressions() {
|
||||
test_media_rule("@media (min-width: 100px) and (max-width: 200px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 2, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
match q.expressions[1] {
|
||||
Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(200))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
|
||||
test_media_rule("@media not screen and (min-width: 100px) and (max-width: 200px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q.expressions.len() == 2, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
match q.expressions[1] {
|
||||
Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(200))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_malformed_expressions() {
|
||||
test_media_rule("@media (min-width: 100blah) and (max-width: 200px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media screen and (height: 200px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media (min-width: 30em foo bar) {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not (min-width: 300px) {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media , {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 2, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
let q = &list.media_queries[1];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media screen 4px, print {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 2, css.to_owned());
|
||||
let q0 = &list.media_queries[0];
|
||||
assert!(q0.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q0.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q0.expressions.len() == 0, css.to_owned());
|
||||
let q1 = &list.media_queries[1];
|
||||
assert!(q1.qualifier == None, css.to_owned());
|
||||
assert!(q1.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q1.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media screen, {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 2, css.to_owned());
|
||||
let q0 = &list.media_queries[0];
|
||||
assert!(q0.qualifier == None, css.to_owned());
|
||||
assert!(q0.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q0.expressions.len() == 0, css.to_owned());
|
||||
let q1 = &list.media_queries[1];
|
||||
assert!(q1.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q1.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q1.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matching_simple() {
|
||||
let device = Device {
|
||||
media_type: MediaType::Screen,
|
||||
viewport_size: TypedSize2D(200.0, 100.0),
|
||||
};
|
||||
|
||||
media_query_test(&device, "@media not all { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not screen { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not print { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media unknown { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not unknown { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media screen { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media print { a { color: red; } }", 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matching_width() {
|
||||
let device = Device {
|
||||
media_type: MediaType::Screen,
|
||||
viewport_size: TypedSize2D(200.0, 100.0),
|
||||
};
|
||||
|
||||
media_query_test(&device, "@media { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media (min-width: 50px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media (min-width: 150px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media (min-width: 300px) { a { color: red; } }", 0);
|
||||
|
||||
media_query_test(&device, "@media screen and (min-width: 50px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media screen and (min-width: 150px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media screen and (min-width: 300px) { a { color: red; } }", 0);
|
||||
|
||||
media_query_test(&device, "@media not screen and (min-width: 50px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not screen and (min-width: 150px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not screen and (min-width: 300px) { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media (max-width: 50px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media (max-width: 150px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media (max-width: 300px) { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media screen and (min-width: 50px) and (max-width: 100px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media screen and (min-width: 250px) and (max-width: 300px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media screen and (min-width: 50px) and (max-width: 250px) { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media not screen and (min-width: 50px) and (max-width: 100px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media not screen and (min-width: 250px) and (max-width: 300px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media not screen and (min-width: 50px) and (max-width: 250px) { a { color: red; } }", 0);
|
||||
|
||||
media_query_test(&device, "@media not screen and (min-width: 3.1em) and (max-width: 6em) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media not screen and (min-width: 16em) and (max-width: 19.75em) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media not screen and (min-width: 3em) and (max-width: 250px) { a { color: red; } }", 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matching_invalid() {
|
||||
let device = Device {
|
||||
media_type: MediaType::Screen,
|
||||
viewport_size: TypedSize2D(200.0, 100.0),
|
||||
};
|
||||
|
||||
media_query_test(&device, "@media fridge { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media screen and (height: 100px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not print and (width: 100) { a { color: red; } }", 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4803,7 +4803,7 @@ impl ComputedValues {
|
|||
|
||||
|
||||
/// Return a WritingMode bitflags from the relevant CSS properties.
|
||||
fn get_writing_mode(inheritedbox_style: &style_structs::InheritedBox) -> WritingMode {
|
||||
pub fn get_writing_mode(inheritedbox_style: &style_structs::InheritedBox) -> WritingMode {
|
||||
use util::logical_geometry;
|
||||
let mut flags = WritingMode::empty();
|
||||
match inheritedbox_style.direction {
|
||||
|
@ -4839,7 +4839,7 @@ fn get_writing_mode(inheritedbox_style: &style_structs::InheritedBox) -> Writing
|
|||
|
||||
/// The initial values for all style structs as defined by the specification.
|
||||
lazy_static! {
|
||||
static ref INITIAL_VALUES: ComputedValues = ComputedValues {
|
||||
pub static ref INITIAL_VALUES: ComputedValues = ComputedValues {
|
||||
% for style_struct in STYLE_STRUCTS:
|
||||
${style_struct.ident}: Arc::new(style_structs::${style_struct.name} {
|
||||
% for longhand in style_struct.longhands:
|
||||
|
@ -4857,11 +4857,6 @@ lazy_static! {
|
|||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn initial_writing_mode_is_empty() {
|
||||
assert_eq!(get_writing_mode(INITIAL_VALUES.get_inheritedbox()), WritingMode::empty())
|
||||
}
|
||||
|
||||
/// Fast path for the function below. Only computes new inherited styles.
|
||||
#[allow(unused_mut)]
|
||||
fn cascade_with_cached_declarations(
|
||||
|
|
|
@ -31,7 +31,7 @@ pub enum Origin {
|
|||
pub struct Stylesheet {
|
||||
/// List of rules in the order they were found (important for
|
||||
/// cascading order)
|
||||
rules: Vec<CSSRule>,
|
||||
pub rules: Vec<CSSRule>,
|
||||
pub origin: Origin,
|
||||
}
|
||||
|
||||
|
@ -322,136 +322,3 @@ pub fn iter_font_face_rules<F>(stylesheet: &Stylesheet, device: &Device, callbac
|
|||
where F: Fn(&Atom, &Source) {
|
||||
iter_font_face_rules_inner(&stylesheet.rules, device, callback)
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_parse_stylesheet() {
|
||||
use std::sync::Arc;
|
||||
use cssparser;
|
||||
use selectors::parser::*;
|
||||
use string_cache::Atom;
|
||||
use properties::{PropertyDeclaration, DeclaredValue, longhands};
|
||||
use std::borrow::ToOwned;
|
||||
|
||||
let css = r"
|
||||
@namespace url(http://www.w3.org/1999/xhtml);
|
||||
/* FIXME: only if scripting is enabled */
|
||||
input[type=hidden i] { display: none !important; }
|
||||
html , body /**/ { display: block; }
|
||||
#d1 > .ok { background: blue; }
|
||||
";
|
||||
let url = Url::parse("about::test").unwrap();
|
||||
let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent);
|
||||
assert_eq!(stylesheet, Stylesheet {
|
||||
origin: Origin::UserAgent,
|
||||
rules: vec![
|
||||
CSSRule::Namespace(None, ns!(HTML)),
|
||||
CSSRule::Style(StyleRule {
|
||||
selectors: vec![
|
||||
Selector {
|
||||
compound_selectors: Arc::new(CompoundSelector {
|
||||
simple_selectors: vec![
|
||||
SimpleSelector::Namespace(ns!(HTML)),
|
||||
SimpleSelector::LocalName(LocalName {
|
||||
name: atom!(input),
|
||||
lower_name: atom!(input),
|
||||
}),
|
||||
SimpleSelector::AttrEqual(AttrSelector {
|
||||
name: atom!(type),
|
||||
lower_name: atom!(type),
|
||||
namespace: NamespaceConstraint::Specific(ns!("")),
|
||||
}, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
|
||||
],
|
||||
next: None,
|
||||
}),
|
||||
pseudo_element: None,
|
||||
specificity: (0 << 20) + (1 << 10) + (1 << 0),
|
||||
},
|
||||
],
|
||||
declarations: PropertyDeclarationBlock {
|
||||
normal: Arc::new(vec![]),
|
||||
important: Arc::new(vec![
|
||||
PropertyDeclaration::Display(DeclaredValue::SpecifiedValue(
|
||||
longhands::display::SpecifiedValue::none)),
|
||||
]),
|
||||
},
|
||||
}),
|
||||
CSSRule::Style(StyleRule {
|
||||
selectors: vec![
|
||||
Selector {
|
||||
compound_selectors: Arc::new(CompoundSelector {
|
||||
simple_selectors: vec![
|
||||
SimpleSelector::Namespace(ns!(HTML)),
|
||||
SimpleSelector::LocalName(LocalName {
|
||||
name: atom!(html),
|
||||
lower_name: atom!(html),
|
||||
}),
|
||||
],
|
||||
next: None,
|
||||
}),
|
||||
pseudo_element: None,
|
||||
specificity: (0 << 20) + (0 << 10) + (1 << 0),
|
||||
},
|
||||
Selector {
|
||||
compound_selectors: Arc::new(CompoundSelector {
|
||||
simple_selectors: vec![
|
||||
SimpleSelector::Namespace(ns!(HTML)),
|
||||
SimpleSelector::LocalName(LocalName {
|
||||
name: atom!(body),
|
||||
lower_name: atom!(body),
|
||||
}),
|
||||
],
|
||||
next: None,
|
||||
}),
|
||||
pseudo_element: None,
|
||||
specificity: (0 << 20) + (0 << 10) + (1 << 0),
|
||||
},
|
||||
],
|
||||
declarations: PropertyDeclarationBlock {
|
||||
normal: Arc::new(vec![
|
||||
PropertyDeclaration::Display(DeclaredValue::SpecifiedValue(
|
||||
longhands::display::SpecifiedValue::block)),
|
||||
]),
|
||||
important: Arc::new(vec![]),
|
||||
},
|
||||
}),
|
||||
CSSRule::Style(StyleRule {
|
||||
selectors: vec![
|
||||
Selector {
|
||||
compound_selectors: Arc::new(CompoundSelector {
|
||||
simple_selectors: vec![
|
||||
SimpleSelector::Class(Atom::from_slice("ok")),
|
||||
],
|
||||
next: Some((box CompoundSelector {
|
||||
simple_selectors: vec![
|
||||
SimpleSelector::ID(Atom::from_slice("d1")),
|
||||
],
|
||||
next: None,
|
||||
}, Combinator::Child)),
|
||||
}),
|
||||
pseudo_element: None,
|
||||
specificity: (1 << 20) + (1 << 10) + (0 << 0),
|
||||
},
|
||||
],
|
||||
declarations: PropertyDeclarationBlock {
|
||||
normal: Arc::new(vec![
|
||||
PropertyDeclaration::BackgroundSize(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundImage(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundPosition(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundColor(DeclaredValue::SpecifiedValue(
|
||||
longhands::background_color::SpecifiedValue {
|
||||
authored: Some("blue".to_owned()),
|
||||
parsed: cssparser::Color::RGBA(cssparser::RGBA {
|
||||
red: 0., green: 0., blue: 1., alpha: 1.
|
||||
}),
|
||||
}
|
||||
)),
|
||||
]),
|
||||
important: Arc::new(vec![]),
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,8 +12,6 @@ use rand;
|
|||
use std::slice::Iter;
|
||||
use std::default::Default;
|
||||
|
||||
#[cfg(test)]
|
||||
use std::cell::Cell;
|
||||
|
||||
pub struct HashCache<K, V> {
|
||||
entries: HashMap<K, V, DefaultState<SipHasher>>,
|
||||
|
@ -56,19 +54,6 @@ impl<K, V> HashCache<K,V>
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hashcache() {
|
||||
let mut cache: HashCache<usize, Cell<&str>> = HashCache::new();
|
||||
|
||||
cache.insert(1, Cell::new("one"));
|
||||
assert!(cache.find(&1).is_some());
|
||||
assert!(cache.find(&2).is_none());
|
||||
|
||||
cache.find_or_create(&2, |_v| { Cell::new("two") });
|
||||
assert!(cache.find(&1).is_some());
|
||||
assert!(cache.find(&2).is_some());
|
||||
}
|
||||
|
||||
pub struct LRUCache<K, V> {
|
||||
entries: Vec<(K, V)>,
|
||||
cache_size: usize,
|
||||
|
@ -183,37 +168,3 @@ impl<K:Clone+Eq+Hash,V:Clone> SimpleHashCache<K,V> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lru_cache() {
|
||||
let one = Cell::new("one");
|
||||
let two = Cell::new("two");
|
||||
let three = Cell::new("three");
|
||||
let four = Cell::new("four");
|
||||
|
||||
// Test normal insertion.
|
||||
let mut cache: LRUCache<usize,Cell<&str>> = LRUCache::new(2); // (_, _) (cache is empty)
|
||||
cache.insert(1, one); // (1, _)
|
||||
cache.insert(2, two); // (1, 2)
|
||||
cache.insert(3, three); // (2, 3)
|
||||
|
||||
assert!(cache.find(&1).is_none()); // (2, 3) (no change)
|
||||
assert!(cache.find(&3).is_some()); // (2, 3)
|
||||
assert!(cache.find(&2).is_some()); // (3, 2)
|
||||
|
||||
// Test that LRU works (this insertion should replace 3, not 2).
|
||||
cache.insert(4, four); // (2, 4)
|
||||
|
||||
assert!(cache.find(&1).is_none()); // (2, 4) (no change)
|
||||
assert!(cache.find(&2).is_some()); // (4, 2)
|
||||
assert!(cache.find(&3).is_none()); // (4, 2) (no change)
|
||||
assert!(cache.find(&4).is_some()); // (2, 4) (no change)
|
||||
|
||||
// Test find_or_create.
|
||||
cache.find_or_create(&1, |_| { Cell::new("one") }); // (4, 1)
|
||||
|
||||
assert!(cache.find(&1).is_some()); // (4, 1) (no change)
|
||||
assert!(cache.find(&2).is_none()); // (4, 1) (no change)
|
||||
assert!(cache.find(&3).is_none()); // (4, 1) (no change)
|
||||
assert!(cache.find(&4).is_some()); // (1, 4)
|
||||
}
|
||||
|
|
|
@ -965,65 +965,3 @@ impl<T: Copy + Add<T, Output=T> + Sub<T, Output=T>> Sub<LogicalMargin<T>> for Lo
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn modes() -> [WritingMode; 10] {
|
||||
[
|
||||
WritingMode::empty(),
|
||||
FLAG_VERTICAL,
|
||||
FLAG_VERTICAL | FLAG_VERTICAL_LR,
|
||||
FLAG_VERTICAL | FLAG_VERTICAL_LR | FLAG_SIDEWAYS_LEFT,
|
||||
FLAG_VERTICAL | FLAG_SIDEWAYS_LEFT,
|
||||
FLAG_RTL,
|
||||
FLAG_VERTICAL | FLAG_RTL,
|
||||
FLAG_VERTICAL | FLAG_VERTICAL_LR | FLAG_RTL,
|
||||
FLAG_VERTICAL | FLAG_VERTICAL_LR | FLAG_SIDEWAYS_LEFT | FLAG_RTL,
|
||||
FLAG_VERTICAL | FLAG_SIDEWAYS_LEFT | FLAG_RTL,
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_size_round_trip() {
|
||||
let physical = Size2D(1u32, 2u32);
|
||||
for &mode in modes().iter() {
|
||||
let logical = LogicalSize::from_physical(mode, physical);
|
||||
assert!(logical.to_physical(mode) == physical);
|
||||
assert!(logical.width(mode) == 1);
|
||||
assert!(logical.height(mode) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_point_round_trip() {
|
||||
let physical = Point2D(1u32, 2u32);
|
||||
let container = Size2D(100, 200);
|
||||
for &mode in modes().iter() {
|
||||
let logical = LogicalPoint::from_physical(mode, physical, container);
|
||||
assert!(logical.to_physical(mode, container) == physical);
|
||||
assert!(logical.x(mode, container) == 1);
|
||||
assert!(logical.y(mode, container) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_margin_round_trip() {
|
||||
let physical = SideOffsets2D::new(1u32, 2u32, 3u32, 4u32);
|
||||
for &mode in modes().iter() {
|
||||
let logical = LogicalMargin::from_physical(mode, physical);
|
||||
assert!(logical.to_physical(mode) == physical);
|
||||
assert!(logical.top(mode) == 1);
|
||||
assert!(logical.right(mode) == 2);
|
||||
assert!(logical.bottom(mode) == 3);
|
||||
assert!(logical.left(mode) == 4);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rect_round_trip() {
|
||||
let physical = Rect(Point2D(1u32, 2u32), Size2D(3u32, 4u32));
|
||||
let container = Size2D(100, 200);
|
||||
for &mode in modes().iter() {
|
||||
let logical = LogicalRect::from_physical(mode, physical, container);
|
||||
assert!(logical.to_physical(mode, container) == physical);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,10 +42,3 @@ pub fn spawn_named_with_send_on_failure<F, T>(name: &'static str,
|
|||
}
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spawn_named_test() {
|
||||
spawn_named("Test".to_owned(), move || {
|
||||
debug!("I can run!");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
use std::cmp::{PartialOrd, PartialEq, Ordering};
|
||||
use std::iter::range_step;
|
||||
|
||||
#[cfg(test)]
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// FIXME(pcwalton): Workaround for lack of unboxed closures. This is called in
|
||||
/// performance-critical code, so a closure is insufficient.
|
||||
pub trait Comparator<K,T> {
|
||||
|
@ -75,65 +72,3 @@ pub fn byte_swap(data: &mut [u8]) {
|
|||
data[i + 0] = r;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn test_find_all_elems<T: PartialEq + PartialOrd + Eq + Ord>(arr: &[T]) {
|
||||
let mut i = 0;
|
||||
while i < arr.len() {
|
||||
assert!(test_match(&arr[i], arr.binary_search_(&arr[i])));
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn test_miss_all_elems<T: PartialEq + PartialOrd + Eq + Ord + Debug>(arr: &[T], misses: &[T]) {
|
||||
let mut i = 0;
|
||||
while i < misses.len() {
|
||||
let res = arr.binary_search_(&misses[i]);
|
||||
debug!("{:?} == {:?} ?", misses[i], res);
|
||||
assert!(!test_match(&misses[i], arr.binary_search_(&misses[i])));
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn test_match<T: PartialEq>(b: &T, a: Option<&T>) -> bool {
|
||||
match a {
|
||||
None => false,
|
||||
Some(t) => t == b
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_find_all_elements() {
|
||||
let arr_odd = [1u32, 2, 4, 6, 7, 8, 9];
|
||||
let arr_even = [1u32, 2, 5, 6, 7, 8, 9, 42];
|
||||
let arr_double = [1u32, 1, 2, 2, 6, 8, 22];
|
||||
let arr_one = [234986325u32];
|
||||
let arr_two = [3044u32, 8393];
|
||||
let arr_three = [12u32, 23, 34];
|
||||
|
||||
test_find_all_elems(&arr_odd);
|
||||
test_find_all_elems(&arr_even);
|
||||
test_find_all_elems(&arr_double);
|
||||
test_find_all_elems(&arr_one);
|
||||
test_find_all_elems(&arr_two);
|
||||
test_find_all_elems(&arr_three);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_find_missing_elements() {
|
||||
let arr_odd = [1u32, 2, 4, 6, 7, 8, 9];
|
||||
let arr_even = [1u32, 2, 5, 6, 7, 8, 9, 42];
|
||||
let arr_double = [1u32, 1, 2, 2, 6, 8, 22];
|
||||
let arr_one = [234986325u32];
|
||||
let arr_two = [3044u32, 8393];
|
||||
let arr_three = [12u32, 23, 34];
|
||||
|
||||
test_miss_all_elems(&arr_odd, &[-22, 0, 3, 5, 34938, 10, 11, 12]);
|
||||
test_miss_all_elems(&arr_even, &[-1, 0, 3, 34938, 10, 11, 12]);
|
||||
test_miss_all_elems(&arr_double, &[-1, 0, 3, 4, 34938, 10, 11, 12, 234, 234, 33]);
|
||||
test_miss_all_elems(&arr_one, &[-1, 0, 3, 34938, 10, 11, 12, 234, 234, 33]);
|
||||
test_miss_all_elems(&arr_two, &[-1, 0, 3, 34938, 10, 11, 12, 234, 234, 33]);
|
||||
test_miss_all_elems(&arr_three, &[-2, 0, 1, 2, 3, 34938, 10, 11, 234, 234, 33]);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,14 @@ licenses = [
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
""",
|
||||
|
||||
"""\
|
||||
#!/usr/bin/env python
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
""",
|
||||
|
||||
"""\
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
|
|
@ -102,38 +102,17 @@ class MachCommands(CommandBase):
|
|||
@Command('test-unit',
|
||||
description='Run unit tests',
|
||||
category='testing')
|
||||
@CommandArgument('--package', '-p', default=None,
|
||||
help="Specific package to test")
|
||||
@CommandArgument('--component', '-c', default=None,
|
||||
help="Alias for --package")
|
||||
@CommandArgument('test_name', nargs=argparse.REMAINDER,
|
||||
help="Only run tests that match this pattern")
|
||||
def test_unit(self, test_name=None, component=None, package=None):
|
||||
if test_name is None:
|
||||
test_name = []
|
||||
|
||||
if component is not None:
|
||||
if package is not None:
|
||||
print("Please use either -p or -c, not both.")
|
||||
return 1
|
||||
package = component
|
||||
|
||||
self.ensure_bootstrapped()
|
||||
|
||||
def cargo_test(component):
|
||||
return 0 != subprocess.call(
|
||||
["cargo", "test", "-p", component]
|
||||
+ test_name, env=self.build_env(), cwd=self.servo_crate())
|
||||
|
||||
if package is not None:
|
||||
return cargo_test(package)
|
||||
|
||||
self.ensure_built_tests()
|
||||
ret = self.run_test("servo", test_name) != 0
|
||||
for c in os.listdir("components"):
|
||||
if c != "servo":
|
||||
ret = ret or cargo_test(c)
|
||||
return ret
|
||||
return 0 != subprocess.call(
|
||||
["cargo", "test", "-p", "unit_tests"]
|
||||
+ test_name, env=self.build_env(), cwd=self.servo_crate())
|
||||
|
||||
@Command('test-ref',
|
||||
description='Run the reference tests',
|
||||
|
|
|
@ -14,7 +14,7 @@ import fnmatch
|
|||
import itertools
|
||||
from licenseck import licenses
|
||||
|
||||
directories_to_check = ["ports", "components"]
|
||||
directories_to_check = ["ports", "components", "tests"]
|
||||
filetypes_to_check = [".rs", ".rc", ".cpp", ".c", ".h", ".py"]
|
||||
reftest_directories = ["tests/ref"]
|
||||
reftest_filetype = ".list"
|
||||
|
@ -22,7 +22,7 @@ reftest_filetype = ".list"
|
|||
ignored_files = [
|
||||
# Upstream
|
||||
"support/*",
|
||||
"tests/wpt/web-platform-tests/*",
|
||||
"tests/wpt/*",
|
||||
|
||||
# Generated and upstream code combined with our own. Could use cleanup
|
||||
"components/script/dom/bindings/codegen/*",
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
[package]
|
||||
name = "unit_tests"
|
||||
version = "0.0.1"
|
||||
authors = ["The Servo Project Developers"]
|
||||
|
||||
[lib]
|
||||
name = "unit_tests"
|
||||
path = "lib.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies.util]
|
||||
path = "../../components/util"
|
||||
|
||||
[dependencies.gfx]
|
||||
path = "../../components/gfx"
|
||||
|
||||
[dependencies.net]
|
||||
path = "../../components/net"
|
||||
|
||||
[dependencies.net_traits]
|
||||
path = "../../components/net_traits"
|
||||
|
||||
[dependencies.profile]
|
||||
path = "../../components/profile"
|
||||
|
||||
[dependencies.style]
|
||||
path = "../../components/style"
|
||||
|
||||
[dependencies.script]
|
||||
path = "../../components/script"
|
||||
|
||||
[dependencies.geom]
|
||||
git = "https://github.com/servo/rust-geom"
|
||||
|
||||
[dependencies.cssparser]
|
||||
git = "https://github.com/servo/rust-cssparser"
|
||||
|
||||
[dependencies.selectors]
|
||||
git = "https://github.com/servo/rust-selectors"
|
||||
|
||||
[dependencies.string_cache]
|
||||
git = "https://github.com/servo/string-cache"
|
||||
|
||||
[dependencies.string_cache_plugin]
|
||||
git = "https://github.com/servo/string-cache"
|
||||
|
||||
[dependencies]
|
||||
cookie = "*"
|
||||
url = "*"
|
|
@ -0,0 +1,5 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
mod text_util;
|
|
@ -0,0 +1,165 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use gfx::text::util::{CompressionMode, transform_text};
|
||||
|
||||
#[test]
|
||||
fn test_transform_compress_none() {
|
||||
let test_strs = [
|
||||
" foo bar",
|
||||
"foo bar ",
|
||||
"foo\n bar",
|
||||
"foo \nbar",
|
||||
" foo bar \nbaz",
|
||||
"foo bar baz",
|
||||
"foobarbaz\n\n",
|
||||
];
|
||||
|
||||
let mode = CompressionMode::CompressNone;
|
||||
for &test in test_strs.iter() {
|
||||
let mut new_line_pos = vec![];
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(trimmed_str, test)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_discard_newline() {
|
||||
let test_strs = [
|
||||
(" foo bar",
|
||||
" foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("foo\n bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo \nbar",
|
||||
"foo bar"),
|
||||
|
||||
(" foo bar \nbaz",
|
||||
" foo bar baz"),
|
||||
|
||||
("foo bar baz",
|
||||
"foo bar baz"),
|
||||
|
||||
("foobarbaz\n\n",
|
||||
"foobarbaz"),
|
||||
];
|
||||
|
||||
let mode = CompressionMode::DiscardNewline;
|
||||
for &(test, oracle) in test_strs.iter() {
|
||||
let mut new_line_pos = vec![];
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(trimmed_str, oracle)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_compress_whitespace() {
|
||||
let test_strs = [
|
||||
(" foo bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("foo\n bar",
|
||||
"foo\n bar"),
|
||||
|
||||
("foo \nbar",
|
||||
"foo \nbar"),
|
||||
|
||||
(" foo bar \nbaz",
|
||||
"foo bar \nbaz"),
|
||||
|
||||
("foo bar baz",
|
||||
"foo bar baz"),
|
||||
|
||||
("foobarbaz\n\n",
|
||||
"foobarbaz\n\n"),
|
||||
];
|
||||
|
||||
let mode = CompressionMode::CompressWhitespace;
|
||||
for &(test, oracle) in test_strs.iter() {
|
||||
let mut new_line_pos = vec![];
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(&*trimmed_str, oracle)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_compress_whitespace_newline() {
|
||||
let test_strs = vec![
|
||||
(" foo bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("foo\n bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo \nbar",
|
||||
"foo bar"),
|
||||
|
||||
(" foo bar \nbaz",
|
||||
"foo bar baz"),
|
||||
|
||||
("foo bar baz",
|
||||
"foo bar baz"),
|
||||
|
||||
("foobarbaz\n\n",
|
||||
"foobarbaz "),
|
||||
];
|
||||
|
||||
let mode = CompressionMode::CompressWhitespaceNewline;
|
||||
for &(test, oracle) in test_strs.iter() {
|
||||
let mut new_line_pos = vec![];
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(test, mode, true, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(&*trimmed_str, oracle)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_compress_whitespace_newline_no_incoming() {
|
||||
let test_strs = [
|
||||
(" foo bar",
|
||||
" foo bar"),
|
||||
|
||||
("\nfoo bar",
|
||||
" foo bar"),
|
||||
|
||||
("foo bar ",
|
||||
"foo bar "),
|
||||
|
||||
("foo\n bar",
|
||||
"foo bar"),
|
||||
|
||||
("foo \nbar",
|
||||
"foo bar"),
|
||||
|
||||
(" foo bar \nbaz",
|
||||
" foo bar baz"),
|
||||
|
||||
("foo bar baz",
|
||||
"foo bar baz"),
|
||||
|
||||
("foobarbaz\n\n",
|
||||
"foobarbaz "),
|
||||
];
|
||||
|
||||
let mode = CompressionMode::CompressWhitespaceNewline;
|
||||
for &(test, oracle) in test_strs.iter() {
|
||||
let mut new_line_pos = vec![];
|
||||
let mut trimmed_str = String::new();
|
||||
transform_text(test, mode, false, &mut trimmed_str, &mut new_line_pos);
|
||||
assert_eq!(trimmed_str, oracle)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![feature(plugin)]
|
||||
#![cfg_attr(test, feature(net, alloc))]
|
||||
|
||||
#![plugin(string_cache_plugin)]
|
||||
|
||||
extern crate cssparser;
|
||||
extern crate geom;
|
||||
extern crate gfx;
|
||||
extern crate net;
|
||||
extern crate net_traits;
|
||||
extern crate profile;
|
||||
extern crate script;
|
||||
extern crate selectors;
|
||||
extern crate string_cache;
|
||||
extern crate style;
|
||||
extern crate util;
|
||||
extern crate url;
|
||||
|
||||
#[cfg(test)] #[path="gfx/mod.rs"] mod gfx_tests;
|
||||
#[cfg(test)] #[path="net/mod.rs"] mod net_tests;
|
||||
#[cfg(test)] #[path="script/mod.rs"] mod script_tests;
|
||||
#[cfg(test)] #[path="style/mod.rs"] mod style_tests;
|
||||
#[cfg(test)] #[path="util/mod.rs"] mod util_tests;
|
|
@ -0,0 +1,104 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
extern crate "cookie" as cookie_rs;
|
||||
|
||||
use net::cookie::Cookie;
|
||||
use net::cookie_storage::CookieStorage;
|
||||
use net_traits::CookieSource;
|
||||
use url::Url;
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_domain_match() {
|
||||
assert!(Cookie::domain_match("foo.com", "foo.com"));
|
||||
assert!(Cookie::domain_match("bar.foo.com", "foo.com"));
|
||||
assert!(Cookie::domain_match("baz.bar.foo.com", "foo.com"));
|
||||
|
||||
assert!(!Cookie::domain_match("bar.foo.com", "bar.com"));
|
||||
assert!(!Cookie::domain_match("bar.com", "baz.bar.com"));
|
||||
assert!(!Cookie::domain_match("foo.com", "bar.com"));
|
||||
|
||||
assert!(!Cookie::domain_match("bar.com", "bbar.com"));
|
||||
assert!(Cookie::domain_match("235.132.2.3", "235.132.2.3"));
|
||||
assert!(!Cookie::domain_match("235.132.2.3", "1.1.1.1"));
|
||||
assert!(!Cookie::domain_match("235.132.2.3", ".2.3"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_path() {
|
||||
assert!(&*Cookie::default_path("/foo/bar/baz/") == "/foo/bar/baz");
|
||||
assert!(&*Cookie::default_path("/foo/bar/baz") == "/foo/bar");
|
||||
assert!(&*Cookie::default_path("/foo/") == "/foo");
|
||||
assert!(&*Cookie::default_path("/foo") == "/");
|
||||
assert!(&*Cookie::default_path("/") == "/");
|
||||
assert!(&*Cookie::default_path("") == "/");
|
||||
assert!(&*Cookie::default_path("foo") == "/");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_cookie_constructor() {
|
||||
use net_traits::CookieSource;
|
||||
|
||||
let url = &Url::parse("http://example.com/foo").unwrap();
|
||||
|
||||
let gov_url = &Url::parse("http://gov.ac/foo").unwrap();
|
||||
// cookie name/value test
|
||||
assert!(cookie_rs::Cookie::parse(" baz ").is_err());
|
||||
assert!(cookie_rs::Cookie::parse(" = bar ").is_err());
|
||||
assert!(cookie_rs::Cookie::parse(" baz = ").is_ok());
|
||||
|
||||
// cookie domains test
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain = ").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_some());
|
||||
let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
|
||||
assert!(&**cookie.cookie.domain.as_ref().unwrap() == "example.com");
|
||||
|
||||
// cookie public domains test
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain = gov.ac").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_none());
|
||||
assert!(Cookie::new_wrapped(cookie, gov_url, CookieSource::HTTP).is_some());
|
||||
|
||||
// cookie domain matching test
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Domain = bazample.com").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_some());
|
||||
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; HttpOnly").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::NonHTTP).is_none());
|
||||
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
|
||||
let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
|
||||
assert!(cookie.cookie.value == "bar");
|
||||
assert!(cookie.cookie.name == "baz");
|
||||
assert!(cookie.cookie.secure);
|
||||
assert!(&cookie.cookie.path.as_ref().unwrap()[..] == "/foo/bar/");
|
||||
assert!(&cookie.cookie.domain.as_ref().unwrap()[..] == "example.com");
|
||||
assert!(cookie.host_only);
|
||||
|
||||
let u = &Url::parse("http://example.com/foobar").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("foobar=value;path=/").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, u, CookieSource::HTTP).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sort_order() {
|
||||
use std::cmp::Ordering;
|
||||
|
||||
let url = &Url::parse("http://example.com/foo").unwrap();
|
||||
let a_wrapped = cookie_rs::Cookie::parse("baz=bar; Path=/foo/bar/").unwrap();
|
||||
let a = Cookie::new_wrapped(a_wrapped.clone(), url, CookieSource::HTTP).unwrap();
|
||||
let a_prime = Cookie::new_wrapped(a_wrapped, url, CookieSource::HTTP).unwrap();
|
||||
let b = cookie_rs::Cookie::parse("baz=bar;Path=/foo/bar/baz/").unwrap();
|
||||
let b = Cookie::new_wrapped(b, url, CookieSource::HTTP).unwrap();
|
||||
|
||||
assert!(b.cookie.path.as_ref().unwrap().len() > a.cookie.path.as_ref().unwrap().len());
|
||||
assert!(CookieStorage::cookie_comparator(&a, &b) == Ordering::Greater);
|
||||
assert!(CookieStorage::cookie_comparator(&b, &a) == Ordering::Less);
|
||||
assert!(CookieStorage::cookie_comparator(&a, &a_prime) == Ordering::Less);
|
||||
assert!(CookieStorage::cookie_comparator(&a_prime, &a) == Ordering::Greater);
|
||||
assert!(CookieStorage::cookie_comparator(&a, &a) == Ordering::Equal);
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use net_traits::LoadData;
|
||||
use net_traits::ProgressMsg::{Payload, Done};
|
||||
|
||||
#[cfg(test)]
|
||||
fn assert_parse(url: &'static str,
|
||||
content_type: Option<(String, String)>,
|
||||
charset: Option<String>,
|
||||
data: Option<Vec<u8>>) {
|
||||
use std::sync::mpsc::channel;
|
||||
use url::Url;
|
||||
use net::data_loader::load;
|
||||
|
||||
let (start_chan, start_port) = channel();
|
||||
load(LoadData::new(Url::parse(url).unwrap(), start_chan));
|
||||
|
||||
let response = start_port.recv().unwrap();
|
||||
assert_eq!(&response.metadata.content_type, &content_type);
|
||||
assert_eq!(&response.metadata.charset, &charset);
|
||||
|
||||
let progress = response.progress_port.recv().unwrap();
|
||||
|
||||
match data {
|
||||
None => {
|
||||
assert_eq!(progress, Done(Err("invalid data uri".to_string())));
|
||||
}
|
||||
Some(dat) => {
|
||||
assert_eq!(progress, Payload(dat));
|
||||
assert_eq!(response.progress_port.recv().unwrap(), Done(Ok(())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_invalid() {
|
||||
assert_parse("data:", None, None, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain() {
|
||||
assert_parse("data:,hello%20world", None, None, Some(b"hello world".iter().map(|&x| x).collect()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain_ct() {
|
||||
assert_parse("data:text/plain,hello",
|
||||
Some(("text".to_string(), "plain".to_string())), None, Some(b"hello".iter().map(|&x| x).collect()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain_charset() {
|
||||
assert_parse("data:text/plain;charset=latin1,hello",
|
||||
Some(("text".to_string(), "plain".to_string())), Some("latin1".to_string()), Some(b"hello".iter().map(|&x| x).collect()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn base64() {
|
||||
assert_parse("data:;base64,C62+7w==", None, None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn base64_ct() {
|
||||
assert_parse("data:application/octet-stream;base64,C62+7w==",
|
||||
Some(("application".to_string(), "octet-stream".to_string())), None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn base64_charset() {
|
||||
assert_parse("data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
|
||||
Some(("text".to_string(), "plain".to_string())), Some("koi8-r".to_string()),
|
||||
Some(vec!(0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4)));
|
||||
}
|
|
@ -0,0 +1,574 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use net::image_cache_task::*;
|
||||
use net_traits::image_cache_task::ImageResponseMsg::*;
|
||||
use net_traits::image_cache_task::Msg::*;
|
||||
|
||||
use net::resource_task::start_sending;
|
||||
use net_traits::{ControlMsg, Metadata, ProgressMsg, ResourceTask};
|
||||
use net_traits::image_cache_task::{ImageCacheTask, ImageResponseMsg, Msg};
|
||||
use net_traits::ProgressMsg::{Payload, Done};
|
||||
use profile::time;
|
||||
use std::sync::mpsc::{Sender, channel, Receiver};
|
||||
use url::Url;
|
||||
use util::taskpool::TaskPool;
|
||||
|
||||
static TEST_IMAGE: &'static [u8] = include_bytes!("test.jpeg");
|
||||
|
||||
pub fn test_image_bin() -> Vec<u8> {
|
||||
TEST_IMAGE.iter().map(|&x| x).collect()
|
||||
}
|
||||
|
||||
trait ImageCacheTaskHelper {
|
||||
fn wait_for_store(&self) -> Receiver<()>;
|
||||
fn wait_for_store_prefetched(&self) -> Receiver<()>;
|
||||
}
|
||||
|
||||
impl ImageCacheTaskHelper for ImageCacheTask {
|
||||
fn wait_for_store(&self) -> Receiver<()> {
|
||||
let (chan, port) = channel();
|
||||
self.send(Msg::WaitForStore(chan));
|
||||
port
|
||||
}
|
||||
|
||||
fn wait_for_store_prefetched(&self) -> Receiver<()> {
|
||||
let (chan, port) = channel();
|
||||
self.send(Msg::WaitForStorePrefetched(chan));
|
||||
port
|
||||
}
|
||||
}
|
||||
|
||||
trait Closure {
|
||||
fn invoke(&self, _response: Sender<ProgressMsg>) { }
|
||||
}
|
||||
struct DoesNothing;
|
||||
impl Closure for DoesNothing { }
|
||||
|
||||
struct JustSendOK {
|
||||
url_requested_chan: Sender<()>,
|
||||
}
|
||||
impl Closure for JustSendOK {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
self.url_requested_chan.send(()).unwrap();
|
||||
response.send(Done(Ok(()))).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
struct SendTestImage;
|
||||
impl Closure for SendTestImage {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
response.send(Payload(test_image_bin())).unwrap();
|
||||
response.send(Done(Ok(()))).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
struct SendBogusImage;
|
||||
impl Closure for SendBogusImage {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
response.send(Payload(vec!())).unwrap();
|
||||
response.send(Done(Ok(()))).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
struct SendTestImageErr;
|
||||
impl Closure for SendTestImageErr {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
response.send(Payload(test_image_bin())).unwrap();
|
||||
response.send(Done(Err("".to_string()))).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
struct WaitSendTestImage {
|
||||
wait_port: Receiver<()>,
|
||||
}
|
||||
impl Closure for WaitSendTestImage {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
// Don't send the data until after the client requests
|
||||
// the image
|
||||
self.wait_port.recv().unwrap();
|
||||
response.send(Payload(test_image_bin())).unwrap();
|
||||
response.send(Done(Ok(()))).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
struct WaitSendTestImageErr {
|
||||
wait_port: Receiver<()>,
|
||||
}
|
||||
impl Closure for WaitSendTestImageErr {
|
||||
fn invoke(&self, response: Sender<ProgressMsg>) {
|
||||
// Don't send the data until after the client requests
|
||||
// the image
|
||||
self.wait_port.recv().unwrap();
|
||||
response.send(Payload(test_image_bin())).unwrap();
|
||||
response.send(Done(Err("".to_string()))).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn mock_resource_task<T: Closure + Send + 'static>(on_load: Box<T>) -> ResourceTask {
|
||||
spawn_listener(move |port: Receiver<ControlMsg>| {
|
||||
loop {
|
||||
match port.recv().unwrap() {
|
||||
ControlMsg::Load(response) => {
|
||||
let chan = start_sending(response.consumer, Metadata::default(
|
||||
Url::parse("file:///fake").unwrap()));
|
||||
on_load.invoke(chan);
|
||||
}
|
||||
ControlMsg::Exit => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn profiler() -> time::ProfilerChan {
|
||||
time::Profiler::create(None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_exit_on_request() {
|
||||
let mock_resource_task = mock_resource_task(Box::new(DoesNothing));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn should_panic_if_unprefetched_image_is_requested() {
|
||||
let mock_resource_task = mock_resource_task(Box::new(DoesNothing));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let (chan, port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, chan));
|
||||
port.recv().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_request_url_from_resource_task_on_prefetch() {
|
||||
let (url_requested_chan, url_requested) = channel();
|
||||
|
||||
let mock_resource_task = mock_resource_task(Box::new(JustSendOK { url_requested_chan: url_requested_chan}));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url));
|
||||
url_requested.recv().unwrap();
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
|
||||
let (url_requested_chan, url_requested) = channel();
|
||||
|
||||
let mock_resource_task = mock_resource_task(Box::new(JustSendOK { url_requested_chan: url_requested_chan}));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Prefetch(url));
|
||||
url_requested.recv().unwrap();
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit).unwrap();
|
||||
match url_requested.try_recv() {
|
||||
Err(_) => (),
|
||||
Ok(_) => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_image_not_ready_if_data_has_not_arrived() {
|
||||
let (wait_chan, wait_port) = channel();
|
||||
|
||||
let mock_resource_task = mock_resource_task(Box::new(WaitSendTestImage{wait_port: wait_port}));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
assert!(response_port.recv().unwrap() == ImageResponseMsg::ImageNotReady);
|
||||
wait_chan.send(()).unwrap();
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_decoded_image_data_if_data_has_arrived() {
|
||||
let mock_resource_task = mock_resource_task(Box::new(SendTestImage));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageReady(_) => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_decoded_image_data_for_multiple_requests() {
|
||||
let mock_resource_task = mock_resource_task(Box::new(SendTestImage));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
for _ in 0..2 {
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url.clone(), response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageReady(_) => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_request_image_from_resource_task_if_image_is_already_available() {
|
||||
let (image_bin_sent_chan, image_bin_sent) = channel();
|
||||
|
||||
let (resource_task_exited_chan, resource_task_exited) = channel();
|
||||
|
||||
let mock_resource_task = spawn_listener(move |port: Receiver<ControlMsg>| {
|
||||
loop {
|
||||
match port.recv().unwrap() {
|
||||
ControlMsg::Load(response) => {
|
||||
let chan = start_sending(response.consumer, Metadata::default(
|
||||
Url::parse("file:///fake").unwrap()));
|
||||
chan.send(Payload(test_image_bin()));
|
||||
chan.send(Done(Ok(())));
|
||||
image_bin_sent_chan.send(());
|
||||
}
|
||||
ControlMsg::Exit => {
|
||||
resource_task_exited_chan.send(());
|
||||
break
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
image_bin_sent.recv().unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
|
||||
resource_task_exited.recv().unwrap();
|
||||
|
||||
// Our resource task should not have received another request for the image
|
||||
// because it's already cached
|
||||
match image_bin_sent.try_recv() {
|
||||
Err(_) => (),
|
||||
Ok(_) => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
|
||||
let (image_bin_sent_chan, image_bin_sent) = channel();
|
||||
|
||||
let (resource_task_exited_chan, resource_task_exited) = channel();
|
||||
let mock_resource_task = spawn_listener(move |port: Receiver<ControlMsg>| {
|
||||
loop {
|
||||
match port.recv().unwrap() {
|
||||
ControlMsg::Load(response) => {
|
||||
let chan = start_sending(response.consumer, Metadata::default(
|
||||
Url::parse("file:///fake").unwrap()));
|
||||
chan.send(Payload(test_image_bin()));
|
||||
chan.send(Done(Err("".to_string())));
|
||||
image_bin_sent_chan.send(());
|
||||
}
|
||||
ControlMsg::Exit => {
|
||||
resource_task_exited_chan.send(());
|
||||
break
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
image_bin_sent.recv().unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
|
||||
resource_task_exited.recv().unwrap();
|
||||
|
||||
// Our resource task should not have received another request for the image
|
||||
// because it's already cached
|
||||
match image_bin_sent.try_recv() {
|
||||
Err(_) => (),
|
||||
Ok(_) => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_failed_if_image_bin_cannot_be_fetched() {
|
||||
let mock_resource_task = mock_resource_task(Box::new(SendTestImageErr));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store_prefetched();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageFailed => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_fetched() {
|
||||
let mock_resource_task = mock_resource_task(Box::new(SendTestImageErr));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store_prefetched();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url.clone(), response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageFailed => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
// And ask again, we should get the same response
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageFailed => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_failed_if_image_decode_fails() {
|
||||
let mock_resource_task = mock_resource_task(Box::new(SendBogusImage));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
// Make the request
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageFailed => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_image_on_wait_if_image_is_already_loaded() {
|
||||
let mock_resource_task = mock_resource_task(Box::new(SendTestImage));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
// Wait until our mock resource task has sent the image to the image cache
|
||||
join_port.recv().unwrap();
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::WaitForImage(url, response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageReady(..) => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_image_on_wait_if_image_is_not_yet_loaded() {
|
||||
let (wait_chan, wait_port) = channel();
|
||||
|
||||
let mock_resource_task = mock_resource_task(Box::new(WaitSendTestImage {wait_port: wait_port}));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::WaitForImage(url, response_chan));
|
||||
|
||||
wait_chan.send(());
|
||||
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageReady(..) => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_image_failed_on_wait_if_image_fails_to_load() {
|
||||
let (wait_chan, wait_port) = channel();
|
||||
|
||||
let mock_resource_task = mock_resource_task(Box::new(WaitSendTestImageErr{wait_port: wait_port}));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Ignore);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::WaitForImage(url, response_chan));
|
||||
|
||||
wait_chan.send(());
|
||||
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageFailed => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_cache_should_wait_for_images() {
|
||||
let mock_resource_task = mock_resource_task(Box::new(SendTestImage));
|
||||
|
||||
let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new_sync(mock_resource_task.clone(),
|
||||
TaskPool::new(4), profiler(),
|
||||
LoadPlaceholder::Preload);
|
||||
let url = Url::parse("file:///").unwrap();
|
||||
|
||||
image_cache_task.send(Prefetch(url.clone()));
|
||||
image_cache_task.send(Decode(url.clone()));
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
image_cache_task.send(Msg::GetImage(url, response_chan));
|
||||
match response_port.recv().unwrap() {
|
||||
ImageResponseMsg::ImageReady(_) => (),
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(ControlMsg::Exit);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
mod cookie;
|
||||
mod data_loader;
|
||||
mod image_cache_task;
|
||||
mod resource_task;
|
|
@ -0,0 +1,184 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use net::resource_task::{new_resource_task, parse_hostsfile, replace_hosts};
|
||||
use net_traits::{ControlMsg, LoadData};
|
||||
use net_traits::ProgressMsg;
|
||||
use std::borrow::ToOwned;
|
||||
use std::boxed;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::mpsc::channel;
|
||||
use url::Url;
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_exit() {
|
||||
let resource_task = new_resource_task(None);
|
||||
resource_task.send(ControlMsg::Exit).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_scheme() {
|
||||
let resource_task = new_resource_task(None);
|
||||
let (start_chan, start) = channel();
|
||||
let url = Url::parse("bogus://whatever").unwrap();
|
||||
resource_task.send(ControlMsg::Load(LoadData::new(url, start_chan))).unwrap();
|
||||
let response = start.recv().unwrap();
|
||||
match response.progress_port.recv().unwrap() {
|
||||
ProgressMsg::Done(result) => { assert!(result.is_err()) }
|
||||
_ => panic!("bleh")
|
||||
}
|
||||
resource_task.send(ControlMsg::Exit).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile() {
|
||||
let mock_hosts_file_content = "127.0.0.1 foo.bar.com\n127.0.0.2 servo.test.server";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(2, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.2".to_owned(), *hosts_table.get(&"servo.test.server".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_malformed_hostsfile() {
|
||||
let mock_hosts_file_content = "malformed file\n127.0.0.1 foo.bar.com\nservo.test.server 127.0.0.1";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(1, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_line_comment() {
|
||||
let mock_hosts_file_content = "# this is a line comment\n127.0.0.1 foo.bar.com\n# anothercomment";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(1, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_end_of_line_comment() {
|
||||
let mock_hosts_file_content = "127.0.0.1 foo.bar.com # line ending comment\n127.0.0.2 servo.test.server #comment";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(2, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.2".to_owned(), *hosts_table.get(&"servo.test.server".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_2_hostnames_for_1_address() {
|
||||
let mock_hosts_file_content = "127.0.0.1 foo.bar.com baz.bar.com";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(2, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"baz.bar.com".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_4_hostnames_for_1_address() {
|
||||
let mock_hosts_file_content = "127.0.0.1 moz.foo.com moz.bar.com moz.baz.com moz.moz.com";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(4, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"moz.foo.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"moz.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"moz.baz.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"moz.moz.com".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_tabs_instead_spaces() {
|
||||
let mock_hosts_file_content = "127.0.0.1\tfoo.bar.com\n127.0.0.2\tservo.test.server";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(2, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.2".to_owned(), *hosts_table.get(&"servo.test.server".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_valid_ipv4_addresses()
|
||||
{
|
||||
let mock_hosts_file_content = "255.255.255.255 foo.bar.com\n169.0.1.201 servo.test.server\n192.168.5.0 servo.foo.com";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(3, (*hosts_table).len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_invalid_ipv4_addresses()
|
||||
{
|
||||
let mock_hosts_file_content = "256.255.255.255 foo.bar.com\n169.0.1000.201 servo.test.server \
|
||||
\n192.168.5.500 servo.foo.com\n192.abc.100.2 test.servo.com";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(0, (*hosts_table).len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_valid_ipv6_addresses()
|
||||
{
|
||||
let mock_hosts_file_content = "2001:0db8:0000:0000:0000:ff00:0042:8329 foo.bar.com\n\
|
||||
2001:db8:0:0:0:ff00:42:8329 moz.foo.com\n\
|
||||
2001:db8::ff00:42:8329 foo.moz.com moz.moz.com\n\
|
||||
0000:0000:0000:0000:0000:0000:0000:0001 bar.moz.com\n\
|
||||
::1 foo.bar.baz baz.foo.com\n\
|
||||
2001:0DB8:85A3:0042:1000:8A2E:0370:7334 baz.bar.moz\n\
|
||||
2002:0DB8:85A3:0042:1000:8A2E:0370:7334/96 baz2.bar.moz\n\
|
||||
2002:0DB8:85A3:0042:1000:8A2E:0370:7334/128 baz3.bar.moz\n\
|
||||
:: unspecified.moz.com\n\
|
||||
::/128 unspecified.address.com";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(12, (*hosts_table).len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_invalid_ipv6_addresses()
|
||||
{
|
||||
let mock_hosts_file_content = "12001:0db8:0000:0000:0000:ff00:0042:8329 foo.bar.com\n\
|
||||
2001:zdb8:0:0:0:gg00:42:t329 moz.foo.com\n\
|
||||
2001:db8::ff00:42:8329:1111:1111:42 foo.moz.com moz.moz.com\n\
|
||||
2002:0DB8:85A3:0042:1000:8A2E:0370:7334/1289 baz3.bar.moz";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(0, (*hosts_table).len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hostsfile_with_end_of_line_whitespace()
|
||||
{
|
||||
let mock_hosts_file_content = "127.0.0.1 foo.bar.com \n\
|
||||
2001:db8:0:0:0:ff00:42:8329 moz.foo.com\n \
|
||||
127.0.0.2 servo.test.server ";
|
||||
let hosts_table = parse_hostsfile(mock_hosts_file_content);
|
||||
assert_eq!(3, (*hosts_table).len());
|
||||
assert_eq!("127.0.0.1".to_owned(), *hosts_table.get(&"foo.bar.com".to_owned()).unwrap());
|
||||
assert_eq!("2001:db8:0:0:0:ff00:42:8329".to_owned(), *hosts_table.get(&"moz.foo.com".to_owned()).unwrap());
|
||||
assert_eq!("127.0.0.2".to_owned(), *hosts_table.get(&"servo.test.server".to_owned()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replace_hosts() {
|
||||
use std::net::TcpListener;
|
||||
|
||||
let mut host_table_box = Box::new(HashMap::new());
|
||||
host_table_box.insert("foo.bar.com".to_owned(), "127.0.0.1".to_owned());
|
||||
host_table_box.insert("servo.test.server".to_owned(), "127.0.0.2".to_owned());
|
||||
|
||||
let host_table: *mut HashMap<String, String> = unsafe {
|
||||
boxed::into_raw(host_table_box)
|
||||
};
|
||||
|
||||
//Start the TCP server
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let port = listener.socket_addr().unwrap().port();
|
||||
|
||||
//Start the resource task and make a request to our TCP server
|
||||
let resource_task = new_resource_task(None);
|
||||
let (start_chan, _) = channel();
|
||||
let url = Url::parse(&format!("http://foo.bar.com:{}", port)).unwrap();
|
||||
resource_task.send(ControlMsg::Load(replace_hosts(LoadData::new(url, start_chan), host_table))).unwrap();
|
||||
|
||||
match listener.accept() {
|
||||
Ok(..) => assert!(true, "received request"),
|
||||
Err(_) => assert!(false, "error")
|
||||
}
|
||||
|
||||
resource_task.send(ControlMsg::Exit).unwrap();
|
||||
}
|
До Ширина: | Высота: | Размер: 4.8 KiB После Ширина: | Высота: | Размер: 4.8 KiB |
|
@ -0,0 +1,6 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#[cfg(target_pointer_width = "64")] mod size_of;
|
||||
mod textinput;
|
|
@ -2,14 +2,14 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::characterdata::CharacterData;
|
||||
use dom::element::Element;
|
||||
use dom::eventtarget::EventTarget;
|
||||
use dom::htmldivelement::HTMLDivElement;
|
||||
use dom::htmlelement::HTMLElement;
|
||||
use dom::htmlspanelement::HTMLSpanElement;
|
||||
use dom::node::Node;
|
||||
use dom::text::Text;
|
||||
use script::dom::characterdata::CharacterData;
|
||||
use script::dom::element::Element;
|
||||
use script::dom::eventtarget::EventTarget;
|
||||
use script::dom::htmldivelement::HTMLDivElement;
|
||||
use script::dom::htmlelement::HTMLElement;
|
||||
use script::dom::htmlspanelement::HTMLSpanElement;
|
||||
use script::dom::node::Node;
|
||||
use script::dom::text::Text;
|
||||
|
||||
use std::mem::size_of;
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use script::textinput::{TextInput, Selection, Lines, DeleteDir};
|
||||
use std::borrow::ToOwned;
|
||||
|
||||
#[test]
|
||||
fn test_textinput_delete_char() {
|
||||
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
textinput.delete_char(DeleteDir::Backward);
|
||||
assert_eq!(textinput.get_content(), "acdefg");
|
||||
|
||||
textinput.delete_char(DeleteDir::Forward);
|
||||
assert_eq!(textinput.get_content(), "adefg");
|
||||
|
||||
textinput.adjust_horizontal(2, Selection::Selected);
|
||||
textinput.delete_char(DeleteDir::Forward);
|
||||
assert_eq!(textinput.get_content(), "afg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_insert_char() {
|
||||
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
textinput.insert_char('a');
|
||||
assert_eq!(textinput.get_content(), "abacdefg");
|
||||
|
||||
textinput.adjust_horizontal(2, Selection::Selected);
|
||||
textinput.insert_char('b');
|
||||
assert_eq!(textinput.get_content(), "ababefg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_get_sorted_selection() {
|
||||
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(2, Selection::Selected);
|
||||
let (begin, end) = textinput.get_sorted_selection();
|
||||
assert_eq!(begin.index, 2);
|
||||
assert_eq!(end.index, 4);
|
||||
|
||||
textinput.clear_selection();
|
||||
|
||||
textinput.adjust_horizontal(-2, Selection::Selected);
|
||||
let (begin, end) = textinput.get_sorted_selection();
|
||||
assert_eq!(begin.index, 2);
|
||||
assert_eq!(end.index, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_replace_selection() {
|
||||
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(2, Selection::Selected);
|
||||
|
||||
textinput.replace_selection("xyz".to_owned());
|
||||
assert_eq!(textinput.get_content(), "abxyzefg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_current_line_length() {
|
||||
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
assert_eq!(textinput.current_line_length(), 3);
|
||||
|
||||
textinput.adjust_vertical(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.current_line_length(), 2);
|
||||
|
||||
textinput.adjust_vertical(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.current_line_length(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_adjust_vertical() {
|
||||
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
textinput.adjust_horizontal(3, Selection::NotSelected);
|
||||
textinput.adjust_vertical(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
|
||||
textinput.adjust_vertical(-1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
|
||||
textinput.adjust_vertical(2, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 2);
|
||||
assert_eq!(textinput.edit_point.index, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_adjust_horizontal() {
|
||||
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
textinput.adjust_horizontal(4, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
|
||||
textinput.adjust_horizontal(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 1);
|
||||
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 2);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
|
||||
textinput.adjust_horizontal(-1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_handle_return() {
|
||||
let mut single_line_textinput = TextInput::new(Lines::Single, "abcdef".to_owned());
|
||||
single_line_textinput.adjust_horizontal(3, Selection::NotSelected);
|
||||
single_line_textinput.handle_return();
|
||||
assert_eq!(single_line_textinput.get_content(), "abcdef");
|
||||
|
||||
let mut multi_line_textinput = TextInput::new(Lines::Multiple, "abcdef".to_owned());
|
||||
multi_line_textinput.adjust_horizontal(3, Selection::NotSelected);
|
||||
multi_line_textinput.handle_return();
|
||||
assert_eq!(multi_line_textinput.get_content(), "abc\ndef");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_select_all() {
|
||||
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
|
||||
textinput.select_all();
|
||||
assert_eq!(textinput.edit_point.line, 2);
|
||||
assert_eq!(textinput.edit_point.index, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_get_content() {
|
||||
let single_line_textinput = TextInput::new(Lines::Single, "abcdefg".to_owned());
|
||||
assert_eq!(single_line_textinput.get_content(), "abcdefg");
|
||||
|
||||
let multi_line_textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
assert_eq!(multi_line_textinput.get_content(), "abc\nde\nf");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_set_content() {
|
||||
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned());
|
||||
assert_eq!(textinput.get_content(), "abc\nde\nf");
|
||||
|
||||
textinput.set_content("abc\nf".to_owned());
|
||||
assert_eq!(textinput.get_content(), "abc\nf");
|
||||
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
textinput.adjust_horizontal(3, Selection::Selected);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 3);
|
||||
textinput.set_content("de".to_owned());
|
||||
assert_eq!(textinput.get_content(), "de");
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
}
|
||||
|
|
@ -0,0 +1,416 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use geom::size::TypedSize2D;
|
||||
use style::stylesheets::{iter_stylesheet_media_rules, iter_stylesheet_style_rules, Stylesheet};
|
||||
use style::stylesheets::Origin;
|
||||
use style::media_queries::*;
|
||||
use style::values::specified;
|
||||
use std::borrow::ToOwned;
|
||||
use url::Url;
|
||||
use util::geometry::Au;
|
||||
|
||||
|
||||
fn test_media_rule<F>(css: &str, callback: F) where F: Fn(&MediaQueryList, &str) {
|
||||
let url = Url::parse("http://localhost").unwrap();
|
||||
let stylesheet = Stylesheet::from_str(css, url, Origin::Author);
|
||||
let mut rule_count = 0;
|
||||
iter_stylesheet_media_rules(&stylesheet, |rule| {
|
||||
rule_count += 1;
|
||||
callback(&rule.media_queries, css);
|
||||
});
|
||||
assert!(rule_count > 0);
|
||||
}
|
||||
|
||||
fn media_query_test(device: &Device, css: &str, expected_rule_count: u32) {
|
||||
let url = Url::parse("http://localhost").unwrap();
|
||||
let ss = Stylesheet::from_str(css, url, Origin::Author);
|
||||
let mut rule_count: u32 = 0;
|
||||
iter_stylesheet_style_rules(&ss, device, |_| rule_count += 1);
|
||||
assert!(rule_count == expected_rule_count, css.to_owned());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_empty() {
|
||||
test_media_rule("@media { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_screen() {
|
||||
test_media_rule("@media screen { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media only screen { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Only), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not screen { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_print() {
|
||||
test_media_rule("@media print { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media only print { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Only), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not print { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_unknown() {
|
||||
test_media_rule("@media fridge { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media only glass { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Only), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not wood { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_all() {
|
||||
test_media_rule("@media all { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media only all { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Only), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not all { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_or() {
|
||||
test_media_rule("@media screen, print { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 2, css.to_owned());
|
||||
let q0 = &list.media_queries[0];
|
||||
assert!(q0.qualifier == None, css.to_owned());
|
||||
assert!(q0.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q0.expressions.len() == 0, css.to_owned());
|
||||
|
||||
let q1 = &list.media_queries[1];
|
||||
assert!(q1.qualifier == None, css.to_owned());
|
||||
assert!(q1.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q1.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_default_expressions() {
|
||||
test_media_rule("@media (min-width: 100px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 1, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
|
||||
test_media_rule("@media (max-width: 43px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 1, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(43))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_expressions() {
|
||||
test_media_rule("@media screen and (min-width: 100px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q.expressions.len() == 1, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
|
||||
test_media_rule("@media print and (max-width: 43px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q.expressions.len() == 1, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(43))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
|
||||
test_media_rule("@media fridge and (max-width: 52px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
|
||||
assert!(q.expressions.len() == 1, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(52))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_multiple_expressions() {
|
||||
test_media_rule("@media (min-width: 100px) and (max-width: 200px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == None, css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 2, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
match q.expressions[1] {
|
||||
Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(200))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
|
||||
test_media_rule("@media not screen and (min-width: 100px) and (max-width: 200px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q.expressions.len() == 2, css.to_owned());
|
||||
match q.expressions[0] {
|
||||
Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
match q.expressions[1] {
|
||||
Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(200))),
|
||||
_ => panic!("wrong expression type"),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_malformed_expressions() {
|
||||
test_media_rule("@media (min-width: 100blah) and (max-width: 200px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media screen and (height: 200px) { }", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media (min-width: 30em foo bar) {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media not (min-width: 300px) {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media , {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 2, css.to_owned());
|
||||
let q = &list.media_queries[0];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
let q = &list.media_queries[1];
|
||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media screen 4px, print {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 2, css.to_owned());
|
||||
let q0 = &list.media_queries[0];
|
||||
assert!(q0.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q0.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q0.expressions.len() == 0, css.to_owned());
|
||||
let q1 = &list.media_queries[1];
|
||||
assert!(q1.qualifier == None, css.to_owned());
|
||||
assert!(q1.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
|
||||
assert!(q1.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
|
||||
test_media_rule("@media screen, {}", |list, css| {
|
||||
assert!(list.media_queries.len() == 2, css.to_owned());
|
||||
let q0 = &list.media_queries[0];
|
||||
assert!(q0.qualifier == None, css.to_owned());
|
||||
assert!(q0.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
|
||||
assert!(q0.expressions.len() == 0, css.to_owned());
|
||||
let q1 = &list.media_queries[1];
|
||||
assert!(q1.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||
assert!(q1.media_type == MediaQueryType::All, css.to_owned());
|
||||
assert!(q1.expressions.len() == 0, css.to_owned());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matching_simple() {
|
||||
let device = Device {
|
||||
media_type: MediaType::Screen,
|
||||
viewport_size: TypedSize2D(200.0, 100.0),
|
||||
};
|
||||
|
||||
media_query_test(&device, "@media not all { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not screen { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not print { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media unknown { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not unknown { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media screen { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media print { a { color: red; } }", 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matching_width() {
|
||||
let device = Device {
|
||||
media_type: MediaType::Screen,
|
||||
viewport_size: TypedSize2D(200.0, 100.0),
|
||||
};
|
||||
|
||||
media_query_test(&device, "@media { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media (min-width: 50px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media (min-width: 150px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media (min-width: 300px) { a { color: red; } }", 0);
|
||||
|
||||
media_query_test(&device, "@media screen and (min-width: 50px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media screen and (min-width: 150px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media screen and (min-width: 300px) { a { color: red; } }", 0);
|
||||
|
||||
media_query_test(&device, "@media not screen and (min-width: 50px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not screen and (min-width: 150px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not screen and (min-width: 300px) { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media (max-width: 50px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media (max-width: 150px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media (max-width: 300px) { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media screen and (min-width: 50px) and (max-width: 100px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media screen and (min-width: 250px) and (max-width: 300px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media screen and (min-width: 50px) and (max-width: 250px) { a { color: red; } }", 1);
|
||||
|
||||
media_query_test(&device, "@media not screen and (min-width: 50px) and (max-width: 100px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media not screen and (min-width: 250px) and (max-width: 300px) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media not screen and (min-width: 50px) and (max-width: 250px) { a { color: red; } }", 0);
|
||||
|
||||
media_query_test(&device, "@media not screen and (min-width: 3.1em) and (max-width: 6em) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media not screen and (min-width: 16em) and (max-width: 19.75em) { a { color: red; } }", 1);
|
||||
media_query_test(&device, "@media not screen and (min-width: 3em) and (max-width: 250px) { a { color: red; } }", 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matching_invalid() {
|
||||
let device = Device {
|
||||
media_type: MediaType::Screen,
|
||||
viewport_size: TypedSize2D(200.0, 100.0),
|
||||
};
|
||||
|
||||
media_query_test(&device, "@media fridge { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media screen and (height: 100px) { a { color: red; } }", 0);
|
||||
media_query_test(&device, "@media not print and (width: 100) { a { color: red; } }", 0);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use util::logical_geometry::WritingMode;
|
||||
use style::properties::{INITIAL_VALUES, get_writing_mode};
|
||||
|
||||
|
||||
mod stylesheets;
|
||||
mod media_queries;
|
||||
|
||||
|
||||
#[test]
|
||||
fn initial_writing_mode_is_empty() {
|
||||
assert_eq!(get_writing_mode(INITIAL_VALUES.get_inheritedbox()), WritingMode::empty())
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::borrow::ToOwned;
|
||||
use std::sync::Arc;
|
||||
use cssparser;
|
||||
use selectors::parser::*;
|
||||
use string_cache::Atom;
|
||||
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, DeclaredValue, longhands};
|
||||
use style::stylesheets::{CSSRule, StyleRule, Origin, Stylesheet};
|
||||
use url::Url;
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_parse_stylesheet() {
|
||||
let css = r"
|
||||
@namespace url(http://www.w3.org/1999/xhtml);
|
||||
/* FIXME: only if scripting is enabled */
|
||||
input[type=hidden i] { display: none !important; }
|
||||
html , body /**/ { display: block; }
|
||||
#d1 > .ok { background: blue; }
|
||||
";
|
||||
let url = Url::parse("about::test").unwrap();
|
||||
let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent);
|
||||
assert_eq!(stylesheet, Stylesheet {
|
||||
origin: Origin::UserAgent,
|
||||
rules: vec![
|
||||
CSSRule::Namespace(None, ns!(HTML)),
|
||||
CSSRule::Style(StyleRule {
|
||||
selectors: vec![
|
||||
Selector {
|
||||
compound_selectors: Arc::new(CompoundSelector {
|
||||
simple_selectors: vec![
|
||||
SimpleSelector::Namespace(ns!(HTML)),
|
||||
SimpleSelector::LocalName(LocalName {
|
||||
name: atom!(input),
|
||||
lower_name: atom!(input),
|
||||
}),
|
||||
SimpleSelector::AttrEqual(AttrSelector {
|
||||
name: atom!(type),
|
||||
lower_name: atom!(type),
|
||||
namespace: NamespaceConstraint::Specific(ns!("")),
|
||||
}, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
|
||||
],
|
||||
next: None,
|
||||
}),
|
||||
pseudo_element: None,
|
||||
specificity: (0 << 20) + (1 << 10) + (1 << 0),
|
||||
},
|
||||
],
|
||||
declarations: PropertyDeclarationBlock {
|
||||
normal: Arc::new(vec![]),
|
||||
important: Arc::new(vec![
|
||||
PropertyDeclaration::Display(DeclaredValue::SpecifiedValue(
|
||||
longhands::display::SpecifiedValue::none)),
|
||||
]),
|
||||
},
|
||||
}),
|
||||
CSSRule::Style(StyleRule {
|
||||
selectors: vec![
|
||||
Selector {
|
||||
compound_selectors: Arc::new(CompoundSelector {
|
||||
simple_selectors: vec![
|
||||
SimpleSelector::Namespace(ns!(HTML)),
|
||||
SimpleSelector::LocalName(LocalName {
|
||||
name: atom!(html),
|
||||
lower_name: atom!(html),
|
||||
}),
|
||||
],
|
||||
next: None,
|
||||
}),
|
||||
pseudo_element: None,
|
||||
specificity: (0 << 20) + (0 << 10) + (1 << 0),
|
||||
},
|
||||
Selector {
|
||||
compound_selectors: Arc::new(CompoundSelector {
|
||||
simple_selectors: vec![
|
||||
SimpleSelector::Namespace(ns!(HTML)),
|
||||
SimpleSelector::LocalName(LocalName {
|
||||
name: atom!(body),
|
||||
lower_name: atom!(body),
|
||||
}),
|
||||
],
|
||||
next: None,
|
||||
}),
|
||||
pseudo_element: None,
|
||||
specificity: (0 << 20) + (0 << 10) + (1 << 0),
|
||||
},
|
||||
],
|
||||
declarations: PropertyDeclarationBlock {
|
||||
normal: Arc::new(vec![
|
||||
PropertyDeclaration::Display(DeclaredValue::SpecifiedValue(
|
||||
longhands::display::SpecifiedValue::block)),
|
||||
]),
|
||||
important: Arc::new(vec![]),
|
||||
},
|
||||
}),
|
||||
CSSRule::Style(StyleRule {
|
||||
selectors: vec![
|
||||
Selector {
|
||||
compound_selectors: Arc::new(CompoundSelector {
|
||||
simple_selectors: vec![
|
||||
SimpleSelector::Class(Atom::from_slice("ok")),
|
||||
],
|
||||
next: Some((Box::new(CompoundSelector {
|
||||
simple_selectors: vec![
|
||||
SimpleSelector::ID(Atom::from_slice("d1")),
|
||||
],
|
||||
next: None,
|
||||
}), Combinator::Child)),
|
||||
}),
|
||||
pseudo_element: None,
|
||||
specificity: (1 << 20) + (1 << 10) + (0 << 0),
|
||||
},
|
||||
],
|
||||
declarations: PropertyDeclarationBlock {
|
||||
normal: Arc::new(vec![
|
||||
PropertyDeclaration::BackgroundSize(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundImage(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundPosition(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundColor(DeclaredValue::SpecifiedValue(
|
||||
longhands::background_color::SpecifiedValue {
|
||||
authored: Some("blue".to_owned()),
|
||||
parsed: cssparser::Color::RGBA(cssparser::RGBA {
|
||||
red: 0., green: 0., blue: 1., alpha: 1.
|
||||
}),
|
||||
}
|
||||
)),
|
||||
]),
|
||||
important: Arc::new(vec![]),
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::cell::Cell;
|
||||
use util::cache::{HashCache, LRUCache};
|
||||
|
||||
#[test]
|
||||
fn test_hashcache() {
|
||||
let mut cache: HashCache<usize, Cell<&str>> = HashCache::new();
|
||||
|
||||
cache.insert(1, Cell::new("one"));
|
||||
assert!(cache.find(&1).is_some());
|
||||
assert!(cache.find(&2).is_none());
|
||||
|
||||
cache.find_or_create(&2, |_v| { Cell::new("two") });
|
||||
assert!(cache.find(&1).is_some());
|
||||
assert!(cache.find(&2).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lru_cache() {
|
||||
let one = Cell::new("one");
|
||||
let two = Cell::new("two");
|
||||
let three = Cell::new("three");
|
||||
let four = Cell::new("four");
|
||||
|
||||
// Test normal insertion.
|
||||
let mut cache: LRUCache<usize,Cell<&str>> = LRUCache::new(2); // (_, _) (cache is empty)
|
||||
cache.insert(1, one); // (1, _)
|
||||
cache.insert(2, two); // (1, 2)
|
||||
cache.insert(3, three); // (2, 3)
|
||||
|
||||
assert!(cache.find(&1).is_none()); // (2, 3) (no change)
|
||||
assert!(cache.find(&3).is_some()); // (2, 3)
|
||||
assert!(cache.find(&2).is_some()); // (3, 2)
|
||||
|
||||
// Test that LRU works (this insertion should replace 3, not 2).
|
||||
cache.insert(4, four); // (2, 4)
|
||||
|
||||
assert!(cache.find(&1).is_none()); // (2, 4) (no change)
|
||||
assert!(cache.find(&2).is_some()); // (4, 2)
|
||||
assert!(cache.find(&3).is_none()); // (4, 2) (no change)
|
||||
assert!(cache.find(&4).is_some()); // (2, 4) (no change)
|
||||
|
||||
// Test find_or_create.
|
||||
cache.find_or_create(&1, |_| { Cell::new("one") }); // (4, 1)
|
||||
|
||||
assert!(cache.find(&1).is_some()); // (4, 1) (no change)
|
||||
assert!(cache.find(&2).is_none()); // (4, 1) (no change)
|
||||
assert!(cache.find(&3).is_none()); // (4, 1) (no change)
|
||||
assert!(cache.find(&4).is_some()); // (1, 4)
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use geom::{Size2D, Point2D, SideOffsets2D, Rect};
|
||||
use util::logical_geometry::{WritingMode, LogicalSize, LogicalPoint, LogicalMargin, LogicalRect,
|
||||
FLAG_RTL, FLAG_VERTICAL, FLAG_VERTICAL_LR, FLAG_SIDEWAYS_LEFT};
|
||||
|
||||
#[cfg(test)]
|
||||
fn modes() -> [WritingMode; 10] {
|
||||
[
|
||||
WritingMode::empty(),
|
||||
FLAG_VERTICAL,
|
||||
FLAG_VERTICAL | FLAG_VERTICAL_LR,
|
||||
FLAG_VERTICAL | FLAG_VERTICAL_LR | FLAG_SIDEWAYS_LEFT,
|
||||
FLAG_VERTICAL | FLAG_SIDEWAYS_LEFT,
|
||||
FLAG_RTL,
|
||||
FLAG_VERTICAL | FLAG_RTL,
|
||||
FLAG_VERTICAL | FLAG_VERTICAL_LR | FLAG_RTL,
|
||||
FLAG_VERTICAL | FLAG_VERTICAL_LR | FLAG_SIDEWAYS_LEFT | FLAG_RTL,
|
||||
FLAG_VERTICAL | FLAG_SIDEWAYS_LEFT | FLAG_RTL,
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_size_round_trip() {
|
||||
let physical = Size2D(1u32, 2u32);
|
||||
for &mode in modes().iter() {
|
||||
let logical = LogicalSize::from_physical(mode, physical);
|
||||
assert!(logical.to_physical(mode) == physical);
|
||||
assert!(logical.width(mode) == 1);
|
||||
assert!(logical.height(mode) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_point_round_trip() {
|
||||
let physical = Point2D(1u32, 2u32);
|
||||
let container = Size2D(100, 200);
|
||||
for &mode in modes().iter() {
|
||||
let logical = LogicalPoint::from_physical(mode, physical, container);
|
||||
assert!(logical.to_physical(mode, container) == physical);
|
||||
assert!(logical.x(mode, container) == 1);
|
||||
assert!(logical.y(mode, container) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_margin_round_trip() {
|
||||
let physical = SideOffsets2D::new(1u32, 2u32, 3u32, 4u32);
|
||||
for &mode in modes().iter() {
|
||||
let logical = LogicalMargin::from_physical(mode, physical);
|
||||
assert!(logical.to_physical(mode) == physical);
|
||||
assert!(logical.top(mode) == 1);
|
||||
assert!(logical.right(mode) == 2);
|
||||
assert!(logical.bottom(mode) == 3);
|
||||
assert!(logical.left(mode) == 4);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rect_round_trip() {
|
||||
let physical = Rect(Point2D(1u32, 2u32), Size2D(3u32, 4u32));
|
||||
let container = Size2D(100, 200);
|
||||
for &mode in modes().iter() {
|
||||
let logical = LogicalRect::from_physical(mode, physical, container);
|
||||
assert!(logical.to_physical(mode, container) == physical);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
mod cache;
|
||||
mod logical_geometry;
|
||||
mod task;
|
||||
mod vec;
|
|
@ -0,0 +1,13 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::borrow::ToOwned;
|
||||
use util::task::spawn_named;
|
||||
|
||||
#[test]
|
||||
fn spawn_named_test() {
|
||||
spawn_named("Test".to_owned(), move || {
|
||||
println!("I can run!");
|
||||
});
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::fmt::Debug;
|
||||
use util::vec::BinarySearchMethods;
|
||||
|
||||
#[cfg(test)]
|
||||
fn test_find_all_elems<T: PartialEq + PartialOrd + Eq + Ord>(arr: &[T]) {
|
||||
let mut i = 0;
|
||||
while i < arr.len() {
|
||||
assert!(test_match(&arr[i], arr.binary_search_(&arr[i])));
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn test_miss_all_elems<T: PartialEq + PartialOrd + Eq + Ord + Debug>(arr: &[T], misses: &[T]) {
|
||||
let mut i = 0;
|
||||
while i < misses.len() {
|
||||
let res = arr.binary_search_(&misses[i]);
|
||||
println!("{:?} == {:?} ?", misses[i], res);
|
||||
assert!(!test_match(&misses[i], arr.binary_search_(&misses[i])));
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn test_match<T: PartialEq>(b: &T, a: Option<&T>) -> bool {
|
||||
match a {
|
||||
None => false,
|
||||
Some(t) => t == b
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_find_all_elements() {
|
||||
let arr_odd = [1u32, 2, 4, 6, 7, 8, 9];
|
||||
let arr_even = [1u32, 2, 5, 6, 7, 8, 9, 42];
|
||||
let arr_double = [1u32, 1, 2, 2, 6, 8, 22];
|
||||
let arr_one = [234986325u32];
|
||||
let arr_two = [3044u32, 8393];
|
||||
let arr_three = [12u32, 23, 34];
|
||||
|
||||
test_find_all_elems(&arr_odd);
|
||||
test_find_all_elems(&arr_even);
|
||||
test_find_all_elems(&arr_double);
|
||||
test_find_all_elems(&arr_one);
|
||||
test_find_all_elems(&arr_two);
|
||||
test_find_all_elems(&arr_three);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_find_missing_elements() {
|
||||
let arr_odd = [1u32, 2, 4, 6, 7, 8, 9];
|
||||
let arr_even = [1u32, 2, 5, 6, 7, 8, 9, 42];
|
||||
let arr_double = [1u32, 1, 2, 2, 6, 8, 22];
|
||||
let arr_one = [234986325u32];
|
||||
let arr_two = [3044u32, 8393];
|
||||
let arr_three = [12u32, 23, 34];
|
||||
|
||||
test_miss_all_elems(&arr_odd, &[-22, 0, 3, 5, 34938, 10, 11, 12]);
|
||||
test_miss_all_elems(&arr_even, &[-1, 0, 3, 34938, 10, 11, 12]);
|
||||
test_miss_all_elems(&arr_double, &[-1, 0, 3, 4, 34938, 10, 11, 12, 234, 234, 33]);
|
||||
test_miss_all_elems(&arr_one, &[-1, 0, 3, 34938, 10, 11, 12, 234, 234, 33]);
|
||||
test_miss_all_elems(&arr_two, &[-1, 0, 3, 34938, 10, 11, 12, 234, 234, 33]);
|
||||
test_miss_all_elems(&arr_three, &[-2, 0, 1, 2, 3, 34938, 10, 11, 234, 234, 33]);
|
||||
}
|
Загрузка…
Ссылка в новой задаче