2021-12-14 01:37:46 +09:00
|
|
|
import { exec } from 'child_process'
|
2021-10-25 01:00:31 +09:00
|
|
|
import { join } from 'path'
|
|
|
|
|
2021-09-23 02:29:09 +09:00
|
|
|
import test from 'ava'
|
2022-04-14 01:02:06 +09:00
|
|
|
import { spy } from 'sinon'
|
2021-09-23 02:29:09 +09:00
|
|
|
|
|
|
|
import {
|
2021-11-10 20:04:36 +09:00
|
|
|
DEFAULT_COST,
|
2021-09-23 02:29:09 +09:00
|
|
|
add,
|
|
|
|
fibonacci,
|
|
|
|
contains,
|
|
|
|
concatLatin1,
|
|
|
|
concatStr,
|
|
|
|
concatUtf16,
|
2022-02-04 17:29:17 +09:00
|
|
|
roundtripStr,
|
2021-09-23 02:29:09 +09:00
|
|
|
getNums,
|
|
|
|
getWords,
|
|
|
|
sumNums,
|
2021-12-19 00:16:09 +09:00
|
|
|
getMapping,
|
|
|
|
sumMapping,
|
2021-09-23 02:29:09 +09:00
|
|
|
getCwd,
|
|
|
|
Animal,
|
|
|
|
Kind,
|
2022-07-06 00:09:40 +09:00
|
|
|
NinjaTurtle,
|
2021-11-05 19:31:36 +09:00
|
|
|
ClassWithFactory,
|
2021-09-23 02:29:09 +09:00
|
|
|
CustomNumEnum,
|
2021-11-06 22:48:18 +09:00
|
|
|
Context,
|
2021-09-23 02:29:09 +09:00
|
|
|
enumToI32,
|
|
|
|
listObjKeys,
|
|
|
|
createObj,
|
|
|
|
mapOption,
|
2021-09-24 10:15:48 +09:00
|
|
|
readFile,
|
2021-09-24 15:45:27 +09:00
|
|
|
throwError,
|
2022-08-20 00:36:36 +09:00
|
|
|
panic,
|
2021-09-24 18:01:54 +09:00
|
|
|
readPackageJson,
|
2021-09-28 01:01:19 +09:00
|
|
|
getPackageJsonName,
|
2021-10-08 22:13:27 +09:00
|
|
|
getBuffer,
|
2022-04-23 17:43:36 +09:00
|
|
|
getEmptyBuffer,
|
2021-10-25 01:00:31 +09:00
|
|
|
readFileAsync,
|
2021-11-02 01:34:19 +09:00
|
|
|
eitherStringOrNumber,
|
|
|
|
returnEither,
|
|
|
|
either3,
|
|
|
|
either4,
|
2021-11-02 21:36:34 +09:00
|
|
|
withoutAbortController,
|
|
|
|
withAbortController,
|
2021-11-06 23:19:42 +09:00
|
|
|
asyncMultiTwo,
|
2021-11-11 01:33:51 +09:00
|
|
|
bigintAdd,
|
|
|
|
createBigInt,
|
|
|
|
createBigIntI64,
|
2022-02-04 17:03:32 +09:00
|
|
|
bigintGetU64AsString,
|
2021-11-12 18:22:57 +09:00
|
|
|
callThreadsafeFunction,
|
|
|
|
threadsafeFunctionThrowError,
|
2022-08-20 23:40:26 +09:00
|
|
|
threadsafeFunctionClosureCapture,
|
2023-01-11 19:54:45 +09:00
|
|
|
tsfnCallWithCallback,
|
|
|
|
tsfnAsyncCall,
|
2021-11-13 21:51:14 +09:00
|
|
|
asyncPlus100,
|
2021-11-15 19:56:06 +09:00
|
|
|
getGlobal,
|
|
|
|
getUndefined,
|
|
|
|
getNull,
|
2021-11-16 00:09:44 +09:00
|
|
|
setSymbolInObj,
|
|
|
|
createSymbol,
|
2021-11-21 15:49:04 +09:00
|
|
|
threadsafeFunctionFatalMode,
|
2021-11-21 17:11:15 +09:00
|
|
|
createExternal,
|
|
|
|
getExternal,
|
|
|
|
mutateExternal,
|
|
|
|
createExternalString,
|
2021-11-23 20:00:31 +09:00
|
|
|
xxh2,
|
|
|
|
xxh3,
|
|
|
|
xxh64Alias,
|
2021-11-26 18:26:14 +09:00
|
|
|
tsRename,
|
2021-11-30 19:43:34 +09:00
|
|
|
convertU32Array,
|
|
|
|
createExternalTypedArray,
|
|
|
|
mutateTypedArray,
|
2021-12-02 16:47:59 +09:00
|
|
|
receiveAllOptionalObject,
|
2021-12-02 17:25:20 +09:00
|
|
|
fnReceivedAliased,
|
|
|
|
ALIAS,
|
|
|
|
AliasedStruct,
|
2021-12-18 14:24:16 +09:00
|
|
|
appendBuffer,
|
2021-12-18 14:36:45 +09:00
|
|
|
returnNull,
|
|
|
|
returnUndefined,
|
2021-12-23 15:07:35 +09:00
|
|
|
Dog,
|
2021-12-24 19:46:10 +09:00
|
|
|
Bird,
|
2021-12-25 18:35:47 +09:00
|
|
|
Assets,
|
2022-01-06 16:56:14 +09:00
|
|
|
receiveStrictObject,
|
2022-01-06 17:16:43 +09:00
|
|
|
receiveClassOrNumber,
|
|
|
|
JsClassForEither,
|
|
|
|
receiveMutClassOrNumber,
|
2022-01-12 16:19:05 +09:00
|
|
|
getStrFromObject,
|
2022-01-23 19:17:00 +09:00
|
|
|
returnJsFunction,
|
2022-02-06 12:58:17 +09:00
|
|
|
testSerdeRoundtrip,
|
2022-02-06 17:25:32 +09:00
|
|
|
createObjWithProperty,
|
2022-02-06 21:42:48 +09:00
|
|
|
dateToNumber,
|
2022-02-10 04:50:46 +09:00
|
|
|
chronoDateToMillis,
|
2022-02-07 13:24:09 +09:00
|
|
|
derefUint8Array,
|
2022-02-10 04:50:46 +09:00
|
|
|
chronoDateAdd1Minute,
|
2022-02-28 02:26:48 +09:00
|
|
|
bufferPassThrough,
|
2022-07-06 20:08:34 +09:00
|
|
|
arrayBufferPassThrough,
|
2022-03-21 17:36:06 +09:00
|
|
|
JsRepo,
|
2022-04-26 19:06:52 +09:00
|
|
|
CssStyleSheet,
|
2022-04-06 22:08:00 +09:00
|
|
|
asyncReduceBuffer,
|
2022-04-14 01:02:06 +09:00
|
|
|
callbackReturnPromise,
|
2022-05-12 16:11:47 +09:00
|
|
|
returnEitherClass,
|
|
|
|
eitherFromOption,
|
2022-08-07 02:16:28 +09:00
|
|
|
eitherFromObjects,
|
2022-05-22 14:43:11 +09:00
|
|
|
overrideIndividualArgOnFunction,
|
|
|
|
overrideIndividualArgOnFunctionWithCbArg,
|
2022-06-04 02:07:39 +09:00
|
|
|
createObjectWithClassField,
|
|
|
|
receiveObjectWithClassField,
|
2022-07-05 18:00:45 +09:00
|
|
|
AnotherClassForEither,
|
|
|
|
receiveDifferentClass,
|
2022-08-11 23:47:13 +09:00
|
|
|
getNumArr,
|
|
|
|
getNestedNumArr,
|
2022-08-17 14:24:40 +09:00
|
|
|
CustomFinalize,
|
2022-08-17 18:49:22 +09:00
|
|
|
plusOne,
|
|
|
|
Width,
|
2022-09-14 20:30:43 +09:00
|
|
|
captureErrorInCallback,
|
2023-01-17 01:05:19 +09:00
|
|
|
bigintFromI128,
|
|
|
|
bigintFromI64,
|
2021-09-23 02:29:09 +09:00
|
|
|
} from '../'
|
|
|
|
|
2021-11-10 20:04:36 +09:00
|
|
|
test('export const', (t) => {
|
|
|
|
t.is(DEFAULT_COST, 12)
|
|
|
|
})
|
|
|
|
|
2021-09-23 02:29:09 +09:00
|
|
|
test('number', (t) => {
|
|
|
|
t.is(add(1, 2), 3)
|
|
|
|
t.is(fibonacci(5), 5)
|
|
|
|
|
|
|
|
t.throws(
|
|
|
|
// @ts-expect-error
|
|
|
|
() => fibonacci(''),
|
2022-01-04 12:04:45 +09:00
|
|
|
void 0,
|
2021-09-23 02:29:09 +09:00
|
|
|
'Expect value to be Number, but received String',
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
test('string', (t) => {
|
|
|
|
t.true(contains('hello', 'ell'))
|
|
|
|
t.false(contains('John', 'jn'))
|
|
|
|
|
|
|
|
t.is(concatStr('涽¾DEL'), '涽¾DEL + Rust 🦀 string!')
|
|
|
|
t.is(concatLatin1('涽¾DEL'), '涽¾DEL + Rust 🦀 string!')
|
|
|
|
t.is(
|
|
|
|
concatUtf16('JavaScript 🌳 你好 napi'),
|
|
|
|
'JavaScript 🌳 你好 napi + Rust 🦀 string!',
|
|
|
|
)
|
2022-02-04 17:29:17 +09:00
|
|
|
t.is(
|
|
|
|
roundtripStr('what up?!\u0000after the NULL'),
|
|
|
|
'what up?!\u0000after the NULL',
|
|
|
|
)
|
2021-09-23 02:29:09 +09:00
|
|
|
})
|
|
|
|
|
|
|
|
test('array', (t) => {
|
|
|
|
t.deepEqual(getNums(), [1, 1, 2, 3, 5, 8])
|
|
|
|
t.deepEqual(getWords(), ['foo', 'bar'])
|
|
|
|
|
|
|
|
t.is(sumNums([1, 2, 3, 4, 5]), 15)
|
2022-08-11 23:47:13 +09:00
|
|
|
t.deepEqual(getNumArr(), [1, 2])
|
|
|
|
t.deepEqual(getNestedNumArr(), [[[1]], [[1]]])
|
2021-09-23 02:29:09 +09:00
|
|
|
})
|
|
|
|
|
2021-12-19 00:16:09 +09:00
|
|
|
test('map', (t) => {
|
|
|
|
t.deepEqual(getMapping(), { a: 101, b: 102 })
|
|
|
|
t.is(sumMapping({ a: 101, b: 102 }), 203)
|
|
|
|
})
|
|
|
|
|
2021-09-23 02:29:09 +09:00
|
|
|
test('enum', (t) => {
|
|
|
|
t.deepEqual([Kind.Dog, Kind.Cat, Kind.Duck], [0, 1, 2])
|
|
|
|
t.is(enumToI32(CustomNumEnum.Eight), 8)
|
|
|
|
})
|
|
|
|
|
2022-08-20 00:36:36 +09:00
|
|
|
test('class', (t) => {
|
2021-09-23 02:29:09 +09:00
|
|
|
const dog = new Animal(Kind.Dog, '旺财')
|
|
|
|
|
|
|
|
t.is(dog.name, '旺财')
|
|
|
|
t.is(dog.kind, Kind.Dog)
|
|
|
|
t.is(dog.whoami(), 'Dog: 旺财')
|
|
|
|
|
2022-08-06 22:54:58 +09:00
|
|
|
t.notThrows(() => {
|
|
|
|
const rawMethod = dog.whoami
|
|
|
|
dog.whoami = function (...args) {
|
|
|
|
return rawMethod.apply(this, args)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2021-09-23 02:29:09 +09:00
|
|
|
dog.name = '可乐'
|
|
|
|
t.is(dog.name, '可乐')
|
2021-12-23 15:07:35 +09:00
|
|
|
t.deepEqual(dog.returnOtherClass(), new Dog('Doge'))
|
2021-12-24 19:46:10 +09:00
|
|
|
t.deepEqual(dog.returnOtherClassWithCustomConstructor(), new Bird('parrot'))
|
2022-05-22 14:43:11 +09:00
|
|
|
t.is(
|
|
|
|
dog.overrideIndividualArgOnMethod('Jafar', { n: 'Iago' }).name,
|
|
|
|
'Jafar-Iago',
|
|
|
|
)
|
2021-12-24 23:56:16 +09:00
|
|
|
t.is(dog.returnOtherClassWithCustomConstructor().getCount(), 1234)
|
2022-05-13 13:55:54 +09:00
|
|
|
t.is(dog.type, Kind.Dog)
|
|
|
|
dog.type = Kind.Cat
|
|
|
|
t.is(dog.type, Kind.Cat)
|
2021-12-25 18:35:47 +09:00
|
|
|
const assets = new Assets()
|
|
|
|
t.is(assets.get(1)?.filePath, 1)
|
2022-07-06 00:09:40 +09:00
|
|
|
const turtle = NinjaTurtle.newRaph()
|
|
|
|
t.is(turtle.returnThis(), turtle)
|
2022-08-17 16:11:32 +09:00
|
|
|
t.is(NinjaTurtle.isInstanceOf(turtle), true)
|
2022-08-17 18:49:22 +09:00
|
|
|
// Inject this to function
|
|
|
|
const width = new Width(1)
|
|
|
|
t.is(plusOne.call(width), 2)
|
|
|
|
t.throws(() => {
|
|
|
|
// @ts-expect-error
|
|
|
|
plusOne.call('')
|
|
|
|
})
|
2021-09-23 02:29:09 +09:00
|
|
|
})
|
|
|
|
|
2022-11-22 01:17:19 +09:00
|
|
|
test('async self in class', async (t) => {
|
|
|
|
const b = new Bird('foo')
|
|
|
|
t.is(await b.getNameAsync(), 'foo')
|
|
|
|
})
|
|
|
|
|
2021-11-05 19:31:36 +09:00
|
|
|
test('class factory', (t) => {
|
|
|
|
const duck = ClassWithFactory.withName('Default')
|
|
|
|
t.is(duck.name, 'Default')
|
|
|
|
|
2021-11-26 00:42:40 +09:00
|
|
|
const ret = duck.setName('D')
|
|
|
|
t.is(ret.name, 'D')
|
|
|
|
t.is(ret, duck)
|
|
|
|
|
2021-11-05 19:31:36 +09:00
|
|
|
duck.name = '周黑鸭'
|
|
|
|
t.is(duck.name, '周黑鸭')
|
|
|
|
|
|
|
|
const doge = Animal.withKind(Kind.Dog)
|
|
|
|
t.is(doge.name, 'Default')
|
|
|
|
|
|
|
|
doge.name = '旺财'
|
|
|
|
t.is(doge.name, '旺财')
|
2021-12-08 18:59:30 +09:00
|
|
|
|
|
|
|
const error = t.throws(() => new ClassWithFactory())
|
|
|
|
t.true(
|
2022-01-04 12:04:45 +09:00
|
|
|
error!.message.startsWith(
|
2021-12-08 18:59:30 +09:00
|
|
|
'Class contains no `constructor`, can not new it!',
|
|
|
|
),
|
|
|
|
)
|
2021-11-05 19:31:36 +09:00
|
|
|
})
|
|
|
|
|
2021-11-06 22:48:18 +09:00
|
|
|
test('class constructor return Result', (t) => {
|
|
|
|
const c = new Context()
|
|
|
|
t.is(c.method(), 'not empty')
|
|
|
|
})
|
|
|
|
|
2022-07-06 20:08:34 +09:00
|
|
|
test('class default field is TypedArray', (t) => {
|
|
|
|
const c = new Context()
|
|
|
|
t.deepEqual(c.buffer, new Uint8Array([0, 1, 2, 3]))
|
|
|
|
const fixture = new Uint8Array([0, 1, 2, 3, 4, 5, 6])
|
|
|
|
const c2 = Context.withBuffer(fixture)
|
|
|
|
t.is(c2.buffer, fixture)
|
|
|
|
})
|
|
|
|
|
2021-11-06 22:48:18 +09:00
|
|
|
test('class Factory return Result', (t) => {
|
|
|
|
const c = Context.withData('not empty')
|
|
|
|
t.is(c.method(), 'not empty')
|
|
|
|
})
|
|
|
|
|
2022-06-04 02:07:39 +09:00
|
|
|
test('class in object field', (t) => {
|
|
|
|
const obj = createObjectWithClassField()
|
|
|
|
t.is(obj.bird.name, 'Carolyn')
|
|
|
|
t.is(receiveObjectWithClassField(obj), obj.bird)
|
|
|
|
})
|
|
|
|
|
2022-08-17 14:24:40 +09:00
|
|
|
test('custom finalize class', (t) => {
|
|
|
|
t.notThrows(() => new CustomFinalize(200, 200))
|
|
|
|
})
|
|
|
|
|
2022-03-21 17:36:06 +09:00
|
|
|
test('should be able to create object reference and shared reference', (t) => {
|
|
|
|
const repo = new JsRepo('.')
|
|
|
|
t.is(repo.remote().name(), 'origin')
|
|
|
|
})
|
|
|
|
|
2022-04-26 19:06:52 +09:00
|
|
|
test('should be able to into_reference', (t) => {
|
|
|
|
const rules = ['body: { color: red }', 'div: { color: blue }']
|
2022-05-08 10:48:10 +09:00
|
|
|
const sheet = new CssStyleSheet('test.css', rules)
|
2022-04-26 19:06:52 +09:00
|
|
|
t.is(sheet.rules, sheet.rules)
|
|
|
|
t.deepEqual(sheet.rules.getRules(), rules)
|
2022-05-08 10:48:10 +09:00
|
|
|
t.is(sheet.rules.parentStyleSheet, sheet)
|
|
|
|
t.is(sheet.rules.name, 'test.css')
|
2022-05-03 09:27:18 +09:00
|
|
|
const anotherStyleSheet = sheet.anotherCssStyleSheet()
|
|
|
|
t.is(anotherStyleSheet.rules, sheet.rules)
|
2022-04-26 19:06:52 +09:00
|
|
|
})
|
|
|
|
|
2021-09-23 02:29:09 +09:00
|
|
|
test('callback', (t) => {
|
|
|
|
getCwd((cwd) => {
|
|
|
|
t.is(cwd, process.cwd())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.throws(
|
|
|
|
// @ts-expect-error
|
|
|
|
() => getCwd(),
|
2022-01-04 12:04:45 +09:00
|
|
|
void 0,
|
2021-09-23 02:29:09 +09:00
|
|
|
'Expect value to be Function, but received Undefined',
|
|
|
|
)
|
2021-09-24 10:15:48 +09:00
|
|
|
|
|
|
|
readFile((err, content) => {
|
2021-09-24 10:46:27 +09:00
|
|
|
t.is(err, undefined)
|
2021-09-24 10:15:48 +09:00
|
|
|
t.is(content, 'hello world')
|
|
|
|
})
|
2022-09-14 20:30:43 +09:00
|
|
|
|
|
|
|
captureErrorInCallback(
|
|
|
|
() => {
|
|
|
|
throw new Error('Testing')
|
|
|
|
},
|
|
|
|
(err) => {
|
|
|
|
t.is((err as Error).message, 'Testing')
|
|
|
|
},
|
|
|
|
)
|
2021-09-23 02:29:09 +09:00
|
|
|
})
|
|
|
|
|
2022-01-23 19:17:00 +09:00
|
|
|
test('return function', (t) => {
|
|
|
|
return new Promise<void>((resolve) => {
|
|
|
|
returnJsFunction()((err: Error | undefined, content: string) => {
|
|
|
|
t.is(err, undefined)
|
|
|
|
t.is(content, 'hello world')
|
|
|
|
resolve()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2022-04-14 01:02:06 +09:00
|
|
|
test('function return Promise', async (t) => {
|
|
|
|
const cbSpy = spy()
|
|
|
|
await callbackReturnPromise<string>(() => '1', spy)
|
|
|
|
t.is(cbSpy.callCount, 0)
|
|
|
|
await callbackReturnPromise(
|
|
|
|
() => Promise.resolve('42'),
|
|
|
|
(err, res) => {
|
|
|
|
t.is(err, null)
|
|
|
|
cbSpy(res)
|
|
|
|
},
|
|
|
|
)
|
|
|
|
t.is(cbSpy.callCount, 1)
|
|
|
|
t.deepEqual(cbSpy.args, [['42']])
|
|
|
|
})
|
|
|
|
|
2021-09-23 02:29:09 +09:00
|
|
|
test('object', (t) => {
|
|
|
|
t.deepEqual(listObjKeys({ name: 'John Doe', age: 20 }), ['name', 'age'])
|
|
|
|
t.deepEqual(createObj(), { test: 1 })
|
|
|
|
})
|
|
|
|
|
2022-01-12 16:19:05 +09:00
|
|
|
test('get str from object', (t) => {
|
|
|
|
t.notThrows(() => getStrFromObject())
|
|
|
|
})
|
|
|
|
|
2022-02-06 17:25:32 +09:00
|
|
|
test('create object from Property', (t) => {
|
|
|
|
const obj = createObjWithProperty()
|
|
|
|
t.true(obj.value instanceof ArrayBuffer)
|
|
|
|
t.is(obj.getter, 42)
|
|
|
|
})
|
|
|
|
|
2021-11-15 19:56:06 +09:00
|
|
|
test('global', (t) => {
|
|
|
|
t.is(getGlobal(), global)
|
|
|
|
})
|
|
|
|
|
|
|
|
test('get undefined', (t) => {
|
|
|
|
for (const _ of Array.from({ length: 100 })) {
|
|
|
|
t.is(getUndefined(), undefined)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
test('get null', (t) => {
|
|
|
|
for (const _ of Array.from({ length: 100 })) {
|
|
|
|
t.is(getNull(), null)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2021-12-18 14:36:45 +09:00
|
|
|
test('return Null', (t) => {
|
|
|
|
t.is(returnNull(), null)
|
|
|
|
})
|
|
|
|
|
|
|
|
test('return Undefined', (t) => {
|
|
|
|
t.is(returnUndefined(), undefined)
|
|
|
|
})
|
|
|
|
|
2021-11-16 00:09:44 +09:00
|
|
|
test('pass symbol in', (t) => {
|
|
|
|
const sym = Symbol('test')
|
|
|
|
const obj = setSymbolInObj(sym)
|
|
|
|
t.is(obj[sym], 'a symbol')
|
|
|
|
})
|
|
|
|
|
|
|
|
test('create symbol', (t) => {
|
|
|
|
t.is(createSymbol().toString(), 'Symbol(a symbol)')
|
|
|
|
})
|
|
|
|
|
2021-09-23 02:29:09 +09:00
|
|
|
test('Option', (t) => {
|
2021-09-24 10:46:27 +09:00
|
|
|
t.is(mapOption(null), null)
|
2021-09-23 02:29:09 +09:00
|
|
|
t.is(mapOption(3), 4)
|
|
|
|
})
|
2021-09-24 10:46:27 +09:00
|
|
|
|
|
|
|
test('Result', (t) => {
|
2022-01-04 12:04:45 +09:00
|
|
|
t.throws(() => throwError(), void 0, 'Manual Error')
|
2022-08-20 00:36:36 +09:00
|
|
|
if (!process.env.SKIP_UNWIND_TEST) {
|
|
|
|
t.throws(() => panic(), void 0, `Don't panic`)
|
|
|
|
}
|
2021-09-24 10:46:27 +09:00
|
|
|
})
|
2021-09-28 01:01:19 +09:00
|
|
|
|
2021-11-26 18:26:14 +09:00
|
|
|
test('function ts type override', (t) => {
|
|
|
|
t.deepEqual(tsRename({ foo: 1, bar: 2, baz: 2 }), ['foo', 'bar', 'baz'])
|
|
|
|
})
|
|
|
|
|
2022-05-22 14:43:11 +09:00
|
|
|
test('function individual ts arg type override', (t) => {
|
|
|
|
t.is(
|
|
|
|
overrideIndividualArgOnFunction('someStr', () => 'anotherStr', 42),
|
|
|
|
'oia: someStr-42-anotherStr',
|
|
|
|
)
|
|
|
|
t.deepEqual(
|
|
|
|
overrideIndividualArgOnFunctionWithCbArg(
|
|
|
|
(town, opt) => `im: ${town}-${opt}`,
|
|
|
|
89,
|
|
|
|
),
|
|
|
|
'im: World(89)-null',
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-12-02 16:47:59 +09:00
|
|
|
test('option object', (t) => {
|
|
|
|
t.notThrows(() => receiveAllOptionalObject())
|
|
|
|
t.notThrows(() => receiveAllOptionalObject({}))
|
|
|
|
})
|
|
|
|
|
2022-01-06 16:56:14 +09:00
|
|
|
test('should throw if object type is not matched', (t) => {
|
|
|
|
// @ts-expect-error
|
|
|
|
const err1 = t.throws(() => receiveStrictObject({ name: 1 }))
|
2022-10-24 01:16:30 +09:00
|
|
|
t.is(err1!.message, 'Failed to convert napi `Number` into rust type `String`')
|
2022-01-06 16:56:14 +09:00
|
|
|
// @ts-expect-error
|
|
|
|
const err2 = t.throws(() => receiveStrictObject({ bar: 1 }))
|
|
|
|
t.is(err2!.message, 'Missing field `name`')
|
|
|
|
})
|
|
|
|
|
2021-12-02 17:25:20 +09:00
|
|
|
test('aliased rust struct and enum', (t) => {
|
|
|
|
const a: ALIAS = ALIAS.A
|
|
|
|
const b: AliasedStruct = {
|
|
|
|
a,
|
|
|
|
b: 1,
|
|
|
|
}
|
|
|
|
t.notThrows(() => fnReceivedAliased(b, ALIAS.B))
|
|
|
|
})
|
|
|
|
|
2021-09-28 01:01:19 +09:00
|
|
|
test('serde-json', (t) => {
|
|
|
|
const packageJson = readPackageJson()
|
|
|
|
t.is(packageJson.name, 'napi-rs')
|
|
|
|
t.is(packageJson.version, '0.0.0')
|
2021-12-07 22:49:45 +09:00
|
|
|
t.is(packageJson.dependencies, undefined)
|
2021-09-28 01:01:19 +09:00
|
|
|
t.snapshot(Object.keys(packageJson.devDependencies!).sort())
|
|
|
|
|
|
|
|
t.is(getPackageJsonName(packageJson), 'napi-rs')
|
|
|
|
})
|
2021-10-08 22:13:27 +09:00
|
|
|
|
2022-02-06 12:58:17 +09:00
|
|
|
test('serde-roundtrip', (t) => {
|
|
|
|
t.is(testSerdeRoundtrip(1), 1)
|
|
|
|
t.is(testSerdeRoundtrip(1.2), 1.2)
|
|
|
|
t.is(testSerdeRoundtrip(-1), -1)
|
|
|
|
|
|
|
|
t.deepEqual(testSerdeRoundtrip([1, 1.2, -1]), [1, 1.2, -1])
|
|
|
|
t.deepEqual(testSerdeRoundtrip({ a: 1, b: 1.2, c: -1 }), {
|
|
|
|
a: 1,
|
|
|
|
b: 1.2,
|
|
|
|
c: -1,
|
|
|
|
})
|
|
|
|
t.throws(() => testSerdeRoundtrip(NaN))
|
|
|
|
|
|
|
|
t.is(testSerdeRoundtrip(null), null)
|
|
|
|
|
|
|
|
let err = t.throws(() => testSerdeRoundtrip(undefined))
|
|
|
|
t.is(err!.message, 'undefined cannot be represented as a serde_json::Value')
|
|
|
|
|
|
|
|
err = t.throws(() => testSerdeRoundtrip(() => {}))
|
|
|
|
t.is(
|
|
|
|
err!.message,
|
|
|
|
'JS functions cannot be represented as a serde_json::Value',
|
|
|
|
)
|
|
|
|
|
|
|
|
err = t.throws(() => testSerdeRoundtrip(Symbol.for('foo')))
|
|
|
|
t.is(err!.message, 'JS symbols cannot be represented as a serde_json::Value')
|
|
|
|
})
|
|
|
|
|
2021-10-08 22:13:27 +09:00
|
|
|
test('buffer', (t) => {
|
2021-12-18 14:24:16 +09:00
|
|
|
let buf = getBuffer()
|
|
|
|
t.is(buf.toString('utf-8'), 'Hello world')
|
|
|
|
buf = appendBuffer(buf)
|
|
|
|
t.is(buf.toString('utf-8'), 'Hello world!')
|
2022-04-23 17:43:36 +09:00
|
|
|
|
|
|
|
const a = getEmptyBuffer()
|
|
|
|
const b = getEmptyBuffer()
|
|
|
|
t.is(a.toString(), '')
|
|
|
|
t.is(b.toString(), '')
|
2021-10-08 22:13:27 +09:00
|
|
|
})
|
2021-10-25 01:00:31 +09:00
|
|
|
|
2022-04-26 16:14:37 +09:00
|
|
|
test('reset empty buffer', (t) => {
|
|
|
|
const empty = getEmptyBuffer()
|
|
|
|
|
|
|
|
const shared = new ArrayBuffer(0)
|
|
|
|
const buffer = Buffer.from(shared)
|
|
|
|
t.notThrows(() => {
|
|
|
|
buffer.set(empty)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-11-30 19:43:34 +09:00
|
|
|
test('convert typedarray to vec', (t) => {
|
|
|
|
const input = new Uint32Array([1, 2, 3, 4, 5])
|
|
|
|
t.deepEqual(convertU32Array(input), Array.from(input))
|
|
|
|
})
|
|
|
|
|
|
|
|
test('create external TypedArray', (t) => {
|
|
|
|
t.deepEqual(createExternalTypedArray(), new Uint32Array([1, 2, 3, 4, 5]))
|
|
|
|
})
|
|
|
|
|
|
|
|
test('mutate TypedArray', (t) => {
|
|
|
|
const input = new Float32Array([1, 2, 3, 4, 5])
|
|
|
|
mutateTypedArray(input)
|
|
|
|
t.deepEqual(input, new Float32Array([2.0, 4.0, 6.0, 8.0, 10.0]))
|
|
|
|
})
|
|
|
|
|
2022-02-07 13:24:09 +09:00
|
|
|
test('deref uint8 array', (t) => {
|
|
|
|
t.is(
|
|
|
|
derefUint8Array(new Uint8Array([1, 2]), new Uint8ClampedArray([3, 4])),
|
|
|
|
4,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-10-25 01:00:31 +09:00
|
|
|
test('async', async (t) => {
|
|
|
|
const bufPromise = readFileAsync(join(__dirname, '../package.json'))
|
|
|
|
await t.notThrowsAsync(bufPromise)
|
|
|
|
const buf = await bufPromise
|
|
|
|
const { name } = JSON.parse(buf.toString())
|
2022-01-24 12:33:51 +09:00
|
|
|
t.is(name, 'examples')
|
2021-10-25 01:00:31 +09:00
|
|
|
|
|
|
|
await t.throwsAsync(() => readFileAsync('some_nonexist_path.file'))
|
|
|
|
})
|
2021-11-02 01:34:19 +09:00
|
|
|
|
2021-11-06 23:19:42 +09:00
|
|
|
test('async move', async (t) => {
|
|
|
|
t.is(await asyncMultiTwo(2), 4)
|
|
|
|
})
|
|
|
|
|
2022-02-28 02:26:48 +09:00
|
|
|
test('buffer passthrough', async (t) => {
|
|
|
|
const fixture = Buffer.from('hello world')
|
|
|
|
const ret = await bufferPassThrough(fixture)
|
|
|
|
t.deepEqual(ret, fixture)
|
|
|
|
})
|
|
|
|
|
2022-07-06 20:08:34 +09:00
|
|
|
test('arraybuffer passthrough', async (t) => {
|
|
|
|
const fixture = new Uint8Array([1, 2, 3, 4, 5])
|
|
|
|
const ret = await arrayBufferPassThrough(fixture)
|
|
|
|
t.deepEqual(ret, fixture)
|
|
|
|
})
|
|
|
|
|
2022-04-06 22:08:00 +09:00
|
|
|
test('async reduce buffer', async (t) => {
|
|
|
|
const input = [1, 2, 3, 4, 5, 6]
|
|
|
|
const fixture = Buffer.from(input)
|
|
|
|
t.is(
|
|
|
|
await asyncReduceBuffer(fixture),
|
|
|
|
input.reduce((acc, cur) => acc + cur),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-11-02 01:34:19 +09:00
|
|
|
test('either', (t) => {
|
|
|
|
t.is(eitherStringOrNumber(2), 2)
|
|
|
|
t.is(eitherStringOrNumber('hello'), 'hello'.length)
|
|
|
|
})
|
|
|
|
|
|
|
|
test('return either', (t) => {
|
|
|
|
t.is(returnEither(2), 2)
|
|
|
|
t.is(returnEither(42), '42')
|
|
|
|
})
|
|
|
|
|
2022-01-06 17:16:43 +09:00
|
|
|
test('receive class reference in either', (t) => {
|
|
|
|
const c = new JsClassForEither()
|
|
|
|
t.is(receiveClassOrNumber(1), 2)
|
|
|
|
t.is(receiveClassOrNumber(c), 100)
|
|
|
|
t.is(receiveMutClassOrNumber(c), 100)
|
|
|
|
})
|
|
|
|
|
2022-07-05 18:00:45 +09:00
|
|
|
test('receive different class', (t) => {
|
|
|
|
const a = new JsClassForEither()
|
|
|
|
const b = new AnotherClassForEither()
|
|
|
|
t.is(receiveDifferentClass(a), 42)
|
|
|
|
t.is(receiveDifferentClass(b), 100)
|
|
|
|
})
|
|
|
|
|
2022-05-12 16:11:47 +09:00
|
|
|
test('return either class', (t) => {
|
|
|
|
t.is(returnEitherClass(1), 1)
|
|
|
|
t.true(returnEitherClass(-1) instanceof JsClassForEither)
|
|
|
|
})
|
|
|
|
|
|
|
|
test('either from option', (t) => {
|
|
|
|
t.true(eitherFromOption() instanceof JsClassForEither)
|
|
|
|
})
|
|
|
|
|
2022-08-07 02:16:28 +09:00
|
|
|
test('either from objects', (t) => {
|
|
|
|
t.is(eitherFromObjects({ foo: 1 }), 'A')
|
|
|
|
t.is(eitherFromObjects({ bar: 2 }), 'B')
|
|
|
|
t.is(eitherFromObjects({ baz: 3 }), 'C')
|
|
|
|
})
|
|
|
|
|
2021-11-02 01:34:19 +09:00
|
|
|
test('either3', (t) => {
|
|
|
|
t.is(either3(2), 2)
|
|
|
|
t.is(either3('hello'), 'hello'.length)
|
|
|
|
t.is(either3(true), 1)
|
|
|
|
t.is(either3(false), 0)
|
|
|
|
})
|
|
|
|
|
|
|
|
test('either4', (t) => {
|
|
|
|
t.is(either4(2), 2)
|
|
|
|
t.is(either4('hello'), 'hello'.length)
|
|
|
|
t.is(either4(true), 1)
|
|
|
|
t.is(either4(false), 0)
|
|
|
|
t.is(either4({ v: 1 }), 1)
|
|
|
|
t.is(either4({ v: 'world' }), 'world'.length)
|
|
|
|
})
|
2021-11-02 21:36:34 +09:00
|
|
|
|
2021-11-21 17:11:15 +09:00
|
|
|
test('external', (t) => {
|
|
|
|
const FX = 42
|
|
|
|
const ext = createExternal(FX)
|
|
|
|
t.is(getExternal(ext), FX)
|
|
|
|
mutateExternal(ext, FX + 1)
|
|
|
|
t.is(getExternal(ext), FX + 1)
|
|
|
|
// @ts-expect-error
|
|
|
|
t.throws(() => getExternal({}))
|
|
|
|
const ext2 = createExternalString('wtf')
|
|
|
|
// @ts-expect-error
|
|
|
|
const e = t.throws(() => getExternal(ext2))
|
2022-01-04 12:04:45 +09:00
|
|
|
t.is(
|
|
|
|
e!.message,
|
|
|
|
'T on `get_value_external` is not the type of wrapped object',
|
|
|
|
)
|
2021-11-02 21:36:34 +09:00
|
|
|
})
|
|
|
|
|
2021-11-12 18:22:57 +09:00
|
|
|
const AbortSignalTest =
|
|
|
|
typeof AbortController !== 'undefined' ? test : test.skip
|
2021-11-04 19:44:06 +09:00
|
|
|
|
2021-11-21 17:11:15 +09:00
|
|
|
AbortSignalTest('async task without abort controller', async (t) => {
|
|
|
|
t.is(await withoutAbortController(1, 2), 3)
|
|
|
|
})
|
|
|
|
|
2021-11-12 18:22:57 +09:00
|
|
|
AbortSignalTest('async task with abort controller', async (t) => {
|
2021-11-02 21:36:34 +09:00
|
|
|
const ctrl = new AbortController()
|
2021-11-04 19:44:06 +09:00
|
|
|
const promise = withAbortController(1, 2, ctrl.signal)
|
2021-11-02 21:36:34 +09:00
|
|
|
try {
|
|
|
|
ctrl.abort()
|
|
|
|
await promise
|
|
|
|
t.fail('Should throw AbortError')
|
|
|
|
} catch (err: unknown) {
|
|
|
|
t.is((err as Error).message, 'AbortError')
|
|
|
|
}
|
|
|
|
})
|
2021-11-04 19:44:06 +09:00
|
|
|
|
2021-11-12 18:22:57 +09:00
|
|
|
AbortSignalTest('abort resolved task', async (t) => {
|
2021-11-04 19:44:06 +09:00
|
|
|
const ctrl = new AbortController()
|
|
|
|
await withAbortController(1, 2, ctrl.signal).then(() => ctrl.abort())
|
|
|
|
t.pass('should not throw')
|
|
|
|
})
|
2021-11-11 01:33:51 +09:00
|
|
|
|
|
|
|
const BigIntTest = typeof BigInt !== 'undefined' ? test : test.skip
|
|
|
|
|
|
|
|
BigIntTest('BigInt add', (t) => {
|
|
|
|
t.is(bigintAdd(BigInt(1), BigInt(2)), BigInt(3))
|
|
|
|
})
|
|
|
|
|
|
|
|
BigIntTest('create BigInt', (t) => {
|
|
|
|
t.is(createBigInt(), BigInt('-3689348814741910323300'))
|
|
|
|
})
|
|
|
|
|
|
|
|
BigIntTest('create BigInt i64', (t) => {
|
|
|
|
t.is(createBigIntI64(), BigInt(100))
|
|
|
|
})
|
2021-11-12 18:22:57 +09:00
|
|
|
|
2022-02-04 17:03:32 +09:00
|
|
|
BigIntTest('BigInt get_u64', (t) => {
|
|
|
|
t.is(bigintGetU64AsString(BigInt(0)), '0')
|
|
|
|
})
|
|
|
|
|
2021-11-23 20:00:31 +09:00
|
|
|
BigIntTest('js mod test', (t) => {
|
|
|
|
t.is(xxh64Alias(Buffer.from('hello world')), BigInt('1116'))
|
|
|
|
t.is(xxh3.xxh3_64(Buffer.from('hello world')), BigInt('1116'))
|
|
|
|
t.is(xxh3.xxh128(Buffer.from('hello world')), BigInt('1116'))
|
|
|
|
t.is(xxh2.xxh2Plus(1, 2), 3)
|
|
|
|
t.is(xxh2.xxh3Xxh64Alias(Buffer.from('hello world')), BigInt('1116'))
|
|
|
|
t.is(xxh3.ALIGNMENT, 16)
|
|
|
|
const xx3 = new xxh3.Xxh3()
|
|
|
|
xx3.update(Buffer.from('hello world'))
|
|
|
|
t.is(xx3.digest(), BigInt('1116'))
|
|
|
|
})
|
|
|
|
|
2023-01-17 01:05:19 +09:00
|
|
|
BigIntTest('from i128 i64', (t) => {
|
|
|
|
t.is(bigintFromI64(), BigInt('100'))
|
|
|
|
t.is(bigintFromI128(), BigInt('-100'))
|
|
|
|
})
|
|
|
|
|
2021-11-13 21:51:14 +09:00
|
|
|
const Napi4Test = Number(process.versions.napi) >= 4 ? test : test.skip
|
2021-11-12 18:22:57 +09:00
|
|
|
|
2021-11-13 21:51:14 +09:00
|
|
|
Napi4Test('call thread safe function', (t) => {
|
2021-11-12 18:22:57 +09:00
|
|
|
let i = 0
|
|
|
|
let value = 0
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
callThreadsafeFunction((err, v) => {
|
|
|
|
t.is(err, null)
|
|
|
|
i++
|
|
|
|
value += v
|
|
|
|
if (i === 100) {
|
|
|
|
resolve()
|
|
|
|
t.is(
|
|
|
|
value,
|
|
|
|
Array.from({ length: 100 }, (_, i) => i + 1).reduce((a, b) => a + b),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-11-13 21:51:14 +09:00
|
|
|
Napi4Test('throw error from thread safe function', async (t) => {
|
2021-11-12 18:22:57 +09:00
|
|
|
const throwPromise = new Promise((_, reject) => {
|
|
|
|
threadsafeFunctionThrowError(reject)
|
|
|
|
})
|
|
|
|
const err = await t.throwsAsync(throwPromise)
|
2022-01-04 12:04:45 +09:00
|
|
|
t.is(err!.message, 'ThrowFromNative')
|
2021-11-12 18:22:57 +09:00
|
|
|
})
|
2021-11-13 21:51:14 +09:00
|
|
|
|
2022-08-20 23:40:26 +09:00
|
|
|
Napi4Test('thread safe function closure capture data', (t) => {
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
threadsafeFunctionClosureCapture(() => {
|
|
|
|
resolve()
|
|
|
|
t.pass()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-12-14 01:37:46 +09:00
|
|
|
Napi4Test('resolve value from thread safe function fatal mode', async (t) => {
|
2021-11-21 15:49:04 +09:00
|
|
|
const tsfnFatalMode = new Promise<boolean>((resolve) => {
|
|
|
|
threadsafeFunctionFatalMode(resolve)
|
|
|
|
})
|
|
|
|
t.true(await tsfnFatalMode)
|
|
|
|
})
|
|
|
|
|
2021-12-14 01:37:46 +09:00
|
|
|
Napi4Test('throw error from thread safe function fatal mode', (t) => {
|
|
|
|
const p = exec('node ./tsfn-error.js', {
|
|
|
|
cwd: __dirname,
|
|
|
|
})
|
|
|
|
let stderr = Buffer.from([])
|
|
|
|
p.stderr?.on('data', (data) => {
|
|
|
|
stderr = Buffer.concat([stderr, Buffer.from(data)])
|
|
|
|
})
|
|
|
|
return new Promise<void>((resolve) => {
|
|
|
|
p.on('exit', (code) => {
|
|
|
|
t.is(code, 1)
|
|
|
|
t.true(
|
|
|
|
stderr
|
|
|
|
.toString('utf8')
|
|
|
|
.includes(`[Error: Generic tsfn error] { code: 'GenericFailure' }`),
|
|
|
|
)
|
|
|
|
resolve()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-11-13 21:51:14 +09:00
|
|
|
Napi4Test('await Promise in rust', async (t) => {
|
|
|
|
const fx = 20
|
|
|
|
const result = await asyncPlus100(
|
|
|
|
new Promise((resolve) => {
|
|
|
|
setTimeout(() => resolve(fx), 50)
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
t.is(result, fx + 100)
|
|
|
|
})
|
|
|
|
|
|
|
|
Napi4Test('Promise should reject raw error in rust', async (t) => {
|
|
|
|
const fxError = new Error('What is Happy Planet')
|
|
|
|
const err = await t.throwsAsync(() => asyncPlus100(Promise.reject(fxError)))
|
|
|
|
t.is(err, fxError)
|
|
|
|
})
|
2022-02-06 21:42:48 +09:00
|
|
|
|
2023-01-11 19:54:45 +09:00
|
|
|
Napi4Test('call ThreadsafeFunction with callback', async (t) => {
|
|
|
|
await t.notThrowsAsync(
|
|
|
|
() =>
|
|
|
|
new Promise<void>((resolve) => {
|
|
|
|
tsfnCallWithCallback(() => {
|
|
|
|
resolve()
|
|
|
|
return 'ReturnFromJavaScriptRawCallback'
|
|
|
|
})
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
Napi4Test('async call ThreadsafeFunction', async (t) => {
|
|
|
|
await t.notThrowsAsync(() =>
|
|
|
|
tsfnAsyncCall((err, arg1, arg2, arg3) => {
|
|
|
|
t.is(err, null)
|
|
|
|
t.is(arg1, 0)
|
|
|
|
t.is(arg2, 1)
|
|
|
|
t.is(arg3, 2)
|
|
|
|
return 'ReturnFromJavaScriptRawCallback'
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2022-02-06 21:42:48 +09:00
|
|
|
const Napi5Test = Number(process.versions.napi) >= 5 ? test : test.skip
|
|
|
|
|
|
|
|
Napi5Test('Date test', (t) => {
|
|
|
|
const fixture = new Date('2016-12-24')
|
|
|
|
t.is(dateToNumber(fixture), fixture.valueOf())
|
|
|
|
})
|
2022-02-10 04:50:46 +09:00
|
|
|
|
|
|
|
Napi5Test('Date to chrono test', (t) => {
|
|
|
|
const fixture = new Date('2022-02-09T19:31:55.396Z')
|
|
|
|
t.is(chronoDateToMillis(fixture), fixture.getTime())
|
|
|
|
t.deepEqual(
|
|
|
|
chronoDateAdd1Minute(fixture),
|
|
|
|
new Date(fixture.getTime() + 60 * 1000),
|
|
|
|
)
|
|
|
|
})
|