pub mod test_types; #[cfg(test)] mod test_round_trip { use serde::{de::DeserializeOwned, Serialize}; use super::test_types::*; use std::{ fmt::Debug, fs, io::Write, path::Path, process::{Command, Stdio}, }; #[cfg(target_os = "windows")] static TS_NODE_BIN: &str = "./node_modules/.bin/ts-node.cmd"; #[cfg(not(target_os = "windows"))] static TS_NODE_BIN: &str = "./node_modules/.bin/ts-node"; fn get_test_code(api_path: &Path, test_code: &str) -> String { format!( " import * as api from '{}'; const assert = require('assert'); const getStdin = require('get-stdin'); process.on('unhandledRejection', (error: Error) => {{ console.error(error); process.exit(1); }}); function test(buffer: Buffer): api.Sink {{ {} }} (async function main() {{ let inBuf = await getStdin.buffer(); let outBuf = test(inBuf).getUint8Array(); process.stdout.write(outBuf); }})(); ", api_path .to_string_lossy() .replace("\\", "\\\\") .replace(".ts", ""), test_code ) } fn generate_and_run(test_type: T, test_code: &str) where T: PartialEq + Debug + Serialize + DeserializeOwned, { let dir = tempfile::tempdir_in("./tests").unwrap(); let gen_path = dir.path().join("generated.ts"); let test_path = dir.path().join("test.ts"); bincode_typescript::from_file("./tests/test_types.rs", &gen_path, true).unwrap(); let code = get_test_code(&gen_path, test_code); fs::write(&test_path, code).unwrap(); let mut child = Command::new(TS_NODE_BIN) .args(&[test_path]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() .expect("failed to spawn process"); let child_stdin = child.stdin.as_mut().expect("failed to get stdin"); let encoded: Vec = bincode::serialize(&test_type).unwrap(); child_stdin.write_all(&encoded).unwrap(); let output = child.wait_with_output().unwrap(); assert!(output.status.success()); let returned_type: T = bincode::deserialize(&output.stdout).unwrap(); assert_eq!(test_type, returned_type); } #[test] fn unit_enum() { generate_and_run( UnitEnum::Three, " let val = api.readUnitEnum(buffer); let expected = api.UnitEnum.Three; assert.deepStrictEqual(val, expected); return api.writeUnitEnum(api.UnitEnum.Three); ", ); } #[test] fn unit_enum_valued() { generate_and_run( UnitEnumNumbered::Eight, " let val = api.readUnitEnumNumbered(buffer); let expected = api.UnitEnumNumbered.Eight; assert.deepStrictEqual(val, expected); assert.deepStrictEqual(val, 8); return api.writeUnitEnumNumbered(expected); ", ); } #[test] fn tuple_struct() { generate_and_run( TupleStruct(-145, vec![9987, 456]), " let val = api.readTupleStruct(buffer); let expected: api.TupleStruct = [-145, new Uint32Array([9987, 456])]; assert.deepStrictEqual(val, expected); return api.writeTupleStruct(expected); ", ); } #[test] fn named_struct_with_tuple() { generate_and_run( NamedStruct { zero: Some(28), one: 1.23, two: (128, UnitEnum::Three), three: "something".to_string(), }, " let val = api.readNamedStruct(buffer); let expected = { zero: 28, one: 1.23, two: [128, api.UnitEnum.Three] as [number, api.UnitEnum], three: 'something' }; assert.deepStrictEqual(val, expected); return api.writeNamedStruct(expected); ", ); } #[test] fn named_enum_variant() { generate_and_run( SomeEvent::Named { length: 34567, interval: 0.0001, }, " let val = api.readSomeEvent(buffer); let expected = api.SomeEvent.Named({ length: BigInt(34567), interval: 0.0001 }); assert.deepStrictEqual(val, expected); return api.writeSomeEvent(expected); ", ); } #[test] fn unnamed_enum_many_numbers() { generate_and_run( SomeEvent::UnnamedMultiple( 1, -2, 3, -4, 5, -6, 1152921504606846976, -8152921504606846976, 9, -10, 11, -12, false, ), " let val = api.readSomeEvent(buffer); let expected = api.SomeEvent.UnnamedMultiple( 1, -2, 3, -4, 5, -6, BigInt(1152921504606846976), BigInt(-8152921504606846976), BigInt(9), BigInt(-10), BigInt(11), BigInt(-12), false ); assert.deepStrictEqual(val, expected); return api.writeSomeEvent(expected); ", ); } #[test] fn named_struct_in_enum() { generate_and_run( SomeEvent::NamedStruct { inner: NamedStruct { zero: None, one: 1.23, two: (128, UnitEnum::Three), three: "something".to_string(), }, }, " let val = api.readSomeEvent(buffer); let expected = api.SomeEvent.NamedStruct({ inner: { zero: undefined, one: 1.23, two: [128, api.UnitEnum.Three] as [number, api.UnitEnum], three: 'something' } }); assert.deepStrictEqual(val, expected); return api.writeSomeEvent(expected); ", ); } #[test] fn unnamed_optional_vec() { generate_and_run( SomeEvent::UnnamedOptVec(Some(vec![128; 1000])), " let val = api.readSomeEvent(buffer); let arr = new Uint8Array(1000); arr.fill(128); let expected = api.SomeEvent.UnnamedOptVec(arr); assert.deepStrictEqual(val, expected); return api.writeSomeEvent(expected); ", ); } #[test] fn hashmap() { generate_and_run( SomeEvent::UnnamedHashMap(Some( vec![ ("One".to_string(), Some(UnitEnum::One)), ("Two".to_string(), None), ("Three".to_string(), Some(UnitEnum::Three)), ] .into_iter() .collect(), )), " let val = api.readSomeEvent(buffer); let expected = api.SomeEvent.UnnamedHashMap( new Map([ ['One', api.UnitEnum.One], ['Two', undefined], ['Three', api.UnitEnum.Three], ]) ); assert.deepStrictEqual(val, expected); return api.writeSomeEvent(expected); ", ); } }