diff --git a/Cargo.lock b/Cargo.lock index d3669c1..5125ace 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1376,6 +1376,7 @@ dependencies = [ "futures", "futures-channel", "gloo-timers", + "gloo-utils", "instant", "js-sys", "keyring", @@ -1402,6 +1403,7 @@ dependencies = [ "urlencoding", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-bindgen-test", "web-sys", ] diff --git a/Cargo.toml b/Cargo.toml index 61fd05a..3d2d526 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ crypto-bigint = "0.5.5" tsify-next = { version = "0.5.4", features = ["js"] } instant = { version = "0.1.13", features = ["wasm-bindgen"] } gloo-timers = { version = "0.3.0", features = ["futures"] } +gloo-utils = { version = "0.2.0", features = ["serde"] } num-bigint = "0.4.6" num-traits = "0.2.19" chrono = "0.4.41" @@ -69,5 +70,8 @@ base64 = "0.22.1" # see. https://github.com/mozilla/cbindgen/issues/43 cbindgen = { git = "https://github.com/masnagam/cbindgen", branch = "fix-issue-43" } +[dev-dependencies] +wasm-bindgen-test = "0.3.33" + [patch.crates-io] crunchy = { git = "https://github.com/nmathewson/crunchy", branch = "cross-compilation-fix" } \ No newline at end of file diff --git a/src/wasm/utils.rs b/src/wasm/utils.rs index 8ed213b..0c752a6 100644 --- a/src/wasm/utils.rs +++ b/src/wasm/utils.rs @@ -1,18 +1,24 @@ use std::collections::HashMap; +use gloo_utils::format::JsValueSerdeExt; use num_bigint::BigUint; use num_traits::Num; +use serde_json::Value as JsonValue; use wasm_bindgen::JsValue; use super::types::{EnumValue, Ty}; use crate::wasm::types::FixedSizeArray; +fn json_value_to_js_value(json_value: &JsonValue) -> JsValue { + JsValue::from_serde(json_value).unwrap() +} + pub fn parse_ty_as_json_str(ty: &dojo_types::schema::Ty, key: bool) -> Ty { match ty { dojo_types::schema::Ty::Primitive(primitive) => Ty { r#type: "primitive".to_string(), type_name: ty.name(), - value: serde_wasm_bindgen::to_value(&primitive.to_json_value().unwrap()).unwrap(), + value: json_value_to_js_value(&primitive.to_json_value().unwrap()), key, }, dojo_types::schema::Ty::Struct(struct_ty) => Ty { @@ -131,3 +137,127 @@ pub fn pad_to_hex(input: &str) -> Result { Ok(padded_hex) } + +#[cfg(test)] +mod tests { + use dojo_types::primitive::Primitive; + use serde_json::json; + use wasm_bindgen_test::*; + + use super::*; + + #[wasm_bindgen_test] + fn test_json_value_to_js_value_primitives() { + // Test null + let json_val = json!(null); + let js_val = json_value_to_js_value(&json_val); + assert!(js_val.is_null()); + + // Test boolean + let json_val = json!(true); + let js_val = json_value_to_js_value(&json_val); + assert!(js_val.is_truthy()); + + let json_val = json!(false); + let js_val = json_value_to_js_value(&json_val); + assert!(!js_val.is_truthy()); + + // Test number + let json_val = json!(42); + let js_val = json_value_to_js_value(&json_val); + assert!(js_val.as_f64().is_some()); + assert_eq!(js_val.as_f64().unwrap() as i32, 42); + + // Test string + let json_val = json!("hello world"); + let js_val = json_value_to_js_value(&json_val); + assert!(js_val.is_string()); + assert_eq!(js_val.as_string().unwrap(), "hello world"); + + // Test hex string (like what primitives produce) + let json_val = json!("0x000000000000000000000000000000000000000000000000000000000000002a"); + let js_val = json_value_to_js_value(&json_val); + assert!(js_val.is_string()); + assert_eq!( + js_val.as_string().unwrap(), + "0x000000000000000000000000000000000000000000000000000000000000002a" + ); + } + + #[wasm_bindgen_test] + fn test_primitive_to_js_value_conversions() { + // Test small integers + let primitive = Primitive::I8(Some(42)); + let json_val = primitive.to_json_value().unwrap(); + let js_val = json_value_to_js_value(&json_val); + assert!(js_val.as_f64().is_some()); + assert_eq!(js_val.as_f64().unwrap() as i8, 42); + + let primitive = Primitive::U32(Some(1234567)); + let json_val = primitive.to_json_value().unwrap(); + let js_val = json_value_to_js_value(&json_val); + assert!(js_val.as_f64().is_some()); + assert_eq!(js_val.as_f64().unwrap() as u32, 1234567); + + // Test boolean + let primitive = Primitive::Bool(Some(true)); + let json_val = primitive.to_json_value().unwrap(); + let js_val = json_value_to_js_value(&json_val); + assert!(js_val.is_truthy()); + + // Test large integers (should be strings) + let primitive = Primitive::U64(Some(18446744073709551615u64)); + let json_val = primitive.to_json_value().unwrap(); + let js_val = json_value_to_js_value(&json_val); + assert!(js_val.is_string()); + assert_eq!(js_val.as_string().unwrap(), "18446744073709551615"); + + // Test U256 (should be hex string) + use crypto_bigint::U256; + let primitive = Primitive::U256(Some(U256::from(42u32))); + let json_val = primitive.to_json_value().unwrap(); + let js_val = json_value_to_js_value(&json_val); + assert!(js_val.is_string()); + assert!(js_val.as_string().unwrap().starts_with("0x")); + + // Test ContractAddress (should be hex string) + let primitive = + Primitive::ContractAddress(Some(starknet_types_core::felt::Felt::from(42u32))); + let json_val = primitive.to_json_value().unwrap(); + let js_val = json_value_to_js_value(&json_val); + assert!(js_val.is_string()); + assert!(js_val.as_string().unwrap().starts_with("0x")); + } + + #[wasm_bindgen_test] + fn test_json_array_conversion() { + let json_val = json!([1, 2, 3, "test", true]); + let js_val = json_value_to_js_value(&json_val); + + // Check if it's an array + assert!(js_val.is_object()); + + // Convert to js_sys::Array to test further + let js_array = js_sys::Array::from(&js_val); + assert_eq!(js_array.length(), 5); + } + + #[wasm_bindgen_test] + fn test_json_object_conversion() { + let json_val = json!({ + "name": "test", + "value": 42, + "active": true + }); + let js_val = json_value_to_js_value(&json_val); + + // Check if it's an object + assert!(js_val.is_object()); + + // Test that we can access properties + let js_obj = js_sys::Object::from(js_val); + let name_val = js_sys::Reflect::get(&js_obj, &JsValue::from("name")).unwrap(); + assert!(name_val.is_string()); + assert_eq!(name_val.as_string().unwrap(), "test"); + } +}