import { describe, it, expect } from 'vitest'; import { Query, OkSome, OkNone, ErrNone, okSome, okNone, errNone } from '../'; describe('Query constructors and factories - Runtime Tests', () => { describe('OkSome constructor', () => { it('should create OkSome instance with provided value', () => { // Arrange const value = 42; // Act const result = new OkSome(value); // Assert expect(result).toBeInstanceOf(OkSome); expect(result.value).toBe(value); }); it('should store different types of values correctly', () => { // Arrange const numberValue = 42; const stringValue = 'hello'; const objectValue = { id: 1, name: 'test' }; const arrayValue = [1, 2, 3]; const functionValue = (x: number) => x * 2; // Act const numberOkSome = new OkSome(numberValue); const stringOkSome = new OkSome(stringValue); const objectOkSome = new OkSome(objectValue); const arrayOkSome = new OkSome(arrayValue); const functionOkSome = new OkSome(functionValue); // Assert expect(numberOkSome.value).toBe(numberValue); expect(stringOkSome.value).toBe(stringValue); expect(objectOkSome.value).toBe(objectValue); expect(arrayOkSome.value).toBe(arrayValue); expect(functionOkSome.value).toBe(functionValue); }); it('should implement QueryInterface methods', () => { // Arrange const instance = new OkSome(42); // Assert expect(typeof instance.isSome).toBe('function'); expect(typeof instance.isNone).toBe('function'); expect(typeof instance.isErr).toBe('function'); expect(typeof instance.map).toBe('function'); expect(typeof instance.mapErr).toBe('function'); expect(typeof instance.flatMap).toBe('function'); expect(typeof instance.flatMapErr).toBe('function'); expect(typeof instance.match).toBe('function'); expect(typeof instance.filter).toBe('function'); expect(typeof instance.toNullable).toBe('function'); expect(typeof instance.toUndefined).toBe('function'); expect(typeof instance.toString).toBe('function'); }); it('should correctly identify as OkSome', () => { // Arrange const instance = new OkSome(42); // Act & Assert expect(instance.isSome()).toBe(true); expect(instance.isNone()).toBe(false); expect(instance.isErr()).toBe(false); }); }); describe('OkNone constructor', () => { it('should create OkNone instance', () => { // Act const result = new OkNone(); // Assert expect(result).toBeInstanceOf(OkNone); }); it('should implement QueryInterface methods', () => { // Arrange const instance = new OkNone(); // Assert expect(typeof instance.isSome).toBe('function'); expect(typeof instance.isNone).toBe('function'); expect(typeof instance.isErr).toBe('function'); expect(typeof instance.map).toBe('function'); expect(typeof instance.mapErr).toBe('function'); expect(typeof instance.flatMap).toBe('function'); expect(typeof instance.flatMapErr).toBe('function'); expect(typeof instance.match).toBe('function'); expect(typeof instance.filter).toBe('function'); expect(typeof instance.toNullable).toBe('function'); expect(typeof instance.toUndefined).toBe('function'); expect(typeof instance.toString).toBe('function'); }); it('should correctly identify as OkNone', () => { // Arrange const instance = new OkNone(); // Act & Assert expect(instance.isSome()).toBe(false); expect(instance.isNone()).toBe(true); expect(instance.isErr()).toBe(false); }); }); describe('ErrNone constructor', () => { it('should create ErrNone instance with provided error', () => { // Arrange const error = 'something went wrong'; // Act const result = new ErrNone(error); // Assert expect(result).toBeInstanceOf(ErrNone); expect(result.err).toBe(error); }); it('should store different types of errors correctly', () => { // Arrange const stringError = 'error'; const numberError = 404; const objectError = { code: 'NOT_FOUND', message: 'not found' }; const errorInstance = new Error('fail'); // Act const stringErrNone = new ErrNone(stringError); const numberErrNone = new ErrNone(numberError); const objectErrNone = new ErrNone(objectError); const errorErrNone = new ErrNone(errorInstance); // Assert expect(stringErrNone.err).toBe(stringError); expect(numberErrNone.err).toBe(numberError); expect(objectErrNone.err).toBe(objectError); expect(errorErrNone.err).toBe(errorInstance); }); it('should implement QueryInterface methods', () => { // Arrange const instance = new ErrNone('error'); // Assert expect(typeof instance.isSome).toBe('function'); expect(typeof instance.isNone).toBe('function'); expect(typeof instance.isErr).toBe('function'); expect(typeof instance.map).toBe('function'); expect(typeof instance.mapErr).toBe('function'); expect(typeof instance.flatMap).toBe('function'); expect(typeof instance.flatMapErr).toBe('function'); expect(typeof instance.match).toBe('function'); expect(typeof instance.filter).toBe('function'); expect(typeof instance.toNullable).toBe('function'); expect(typeof instance.toUndefined).toBe('function'); expect(typeof instance.toString).toBe('function'); }); it('should correctly identify as ErrNone', () => { // Arrange const instance = new ErrNone('error'); // Act & Assert expect(instance.isSome()).toBe(false); expect(instance.isNone()).toBe(false); expect(instance.isErr()).toBe(true); }); }); describe('okSome() factory function', () => { it('should create OkSome instance with provided value', () => { // Arrange const value = 42; // Act const result = okSome(value); // Assert expect(result).toBeInstanceOf(OkSome); expect(result.value).toBe(value); }); it('should work with various data types', () => { // Arrange const testCases = [ 42, 'hello', true, { id: 1, name: 'test' }, [1, 2, 3], (x: number) => x * 2, ]; testCases.forEach((testValue) => { // Act const result = okSome(testValue); // Assert expect(result).toBeInstanceOf(OkSome); expect(result.value).toBe(testValue); expect(result.isSome()).toBe(true); expect(result.isNone()).toBe(false); expect(result.isErr()).toBe(false); }); }); it('should create new instances for each call', () => { // Arrange const value = 42; // Act const first = okSome(value); const second = okSome(value); // Assert expect(first).toBeInstanceOf(OkSome); expect(second).toBeInstanceOf(OkSome); expect(first).not.toBe(second); expect(first.value).toBe(second.value); }); }); describe('okNone() factory function', () => { it('should return OkNone instance', () => { // Act const result = okNone(); // Assert expect(result).toBeInstanceOf(OkNone); expect(result.isSome()).toBe(false); expect(result.isNone()).toBe(true); expect(result.isErr()).toBe(false); }); it('should return the same singleton instance', () => { // Act const first = okNone(); const second = okNone(); const third = okNone(); // Assert expect(first).toBe(second); expect(second).toBe(third); expect(first).toBe(third); }); it('should return a frozen instance', () => { // Act const instance = okNone(); // Assert expect(Object.isFrozen(instance)).toBe(true); }); it('should not accept any arguments', () => { // Act & Assert expect(() => okNone()).not.toThrow(); // @ts-expect-error Testing runtime behavior when called incorrectly expect(() => okNone(42)).not.toThrow(); }); }); describe('errNone() factory function', () => { it('should create ErrNone instance with provided error', () => { // Arrange const error = 'something failed'; // Act const result = errNone(error); // Assert expect(result).toBeInstanceOf(ErrNone); expect(result.err).toBe(error); }); it('should work with various error types', () => { // Arrange const testCases = [ 'error string', 42, new Error('fail'), { code: 'ERR', message: 'failed' }, ['err1', 'err2'], ]; testCases.forEach((testError) => { // Act const result = errNone(testError); // Assert expect(result).toBeInstanceOf(ErrNone); expect(result.err).toBe(testError); expect(result.isSome()).toBe(false); expect(result.isNone()).toBe(false); expect(result.isErr()).toBe(true); }); }); it('should create new instances for each call', () => { // Arrange const error = 'error'; // Act const first = errNone(error); const second = errNone(error); // Assert expect(first).not.toBe(second); expect(first.err).toBe(second.err); }); }); describe('toString()', () => { it('should return correct string for OkSome', () => { // Arrange & Act & Assert expect(okSome(42).toString()).toBe('OkSome(42)'); expect(okSome('hello').toString()).toBe('OkSome(hello)'); expect(okSome(true).toString()).toBe('OkSome(true)'); }); it('should return correct string for OkNone', () => { // Arrange & Act & Assert expect(okNone().toString()).toBe('OkNone()'); }); it('should return correct string for ErrNone', () => { // Arrange & Act & Assert expect(errNone('error').toString()).toBe('ErrNone(error)'); expect(errNone(404).toString()).toBe('ErrNone(404)'); }); }); describe('Integration tests', () => { it('should allow creating mixed arrays of Queries', () => { // Arrange & Act const queries: Query[] = [ okSome(1) as Query, okSome(2) as Query, okNone() as Query, errNone('error') as Query, okSome(3) as Query, ]; // Assert expect(queries).toHaveLength(5); expect(queries[0].isSome()).toBe(true); expect(queries[1].isSome()).toBe(true); expect(queries[2].isNone()).toBe(true); expect(queries[3].isErr()).toBe(true); expect(queries[4].isSome()).toBe(true); }); it('should enable type narrowing in runtime', () => { // Arrange const query: Query = okSome('hello') as Query; // Act & Assert if (query.isSome()) { expect(query.value).toBe('hello'); expect(typeof query.value).toBe('string'); } else { fail('Expected query to be OkSome'); } }); it('should handle edge cases correctly', () => { // Arrange & Act const zeroOkSome = okSome(0); const falseOkSome = okSome(false); const emptyOkSome = okSome(''); const emptyArrayOkSome = okSome([]); // Assert - All should be OkSome instances even with "falsy" values expect(zeroOkSome.isSome()).toBe(true); expect(falseOkSome.isSome()).toBe(true); expect(emptyOkSome.isSome()).toBe(true); expect(emptyArrayOkSome.isSome()).toBe(true); expect(zeroOkSome.value).toBe(0); expect(falseOkSome.value).toBe(false); expect(emptyOkSome.value).toBe(''); expect(emptyArrayOkSome.value).toEqual([]); }); }); });