Add a test for autoload_t

This commit is contained in:
ridiculousfish 2019-04-27 14:26:41 -07:00
parent 4ff50eba41
commit 51c62d6cc6
3 changed files with 93 additions and 4 deletions

View File

@ -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<autoload_file_cache_t>(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<wcstring> autoload_t::resolve_command(const wcstring &cmd, const environment_t &env) {
maybe_t<env_var_t> mvar = env.get(env_var_name_);
return resolve_command(cmd, mvar ? mvar->as_list() : wcstring_list_t{});
}
maybe_t<wcstring> 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<env_var_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<autoload_file_cache_t>(paths);
}

View File

@ -15,6 +15,7 @@
class autoload_file_cache_t;
class environment_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
@ -38,6 +39,16 @@ class autoload_t {
/// changes. This is never null (but it may be a cache with no paths).
std::unique_ptr<autoload_file_cache_t> 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<wcstring> 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);
@ -76,7 +87,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.

View File

@ -38,6 +38,7 @@
#include <utility>
#include <vector>
#include "autoload.h"
#include "builtin.h"
#include "color.h"
#include "common.h"
@ -2472,6 +2473,74 @@ 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 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));
run(L"touch %ls/file1.fish", p1.c_str());
autoload.invalidate_cache();
do_test(autoload.resolve_command(L"file1", paths));
autoload.mark_autoload_finished(L"file1");
}
};
static void test_autoload() {
say(L"Testing autoload");
autoload_tester_t::run_test();
}
static void test_complete() {
say(L"Testing complete");
@ -5289,6 +5358,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();