From be974991063bb6af5f860adab350901cf7ed71f1 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 28 Apr 2019 11:08:18 -0700 Subject: [PATCH] Revert "Revert "Add a test for autoload_t"" This reverts commit 2507162f805db9f864b290e77efc34182b170c2c. Put back the autoload test. --- src/autoload.cpp | 13 ++++++-- src/autoload.h | 14 +++++++- src/fish_tests.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 4 deletions(-) diff --git a/src/autoload.cpp b/src/autoload.cpp index 6a750cfd3..4cdbc6cf8 100644 --- a/src/autoload.cpp +++ b/src/autoload.cpp @@ -144,6 +144,11 @@ autoload_t::autoload_t(wcstring env_var_name) autoload_t::autoload_t(autoload_t &&) = default; autoload_t::~autoload_t() = default; +void autoload_t::invalidate_cache() { + auto cache = make_unique(cache_->dirs()); + cache_ = std::move(cache); +} + bool autoload_t::can_autoload(const wcstring &cmd) { return cache_->check(cmd, true /* allow stale */).has_value(); } @@ -160,15 +165,17 @@ wcstring_list_t autoload_t::get_autoloaded_commands() const { } maybe_t autoload_t::resolve_command(const wcstring &cmd, const environment_t &env) { + maybe_t mvar = env.get(env_var_name_); + return resolve_command(cmd, mvar ? mvar->as_list() : wcstring_list_t{}); +} + +maybe_t autoload_t::resolve_command(const wcstring &cmd, const wcstring_list_t &paths) { // Are we currently in the process of autoloading this? if (current_autoloading_.count(cmd) > 0) return none(); // Check to see if our paths have changed. If so, replace our cache. // Note we don't have to modify autoloadable_files_. We'll naturally detect if those have // changed when we query the cache. - maybe_t mvar = env.get(env_var_name_); - const wcstring_list_t empty; - const wcstring_list_t &paths = mvar ? mvar->as_list() : empty; if (paths != cache_->dirs()) { cache_ = make_unique(paths); } diff --git a/src/autoload.h b/src/autoload.h index d59486364..3a17538fd 100644 --- a/src/autoload.h +++ b/src/autoload.h @@ -16,6 +16,7 @@ class autoload_file_cache_t; class environment_t; class parser_t; +struct autoload_tester_t; /// autoload_t is a class that knows how to autoload .fish files from a list of directories. This /// is used by autoloading functions and completions. It maintains a file cache, which is @@ -39,6 +40,16 @@ class autoload_t { /// changes. This is never null (but it may be a cache with no paths). std::unique_ptr cache_; + /// Invalidate any underlying cache. + /// This is exposed for testing. + void invalidate_cache(); + + /// Like resolve_autoload(), but accepts the paths directly. + /// This is exposed for testing. + maybe_t resolve_command(const wcstring &cmd, const wcstring_list_t &paths); + + friend autoload_tester_t; + public: /// Construct an autoloader that loads from the paths given by \p env_var_name. explicit autoload_t(wcstring env_var_name); @@ -77,7 +88,8 @@ class autoload_t { /// This does not actually mark the command as being autoloaded. bool can_autoload(const wcstring &cmd); - /// \return the names of all commands that have been autoloaded. + /// \return the names of all commands that have been autoloaded. Note this includes "in-flight" + /// commands. wcstring_list_t get_autoloaded_commands() const; /// Mark that all autoloaded files have been forgotten. diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index c843ee3e2..32bec017f 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -4,6 +4,7 @@ // IWYU pragma: no_include // IWYU pragma: no_include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include +#include "autoload.h" #include "builtin.h" #include "color.h" #include "common.h" @@ -2482,6 +2484,85 @@ static void test_colors() { do_test(rgb_color_t(L"mooganta").is_none()); } +// This class allows accessing private bits of autoload_t. +struct autoload_tester_t { + static void run(const wchar_t *fmt, ...) { + va_list va; + va_start(va, fmt); + wcstring cmd = vformat_string(fmt, va); + va_end(va); + + int status = system(wcs2string(cmd).c_str()); + do_test(status == 0); + } + + static void touch_file(const wcstring &path) { + int fd = wopen_cloexec(path, O_RDWR | O_CREAT, 0666); + do_test(fd >= 0); + write_loop(fd, "Hello", 5); + close(fd); + } + + static void run_test() { + char t1[] = "/tmp/fish_test_autoload.XXXXXX"; + wcstring p1 = str2wcstring(mkdtemp(t1)); + char t2[] = "/tmp/fish_test_autoload.XXXXXX"; + wcstring p2 = str2wcstring(mkdtemp(t2)); + + const wcstring_list_t paths = {p1, p2}; + + autoload_t autoload(L"test_var"); + do_test(!autoload.resolve_command(L"file1", paths)); + do_test(!autoload.resolve_command(L"nothing", paths)); + do_test(autoload.get_autoloaded_commands().empty()); + + run(L"touch %ls/file1.fish", p1.c_str()); + run(L"touch %ls/file2.fish", p2.c_str()); + autoload.invalidate_cache(); + + do_test(!autoload.autoload_in_progress(L"file1")); + do_test(autoload.resolve_command(L"file1", paths)); + do_test(!autoload.resolve_command(L"file1", paths)); + do_test(autoload.autoload_in_progress(L"file1")); + do_test(autoload.get_autoloaded_commands() == wcstring_list_t{L"file1"}); + autoload.mark_autoload_finished(L"file1"); + do_test(!autoload.autoload_in_progress(L"file1")); + do_test(autoload.get_autoloaded_commands() == wcstring_list_t{L"file1"}); + + do_test(!autoload.resolve_command(L"file1", paths)); + do_test(!autoload.resolve_command(L"nothing", paths)); + do_test(autoload.resolve_command(L"file2", paths)); + do_test(!autoload.resolve_command(L"file2", paths)); + autoload.mark_autoload_finished(L"file2"); + do_test(!autoload.resolve_command(L"file2", paths)); + do_test((autoload.get_autoloaded_commands() == wcstring_list_t{L"file1", L"file2"})); + + autoload.clear(); + do_test(autoload.resolve_command(L"file1", paths)); + autoload.mark_autoload_finished(L"file1"); + do_test(!autoload.resolve_command(L"file1", paths)); + do_test(!autoload.resolve_command(L"nothing", paths)); + do_test(autoload.resolve_command(L"file2", paths)); + do_test(!autoload.resolve_command(L"file2", paths)); + autoload.mark_autoload_finished(L"file2"); + + do_test(!autoload.resolve_command(L"file1", paths)); + touch_file(format_string(L"%ls/file1.fish", p1.c_str())); + autoload.invalidate_cache(); + do_test(autoload.resolve_command(L"file1", paths)); + autoload.mark_autoload_finished(L"file1"); + + run(L"rm -Rf %ls", p1.c_str()); + run(L"rm -Rf %ls", p2.c_str()); + + } +}; + +static void test_autoload() { + say(L"Testing autoload"); + autoload_tester_t::run_test(); +} + static void test_complete() { say(L"Testing complete"); @@ -5341,6 +5422,7 @@ int main(int argc, char **argv) { if (should_test_function("is_potential_path")) test_is_potential_path(); if (should_test_function("colors")) test_colors(); if (should_test_function("complete")) test_complete(); + if (should_test_function("autoload")) test_autoload(); if (should_test_function("input")) test_input(); if (should_test_function("line_iterator")) test_line_iterator(); if (should_test_function("universal")) test_universal();