Moonshark/tests/fs.lua

456 lines
13 KiB
Lua

require("tests")
local fs = require("fs")
-- Test data
local test_content = "Hello, filesystem!\nThis is a test file.\n"
local test_dir = "test_fs_dir"
local test_file = fs.join(test_dir, "test.txt")
-- Clean up function
local function cleanup()
if fs.exists(test_file) then fs.remove(test_file) end
if fs.exists(test_dir) then fs.rmdir(test_dir) end
end
-- ======================================================================
-- SETUP AND CLEANUP
-- ======================================================================
-- Clean up before tests
cleanup()
-- ======================================================================
-- BASIC FILE OPERATIONS
-- ======================================================================
test("File Write and Read", function()
fs.mkdir(test_dir)
fs.write(test_file, test_content)
assert_equal(fs.exists(test_file), true)
assert_equal(fs.is_file(test_file), true)
assert_equal(fs.is_dir(test_file), false)
local content = fs.read(test_file)
assert_equal(content, test_content)
end)
test("File Size", function()
local size = fs.size(test_file)
assert_equal(size, #test_content)
assert_equal(fs.size("nonexistent.txt"), nil)
end)
test("File Append", function()
local additional = "Appended content.\n"
fs.append(test_file, additional)
local content = fs.read(test_file)
assert_equal(content, test_content .. additional)
end)
test("File Copy", function()
local copy_file = fs.join(test_dir, "copy.txt")
fs.copy(test_file, copy_file)
assert_equal(fs.exists(copy_file), true)
assert_equal(fs.read(copy_file), fs.read(test_file))
fs.remove(copy_file)
end)
test("File Move", function()
local move_file = fs.join(test_dir, "moved.txt")
local original_content = fs.read(test_file)
fs.move(test_file, move_file)
assert_equal(fs.exists(test_file), false)
assert_equal(fs.exists(move_file), true)
assert_equal(fs.read(move_file), original_content)
-- Move back for other tests
fs.move(move_file, test_file)
end)
test("File Lines", function()
local lines = fs.lines(test_file)
assert_equal(type(lines), "table")
assert(#lines >= 2, "should have multiple lines")
assert(string.find(lines[1], "Hello"), "first line should contain 'Hello'")
end)
test("File Touch", function()
local touch_file = fs.join(test_dir, "touched.txt")
fs.touch(touch_file)
assert_equal(fs.exists(touch_file), true)
assert_equal(fs.size(touch_file), 0)
fs.remove(touch_file)
end)
test("File Modification Time", function()
local mtime = fs.mtime(test_file)
assert_equal(type(mtime), "number")
assert(mtime > 0, "mtime should be positive")
-- Touch should update mtime
local old_mtime = mtime
fs.touch(test_file)
local new_mtime = fs.mtime(test_file)
assert(new_mtime >= old_mtime, "mtime should be updated")
end)
-- ======================================================================
-- DIRECTORY OPERATIONS
-- ======================================================================
test("Directory Creation and Removal", function()
local nested_dir = fs.join(test_dir, "nested", "deep")
fs.mkdir(nested_dir)
assert_equal(fs.exists(nested_dir), true)
assert_equal(fs.is_dir(nested_dir), true)
-- Clean up nested directories
fs.rmdir(fs.join(test_dir, "nested"))
end)
test("Directory Listing", function()
-- Create some test files
fs.write(fs.join(test_dir, "file1.txt"), "content1")
fs.write(fs.join(test_dir, "file2.log"), "content2")
fs.mkdir(fs.join(test_dir, "subdir"))
local entries = fs.list(test_dir)
assert_equal(type(entries), "table")
assert(#entries >= 3, "should have at least 3 entries")
-- Check entry structure
local found_file = false
for _, entry in ipairs(entries) do
assert_equal(type(entry.name), "string")
assert_equal(type(entry.is_dir), "boolean")
if entry.name == "file1.txt" then
found_file = true
assert_equal(entry.is_dir, false)
assert_equal(type(entry.size), "number")
end
end
assert_equal(found_file, true)
-- Test filtered listings
local files = fs.list_files(test_dir)
local dirs = fs.list_dirs(test_dir)
local names = fs.list_names(test_dir)
assert_equal(type(files), "table")
assert_equal(type(dirs), "table")
assert_equal(type(names), "table")
assert(#files > 0, "should have files")
assert(#dirs > 0, "should have directories")
-- Clean up
fs.remove(fs.join(test_dir, "file1.txt"))
fs.remove(fs.join(test_dir, "file2.log"))
fs.rmdir(fs.join(test_dir, "subdir"))
end)
-- ======================================================================
-- PATH OPERATIONS
-- ======================================================================
test("Path Join", function()
local path = fs.join("a", "b", "c", "file.txt")
assert(string.find(path, "file.txt"), "should contain filename")
local empty_path = fs.join()
assert_equal(type(empty_path), "string")
end)
test("Path Components", function()
local test_path = fs.join("home", "user", "documents", "file.txt")
local dir = fs.dirname(test_path)
local base = fs.basename(test_path)
local ext = fs.ext(test_path)
assert_equal(base, "file.txt")
assert_equal(ext, ".txt")
assert(string.find(dir, "documents"), "dirname should contain 'documents'")
end)
test("Path Split Extension", function()
local test_path = fs.join("home", "user", "file.tar.gz")
local dir, name, ext = fs.splitext(test_path)
assert_equal(name, "file.tar")
assert_equal(ext, ".gz")
assert(string.find(dir, "user"), "dir should contain 'user'")
end)
test("Path Absolute", function()
local abs_path = fs.abs(".")
assert_equal(type(abs_path), "string")
assert(#abs_path > 1, "absolute path should not be empty")
end)
test("Path Clean", function()
local messy_path = "./test/../test/./file.txt"
local clean_path = fs.clean(messy_path)
assert_equal(type(clean_path), "string")
assert(not string.find(clean_path, "%.%."), "should not contain '..'")
end)
test("Path Split", function()
local test_path = fs.join("home", "user", "file.txt")
local dir, file = fs.split(test_path)
assert_equal(file, "file.txt")
assert(string.find(dir, "user"), "dir should contain 'user'")
end)
-- ======================================================================
-- WORKING DIRECTORY
-- ======================================================================
test("Working Directory", function()
local original_cwd = fs.getcwd()
assert_equal(type(original_cwd), "string")
assert(#original_cwd > 0, "cwd should not be empty")
-- Test directory change
fs.chdir(test_dir)
local new_cwd = fs.getcwd()
assert(string.find(new_cwd, test_dir), "cwd should contain test_dir")
-- Change back
fs.chdir(original_cwd)
assert_equal(fs.getcwd(), original_cwd)
end)
-- ======================================================================
-- TEMPORARY FILES
-- ======================================================================
test("Temporary Files", function()
local temp_file = fs.tempfile("test_")
local temp_dir = fs.tempdir("test_")
assert_equal(type(temp_file), "string")
assert_equal(type(temp_dir), "string")
assert_equal(fs.exists(temp_file), true)
assert_equal(fs.exists(temp_dir), true)
assert_equal(fs.is_dir(temp_dir), true)
-- Clean up
fs.remove(temp_file)
fs.rmdir(temp_dir)
end)
-- ======================================================================
-- PATTERN MATCHING
-- ======================================================================
test("Glob Patterns", function()
-- Create test files for globbing
fs.write(fs.join(test_dir, "test1.txt"), "content")
fs.write(fs.join(test_dir, "test2.txt"), "content")
fs.write(fs.join(test_dir, "other.log"), "content")
local pattern = fs.join(test_dir, "*.txt")
local matches = fs.glob(pattern)
assert_equal(type(matches), "table")
assert(#matches >= 2, "should match txt files")
-- Clean up
fs.remove(fs.join(test_dir, "test1.txt"))
fs.remove(fs.join(test_dir, "test2.txt"))
fs.remove(fs.join(test_dir, "other.log"))
end)
test("Walk Directory", function()
-- Create nested structure
fs.mkdir(fs.join(test_dir, "sub1"))
fs.mkdir(fs.join(test_dir, "sub2"))
fs.write(fs.join(test_dir, "root.txt"), "content")
fs.write(fs.join(test_dir, "sub1", "nested.txt"), "content")
local files = fs.walk(test_dir)
assert_equal(type(files), "table")
assert(#files > 3, "should find multiple files and directories")
-- Clean up
fs.remove(fs.join(test_dir, "root.txt"))
fs.remove(fs.join(test_dir, "sub1", "nested.txt"))
fs.rmdir(fs.join(test_dir, "sub1"))
fs.rmdir(fs.join(test_dir, "sub2"))
end)
-- ======================================================================
-- UTILITY FUNCTIONS
-- ======================================================================
test("File Extension Functions", function()
local path = "document.pdf"
assert_equal(fs.extension(path), "pdf")
local new_path = fs.change_ext(path, "txt")
assert_equal(new_path, "document.txt")
local new_path2 = fs.change_ext(path, ".docx")
assert_equal(new_path2, "document.docx")
end)
test("Ensure Directory", function()
local ensure_dir = fs.join(test_dir, "ensure_test")
fs.ensure_dir(ensure_dir)
assert_equal(fs.exists(ensure_dir), true)
assert_equal(fs.is_dir(ensure_dir), true)
-- Should not error if already exists
fs.ensure_dir(ensure_dir)
fs.rmdir(ensure_dir)
end)
test("Human Readable Size", function()
local small_file = fs.join(test_dir, "small.txt")
fs.write(small_file, "test")
local size_str = fs.size_human(small_file)
assert_equal(type(size_str), "string")
assert(string.find(size_str, "B"), "should contain byte unit")
fs.remove(small_file)
end)
test("Safe Path Check", function()
assert_equal(fs.is_safe_path("safe/path.txt"), true)
assert_equal(fs.is_safe_path("../dangerous"), false)
assert_equal(fs.is_safe_path("/absolute/path"), false)
assert_equal(fs.is_safe_path("~/home/path"), false)
end)
test("Copy Tree", function()
-- Create source structure
local src_dir = fs.join(test_dir, "src")
local dst_dir = fs.join(test_dir, "dst")
fs.mkdir(src_dir)
fs.mkdir(fs.join(src_dir, "subdir"))
fs.write(fs.join(src_dir, "file1.txt"), "content1")
fs.write(fs.join(src_dir, "subdir", "file2.txt"), "content2")
fs.copytree(src_dir, dst_dir)
assert_equal(fs.exists(dst_dir), true)
assert_equal(fs.exists(fs.join(dst_dir, "file1.txt")), true)
assert_equal(fs.exists(fs.join(dst_dir, "subdir", "file2.txt")), true)
assert_equal(fs.read(fs.join(dst_dir, "file1.txt")), "content1")
-- Clean up
fs.rmdir(src_dir)
fs.rmdir(dst_dir)
end)
test("Find Files", function()
-- Create test files
fs.write(fs.join(test_dir, "find1.txt"), "content")
fs.write(fs.join(test_dir, "find2.txt"), "content")
fs.write(fs.join(test_dir, "other.log"), "content")
fs.mkdir(fs.join(test_dir, "subdir"))
fs.write(fs.join(test_dir, "subdir", "find3.txt"), "content")
local txt_files = fs.find(test_dir, "%.txt$", true)
assert_equal(type(txt_files), "table")
assert(#txt_files >= 3, "should find txt files recursively")
local txt_files_flat = fs.find(test_dir, "%.txt$", false)
assert(#txt_files_flat < #txt_files, "non-recursive should find fewer files")
-- Clean up
fs.remove(fs.join(test_dir, "find1.txt"))
fs.remove(fs.join(test_dir, "find2.txt"))
fs.remove(fs.join(test_dir, "other.log"))
fs.remove(fs.join(test_dir, "subdir", "find3.txt"))
fs.rmdir(fs.join(test_dir, "subdir"))
end)
test("Directory Tree", function()
-- Create test structure
fs.mkdir(fs.join(test_dir, "tree_test"))
fs.write(fs.join(test_dir, "tree_test", "file.txt"), "content")
fs.mkdir(fs.join(test_dir, "tree_test", "subdir"))
local tree = fs.tree(test_dir)
assert_equal(type(tree), "table")
assert_equal(tree.is_dir, true)
assert_equal(type(tree.children), "table")
assert(#tree.children > 0, "should have children")
-- Clean up
fs.remove(fs.join(test_dir, "tree_test", "file.txt"))
fs.rmdir(fs.join(test_dir, "tree_test", "subdir"))
fs.rmdir(fs.join(test_dir, "tree_test"))
end)
-- ======================================================================
-- ERROR HANDLING
-- ======================================================================
test("Error Handling", function()
-- Reading non-existent file
local success, err = pcall(fs.read, "nonexistent.txt")
assert_equal(false, success)
-- Writing to invalid path
local success2, err2 = pcall(fs.write, "/invalid/path/file.txt", "content")
assert_equal(false, success2)
-- Listing non-existent directory
local success3, err3 = pcall(fs.list, "nonexistent_dir")
assert_equal(false, success3)
end)
-- ======================================================================
-- PERFORMANCE TESTS
-- ======================================================================
test("Performance Test", function()
local large_content = string.rep("performance test data\n", 1000)
local perf_file = fs.join(test_dir, "performance.txt")
local start = os.clock()
fs.write(perf_file, large_content)
local write_time = os.clock() - start
start = os.clock()
local read_content = fs.read(perf_file)
local read_time = os.clock() - start
start = os.clock()
local lines = fs.lines(perf_file)
local lines_time = os.clock() - start
print(string.format(" Write %d bytes: %.3fs", #large_content, write_time))
print(string.format(" Read %d bytes: %.3fs", #read_content, read_time))
print(string.format(" Parse %d lines: %.3fs", #lines, lines_time))
assert_equal(read_content, large_content)
assert_equal(#lines, 1000)
fs.remove(perf_file)
end)
-- ======================================================================
-- CLEANUP
-- ======================================================================
cleanup()
summary()
test_exit()