-module(xdg_pipe_menu_renderer_tests). -include_lib("eunit/include/eunit.hrl"). -include_lib("xmerl/include/xmerl.hrl"). -include("xdg_pipe_menu.hrl"). entry(Name, Exec, Icon) -> entry(Name, Exec, Icon, []). entry(Name, Exec, Icon, Categories) -> entry(Name, Exec, Icon, Categories, false). entry(Name, Exec, Icon, Categories, Hidden) -> #desktop_entry{ name = Name, exec = Exec, icon = Icon, categories = Categories, hidden = Hidden }. empty_list_renders_empty_menu_test() -> ?assertEqual( <<"\n" "\n" "\n">>, xdg_pipe_menu_renderer:render([]) ). single_entry_with_icon_test() -> Rendered = xdg_pipe_menu_renderer:render([ entry(<<"Firefox">>, <<"firefox">>, <<"firefox">>, [<<"Network">>]) ]), ?assertEqual( <<"\n" "\n" " \n" " \n" " \n" " firefox\n" " \n" " \n" " \n" "\n">>, Rendered ). entry_without_icon_omits_icon_attr_test() -> Rendered = xdg_pipe_menu_renderer:render([ entry(<<"Foo">>, <<"foo">>, undefined, [<<"Utility">>]) ]), ?assertEqual( <<"\n" "\n" " \n" " \n" " \n" " foo\n" " \n" " \n" " \n" "\n">>, Rendered ). entries_without_categories_go_in_other_submenu_test() -> Rendered = xdg_pipe_menu_renderer:render([entry(<<"Foo">>, <<"foo">>, undefined)]), ?assertEqual( <<"\n" "\n" " \n" " \n" " \n" " foo\n" " \n" " \n" " \n" "\n">>, Rendered ). hidden_entries_are_dropped_test() -> Entries = [ entry(<<"Visible">>, <<"visible">>, undefined, [<<"Utility">>]), entry(<<"Invisible">>, <<"invisible">>, undefined, [<<"Utility">>], true) ], Rendered = xdg_pipe_menu_renderer:render(Entries), ?assertNot(binary:match(Rendered, <<"Invisible">>) =/= nomatch), ?assert(binary:match(Rendered, <<"Visible">>) =/= nomatch). hidden_entry_leaves_no_empty_submenu_test() -> Entries = [entry(<<"Invisible">>, <<"invisible">>, undefined, [<<"Utility">>], true)], Rendered = xdg_pipe_menu_renderer:render(Entries), ?assertNot(binary:match(Rendered, <<"Utility">>) =/= nomatch). entries_are_sorted_case_insensitively_within_a_submenu_test() -> Entries = [ entry(<<"zeta">>, <<"zeta">>, undefined, [<<"Utility">>]), entry(<<"Alpha">>, <<"alpha">>, undefined, [<<"Utility">>]), entry(<<"beta">>, <<"beta">>, undefined, [<<"Utility">>]) ], Rendered = xdg_pipe_menu_renderer:render(Entries), Positions = [ element(1, binary:match(Rendered, <<"label=\"Alpha\"">>)), element(1, binary:match(Rendered, <<"label=\"beta\"">>)), element(1, binary:match(Rendered, <<"label=\"zeta\"">>)) ], ?assertEqual(Positions, lists:sort(Positions)). submenus_are_sorted_case_insensitively_test() -> Entries = [ entry(<<"Zed App">>, <<"zed">>, undefined, [<<"zeta">>]), entry(<<"Alpha App">>, <<"alpha">>, undefined, [<<"Alpha">>]), entry(<<"Beta App">>, <<"beta">>, undefined, [<<"beta">>]) ], Rendered = xdg_pipe_menu_renderer:render(Entries), Positions = [ element(1, binary:match(Rendered, <<"label=\"Alpha\"">>)), element(1, binary:match(Rendered, <<"label=\"beta\"">>)), element(1, binary:match(Rendered, <<"label=\"zeta\"">>)) ], ?assertEqual(Positions, lists:sort(Positions)). entry_with_multiple_categories_appears_in_each_submenu_test() -> Entries = [entry(<<"Foo">>, <<"foo">>, undefined, [<<"Utility">>, <<"Development">>])], Rendered = xdg_pipe_menu_renderer:render(Entries), {Doc, _Rest} = xmerl_scan:string(binary_to_list(Rendered)), Menus = [E || E = #xmlElement{name = menu} <- Doc#xmlElement.content], ?assertEqual([<<"Development">>, <<"Utility">>], lists:sort([menu_id(M) || M <- Menus])), Items = [I || M <- Menus, I = #xmlElement{name = item} <- M#xmlElement.content], ?assertEqual(2, length(Items)). escapes_special_characters_test() -> Entry = entry( <<"Foo & \"Baz\"">>, <<"foo --title=\"&y\"">>, <<"icon\"&<>">>, [<<"Foo & ">>] ), Rendered = xdg_pipe_menu_renderer:render([Entry]), ?assertEqual( <<"\n" "\n" " \" label=\"Foo & <Bar>\">\n" " "Baz"\" icon=\"icon"&<>\">\n" " \n" " foo --title=\"<x>&y\"\n" " \n" " \n" " \n" "\n">>, Rendered ). output_is_well_formed_xml_test() -> Entries = [ entry(<<"Firefox">>, <<"firefox">>, <<"firefox">>, [<<"Network">>]), entry(<<"Foo & Bar">>, <<"foo">>, undefined, [<<"Network">>]) ], Rendered = xdg_pipe_menu_renderer:render(Entries), {Doc, _Rest} = xmerl_scan:string(binary_to_list(Rendered)), ?assertEqual(openbox_pipe_menu, Doc#xmlElement.name), Menus = [E || E = #xmlElement{name = menu} <- Doc#xmlElement.content], ?assertEqual(1, length(Menus)), [Menu] = Menus, Items = [E || E = #xmlElement{name = item} <- Menu#xmlElement.content], ?assertEqual(2, length(Items)). menu_id(#xmlElement{attributes = Attrs}) -> [Value] = [V || #xmlAttribute{name = id, value = V} <- Attrs], list_to_binary(Value).