Repository: icebob/fastest-validator
Pull request #55 (2019-01-28 12:45:30)

add `uuid` rule fix#43
Add and check all tests.
Supports rule all versions UUID 1-5


Patch:
diff --git a/examples/full.js b/examples/full.js
index 55758f3..15441f5 100644
--- a/examples/full.js
+++ b/examples/full.js
@@ -35,6 +35,8 @@ const schema = {
 	status: "boolean",
 	age: { type: "number", min: 18, max: 100, convert: true },
 	apikey: "forbidden",
+	uuidv4: { type: "uuid", version: 4 },
+	uuid: "uuid",
 	action: "function",
 	created: "date"
 };
@@ -81,6 +83,8 @@ const obj = {
 	status: true,
 	age: "28",
 	apikey: null,
+	uuidv4: "10ba038e-48da-487b-96e8-8d3b99b6d18a",
+	uuid: "10ba038e-48da-487b-96e8-8d3b99b6d18a",
 	action: () => {},
 	created: new Date()
 };
diff --git a/lib/messages.js b/lib/messages.js
index cef228b..4e2e54b 100644
--- a/lib/messages.js
+++ b/lib/messages.js
@@ -24,7 +24,7 @@ module.exports = {
 	numberInteger: "The '{field}' field must be an integer!",
 	numberPositive: "The '{field}' field must be a positive number!",
 	numberNegative: "The '{field}' field must be a negative number!",
-	
+
 	array: "The '{field}' field must be an array!",
 	arrayEmpty: "The '{field}' field must not be an empty array!",
 	arrayMin: "The '{field}' field must contain at least {expected} items!",
@@ -42,10 +42,13 @@ module.exports = {
 	dateMax: "The '{field}' field must be less than or equal to {expected}!",
 
 	forbidden: "The '{field}' field is forbidden!",
-	
+
 	email: "The '{field}' field must be a valid e-mail!",
 
 	url: "The '{field}' field must be a valid URL!",
 
 	enumValue: "The '{field} field value '{expected}' does not match any of the allowed values!",
+
+	uuid: "The {field} field must be a valid UUID",
+	uuidVersion: "The {field} field must be a valid version provided",
 };
\ No newline at end of file
diff --git a/lib/rules/uuid.js b/lib/rules/uuid.js
new file mode 100644
index 0000000..2209825
--- /dev/null
+++ b/lib/rules/uuid.js
@@ -0,0 +1,26 @@
+"use strict";
+
+const PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
+
+module.exports = function checkUUID(value, schema) {
+	if (typeof value !== "string")
+		return this.makeError("string");
+
+	value = value.toLowerCase();
+	if (!PATTERN.test(value))
+		return this.makeError("uuid");
+
+	const version = value.charAt(14)|0;
+	if(schema.version && schema.version !== version)
+		return this.makeError("uuidVersion", schema.version, version);
+
+	switch (version) {
+	case 1:
+	case 2:
+		return true;
+	case 3:
+	case 4:
+	case 5:
+		return ["8", "9", "a", "b"].indexOf(value.charAt(19)) !== -1 || this.makeError("uuid");
+	}
+};
\ No newline at end of file


Test patch:
diff --git a/test/messages.spec.js b/test/messages.spec.js
index 45d8c5d..ae6aabb 100644
--- a/test/messages.spec.js
+++ b/test/messages.spec.js
@@ -39,6 +39,8 @@ describe("Test Messages", () => {
 		expect(msg.forbidden).toBeDefined();
 		expect(msg.email).toBeDefined();
 		expect(msg.url).toBeDefined();
+		expect(msg.uuid).toBeDefined();
+		expect(msg.uuidVersion).toBeDefined();
 
 	});
 
diff --git a/test/rules/uuid.spec.js b/test/rules/uuid.spec.js
new file mode 100644
index 0000000..96b8b31
--- /dev/null
+++ b/test/rules/uuid.spec.js
@@ -0,0 +1,63 @@
+"use strict";
+
+const Validator = require("../../lib/validator");
+const fn = require("../../lib/rules/uuid");
+
+const v = new Validator();
+const check = fn.bind(v);
+
+describe("Test checkUUID", () => {
+
+	it("should check type of value", () => {
+		const uuid = {type: "uuid"};
+		const err = {type: "uuid"};
+		const errString = {type: "string"};
+
+		expect(check(null, uuid)).toEqual(errString);
+		expect(check(undefined, uuid)).toEqual(errString);
+		expect(check(0, uuid)).toEqual(errString);
+		expect(check(1, uuid)).toEqual(errString);
+		expect(check("", uuid)).toEqual(err);
+		expect(check("true", uuid)).toEqual(err);
+		expect(check([], uuid)).toEqual(errString);
+		expect(check({}, uuid)).toEqual(errString);
+		expect(check(false, uuid)).toEqual(errString);
+		expect(check(true, uuid)).toEqual(errString);
+		expect(check("00000000-0000-0000-0000-000000000000", uuid)).toEqual(err);
+		expect(check("1234567-1234-1234-1234-1234567890ab", uuid)).toEqual(err);
+		expect(check("12345678-1234-1234-1234-1234567890ab", uuid)).toEqual(true);
+	});
+
+	it("check invalid version", () => {
+		const err = {type: "uuid"};
+		const v1 = {type: "uuid", version: 1};
+		const v2 = {type: "uuid", version: 2};
+		const v3 = {type: "uuid", version: 3};
+		const v4 = {type: "uuid", version: 4};
+		const v5 = {type: "uuid", version: 5};
+
+		expect(check("00000000-0000-7000-0000-000000000000", err)).toEqual(err);
+		expect(check("fdda765f-fc57-5604-c269-52a7df8164ec", v5)).toEqual(err);
+		expect(check("9a7b330a-a736-51e5-af7f-feaf819cdc9f", v1)).toEqual({"actual": 5, "expected": 1, "type": "uuidVersion"});
+		expect(check("9a7b330a-a736-51e5-af7f-feaf819cdc9f", v1)).toEqual({"actual": 5, "expected": 1, "type": "uuidVersion"});
+		expect(check("9a7b330a-a736-41e5-af7f-feaf819cdc9f", v2)).toEqual({"actual": 4, "expected": 2, "type": "uuidVersion"});
+		expect(check("9a7b330a-a736-41e5-af7f-feaf819cdc9f", v3)).toEqual({"actual": 4, "expected": 3, "type": "uuidVersion"});
+		expect(check("9a7b330a-a736-21e5-af7f-feaf819cdc9f", v4)).toEqual({"actual": 2, "expected": 4, "type": "uuidVersion"});
+		expect(check("9a7b330a-a736-11e5-af7f-feaf819cdc9f", v5)).toEqual({"actual": 1, "expected": 5, "type": "uuidVersion"});
+	});
+
+	it("check valid version", () => {
+		const v1 = {type: "uuid", version: 1};
+		const v2 = {type: "uuid", version: 2};
+		const v3 = {type: "uuid", version: 3};
+		const v4 = {type: "uuid", version: 4};
+		const v5 = {type: "uuid", version: 5};
+
+		expect(check("45745c60-7b1a-11e8-9c9c-2d42b21b1a3e", v1)).toEqual(true);
+		expect(check("9a7b330a-a736-21e5-af7f-feaf819cdc9f", v2)).toEqual(true);
+		expect(check("9125a8dc-52ee-365b-a5aa-81b0b3681cf6", v3)).toEqual(true);
+		expect(check("10ba038e-48da-487b-96e8-8d3b99b6d18a", v4)).toEqual(true);
+		expect(check("fdda765f-fc57-5604-a269-52a7df8164ec", v5)).toEqual(true);
+
+	});
+});