282 lines
8.6 KiB
Lua
282 lines
8.6 KiB
Lua
|
-- Unit tests for validation utilities
|
||
|
local validation = require('notex.utils.validation')
|
||
|
|
||
|
describe("validation utilities", function()
|
||
|
|
||
|
describe("validate_value", function()
|
||
|
it("should validate string values", function()
|
||
|
local schema = {type = "string", required = true}
|
||
|
local valid, error = validation.validate_value("hello", schema)
|
||
|
assert.is_true(valid)
|
||
|
assert.equals("Validation passed", error)
|
||
|
end)
|
||
|
|
||
|
it("should reject required string when nil", function()
|
||
|
local schema = {type = "string", required = true}
|
||
|
local valid, error = validation.validate_value(nil, schema)
|
||
|
assert.is_false(valid)
|
||
|
assert.equals("Value is required", error)
|
||
|
end)
|
||
|
|
||
|
it("should validate string length constraints", function()
|
||
|
local schema = {type = "string", min_length = 5, max_length = 10}
|
||
|
|
||
|
-- Too short
|
||
|
local valid, error = validation.validate_value("hi", schema)
|
||
|
assert.is_false(valid)
|
||
|
assert.matches("too short", error)
|
||
|
|
||
|
-- Too long
|
||
|
valid, error = validation.validate_value("this is too long", schema)
|
||
|
assert.is_false(valid)
|
||
|
assert.matches("too long", error)
|
||
|
|
||
|
-- Just right
|
||
|
valid, error = validation.validate_value("perfect", schema)
|
||
|
assert.is_true(valid)
|
||
|
end)
|
||
|
|
||
|
it("should validate number values", function()
|
||
|
local schema = {type = "number", min_value = 1, max_value = 10}
|
||
|
|
||
|
-- Valid number
|
||
|
local valid, error = validation.validate_value(5, schema)
|
||
|
assert.is_true(valid)
|
||
|
|
||
|
-- Too small
|
||
|
valid, error = validation.validate_value(0, schema)
|
||
|
assert.is_false(valid)
|
||
|
assert.matches("too small", error)
|
||
|
|
||
|
-- Too large
|
||
|
valid, error = validation.validate_value(11, schema)
|
||
|
assert.is_false(valid)
|
||
|
assert.matches("too large", error)
|
||
|
end)
|
||
|
|
||
|
it("should validate boolean values", function()
|
||
|
local schema = {type = "boolean"}
|
||
|
|
||
|
-- Valid booleans
|
||
|
local valid, error = validation.validate_value(true, schema)
|
||
|
assert.is_true(valid)
|
||
|
|
||
|
valid, error = validation.validate_value(false, schema)
|
||
|
assert.is_true(valid)
|
||
|
|
||
|
-- String conversion
|
||
|
valid, error = validation.validate_value("true", schema)
|
||
|
assert.is_true(valid)
|
||
|
|
||
|
valid, error = validation.validate_value("false", schema)
|
||
|
assert.is_true(valid)
|
||
|
end)
|
||
|
|
||
|
it("should validate array values", function()
|
||
|
local schema = {type = "array", min_items = 2, max_items = 5}
|
||
|
|
||
|
-- Valid array
|
||
|
local valid, error = validation.validate_value({1, 2, 3}, schema)
|
||
|
assert.is_true(valid)
|
||
|
|
||
|
-- Too few items
|
||
|
valid, error = validation.validate_value({1}, schema)
|
||
|
assert.is_false(valid)
|
||
|
assert.matches("too short", error)
|
||
|
|
||
|
-- Too many items
|
||
|
valid, error = validation.validate_value({1, 2, 3, 4, 5, 6}, schema)
|
||
|
assert.is_false(valid)
|
||
|
assert.matches("too long", error)
|
||
|
end)
|
||
|
|
||
|
it("should validate object values", function()
|
||
|
local schema = {
|
||
|
type = "object",
|
||
|
required_fields = {"name"},
|
||
|
field_types = {
|
||
|
name = {type = "string"},
|
||
|
age = {type = "number"}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-- Valid object
|
||
|
local valid, error = validation.validate_value({name = "John", age = 30}, schema)
|
||
|
assert.is_true(valid)
|
||
|
|
||
|
-- Missing required field
|
||
|
valid, error = validation.validate_value({age = 30}, schema)
|
||
|
assert.is_false(valid)
|
||
|
assert.matches("Missing required field", error)
|
||
|
|
||
|
-- Invalid field type
|
||
|
valid, error = validation.validate_value({name = 123, age = 30}, schema)
|
||
|
assert.is_false(valid)
|
||
|
assert.matches("Field 'name' invalid", error)
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
describe("validate_document_properties", function()
|
||
|
it("should validate document properties against schema", function()
|
||
|
local schema_definition = {
|
||
|
title = {type = "string", required = true},
|
||
|
status = {type = "string", enum = {"draft", "published"}},
|
||
|
priority = {type = "number", min_value = 1, max_value = 5}
|
||
|
}
|
||
|
|
||
|
local properties = {
|
||
|
title = "Test Document",
|
||
|
status = "draft",
|
||
|
priority = 3
|
||
|
}
|
||
|
|
||
|
local valid, result = validation.validate_document_properties(properties, schema_definition)
|
||
|
assert.is_true(valid)
|
||
|
assert.equals(0, #result.errors)
|
||
|
end)
|
||
|
|
||
|
it("should return errors for invalid properties", function()
|
||
|
local schema_definition = {
|
||
|
title = {type = "string", required = true},
|
||
|
status = {type = "string", enum = {"draft", "published"}}
|
||
|
}
|
||
|
|
||
|
local properties = {
|
||
|
status = "invalid_status" -- Missing required title, invalid status
|
||
|
}
|
||
|
|
||
|
local valid, result = validation.validate_document_properties(properties, schema_definition)
|
||
|
assert.is_false(valid)
|
||
|
assert.is_true(#result.errors > 0)
|
||
|
end)
|
||
|
|
||
|
it("should include warnings for unknown properties", function()
|
||
|
local schema_definition = {
|
||
|
title = {type = "string", required = true}
|
||
|
}
|
||
|
|
||
|
local properties = {
|
||
|
title = "Test Document",
|
||
|
unknown_property = "value"
|
||
|
}
|
||
|
|
||
|
local valid, result = validation.validate_document_properties(properties, schema_definition)
|
||
|
assert.is_true(valid)
|
||
|
assert.is_true(#result.warnings > 0)
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
describe("validate_query_params", function()
|
||
|
it("should validate query parameters", function()
|
||
|
local allowed_params = {
|
||
|
limit = {type = "number", min_value = 1, max_value = 100},
|
||
|
sort = {type = "string", enum = {"asc", "desc"}},
|
||
|
filter = {type = "string", required = false}
|
||
|
}
|
||
|
|
||
|
local params = {
|
||
|
limit = 10,
|
||
|
sort = "asc"
|
||
|
}
|
||
|
|
||
|
local valid, errors = validation.validate_query_params(params, allowed_params)
|
||
|
assert.is_true(valid)
|
||
|
assert.equals(0, #errors)
|
||
|
end)
|
||
|
|
||
|
it("should reject unknown parameters", function()
|
||
|
local allowed_params = {
|
||
|
limit = {type = "number"}
|
||
|
}
|
||
|
|
||
|
local params = {
|
||
|
limit = 10,
|
||
|
unknown = "value"
|
||
|
}
|
||
|
|
||
|
local valid, errors = validation.validate_query_params(params, allowed_params)
|
||
|
assert.is_false(valid)
|
||
|
assert.is_true(#errors > 0)
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
describe("sanitize_input", function()
|
||
|
it("should remove dangerous characters", function()
|
||
|
local input = '<script>alert("xss")</script>'
|
||
|
local sanitized = validation.sanitize_input(input)
|
||
|
assert.equals('scriptalertxss/script', sanitized)
|
||
|
end)
|
||
|
|
||
|
it("should limit length", function()
|
||
|
local input = string.rep("a", 100)
|
||
|
local sanitized = validation.sanitize_input(input, {max_length = 10})
|
||
|
assert.equals(10, #sanitized)
|
||
|
end)
|
||
|
|
||
|
it("should trim whitespace", function()
|
||
|
local input = " hello world "
|
||
|
local sanitized = validation.sanitize_input(input)
|
||
|
assert.equals("hello world", sanitized)
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
describe("validate_file_path", function()
|
||
|
it("should validate safe file paths", function()
|
||
|
local valid, error = validation.validate_file_path("/home/user/document.md")
|
||
|
assert.is_true(valid)
|
||
|
end)
|
||
|
|
||
|
it("should reject paths with invalid characters", function()
|
||
|
local valid, error = validation.validate_file_path('file<name>.md')
|
||
|
assert.is_false(valid)
|
||
|
assert.matches("Invalid characters", error)
|
||
|
end)
|
||
|
|
||
|
it("should reject directory traversal", function()
|
||
|
local valid, error = validation.validate_file_path("../../../etc/passwd")
|
||
|
assert.is_false(valid)
|
||
|
assert.matches("Directory traversal", error)
|
||
|
end)
|
||
|
|
||
|
it("should reject empty paths", function()
|
||
|
local valid, error = validation.validate_file_path("")
|
||
|
assert.is_false(valid)
|
||
|
assert.equals("Empty file path", error)
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
describe("create_schema", function()
|
||
|
it("should create validation schema", function()
|
||
|
local schema = validation.create_schema("test_field", {
|
||
|
type = "string",
|
||
|
required = true,
|
||
|
min_length = 5
|
||
|
})
|
||
|
|
||
|
assert.equals("test_field", schema.field_name)
|
||
|
assert.equals("string", schema.type)
|
||
|
assert.is_true(schema.required)
|
||
|
assert.equals(5, schema.min_length)
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
describe("create_validation_summary", function()
|
||
|
it("should create validation summary", function()
|
||
|
local results = {
|
||
|
{valid = true},
|
||
|
{valid = false, errors = {"Error 1"}},
|
||
|
{valid = false, errors = {"Error 2", "Error 3"}, warnings = {"Warning 1"}},
|
||
|
{valid = true, warnings = {"Warning 2"}}
|
||
|
}
|
||
|
|
||
|
local summary = validation.create_validation_summary(results)
|
||
|
|
||
|
assert.equals(4, summary.total)
|
||
|
assert.equals(2, summary.valid)
|
||
|
assert.equals(2, summary.invalid)
|
||
|
assert.equals(3, #summary.errors)
|
||
|
assert.equals(2, #summary.warnings)
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
end)
|