Files
FlexLove/testing/__tests__/path_validation_test.lua
2025-11-14 21:54:01 -05:00

282 lines
8.8 KiB
Lua

-- Test suite for path validation functions
-- Tests sanitizePath, isPathSafe, validatePath, getFileExtension, hasAllowedExtension
package.path = package.path .. ";./?.lua;./modules/?.lua"
-- Load love stub before anything else
require("testing.loveStub")
local luaunit = require("testing.luaunit")
local utils = require("modules.utils")
-- Test suite for sanitizePath
TestSanitizePath = {}
function TestSanitizePath:testSanitizePath_NilInput()
local result = utils.sanitizePath(nil)
luaunit.assertEquals(result, "")
end
function TestSanitizePath:testSanitizePath_EmptyString()
local result = utils.sanitizePath("")
luaunit.assertEquals(result, "")
end
function TestSanitizePath:testSanitizePath_Whitespace()
local result = utils.sanitizePath(" /path/to/file ")
luaunit.assertEquals(result, "/path/to/file")
end
function TestSanitizePath:testSanitizePath_Backslashes()
local result = utils.sanitizePath("C:\\path\\to\\file")
luaunit.assertEquals(result, "C:/path/to/file")
end
function TestSanitizePath:testSanitizePath_DuplicateSlashes()
local result = utils.sanitizePath("/path//to///file")
luaunit.assertEquals(result, "/path/to/file")
end
function TestSanitizePath:testSanitizePath_TrailingSlash()
local result = utils.sanitizePath("/path/to/dir/")
luaunit.assertEquals(result, "/path/to/dir")
-- Root should keep trailing slash
result = utils.sanitizePath("/")
luaunit.assertEquals(result, "/")
end
function TestSanitizePath:testSanitizePath_MixedIssues()
local result = utils.sanitizePath(" C:\\path\\\\to///file.txt ")
luaunit.assertEquals(result, "C:/path/to/file.txt")
end
-- Test suite for isPathSafe
TestIsPathSafe = {}
function TestIsPathSafe:testIsPathSafe_EmptyPath()
local safe, reason = utils.isPathSafe("")
luaunit.assertFalse(safe)
luaunit.assertStrContains(reason, "empty")
end
function TestIsPathSafe:testIsPathSafe_NilPath()
local safe, reason = utils.isPathSafe(nil)
luaunit.assertFalse(safe)
luaunit.assertNotNil(reason)
end
function TestIsPathSafe:testIsPathSafe_ParentDirectory()
local safe, reason = utils.isPathSafe("../etc/passwd")
luaunit.assertFalse(safe)
luaunit.assertStrContains(reason, "..")
end
function TestIsPathSafe:testIsPathSafe_MultipleParentDirectories()
local safe, reason = utils.isPathSafe("../../../../../../etc/passwd")
luaunit.assertFalse(safe)
luaunit.assertStrContains(reason, "..")
end
function TestIsPathSafe:testIsPathSafe_HiddenParentDirectory()
local safe, reason = utils.isPathSafe("/path/to/../../../etc/passwd")
luaunit.assertFalse(safe)
luaunit.assertStrContains(reason, "..")
end
function TestIsPathSafe:testIsPathSafe_NullBytes()
local safe, reason = utils.isPathSafe("/path/to/file\0.txt")
luaunit.assertFalse(safe)
luaunit.assertStrContains(reason, "null")
end
function TestIsPathSafe:testIsPathSafe_EncodedTraversal()
local safe, reason = utils.isPathSafe("/path/%2e%2e/file")
luaunit.assertFalse(safe)
luaunit.assertStrContains(reason, "encoded")
end
function TestIsPathSafe:testIsPathSafe_LegitimatePathNoBaseDir()
local safe, reason = utils.isPathSafe("/themes/default.lua")
luaunit.assertTrue(safe)
luaunit.assertNil(reason)
end
function TestIsPathSafe:testIsPathSafe_LegitimatePathWithBaseDir()
local safe, reason = utils.isPathSafe("/allowed/themes/default.lua", "/allowed")
luaunit.assertTrue(safe)
luaunit.assertNil(reason)
end
function TestIsPathSafe:testIsPathSafe_RelativePathWithBaseDir()
local safe, reason = utils.isPathSafe("themes/default.lua", "/allowed")
luaunit.assertTrue(safe)
luaunit.assertNil(reason)
end
function TestIsPathSafe:testIsPathSafe_OutsideBaseDir()
local safe, reason = utils.isPathSafe("/other/themes/default.lua", "/allowed")
luaunit.assertFalse(safe)
luaunit.assertStrContains(reason, "outside")
end
-- Test suite for validatePath
TestValidatePath = {}
function TestValidatePath:testValidatePath_EmptyPath()
local valid, err = utils.validatePath("")
luaunit.assertFalse(valid)
luaunit.assertStrContains(err, "empty")
end
function TestValidatePath:testValidatePath_NilPath()
local valid, err = utils.validatePath(nil)
luaunit.assertFalse(valid)
luaunit.assertStrContains(err, "empty")
end
function TestValidatePath:testValidatePath_TooLong()
local longPath = string.rep("a", 5000)
local valid, err = utils.validatePath(longPath, { maxLength = 100 })
luaunit.assertFalse(valid)
luaunit.assertStrContains(err, "maximum length")
end
function TestValidatePath:testValidatePath_TraversalAttack()
local valid, err = utils.validatePath("../../../etc/passwd")
luaunit.assertFalse(valid)
luaunit.assertNotNil(err)
end
function TestValidatePath:testValidatePath_AllowedExtension()
local valid, err = utils.validatePath("theme.lua", { allowedExtensions = { "lua", "txt" } })
luaunit.assertTrue(valid)
luaunit.assertNil(err)
end
function TestValidatePath:testValidatePath_DisallowedExtension()
local valid, err = utils.validatePath("script.exe", { allowedExtensions = { "lua", "txt" } })
luaunit.assertFalse(valid)
luaunit.assertStrContains(err, "not allowed")
end
function TestValidatePath:testValidatePath_NoExtension()
local valid, err = utils.validatePath("README", { allowedExtensions = { "lua", "txt" } })
luaunit.assertFalse(valid)
luaunit.assertStrContains(err, "no file extension")
end
function TestValidatePath:testValidatePath_CaseInsensitiveExtension()
local valid, err = utils.validatePath("Theme.LUA", { allowedExtensions = { "lua" } })
luaunit.assertTrue(valid)
luaunit.assertNil(err)
end
function TestValidatePath:testValidatePath_WithBaseDir()
local valid, err = utils.validatePath("themes/default.lua", { baseDir = "/allowed" })
luaunit.assertTrue(valid)
luaunit.assertNil(err)
end
function TestValidatePath:testValidatePath_OutsideBaseDir()
local valid, err = utils.validatePath("/other/theme.lua", { baseDir = "/allowed" })
luaunit.assertFalse(valid)
luaunit.assertStrContains(err, "outside")
end
-- Test suite for getFileExtension
TestGetFileExtension = {}
function TestGetFileExtension:testGetFileExtension_SimpleExtension()
local ext = utils.getFileExtension("file.txt")
luaunit.assertEquals(ext, "txt")
end
function TestGetFileExtension:testGetFileExtension_MultipleDotsInPath()
local ext = utils.getFileExtension("/path/to/file.name.txt")
luaunit.assertEquals(ext, "txt")
end
function TestGetFileExtension:testGetFileExtension_NoExtension()
local ext = utils.getFileExtension("README")
luaunit.assertNil(ext)
end
function TestGetFileExtension:testGetFileExtension_NilPath()
local ext = utils.getFileExtension(nil)
luaunit.assertNil(ext)
end
function TestGetFileExtension:testGetFileExtension_CaseSensitive()
local ext = utils.getFileExtension("File.TXT")
luaunit.assertEquals(ext, "txt") -- Should be lowercase
end
function TestGetFileExtension:testGetFileExtension_LongExtension()
local ext = utils.getFileExtension("archive.tar.gz")
luaunit.assertEquals(ext, "gz")
end
-- Test suite for hasAllowedExtension
TestHasAllowedExtension = {}
function TestHasAllowedExtension:testHasAllowedExtension_Allowed()
local allowed = utils.hasAllowedExtension("file.txt", { "txt", "lua" })
luaunit.assertTrue(allowed)
end
function TestHasAllowedExtension:testHasAllowedExtension_NotAllowed()
local allowed = utils.hasAllowedExtension("file.exe", { "txt", "lua" })
luaunit.assertFalse(allowed)
end
function TestHasAllowedExtension:testHasAllowedExtension_CaseInsensitive()
local allowed = utils.hasAllowedExtension("File.TXT", { "txt", "lua" })
luaunit.assertTrue(allowed)
end
function TestHasAllowedExtension:testHasAllowedExtension_NoExtension()
local allowed = utils.hasAllowedExtension("README", { "txt", "lua" })
luaunit.assertFalse(allowed)
end
function TestHasAllowedExtension:testHasAllowedExtension_EmptyArray()
local allowed = utils.hasAllowedExtension("file.txt", {})
luaunit.assertFalse(allowed)
end
-- Test suite for security scenarios
TestPathSecurity = {}
function TestPathSecurity:testPathSecurity_WindowsTraversal()
local safe = utils.isPathSafe("..\\..\\..\\windows\\system32")
luaunit.assertFalse(safe)
end
function TestPathSecurity:testPathSecurity_MixedSeparators()
local safe = utils.isPathSafe("../path\\to/../file")
luaunit.assertFalse(safe)
end
function TestPathSecurity:testPathSecurity_DoubleEncodedTraversal()
local safe = utils.isPathSafe("%252e%252e%252f")
luaunit.assertFalse(safe)
end
function TestPathSecurity:testPathSecurity_LegitimateFileWithDots()
-- Files with dots in name should be OK (not ..)
local safe = utils.isPathSafe("/path/to/file.backup.txt")
luaunit.assertTrue(safe)
end
function TestPathSecurity:testPathSecurity_HiddenFiles()
-- Hidden files (starting with .) should be OK
local safe = utils.isPathSafe("/path/to/.hidden")
luaunit.assertTrue(safe)
end
-- Run tests if this file is executed directly
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end