# -*- coding: utf-8; -*- from unittest import TestCase from unittest.mock import patch, MagicMock from wuttaweb import menus as mod from wuttaweb.testing import WebTestCase class TestMenuHandler(WebTestCase): def setUp(self): self.setup_web() self.handler = mod.MenuHandler(self.config) def test_make_admin_menu(self): # no people entry by default menu = self.handler.make_admin_menu(self.request) self.assertIsInstance(menu, dict) routes = [item.get("route") for item in menu["items"]] self.assertNotIn("people", routes) # but we can request it menu = self.handler.make_admin_menu(self.request, include_people=True) routes = [item.get("route") for item in menu["items"]] self.assertIn("people", routes) def test_make_menus(self): menus = self.handler.make_menus(self.request) self.assertIsInstance(menus, list) def test_is_allowed(self): model = self.app.model auth = self.app.get_auth_handler() # user with perms barney = model.User(username="barney") self.session.add(barney) blokes = model.Role(name="Blokes") self.session.add(blokes) barney.roles.append(blokes) auth.grant_permission(blokes, "appinfo.list") self.request.user = barney # perm not granted to user item = {"perm": "appinfo.configure"} self.assertFalse(self.handler._is_allowed(self.request, item)) # perm *is* granted to user item = {"perm": "appinfo.list"} self.assertTrue(self.handler._is_allowed(self.request, item)) # perm not required item = {} self.assertTrue(self.handler._is_allowed(self.request, item)) def test_mark_allowed(self): def make_menus(): return [ { "type": "menu", "items": [ {"title": "Foo", "url": "#"}, {"title": "Bar", "url": "#"}, ], }, ] mock_is_allowed = MagicMock() with patch.object(self.handler, "_is_allowed", new=mock_is_allowed): # all should be allowed mock_is_allowed.return_value = True menus = make_menus() self.handler._mark_allowed(self.request, menus) menu = menus[0] self.assertTrue(menu["allowed"]) foo, bar = menu["items"] self.assertTrue(foo["allowed"]) self.assertTrue(bar["allowed"]) # none should be allowed mock_is_allowed.return_value = False menus = make_menus() self.handler._mark_allowed(self.request, menus) menu = menus[0] self.assertFalse(menu["allowed"]) foo, bar = menu["items"] self.assertFalse(foo["allowed"]) self.assertFalse(bar["allowed"]) def test_mark_allowed_submenu(self): def make_menus(): return [ { "type": "menu", "items": [ {"title": "Foo", "url": "#"}, { "type": "menu", "items": [ {"title": "Bar", "url": "#"}, ], }, ], }, ] mock_is_allowed = MagicMock() with patch.object(self.handler, "_is_allowed", new=mock_is_allowed): # all should be allowed mock_is_allowed.return_value = True menus = make_menus() self.handler._mark_allowed(self.request, menus) menu = menus[0] self.assertTrue(menu["allowed"]) foo, submenu = menu["items"] self.assertTrue(foo["allowed"]) self.assertTrue(submenu["allowed"]) subitem = submenu["items"][0] self.assertTrue(subitem["allowed"]) # none should be allowed mock_is_allowed.return_value = False menus = make_menus() self.handler._mark_allowed(self.request, menus) menu = menus[0] self.assertFalse(menu["allowed"]) foo, submenu = menu["items"] self.assertFalse(foo["allowed"]) self.assertFalse(submenu["allowed"]) subitem = submenu["items"][0] self.assertFalse(subitem["allowed"]) def test_make_menu_key(self): self.assertEqual(self.handler._make_menu_key("foo"), "foo") self.assertEqual(self.handler._make_menu_key("FooBar"), "foobar") self.assertEqual(self.handler._make_menu_key("Foo - $#Bar"), "foobar") self.assertEqual(self.handler._make_menu_key("Foo__Bar"), "foo__bar") def test_make_menu_entry_item(self): item = {"title": "Foo", "url": "#"} entry = self.handler._make_menu_entry(self.request, item) self.assertEqual(entry["type"], "item") self.assertEqual(entry["title"], "Foo") self.assertEqual(entry["url"], "#") self.assertTrue(entry["is_link"]) def test_make_menu_entry_item_with_no_url(self): item = {"title": "Foo"} entry = self.handler._make_menu_entry(self.request, item) self.assertEqual(entry["type"], "item") self.assertEqual(entry["title"], "Foo") self.assertNotIn("url", entry) # nb. still sets is_link = True; basically it's with no href self.assertTrue(entry["is_link"]) def test_make_menu_entry_item_with_known_route(self): item = {"title": "Foo", "route": "home"} with patch.object(self.request, "route_url", return_value="/something"): entry = self.handler._make_menu_entry(self.request, item) self.assertEqual(entry["type"], "item") self.assertEqual(entry["url"], "/something") self.assertTrue(entry["is_link"]) def test_make_menu_entry_item_with_unknown_route(self): item = {"title": "Foo", "route": "home"} with patch.object(self.request, "route_url", side_effect=KeyError): entry = self.handler._make_menu_entry(self.request, item) self.assertEqual(entry["type"], "item") # nb. fake url is used, based on (bad) route name self.assertEqual(entry["url"], "home") self.assertTrue(entry["is_link"]) def test_make_menu_entry_sep(self): item = {"type": "sep"} entry = self.handler._make_menu_entry(self.request, item) self.assertEqual(entry["type"], "sep") self.assertTrue(entry["is_sep"]) self.assertFalse(entry["is_menu"]) def test_make_raw_menus(self): # minimal test to ensure it calls the other method with patch.object(self.handler, "make_menus") as make_menus: self.handler._make_raw_menus(self.request, foo="bar") make_menus.assert_called_once_with(self.request, foo="bar") def test_do_make_menus_prune_unallowed_item(self): test_menus = [ { "title": "First Menu", "type": "menu", "items": [ {"title": "Foo", "url": "#"}, {"title": "Bar", "url": "#"}, ], }, ] def is_allowed(request, item): if item.get("title") == "Bar": return False return True with patch.object(self.handler, "make_menus", return_value=test_menus): with patch.object(self.handler, "_is_allowed", side_effect=is_allowed): menus = self.handler.do_make_menus(self.request) # Foo remains but Bar is pruned menu = menus[0] self.assertEqual(len(menu["items"]), 1) item = menu["items"][0] self.assertEqual(item["title"], "Foo") def test_do_make_menus_prune_unallowed_menu(self): test_menus = [ { "title": "First Menu", "type": "menu", "items": [ {"title": "Foo", "url": "#"}, {"title": "Bar", "url": "#"}, ], }, { "title": "Second Menu", "type": "menu", "items": [ {"title": "Baz", "url": "#"}, ], }, ] def is_allowed(request, item): if item.get("title") == "Baz": return True return False with patch.object(self.handler, "make_menus", return_value=test_menus): with patch.object(self.handler, "_is_allowed", side_effect=is_allowed): menus = self.handler.do_make_menus(self.request) # Second/Baz remains but First/Foo/Bar are pruned self.assertEqual(len(menus), 1) menu = menus[0] self.assertEqual(menu["title"], "Second Menu") self.assertEqual(len(menu["items"]), 1) item = menu["items"][0] self.assertEqual(item["title"], "Baz") def test_do_make_menus_with_top_link(self): test_menus = [ { "title": "First Menu", "type": "menu", "items": [ {"title": "Foo", "url": "#"}, {"title": "Bar", "url": "#"}, ], }, { "title": "Second Link", "type": "link", }, ] with patch.object(self.handler, "make_menus", return_value=test_menus): with patch.object(self.handler, "_is_allowed", return_value=True): menus = self.handler.do_make_menus(self.request) # ensure top link remains self.assertEqual(len(menus), 2) menu = menus[1] self.assertEqual(menu["title"], "Second Link") def test_do_make_menus_with_trailing_sep(self): test_menus = [ { "title": "First Menu", "type": "menu", "items": [ {"title": "Foo", "url": "#"}, {"title": "Bar", "url": "#"}, {"type": "sep"}, ], }, ] with patch.object(self.handler, "make_menus", return_value=test_menus): with patch.object(self.handler, "_is_allowed", return_value=True): menus = self.handler.do_make_menus(self.request) # ensure trailing sep was pruned menu = menus[0] self.assertEqual(len(menu["items"]), 2) foo, bar = menu["items"] self.assertEqual(foo["title"], "Foo") self.assertEqual(bar["title"], "Bar") def test_do_make_menus_with_submenu(self): test_menus = [ { "title": "First Menu", "type": "menu", "items": [ { "title": "First Submenu", "type": "menu", "items": [ {"title": "Foo", "url": "#"}, ], }, { "title": "Second Submenu", "type": "menu", "items": [ {"title": "Bar", "url": "#"}, ], }, ], }, ] def is_allowed(request, item): if item.get("title") == "Bar": return False return True with patch.object(self.handler, "make_menus", return_value=test_menus): with patch.object(self.handler, "_is_allowed", side_effect=is_allowed): menus = self.handler.do_make_menus(self.request) # first submenu remains, second is pruned menu = menus[0] self.assertEqual(len(menu["items"]), 1) submenu = menu["items"][0] self.assertEqual(submenu["type"], "submenu") self.assertEqual(submenu["title"], "First Submenu") self.assertEqual(len(submenu["items"]), 1) item = submenu["items"][0] self.assertEqual(item["title"], "Foo")