Add runtime type checking and errors when invalid values are provided.
This commit is contained in:
		
							parent
							
								
									f5502109ac
								
							
						
					
					
						commit
						8afce56b9e
					
				
					 22 changed files with 273 additions and 10 deletions
				
			
		
							
								
								
									
										4
									
								
								src/errors/index.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/errors/index.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
 | 
			
		||||
export * from "./sharkitek-error";
 | 
			
		||||
export * from "./type-error";
 | 
			
		||||
export * from "./invalid-type-value-error";
 | 
			
		||||
							
								
								
									
										13
									
								
								src/errors/invalid-type-value-error.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/errors/invalid-type-value-error.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
import {TypeError} from "./type-error";
 | 
			
		||||
import {Type} from "../model/types/type";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A Sharkitek type error when the passed value is invalid.
 | 
			
		||||
 */
 | 
			
		||||
export class InvalidTypeValueError<SerializedType, ModelType> extends TypeError<SerializedType, ModelType>
 | 
			
		||||
{
 | 
			
		||||
	constructor(public type: Type<SerializedType, ModelType>, public value: any, message?: string)
 | 
			
		||||
	{
 | 
			
		||||
		super(type, message ?? `${JSON.stringify(value)} is an invalid value`)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								src/errors/sharkitek-error.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/errors/sharkitek-error.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
/**
 | 
			
		||||
 * A Sharkitek error.
 | 
			
		||||
 */
 | 
			
		||||
export class SharkitekError extends Error
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								src/errors/type-error.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/errors/type-error.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
import {SharkitekError} from "./sharkitek-error";
 | 
			
		||||
import {Type} from "../model/types/type";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A Sharkitek type error.
 | 
			
		||||
 */
 | 
			
		||||
export class TypeError<SerializedType, ModelType> extends SharkitekError
 | 
			
		||||
{
 | 
			
		||||
	constructor(public type: Type<SerializedType, ModelType>, message?: string)
 | 
			
		||||
	{
 | 
			
		||||
		super(`Error in type ${type.constructor.name}${message ? `: ${message}` : ""}`);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
import * as s from "./model";
 | 
			
		||||
export * from "./model";
 | 
			
		||||
export * from "./errors";
 | 
			
		||||
export { s };
 | 
			
		||||
export default s;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import * as property from "./properties";
 | 
			
		||||
export { property };
 | 
			
		||||
export {property};
 | 
			
		||||
 | 
			
		||||
export * from "./model";
 | 
			
		||||
export {Definition} from "./property-definition";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import {Type} from "./type";
 | 
			
		||||
import {define, Definition} from "../property-definition";
 | 
			
		||||
import {InvalidTypeValueError} from "../../errors";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Type of an array of values.
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +21,8 @@ export class ArrayType<SerializedValueType, SharkitekValueType> extends Type<Ser
 | 
			
		|||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		if (!Array.isArray(value)) throw new InvalidTypeValueError(this, value, "value must be an array");
 | 
			
		||||
 | 
			
		||||
		return value.map((value) => (
 | 
			
		||||
			// Serializing each value of the array.
 | 
			
		||||
			this.valueDefinition.type.serialize(value)
 | 
			
		||||
| 
						 | 
				
			
			@ -31,6 +34,8 @@ export class ArrayType<SerializedValueType, SharkitekValueType> extends Type<Ser
 | 
			
		|||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		if (!Array.isArray(value)) throw new InvalidTypeValueError(this, value, "value must be an array");
 | 
			
		||||
 | 
			
		||||
		return value.map((serializedValue) => (
 | 
			
		||||
			// Deserializing each value of the array.
 | 
			
		||||
			this.valueDefinition.type.deserialize(serializedValue)
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +47,8 @@ export class ArrayType<SerializedValueType, SharkitekValueType> extends Type<Ser
 | 
			
		|||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		if (!Array.isArray(value)) throw new InvalidTypeValueError(this, value, "value must be an array");
 | 
			
		||||
 | 
			
		||||
		// Serializing diff of all elements.
 | 
			
		||||
		return value.map((value) => this.valueDefinition.type.serializeDiff(value) as SerializedValueType);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -94,6 +101,8 @@ export class ArrayType<SerializedValueType, SharkitekValueType> extends Type<Ser
 | 
			
		|||
		// Handle NULL / undefined array.
 | 
			
		||||
		if (!array) return super.clone(array);
 | 
			
		||||
 | 
			
		||||
		if (!Array.isArray(array)) throw new InvalidTypeValueError(this, array, "value must be an array");
 | 
			
		||||
 | 
			
		||||
		// Initialize an empty array.
 | 
			
		||||
		const cloned = [] as T;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import {Type} from "./type";
 | 
			
		||||
import {define, Definition} from "../property-definition";
 | 
			
		||||
import {InvalidTypeValueError} from "../../errors";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Type of dates.
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +19,7 @@ export class DateType extends Type<string, Date>
 | 
			
		|||
	{
 | 
			
		||||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
		if (!(value instanceof Date)) throw new InvalidTypeValueError(this, value, "value must be a date");
 | 
			
		||||
		if (isNaN(value?.valueOf())) return value?.toString();
 | 
			
		||||
 | 
			
		||||
		return value?.toISOString();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import {Type} from "./type";
 | 
			
		||||
import {define, Definition} from "../property-definition";
 | 
			
		||||
import {InvalidTypeValueError} from "../../errors";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Type of decimal numbers.
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +19,7 @@ export class DecimalType extends Type<string, number>
 | 
			
		|||
	{
 | 
			
		||||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
		if (typeof value !== "number" && typeof value !== "string") throw new InvalidTypeValueError(this, value, "value must be a number");
 | 
			
		||||
 | 
			
		||||
		return value?.toString();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ import {
 | 
			
		|||
	ModelShape,
 | 
			
		||||
	SerializedModel
 | 
			
		||||
} from "../model";
 | 
			
		||||
import {InvalidTypeValueError} from "../../errors";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Type of a Sharkitek model value.
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +37,9 @@ export class ModelType<T extends object, Shape extends ModelShape<T>, Identifier
 | 
			
		|||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		if (!(value instanceof this.definedModel.definition.Class))
 | 
			
		||||
			throw new InvalidTypeValueError(this, value, `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`);
 | 
			
		||||
 | 
			
		||||
		// Serializing the given model.
 | 
			
		||||
		return this.definedModel.model(value).serialize();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +49,9 @@ export class ModelType<T extends object, Shape extends ModelShape<T>, Identifier
 | 
			
		|||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		if (typeof value !== "object" || Array.isArray(value))
 | 
			
		||||
			throw new InvalidTypeValueError(this, value, "value must be an object");
 | 
			
		||||
 | 
			
		||||
		// Parse the given object in the new model.
 | 
			
		||||
		return this.definedModel.parse(value);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -54,12 +61,21 @@ export class ModelType<T extends object, Shape extends ModelShape<T>, Identifier
 | 
			
		|||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		if (!(value instanceof this.definedModel.definition.Class))
 | 
			
		||||
			throw new InvalidTypeValueError(this, value, `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`);
 | 
			
		||||
 | 
			
		||||
		// Serializing the given model.
 | 
			
		||||
		return this.definedModel.model(value).serializeDiff();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resetDiff(value: ModelInstance<T, Shape, Identifier>|null|undefined): void
 | 
			
		||||
	{
 | 
			
		||||
		if (value === undefined) return;
 | 
			
		||||
		if (value === null) return;
 | 
			
		||||
 | 
			
		||||
		if (!(value instanceof this.definedModel.definition.Class))
 | 
			
		||||
			throw new InvalidTypeValueError(this, value, `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`);
 | 
			
		||||
 | 
			
		||||
		// Reset diff of the given model.
 | 
			
		||||
		this.definedModel.model(value).resetDiff();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +87,11 @@ export class ModelType<T extends object, Shape extends ModelShape<T>, Identifier
 | 
			
		|||
		if (currentValue === undefined) return true; // Original value is not undefined.
 | 
			
		||||
		if (currentValue === null) return true; // Original value is not null.
 | 
			
		||||
 | 
			
		||||
		if (!(originalValue instanceof this.definedModel.definition.Class))
 | 
			
		||||
			throw new InvalidTypeValueError(this, originalValue, `value must be a compatible model (given ${originalValue.constructor.name}, expected ${this.definedModel.definition.Class.name})`);
 | 
			
		||||
		if (!(currentValue instanceof this.definedModel.definition.Class))
 | 
			
		||||
			throw new InvalidTypeValueError(this, currentValue, `value must be a compatible model (given ${currentValue.constructor.name}, expected ${this.definedModel.definition.Class.name})`);
 | 
			
		||||
 | 
			
		||||
		// If the current value is dirty, it has changed.
 | 
			
		||||
		return this.definedModel.model(currentValue).isDirty();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -82,6 +103,11 @@ export class ModelType<T extends object, Shape extends ModelShape<T>, Identifier
 | 
			
		|||
		if (currentValue === undefined) return true; // Original value is not undefined.
 | 
			
		||||
		if (currentValue === null) return true; // Original value is not null.
 | 
			
		||||
 | 
			
		||||
		if (typeof originalValue !== "object" || Array.isArray(originalValue))
 | 
			
		||||
			throw new InvalidTypeValueError(this, originalValue, "value must be an object");
 | 
			
		||||
		if (typeof currentValue !== "object" || Array.isArray(currentValue))
 | 
			
		||||
			throw new InvalidTypeValueError(this, currentValue, "value must be an object");
 | 
			
		||||
 | 
			
		||||
		// If any property has changed, the value has changed.
 | 
			
		||||
		for (const property of this.definedModel.properties)
 | 
			
		||||
			if (property.definition.type.serializedHasChanged(originalValue?.[property.name], currentValue?.[property.name]))
 | 
			
		||||
| 
						 | 
				
			
			@ -95,6 +121,9 @@ export class ModelType<T extends object, Shape extends ModelShape<T>, Identifier
 | 
			
		|||
		// Handle NULL / undefined values.
 | 
			
		||||
		if (!value) return super.clone(value);
 | 
			
		||||
 | 
			
		||||
		if (!(value instanceof this.definedModel.definition.Class))
 | 
			
		||||
			throw new InvalidTypeValueError(this, value, `value must be a compatible model (given ${value.constructor.name}, expected ${this.definedModel.definition.Class.name})`);
 | 
			
		||||
 | 
			
		||||
		return this.definedModel.model(value).clone() as Type;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import {Type} from "./type";
 | 
			
		||||
import {define, Definition} from "../property-definition";
 | 
			
		||||
import {InvalidTypeValueError} from "../../errors";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Type of any numeric value.
 | 
			
		||||
| 
						 | 
				
			
			@ -8,11 +9,21 @@ export class NumericType extends Type<number, number>
 | 
			
		|||
{
 | 
			
		||||
	deserialize(value: number|null|undefined): number|null|undefined
 | 
			
		||||
	{
 | 
			
		||||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		if (typeof value !== "number") throw new InvalidTypeValueError(this, value, "value must be a number");
 | 
			
		||||
 | 
			
		||||
		return value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	serialize(value: number|null|undefined): number|null|undefined
 | 
			
		||||
	{
 | 
			
		||||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		if (typeof value !== "number") throw new InvalidTypeValueError(this, value, "value must be a number");
 | 
			
		||||
 | 
			
		||||
		return value;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
import {Type} from "./type";
 | 
			
		||||
import {define, Definition} from "../property-definition";
 | 
			
		||||
import {ModelProperties, ModelPropertiesValues, ModelProperty, ModelShape, SerializedModel} from "../model";
 | 
			
		||||
import {InvalidTypeValueError} from "../../errors";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Type of a custom object.
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +46,9 @@ export class ObjectType<Shape extends ModelShape<T>, T extends object> extends T
 | 
			
		|||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		if (typeof value !== "object" || Array.isArray(value))
 | 
			
		||||
			throw new InvalidTypeValueError(this, value, "value must be an object");
 | 
			
		||||
 | 
			
		||||
		// Initialize an empty object.
 | 
			
		||||
		const obj: Partial<ModelPropertiesValues<T, Shape>> = {};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +65,9 @@ export class ObjectType<Shape extends ModelShape<T>, T extends object> extends T
 | 
			
		|||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		if (typeof value !== "object" || Array.isArray(value))
 | 
			
		||||
			throw new InvalidTypeValueError(this, value, "value must be an object");
 | 
			
		||||
 | 
			
		||||
		// Creating an empty serialized object.
 | 
			
		||||
		const serializedObject: Partial<SerializedModel<T, Shape>> = {};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +87,9 @@ export class ObjectType<Shape extends ModelShape<T>, T extends object> extends T
 | 
			
		|||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		if (typeof value !== "object" || Array.isArray(value))
 | 
			
		||||
			throw new InvalidTypeValueError(this, value, "value must be an object");
 | 
			
		||||
 | 
			
		||||
		// Creating an empty serialized object.
 | 
			
		||||
		const serializedObject: Partial<SerializedModel<T, Shape>> = {};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -96,6 +106,12 @@ export class ObjectType<Shape extends ModelShape<T>, T extends object> extends T
 | 
			
		|||
 | 
			
		||||
	resetDiff(value: ModelPropertiesValues<T, Shape>|null|undefined)
 | 
			
		||||
	{
 | 
			
		||||
		if (value === undefined) return;
 | 
			
		||||
		if (value === null) return;
 | 
			
		||||
 | 
			
		||||
		if (typeof value !== "object" || Array.isArray(value))
 | 
			
		||||
			throw new InvalidTypeValueError(this, value, "value must be an object");
 | 
			
		||||
 | 
			
		||||
		// For each property, reset its diff.
 | 
			
		||||
		for (const property of this.properties)
 | 
			
		||||
			// keyof Shape is a subset of keyof T.
 | 
			
		||||
| 
						 | 
				
			
			@ -109,6 +125,11 @@ export class ObjectType<Shape extends ModelShape<T>, T extends object> extends T
 | 
			
		|||
		if (currentValue === undefined) return true; // Original value is not undefined.
 | 
			
		||||
		if (currentValue === null) return true; // Original value is not null.
 | 
			
		||||
 | 
			
		||||
		if (typeof originalValue !== "object" || Array.isArray(originalValue))
 | 
			
		||||
			throw new InvalidTypeValueError(this, originalValue, "value must be an object");
 | 
			
		||||
		if (typeof currentValue !== "object" || Array.isArray(currentValue))
 | 
			
		||||
			throw new InvalidTypeValueError(this, currentValue, "value must be an object");
 | 
			
		||||
 | 
			
		||||
		// If any property has changed, the value has changed.
 | 
			
		||||
		for (const property of this.properties)
 | 
			
		||||
			if (property.definition.type.hasChanged(originalValue?.[property.name as keyof T], currentValue?.[property.name as keyof T]))
 | 
			
		||||
| 
						 | 
				
			
			@ -124,6 +145,11 @@ export class ObjectType<Shape extends ModelShape<T>, T extends object> extends T
 | 
			
		|||
		if (currentValue === undefined) return true; // Original value is not undefined.
 | 
			
		||||
		if (currentValue === null) return true; // Original value is not null.
 | 
			
		||||
 | 
			
		||||
		if (typeof originalValue !== "object" || Array.isArray(originalValue))
 | 
			
		||||
			throw new InvalidTypeValueError(this, originalValue, "value must be an object");
 | 
			
		||||
		if (typeof currentValue !== "object" || Array.isArray(currentValue))
 | 
			
		||||
			throw new InvalidTypeValueError(this, currentValue, "value must be an object");
 | 
			
		||||
 | 
			
		||||
		// If any property has changed, the value has changed.
 | 
			
		||||
		for (const property of this.properties)
 | 
			
		||||
			if (property.definition.type.serializedHasChanged(originalValue?.[property.name], currentValue?.[property.name]))
 | 
			
		||||
| 
						 | 
				
			
			@ -137,6 +163,9 @@ export class ObjectType<Shape extends ModelShape<T>, T extends object> extends T
 | 
			
		|||
		// Handle NULL / undefined object.
 | 
			
		||||
		if (!value) return super.clone(value);
 | 
			
		||||
 | 
			
		||||
		if (typeof value !== "object" || Array.isArray(value))
 | 
			
		||||
			throw new InvalidTypeValueError(this, value, "value must be an object");
 | 
			
		||||
 | 
			
		||||
		// Initialize an empty object.
 | 
			
		||||
		const cloned: Partial<ModelPropertiesValues<T, Shape>> = {};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,12 +8,18 @@ export class StringType extends Type<string, string>
 | 
			
		|||
{
 | 
			
		||||
	deserialize(value: string|null|undefined): string|null|undefined
 | 
			
		||||
	{
 | 
			
		||||
		return value;
 | 
			
		||||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		return String(value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	serialize(value: string|null|undefined): string|null|undefined
 | 
			
		||||
	{
 | 
			
		||||
		return value;
 | 
			
		||||
		if (value === undefined) return undefined;
 | 
			
		||||
		if (value === null) return null;
 | 
			
		||||
 | 
			
		||||
		return String(value);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										15
									
								
								tests/errors.test.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								tests/errors.test.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
import {describe, expect, it} from "vitest";
 | 
			
		||||
import {InvalidTypeValueError, TypeError} from "../src/errors";
 | 
			
		||||
import {s} from "../src/library";
 | 
			
		||||
 | 
			
		||||
describe("errors", () => {
 | 
			
		||||
	it("tests type error", () => {
 | 
			
		||||
		expect((new TypeError(s.property.string().type)).message).toBe("Error in type StringType");
 | 
			
		||||
		expect((new TypeError(s.property.string().type, "test")).message).toBe("Error in type StringType: test");
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	it("tests invalid type value error", () => {
 | 
			
		||||
		expect((new InvalidTypeValueError(s.property.decimal().type, ["value"])).message).toBe("Error in type DecimalType: [\"value\"] is an invalid value");
 | 
			
		||||
		expect((new InvalidTypeValueError(s.property.decimal().type, ["value"], "test")).message).toBe("Error in type DecimalType: test");
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import {describe, expect, test} from "vitest";
 | 
			
		||||
import {ArrayType, s} from "../../../src/library";
 | 
			
		||||
import {ArrayType, InvalidTypeValueError, s} from "../../../src/library";
 | 
			
		||||
 | 
			
		||||
class TestModel
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -122,4 +122,16 @@ describe("array type", () => {
 | 
			
		|||
		expect(testProperty.type.clone(undefined)).toBe(undefined);
 | 
			
		||||
		expect(testProperty.type.clone(null)).toBe(null);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	test("invalid parameters types", () => {
 | 
			
		||||
		expect(() => testProperty.type.serialize({} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.deserialize({} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.serializeDiff({} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.resetDiff({} as any)).not.toThrow();
 | 
			
		||||
		expect(testProperty.type.hasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(testProperty.type.hasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(testProperty.type.serializedHasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(testProperty.type.serializedHasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(() => testProperty.type.clone({} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import {describe, expect, test} from "vitest";
 | 
			
		||||
import {BooleanType, s, StringType} from "../../../src/library";
 | 
			
		||||
import {BooleanType, s} from "../../../src/library";
 | 
			
		||||
 | 
			
		||||
describe("boolean type", () => {
 | 
			
		||||
	test("boolean type definition", () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -50,4 +50,19 @@ describe("boolean type", () => {
 | 
			
		|||
		s.property.boolean().type.resetDiff(undefined);
 | 
			
		||||
		s.property.boolean().type.resetDiff(null);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	test("invalid parameters types", () => {
 | 
			
		||||
		expect(s.property.boolean().type.serialize(1 as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.boolean().type.serialize(0 as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.boolean().type.deserialize(1 as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.boolean().type.deserialize(0 as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.boolean().type.serializeDiff(1 as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.boolean().type.serializeDiff(0 as any)).toBeFalsy();
 | 
			
		||||
		expect(() => s.property.boolean().type.resetDiff({} as any)).not.toThrow();
 | 
			
		||||
		expect(s.property.boolean().type.hasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.boolean().type.hasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.boolean().type.serializedHasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.boolean().type.serializedHasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.boolean().type.clone({} as any)).toStrictEqual({});
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import {describe, expect, test} from "vitest";
 | 
			
		||||
import {DateType, s} from "../../../src/library";
 | 
			
		||||
import {DateType, InvalidTypeValueError, s} from "../../../src/library";
 | 
			
		||||
 | 
			
		||||
describe("date type", () => {
 | 
			
		||||
	const testDate = new Date();
 | 
			
		||||
| 
						 | 
				
			
			@ -59,4 +59,16 @@ describe("date type", () => {
 | 
			
		|||
			expect(clonedPropertyValue).toEqual(propertyValue);
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	test("invalid parameters types", () => {
 | 
			
		||||
		expect(() => s.property.date().type.serialize({} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(s.property.date().type.deserialize({} as any).getTime()).toBe(NaN);
 | 
			
		||||
		expect(() => s.property.date().type.serializeDiff({} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.date().type.resetDiff({} as any)).not.toThrow();
 | 
			
		||||
		expect(s.property.date().type.hasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.date().type.hasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.date().type.serializedHasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.date().type.serializedHasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.date().type.clone({} as any)).toStrictEqual({});
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import {describe, expect, test} from "vitest";
 | 
			
		||||
import {DecimalType, s} from "../../../src/library";
 | 
			
		||||
import {DecimalType, InvalidTypeValueError, s} from "../../../src/library";
 | 
			
		||||
 | 
			
		||||
describe("decimal type", () => {
 | 
			
		||||
	test("decimal type definition", () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -44,4 +44,17 @@ describe("decimal type", () => {
 | 
			
		|||
		s.property.decimal().type.resetDiff(undefined);
 | 
			
		||||
		s.property.decimal().type.resetDiff(null);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	test("invalid parameters types", () => {
 | 
			
		||||
		expect(() => s.property.decimal().type.serialize({} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(s.property.decimal().type.deserialize({} as any)).toBe(NaN);
 | 
			
		||||
		expect(s.property.decimal().type.deserialize({} as any)).toBe(NaN);
 | 
			
		||||
		expect(() => s.property.decimal().type.serializeDiff({} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.decimal().type.resetDiff({} as any)).not.toThrow();
 | 
			
		||||
		expect(s.property.decimal().type.hasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.decimal().type.hasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.decimal().type.serializedHasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.decimal().type.serializedHasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.decimal().type.clone({} as any)).toStrictEqual({});
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import {describe, expect, test} from "vitest";
 | 
			
		||||
import {ModelType, s} from "../../../src/library";
 | 
			
		||||
import {InvalidTypeValueError, ModelType, s} from "../../../src/library";
 | 
			
		||||
 | 
			
		||||
class TestModel
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -104,4 +104,29 @@ describe("model type", () => {
 | 
			
		|||
		expect(s.property.model(testModel).type.clone(undefined)).toBe(undefined);
 | 
			
		||||
		expect(s.property.model(testModel).type.clone(null)).toBe(null);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	test("invalid parameters types", () => {
 | 
			
		||||
		expect(() => s.property.model(testModel).type.serialize(5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.deserialize(5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.serializeDiff(5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.resetDiff(5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.hasChanged(5 as any, 5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.serializedHasChanged(5 as any, 5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.clone(5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
 | 
			
		||||
		expect(() => s.property.model(testModel).type.serialize([] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.deserialize([] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.serializeDiff([] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.resetDiff([] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.hasChanged(testModel.model(new TestModel()).instance, [] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.serializedHasChanged({} as any, [] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.clone([] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
 | 
			
		||||
		expect(() => s.property.model(testModel).type.serialize(new class{} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.serializeDiff(new class{} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.resetDiff(new class{} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.model(testModel).type.hasChanged(testModel.model(new TestModel()).instance, new class{} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(s.property.model(testModel).type.serializedHasChanged({} as any, new class{} as any)).toBeFalsy();
 | 
			
		||||
		expect(() => s.property.model(testModel).type.clone(new class{} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import {describe, expect, test} from "vitest";
 | 
			
		||||
import {NumericType, s} from "../../../src/library";
 | 
			
		||||
import {InvalidTypeValueError, NumericType, s} from "../../../src/library";
 | 
			
		||||
 | 
			
		||||
describe("numeric type", () => {
 | 
			
		||||
	test("numeric type definition", () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -44,4 +44,16 @@ describe("numeric type", () => {
 | 
			
		|||
		s.property.numeric().type.resetDiff(undefined);
 | 
			
		||||
		s.property.numeric().type.resetDiff(null);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	test("invalid parameters types", () => {
 | 
			
		||||
		expect(() => s.property.numeric().type.serialize({} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.numeric().type.deserialize({} as any)).toThrowError(InvalidTypeValueError)
 | 
			
		||||
		expect(() => s.property.numeric().type.serializeDiff({} as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => s.property.numeric().type.resetDiff({} as any)).not.toThrow();
 | 
			
		||||
		expect(s.property.numeric().type.hasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.numeric().type.hasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.numeric().type.serializedHasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.numeric().type.serializedHasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.numeric().type.clone({} as any)).toStrictEqual({});
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import {describe, expect, test} from "vitest";
 | 
			
		||||
import {NumericType, ObjectType, s, StringType} from "../../../src/library";
 | 
			
		||||
import {InvalidTypeValueError, NumericType, ObjectType, s, StringType} from "../../../src/library";
 | 
			
		||||
 | 
			
		||||
describe("object type", () => {
 | 
			
		||||
	test("object type definition", () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -79,4 +79,22 @@ describe("object type", () => {
 | 
			
		|||
		expect(testProperty.type.clone(undefined)).toBe(undefined);
 | 
			
		||||
		expect(testProperty.type.clone(null)).toBe(null);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	test("invalid parameters types", () => {
 | 
			
		||||
		expect(() => testProperty.type.serialize(5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.deserialize(5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.serializeDiff(5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.resetDiff(5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.hasChanged(5 as any, 5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.serializedHasChanged(5 as any, 5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.clone(5 as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
 | 
			
		||||
		expect(() => testProperty.type.serialize([] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.deserialize([] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.serializeDiff([] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.resetDiff([] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.hasChanged({} as any, [] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.serializedHasChanged({} as any, [] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
		expect(() => testProperty.type.clone([] as any)).toThrowError(InvalidTypeValueError);
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,4 +44,20 @@ describe("string type", () => {
 | 
			
		|||
		s.property.string().type.resetDiff(undefined);
 | 
			
		||||
		s.property.string().type.resetDiff(null);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	test("invalid parameters types", () => {
 | 
			
		||||
		const testDate = new Date();
 | 
			
		||||
		expect(s.property.string().type.serialize({} as any)).toBe("[object Object]");
 | 
			
		||||
		expect(s.property.string().type.serialize(2120 as any)).toBe("2120");
 | 
			
		||||
		expect(s.property.string().type.serialize(testDate as any)).toBe(testDate.toString());
 | 
			
		||||
		expect(s.property.string().type.deserialize({} as any)).toBe("[object Object]");
 | 
			
		||||
		expect(s.property.string().type.deserialize(2120 as any)).toBe("2120");
 | 
			
		||||
		expect(s.property.string().type.serializeDiff({} as any)).toBe("[object Object]");
 | 
			
		||||
		expect(s.property.string().type.serializeDiff(2120 as any)).toBe("2120");
 | 
			
		||||
		expect(s.property.string().type.hasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.string().type.hasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.string().type.serializedHasChanged({} as any, {} as any)).toBeTruthy();
 | 
			
		||||
		expect(s.property.string().type.serializedHasChanged(false as any, false as any)).toBeFalsy();
 | 
			
		||||
		expect(s.property.string().type.clone({} as any)).toStrictEqual({});
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue