initial commit
This commit is contained in:
389
src/query/spec/query.spec.ts
Normal file
389
src/query/spec/query.spec.ts
Normal file
@@ -0,0 +1,389 @@
|
||||
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<number, string>[] = [
|
||||
okSome(1) as Query<number, string>,
|
||||
okSome(2) as Query<number, string>,
|
||||
okNone() as Query<number, string>,
|
||||
errNone('error') as Query<number, string>,
|
||||
okSome(3) as Query<number, string>,
|
||||
];
|
||||
|
||||
// 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<string, number> = okSome('hello') as Query<string, number>;
|
||||
|
||||
// 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([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user