From 01cce7cbcdc48c2aae1977128a1a4c2b698a6089 Mon Sep 17 00:00:00 2001 From: yifanwww Date: Sun, 17 Mar 2024 18:05:05 +0800 Subject: [PATCH] feat: support inspectAsync and inspectErrAsync methods --- src/__tests__/result.test.ts | 104 +++++++++++++++++++++++++++++++++-- src/result.ts | 24 ++++++++ src/types.ts | 14 +++++ 3 files changed, 138 insertions(+), 4 deletions(-) diff --git a/src/__tests__/result.test.ts b/src/__tests__/result.test.ts index e50e9e7..0522674 100644 --- a/src/__tests__/result.test.ts +++ b/src/__tests__/result.test.ts @@ -516,9 +516,9 @@ describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.protot describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.prototype.inspect.name}\``, () => { it('should return itself', () => { - const fn = jest.fn(() => { + const fn = () => { // do something - }); + }; const okResult = Ok(1); const errResult = Err(0); expect(okResult.inspect(fn)).toBe(okResult); @@ -546,11 +546,59 @@ describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.protot }); }); -describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.prototype.inspectErr.name}\``, () => { - it('should return itself', () => { +describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.prototype.inspectAsync.name}\``, () => { + it('should return itself', async () => { + const fn1 = () => { + // do something + }; + const fn2 = () => { + // do something + return Promise.resolve(); + }; + + const okResult = Ok(1); + const errResult = Err(0); + + await expect(okResult.inspectAsync(fn1)).resolves.toStrictEqual(okResult); + await expect(errResult.inspectAsync(fn1)).resolves.toStrictEqual(errResult); + await expect(okResult.inspectAsync(fn2)).resolves.toStrictEqual(okResult); + await expect(errResult.inspectAsync(fn2)).resolves.toStrictEqual(errResult); + }); + + it('should inspect ok value', async () => { + const fn1 = jest.fn((value: number) => expect(value).toBe(1)); + const fn2 = jest.fn((value: number) => { + expect(value).toBe(1); + return Promise.resolve(); + }); + expect(fn1).toHaveBeenCalledTimes(0); + expect(fn2).toHaveBeenCalledTimes(0); + await Ok(1).inspectAsync(fn1); + await Ok(1).inspectAsync(fn2); + expect(fn1).toHaveBeenCalledTimes(1); + expect(fn2).toHaveBeenCalledTimes(1); + }); + + it('should not inspect err value', async () => { const fn = jest.fn(() => { // do something }); + expect(fn).toHaveBeenCalledTimes(0); + await Err(1).inspectAsync(fn); + expect(fn).toHaveBeenCalledTimes(0); + }); + + it('should panic if fn panic', async () => { + await expect(() => Ok(1).inspectAsync(panicFn1)).rejects.toThrow(Error('error')); + await expect(() => Ok(1).inspectAsync(panicFn2)).rejects.toThrow(Error('error')); + }); +}); + +describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.prototype.inspectErr.name}\``, () => { + it('should return itself', () => { + const fn = () => { + // do something + }; const okResult = Ok(1); const errResult = Err(0); expect(okResult.inspectErr(fn)).toBe(okResult); @@ -578,6 +626,54 @@ describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.protot }); }); +describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.prototype.inspectErrAsync.name}\``, () => { + it('should return itself', async () => { + const fn1 = () => { + // do something + }; + const fn2 = () => { + // do something + return Promise.resolve(); + }; + + const okResult = Ok(1); + const errResult = Err(0); + + await expect(okResult.inspectErrAsync(fn1)).resolves.toBe(okResult); + await expect(errResult.inspectErrAsync(fn1)).resolves.toBe(errResult); + await expect(okResult.inspectErrAsync(fn2)).resolves.toBe(okResult); + await expect(errResult.inspectErrAsync(fn2)).resolves.toBe(errResult); + }); + + it('should not inspect ok value', async () => { + const fn = jest.fn(() => { + // do something + }); + expect(fn).toHaveBeenCalledTimes(0); + await Ok(1).inspectErrAsync(fn); + expect(fn).toHaveBeenCalledTimes(0); + }); + + it('should inspect err value', async () => { + const fn1 = jest.fn((value: number) => expect(value).toBe(1)); + const fn2 = jest.fn((value: number) => { + expect(value).toBe(1); + return Promise.resolve(); + }); + expect(fn1).toHaveBeenCalledTimes(0); + expect(fn2).toHaveBeenCalledTimes(0); + await Err(1).inspectErrAsync(fn1); + await Err(1).inspectErrAsync(fn2); + expect(fn1).toHaveBeenCalledTimes(1); + expect(fn2).toHaveBeenCalledTimes(1); + }); + + it('should panic if fn panic', async () => { + await expect(() => Err('err').inspectErrAsync(panicFn1)).rejects.toThrow(Error('error')); + await expect(() => Err('err').inspectErrAsync(panicFn2)).rejects.toThrow(Error('error')); + }); +}); + describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.prototype.expect.name}\``, () => { it('should unwrap itself to get the contained `Ok` value', () => { expect(Ok(1).expect('Operation type should be correct')).toBe(1); diff --git a/src/result.ts b/src/result.ts index ed9bbce..1d9344a 100644 --- a/src/result.ts +++ b/src/result.ts @@ -222,6 +222,18 @@ export class RustlikeResult implements Result { return this; } + /** + * Asynchronously calls the provided closure with a reference to the contained value if `Ok`. + * + * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.inspect + */ + async inspectAsync(fn: (value: T) => void | Promise): Promise { + if (this.isOk()) { + await fn(this.unwrapUnchecked()); + } + return this; + } + /** * Calls the provided closure with a reference to the contained value if `Err`. * @@ -234,6 +246,18 @@ export class RustlikeResult implements Result { return this; } + /** + * Asynchronously calls the provided closure with a reference to the contained value if `Err`. + * + * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.inspect_err + */ + async inspectErrAsync(fn: (err: E) => void | Promise): Promise { + if (this.isErr()) { + await fn(this.unwrapErrUnchecked()); + } + return this; + } + private _unwrapFailed(msg: string, err: unknown): never { throw new Error(`${msg}: ${String(err)}`); } diff --git a/src/types.ts b/src/types.ts index b532f81..3e1a01c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -157,6 +157,13 @@ export interface Result { */ inspect(fn: (value: T) => void): this; + /** + * Asynchronously calls the provided closure with a reference to the contained value if `Ok`. + * + * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.inspect + */ + inspectAsync(fn: (value: T) => void | Promise): Promise; + /** * Calls the provided closure with a reference to the contained value if `Err`. * @@ -164,6 +171,13 @@ export interface Result { */ inspectErr(fn: (err: E) => void): this; + /** + * Asynchronously calls the provided closure with a reference to the contained value if `Err`. + * + * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.inspect_err + */ + inspectErrAsync(fn: (err: E) => void | Promise): Promise; + /** * Returns the contained `Ok` value. *