diff --git a/components/gfx/text/util.rs b/components/gfx/text/util.rs index 4b8f5041143..42bba6c449e 100644 --- a/components/gfx/text/util.rs +++ b/components/gfx/text/util.rs @@ -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) - } -} diff --git a/components/net/cookie.rs b/components/net/cookie.rs index cce566785d4..48b9fab41ed 100644 --- a/components/net/cookie.rs +++ b/components/net/cookie.rs @@ -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()); -} diff --git a/components/net/cookie_storage.rs b/components/net/cookie_storage.rs index 6af661ee60c..80c69a45809 100644 --- a/components/net/cookie_storage.rs +++ b/components/net/cookie_storage.rs @@ -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); -} diff --git a/components/net/data_loader.rs b/components/net/data_loader.rs index dc1b4356390..03ec60be3a8 100644 --- a/components/net/data_loader.rs +++ b/components/net/data_loader.rs @@ -21,7 +21,7 @@ pub fn factory(load_data: LoadData, _classifier: Arc) { 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, - data: Option>) { - 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))); -} diff --git a/components/net/image_cache_task.rs b/components/net/image_cache_task.rs index df38f9d7c31..5897ee50fb2 100644 --- a/components/net/image_cache_task.rs +++ b/components/net/image_cache_task.rs @@ -420,578 +420,3 @@ pub fn spawn_listener(f: F) -> Sender }); 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 { - 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) { } - } - struct DoesNothing; - impl Closure for DoesNothing { } - - struct JustSendOK { - url_requested_chan: Sender<()>, - } - impl Closure for JustSendOK { - fn invoke(&self, response: Sender) { - self.url_requested_chan.send(()); - response.send(Done(Ok(()))); - } - } - - struct SendTestImage; - impl Closure for SendTestImage { - fn invoke(&self, response: Sender) { - response.send(Payload(test_image_bin())); - response.send(Done(Ok(()))); - } - } - - struct SendBogusImage; - impl Closure for SendBogusImage { - fn invoke(&self, response: Sender) { - response.send(Payload(vec!())); - response.send(Done(Ok(()))); - } - } - - struct SendTestImageErr; - impl Closure for SendTestImageErr { - fn invoke(&self, response: Sender) { - 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) { - // 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) { - // 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(on_load: Box) -> ResourceTask { - spawn_listener(move |port: Receiver| { - 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| { - 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| { - 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); - } -} diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index a63cf83a7af..4d29526a989 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -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 = 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); -} diff --git a/components/script/lib.rs b/components/script/lib.rs index c51219cb11d..4a9fcdbd09c 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -66,6 +66,3 @@ pub mod script_task; mod timers; pub mod textinput; mod devtools; - -#[cfg(all(test, target_pointer_width = "64"))] -mod tests; diff --git a/components/script/textinput.rs b/components/script/textinput.rs index 8239c08c58f..c26549bff73 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -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, /// 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, /// 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); -} - diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 67fac783c24..83800fc7709 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -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" diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index a72401d3ad5..37644696810 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -16,6 +16,9 @@ test = false doc = false bench = false +[dev-dependencies.unit_tests] +path = "../../tests/unit" + [[test]] name = "reftest" path = "../../tests/reftest.rs" diff --git a/components/style/media_queries.rs b/components/style/media_queries.rs index 69715b80885..ce69b0b0716 100644 --- a/components/style/media_queries.rs +++ b/components/style/media_queries.rs @@ -13,7 +13,7 @@ use values::specified; #[derive(Debug, PartialEq)] pub struct MediaQueryList { - media_queries: Vec + pub media_queries: Vec } #[derive(PartialEq, Eq, Copy, Debug)] @@ -71,9 +71,9 @@ pub enum Qualifier { #[derive(Debug, PartialEq)] pub struct MediaQuery { - qualifier: Option, - media_type: MediaQueryType, - expressions: Vec, + pub qualifier: Option, + pub media_type: MediaQueryType, + pub expressions: Vec, } 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(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); - } -} diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 2ec8edee31a..2b2c74a2495 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -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( diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 11135ac580e..1bc41a20da1 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -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, + pub rules: Vec, pub origin: Origin, } @@ -322,136 +322,3 @@ pub fn iter_font_face_rules(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![]), - }, - }), - ], - }); -} diff --git a/components/util/cache.rs b/components/util/cache.rs index 8719c176921..26eab254ccf 100644 --- a/components/util/cache.rs +++ b/components/util/cache.rs @@ -12,8 +12,6 @@ use rand; use std::slice::Iter; use std::default::Default; -#[cfg(test)] -use std::cell::Cell; pub struct HashCache { entries: HashMap>, @@ -56,19 +54,6 @@ impl HashCache } } -#[test] -fn test_hashcache() { - let mut cache: HashCache> = 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 { entries: Vec<(K, V)>, cache_size: usize, @@ -183,37 +168,3 @@ impl SimpleHashCache { } } } - -#[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> = 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) -} diff --git a/components/util/logical_geometry.rs b/components/util/logical_geometry.rs index f464412fb46..ef85866fb97 100644 --- a/components/util/logical_geometry.rs +++ b/components/util/logical_geometry.rs @@ -965,65 +965,3 @@ impl + Sub> Sub> 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); - } -} diff --git a/components/util/task.rs b/components/util/task.rs index 97770269259..de206526f44 100644 --- a/components/util/task.rs +++ b/components/util/task.rs @@ -42,10 +42,3 @@ pub fn spawn_named_with_send_on_failure(name: &'static str, } }).unwrap(); } - -#[test] -fn spawn_named_test() { - spawn_named("Test".to_owned(), move || { - debug!("I can run!"); - }); -} diff --git a/components/util/vec.rs b/components/util/vec.rs index a1b07126e06..cce3e867676 100644 --- a/components/util/vec.rs +++ b/components/util/vec.rs @@ -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 { @@ -75,65 +72,3 @@ pub fn byte_swap(data: &mut [u8]) { data[i + 0] = r; } } - -#[cfg(test)] -fn test_find_all_elems(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(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(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]); -} diff --git a/python/licenseck.py b/python/licenseck.py index 0b2f6700c82..c904833ea8e 100644 --- a/python/licenseck.py +++ b/python/licenseck.py @@ -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 diff --git a/python/servo/testing_commands.py b/python/servo/testing_commands.py index b64d0030d18..e538c79c789 100644 --- a/python/servo/testing_commands.py +++ b/python/servo/testing_commands.py @@ -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', diff --git a/python/tidy.py b/python/tidy.py index cb20dff1646..4d24b2163cb 100644 --- a/python/tidy.py +++ b/python/tidy.py @@ -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/*", diff --git a/tests/unit/Cargo.toml b/tests/unit/Cargo.toml new file mode 100644 index 00000000000..5f0d1125796 --- /dev/null +++ b/tests/unit/Cargo.toml @@ -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 = "*" diff --git a/tests/unit/gfx/mod.rs b/tests/unit/gfx/mod.rs new file mode 100644 index 00000000000..4d160f2a8dc --- /dev/null +++ b/tests/unit/gfx/mod.rs @@ -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; diff --git a/tests/unit/gfx/text_util.rs b/tests/unit/gfx/text_util.rs new file mode 100644 index 00000000000..6f63d18316f --- /dev/null +++ b/tests/unit/gfx/text_util.rs @@ -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) + } +} diff --git a/tests/unit/lib.rs b/tests/unit/lib.rs new file mode 100644 index 00000000000..f040b2e9513 --- /dev/null +++ b/tests/unit/lib.rs @@ -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; diff --git a/tests/unit/net/cookie.rs b/tests/unit/net/cookie.rs new file mode 100644 index 00000000000..afdbd05334b --- /dev/null +++ b/tests/unit/net/cookie.rs @@ -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); +} diff --git a/tests/unit/net/data_loader.rs b/tests/unit/net/data_loader.rs new file mode 100644 index 00000000000..370fa1bd28e --- /dev/null +++ b/tests/unit/net/data_loader.rs @@ -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, + data: Option>) { + 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))); +} diff --git a/tests/unit/net/image_cache_task.rs b/tests/unit/net/image_cache_task.rs new file mode 100644 index 00000000000..a57b0361e6c --- /dev/null +++ b/tests/unit/net/image_cache_task.rs @@ -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 { + 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) { } +} +struct DoesNothing; +impl Closure for DoesNothing { } + +struct JustSendOK { + url_requested_chan: Sender<()>, +} +impl Closure for JustSendOK { + fn invoke(&self, response: Sender) { + self.url_requested_chan.send(()).unwrap(); + response.send(Done(Ok(()))).unwrap(); + } +} + +struct SendTestImage; +impl Closure for SendTestImage { + fn invoke(&self, response: Sender) { + response.send(Payload(test_image_bin())).unwrap(); + response.send(Done(Ok(()))).unwrap(); + } +} + +struct SendBogusImage; +impl Closure for SendBogusImage { + fn invoke(&self, response: Sender) { + response.send(Payload(vec!())).unwrap(); + response.send(Done(Ok(()))).unwrap(); + } +} + +struct SendTestImageErr; +impl Closure for SendTestImageErr { + fn invoke(&self, response: Sender) { + 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) { + // 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) { + // 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(on_load: Box) -> ResourceTask { + spawn_listener(move |port: Receiver| { + 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| { + 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| { + 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); +} diff --git a/tests/unit/net/mod.rs b/tests/unit/net/mod.rs new file mode 100644 index 00000000000..e4137759590 --- /dev/null +++ b/tests/unit/net/mod.rs @@ -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; diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs new file mode 100644 index 00000000000..da79322a2ff --- /dev/null +++ b/tests/unit/net/resource_task.rs @@ -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 = 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(); +} diff --git a/components/net/test.jpeg b/tests/unit/net/test.jpeg similarity index 100% rename from components/net/test.jpeg rename to tests/unit/net/test.jpeg diff --git a/tests/unit/script/mod.rs b/tests/unit/script/mod.rs new file mode 100644 index 00000000000..1631a9adc8c --- /dev/null +++ b/tests/unit/script/mod.rs @@ -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; diff --git a/components/script/tests.rs b/tests/unit/script/size_of.rs similarity index 85% rename from components/script/tests.rs rename to tests/unit/script/size_of.rs index a0f82628cd6..d32f2bf4375 100644 --- a/components/script/tests.rs +++ b/tests/unit/script/size_of.rs @@ -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; diff --git a/tests/unit/script/textinput.rs b/tests/unit/script/textinput.rs new file mode 100644 index 00000000000..322ee63c1c5 --- /dev/null +++ b/tests/unit/script/textinput.rs @@ -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 or the MIT license +// , 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); +} + diff --git a/tests/unit/style/media_queries.rs b/tests/unit/style/media_queries.rs new file mode 100644 index 00000000000..7f4dbc8f5e6 --- /dev/null +++ b/tests/unit/style/media_queries.rs @@ -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(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); +} diff --git a/tests/unit/style/mod.rs b/tests/unit/style/mod.rs new file mode 100644 index 00000000000..a2af201f7c3 --- /dev/null +++ b/tests/unit/style/mod.rs @@ -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()) +} diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs new file mode 100644 index 00000000000..6d7a3814394 --- /dev/null +++ b/tests/unit/style/stylesheets.rs @@ -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![]), + }, + }), + ], + }); +} diff --git a/tests/unit/util/cache.rs b/tests/unit/util/cache.rs new file mode 100644 index 00000000000..f6e93222208 --- /dev/null +++ b/tests/unit/util/cache.rs @@ -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> = 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> = 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) +} diff --git a/tests/unit/util/logical_geometry.rs b/tests/unit/util/logical_geometry.rs new file mode 100644 index 00000000000..d336d441734 --- /dev/null +++ b/tests/unit/util/logical_geometry.rs @@ -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); + } +} diff --git a/tests/unit/util/mod.rs b/tests/unit/util/mod.rs new file mode 100644 index 00000000000..756af732b67 --- /dev/null +++ b/tests/unit/util/mod.rs @@ -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; diff --git a/tests/unit/util/task.rs b/tests/unit/util/task.rs new file mode 100644 index 00000000000..48edf0c7177 --- /dev/null +++ b/tests/unit/util/task.rs @@ -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!"); + }); +} diff --git a/tests/unit/util/vec.rs b/tests/unit/util/vec.rs new file mode 100644 index 00000000000..815e0500918 --- /dev/null +++ b/tests/unit/util/vec.rs @@ -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(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(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(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]); +}