-- -- Tests for the system module -- local io = require 'io' local system = require 'system' local tasty = require 'tasty' local group = tasty.test_group local test = tasty.test_case local assert = tasty.assert --- helper function, combining with_wd and with_tmpdir function in_tmpdir (callback) return function () system.with_tmpdir('test-sytem-tmpdir', function (tmpdir) system.with_wd(tmpdir, callback) end) end end --- dummy string for testing local token = 'Banana' --- check if token can be written into a file in given directory; returns the --- content of this file. function write_read_token (dir, filename) local filename = string.format('%s/%s', dir, 'foo.txt') local fh = io.open(filename, 'w') fh:write(token .. '\n') fh:close() return io.open(filename):read '*l' end -- Check existence static fields return { group 'static fields' { test('arch', function () assert.are_equal(type(system.arch), 'string') end), test('compiler_name', function () assert.are_equal(type(system.compiler_name), 'string') end), test('compiler_version', function () assert.are_equal(type(system.compiler_version), 'table') end), test('cputime_precision', function () assert.are_equal(type(system.cputime_precision), 'number') end), test('os', function () assert.are_equal(type(system.os), 'string') end), }, group 'copy' { test('copys the file', in_tmpdir(function () local content = 'Це тестовий контент.' local fh = io.open('a.txt', 'w') fh:write(content) fh:close() system.cp('a.txt', 'b.txt') assert.are_equal(content, io.open('b.txt'):read('a')) end)) }, group 'cputime' { test('returns a number', function () assert.are_equal(type(system.cputime()), 'number') end), }, group 'environment' { test('getenv returns same result as os.getenv', function () assert.are_equal(system.getenv 'PATH', os.getenv 'PATH') end), test('setenv sets environment values', function () system.setenv('HSLUA_SYSTEM_MODULE', 'test') -- apparently this works differently on Windows. local getenv = system.os == 'mingw32' and system.getenv or os.getenv assert.are_equal(getenv 'HSLUA_SYSTEM_MODULE', 'test') end), }, group 'getwd' { test('returns a string', function () assert.are_equal(type(system.getwd()), 'string') end) }, group 'env' { test('returns a table', function () assert.are_equal(type(system.env()), 'table') end) }, group 'exists' { test('returns `false` if the path does not exist', in_tmpdir(function () -- the temporary dir should be empty assert.is_falsy(system.exists('does-not-exist.txt')) end)), test('returns `true` if the path does not exist', in_tmpdir(function () io.open('README.md', 'w'):close() assert.is_truthy(system.exists('README.md')) end)), test('returns `false` for non-existing files', in_tmpdir(function () assert.is_falsy(system.exists('README.md', 'file')) end)), test('returns `true` for existing files', in_tmpdir(function () io.open('README.md', 'w'):close() assert.is_truthy(system.exists('README.md', 'file')) end)), test('returns `false` for missing directories', in_tmpdir(function () assert.is_falsy(system.exists('folder', 'directory')) end)), test('returns `true` for existing directories', in_tmpdir(function () system.mkdir 'folder' assert.is_truthy(system.exists('folder', 'directory')) end)), test('returns `false` for missing directories', in_tmpdir(function () assert.is_falsy(system.exists('folder', 'directory')) end)), test('returns `false` for file when checking for dir', in_tmpdir(function () io.open('folder', 'w'):close() assert.is_falsy(system.exists('folder', 'directory')) end)), test('returns `true` for dir when checking for file', in_tmpdir(function () system.mkdir 'README.md' assert.is_falsy(system.exists('README.md', 'file')) end)), test('errors for unknown type', in_tmpdir(function () assert.error_matches( function () system.exists('x', 'device') end, 'Unsupported filesystem object' ) end)), }, group 'ls' { test('returns a table', function () assert.are_equal(type(system.ls('.')), 'table') end), test('lists files in directory', in_tmpdir(function () io.open('README.org', 'w'):close() assert.are_same(system.ls '.', {'README.org'}) end)), test('argument defaults to `.`', function () assert.are_equal(#system.ls('.'), #system.ls()) end), test('fails when arg is not a directory', function () assert.error_matches( function () system.ls('thisdoesnotexist') end, 'thisdoesnotexist' ) assert.error_matches( function () system.ls('README.md') end, 'README%.md' ) end) }, group 'mkdir' { test('create directory', in_tmpdir(function () system.mkdir 'foo' assert.are_equal((system.ls())[1], 'foo') end)), test('create nested directories', in_tmpdir(function () system.mkdir('foo/bar', true) assert.are_equal((system.ls())[1], 'foo') assert.are_equal((system.ls 'foo')[1], 'bar') end)), test('cannot create existing directory', in_tmpdir(function () assert.error_matches(function () system.mkdir '.' end, '%.') end)), test('optionally ignores existing directories', in_tmpdir(function () system.mkdir 'foo' system.mkdir('foo', true) end)), test('normal operation', in_tmpdir(function () system.mkdir 'foo' end)), }, group 'read_file' { test('reads the contents of a file', in_tmpdir(function () local contents = '# Topic\n\nSome contents.\n' local filename = 'my-test.md' local fh = io.open(filename, 'wb') fh:write(contents) fh:close() assert.are_equal(system.read_file(filename), contents) end)), test('can read non-UTF-8 binary data', in_tmpdir(function () local contents = table.concat({ 'Valid ASCII: a', 'Valid 2 Octet Sequence: "\xc3\xb1"', 'Invalid 2 Octet Sequence: "\xc3\x28"', 'Invalid Sequence Identifier: "\xa0\xa1"', 'Valid 3 Octet Sequence: "\xe2\x82\xa1"', 'Invalid 3 Octet Sequence (in 2nd Octet): "\xe2\x28\xa1"', 'Invalid 3 Octet Sequence (in 3rd Octet): "\xe2\x82\x28"', 'Valid 4 Octet Sequence: "\xf0\x90\x8c\xbc"', 'Invalid 4 Octet Sequence (in 2nd Octet): "\xf0\x28\x8c\xbc"', 'Invalid 4 Octet Sequence (in 3rd Octet): "\xf0\x90\x28\xbc"', 'Invalid 4 Octet Sequence (in 4th Octet): "\xf0\x28\x8c\x28"', }, '\n') local fh = io.open('my-other-test.md', 'wb') fh:write(contents) fh:close() assert.are_equal(system.read_file('my-other-test.md'), contents) end)), test('fails if file does not exist', in_tmpdir(function () assert.error_matches( function () system.read_file('does-not-exist.org') end, 'No such file or directory' ) end)), test('fails when trying to read a directory', in_tmpdir(function () system.mkdir 'folder' assert.error_matches( function () system.read_file('folder') end, system.os == 'mingw32' and 'permission denied' or 'inappropriate type' ) end)), }, group 'rename' { test('renames a file', in_tmpdir(function () local contents = 'Le café au lait es très délicieux.' local old = 'original.txt' local new = 'moved.txt' local fh = io.open(old, 'wb') fh:write(contents) fh:close() system.rename(old, new) assert.are_equal(io.open(new, 'rb'):read('a'), contents) end)), test('renames a directory', in_tmpdir(function () local old = 'folder' local new = 'moved' -- Create folder that contains a file. system.mkdir(old) system.with_wd(old, function () io.open('test.txt', 'wb'):close() end) local filelist = system.ls(old) -- Move folder to new path system.rename(old, new) assert.are_same(filelist, system.ls(new)) end)), test( 'fails if source path is a file and target is a directory', in_tmpdir(function () local old = 'foo.txt' local new = 'folder' io.open(old, 'wb'):close() system.mkdir(new) assert.error_matches( function () system.rename(old, new) end, os.system == 'mingw32' and 'permission denied' or 'inappropriate type' ) end) ), }, group 'rm' { test('removes a file', in_tmpdir(function () local fh = io.open('test.txt', 'w') fh:write('Hello\n') fh:close() system.rm('test.txt') assert.are_same(system.ls '.', {}) end)), test('fails if file does not exist', in_tmpdir(function () assert.error_matches( function () system.rm('nope.txt') end, 'does not exist' ) end)), }, group 'rmdir' { test('remove empty directory', in_tmpdir(function () system.mkdir 'remove-me' system.rmdir 'remove-me' assert.are_same(system.ls(), {}) end)), test('fail if directory is not empty', in_tmpdir(function () system.mkdir('outer/inner', true) assert.error_matches(function () system.rmdir('outer') end, '.') end)), test('optionally delete recursively', in_tmpdir(function () system.mkdir('outer/inner', true) system.rmdir('outer', true) assert.are_same(system.ls(), {}) end)) }, group 'times' { test('returns two strings', in_tmpdir(function () system.write_file('foo.txt', 'test') local mtime, atime = system.times('foo.txt') assert.are_equal(type(mtime), 'string') assert.are_equal(type(atime), 'string') end)), test('mtime can be parsed as ISO 8601 ', in_tmpdir(function () system.write_file('foo.txt', 'test') local mtime = system.times('foo.txt') local year, month, day, hour, min, sec = string.match(mtime, '(%d%d%d%d)%-(%d%d)-(%d%d)T(%d%d):(%d%d):(%d%d)') assert.is_truthy(year and month and day and hour and min and sec) end)), test('atime can be parsed as ISO 8601 ', in_tmpdir(function () system.write_file('foo.txt', 'test') local _, atime = system.times('foo.txt') local year, month, day, hour, min, sec = string.match(atime, '(%d%d%d%d)%-(%d%d)-(%d%d)T(%d%d):(%d%d):(%d%d)') assert.is_truthy(year and month and day and hour and min and sec) end)), }, group 'tmpdirname' { test('returns a string', function () assert.are_equal(type(system.tmpdirname()), 'string') end) }, group 'with_env' { test('resets environment', function () -- TODO: this test fails on Windows for unknown reasons and is -- disabled on there for that reason. This needs fixing. if system.os == 'mingw32' then return nil end local outer_value = 'outer test value' local inner_value = 'inner test value' local inner_only = 'test #2' function check_env () assert.are_equal(os.getenv 'HSLUA_SYSTEM_TEST', inner_value) assert.are_equal( os.getenv 'HSLUA_SYSTEM_TEST_INNER_ONLY', inner_only ) assert.is_nil(os.getenv 'HSLUA_SYSTEM_TEST_OUTER_ONLY') end local test_env = { HSLUA_SYSTEM_TEST = inner_value, HSLUA_SYSTEM_TEST_INNER_ONLY = inner_only } system.setenv('HSLUA_SYSTEM_TEST_OUTER_ONLY', outer_value) system.setenv('HSLUA_SYSTEM_TEST', outer_value) system.with_env(test_env, check_env) assert.are_equal(system.getenv 'HSLUA_SYSTEM_TEST', outer_value) assert.is_nil(system.getenv 'HSLUA_SYSTEM_TEST_INNER_ONLY') assert.are_equal( system.getenv 'HSLUA_SYSTEM_TEST_OUTER_ONLY', outer_value ) end) }, group 'with_tmpdir' { test('no base directory given', function () assert.are_equal(system.with_tmpdir('foo', write_read_token), token) end), test('cwd as base directory', function () assert.are_equal(system.with_tmpdir('.', 'foo', write_read_token), token) end), }, group 'with_wd' { test('can change to test directory', function () system.with_wd('test', function () local cwd = system.getwd() assert.is_truthy(cwd:match 'test$') end) end), test('returns to old directory once done', function () local cwd = system.getwd() system.with_wd('test', function () end) assert.are_equal(system.getwd(), cwd) end), test('working directory is passed to callback', function () system.with_wd('test', function (path) assert.is_truthy(system.getwd():match (path .. '$')) end) end), test('all callback results are returned', function () local a, b, c = system.with_wd('test', function (path) return 'a', 'b', 'c' end) assert.are_same({a, b, c}, {'a', 'b', 'c'}) end), test('raises an error on nonexistent directory', function () assert.error_matches( function () system.with_wd('does-not-exist', function () end) end, 'does not exist' ) end) }, group 'write_file' { test('writes a string to a file', in_tmpdir(function () local contents = 'Das ist ein Satz auf deutsch.\n' local filename = 'deutsch.txt' system.write_file(filename, contents) assert.are_equal(io.open(filename, 'rb'):read('a'), contents) end)), test('works with `read_file` on Unicode filenames', in_tmpdir(function () local contents = 'Речення українською для перевірки Юнікоду.' local filename = 'український_текст.txt' system.write_file(filename, contents) assert.are_equal(system.read_file(filename), contents) end)), }, group 'xdg' { test('returns a cache directory', function () assert.is_truthy(#system.xdg('cache') > 1) end), test("second argument get's appended" , function () local rel_path = 'pandoc/lua' local data_path = system.xdg('data', rel_path) assert.are_equal( -- replace backslashes with slashes to make this work on windows data_path:sub(- #rel_path, -1):gsub('\\', '/'), rel_path ) end), test("raises an error if the XDG directory is unknown" , function () assert.error_matches(function () system.xdg('foo') end, 'got: foo') end), test('`xdg_` prefix is accepted', function () assert.is_truthy(#system.xdg('xdg_cache') > 1) end), test('returns a list of `XDG_DATA_DIRS`', function () assert.are_equal(type(system.xdg('XDG_DATA_DIRS')), 'table') end), }, }