feat: add NumberUtils class with safe number manipulation methods and comprehensive tests; enhance StringUtils with UUID and non-empty string validation

This commit is contained in:
Firman Ramdhani
2026-01-29 13:52:54 +07:00
parent a1db9b93e1
commit a2e317ca9e
4 changed files with 462 additions and 0 deletions
@@ -165,4 +165,77 @@ describe('StringUtils', () => {
expect(json).toBe('{"id":1,"name":"Product A"}');
});
});
// ==========================================
// 1. UUID Validation Tests
// ==========================================
describe('isUuid', () => {
// Sample UUID v4 yang valid
const validUuidV4 = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
// Sample UUID v4 uppercase
const validUuidUpper = 'F47AC10B-58CC-4372-A567-0E02B2C3D479';
it('should return true for a valid UUID v4 string', () => {
expect(StringUtils.isUuid(validUuidV4)).toBe(true);
});
it('should return true for uppercase UUID (case insensitive)', () => {
expect(StringUtils.isUuid(validUuidUpper)).toBe(true);
});
it('should return false for invalid UUID formats', () => {
// One character missing
expect(StringUtils.isUuid('f47ac10b-58cc-4372-a567-0e02b2c3d47')).toBe(false);
// Correct format but non-hex character (z)
expect(StringUtils.isUuid('z47ac10b-58cc-4372-a567-0e02b2c3d479')).toBe(false);
// No hyphens (-)
expect(StringUtils.isUuid('f47ac10b58cc4372a5670e02b2c3d479')).toBe(false);
// Plain random string
expect(StringUtils.isUuid('random-string-not-uuid')).toBe(false);
});
it('should return false for empty strings', () => {
expect(StringUtils.isUuid('')).toBe(false);
});
it('should return false for non-string types', () => {
expect(StringUtils.isUuid(null)).toBe(false);
expect(StringUtils.isUuid(undefined)).toBe(false);
expect(StringUtils.isUuid(12345)).toBe(false);
expect(StringUtils.isUuid({})).toBe(false);
});
});
// ==========================================
// 2. Non-Empty String Validation Tests
// ==========================================
describe('isNonEmptyString', () => {
it('should return true for standard strings', () => {
expect(StringUtils.isNonEmptyString('BRG-001')).toBe(true);
expect(StringUtils.isNonEmptyString('Hello World')).toBe(true);
});
it('should return true for strings with surrounding whitespace', () => {
// .trim() will remove spaces, but the remainder will still be > 0
expect(StringUtils.isNonEmptyString(' user123 ')).toBe(true);
});
it('should return false for empty strings', () => {
expect(StringUtils.isNonEmptyString('')).toBe(false);
});
it('should return false for strings containing only whitespace', () => {
// .trim() will make this string become "" (length 0)
expect(StringUtils.isNonEmptyString(' ')).toBe(false);
expect(StringUtils.isNonEmptyString('\t\n')).toBe(false);
});
it('should return false for non-string types', () => {
expect(StringUtils.isNonEmptyString(null)).toBe(false);
expect(StringUtils.isNonEmptyString(undefined)).toBe(false);
expect(StringUtils.isNonEmptyString(0)).toBe(false); // Angka 0 bukan string
expect(StringUtils.isNonEmptyString(true)).toBe(false);
expect(StringUtils.isNonEmptyString(['a'])).toBe(false);
});
});
});
+18
View File
@@ -57,6 +57,9 @@ interface IStringUtils {
export class StringUtils implements IStringUtils {
private readonly _value: string;
// Standard regex for UUIDs (v4, v5, etc.)
private static readonly UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
/* ----------------------------------------------------------------
* Constructor & Static Initializers
* ---------------------------------------------------------------- */
@@ -272,4 +275,19 @@ export class StringUtils implements IStringUtils {
toJSON(): string {
return this._value;
}
/**
* Validate the UUID format.
*/
static isUuid(value: unknown): boolean {
return typeof value === 'string' && this.UUID_REGEX.test(value);
}
/**
* Validation for IDs that are non-empty strings
* (Example: Item Code "BRG-001", Username, etc.)
*/
static isNonEmptyString(value: unknown): boolean {
return typeof value === 'string' && value.trim().length > 0;
}
}