diff --git a/lib/gears/filesystem.lua b/lib/gears/filesystem.lua index b9c840567..26b315450 100644 --- a/lib/gears/filesystem.lua +++ b/lib/gears/filesystem.lua @@ -153,4 +153,33 @@ function filesystem.get_dir(d) end end +math.randomseed( os.clock() % 1 * 1e6 ) + +--- Get the name of a random file from a given directory. +-- @tparam string path The directory to search. +-- @tparam[opt] table exts Specific extensions to limit the search to. eg:`{ "jpg", "png" }` +-- If ommited, all files are considered. +-- @treturn string|nil A randomly selected filename from the specified path (with +-- a specified extension if required) or nil if no suitable file is found. +function filesystem.get_random_file_from_dir(path, exts) + local files, valid_exts = {}, {} + + -- Transforms { "jpg", ... } into { [jpg] = #, ... } + if exts then for i, j in ipairs(exts) do valid_exts[j:lower()] = i end end + + -- Build a table of files from the path with the required extensions + local file_list = Gio.File.new_for_path(path):enumerate_children("standard::*", 0) + for file in function() return file_list:next_file() end do + if file:get_file_type() == "REGULAR" then + local file_name = file:get_display_name() + if not exts or valid_exts[file_name:lower():match(".+%.(.*)$") or ""] then + table.insert(files, file_name) + end + end + end + + -- Return a randomly selected filename from the file table + return #files > 0 and files[math.random(#files)] or nil +end + return filesystem diff --git a/spec/gears/filesystem_spec.lua b/spec/gears/filesystem_spec.lua new file mode 100644 index 000000000..d277aeacf --- /dev/null +++ b/spec/gears/filesystem_spec.lua @@ -0,0 +1,138 @@ +--------------------------------------------------------------------------- +-- @author +-- @copyright 2019 +--------------------------------------------------------------------------- + +local gfs = require("gears.filesystem") + +describe("gears.filesystem", function() + local root = (os.getenv("SOURCE_DIRECTORY") or '.') .. "/spec/gears/" + + -- Check filesystem.make_directories + it('Check filesystem.make_directories', function() + assert.is_true(gfs.make_directories(root .. "filesystem_tests/x/y")) + end) + + -- Check filesystem.make_parent_directories + it('Check filesystem.make_parent_directories', function() + assert.is_true(gfs.make_directories(root .. "filesystem_tests/x/y")) + end) + + -- Check filesystem.file_readable + it('Check filesystem.file_readable', function() + os.execute("chmod g-r,o-r,a-r " .. root .. "filesystem_tests/x/NoRead") + + assert.is_true(gfs.file_readable(root .. "filesystem_tests/x/Read")) + assert.is_false(gfs.file_readable(root .. "filesystem_tests/x/NoRead")) + assert.is_nil(gfs.file_readable(root .. "filesystem_tests/x/NO_FILE")) + + os.execute("chmod g+r,o+r,a+r " .. root .. "filesystem_tests/x/NoRead") + end) + + -- Check filesystem.file_executable + it('Check filesystem.file_executable', function() + assert.is_true(gfs.file_executable(root .. "filesystem_tests/x/Exec")) + assert.is_false(gfs.file_executable(root .. "filesystem_tests/x/NoExec")) + assert.is_nil(gfs.file_executable(root .. "filesystem_tests/x/NO_FILE")) + end) + + -- Check filesystem.dir_readable + it('Check filesystem.dir_readable', function() + os.execute("chmod g-r,o-r,a-r " .. root .. "filesystem_tests/y") + + assert.is_true(gfs.dir_readable(root .. "filesystem_tests/x")) + assert.is_false(gfs.dir_readable(root .. "filesystem_tests/y")) + assert.is_nil(gfs.dir_readable(root .. "filesystem_tests/NO_DIR")) + + os.execute("chmod g+r,o+r,a+r " .. root .. "filesystem_tests/y") + end) + + -- Check filesystem.is_dir + it('Check filesystem.is_dir', function() + assert.is_true(gfs.is_dir(root .. "filesystem_tests/x/y")) + assert.is_false(gfs.is_dir(root .. "filesystem_tests/x/Read")) + -- Following would be nicer if it returned nil but it is what it is + assert.is_false(gfs.is_dir(root .. "filesystem_tests/x/NO_DIR")) + end) + + -- Check filesystem.get_xdg_config_home + it('Check filesystem.get_xdg_config_home', function() + -- TODO: assert.is_same("?", gfs.get_xdg_config_home()) + end) + + -- Check filesystem.get_xdg_cache_home + it('Check filesystem.get_xdg_cache_home', function() + -- TODO: assert.is_same("?", gfs.get_xdg_cache_home()) + end) + + -- Check filesystem.get_xdg_data_home + it('Check filesystem.get_xdg_data_home', function() + -- TODO: assert.is_same("?", gfs.get_xdg_data_home()) + end) + + -- Check filesystem.get_xdg_data_dirs + it('Check filesystem.get_xdg_data_dirs', function() + -- TODO: assert.is_same("?", gfs.get_xdg_data_dirs()) + end) + + -- Check filesystem.get_configuration_dir + it('Check filesystem.get_configuration_dir', function() + -- TODO: assert.is_same("?", gfs.get_configuration_dir()) + end) + + -- Check filesystem.get_cache_dir + it('Check filesystem.get_cache_dir', function() + -- TODO: assert.is_same("?", gfs.get_cache_dir()) + end) + + -- Check filesystem.get_themes_dir + it('Check filesystem.get_themes_dir', function() + -- TODO: assert.is_same("?", gfs.get_themes_dir()) + end) + + -- Check filesystem.get_awesome_icon_dir + it('Check filesystem.get_awesome_icon_dir', function() + -- TODO: assert.is_same("?", gfs.get_awesome_icon_dir()) + end) + + -- Check filesystem.get_random_file_from_dir + it('Check filesystem.get_random_file_from_dir', function() + -- No file + assert.is_nil(gfs.get_random_file_from_dir(root .. "filesystem_tests", {"bmp"})) + + -- File found matching extension + assert.is_same("a.png", gfs.get_random_file_from_dir(root .. "filesystem_tests", {"png"})) + assert.is_same("b.jpg", gfs.get_random_file_from_dir(root .. "filesystem_tests", {"jpg"})) + + for _ = 1, 20 do + -- Any file found (any extension) + local test_a = gfs.get_random_file_from_dir(root .. "filesystem_tests") + assert.is_true(test_a == "a.png" + or test_a == "b.jpg") + + -- Any file found (selected extensions) + local test_b = gfs.get_random_file_from_dir(root .. "filesystem_tests", {"png", "jpg"}) + assert.is_true(test_b == "a.png" + or test_b == "b.jpg") + + -- "." in filename test cases with extensions + local test_c = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {"ext"}) + assert.is_true(test_c == "filename.ext" + or test_c == ".filename.ext" + or test_c == "file.name.ext" + or test_c == ".file.name.ext") + + -- "." in filename test cases with no extensions + local test_d = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {""}) + assert.is_true(test_d == "filename" + or test_d == "filename." + or test_d == "filename.ext." + or test_d == ".filename" + or test_d == ".filename." + or test_d == "file.name.ext." + or test_d == ".file.name.ext.") + end + end) +end) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/spec/gears/filesystem_tests/a.png b/spec/gears/filesystem_tests/a.png new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/b.jpg b/spec/gears/filesystem_tests/b.jpg new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/x/Exec b/spec/gears/filesystem_tests/x/Exec new file mode 100755 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/x/NoExec b/spec/gears/filesystem_tests/x/NoExec new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/x/NoRead b/spec/gears/filesystem_tests/x/NoRead new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/x/Read b/spec/gears/filesystem_tests/x/Read new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/y/.file.name.ext b/spec/gears/filesystem_tests/y/.file.name.ext new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/y/.file.name.ext. b/spec/gears/filesystem_tests/y/.file.name.ext. new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/y/.filename b/spec/gears/filesystem_tests/y/.filename new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/y/.filename. b/spec/gears/filesystem_tests/y/.filename. new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/y/.filename.ext b/spec/gears/filesystem_tests/y/.filename.ext new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/y/file.name.ext b/spec/gears/filesystem_tests/y/file.name.ext new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/y/file.name.ext. b/spec/gears/filesystem_tests/y/file.name.ext. new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/y/filename b/spec/gears/filesystem_tests/y/filename new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/y/filename. b/spec/gears/filesystem_tests/y/filename. new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/y/filename.ext b/spec/gears/filesystem_tests/y/filename.ext new file mode 100644 index 000000000..e69de29bb diff --git a/spec/gears/filesystem_tests/y/filename.ext. b/spec/gears/filesystem_tests/y/filename.ext. new file mode 100644 index 000000000..e69de29bb