ソースを参照

Fix multiple issues on wasm32: (#886)

* remove `Url::socket_addrs` on wasm32-unknown-unknown (it won't work, those
  platform API calls are not supported)

* disable unit tests which won't work on wasm32-unknown-unknown

* run tests in `wasm_bindgen_test` on wasm32-unknown-unknown

* remove `panic::catch_unwind` from wpt tests, as that conflicts with
  wasm-bindgen's panic handler

* run the tests in CI
micolous 2 年 前
コミット
49eea1c2eb
5 ファイル変更126 行追加60 行削除
  1. 4 0
      .github/workflows/main.yml
  2. 3 0
      url/Cargo.toml
  3. 5 1
      url/src/lib.rs
  4. 28 19
      url/tests/unit.rs
  5. 86 40
      url/tests/wpt.rs

+ 4 - 0
.github/workflows/main.yml

@@ -59,7 +59,11 @@ jobs:
       - uses: dtolnay/rust-toolchain@stable
         with:
           targets: wasm32-unknown-unknown
+      - name: Install wasm-pack
+        run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
       - run: cargo build --target wasm32-unknown-unknown
+      - run: cd url && wasm-pack test --headless --chrome
+      - run: cd url && wasm-pack test --headless --firefox
 
   Lint:
     runs-on: ubuntu-latest

+ 3 - 0
url/Cargo.toml

@@ -21,6 +21,9 @@ serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 bencher = "0.1"
 
+[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies]
+wasm-bindgen-test = "0.3"
+
 [dependencies]
 form_urlencoded = { version = "1.2.1", path = "../form_urlencoded" }
 idna = { version = "0.5.0", path = "../idna" }

+ 5 - 1
url/src/lib.rs

@@ -154,9 +154,12 @@ use std::borrow::Borrow;
 use std::cmp;
 use std::fmt::{self, Write};
 use std::hash;
+#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
 use std::io;
 use std::mem;
-use std::net::{IpAddr, SocketAddr, ToSocketAddrs};
+use std::net::IpAddr;
+#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
+use std::net::{SocketAddr, ToSocketAddrs};
 use std::ops::{Range, RangeFrom, RangeTo};
 use std::path::{Path, PathBuf};
 use std::str;
@@ -1252,6 +1255,7 @@ impl Url {
     ///     })
     /// }
     /// ```
+    #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
     pub fn socket_addrs(
         &self,
         default_port_number: impl Fn() -> Option<u16>,

+ 28 - 19
url/tests/unit.rs

@@ -11,9 +11,16 @@
 use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
 use std::net::{Ipv4Addr, Ipv6Addr};
+#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
 use std::path::{Path, PathBuf};
 use url::{form_urlencoded, Host, Origin, Url};
 
+// https://rustwasm.github.io/wasm-bindgen/wasm-bindgen-test/usage.html
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+wasm_bindgen_test_configure!(run_in_browser);
+
 #[test]
 fn size() {
     use std::mem::size_of;
@@ -117,6 +124,7 @@ fn test_set_empty_query() {
     assert_eq!(base.as_str(), "moz://example.com/path");
 }
 
+#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
 macro_rules! assert_from_file_path {
     ($path: expr) => {
         assert_from_file_path!($path, $path)
@@ -130,6 +138,7 @@ macro_rules! assert_from_file_path {
 }
 
 #[test]
+#[cfg(any(unix, windows))]
 fn new_file_paths() {
     if cfg!(unix) {
         assert_eq!(Url::from_file_path(Path::new("relative")), Err(()));
@@ -162,28 +171,28 @@ fn new_path_bad_utf8() {
 }
 
 #[test]
+#[cfg(windows)]
 fn new_path_windows_fun() {
-    if cfg!(windows) {
-        assert_from_file_path!(r"C:\foo\bar", "/C:/foo/bar");
-        assert_from_file_path!("C:\\foo\\ba\0r", "/C:/foo/ba%00r");
+    assert_from_file_path!(r"C:\foo\bar", "/C:/foo/bar");
+    assert_from_file_path!("C:\\foo\\ba\0r", "/C:/foo/ba%00r");
 
-        // Invalid UTF-8
-        assert!(Url::parse("file:///C:/foo/ba%80r")
-            .unwrap()
-            .to_file_path()
-            .is_err());
+    // Invalid UTF-8
+    assert!(Url::parse("file:///C:/foo/ba%80r")
+        .unwrap()
+        .to_file_path()
+        .is_err());
 
-        // test windows canonicalized path
-        let path = PathBuf::from(r"\\?\C:\foo\bar");
-        assert!(Url::from_file_path(path).is_ok());
+    // test windows canonicalized path
+    let path = PathBuf::from(r"\\?\C:\foo\bar");
+    assert!(Url::from_file_path(path).is_ok());
 
-        // Percent-encoded drive letter
-        let url = Url::parse("file:///C%3A/foo/bar").unwrap();
-        assert_eq!(url.to_file_path(), Ok(PathBuf::from(r"C:\foo\bar")));
-    }
+    // Percent-encoded drive letter
+    let url = Url::parse("file:///C%3A/foo/bar").unwrap();
+    assert_eq!(url.to_file_path(), Ok(PathBuf::from(r"C:\foo\bar")));
 }
 
 #[test]
+#[cfg(any(unix, windows))]
 fn new_directory_paths() {
     if cfg!(unix) {
         assert_eq!(Url::from_directory_path(Path::new("relative")), Err(()));
@@ -439,6 +448,7 @@ fn issue_61() {
 }
 
 #[test]
+#[cfg(any(unix, target_os = "redox", target_os = "wasi"))]
 #[cfg(not(windows))]
 /// https://github.com/servo/rust-url/issues/197
 fn issue_197() {
@@ -623,6 +633,7 @@ fn test_origin_unicode_serialization() {
 }
 
 #[test]
+#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
 fn test_socket_addrs() {
     use std::net::ToSocketAddrs;
 
@@ -804,11 +815,8 @@ fn test_expose_internals() {
 }
 
 #[test]
+#[cfg(windows)]
 fn test_windows_unc_path() {
-    if !cfg!(windows) {
-        return;
-    }
-
     let url = Url::from_file_path(Path::new(r"\\host\share\path\file.txt")).unwrap();
     assert_eq!(url.as_str(), "file://host/share/path/file.txt");
 
@@ -928,6 +936,7 @@ fn test_url_from_file_path() {
 }
 
 /// https://github.com/servo/rust-url/issues/505
+#[cfg(any(unix, target_os = "redox", target_os = "wasi"))]
 #[cfg(not(windows))]
 #[test]
 fn test_url_from_file_path() {

+ 86 - 40
url/tests/wpt.rs

@@ -8,13 +8,62 @@
 
 //! Data-driven tests imported from web-platform-tests
 
+use serde_json::Value;
 use std::collections::HashMap;
 use std::fmt::Write;
-use std::panic;
-
-use serde_json::Value;
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+use std::sync::Mutex;
 use url::Url;
 
+// https://rustwasm.github.io/wasm-bindgen/wasm-bindgen-test/usage.html
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+use wasm_bindgen_test::{console_log, wasm_bindgen_test, wasm_bindgen_test_configure};
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+wasm_bindgen_test_configure!(run_in_browser);
+
+// wpt has its own test driver, but we shoe-horn this into wasm_bindgen_test
+// which will discard stdout and stderr. So, we make println! go to
+// console.log(), so we see failures that do not result in panics.
+
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+static PRINT_BUF: Mutex<Option<String>> = Mutex::new(None);
+
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+macro_rules! print {
+    ($($arg:tt)*) => {
+        let v = format!($($arg)*);
+        {
+            let mut buf = PRINT_BUF.lock().unwrap();
+            if let Some(buf) = buf.as_mut() {
+                buf.push_str(&v);
+            } else {
+                *buf = Some(v);
+            }
+        }
+    };
+}
+
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+macro_rules! println {
+    () => {
+        let buf = PRINT_BUF.lock().unwrap().take();
+        match buf {
+            Some(buf) => console_log!("{buf}"),
+            None => console_log!(""),
+        }
+    };
+    ($($arg:tt)*) => {
+        let buf = PRINT_BUF.lock().unwrap().take();
+        match buf {
+            Some(buf) => {
+                let v = format!($($arg)*);
+                console_log!("{buf}{v}");
+            },
+            None => console_log!($($arg)*),
+        }
+    }
+}
+
 #[derive(Debug, serde::Deserialize)]
 struct UrlTest {
     input: String,
@@ -71,6 +120,7 @@ struct SetterTestExpected {
     hash: Option<String>,
 }
 
+#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), wasm_bindgen_test)]
 fn main() {
     let mut filter = None;
     let mut args = std::env::args().skip(1);
@@ -228,16 +278,16 @@ fn run_url_test(
 ) -> Result<(), String> {
     let base = match base {
         Some(base) => {
-            let base = panic::catch_unwind(|| Url::parse(&base))
-                .map_err(|_| "panicked while parsing base".to_string())?
-                .map_err(|e| format!("errored while parsing base: {}", e))?;
+            let base =
+                Url::parse(&base).map_err(|e| format!("errored while parsing base: {}", e))?;
             Some(base)
         }
         None => None,
     };
 
-    let res = panic::catch_unwind(move || Url::options().base_url(base.as_ref()).parse(&input))
-        .map_err(|_| "panicked while parsing input".to_string())?
+    let res = Url::options()
+        .base_url(base.as_ref())
+        .parse(&input)
         .map_err(|e| format!("errored while parsing input: {}", e));
 
     match result {
@@ -340,38 +390,34 @@ fn run_setter_test(
         expected,
     }: SetterTest,
 ) -> Result<(), String> {
-    let mut url = panic::catch_unwind(|| Url::parse(&href))
-        .map_err(|_| "panicked while parsing href".to_string())?
-        .map_err(|e| format!("errored while parsing href: {}", e))?;
-
-    let url = panic::catch_unwind(move || {
-        match kind {
-            "protocol" => {
-                url::quirks::set_protocol(&mut url, &new_value).ok();
-            }
-            "username" => {
-                url::quirks::set_username(&mut url, &new_value).ok();
-            }
-            "password" => {
-                url::quirks::set_password(&mut url, &new_value).ok();
-            }
-            "host" => {
-                url::quirks::set_host(&mut url, &new_value).ok();
-            }
-            "hostname" => {
-                url::quirks::set_hostname(&mut url, &new_value).ok();
-            }
-            "port" => {
-                url::quirks::set_port(&mut url, &new_value).ok();
-            }
-            "pathname" => url::quirks::set_pathname(&mut url, &new_value),
-            "search" => url::quirks::set_search(&mut url, &new_value),
-            "hash" => url::quirks::set_hash(&mut url, &new_value),
-            _ => panic!("unknown setter kind: {:?}", kind),
-        };
-        url
-    })
-    .map_err(|_| "panicked while setting value".to_string())?;
+    let mut url = Url::parse(&href).map_err(|e| format!("errored while parsing href: {}", e))?;
+
+    match kind {
+        "protocol" => {
+            url::quirks::set_protocol(&mut url, &new_value).ok();
+        }
+        "username" => {
+            url::quirks::set_username(&mut url, &new_value).ok();
+        }
+        "password" => {
+            url::quirks::set_password(&mut url, &new_value).ok();
+        }
+        "host" => {
+            url::quirks::set_host(&mut url, &new_value).ok();
+        }
+        "hostname" => {
+            url::quirks::set_hostname(&mut url, &new_value).ok();
+        }
+        "port" => {
+            url::quirks::set_port(&mut url, &new_value).ok();
+        }
+        "pathname" => url::quirks::set_pathname(&mut url, &new_value),
+        "search" => url::quirks::set_search(&mut url, &new_value),
+        "hash" => url::quirks::set_hash(&mut url, &new_value),
+        _ => {
+            return Err(format!("unknown setter kind: {:?}", kind));
+        }
+    }
 
     if let Some(expected_href) = expected.href {
         let href = url::quirks::href(&url);