1 use super::{make_echo_component, make_echo_component_with_params, Param, Type}; 2 use anyhow::Result; 3 use component_test_util::FuncExt; 4 use wasmtime::component::{self, Component, Linker, Val}; 5 use wasmtime::Store; 6 7 #[test] 8 fn primitives() -> Result<()> { 9 let engine = super::engine(); 10 let mut store = Store::new(&engine, ()); 11 12 for (input, ty, param) in [ 13 (Val::Bool(true), "bool", Param(Type::U8, Some(0))), 14 (Val::S8(-42), "s8", Param(Type::S8, Some(0))), 15 (Val::U8(42), "u8", Param(Type::U8, Some(0))), 16 (Val::S16(-4242), "s16", Param(Type::S16, Some(0))), 17 (Val::U16(4242), "u16", Param(Type::U16, Some(0))), 18 (Val::S32(-314159265), "s32", Param(Type::I32, Some(0))), 19 (Val::U32(314159265), "u32", Param(Type::I32, Some(0))), 20 (Val::S64(-31415926535897), "s64", Param(Type::I64, Some(0))), 21 (Val::U64(31415926535897), "u64", Param(Type::I64, Some(0))), 22 ( 23 Val::Float32(3.14159265_f32.to_bits()), 24 "float32", 25 Param(Type::F32, Some(0)), 26 ), 27 ( 28 Val::Float64(3.14159265_f64.to_bits()), 29 "float64", 30 Param(Type::F64, Some(0)), 31 ), 32 (Val::Char(''), "char", Param(Type::I32, Some(0))), 33 ] { 34 let component = Component::new(&engine, make_echo_component_with_params(ty, &[param]))?; 35 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 36 let func = instance.get_func(&mut store, "echo").unwrap(); 37 let output = func.call_and_post_return(&mut store, &[input.clone()])?; 38 39 assert_eq!(input, output); 40 } 41 42 // Sad path: type mismatch 43 44 let component = Component::new( 45 &engine, 46 make_echo_component_with_params("float64", &[Param(Type::F64, Some(0))]), 47 )?; 48 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 49 let func = instance.get_func(&mut store, "echo").unwrap(); 50 let err = func 51 .call_and_post_return(&mut store, &[Val::U64(42)]) 52 .unwrap_err(); 53 54 assert!(err.to_string().contains("type mismatch"), "{err}"); 55 56 // Sad path: arity mismatch (too many) 57 58 let err = func 59 .call_and_post_return( 60 &mut store, 61 &[ 62 Val::Float64(3.14159265_f64.to_bits()), 63 Val::Float64(3.14159265_f64.to_bits()), 64 ], 65 ) 66 .unwrap_err(); 67 68 assert!( 69 err.to_string().contains("expected 1 argument(s), got 2"), 70 "{err}" 71 ); 72 73 // Sad path: arity mismatch (too few) 74 75 let err = func.call_and_post_return(&mut store, &[]).unwrap_err(); 76 77 assert!( 78 err.to_string().contains("expected 1 argument(s), got 0"), 79 "{err}" 80 ); 81 82 Ok(()) 83 } 84 85 #[test] 86 fn strings() -> Result<()> { 87 let engine = super::engine(); 88 let mut store = Store::new(&engine, ()); 89 90 let component = Component::new(&engine, make_echo_component("string", 8))?; 91 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 92 let func = instance.get_func(&mut store, "echo").unwrap(); 93 let input = Val::String(Box::from("hello, component!")); 94 let output = func.call_and_post_return(&mut store, &[input.clone()])?; 95 96 assert_eq!(input, output); 97 98 Ok(()) 99 } 100 101 #[test] 102 fn lists() -> Result<()> { 103 let engine = super::engine(); 104 let mut store = Store::new(&engine, ()); 105 106 let component = Component::new(&engine, make_echo_component("(list u32)", 8))?; 107 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 108 let func = instance.get_func(&mut store, "echo").unwrap(); 109 let ty = &func.params(&store)[0]; 110 let input = ty.unwrap_list().new_val(Box::new([ 111 Val::U32(32343), 112 Val::U32(79023439), 113 Val::U32(2084037802), 114 ]))?; 115 let output = func.call_and_post_return(&mut store, &[input.clone()])?; 116 117 assert_eq!(input, output); 118 119 // Sad path: type mismatch 120 121 let err = ty 122 .unwrap_list() 123 .new_val(Box::new([ 124 Val::U32(32343), 125 Val::U32(79023439), 126 Val::Float32(3.14159265_f32.to_bits()), 127 ])) 128 .unwrap_err(); 129 130 assert!(err.to_string().contains("type mismatch"), "{err}"); 131 132 Ok(()) 133 } 134 135 #[test] 136 fn records() -> Result<()> { 137 let engine = super::engine(); 138 let mut store = Store::new(&engine, ()); 139 140 let component = Component::new( 141 &engine, 142 make_echo_component_with_params( 143 r#"(record (field "A" u32) (field "B" float64) (field "C" (record (field "D" bool) (field "E" u32))))"#, 144 &[ 145 Param(Type::I32, Some(0)), 146 Param(Type::F64, Some(8)), 147 Param(Type::U8, Some(16)), 148 Param(Type::I32, Some(20)), 149 ], 150 ), 151 )?; 152 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 153 let func = instance.get_func(&mut store, "echo").unwrap(); 154 let ty = &func.params(&store)[0]; 155 let inner_type = &ty.unwrap_record().fields().nth(2).unwrap().ty; 156 let input = ty.unwrap_record().new_val([ 157 ("A", Val::U32(32343)), 158 ("B", Val::Float64(3.14159265_f64.to_bits())), 159 ( 160 "C", 161 inner_type 162 .unwrap_record() 163 .new_val([("D", Val::Bool(false)), ("E", Val::U32(2084037802))])?, 164 ), 165 ])?; 166 let output = func.call_and_post_return(&mut store, &[input.clone()])?; 167 168 assert_eq!(input, output); 169 170 // Sad path: type mismatch 171 172 let err = ty 173 .unwrap_record() 174 .new_val([ 175 ("A", Val::S32(32343)), 176 ("B", Val::Float64(3.14159265_f64.to_bits())), 177 ( 178 "C", 179 inner_type 180 .unwrap_record() 181 .new_val([("D", Val::Bool(false)), ("E", Val::U32(2084037802))])?, 182 ), 183 ]) 184 .unwrap_err(); 185 186 assert!(err.to_string().contains("type mismatch"), "{err}"); 187 188 // Sad path: too many fields 189 190 let err = ty 191 .unwrap_record() 192 .new_val([ 193 ("A", Val::U32(32343)), 194 ("B", Val::Float64(3.14159265_f64.to_bits())), 195 ( 196 "C", 197 inner_type 198 .unwrap_record() 199 .new_val([("D", Val::Bool(false)), ("E", Val::U32(2084037802))])?, 200 ), 201 ("F", Val::Unit), 202 ]) 203 .unwrap_err(); 204 205 assert!( 206 err.to_string().contains("expected 3 value(s); got 4"), 207 "{err}" 208 ); 209 210 // Sad path: too few fields 211 212 let err = ty 213 .unwrap_record() 214 .new_val([ 215 ("A", Val::U32(32343)), 216 ("B", Val::Float64(3.14159265_f64.to_bits())), 217 ]) 218 .unwrap_err(); 219 220 assert!( 221 err.to_string().contains("expected 3 value(s); got 2"), 222 "{err}" 223 ); 224 225 Ok(()) 226 } 227 228 #[test] 229 fn variants() -> Result<()> { 230 let engine = super::engine(); 231 let mut store = Store::new(&engine, ()); 232 233 let component = Component::new( 234 &engine, 235 make_echo_component_with_params( 236 r#"(variant (case "A" u32) (case "B" float64) (case "C" (record (field "D" bool) (field "E" u32))))"#, 237 &[ 238 Param(Type::U8, Some(0)), 239 Param(Type::I64, Some(8)), 240 Param(Type::I32, None), 241 ], 242 ), 243 )?; 244 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 245 let func = instance.get_func(&mut store, "echo").unwrap(); 246 let ty = &func.params(&store)[0]; 247 let input = ty 248 .unwrap_variant() 249 .new_val("B", Val::Float64(3.14159265_f64.to_bits()))?; 250 let output = func.call_and_post_return(&mut store, &[input.clone()])?; 251 252 assert_eq!(input, output); 253 254 // Do it again, this time using case "C" 255 256 let component = Component::new( 257 &engine, 258 dbg!(make_echo_component_with_params( 259 r#"(variant (case "A" u32) (case "B" float64) (case "C" (record (field "D" bool) (field "E" u32))))"#, 260 &[ 261 Param(Type::U8, Some(0)), 262 Param(Type::I64, Some(8)), 263 Param(Type::I32, Some(12)), 264 ], 265 )), 266 )?; 267 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 268 let func = instance.get_func(&mut store, "echo").unwrap(); 269 let ty = &func.params(&store)[0]; 270 let c_type = &ty.unwrap_variant().cases().nth(2).unwrap().ty; 271 let input = ty.unwrap_variant().new_val( 272 "C", 273 c_type 274 .unwrap_record() 275 .new_val([("D", Val::Bool(true)), ("E", Val::U32(314159265))])?, 276 )?; 277 let output = func.call_and_post_return(&mut store, &[input.clone()])?; 278 279 assert_eq!(input, output); 280 281 // Sad path: type mismatch 282 283 let err = ty 284 .unwrap_variant() 285 .new_val("B", Val::U64(314159265)) 286 .unwrap_err(); 287 288 assert!(err.to_string().contains("type mismatch"), "{err}"); 289 290 // Sad path: unknown case 291 292 let err = ty 293 .unwrap_variant() 294 .new_val("D", Val::U64(314159265)) 295 .unwrap_err(); 296 297 assert!(err.to_string().contains("unknown variant case"), "{err}"); 298 299 // Make sure we lift variants which have cases of different sizes with the correct alignment 300 301 let component = Component::new( 302 &engine, 303 make_echo_component_with_params( 304 r#" 305 (record 306 (field "A" (variant 307 (case "A" u32) 308 (case "B" float64) 309 (case "C" (record (field "D" bool) (field "E" u32))))) 310 (field "B" u32))"#, 311 &[ 312 Param(Type::U8, Some(0)), 313 Param(Type::I64, Some(8)), 314 Param(Type::I32, None), 315 Param(Type::I32, Some(16)), 316 ], 317 ), 318 )?; 319 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 320 let func = instance.get_func(&mut store, "echo").unwrap(); 321 let ty = &func.params(&store)[0]; 322 let a_type = &ty.unwrap_record().fields().nth(0).unwrap().ty; 323 let input = ty.unwrap_record().new_val([ 324 ( 325 "A", 326 a_type.unwrap_variant().new_val("A", Val::U32(314159265))?, 327 ), 328 ("B", Val::U32(628318530)), 329 ])?; 330 let output = func.call_and_post_return(&mut store, &[input.clone()])?; 331 332 assert_eq!(input, output); 333 334 Ok(()) 335 } 336 337 #[test] 338 fn flags() -> Result<()> { 339 let engine = super::engine(); 340 let mut store = Store::new(&engine, ()); 341 342 let component = Component::new( 343 &engine, 344 make_echo_component_with_params( 345 r#"(flags "A" "B" "C" "D" "E")"#, 346 &[Param(Type::U8, Some(0))], 347 ), 348 )?; 349 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 350 let func = instance.get_func(&mut store, "echo").unwrap(); 351 let ty = &func.params(&store)[0]; 352 let input = ty.unwrap_flags().new_val(&["B", "D"])?; 353 let output = func.call_and_post_return(&mut store, &[input.clone()])?; 354 355 assert_eq!(input, output); 356 357 // Sad path: unknown flags 358 359 let err = ty.unwrap_flags().new_val(&["B", "D", "F"]).unwrap_err(); 360 361 assert!(err.to_string().contains("unknown flag"), "{err}"); 362 363 Ok(()) 364 } 365 366 #[test] 367 fn everything() -> Result<()> { 368 // This serves to test both nested types and storing parameters on the heap (i.e. exceeding `MAX_STACK_PARAMS`) 369 370 let engine = super::engine(); 371 let mut store = Store::new(&engine, ()); 372 373 let component = Component::new( 374 &engine, 375 make_echo_component_with_params( 376 r#" 377 (record 378 (field "A" u32) 379 (field "B" (enum "1" "2")) 380 (field "C" (record (field "D" bool) (field "E" u32))) 381 (field "F" (list (flags "G" "H" "I"))) 382 (field "J" (variant 383 (case "K" u32) 384 (case "L" float64) 385 (case "M" (record (field "N" bool) (field "O" u32))))) 386 (field "P" s8) 387 (field "Q" s16) 388 (field "R" s32) 389 (field "S" s64) 390 (field "T" float32) 391 (field "U" float64) 392 (field "V" string) 393 (field "W" char) 394 (field "X" unit) 395 (field "Y" (tuple u32 u32)) 396 (field "Z" (union u32 float64)) 397 (field "AA" (option u32)) 398 (field "BB" (expected string string)) 399 )"#, 400 &[ 401 Param(Type::I32, Some(0)), 402 Param(Type::U8, Some(4)), 403 Param(Type::U8, Some(5)), 404 Param(Type::I32, Some(8)), 405 Param(Type::I32, Some(12)), 406 Param(Type::I32, Some(16)), 407 Param(Type::U8, Some(20)), 408 Param(Type::I64, Some(28)), 409 Param(Type::I32, Some(32)), 410 Param(Type::S8, Some(36)), 411 Param(Type::S16, Some(38)), 412 Param(Type::I32, Some(40)), 413 Param(Type::I64, Some(48)), 414 Param(Type::F32, Some(56)), 415 Param(Type::F64, Some(64)), 416 Param(Type::I32, Some(72)), 417 Param(Type::I32, Some(76)), 418 Param(Type::I32, Some(80)), 419 Param(Type::I32, Some(84)), 420 Param(Type::I32, Some(88)), 421 Param(Type::I64, Some(96)), 422 Param(Type::U8, Some(104)), 423 Param(Type::I32, Some(108)), 424 Param(Type::U8, Some(112)), 425 Param(Type::I32, Some(116)), 426 Param(Type::I32, Some(120)), 427 ], 428 ), 429 )?; 430 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 431 let func = instance.get_func(&mut store, "echo").unwrap(); 432 let ty = &func.params(&store)[0]; 433 let types = ty 434 .unwrap_record() 435 .fields() 436 .map(|field| field.ty) 437 .collect::<Box<[component::Type]>>(); 438 let (b_type, c_type, f_type, j_type, y_type, z_type, aa_type, bb_type) = ( 439 &types[1], &types[2], &types[3], &types[4], &types[14], &types[15], &types[16], &types[17], 440 ); 441 let f_element_type = &f_type.unwrap_list().ty(); 442 let input = ty.unwrap_record().new_val([ 443 ("A", Val::U32(32343)), 444 ("B", b_type.unwrap_enum().new_val("2")?), 445 ( 446 "C", 447 c_type 448 .unwrap_record() 449 .new_val([("D", Val::Bool(false)), ("E", Val::U32(2084037802))])?, 450 ), 451 ( 452 "F", 453 f_type.unwrap_list().new_val(Box::new([f_element_type 454 .unwrap_flags() 455 .new_val(&["G", "I"])?]))?, 456 ), 457 ( 458 "J", 459 j_type 460 .unwrap_variant() 461 .new_val("L", Val::Float64(3.14159265_f64.to_bits()))?, 462 ), 463 ("P", Val::S8(42)), 464 ("Q", Val::S16(4242)), 465 ("R", Val::S32(42424242)), 466 ("S", Val::S64(424242424242424242)), 467 ("T", Val::Float32(3.14159265_f32.to_bits())), 468 ("U", Val::Float64(3.14159265_f64.to_bits())), 469 ("V", Val::String(Box::from("wow, nice types"))), 470 ("W", Val::Char('')), 471 ("X", Val::Unit), 472 ( 473 "Y", 474 y_type 475 .unwrap_tuple() 476 .new_val(Box::new([Val::U32(42), Val::U32(24)]))?, 477 ), 478 ( 479 "Z", 480 z_type 481 .unwrap_union() 482 .new_val(1, Val::Float64(3.14159265_f64.to_bits()))?, 483 ), 484 ( 485 "AA", 486 aa_type.unwrap_option().new_val(Some(Val::U32(314159265)))?, 487 ), 488 ( 489 "BB", 490 bb_type 491 .unwrap_expected() 492 .new_val(Ok(Val::String(Box::from("no problem"))))?, 493 ), 494 ])?; 495 let output = func.call_and_post_return(&mut store, &[input.clone()])?; 496 497 assert_eq!(input, output); 498 499 Ok(()) 500 } 501