diff --git a/.travis.yml b/.travis.yml index 73cd33bb0..6f19388ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -114,8 +114,8 @@ matrix: env: JOB=check-nightly-cli script: cargo check --manifest-path crates/cli/Cargo.toml - # Build the guide. - - rust: stable + # Build documentation for the gh-pages branch + - rust: nightly env: JOB=guide-build-and-deploy cache: - cargo @@ -125,6 +125,9 @@ matrix: - cargo install-update -a script: - (cd guide && mdbook build) + - cargo doc -p wasm-bindgen --no-deps + - cargo doc -p web-sys --no-deps + - mv target/doc guide/book/api deploy: provider: pages skip-cleanup: true diff --git a/crates/backend/src/util.rs b/crates/backend/src/util.rs index 8773c4abf..9bdb96a37 100644 --- a/crates/backend/src/util.rs +++ b/crates/backend/src/util.rs @@ -35,6 +35,23 @@ pub fn raw_ident(name: &str) -> Ident { /// Create a path type from the given segments. For example an iterator yielding /// the idents `[foo, bar, baz]` will result in the path type `foo::bar::baz`. pub fn simple_path_ty(segments: I) -> syn::Type +where + I: IntoIterator, +{ + path_ty(false, segments) +} + +/// Create a global path type from the given segments. For example an iterator +/// yielding the idents `[foo, bar, baz]` will result in the path type +/// `::foo::bar::baz`. +pub fn leading_colon_path_ty(segments: I) -> syn::Type +where + I: IntoIterator, +{ + path_ty(true, segments) +} + +fn path_ty(leading_colon: bool, segments: I) -> syn::Type where I: IntoIterator, { @@ -49,7 +66,11 @@ where syn::TypePath { qself: None, path: syn::Path { - leading_colon: None, + leading_colon: if leading_colon { + Some(Default::default()) + } else { + None + }, segments: syn::punctuated::Punctuated::from_iter(segments), }, }.into() diff --git a/crates/web-sys/tests/all/event.rs b/crates/web-sys/tests/all/event.rs index 7025fdf56..90541c2c3 100644 --- a/crates/web-sys/tests/all/event.rs +++ b/crates/web-sys/tests/all/event.rs @@ -1,10 +1,8 @@ -use super::project; +use super::websys_project; #[test] fn event() { - project() - .add_local_dependency("web-sys", env!("CARGO_MANIFEST_DIR")) - .headless(true) + websys_project() .file( "src/lib.rs", r#" diff --git a/crates/web-sys/tests/all/main.rs b/crates/web-sys/tests/all/main.rs index 3e8e39f84..e0181c246 100644 --- a/crates/web-sys/tests/all/main.rs +++ b/crates/web-sys/tests/all/main.rs @@ -1,5 +1,12 @@ extern crate wasm_bindgen_test_project_builder as project_builder; -use project_builder::project; +use project_builder::{project, Project}; mod event; mod response; + +fn websys_project() -> Project { + project() + .add_local_dependency("web-sys", env!("CARGO_MANIFEST_DIR")) + .headless(true) + .clone() +} diff --git a/crates/web-sys/tests/all/response.rs b/crates/web-sys/tests/all/response.rs index 81fdf4cb7..f2c779576 100644 --- a/crates/web-sys/tests/all/response.rs +++ b/crates/web-sys/tests/all/response.rs @@ -1,10 +1,8 @@ -use super::project; +use super::websys_project; #[test] fn response() { - project() - .add_local_dependency("web-sys", env!("CARGO_MANIFEST_DIR")) - .headless(true) + websys_project() .file( "src/lib.rs", r#" diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index 7fa546a44..e54e08bb9 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -78,7 +78,7 @@ fn compile_ast(mut ast: backend::ast::Program) -> String { let mut defined = BTreeSet::from_iter( vec![ "str", "char", "bool", "JsValue", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", - "usize", "isize", "f32", "f64", + "usize", "isize", "f32", "f64", "Result", ].into_iter() .map(|id| proc_macro2::Ident::new(id, proc_macro2::Span::call_site())), ); @@ -211,11 +211,29 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte ) -> Result<()> { let mut add_constructor = |arguments: &[webidl::ast::Argument], class: &str| { let self_ty = ident_ty(rust_ident(&interface.name)); + let kind = backend::ast::ImportFunctionKind::Method { class: class.to_string(), ty: self_ty.clone(), kind: backend::ast::MethodKind::Constructor, }; + + let structural = false; + + // Constructors aren't annotated with `[Throws]` extended attributes + // (how could they be, since they themselves are extended + // attributes?) so we must conservatively assume that they can + // always throw. + // + // From https://heycam.github.io/webidl/#Constructor (emphasis + // mine): + // + // > The prose definition of a constructor must either return an IDL + // > value of a type corresponding to the interface the + // > `[Constructor]` extended attribute appears on, **or throw an + // > exception**. + let throws = true; + create_function( "new", arguments @@ -223,7 +241,8 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte .map(|arg| (&*arg.name, &*arg.type_, arg.variadic)), Some(self_ty), kind, - false, + structural, + throws, ).map(|function| { program.imports.push(backend::ast::Import { module: None, @@ -325,14 +344,27 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute { } let is_structural = util::is_structural(&self.extended_attributes); + let throws = util::throws(&self.extended_attributes); - create_getter(&self.name, &self.type_, self_name, false, is_structural) - .map(wrap_import_function) + create_getter( + &self.name, + &self.type_, + self_name, + false, + is_structural, + throws, + ).map(wrap_import_function) .map(|import| program.imports.push(import)); if !self.read_only { - create_setter(&self.name, &self.type_, self_name, false, is_structural) - .map(wrap_import_function) + create_setter( + &self.name, + &self.type_, + self_name, + false, + is_structural, + throws, + ).map(wrap_import_function) .map(|import| program.imports.push(import)); } @@ -347,14 +379,27 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute { } let is_structural = util::is_structural(&self.extended_attributes); + let throws = util::throws(&self.extended_attributes); - create_getter(&self.name, &self.type_, self_name, true, is_structural) - .map(wrap_import_function) + create_getter( + &self.name, + &self.type_, + self_name, + true, + is_structural, + throws, + ).map(wrap_import_function) .map(|import| program.imports.push(import)); if !self.read_only { - create_setter(&self.name, &self.type_, self_name, true, is_structural) - .map(wrap_import_function) + create_setter( + &self.name, + &self.type_, + self_name, + true, + is_structural, + throws, + ).map(wrap_import_function) .map(|import| program.imports.push(import)); } @@ -368,12 +413,15 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation { return Ok(()); } + let throws = util::throws(&self.extended_attributes); + create_basic_method( &self.arguments, self.name.as_ref(), &self.return_type, self_name, false, + throws, ).map(wrap_import_function) .map(|import| program.imports.push(import)); @@ -387,12 +435,15 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::StaticOperation { return Ok(()); } + let throws = util::throws(&self.extended_attributes); + create_basic_method( &self.arguments, self.name.as_ref(), &self.return_type, self_name, true, + throws, ).map(wrap_import_function) .map(|import| program.imports.push(import)); diff --git a/crates/webidl/src/util.rs b/crates/webidl/src/util.rs index 480aba66c..b8edae82e 100644 --- a/crates/webidl/src/util.rs +++ b/crates/webidl/src/util.rs @@ -1,7 +1,7 @@ -use std::iter; +use std::iter::{self, FromIterator}; use backend; -use backend::util::{ident_ty, raw_ident, rust_ident, simple_path_ty}; +use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident, simple_path_ty}; use heck::SnakeCase; use proc_macro2::Ident; use syn; @@ -146,12 +146,40 @@ where Some(res) } +fn unit_ty() -> syn::Type { + syn::Type::Tuple(syn::TypeTuple { + paren_token: Default::default(), + elems: syn::punctuated::Punctuated::new(), + }) +} + +fn result_ty(t: syn::Type) -> syn::Type { + let js_value = leading_colon_path_ty(vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]); + + let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + colon2_token: None, + lt_token: Default::default(), + args: FromIterator::from_iter(vec![ + syn::GenericArgument::Type(t), + syn::GenericArgument::Type(js_value), + ]), + gt_token: Default::default(), + }); + + let ident = raw_ident("Result"); + let seg = syn::PathSegment { ident, arguments }; + let path: syn::Path = seg.into(); + let ty = syn::TypePath { qself: None, path }; + ty.into() +} + pub fn create_function<'a, I>( name: &str, arguments: I, - ret: Option, + mut ret: Option, kind: backend::ast::ImportFunctionKind, structural: bool, + catch: bool, ) -> Option where I: Iterator, @@ -163,6 +191,10 @@ where let js_ret = ret.clone(); + if catch { + ret = Some(ret.map_or_else(|| result_ty(unit_ty()), |ret| result_ty(ret))) + } + let shim = { let ns = match kind { backend::ast::ImportFunctionKind::Normal => "", @@ -184,7 +216,7 @@ where }, rust_name, js_ret, - catch: false, + catch, structural, kind, shim, @@ -197,6 +229,7 @@ pub fn create_basic_method( return_type: &webidl::ast::ReturnType, self_name: &str, is_static: bool, + catch: bool, ) -> Option { let name = match name { None => { @@ -235,6 +268,7 @@ pub fn create_basic_method( ret, kind, false, + catch, ) } @@ -244,6 +278,7 @@ pub fn create_getter( self_name: &str, is_static: bool, is_structural: bool, + catch: bool, ) -> Option { let ret = match webidl_ty_to_syn_ty(ty, TypePosition::Return) { None => { @@ -262,7 +297,7 @@ pub fn create_getter( }), }; - create_function(name, iter::empty(), ret, kind, is_structural) + create_function(name, iter::empty(), ret, kind, is_structural, catch) } pub fn create_setter( @@ -271,6 +306,7 @@ pub fn create_setter( self_name: &str, is_static: bool, is_structural: bool, + catch: bool, ) -> Option { let kind = backend::ast::ImportFunctionKind::Method { class: self_name.to_string(), @@ -287,6 +323,7 @@ pub fn create_setter( None, kind, is_structural, + catch, ) } @@ -315,3 +352,13 @@ pub fn is_structural(attrs: &[Box]) -> bool { } }) } + +pub fn throws(attrs: &[Box]) -> bool { + attrs.iter().any(|attr| { + if let ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(ref name)) = **attr { + name == "Throws" + } else { + false + } + }) +} diff --git a/crates/webidl/tests/all/main.rs b/crates/webidl/tests/all/main.rs index fd6a36948..13a6f7890 100644 --- a/crates/webidl/tests/all/main.rs +++ b/crates/webidl/tests/all/main.rs @@ -3,3 +3,4 @@ use project_builder::project; mod simple; mod enums; +mod throws; diff --git a/crates/webidl/tests/all/simple.rs b/crates/webidl/tests/all/simple.rs index 726375336..ad177a086 100644 --- a/crates/webidl/tests/all/simple.rs +++ b/crates/webidl/tests/all/simple.rs @@ -41,17 +41,17 @@ fn method() { #[wasm_bindgen] pub fn test() { - let pi = Foo::new(3.14159); - let e = Foo::new(2.71828); + let pi = Foo::new(3.14159).unwrap(); + let e = Foo::new(2.71828).unwrap(); // TODO: figure out why the following doesn't fail - // assert!(!pi.my_cmp(Foo::new(3.14159))); - let tmp = pi.my_cmp(Foo::new(3.14159)); + // assert!(!pi.my_cmp(Foo::new(3.14159).unwrap())); + let tmp = pi.my_cmp(Foo::new(3.14159).unwrap()); assert!(tmp); - let tmp =!pi.my_cmp(Foo::new(2.71828)); + let tmp =!pi.my_cmp(Foo::new(2.71828).unwrap()); assert!(tmp); - let tmp = !e.my_cmp(Foo::new(3.14159)); + let tmp = !e.my_cmp(Foo::new(3.14159).unwrap()); assert!(tmp); - let tmp = e.my_cmp(Foo::new(2.71828)); + let tmp = e.my_cmp(Foo::new(2.71828).unwrap()); assert!(tmp); } "#, @@ -105,7 +105,7 @@ fn property() { #[wasm_bindgen] pub fn test() { - let x = Foo::new(3.14159); + let x = Foo::new(3.14159).unwrap(); assert_eq!(x.value(), 3.14159); assert_ne!(x.value(), 2.71828); x.set_value(2.71828); @@ -167,7 +167,7 @@ fn named_constructor() { #[wasm_bindgen] pub fn test() { - let x = Foo::new(3.14159); + let x = Foo::new(3.14159).unwrap(); assert_eq!(x.value(), 3.14159); assert_ne!(x.value(), 0.); } @@ -317,7 +317,7 @@ fn one_method_using_an_undefined_import_doesnt_break_all_other_methods() { #[wasm_bindgen] pub fn test() { - let f = foo::Foo::new(); + let f = foo::Foo::new().unwrap(); assert!(f.ok_method()); } "#, @@ -362,7 +362,7 @@ fn unforgeable_is_structural() { #[wasm_bindgen] pub fn test() { - let f = foo::Foo::new(); + let f = foo::Foo::new().unwrap(); assert_eq!(f.uno(), 1); assert_eq!(f.dos(), 2); } diff --git a/crates/webidl/tests/all/throws.rs b/crates/webidl/tests/all/throws.rs new file mode 100644 index 000000000..e930cc3ff --- /dev/null +++ b/crates/webidl/tests/all/throws.rs @@ -0,0 +1,100 @@ +use super::project; + +#[test] +fn throws() { + project() + .file( + "thang.webidl", + r#" + [Constructor(long value)] + interface Thang { + [Throws] + attribute long ok_attr; + [Throws] + attribute long err_attr; + + [Throws] + long ok_method(); + [Throws] + long err_method(); + + [Throws] + static long ok_static_method(); + [Throws] + static long err_static_method(); + + [Throws] + static attribute long ok_static_attr; + [Throws] + static attribute long err_static_attr; + }; + "#, + ) + .file( + "thang.js", + r#" + export class Thang { + constructor(value) { + if (value % 2 == 0) { + throw new Error("only odd allowed"); + } + this.value = value; + } + + get ok_attr() { return this.value; } + set ok_attr(x) { } + + get err_attr() { throw new Error("bad"); } + set err_attr(x) { throw new Error("bad"); } + + ok_method() { return this.value + 1; } + err_method() { throw new Error("bad"); } + + static ok_static_method() { return 1; } + static err_static_method() { throw new Error("bad"); } + + static get ok_static_attr() { return 1; } + static set ok_static_attr(x) { } + + static get err_static_attr() { throw new Error("bad"); } + static set err_static_attr(x) { throw new Error("bad"); } + } + "#, + ) + .file( + "src/lib.rs", + r#" + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + + pub mod thang; + use thang::Thang; + + #[wasm_bindgen] + pub fn test() { + assert!(Thang::new(0).is_err()); + let thang = Thang::new(1).unwrap(); + + assert!(thang.ok_attr().is_ok()); + assert!(thang.set_ok_attr(0).is_ok()); + + assert!(thang.err_attr().is_err()); + assert!(thang.set_err_attr(0).is_err()); + + assert!(thang.ok_method().is_ok()); + assert!(thang.err_method().is_err()); + + assert!(Thang::ok_static_method().is_ok()); + assert!(Thang::err_static_method().is_err()); + + assert!(Thang::ok_static_attr().is_ok()); + assert!(Thang::set_ok_static_attr(0).is_ok()); + + assert!(Thang::err_static_attr().is_err()); + assert!(Thang::set_err_static_attr(0).is_err()); + } + "#, + ) + .test(); +} diff --git a/src/js.rs b/src/js.rs index 24789b66b..208ffe875 100644 --- a/src/js.rs +++ b/src/js.rs @@ -1082,6 +1082,52 @@ extern "C" { #[wasm_bindgen(method, js_name = setTime)] pub fn set_time(this: &Date, time: f64) -> f64; + /// The setUTCDate() method sets the day of the month for a specified date + /// according to universal time. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCDate + #[wasm_bindgen(method, js_name = setUTCDate)] + pub fn set_utc_date(this: &Date, day: u32) -> f64; + + /// The setUTCFullYear() method sets the full year for a specified date according to universal time. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCFullYear + #[wasm_bindgen(method, js_name = setUTCFullYear)] + pub fn set_utc_full_year(this: &Date, year: u32) -> f64; + + /// The setUTCHours() method sets the hour for a specified date according to universal time, + /// and returns the number of milliseconds since January 1, 1970 00:00:00 UTC until the time + /// represented by the updated Date instance. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCHours + #[wasm_bindgen(method, js_name = setUTCHours)] + pub fn set_utc_hours(this: &Date, hours: u32) -> f64; + + /// The setUTCMilliseconds() method sets the milliseconds for a specified date + /// according to universal time. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCMilliseconds + #[wasm_bindgen(method, js_name = setUTCMilliseconds)] + pub fn set_utc_milliseconds(this: &Date, milliseconds: u32) -> f64; + + /// The setUTCMinutes() method sets the minutes for a specified date according to universal time. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCMinutes + #[wasm_bindgen(method, js_name = setUTCMinutes)] + pub fn set_utc_minutes(this: &Date, minutes: u32) -> f64; + + /// The setUTCMonth() method sets the month for a specified date according to universal time. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCMonth + #[wasm_bindgen(method, js_name = setUTCMonth)] + pub fn set_utc_month(this: &Date, month: u32) -> f64; + + /// The setUTCSeconds() method sets the seconds for a specified date according to universal time. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCSeconds + #[wasm_bindgen(method, js_name = setUTCSeconds)] + pub fn set_utc_seconds(this: &Date, seconds: u32) -> f64; + /// The toDateString() method returns the date portion of a Date object /// in human readable form in American English. /// diff --git a/tests/all/js_globals/Date.rs b/tests/all/js_globals/Date.rs index 651ea1fdd..8e2bbd782 100755 --- a/tests/all/js_globals/Date.rs +++ b/tests/all/js_globals/Date.rs @@ -1035,6 +1035,279 @@ fn set_time() { .test() } +#[test] +fn set_utc_date() { + project() + .file( + "src/lib.rs", + r#" + #![feature(proc_macro, wasm_custom_section)] + + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + use wasm_bindgen::js::Date; + + #[wasm_bindgen] + pub fn set_utc_date(this: &Date, day: u32) -> f64 { + this.set_utc_date(day) + } + "#, + ) + .file( + "test.js", + r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + let event1 = new Date('August 19, 1975 23:15:30 GMT-3:00'); + let event2 = new Date('August 19, 1975 02:15:30 GMT'); + + let eventMsFromUnixEpoch = wasm.set_utc_date(event1, 19); + + assert.equal(eventMsFromUnixEpoch, event2.getTime()); + assert.equal(event1.getTime(), event2.valueOf()); + assert.equal(event1.getUTCDate(), 19); + } + "#, + ) + .test() +} + +#[test] +fn set_utc_full_year() { + project() + .file( + "src/lib.rs", + r#" + #![feature(proc_macro, wasm_custom_section)] + + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + use wasm_bindgen::js::Date; + + #[wasm_bindgen] + pub fn set_utc_full_year(this: &Date, year: u32) -> f64 { + this.set_utc_full_year(year) + } + "#, + ) + .file( + "test.js", + r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + let event1 = new Date('December 31, 1975 23:15:30 GMT-3:00'); + let event2 = new Date('January 01, 1975 02:15:30 GMT'); + + let eventMsFromUnixEpoch = wasm.set_utc_full_year(event1, 1975); + + assert.equal(eventMsFromUnixEpoch, event2.getTime()); + assert.equal(event1.getTime(), event2.valueOf()); + assert.equal(event1.getUTCFullYear(), 1975); + } + "#, + ) + .test() +} + +#[test] +fn set_utc_hours() { + project() + .file( + "src/lib.rs", + r#" + #![feature(proc_macro, wasm_custom_section)] + + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + use wasm_bindgen::js::Date; + + #[wasm_bindgen] + pub fn set_utc_hours(this: &Date, hours: u32) -> f64 { + this.set_utc_hours(hours) + } + "#, + ) + .file( + "test.js", + r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + let event1 = new Date('August 19, 1975 23:15:30 GMT-3:00'); + let event2 = new Date('August 20, 1975 23:15:30 GMT'); + + let eventMsFromUnixEpoch = wasm.set_utc_hours(event1, 23); + + assert.equal(eventMsFromUnixEpoch, event2.getTime()); + assert.equal(event1.getTime(), event2.valueOf()); + assert.equal(event1.getUTCHours(), 23); + } + "#, + ) + .test() +} + +#[test] +fn set_utc_milliseconds() { + project() + .file( + "src/lib.rs", + r#" + #![feature(proc_macro, wasm_custom_section)] + + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + use wasm_bindgen::js::Date; + + #[wasm_bindgen] + pub fn set_utc_milliseconds(this: &Date, milliseconds: u32) -> f64 { + this.set_utc_milliseconds(milliseconds) + } + "#, + ) + .file( + "test.js", + r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + let event1 = new Date('August 19, 1975 23:15:30 GMT-3:00'); + let event2 = new Date('August 20, 1975 02:15:30.420Z GMT'); + + let eventMsFromUnixEpoch = wasm.set_utc_milliseconds(event1, 420); + + assert.equal(eventMsFromUnixEpoch, event2.getTime()); + assert.equal(event1.getTime(), event2.valueOf()); + assert.equal(event1.getUTCMilliseconds(), 420); + } + "#, + ) + .test() +} + +#[test] +fn set_utc_minutes() { + project() + .file( + "src/lib.rs", + r#" + #![feature(proc_macro, wasm_custom_section)] + + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + use wasm_bindgen::js::Date; + + #[wasm_bindgen] + pub fn set_utc_minutes(this: &Date, minutes: u32) -> f64 { + this.set_utc_minutes(minutes) + } + "#, + ) + .file( + "test.js", + r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + let event1 = new Date('December 31, 1975, 23:15:30 GMT-3:00'); + let event2 = new Date('January 01, 1976 02:25:30 GMT'); + + let eventMsFromUnixEpoch = wasm.set_utc_minutes(event1, 25); + + assert.equal(eventMsFromUnixEpoch, event2.getTime()); + assert.equal(event1.getTime(), event2.valueOf()); + assert.equal(event1.getUTCMinutes(), 25); + } + "#, + ) + .test() +} + +#[test] +fn set_utc_month() { + project() + .file( + "src/lib.rs", + r#" + #![feature(proc_macro, wasm_custom_section)] + + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + use wasm_bindgen::js::Date; + + #[wasm_bindgen] + pub fn set_utc_month(this: &Date, minutes: u32) -> f64 { + this.set_utc_month(minutes) + } + "#, + ) + .file( + "test.js", + r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + let event1 = new Date('December 31, 1975 23:15:30 GMT-3:00'); + let event2 = new Date('December 01, 1976 02:15:30 GMT'); + + let eventMsFromUnixEpoch = wasm.set_utc_month(event1, 11); + + assert.equal(eventMsFromUnixEpoch, event2.getTime()); + assert.equal(event1.getTime(), event2.valueOf()); + assert.equal(event1.getUTCMonth(), 11); + } + "#, + ) + .test() +} + +#[test] +fn set_utc_seconds() { + project() + .file( + "src/lib.rs", + r#" + #![feature(proc_macro, wasm_custom_section)] + + extern crate wasm_bindgen; + use wasm_bindgen::prelude::*; + use wasm_bindgen::js::Date; + + #[wasm_bindgen] + pub fn set_utc_seconds(this: &Date, seconds: u32) -> f64 { + this.set_utc_seconds(seconds) + } + "#, + ) + .file( + "test.js", + r#" + import * as assert from "assert"; + import * as wasm from "./out"; + + export function test() { + let event1 = new Date('December 31, 1975 23:15:30 GMT-3:00'); + let event2 = new Date('January 01, 1976 02:15:39 GMT'); + + let eventMsFromUnixEpoch = wasm.set_utc_seconds(event1, 39); + + assert.equal(eventMsFromUnixEpoch, event2.getTime()); + assert.equal(event1.getTime(), event2.valueOf()); + assert.equal(event1.getUTCSeconds(), 39); + } + "#, + ) + .test() +} + #[test] fn to_date_string() { project()