diff options
| author | Christopher R. Nelson <christopher.nelson@languidnights.com> | 2026-07-21 11:18:56 -0400 |
|---|---|---|
| committer | Christopher R. Nelson <christopher.nelson@languidnights.com> | 2026-07-21 11:18:56 -0400 |
| commit | 7e8472e1e2a0b39746ef86c041d56b92bab5a6b7 (patch) | |
| tree | 4d37a36c945446b4bded6989a780abe4cd3f2f1e /test/er_xdg_pipe_menu_cache_tests.erl | |
| parent | 46b72a375101b54819f8750750017bd71e7c3798 (diff) | |
Wire up cache, file watcher, and Unix socket daemon
Adds a gen_server cache holding the rendered menu, an fs/inotify-based
watcher that debounces changes and invalidates it, a Unix domain
socket serving the cached binary, and the escript client Openbox
invokes (with an inline render fallback if the daemon isn't running).
Also documents local deployment (systemd user unit, Openbox menu.xml
wiring) in the README.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'test/er_xdg_pipe_menu_cache_tests.erl')
| -rw-r--r-- | test/er_xdg_pipe_menu_cache_tests.erl | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/test/er_xdg_pipe_menu_cache_tests.erl b/test/er_xdg_pipe_menu_cache_tests.erl new file mode 100644 index 0000000..a1d1440 --- /dev/null +++ b/test/er_xdg_pipe_menu_cache_tests.erl @@ -0,0 +1,130 @@ +-module(er_xdg_pipe_menu_cache_tests). + +-include_lib("eunit/include/eunit.hrl"). + +build_renders_entries_from_dir_test() -> + Dir = mk_tmp_dir(), + write_desktop(Dir, "foo.desktop", "Foo", "foo"), + Menu = er_xdg_pipe_menu_cache:build([Dir]), + ok = rm_rf(Dir), + ?assert(binary:match(Menu, <<"Foo">>) =/= nomatch). + +build_groups_by_category_test() -> + Dir = mk_tmp_dir(), + write_desktop(Dir, "foo.desktop", "Foo", "foo", "Utility"), + Menu = er_xdg_pipe_menu_cache:build([Dir]), + ok = rm_rf(Dir), + ?assert(binary:match(Menu, <<"label=\"Utility\"">>) =/= nomatch). + +build_skips_hidden_entries_test() -> + Dir = mk_tmp_dir(), + write_desktop(Dir, "visible.desktop", "Visible", "visible"), + ok = file:write_file( + filename:join(Dir, "hidden.desktop"), + <<"[Desktop Entry]\nName=Hidden\nExec=hidden\nNoDisplay=true\n">> + ), + Menu = er_xdg_pipe_menu_cache:build([Dir]), + ok = rm_rf(Dir), + ?assert(binary:match(Menu, <<"Visible">>) =/= nomatch), + ?assertEqual(nomatch, binary:match(Menu, <<"Hidden">>)). + +build_skips_unparseable_files_without_failing_test() -> + Dir = mk_tmp_dir(), + write_desktop(Dir, "good.desktop", "Good", "good"), + ok = file:write_file(filename:join(Dir, "bad.desktop"), <<"[Desktop Entry]\nExec=bad\n">>), + Menu = er_xdg_pipe_menu_cache:build([Dir]), + ok = rm_rf(Dir), + ?assert(binary:match(Menu, <<"Good">>) =/= nomatch). + +build_skips_missing_dirs_test() -> + ?assertEqual( + <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<openbox_pipe_menu>\n" + "</openbox_pipe_menu>\n">>, + er_xdg_pipe_menu_cache:build(["/does-not-exist"]) + ). + +gen_server_serves_and_invalidates_test() -> + Root = mk_tmp_dir(), + AppDir = filename:join(Root, "applications"), + ok = file:make_dir(AppDir), + write_desktop(AppDir, "foo.desktop", "Foo", "foo"), + with_env( + [{"XDG_DATA_HOME", Root}, {"XDG_DATA_DIRS", "/does-not-exist-eunit"}], + fun() -> + {ok, Pid} = er_xdg_pipe_menu_cache:start_link(), + Menu1 = er_xdg_pipe_menu_cache:get_menu(), + ?assert(binary:match(Menu1, <<"Foo">>) =/= nomatch), + + write_desktop(AppDir, "bar.desktop", "Bar", "bar"), + ok = er_xdg_pipe_menu_cache:invalidate(), + Menu2 = er_xdg_pipe_menu_cache:get_menu(), + stop(Pid), + ?assert(binary:match(Menu2, <<"Bar">>) =/= nomatch) + end + ), + ok = rm_rf(Root). + +%% -- helpers ---------------------------------------------------------------- + +%% start_link/0 links the started process to us (the test process); +%% unlink before killing it so the kill signal doesn't propagate back +%% and take the test process down with it. +stop(Pid) -> + unlink(Pid), + true = erlang:exit(Pid, kill). + +with_env(Vars, Fun) -> + Saved = [{Name, os:getenv(Name)} || {Name, _} <- Vars], + try + lists:foreach(fun({Name, Value}) -> set_env(Name, Value) end, Vars), + Fun() + after + lists:foreach(fun({Name, Value}) -> set_env(Name, Value) end, Saved) + end. + +set_env(Name, false) -> os:unsetenv(Name); +set_env(Name, Value) -> os:putenv(Name, Value). + +write_desktop(Dir, FileName, Name, Exec) -> + ok = file:write_file( + filename:join(Dir, FileName), + iolist_to_binary(["[Desktop Entry]\nName=", Name, "\nExec=", Exec, "\n"]) + ). + +write_desktop(Dir, FileName, Name, Exec, Categories) -> + ok = file:write_file( + filename:join(Dir, FileName), + iolist_to_binary([ + "[Desktop Entry]\nName=", + Name, + "\nExec=", + Exec, + "\nCategories=", + Categories, + ";\n" + ]) + ). + +mk_tmp_dir() -> + Path = filename:join( + test_tmp_dir(), "eunit-cache-" ++ integer_to_list(erlang:unique_integer([positive])) + ), + ok = file:make_dir(Path), + Path. + +test_tmp_dir() -> + case os:getenv("TMPDIR") of + false -> "/tmp"; + Dir -> Dir + end. + +rm_rf(Path) -> + case filelib:is_dir(Path) of + true -> + {ok, Entries} = file:list_dir(Path), + lists:foreach(fun(E) -> rm_rf(filename:join(Path, E)) end, Entries), + file:del_dir(Path); + false -> + file:delete(Path) + end. |
