import { Ok, Result } from "..";
import { resultify } from "../resultify";

describe("resultify", () => {
  it("skips if a promise is already resultified", () => {
    const promise = Promise.resolve(Ok(0));
    const resultified = resultify(promise);
    // some state to close on to help testing
    let called = 0;
    // replace a simple combinator with a compatible one that tracks state
    resultified.and = <U>(r: Result<U, unknown>) => {
      called += 1;
      return resultify(Promise.resolve(r));
    };
    resultified.and(Ok(1));
    expect(called).toEqual(1);
    // calling again should *not* replace the custom combinator
    resultify(resultified);
    resultified.and(Ok(2));
    // should still increment if resultify skipped an already resultified
    // promise
    expect(called).toEqual(2);
  });

  it("throws if called with undefined", () => {
    expect(() =>
      resultify(undefined as unknown as Promise<Result<unknown, unknown>>),
    ).toThrow();
  });

  it("accepts a result and wraps with a promise", async () => {
    expect(
      await resultify(Ok(3)).andThenAsync(
        async (i): Promise<Result<number, never>> => Ok(i * 2),
      ),
    ).toEqual(Ok(6));
  });
});
