# -*- coding: utf-8; -*- import functools from unittest import TestCase from unittest.mock import MagicMock, patch from pyramid import testing from pyramid.response import Response from pyramid.httpexceptions import HTTPFound, HTTPNotFound from wuttjamaican.conf import WuttaConfig from wuttaweb.views import master from wuttaweb.subscribers import new_request_set_user from tests.util import WebTestCase class TestMasterView(WebTestCase): def make_view(self): return master.MasterView(self.request) def test_defaults(self): with patch.multiple(master.MasterView, create=True, model_name='Widget', model_key='uuid', configurable=True): master.MasterView.defaults(self.pyramid_config) ############################## # class methods ############################## def test_get_model_class(self): # no model class by default self.assertIsNone(master.MasterView.get_model_class()) # subclass may specify MyModel = MagicMock() with patch.multiple(master.MasterView, create=True, model_class=MyModel): self.assertIs(master.MasterView.get_model_class(), MyModel) def test_get_model_name(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_model_name) # subclass may specify model name master.MasterView.model_name = 'Widget' self.assertEqual(master.MasterView.get_model_name(), 'Widget') del master.MasterView.model_name # or it may specify model class MyModel = MagicMock(__name__='Blaster') with patch.multiple(master.MasterView, create=True, model_class=MyModel): self.assertEqual(master.MasterView.get_model_name(), 'Blaster') def test_get_model_name_normalized(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_model_name_normalized) # subclass may specify *normalized* model name master.MasterView.model_name_normalized = 'widget' self.assertEqual(master.MasterView.get_model_name_normalized(), 'widget') del master.MasterView.model_name_normalized # or it may specify *standard* model name master.MasterView.model_name = 'Blaster' self.assertEqual(master.MasterView.get_model_name_normalized(), 'blaster') del master.MasterView.model_name # or it may specify model class MyModel = MagicMock(__name__='Dinosaur') with patch.multiple(master.MasterView, create=True, model_class=MyModel): self.assertEqual(master.MasterView.get_model_name_normalized(), 'dinosaur') def test_get_model_title(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_model_title) # subclass may specify model title master.MasterView.model_title = 'Wutta Widget' self.assertEqual(master.MasterView.get_model_title(), "Wutta Widget") del master.MasterView.model_title # or it may specify model name master.MasterView.model_name = 'Blaster' self.assertEqual(master.MasterView.get_model_title(), "Blaster") del master.MasterView.model_name # or it may specify model class MyModel = MagicMock(__name__='Dinosaur') with patch.multiple(master.MasterView, create=True, model_class=MyModel): self.assertEqual(master.MasterView.get_model_title(), "Dinosaur") def test_get_model_title_plural(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_model_title_plural) # subclass may specify *plural* model title master.MasterView.model_title_plural = 'People' self.assertEqual(master.MasterView.get_model_title_plural(), "People") del master.MasterView.model_title_plural # or it may specify *singular* model title master.MasterView.model_title = 'Wutta Widget' self.assertEqual(master.MasterView.get_model_title_plural(), "Wutta Widgets") del master.MasterView.model_title # or it may specify model name master.MasterView.model_name = 'Blaster' self.assertEqual(master.MasterView.get_model_title_plural(), "Blasters") del master.MasterView.model_name # or it may specify model class MyModel = MagicMock(__name__='Dinosaur') with patch.multiple(master.MasterView, create=True, model_class=MyModel): self.assertEqual(master.MasterView.get_model_title_plural(), "Dinosaurs") def test_get_model_key(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_model_key) # subclass may specify model key master.MasterView.model_key = 'uuid' self.assertEqual(master.MasterView.get_model_key(), ('uuid',)) del master.MasterView.model_key def test_get_route_prefix(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_route_prefix) # subclass may specify route prefix master.MasterView.route_prefix = 'widgets' self.assertEqual(master.MasterView.get_route_prefix(), 'widgets') del master.MasterView.route_prefix # subclass may specify *normalized* model name master.MasterView.model_name_normalized = 'blaster' self.assertEqual(master.MasterView.get_route_prefix(), 'blasters') del master.MasterView.model_name_normalized # or it may specify *standard* model name master.MasterView.model_name = 'Dinosaur' self.assertEqual(master.MasterView.get_route_prefix(), 'dinosaurs') del master.MasterView.model_name # or it may specify model class MyModel = MagicMock(__name__='Truck') with patch.multiple(master.MasterView, create=True, model_class=MyModel): self.assertEqual(master.MasterView.get_route_prefix(), 'trucks') def test_get_permission_prefix(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_permission_prefix) # subclass may specify permission prefix with patch.object(master.MasterView, 'permission_prefix', new='widgets', create=True): self.assertEqual(master.MasterView.get_permission_prefix(), 'widgets') # subclass may specify route prefix with patch.object(master.MasterView, 'route_prefix', new='widgets', create=True): self.assertEqual(master.MasterView.get_permission_prefix(), 'widgets') # or it may specify model class Truck = MagicMock(__name__='Truck') with patch.object(master.MasterView, 'model_class', new=Truck, create=True): self.assertEqual(master.MasterView.get_permission_prefix(), 'trucks') def test_get_url_prefix(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_url_prefix) # subclass may specify url prefix master.MasterView.url_prefix = '/widgets' self.assertEqual(master.MasterView.get_url_prefix(), '/widgets') del master.MasterView.url_prefix # or it may specify route prefix master.MasterView.route_prefix = 'trucks' self.assertEqual(master.MasterView.get_url_prefix(), '/trucks') del master.MasterView.route_prefix # or it may specify *normalized* model name master.MasterView.model_name_normalized = 'blaster' self.assertEqual(master.MasterView.get_url_prefix(), '/blasters') del master.MasterView.model_name_normalized # or it may specify *standard* model name master.MasterView.model_name = 'Dinosaur' self.assertEqual(master.MasterView.get_url_prefix(), '/dinosaurs') del master.MasterView.model_name # or it may specify model class MyModel = MagicMock(__name__='Machine') with patch.multiple(master.MasterView, create=True, model_class=MyModel): self.assertEqual(master.MasterView.get_url_prefix(), '/machines') def test_get_instance_url_prefix(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_instance_url_prefix) # typical example with url_prefix and simple key master.MasterView.url_prefix = '/widgets' master.MasterView.model_key = 'uuid' self.assertEqual(master.MasterView.get_instance_url_prefix(), '/widgets/{uuid}') del master.MasterView.url_prefix del master.MasterView.model_key # typical example with composite key master.MasterView.url_prefix = '/widgets' master.MasterView.model_key = ('foo', 'bar') self.assertEqual(master.MasterView.get_instance_url_prefix(), '/widgets/{foo}|{bar}') del master.MasterView.url_prefix del master.MasterView.model_key def test_get_template_prefix(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_template_prefix) # subclass may specify template prefix master.MasterView.template_prefix = '/widgets' self.assertEqual(master.MasterView.get_template_prefix(), '/widgets') del master.MasterView.template_prefix # or it may specify url prefix master.MasterView.url_prefix = '/trees' self.assertEqual(master.MasterView.get_template_prefix(), '/trees') del master.MasterView.url_prefix # or it may specify route prefix master.MasterView.route_prefix = 'trucks' self.assertEqual(master.MasterView.get_template_prefix(), '/trucks') del master.MasterView.route_prefix # or it may specify *normalized* model name master.MasterView.model_name_normalized = 'blaster' self.assertEqual(master.MasterView.get_template_prefix(), '/blasters') del master.MasterView.model_name_normalized # or it may specify *standard* model name master.MasterView.model_name = 'Dinosaur' self.assertEqual(master.MasterView.get_template_prefix(), '/dinosaurs') del master.MasterView.model_name # or it may specify model class MyModel = MagicMock(__name__='Machine') with patch.multiple(master.MasterView, create=True, model_class=MyModel): self.assertEqual(master.MasterView.get_template_prefix(), '/machines') def test_get_grid_key(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_grid_key) # subclass may specify grid key master.MasterView.grid_key = 'widgets' self.assertEqual(master.MasterView.get_grid_key(), 'widgets') del master.MasterView.grid_key # or it may specify route prefix master.MasterView.route_prefix = 'trucks' self.assertEqual(master.MasterView.get_grid_key(), 'trucks') del master.MasterView.route_prefix # or it may specify *normalized* model name master.MasterView.model_name_normalized = 'blaster' self.assertEqual(master.MasterView.get_grid_key(), 'blasters') del master.MasterView.model_name_normalized # or it may specify *standard* model name master.MasterView.model_name = 'Dinosaur' self.assertEqual(master.MasterView.get_grid_key(), 'dinosaurs') del master.MasterView.model_name # or it may specify model class MyModel = MagicMock(__name__='Machine') with patch.multiple(master.MasterView, create=True, model_class=MyModel): self.assertEqual(master.MasterView.get_grid_key(), 'machines') def test_get_config_title(self): # error by default (since no model class) self.assertRaises(AttributeError, master.MasterView.get_config_title) # subclass may specify config title master.MasterView.config_title = 'Widgets' self.assertEqual(master.MasterView.get_config_title(), "Widgets") del master.MasterView.config_title # subclass may specify *plural* model title master.MasterView.model_title_plural = 'People' self.assertEqual(master.MasterView.get_config_title(), "People") del master.MasterView.model_title_plural # or it may specify *singular* model title master.MasterView.model_title = 'Wutta Widget' self.assertEqual(master.MasterView.get_config_title(), "Wutta Widgets") del master.MasterView.model_title # or it may specify model name master.MasterView.model_name = 'Blaster' self.assertEqual(master.MasterView.get_config_title(), "Blasters") del master.MasterView.model_name # or it may specify model class MyModel = MagicMock(__name__='Dinosaur') with patch.multiple(master.MasterView, create=True, model_class=MyModel): self.assertEqual(master.MasterView.get_config_title(), "Dinosaurs") ############################## # support methods ############################## def test_has_perm(self): model = self.app.model auth = self.app.get_auth_handler() with patch.multiple(master.MasterView, create=True, model_name='Setting'): view = self.make_view() # anonymous user self.assertFalse(view.has_perm('list')) self.assertFalse(self.request.has_perm('list')) # reset del self.request.user_permissions # make 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, 'settings.list') self.session.commit() # this user has perms self.request.user = barney self.assertTrue(view.has_perm('list')) self.assertTrue(self.request.has_perm('settings.list')) def test_has_any_perm(self): model = self.app.model auth = self.app.get_auth_handler() with patch.multiple(master.MasterView, create=True, model_name='Setting'): view = self.make_view() # anonymous user self.assertFalse(view.has_any_perm('list', 'view')) self.assertFalse(self.request.has_any_perm('settings.list', 'settings.view')) # reset del self.request.user_permissions # make 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, 'settings.view') self.session.commit() # this user has perms self.request.user = barney self.assertTrue(view.has_any_perm('list', 'view')) self.assertTrue(self.request.has_any_perm('settings.list', 'settings.view')) def test_render_to_response(self): self.pyramid_config.include('wuttaweb.views.common') self.pyramid_config.include('wuttaweb.views.auth') self.pyramid_config.add_route('appinfo', '/appinfo/') def widgets(request): return {} self.pyramid_config.add_route('widgets', '/widgets/') self.pyramid_config.add_view(widgets, route_name='widgets') # basic sanity check using /master/index.mako # (nb. it skips /widgets/index.mako since that doesn't exist) with patch.multiple(master.MasterView, create=True, model_name='Widget', creatable=False): view = master.MasterView(self.request) response = view.render_to_response('index', {}) self.assertIsInstance(response, Response) # basic sanity check using /appinfo/index.mako with patch.multiple(master.MasterView, create=True, model_name='AppInfo', route_prefix='appinfo', url_prefix='/appinfo', creatable=False): view = master.MasterView(self.request) response = view.render_to_response('index', {}) self.assertIsInstance(response, Response) # bad template name causes error master.MasterView.model_name = 'Widget' self.assertRaises(IOError, view.render_to_response, 'nonexistent', {}) del master.MasterView.model_name def test_get_index_title(self): master.MasterView.model_title_plural = "Wutta Widgets" view = master.MasterView(self.request) self.assertEqual(view.get_index_title(), "Wutta Widgets") del master.MasterView.model_title_plural def test_make_model_grid(self): model = self.app.model # no model class with patch.multiple(master.MasterView, create=True, model_name='Widget', model_key='uuid'): view = master.MasterView(self.request) grid = view.make_model_grid() self.assertIsNone(grid.model_class) # explicit model class with patch.multiple(master.MasterView, create=True, model_class=model.Setting): grid = view.make_model_grid(session=self.session) self.assertIs(grid.model_class, model.Setting) # no actions by default with patch.multiple(master.MasterView, create=True, model_class=model.Setting): grid = view.make_model_grid(session=self.session) self.assertEqual(grid.actions, []) # now let's test some more actions logic with patch.multiple(master.MasterView, create=True, model_class=model.Setting, viewable=True, editable=True, deletable=True): # should have 3 actions now, but for lack of perms grid = view.make_model_grid(session=self.session) self.assertEqual(len(grid.actions), 0) # but root user has perms, so gets 3 actions with patch.object(self.request, 'is_root', new=True): grid = view.make_model_grid(session=self.session) self.assertEqual(len(grid.actions), 3) def test_get_grid_data(self): model = self.app.model self.app.save_setting(self.session, 'foo', 'bar') self.session.commit() setting = self.session.query(model.Setting).one() view = self.make_view() # empty by default self.assertFalse(hasattr(master.MasterView, 'model_class')) data = view.get_grid_data(session=self.session) self.assertEqual(data, []) # basic logic with Setting model with patch.multiple(master.MasterView, create=True, model_class=model.Setting): view = master.MasterView(self.request) data = view.get_grid_data(session=self.session) self.assertEqual(len(data), 1) self.assertIs(data[0], setting) def test_configure_grid(self): model = self.app.model # uuid field is pruned with patch.multiple(master.MasterView, create=True, model_class=model.Setting): view = master.MasterView(self.request) grid = view.make_grid(model_class=model.Setting, columns=['uuid', 'name', 'value']) self.assertIn('uuid', grid.columns) view.configure_grid(grid) self.assertNotIn('uuid', grid.columns) def test_grid_render_notes(self): model = self.app.model view = self.make_view() # null text = None role = model.Role(name="Foo", notes=text) value = view.grid_render_notes(role, 'notes', text) self.assertIsNone(value) # short string text = "hello world" role = model.Role(name="Foo", notes=text) value = view.grid_render_notes(role, 'notes', text) self.assertEqual(value, text) # long string text = "hello world " * 20 role = model.Role(name="Foo", notes=text) value = view.grid_render_notes(role, 'notes', text) self.assertIn('