3
0
Fork 0

fix: format all code with black

and from now on should not deviate from that...
This commit is contained in:
Lance Edgar 2025-08-31 12:26:43 -05:00
parent 8a09fb1a3c
commit 4d0693862d
68 changed files with 6693 additions and 5659 deletions

View file

@ -10,8 +10,8 @@ from wuttaweb.cli import webapp as mod
class TestWebapp(ConfigTestCase):
def make_context(self, **kwargs):
params = {'auto_reload': False}
params.update(kwargs.get('params', {}))
params = {"auto_reload": False}
params.update(kwargs.get("params", {}))
ctx = MagicMock(params=params)
ctx.parent.wutta_config = self.config
return ctx
@ -19,7 +19,7 @@ class TestWebapp(ConfigTestCase):
def test_missing_config_file(self):
# nb. our default config has no files, so can test w/ that
ctx = self.make_context()
with patch.object(mod, 'sys') as sys:
with patch.object(mod, "sys") as sys:
sys.exit.side_effect = RuntimeError
self.assertRaises(RuntimeError, mod.webapp, ctx)
sys.stderr.write.assert_called_once_with("no config files found!\n")
@ -28,14 +28,17 @@ class TestWebapp(ConfigTestCase):
def test_invalid_runner(self):
# make new config from file, with bad setting
path = self.write_file('my.conf', """
path = self.write_file(
"my.conf",
"""
[wutta.web]
app.runner = bogus
""")
""",
)
self.config = self.make_config(files=[path])
ctx = self.make_context()
with patch.object(mod, 'sys') as sys:
with patch.object(mod, "sys") as sys:
sys.exit.side_effect = RuntimeError
self.assertRaises(RuntimeError, mod.webapp, ctx)
sys.stderr.write.assert_called_once_with("unknown web app runner: bogus\n")
@ -43,64 +46,76 @@ app.runner = bogus
def test_pserve(self):
path = self.write_file('my.conf', """
path = self.write_file(
"my.conf",
"""
[wutta.web]
app.runner = pserve
""")
""",
)
self.config = self.make_config(files=[path])
# normal
with patch.object(mod, 'pserve') as pserve:
with patch.object(mod, "pserve") as pserve:
ctx = self.make_context()
mod.webapp(ctx)
pserve.main.assert_called_once_with(argv=['pserve', f'file+ini:{path}'])
pserve.main.assert_called_once_with(argv=["pserve", f"file+ini:{path}"])
# with reload
with patch.object(mod, 'pserve') as pserve:
ctx = self.make_context(params={'auto_reload': True})
with patch.object(mod, "pserve") as pserve:
ctx = self.make_context(params={"auto_reload": True})
mod.webapp(ctx)
pserve.main.assert_called_once_with(argv=['pserve', f'file+ini:{path}', '--reload'])
pserve.main.assert_called_once_with(
argv=["pserve", f"file+ini:{path}", "--reload"]
)
def test_uvicorn(self):
path = self.write_file('my.conf', """
path = self.write_file(
"my.conf",
"""
[wutta.web]
app.runner = uvicorn
app.spec = wuttaweb.app:make_wsgi_app
""")
""",
)
self.config = self.make_config(files=[path])
orig_import = __import__
uvicorn = MagicMock()
def mock_import(name, *args, **kwargs):
if name == 'uvicorn':
if name == "uvicorn":
return uvicorn
return orig_import(name, *args, **kwargs)
# normal
with patch('builtins.__import__', side_effect=mock_import):
with patch("builtins.__import__", side_effect=mock_import):
ctx = self.make_context()
mod.webapp(ctx)
uvicorn.run.assert_called_once_with('wuttaweb.app:make_wsgi_app',
host='127.0.0.1',
port=8000,
reload=False,
reload_dirs=None,
factory=False,
interface='auto',
root_path='')
uvicorn.run.assert_called_once_with(
"wuttaweb.app:make_wsgi_app",
host="127.0.0.1",
port=8000,
reload=False,
reload_dirs=None,
factory=False,
interface="auto",
root_path="",
)
# with reload
uvicorn.run.reset_mock()
with patch('builtins.__import__', side_effect=mock_import):
ctx = self.make_context(params={'auto_reload': True})
with patch("builtins.__import__", side_effect=mock_import):
ctx = self.make_context(params={"auto_reload": True})
mod.webapp(ctx)
uvicorn.run.assert_called_once_with('wuttaweb.app:make_wsgi_app',
host='127.0.0.1',
port=8000,
reload=True,
reload_dirs=None,
factory=False,
interface='auto',
root_path='')
uvicorn.run.assert_called_once_with(
"wuttaweb.app:make_wsgi_app",
host="127.0.0.1",
port=8000,
reload=True,
reload_dirs=None,
factory=False,
interface="auto",
root_path="",
)

View file

@ -11,7 +11,7 @@ from wuttaweb.testing import WebTestCase
class TestWuttaWebContinuumPlugin(WebTestCase):
def setUp(self):
if not hasattr(mod, 'WuttaWebContinuumPlugin'):
if not hasattr(mod, "WuttaWebContinuumPlugin"):
pytest.skip("test not relevant without sqlalchemy-continuum")
self.setup_web()
@ -21,17 +21,17 @@ class TestWuttaWebContinuumPlugin(WebTestCase):
def test_get_remote_addr(self):
plugin = self.make_plugin()
with patch.object(mod, 'get_current_request', return_value=None):
with patch.object(mod, "get_current_request", return_value=None):
self.assertIsNone(plugin.get_remote_addr(None, self.session))
self.request.client_addr = '127.0.0.1'
self.assertEqual(plugin.get_remote_addr(None, self.session), '127.0.0.1')
self.request.client_addr = "127.0.0.1"
self.assertEqual(plugin.get_remote_addr(None, self.session), "127.0.0.1")
def test_get_user_id(self):
plugin = self.make_plugin()
with patch.object(mod, 'get_current_request', return_value=None):
with patch.object(mod, "get_current_request", return_value=None):
self.assertIsNone(plugin.get_user_id(None, self.session))
self.request.user = MagicMock(uuid='some-random-uuid')
self.assertEqual(plugin.get_user_id(None, self.session), 'some-random-uuid')
self.request.user = MagicMock(uuid="some-random-uuid")
self.assertEqual(plugin.get_user_id(None, self.session), "some-random-uuid")

View file

@ -18,17 +18,22 @@ from wuttaweb.grids import Grid
class TestForm(TestCase):
def setUp(self):
self.config = WuttaConfig(defaults={
'wutta.web.menus.handler_spec': 'tests.util:NullMenuHandler',
})
self.config = WuttaConfig(
defaults={
"wutta.web.menus.handler_spec": "tests.util:NullMenuHandler",
}
)
self.app = self.config.get_app()
self.request = testing.DummyRequest(wutta_config=self.config, use_oruga=False)
self.pyramid_config = testing.setUp(request=self.request, settings={
'wutta_config': self.config,
'mako.directories': ['wuttaweb:templates'],
'pyramid_deform.template_search_path': 'wuttaweb:templates/deform',
})
self.pyramid_config = testing.setUp(
request=self.request,
settings={
"wutta_config": self.config,
"mako.directories": ["wuttaweb:templates"],
"pyramid_deform.template_search_path": "wuttaweb:templates/deform",
},
)
event = MagicMock(request=self.request)
subscribers.new_request(event)
@ -40,12 +45,12 @@ class TestForm(TestCase):
return base.Form(self.request, **kwargs)
def make_schema(self):
schema = colander.Schema(children=[
colander.SchemaNode(colander.String(),
name='foo'),
colander.SchemaNode(colander.String(),
name='bar'),
])
schema = colander.Schema(
children=[
colander.SchemaNode(colander.String(), name="foo"),
colander.SchemaNode(colander.String(), name="bar"),
]
)
return schema
def test_init_with_none(self):
@ -53,126 +58,126 @@ class TestForm(TestCase):
self.assertEqual(form.fields, [])
def test_init_with_fields(self):
form = self.make_form(fields=['foo', 'bar'])
self.assertEqual(form.fields, ['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
self.assertEqual(form.fields, ["foo", "bar"])
def test_init_with_schema(self):
schema = self.make_schema()
form = self.make_form(schema=schema)
self.assertEqual(form.fields, ['foo', 'bar'])
self.assertEqual(form.fields, ["foo", "bar"])
def test_vue_tagname(self):
form = self.make_form()
self.assertEqual(form.vue_tagname, 'wutta-form')
self.assertEqual(form.vue_tagname, "wutta-form")
def test_vue_component(self):
form = self.make_form()
self.assertEqual(form.vue_component, 'WuttaForm')
self.assertEqual(form.vue_component, "WuttaForm")
def test_contains(self):
form = self.make_form(fields=['foo', 'bar'])
self.assertIn('foo', form)
self.assertNotIn('baz', form)
form = self.make_form(fields=["foo", "bar"])
self.assertIn("foo", form)
self.assertNotIn("baz", form)
def test_iter(self):
form = self.make_form(fields=['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
fields = list(iter(form))
self.assertEqual(fields, ['foo', 'bar'])
self.assertEqual(fields, ["foo", "bar"])
fields = []
for field in form:
fields.append(field)
self.assertEqual(fields, ['foo', 'bar'])
self.assertEqual(fields, ["foo", "bar"])
def test_set_fields(self):
form = self.make_form(fields=['foo', 'bar'])
self.assertEqual(form.fields, ['foo', 'bar'])
form.set_fields(['baz'])
self.assertEqual(form.fields, ['baz'])
form = self.make_form(fields=["foo", "bar"])
self.assertEqual(form.fields, ["foo", "bar"])
form.set_fields(["baz"])
self.assertEqual(form.fields, ["baz"])
def test_append(self):
form = self.make_form(fields=['one', 'two'])
self.assertEqual(form.fields, ['one', 'two'])
form.append('one', 'two', 'three')
self.assertEqual(form.fields, ['one', 'two', 'three'])
form = self.make_form(fields=["one", "two"])
self.assertEqual(form.fields, ["one", "two"])
form.append("one", "two", "three")
self.assertEqual(form.fields, ["one", "two", "three"])
def test_remove(self):
form = self.make_form(fields=['one', 'two', 'three', 'four'])
self.assertEqual(form.fields, ['one', 'two', 'three', 'four'])
form.remove('two', 'three')
self.assertEqual(form.fields, ['one', 'four'])
form = self.make_form(fields=["one", "two", "three", "four"])
self.assertEqual(form.fields, ["one", "two", "three", "four"])
form.remove("two", "three")
self.assertEqual(form.fields, ["one", "four"])
def test_set_node(self):
form = self.make_form(fields=['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
self.assertEqual(form.nodes, {})
# complete node
node = colander.SchemaNode(colander.Bool(), name='foo')
form.set_node('foo', node)
self.assertIs(form.nodes['foo'], node)
node = colander.SchemaNode(colander.Bool(), name="foo")
form.set_node("foo", node)
self.assertIs(form.nodes["foo"], node)
# type only
typ = colander.Bool()
form.set_node('foo', typ)
node = form.nodes['foo']
form.set_node("foo", typ)
node = form.nodes["foo"]
self.assertIsInstance(node, colander.SchemaNode)
self.assertIsInstance(node.typ, colander.Bool)
self.assertEqual(node.name, 'foo')
self.assertEqual(node.name, "foo")
# schema is updated if already present
schema = form.get_schema()
self.assertIsNotNone(schema)
typ = colander.Date()
form.set_node('foo', typ)
node = form.nodes['foo']
form.set_node("foo", typ)
node = form.nodes["foo"]
self.assertIsInstance(node, colander.SchemaNode)
self.assertIsInstance(node.typ, colander.Date)
self.assertEqual(node.name, 'foo')
self.assertEqual(node.name, "foo")
def test_set_widget(self):
form = self.make_form(fields=['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
self.assertEqual(form.widgets, {})
# basic
widget = widgets.SelectWidget()
form.set_widget('foo', widget)
self.assertIs(form.widgets['foo'], widget)
form.set_widget("foo", widget)
self.assertIs(form.widgets["foo"], widget)
# schema is updated if already present
schema = form.get_schema()
self.assertIsNotNone(schema)
self.assertIs(schema['foo'].widget, widget)
self.assertIs(schema["foo"].widget, widget)
new_widget = widgets.TextInputWidget()
form.set_widget('foo', new_widget)
self.assertIs(form.widgets['foo'], new_widget)
self.assertIs(schema['foo'].widget, new_widget)
form.set_widget("foo", new_widget)
self.assertIs(form.widgets["foo"], new_widget)
self.assertIs(schema["foo"].widget, new_widget)
# can also just specify widget pseudo-type (invalid)
self.assertNotIn('bar', form.widgets)
self.assertRaises(ValueError, form.set_widget, 'bar', 'ldjfadjfadj')
self.assertNotIn("bar", form.widgets)
self.assertRaises(ValueError, form.set_widget, "bar", "ldjfadjfadj")
# can also just specify widget pseudo-type (valid)
self.assertNotIn('bar', form.widgets)
form.set_widget('bar', 'notes')
self.assertIsInstance(form.widgets['bar'], widgets.NotesWidget)
self.assertNotIn("bar", form.widgets)
form.set_widget("bar", "notes")
self.assertIsInstance(form.widgets["bar"], widgets.NotesWidget)
def test_make_widget(self):
form = self.make_form(fields=['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
# notes
widget = form.make_widget('notes')
widget = form.make_widget("notes")
self.assertIsInstance(widget, widgets.NotesWidget)
# invalid
widget = form.make_widget('fdajvdafjjf')
widget = form.make_widget("fdajvdafjjf")
self.assertIsNone(widget)
def test_set_default_widgets(self):
model = self.app.model
# no defaults for "plain" schema
form = self.make_form(fields=['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
self.assertEqual(form.widgets, {})
# no defaults for "plain" mapped class
@ -184,52 +189,56 @@ class TestForm(TestCase):
# widget set for datetime mapped field
form = self.make_form(model_class=model.Upgrade)
self.assertIn('created', form.widgets)
self.assertIsNot(form.widgets['created'], MyWidget)
self.assertNotIsInstance(form.widgets['created'], MyWidget)
self.assertIn("created", form.widgets)
self.assertIsNot(form.widgets["created"], MyWidget)
self.assertNotIsInstance(form.widgets["created"], MyWidget)
# widget *not* set for datetime, if override present
form = self.make_form(model_class=model.Upgrade,
widgets={'created': MyWidget()})
self.assertIn('created', form.widgets)
self.assertIsInstance(form.widgets['created'], MyWidget)
form = self.make_form(
model_class=model.Upgrade, widgets={"created": MyWidget()}
)
self.assertIn("created", form.widgets)
self.assertIsInstance(form.widgets["created"], MyWidget)
# mock up a table with all relevant column types
class Whatever(model.Base):
__tablename__ = 'whatever'
__tablename__ = "whatever"
id = sa.Column(sa.Integer(), primary_key=True)
date = sa.Column(sa.Date())
date_time = sa.Column(sa.DateTime())
# widget set for all known types
form = self.make_form(model_class=Whatever)
self.assertIsInstance(form.widgets['date'], widgets.WuttaDateWidget)
self.assertIsInstance(form.widgets['date_time'], widgets.WuttaDateTimeWidget)
self.assertIsInstance(form.widgets["date"], widgets.WuttaDateWidget)
self.assertIsInstance(form.widgets["date_time"], widgets.WuttaDateTimeWidget)
def test_set_grid(self):
form = self.make_form(fields=['foo', 'bar'])
self.assertNotIn('foo', form.widgets)
self.assertNotIn('foogrid', form.grid_vue_context)
form = self.make_form(fields=["foo", "bar"])
self.assertNotIn("foo", form.widgets)
self.assertNotIn("foogrid", form.grid_vue_context)
grid = Grid(self.request, key='foogrid',
columns=['a', 'b'],
data=[{'a': 1, 'b': 2}, {'a': 3, 'b': 4}])
grid = Grid(
self.request,
key="foogrid",
columns=["a", "b"],
data=[{"a": 1, "b": 2}, {"a": 3, "b": 4}],
)
form.set_grid('foo', grid)
self.assertIn('foo', form.widgets)
self.assertIsInstance(form.widgets['foo'], widgets.GridWidget)
self.assertIn('foogrid', form.grid_vue_context)
form.set_grid("foo", grid)
self.assertIn("foo", form.widgets)
self.assertIsInstance(form.widgets["foo"], widgets.GridWidget)
self.assertIn("foogrid", form.grid_vue_context)
def test_set_validator(self):
form = self.make_form(fields=['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
self.assertEqual(form.validators, {})
def validate1(node, value):
pass
# basic
form.set_validator('foo', validate1)
self.assertIs(form.validators['foo'], validate1)
form.set_validator("foo", validate1)
self.assertIs(form.validators["foo"], validate1)
def validate2(node, value):
pass
@ -237,18 +246,18 @@ class TestForm(TestCase):
# schema is updated if already present
schema = form.get_schema()
self.assertIsNotNone(schema)
self.assertIs(schema['foo'].validator, validate1)
form.set_validator('foo', validate2)
self.assertIs(form.validators['foo'], validate2)
self.assertIs(schema['foo'].validator, validate2)
self.assertIs(schema["foo"].validator, validate1)
form.set_validator("foo", validate2)
self.assertIs(form.validators["foo"], validate2)
self.assertIs(schema["foo"].validator, validate2)
def test_set_default(self):
form = self.make_form(fields=['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
self.assertEqual(form.defaults, {})
# basic
form.set_default('foo', 42)
self.assertEqual(form.defaults['foo'], 42)
form.set_default("foo", 42)
self.assertEqual(form.defaults["foo"], 42)
def test_get_schema(self):
model = self.app.model
@ -262,10 +271,10 @@ class TestForm(TestCase):
self.assertIs(form.get_schema(), schema)
# schema is auto-generated if fields provided
form = self.make_form(fields=['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
schema = form.get_schema()
self.assertEqual(len(schema.children), 2)
self.assertEqual(schema['foo'].name, 'foo')
self.assertEqual(schema["foo"].name, "foo")
# but auto-generating without fields is not supported
form = self.make_form()
@ -276,58 +285,62 @@ class TestForm(TestCase):
form = self.make_form(model_class=model.Setting)
schema = form.get_schema()
self.assertEqual(len(schema.children), 2)
self.assertIn('name', schema)
self.assertIn('value', schema)
self.assertIn("name", schema)
self.assertIn("value", schema)
# but node overrides are honored when auto-generating
form = self.make_form(model_class=model.Setting)
value_node = colander.SchemaNode(colander.Bool(), name='value')
form.set_node('value', value_node)
value_node = colander.SchemaNode(colander.Bool(), name="value")
form.set_node("value", value_node)
schema = form.get_schema()
self.assertIs(schema['value'], value_node)
self.assertIs(schema["value"], value_node)
# schema is auto-generated if model_instance provided
form = self.make_form(model_instance=model.Setting(name='uhoh'))
self.assertEqual(form.fields, ['name', 'value'])
form = self.make_form(model_instance=model.Setting(name="uhoh"))
self.assertEqual(form.fields, ["name", "value"])
self.assertIsNone(form.schema)
# nb. force method to get new fields
del form.fields
schema = form.get_schema()
self.assertEqual(len(schema.children), 2)
self.assertIn('name', schema)
self.assertIn('value', schema)
self.assertIn("name", schema)
self.assertIn("value", schema)
# ColanderAlchemy schema still has *all* requested fields
form = self.make_form(model_instance=model.Setting(name='uhoh'),
fields=['name', 'value', 'foo', 'bar'])
self.assertEqual(form.fields, ['name', 'value', 'foo', 'bar'])
form = self.make_form(
model_instance=model.Setting(name="uhoh"),
fields=["name", "value", "foo", "bar"],
)
self.assertEqual(form.fields, ["name", "value", "foo", "bar"])
self.assertIsNone(form.schema)
schema = form.get_schema()
self.assertEqual(len(schema.children), 4)
self.assertIn('name', schema)
self.assertIn('value', schema)
self.assertIn('foo', schema)
self.assertIn('bar', schema)
self.assertIn("name", schema)
self.assertIn("value", schema)
self.assertIn("foo", schema)
self.assertIn("bar", schema)
# schema nodes are required by default
form = self.make_form(fields=['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
schema = form.get_schema()
self.assertIs(schema['foo'].missing, colander.required)
self.assertIs(schema['bar'].missing, colander.required)
self.assertIs(schema["foo"].missing, colander.required)
self.assertIs(schema["bar"].missing, colander.required)
# but fields can be marked *not* required
form = self.make_form(fields=['foo', 'bar'])
form.set_required('bar', False)
form = self.make_form(fields=["foo", "bar"])
form.set_required("bar", False)
schema = form.get_schema()
self.assertIs(schema['foo'].missing, colander.required)
self.assertIs(schema['bar'].missing, colander.null)
self.assertIs(schema["foo"].missing, colander.required)
self.assertIs(schema["bar"].missing, colander.null)
# validator overrides are honored
def validate(node, value): pass
def validate(node, value):
pass
form = self.make_form(model_class=model.Setting)
form.set_validator('name', validate)
form.set_validator("name", validate)
schema = form.get_schema()
self.assertIs(schema['name'].validator, validate)
self.assertIs(schema["name"].validator, validate)
# validator can be set for whole form
form = self.make_form(model_class=model.Setting)
@ -340,9 +353,9 @@ class TestForm(TestCase):
# default value overrides are honored
form = self.make_form(model_class=model.Setting)
form.set_default('name', 'foo')
form.set_default("name", "foo")
schema = form.get_schema()
self.assertEqual(schema['name'].default, 'foo')
self.assertEqual(schema["name"].default, "foo")
def test_get_deform(self):
model = self.app.model
@ -350,139 +363,142 @@ class TestForm(TestCase):
# basic
form = self.make_form(schema=schema)
self.assertFalse(hasattr(form, 'deform_form'))
self.assertFalse(hasattr(form, "deform_form"))
dform = form.get_deform()
self.assertIsInstance(dform, deform.Form)
self.assertIs(form.deform_form, dform)
# with model instance as dict
myobj = {'foo': 'one', 'bar': 'two'}
myobj = {"foo": "one", "bar": "two"}
form = self.make_form(schema=schema, model_instance=myobj)
dform = form.get_deform()
self.assertEqual(dform.cstruct, myobj)
# with sqlalchemy model instance
myobj = model.Setting(name='foo', value='bar')
myobj = model.Setting(name="foo", value="bar")
form = self.make_form(model_instance=myobj)
dform = form.get_deform()
self.assertEqual(dform.cstruct, {'name': 'foo', 'value': 'bar'})
self.assertEqual(dform.cstruct, {"name": "foo", "value": "bar"})
# sqlalchemy instance with null value
myobj = model.Setting(name='foo', value=None)
myobj = model.Setting(name="foo", value=None)
form = self.make_form(model_instance=myobj)
dform = form.get_deform()
self.assertEqual(dform.cstruct, {'name': 'foo', 'value': colander.null})
self.assertEqual(dform.cstruct, {"name": "foo", "value": colander.null})
def test_get_cancel_url(self):
# is referrer by default
form = self.make_form()
self.request.get_referrer = MagicMock(return_value='/cancel-default')
self.assertEqual(form.get_cancel_url(), '/cancel-default')
self.request.get_referrer = MagicMock(return_value="/cancel-default")
self.assertEqual(form.get_cancel_url(), "/cancel-default")
del self.request.get_referrer
# or can be static URL
form = self.make_form(cancel_url='/cancel-static')
self.assertEqual(form.get_cancel_url(), '/cancel-static')
form = self.make_form(cancel_url="/cancel-static")
self.assertEqual(form.get_cancel_url(), "/cancel-static")
# or can be fallback URL (nb. 'NOPE' indicates no referrer)
form = self.make_form(cancel_url_fallback='/cancel-fallback')
self.request.get_referrer = MagicMock(return_value='NOPE')
self.assertEqual(form.get_cancel_url(), '/cancel-fallback')
form = self.make_form(cancel_url_fallback="/cancel-fallback")
self.request.get_referrer = MagicMock(return_value="NOPE")
self.assertEqual(form.get_cancel_url(), "/cancel-fallback")
del self.request.get_referrer
# or can be referrer fallback, i.e. home page
form = self.make_form()
def get_referrer(default=None):
if default == 'NOPE':
return 'NOPE'
return '/home-page'
if default == "NOPE":
return "NOPE"
return "/home-page"
self.request.get_referrer = get_referrer
self.assertEqual(form.get_cancel_url(), '/home-page')
self.assertEqual(form.get_cancel_url(), "/home-page")
del self.request.get_referrer
def test_get_label(self):
form = self.make_form(fields=['foo', 'bar'])
self.assertEqual(form.get_label('foo'), "Foo")
form.set_label('foo', "Baz")
self.assertEqual(form.get_label('foo'), "Baz")
form = self.make_form(fields=["foo", "bar"])
self.assertEqual(form.get_label("foo"), "Foo")
form.set_label("foo", "Baz")
self.assertEqual(form.get_label("foo"), "Baz")
def test_set_label(self):
form = self.make_form(fields=['foo', 'bar'])
self.assertEqual(form.get_label('foo'), "Foo")
form.set_label('foo', "Baz")
self.assertEqual(form.get_label('foo'), "Baz")
form = self.make_form(fields=["foo", "bar"])
self.assertEqual(form.get_label("foo"), "Foo")
form.set_label("foo", "Baz")
self.assertEqual(form.get_label("foo"), "Baz")
# schema should be updated when setting label
schema = self.make_schema()
form = self.make_form(schema=schema)
form.set_label('foo', "Woohoo")
self.assertEqual(form.get_label('foo'), "Woohoo")
self.assertEqual(schema['foo'].title, "Woohoo")
form.set_label("foo", "Woohoo")
self.assertEqual(form.get_label("foo"), "Woohoo")
self.assertEqual(schema["foo"].title, "Woohoo")
def test_readonly_fields(self):
form = self.make_form(fields=['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
self.assertEqual(form.readonly_fields, set())
self.assertFalse(form.is_readonly('foo'))
self.assertFalse(form.is_readonly("foo"))
form.set_readonly('foo')
self.assertEqual(form.readonly_fields, {'foo'})
self.assertTrue(form.is_readonly('foo'))
self.assertFalse(form.is_readonly('bar'))
form.set_readonly("foo")
self.assertEqual(form.readonly_fields, {"foo"})
self.assertTrue(form.is_readonly("foo"))
self.assertFalse(form.is_readonly("bar"))
form.set_readonly('bar')
self.assertEqual(form.readonly_fields, {'foo', 'bar'})
self.assertTrue(form.is_readonly('foo'))
self.assertTrue(form.is_readonly('bar'))
form.set_readonly("bar")
self.assertEqual(form.readonly_fields, {"foo", "bar"})
self.assertTrue(form.is_readonly("foo"))
self.assertTrue(form.is_readonly("bar"))
form.set_readonly('foo', False)
self.assertEqual(form.readonly_fields, {'bar'})
self.assertFalse(form.is_readonly('foo'))
self.assertTrue(form.is_readonly('bar'))
form.set_readonly("foo", False)
self.assertEqual(form.readonly_fields, {"bar"})
self.assertFalse(form.is_readonly("foo"))
self.assertTrue(form.is_readonly("bar"))
def test_required_fields(self):
form = self.make_form(fields=['foo', 'bar'])
form = self.make_form(fields=["foo", "bar"])
self.assertEqual(form.required_fields, {})
self.assertIsNone(form.is_required('foo'))
self.assertIsNone(form.is_required("foo"))
form.set_required('foo')
self.assertEqual(form.required_fields, {'foo': True})
self.assertTrue(form.is_required('foo'))
self.assertIsNone(form.is_required('bar'))
form.set_required("foo")
self.assertEqual(form.required_fields, {"foo": True})
self.assertTrue(form.is_required("foo"))
self.assertIsNone(form.is_required("bar"))
form.set_required('bar')
self.assertEqual(form.required_fields, {'foo': True, 'bar': True})
self.assertTrue(form.is_required('foo'))
self.assertTrue(form.is_required('bar'))
form.set_required("bar")
self.assertEqual(form.required_fields, {"foo": True, "bar": True})
self.assertTrue(form.is_required("foo"))
self.assertTrue(form.is_required("bar"))
form.set_required('foo', False)
self.assertEqual(form.required_fields, {'foo': False, 'bar': True})
self.assertFalse(form.is_required('foo'))
self.assertTrue(form.is_required('bar'))
form.set_required("foo", False)
self.assertEqual(form.required_fields, {"foo": False, "bar": True})
self.assertFalse(form.is_required("foo"))
self.assertTrue(form.is_required("bar"))
def test_render_vue_tag(self):
schema = self.make_schema()
form = self.make_form(schema=schema)
html = form.render_vue_tag()
self.assertEqual(html, '<wutta-form></wutta-form>')
self.assertEqual(html, "<wutta-form></wutta-form>")
def test_render_vue_template(self):
self.pyramid_config.include('pyramid_mako')
self.pyramid_config.add_subscriber('wuttaweb.subscribers.before_render',
'pyramid.events.BeforeRender')
self.pyramid_config.include("pyramid_mako")
self.pyramid_config.add_subscriber(
"wuttaweb.subscribers.before_render", "pyramid.events.BeforeRender"
)
# form button is disabled on @submit by default
schema = self.make_schema()
form = self.make_form(schema=schema, cancel_url='/')
form = self.make_form(schema=schema, cancel_url="/")
html = form.render_vue_template()
self.assertIn('<script type="text/x-template" id="wutta-form-template">', html)
self.assertIn('@submit', html)
self.assertIn("@submit", html)
# but not if form is configured otherwise
form = self.make_form(schema=schema, auto_disable_submit=False, cancel_url='/')
form = self.make_form(schema=schema, auto_disable_submit=False, cancel_url="/")
html = form.render_vue_template()
self.assertIn('<script type="text/x-template" id="wutta-form-template">', html)
self.assertNotIn('@submit', html)
self.assertNotIn("@submit", html)
def test_add_grid_vue_context(self):
form = self.make_form()
@ -492,76 +508,84 @@ class TestForm(TestCase):
self.assertRaises(ValueError, form.add_grid_vue_context, grid)
# otherwise it works
grid = Grid(self.request, key='foo')
grid = Grid(self.request, key="foo")
self.assertEqual(len(form.grid_vue_context), 0)
form.add_grid_vue_context(grid)
self.assertEqual(len(form.grid_vue_context), 1)
self.assertIn('foo', form.grid_vue_context)
self.assertEqual(form.grid_vue_context['foo'], {
'data': [],
'row_classes': {},
})
self.assertIn("foo", form.grid_vue_context)
self.assertEqual(
form.grid_vue_context["foo"],
{
"data": [],
"row_classes": {},
},
)
# calling again with same key will replace data
records = [{'foo': 1}, {'foo': 2}]
grid = Grid(self.request, key='foo', columns=['foo'], data=records)
records = [{"foo": 1}, {"foo": 2}]
grid = Grid(self.request, key="foo", columns=["foo"], data=records)
form.add_grid_vue_context(grid)
self.assertEqual(len(form.grid_vue_context), 1)
self.assertIn('foo', form.grid_vue_context)
self.assertEqual(form.grid_vue_context['foo'], {
'data': records,
'row_classes': {},
})
self.assertIn("foo", form.grid_vue_context)
self.assertEqual(
form.grid_vue_context["foo"],
{
"data": records,
"row_classes": {},
},
)
def test_render_vue_finalize(self):
form = self.make_form()
html = form.render_vue_finalize()
self.assertIn('<script>', html)
self.assertIn("<script>", html)
self.assertIn("Vue.component('wutta-form', WuttaForm)", html)
def test_render_vue_field(self):
self.pyramid_config.include('pyramid_deform')
self.pyramid_config.include("pyramid_deform")
schema = self.make_schema()
form = self.make_form(schema=schema)
dform = form.get_deform()
# typical
html = form.render_vue_field('foo')
html = form.render_vue_field("foo")
self.assertIn('<b-field :horizontal="true" label="Foo">', html)
self.assertIn('<b-input name="foo"', html)
# nb. no error message
self.assertNotIn('message', html)
self.assertNotIn("message", html)
# readonly
html = form.render_vue_field('foo', readonly=True)
html = form.render_vue_field("foo", readonly=True)
self.assertIn('<b-field :horizontal="true" label="Foo">', html)
self.assertNotIn('<b-input name="foo"', html)
# nb. no error message
self.assertNotIn('message', html)
self.assertNotIn("message", html)
# with error message
with patch.object(form, 'get_field_errors', return_value=['something is wrong']):
html = form.render_vue_field('foo')
self.assertIn('something is wrong', html)
with patch.object(
form, "get_field_errors", return_value=["something is wrong"]
):
html = form.render_vue_field("foo")
self.assertIn("something is wrong", html)
# add another field, but not to deform, so it should still
# display but with no widget
form.fields.append('zanzibar')
html = form.render_vue_field('zanzibar')
form.fields.append("zanzibar")
html = form.render_vue_field("zanzibar")
self.assertIn('<b-field :horizontal="true" label="Zanzibar">', html)
self.assertNotIn('<b-input', html)
self.assertNotIn("<b-input", html)
# nb. no error message
self.assertNotIn('message', html)
self.assertNotIn("message", html)
# try that once more but with a model record instance
with patch.object(form, 'model_instance', new={'zanzibar': 'omgwtfbbq'}):
html = form.render_vue_field('zanzibar')
self.assertIn('<b-field', html)
with patch.object(form, "model_instance", new={"zanzibar": "omgwtfbbq"}):
html = form.render_vue_field("zanzibar")
self.assertIn("<b-field", html)
self.assertIn('label="Zanzibar"', html)
self.assertNotIn('<b-input', html)
self.assertIn('>omgwtfbbq<', html)
self.assertNotIn("<b-input", html)
self.assertIn(">omgwtfbbq<", html)
# nb. no error message
self.assertNotIn('message', html)
self.assertNotIn("message", html)
def test_get_vue_field_value(self):
schema = self.make_schema()
@ -569,20 +593,20 @@ class TestForm(TestCase):
# TODO: yikes what a hack (?)
dform = form.get_deform()
dform.set_appstruct({'foo': 'one', 'bar': 'two'})
dform.set_appstruct({"foo": "one", "bar": "two"})
# null for missing field
value = form.get_vue_field_value('doesnotexist')
value = form.get_vue_field_value("doesnotexist")
self.assertIsNone(value)
# normal value is returned
value = form.get_vue_field_value('foo')
self.assertEqual(value, 'one')
value = form.get_vue_field_value("foo")
self.assertEqual(value, "one")
# but not if we remove field from deform
# TODO: what is the use case here again?
dform.children.remove(dform['foo'])
value = form.get_vue_field_value('foo')
dform.children.remove(dform["foo"])
value = form.get_vue_field_value("foo")
self.assertIsNone(value)
def test_get_vue_model_data(self):
@ -594,19 +618,22 @@ class TestForm(TestCase):
self.assertEqual(len(data), 2)
# still just 2 fields even if we request more
form.set_fields(['foo', 'bar', 'baz'])
form.set_fields(["foo", "bar", "baz"])
data = form.get_vue_model_data()
self.assertEqual(len(data), 2)
# confirm bool values make it thru as-is
schema.add(colander.SchemaNode(colander.Bool(), name='baz'))
form = self.make_form(schema=schema, model_instance={
'foo': 'one',
'bar': 'two',
'baz': True,
})
schema.add(colander.SchemaNode(colander.Bool(), name="baz"))
form = self.make_form(
schema=schema,
model_instance={
"foo": "one",
"bar": "two",
"baz": True,
},
)
data = form.get_vue_model_data()
self.assertEqual(list(data.values()), ['one', 'two', True])
self.assertEqual(list(data.values()), ["one", "two", True])
def test_has_global_errors(self):
@ -617,8 +644,8 @@ class TestForm(TestCase):
schema.validator = fail
form = self.make_form(schema=schema)
self.assertFalse(form.has_global_errors())
self.request.method = 'POST'
self.request.POST = {'foo': 'one', 'bar': 'two'}
self.request.method = "POST"
self.request.POST = {"foo": "one", "bar": "two"}
self.assertFalse(form.validate())
self.assertTrue(form.has_global_errors())
@ -631,8 +658,8 @@ class TestForm(TestCase):
schema.validator = fail
form = self.make_form(schema=schema)
self.assertEqual(form.get_global_errors(), [])
self.request.method = 'POST'
self.request.POST = {'foo': 'one', 'bar': 'two'}
self.request.method = "POST"
self.request.POST = {"foo": "one", "bar": "two"}
self.assertFalse(form.validate())
self.assertTrue(form.get_global_errors(), ["things are bad!"])
@ -641,55 +668,55 @@ class TestForm(TestCase):
# simple 'Required' validation failure
form = self.make_form(schema=schema)
self.request.method = 'POST'
self.request.POST = {'foo': 'one'}
self.request.method = "POST"
self.request.POST = {"foo": "one"}
self.assertFalse(form.validate())
errors = form.get_field_errors('bar')
self.assertEqual(errors, ['Required'])
errors = form.get_field_errors("bar")
self.assertEqual(errors, ["Required"])
# no errors
form = self.make_form(schema=schema)
self.request.POST = {'foo': 'one', 'bar': 'two'}
self.request.POST = {"foo": "one", "bar": "two"}
self.assertTrue(form.validate())
errors = form.get_field_errors('bar')
errors = form.get_field_errors("bar")
self.assertEqual(errors, [])
def test_validate(self):
schema = self.make_schema()
form = self.make_form(schema=schema)
self.assertFalse(hasattr(form, 'validated'))
self.assertFalse(hasattr(form, "validated"))
# will not validate unless request is POST
self.request.POST = {'foo': 'blarg', 'bar': 'baz'}
self.request.method = 'GET'
self.request.POST = {"foo": "blarg", "bar": "baz"}
self.request.method = "GET"
self.assertFalse(form.validate())
self.request.method = 'POST'
self.request.method = "POST"
data = form.validate()
self.assertEqual(data, {'foo': 'blarg', 'bar': 'baz'})
self.assertEqual(data, {"foo": "blarg", "bar": "baz"})
# validating a second time updates form.validated
self.request.POST = {'foo': 'BLARG', 'bar': 'BAZ'}
self.request.POST = {"foo": "BLARG", "bar": "BAZ"}
data = form.validate()
self.assertEqual(data, {'foo': 'BLARG', 'bar': 'BAZ'})
self.assertEqual(data, {"foo": "BLARG", "bar": "BAZ"})
self.assertIs(form.validated, data)
# bad data does not validate
self.request.POST = {'foo': 42, 'bar': None}
self.request.POST = {"foo": 42, "bar": None}
self.assertFalse(form.validate())
dform = form.get_deform()
self.assertEqual(len(dform.error.children), 2)
self.assertEqual(dform['foo'].errormsg, "Pstruct is not a string")
self.assertEqual(dform["foo"].errormsg, "Pstruct is not a string")
# when a form has readonly fields, validating it will *remove*
# those fields from deform/schema as well as final data dict
schema = self.make_schema()
form = self.make_form(schema=schema)
form.set_readonly('foo')
self.request.POST = {'foo': 'one', 'bar': 'two'}
form.set_readonly("foo")
self.request.POST = {"foo": "one", "bar": "two"}
data = form.validate()
self.assertEqual(data, {'bar': 'two'})
self.assertEqual(data, {"bar": "two"})
dform = form.get_deform()
self.assertNotIn('foo', schema)
self.assertNotIn('foo', dform)
self.assertIn('bar', schema)
self.assertIn('bar', dform)
self.assertNotIn("foo", schema)
self.assertNotIn("foo", dform)
self.assertIn("bar", schema)
self.assertIn("bar", dform)

View file

@ -25,17 +25,17 @@ class TestWuttaDateTime(TestCase):
result = typ.deserialize(node, colander.null)
self.assertIs(result, colander.null)
result = typ.deserialize(node, '2024-12-11T10:33 PM')
result = typ.deserialize(node, "2024-12-11T10:33 PM")
self.assertIsInstance(result, datetime.datetime)
self.assertEqual(result, datetime.datetime(2024, 12, 11, 22, 33))
self.assertIsNone(result.tzinfo)
result = typ.deserialize(node, '2024-12-11T22:33:00')
result = typ.deserialize(node, "2024-12-11T22:33:00")
self.assertIsInstance(result, datetime.datetime)
self.assertEqual(result, datetime.datetime(2024, 12, 11, 22, 33))
self.assertIsNone(result.tzinfo)
self.assertRaises(colander.Invalid, typ.deserialize, node, 'bogus')
self.assertRaises(colander.Invalid, typ.deserialize, node, "bogus")
class TestObjectNode(DataTestCase):
@ -84,20 +84,24 @@ class TestWuttaEnum(WebTestCase):
MOCK_STATUS_ONE = 1
MOCK_STATUS_TWO = 2
MOCK_STATUS = {
MOCK_STATUS_ONE: 'one',
MOCK_STATUS_TWO: 'two',
MOCK_STATUS_ONE: "one",
MOCK_STATUS_TWO: "two",
}
class TestWuttaDictEnum(WebTestCase):
def test_widget_maker(self):
typ = mod.WuttaDictEnum(self.request, MOCK_STATUS)
widget = typ.widget_maker()
self.assertIsInstance(widget, widgets.SelectWidget)
self.assertEqual(widget.values, [
(1, 'one'),
(2, 'two'),
])
self.assertEqual(
widget.values,
[
(1, "one"),
(2, "two"),
],
)
class TestWuttaMoney(WebTestCase):
@ -132,13 +136,13 @@ class TestWuttaQuantity(WebTestCase):
# quantity
result = typ.serialize(node, 42)
self.assertEqual(result, '42')
self.assertEqual(result, "42")
result = typ.serialize(node, 42.00)
self.assertEqual(result, '42')
result = typ.serialize(node, decimal.Decimal('42.00'))
self.assertEqual(result, '42')
self.assertEqual(result, "42")
result = typ.serialize(node, decimal.Decimal("42.00"))
self.assertEqual(result, "42")
result = typ.serialize(node, 42.13)
self.assertEqual(result, '42.13')
self.assertEqual(result, "42.13")
class TestObjectRef(DataTestCase):
@ -155,19 +159,19 @@ class TestObjectRef(DataTestCase):
# passing true yields default empty option
typ = mod.ObjectRef(self.request, empty_option=True)
self.assertEqual(typ.empty_option, ('', "(none)"))
self.assertEqual(typ.empty_option, ("", "(none)"))
# can set explicitly
typ = mod.ObjectRef(self.request, empty_option=('foo', 'bar'))
self.assertEqual(typ.empty_option, ('foo', 'bar'))
typ = mod.ObjectRef(self.request, empty_option=("foo", "bar"))
self.assertEqual(typ.empty_option, ("foo", "bar"))
# can set just a label
typ = mod.ObjectRef(self.request, empty_option="(empty)")
self.assertEqual(typ.empty_option, ('', "(empty)"))
self.assertEqual(typ.empty_option, ("", "(empty)"))
def test_model_class(self):
typ = mod.ObjectRef(self.request)
self.assertRaises(NotImplementedError, getattr, typ, 'model_class')
self.assertRaises(NotImplementedError, getattr, typ, "model_class")
def test_serialize(self):
model = self.app.model
@ -188,9 +192,9 @@ class TestObjectRef(DataTestCase):
self.assertEqual(value, person.uuid.hex)
# null w/ empty option
typ = mod.ObjectRef(self.request, empty_option=('bad', 'BAD'))
typ = mod.ObjectRef(self.request, empty_option=("bad", "BAD"))
value = typ.serialize(node, colander.null)
self.assertEqual(value, 'bad')
self.assertEqual(value, "bad")
def test_deserialize(self):
model = self.app.model
@ -206,8 +210,8 @@ class TestObjectRef(DataTestCase):
self.session.add(person)
self.session.commit()
self.assertIsNotNone(person.uuid)
with patch.object(mod.ObjectRef, 'model_class', new=model.Person):
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod.ObjectRef, "model_class", new=model.Person):
with patch.object(mod, "Session", return_value=self.session):
typ = mod.ObjectRef(self.request)
value = typ.deserialize(node, person.uuid)
self.assertIs(value, person)
@ -234,14 +238,14 @@ class TestObjectRef(DataTestCase):
value = typ.objectify(None)
self.assertIsNone(value)
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod, "Session", return_value=self.session):
# model instance
person = model.Person(full_name="Betty Boop")
self.session.add(person)
self.session.commit()
self.assertIsNotNone(person.uuid)
with patch.object(mod.ObjectRef, 'model_class', new=model.Person):
with patch.object(mod.ObjectRef, "model_class", new=model.Person):
# can specify as uuid
typ = mod.ObjectRef(self.request)
@ -254,22 +258,22 @@ class TestObjectRef(DataTestCase):
self.assertIs(value, person)
# error if not found
with patch.object(mod.ObjectRef, 'model_class', new=model.Person):
with patch.object(mod.ObjectRef, "model_class", new=model.Person):
typ = mod.ObjectRef(self.request)
self.assertRaises(ValueError, typ.objectify, 'WRONG-UUID')
self.assertRaises(ValueError, typ.objectify, "WRONG-UUID")
def test_get_query(self):
model = self.app.model
with patch.object(mod.ObjectRef, 'model_class', new=model.Person):
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod.ObjectRef, "model_class", new=model.Person):
with patch.object(mod, "Session", return_value=self.session):
typ = mod.ObjectRef(self.request)
query = typ.get_query()
self.assertIsInstance(query, orm.Query)
def test_sort_query(self):
model = self.app.model
with patch.object(mod.ObjectRef, 'model_class', new=model.Person):
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod.ObjectRef, "model_class", new=model.Person):
with patch.object(mod, "Session", return_value=self.session):
typ = mod.ObjectRef(self.request)
query = typ.get_query()
sorted_query = typ.sort_query(query)
@ -282,16 +286,16 @@ class TestObjectRef(DataTestCase):
self.session.commit()
# basic
with patch.object(mod.ObjectRef, 'model_class', new=model.Person):
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod.ObjectRef, "model_class", new=model.Person):
with patch.object(mod, "Session", return_value=self.session):
typ = mod.ObjectRef(self.request)
widget = typ.widget_maker()
self.assertEqual(len(widget.values), 1)
self.assertEqual(widget.values[0][1], "Betty Boop")
# empty option
with patch.object(mod.ObjectRef, 'model_class', new=model.Person):
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod.ObjectRef, "model_class", new=model.Person):
with patch.object(mod, "Session", return_value=self.session):
typ = mod.ObjectRef(self.request, empty_option=True)
widget = typ.widget_maker()
self.assertEqual(len(widget.values), 2)
@ -302,7 +306,7 @@ class TestObjectRef(DataTestCase):
class TestPersonRef(WebTestCase):
def test_sort_query(self):
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod, "Session", return_value=self.session):
typ = mod.PersonRef(self.request)
query = typ.get_query()
self.assertIsInstance(query, orm.Query)
@ -311,9 +315,9 @@ class TestPersonRef(WebTestCase):
self.assertIsNot(sorted_query, query)
def test_get_object_url(self):
self.pyramid_config.add_route('people.view', '/people/{uuid}')
self.pyramid_config.add_route("people.view", "/people/{uuid}")
model = self.app.model
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod, "Session", return_value=self.session):
typ = mod.PersonRef(self.request)
person = model.Person(full_name="Barney Rubble")
@ -322,13 +326,13 @@ class TestPersonRef(WebTestCase):
url = typ.get_object_url(person)
self.assertIsNotNone(url)
self.assertIn(f'/people/{person.uuid}', url)
self.assertIn(f"/people/{person.uuid}", url)
class TestRoleRef(WebTestCase):
def test_sort_query(self):
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod, "Session", return_value=self.session):
typ = mod.RoleRef(self.request)
query = typ.get_query()
self.assertIsInstance(query, orm.Query)
@ -337,24 +341,24 @@ class TestRoleRef(WebTestCase):
self.assertIsNot(sorted_query, query)
def test_get_object_url(self):
self.pyramid_config.add_route('roles.view', '/roles/{uuid}')
self.pyramid_config.add_route("roles.view", "/roles/{uuid}")
model = self.app.model
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod, "Session", return_value=self.session):
typ = mod.RoleRef(self.request)
role = model.Role(name='Manager')
role = model.Role(name="Manager")
self.session.add(role)
self.session.commit()
url = typ.get_object_url(role)
self.assertIsNotNone(url)
self.assertIn(f'/roles/{role.uuid}', url)
self.assertIn(f"/roles/{role.uuid}", url)
class TestUserRef(WebTestCase):
def test_sort_query(self):
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod, "Session", return_value=self.session):
typ = mod.UserRef(self.request)
query = typ.get_query()
self.assertIsInstance(query, orm.Query)
@ -363,18 +367,18 @@ class TestUserRef(WebTestCase):
self.assertIsNot(sorted_query, query)
def test_get_object_url(self):
self.pyramid_config.add_route('users.view', '/users/{uuid}')
self.pyramid_config.add_route("users.view", "/users/{uuid}")
model = self.app.model
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod, "Session", return_value=self.session):
typ = mod.UserRef(self.request)
user = model.User(username='barney')
user = model.User(username="barney")
self.session.add(user)
self.session.commit()
url = typ.get_object_url(user)
self.assertIsNotNone(url)
self.assertIn(f'/users/{user.uuid}', url)
self.assertIn(f"/users/{user.uuid}", url)
class TestRoleRefs(DataTestCase):
@ -393,7 +397,7 @@ class TestRoleRefs(DataTestCase):
self.session.add(blokes)
self.session.commit()
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod, "Session", return_value=self.session):
# with root access, default values include: admin, blokes
self.request.is_root = True
@ -427,11 +431,11 @@ class TestPermissions(DataTestCase):
# supported permissions are morphed to values
permissions = {
'widgets': {
'label': "Widgets",
'perms': {
'widgets.polish': {
'label': "Polish the widgets",
"widgets": {
"label": "Widgets",
"perms": {
"widgets.polish": {
"label": "Polish the widgets",
},
},
},
@ -439,7 +443,7 @@ class TestPermissions(DataTestCase):
typ = mod.Permissions(self.request, permissions)
widget = typ.widget_maker()
self.assertEqual(len(widget.values), 1)
self.assertEqual(widget.values[0], ('widgets.polish', "Polish the widgets"))
self.assertEqual(widget.values[0], ("widgets.polish", "Polish the widgets"))
class TestFileDownload(DataTestCase):
@ -451,10 +455,10 @@ class TestFileDownload(DataTestCase):
def test_widget_maker(self):
# sanity / coverage check
typ = mod.FileDownload(self.request, url='/foo')
typ = mod.FileDownload(self.request, url="/foo")
widget = typ.widget_maker()
self.assertIsInstance(widget, widgets.FileDownloadWidget)
self.assertEqual(widget.url, '/foo')
self.assertEqual(widget.url, "/foo")
class TestEmailRecipients(TestCase):
@ -464,14 +468,14 @@ class TestEmailRecipients(TestCase):
node = colander.SchemaNode(typ)
recips = [
'alice@example.com',
'bob@example.com',
"alice@example.com",
"bob@example.com",
]
recips_str = ', '.join(recips)
recips_str = ", ".join(recips)
# values
result = typ.serialize(node, recips_str)
self.assertEqual(result, '\n'.join(recips))
self.assertEqual(result, "\n".join(recips))
# null
result = typ.serialize(node, colander.null)
@ -482,10 +486,10 @@ class TestEmailRecipients(TestCase):
node = colander.SchemaNode(typ)
recips = [
'alice@example.com',
'bob@example.com',
"alice@example.com",
"bob@example.com",
]
recips_str = ', '.join(recips)
recips_str = ", ".join(recips)
# values
result = typ.deserialize(node, recips_str)

View file

@ -11,8 +11,14 @@ from pyramid import testing
from wuttaweb import grids
from wuttaweb.forms import widgets as mod
from wuttaweb.forms import schema
from wuttaweb.forms.schema import (FileDownload, PersonRef, RoleRefs, Permissions,
WuttaDateTime, EmailRecipients)
from wuttaweb.forms.schema import (
FileDownload,
PersonRef,
RoleRefs,
Permissions,
WuttaDateTime,
EmailRecipients,
)
from wuttaweb.testing import WebTestCase
@ -21,7 +27,7 @@ class TestObjectRefWidget(WebTestCase):
def make_field(self, node, **kwargs):
# TODO: not sure why default renderer is in use even though
# pyramid_deform was included in setup? but this works..
kwargs.setdefault('renderer', deform.Form.default_renderer)
kwargs.setdefault("renderer", deform.Form.default_renderer)
return deform.Field(node, **kwargs)
def make_widget(self, **kwargs):
@ -33,14 +39,14 @@ class TestObjectRefWidget(WebTestCase):
self.session.add(person)
self.session.commit()
with patch.object(schema, 'Session', return_value=self.session):
with patch.object(schema, "Session", return_value=self.session):
# standard (editable)
node = colander.SchemaNode(PersonRef(self.request))
widget = self.make_widget()
field = self.make_field(node)
html = widget.serialize(field, person.uuid)
self.assertIn('<b-select ', html)
self.assertIn("<b-select ", html)
# readonly
node = colander.SchemaNode(PersonRef(self.request))
@ -48,17 +54,17 @@ class TestObjectRefWidget(WebTestCase):
widget = self.make_widget()
field = self.make_field(node)
html = widget.serialize(field, person.uuid, readonly=True)
self.assertIn('Betty Boop', html)
self.assertNotIn('<a', html)
self.assertIn("Betty Boop", html)
self.assertNotIn("<a", html)
# with hyperlink
node = colander.SchemaNode(PersonRef(self.request))
node.model_instance = person
widget = self.make_widget(url=lambda p: '/foo')
widget = self.make_widget(url=lambda p: "/foo")
field = self.make_field(node)
html = widget.serialize(field, person.uuid, readonly=True)
self.assertIn('Betty Boop', html)
self.assertIn('<a', html)
self.assertIn("Betty Boop", html)
self.assertIn("<a", html)
self.assertIn('href="/foo"', html)
def test_get_template_values(self):
@ -67,24 +73,25 @@ class TestObjectRefWidget(WebTestCase):
self.session.add(person)
self.session.commit()
with patch.object(schema, 'Session', return_value=self.session):
with patch.object(schema, "Session", return_value=self.session):
# standard
node = colander.SchemaNode(PersonRef(self.request))
widget = self.make_widget()
field = self.make_field(node)
values = widget.get_template_values(field, person.uuid, {})
self.assertIn('cstruct', values)
self.assertNotIn('url', values)
self.assertIn("cstruct", values)
self.assertNotIn("url", values)
# readonly w/ empty option
node = colander.SchemaNode(PersonRef(self.request,
empty_option=('_empty_', '(empty)')))
widget = self.make_widget(readonly=True, url=lambda obj: '/foo')
node = colander.SchemaNode(
PersonRef(self.request, empty_option=("_empty_", "(empty)"))
)
widget = self.make_widget(readonly=True, url=lambda obj: "/foo")
field = self.make_field(node)
values = widget.get_template_values(field, '_empty_', {})
self.assertIn('cstruct', values)
self.assertNotIn('url', values)
values = widget.get_template_values(field, "_empty_", {})
self.assertIn("cstruct", values)
self.assertNotIn("url", values)
class TestWuttaDateWidget(WebTestCase):
@ -92,7 +99,7 @@ class TestWuttaDateWidget(WebTestCase):
def make_field(self, node, **kwargs):
# TODO: not sure why default renderer is in use even though
# pyramid_deform was included in setup? but this works..
kwargs.setdefault('renderer', deform.Form.default_renderer)
kwargs.setdefault("renderer", deform.Form.default_renderer)
return deform.Field(node, **kwargs)
def make_widget(self, **kwargs):
@ -108,11 +115,11 @@ class TestWuttaDateWidget(WebTestCase):
# editable widget has normal picker html
result = widget.serialize(field, str(dt))
self.assertIn('<wutta-datepicker', result)
self.assertIn("<wutta-datepicker", result)
# readonly is rendered per app convention
result = widget.serialize(field, str(dt), readonly=True)
self.assertEqual(result, '2025-01-15')
self.assertEqual(result, "2025-01-15")
# now try again with datetime
widget = self.make_widget()
@ -120,11 +127,11 @@ class TestWuttaDateWidget(WebTestCase):
# editable widget has normal picker html
result = widget.serialize(field, str(dt))
self.assertIn('<wutta-datepicker', result)
self.assertIn("<wutta-datepicker", result)
# readonly is rendered per app convention
result = widget.serialize(field, str(dt), readonly=True)
self.assertEqual(result, '2025-01-15')
self.assertEqual(result, "2025-01-15")
class TestWuttaDateTimeWidget(WebTestCase):
@ -132,7 +139,7 @@ class TestWuttaDateTimeWidget(WebTestCase):
def make_field(self, node, **kwargs):
# TODO: not sure why default renderer is in use even though
# pyramid_deform was included in setup? but this works..
kwargs.setdefault('renderer', deform.Form.default_renderer)
kwargs.setdefault("renderer", deform.Form.default_renderer)
return deform.Field(node, **kwargs)
def make_widget(self, **kwargs):
@ -146,11 +153,11 @@ class TestWuttaDateTimeWidget(WebTestCase):
# editable widget has normal picker html
result = widget.serialize(field, str(dt))
self.assertIn('<wutta-datepicker', result)
self.assertIn("<wutta-datepicker", result)
# readonly is rendered per app convention
result = widget.serialize(field, str(dt), readonly=True)
self.assertEqual(result, '2024-12-12 13:49+0000')
self.assertEqual(result, "2024-12-12 13:49+0000")
class TestWuttaMoneyInputWidget(WebTestCase):
@ -158,7 +165,7 @@ class TestWuttaMoneyInputWidget(WebTestCase):
def make_field(self, node, **kwargs):
# TODO: not sure why default renderer is in use even though
# pyramid_deform was included in setup? but this works..
kwargs.setdefault('renderer', deform.Form.default_renderer)
kwargs.setdefault("renderer", deform.Form.default_renderer)
return deform.Field(node, **kwargs)
def make_widget(self, **kwargs):
@ -168,19 +175,19 @@ class TestWuttaMoneyInputWidget(WebTestCase):
node = colander.SchemaNode(schema.WuttaMoney(self.request))
field = self.make_field(node)
widget = self.make_widget()
amount = decimal.Decimal('12.34')
amount = decimal.Decimal("12.34")
# editable widget has normal text input
result = widget.serialize(field, str(amount))
self.assertIn('<b-input', result)
self.assertIn("<b-input", result)
# readonly is rendered per app convention
result = widget.serialize(field, str(amount), readonly=True)
self.assertEqual(result, '<span>$12.34</span>')
self.assertEqual(result, "<span>$12.34</span>")
# readonly w/ null value
result = widget.serialize(field, None, readonly=True)
self.assertEqual(result, '<span></span>')
self.assertEqual(result, "<span></span>")
class TestFileDownloadWidget(WebTestCase):
@ -188,7 +195,7 @@ class TestFileDownloadWidget(WebTestCase):
def make_field(self, node, **kwargs):
# TODO: not sure why default renderer is in use even though
# pyramid_deform was included in setup? but this works..
kwargs.setdefault('renderer', deform.Form.default_renderer)
kwargs.setdefault("renderer", deform.Form.default_renderer)
return deform.Field(node, **kwargs)
def test_serialize(self):
@ -201,31 +208,31 @@ class TestFileDownloadWidget(WebTestCase):
# null value
html = widget.serialize(field, None, readonly=True)
self.assertNotIn('<a ', html)
self.assertIn('<span>', html)
self.assertNotIn("<a ", html)
self.assertIn("<span>", html)
# path to nonexistent file
html = widget.serialize(field, '/this/path/does/not/exist', readonly=True)
self.assertNotIn('<a ', html)
self.assertIn('<span>', html)
html = widget.serialize(field, "/this/path/does/not/exist", readonly=True)
self.assertNotIn("<a ", html)
self.assertIn("<span>", html)
# path to actual file
datfile = self.write_file('data.txt', "hello\n" * 1000)
datfile = self.write_file("data.txt", "hello\n" * 1000)
html = widget.serialize(field, datfile, readonly=True)
self.assertNotIn('<a ', html)
self.assertIn('<span>', html)
self.assertIn('data.txt', html)
self.assertIn('kB)', html)
self.assertNotIn("<a ", html)
self.assertIn("<span>", html)
self.assertIn("data.txt", html)
self.assertIn("kB)", html)
# path to file, w/ url
node = colander.SchemaNode(FileDownload(self.request, url='/download/blarg'))
node = colander.SchemaNode(FileDownload(self.request, url="/download/blarg"))
field = self.make_field(node)
widget = field.widget
html = widget.serialize(field, datfile, readonly=True)
self.assertNotIn('<span>', html)
self.assertNotIn("<span>", html)
self.assertIn('<a href="/download/blarg">', html)
self.assertIn('data.txt', html)
self.assertIn('kB)', html)
self.assertIn("data.txt", html)
self.assertIn("kB)", html)
# nb. same readonly output even if we ask for editable
html2 = widget.serialize(field, datfile, readonly=False)
@ -237,13 +244,15 @@ class TestGridWidget(WebTestCase):
def make_field(self, node, **kwargs):
# TODO: not sure why default renderer is in use even though
# pyramid_deform was included in setup? but this works..
kwargs.setdefault('renderer', deform.Form.default_renderer)
kwargs.setdefault("renderer", deform.Form.default_renderer)
return deform.Field(node, **kwargs)
def test_serialize(self):
grid = grids.Grid(self.request,
columns=['foo', 'bar'],
data=[{'foo': 1, 'bar': 2}, {'foo': 3, 'bar': 4}])
grid = grids.Grid(
self.request,
columns=["foo", "bar"],
data=[{"foo": 1, "bar": 2}, {"foo": 3, "bar": 4}],
)
node = colander.SchemaNode(colander.String())
widget = mod.GridWidget(self.request, grid)
@ -251,7 +260,7 @@ class TestGridWidget(WebTestCase):
# readonly works okay
html = widget.serialize(field, None, readonly=True)
self.assertIn('<b-table ', html)
self.assertIn("<b-table ", html)
# but otherwise, error
self.assertRaises(NotImplementedError, widget.serialize, field, None)
@ -262,11 +271,11 @@ class TestRoleRefsWidget(WebTestCase):
def make_field(self, node, **kwargs):
# TODO: not sure why default renderer is in use even though
# pyramid_deform was included in setup? but this works..
kwargs.setdefault('renderer', deform.Form.default_renderer)
kwargs.setdefault("renderer", deform.Form.default_renderer)
return deform.Field(node, **kwargs)
def test_serialize(self):
self.pyramid_config.add_route('roles.view', '/roles/{uuid}')
self.pyramid_config.add_route("roles.view", "/roles/{uuid}")
model = self.app.model
auth = self.app.get_auth_handler()
admin = auth.get_role_administrator(self.session)
@ -275,7 +284,7 @@ class TestRoleRefsWidget(WebTestCase):
self.session.commit()
# nb. we let the field construct the widget via our type
with patch.object(schema, 'Session', return_value=self.session):
with patch.object(schema, "Session", return_value=self.session):
node = colander.SchemaNode(RoleRefs(self.request))
field = self.make_field(node)
widget = field.widget
@ -305,16 +314,16 @@ class TestPermissionsWidget(WebTestCase):
def make_field(self, node, **kwargs):
# TODO: not sure why default renderer is in use even though
# pyramid_deform was included in setup? but this works..
kwargs.setdefault('renderer', deform.Form.default_renderer)
kwargs.setdefault("renderer", deform.Form.default_renderer)
return deform.Field(node, **kwargs)
def test_serialize(self):
permissions = {
'widgets': {
'label': "Widgets",
'perms': {
'widgets.polish': {
'label': "Polish the widgets",
"widgets": {
"label": "Widgets",
"perms": {
"widgets.polish": {
"label": "Polish the widgets",
},
},
},
@ -330,7 +339,7 @@ class TestPermissionsWidget(WebTestCase):
self.assertNotIn("Polish the widgets", html)
# readonly output includes the perm if set
html = widget.serialize(field, {'widgets.polish'}, readonly=True)
html = widget.serialize(field, {"widgets.polish"}, readonly=True)
self.assertIn("Polish the widgets", html)
# editable output always includes the perm
@ -343,7 +352,7 @@ class TestEmailRecipientsWidget(WebTestCase):
def make_field(self, node, **kwargs):
# TODO: not sure why default renderer is in use even though
# pyramid_deform was included in setup? but this works..
kwargs.setdefault('renderer', deform.Form.default_renderer)
kwargs.setdefault("renderer", deform.Form.default_renderer)
return deform.Field(node, **kwargs)
def test_serialize(self):
@ -352,19 +361,19 @@ class TestEmailRecipientsWidget(WebTestCase):
widget = mod.EmailRecipientsWidget()
recips = [
'alice@example.com',
'bob@example.com',
"alice@example.com",
"bob@example.com",
]
recips_str = ', '.join(recips)
recips_str = ", ".join(recips)
# readonly
result = widget.serialize(field, recips_str, readonly=True)
self.assertIn('<ul>', result)
self.assertIn('<li>alice@example.com</li>', result)
self.assertIn("<ul>", result)
self.assertIn("<li>alice@example.com</li>", result)
# editable
result = widget.serialize(field, recips_str)
self.assertIn('<b-input', result)
self.assertIn("<b-input", result)
self.assertIn('type="textarea"', result)
def test_deserialize(self):
@ -373,10 +382,10 @@ class TestEmailRecipientsWidget(WebTestCase):
widget = mod.EmailRecipientsWidget()
recips = [
'alice@example.com',
'bob@example.com',
"alice@example.com",
"bob@example.com",
]
recips_str = ', '.join(recips)
recips_str = ", ".join(recips)
# values
result = widget.deserialize(field, recips_str)
@ -392,7 +401,7 @@ class TestBatchIdWidget(WebTestCase):
def make_field(self, node, **kwargs):
# TODO: not sure why default renderer is in use even though
# pyramid_deform was included in setup? but this works..
kwargs.setdefault('renderer', deform.Form.default_renderer)
kwargs.setdefault("renderer", deform.Form.default_renderer)
return deform.Field(node, **kwargs)
def test_serialize(self):
@ -404,4 +413,4 @@ class TestBatchIdWidget(WebTestCase):
self.assertIs(result, colander.null)
result = widget.serialize(field, 42)
self.assertEqual(result, '00000042')
self.assertEqual(result, "00000042")

File diff suppressed because it is too large Load diff

View file

@ -21,24 +21,24 @@ class TestGridFilter(WebTestCase):
model = self.app.model
self.sample_data = [
{'name': 'foo1', 'value': 'ONE'},
{'name': 'foo2', 'value': 'two'},
{'name': 'foo3', 'value': 'ggg'},
{'name': 'foo4', 'value': 'ggg'},
{'name': 'foo5', 'value': 'ggg'},
{'name': 'foo6', 'value': 'six'},
{'name': 'foo7', 'value': 'seven'},
{'name': 'foo8', 'value': 'eight'},
{'name': 'foo9', 'value': 'nine'},
{"name": "foo1", "value": "ONE"},
{"name": "foo2", "value": "two"},
{"name": "foo3", "value": "ggg"},
{"name": "foo4", "value": "ggg"},
{"name": "foo5", "value": "ggg"},
{"name": "foo6", "value": "six"},
{"name": "foo7", "value": "seven"},
{"name": "foo8", "value": "eight"},
{"name": "foo9", "value": "nine"},
]
for setting in self.sample_data:
self.app.save_setting(self.session, setting['name'], setting['value'])
self.app.save_setting(self.session, setting["name"], setting["value"])
self.session.commit()
self.sample_query = self.session.query(model.Setting)
def make_filter(self, model_property, **kwargs):
factory = kwargs.pop('factory', mod.GridFilter)
kwargs['model_property'] = model_property
factory = kwargs.pop("factory", mod.GridFilter)
kwargs["model_property"] = model_property
return factory(self.request, model_property.key, **kwargs)
def test_constructor(self):
@ -46,158 +46,193 @@ class TestGridFilter(WebTestCase):
# verbs is not set by default, but can be set
filtr = self.make_filter(model.Setting.name)
self.assertFalse(hasattr(filtr, 'verbs'))
filtr = self.make_filter(model.Setting.name, verbs=['foo', 'bar'])
self.assertEqual(filtr.verbs, ['foo', 'bar'])
self.assertFalse(hasattr(filtr, "verbs"))
filtr = self.make_filter(model.Setting.name, verbs=["foo", "bar"])
self.assertEqual(filtr.verbs, ["foo", "bar"])
# verb is not set by default, but can be set
filtr = self.make_filter(model.Setting.name)
self.assertFalse(hasattr(filtr, 'verb'))
filtr = self.make_filter(model.Setting.name, verb='foo')
self.assertEqual(filtr.verb, 'foo')
self.assertFalse(hasattr(filtr, "verb"))
filtr = self.make_filter(model.Setting.name, verb="foo")
self.assertEqual(filtr.verb, "foo")
# default verb is not set by default, but can be set
filtr = self.make_filter(model.Setting.name)
self.assertFalse(hasattr(filtr, 'default_verb'))
filtr = self.make_filter(model.Setting.name, default_verb='foo')
self.assertEqual(filtr.default_verb, 'foo')
self.assertFalse(hasattr(filtr, "default_verb"))
filtr = self.make_filter(model.Setting.name, default_verb="foo")
self.assertEqual(filtr.default_verb, "foo")
def test_repr(self):
model = self.app.model
filtr = self.make_filter(model.Setting.name, factory=mod.GridFilter)
self.assertEqual(repr(filtr), "GridFilter(key='name', active=False, verb=None, value=None)")
self.assertEqual(
repr(filtr), "GridFilter(key='name', active=False, verb=None, value=None)"
)
def test_get_verbs(self):
model = self.app.model
filtr = self.make_filter(model.Setting.name, factory=mod.AlchemyFilter)
self.assertFalse(hasattr(filtr, 'verbs'))
self.assertEqual(filtr.default_verbs, ['equal', 'not_equal'])
self.assertFalse(hasattr(filtr, "verbs"))
self.assertEqual(filtr.default_verbs, ["equal", "not_equal"])
# by default, returns default verbs (plus 'is_any')
self.assertEqual(filtr.get_verbs(), ['equal', 'not_equal', 'is_any'])
self.assertEqual(filtr.get_verbs(), ["equal", "not_equal", "is_any"])
# default verbs can be a callable
filtr.default_verbs = lambda: ['foo', 'bar']
self.assertEqual(filtr.get_verbs(), ['foo', 'bar', 'is_any'])
filtr.default_verbs = lambda: ["foo", "bar"]
self.assertEqual(filtr.get_verbs(), ["foo", "bar", "is_any"])
# uses filtr.verbs if set
filtr.verbs = ['is_true', 'is_false']
self.assertEqual(filtr.get_verbs(), ['is_true', 'is_false', 'is_any'])
filtr.verbs = ["is_true", "is_false"]
self.assertEqual(filtr.get_verbs(), ["is_true", "is_false", "is_any"])
# may add is/null verbs
filtr = self.make_filter(model.Setting.name, factory=mod.AlchemyFilter,
nullable=True)
self.assertEqual(filtr.get_verbs(), ['equal', 'not_equal',
'is_null', 'is_not_null',
'is_any'])
filtr = self.make_filter(
model.Setting.name, factory=mod.AlchemyFilter, nullable=True
)
self.assertEqual(
filtr.get_verbs(),
["equal", "not_equal", "is_null", "is_not_null", "is_any"],
)
# filtr.verbs can be a callable
filtr.nullable = False
filtr.verbs = lambda: ['baz', 'blarg']
self.assertEqual(filtr.get_verbs(), ['baz', 'blarg', 'is_any'])
filtr.verbs = lambda: ["baz", "blarg"]
self.assertEqual(filtr.get_verbs(), ["baz", "blarg", "is_any"])
def test_get_default_verb(self):
model = self.app.model
filtr = self.make_filter(model.Setting.name, factory=mod.AlchemyFilter)
self.assertFalse(hasattr(filtr, 'verbs'))
self.assertEqual(filtr.default_verbs, ['equal', 'not_equal'])
self.assertEqual(filtr.get_verbs(), ['equal', 'not_equal', 'is_any'])
self.assertFalse(hasattr(filtr, "verbs"))
self.assertEqual(filtr.default_verbs, ["equal", "not_equal"])
self.assertEqual(filtr.get_verbs(), ["equal", "not_equal", "is_any"])
# returns first verb by default
self.assertEqual(filtr.get_default_verb(), 'equal')
self.assertEqual(filtr.get_default_verb(), "equal")
# returns filtr.verb if set
filtr.verb = 'foo'
self.assertEqual(filtr.get_default_verb(), 'foo')
filtr.verb = "foo"
self.assertEqual(filtr.get_default_verb(), "foo")
# returns filtr.default_verb if set
# (nb. this overrides filtr.verb since the point of this
# method is to return the *default* verb)
filtr.default_verb = 'bar'
self.assertEqual(filtr.get_default_verb(), 'bar')
filtr.default_verb = "bar"
self.assertEqual(filtr.get_default_verb(), "bar")
def test_get_verb_labels(self):
model = self.app.model
filtr = self.make_filter(model.Setting.name, factory=mod.AlchemyFilter)
self.assertFalse(hasattr(filtr, 'verbs'))
self.assertEqual(filtr.get_verbs(), ['equal', 'not_equal', 'is_any'])
self.assertFalse(hasattr(filtr, "verbs"))
self.assertEqual(filtr.get_verbs(), ["equal", "not_equal", "is_any"])
labels = filtr.get_verb_labels()
self.assertIsInstance(labels, dict)
self.assertEqual(labels['equal'], "equal to")
self.assertEqual(labels['not_equal'], "not equal to")
self.assertEqual(labels['is_any'], "is any")
self.assertEqual(labels["equal"], "equal to")
self.assertEqual(labels["not_equal"], "not equal to")
self.assertEqual(labels["is_any"], "is any")
def test_get_valueless_verbs(self):
model = self.app.model
filtr = self.make_filter(model.Setting.name, factory=mod.AlchemyFilter)
self.assertFalse(hasattr(filtr, 'verbs'))
self.assertEqual(filtr.get_verbs(), ['equal', 'not_equal', 'is_any'])
self.assertFalse(hasattr(filtr, "verbs"))
self.assertEqual(filtr.get_verbs(), ["equal", "not_equal", "is_any"])
verbs = filtr.get_valueless_verbs()
self.assertIsInstance(verbs, list)
self.assertIn('is_any', verbs)
self.assertIn("is_any", verbs)
def test_set_choices(self):
model = self.app.model
filtr = self.make_filter(model.Setting.name, factory=mod.AlchemyFilter)
self.assertEqual(filtr.choices, {})
self.assertEqual(filtr.data_type, 'string')
self.assertEqual(filtr.data_type, "string")
class MockEnum(Enum):
FOO = 'foo'
BAR = 'bar'
FOO = "foo"
BAR = "bar"
filtr.set_choices(MockEnum)
self.assertEqual(filtr.choices, OrderedDict([
('FOO', 'foo'),
('BAR', 'bar'),
]))
self.assertEqual(filtr.data_type, 'choice')
self.assertEqual(
filtr.choices,
OrderedDict(
[
("FOO", "foo"),
("BAR", "bar"),
]
),
)
self.assertEqual(filtr.data_type, "choice")
filtr.set_choices(None)
self.assertEqual(filtr.choices, {})
self.assertEqual(filtr.data_type, 'string')
self.assertEqual(filtr.data_type, "string")
def test_normalize_choices(self):
model = self.app.model
filtr = self.make_filter(model.Setting.name, factory=mod.AlchemyFilter)
class MockEnum(Enum):
FOO = 'foo'
BAR = 'bar'
FOO = "foo"
BAR = "bar"
choices = filtr.normalize_choices(MockEnum)
self.assertEqual(choices, OrderedDict([
('FOO', 'foo'),
('BAR', 'bar'),
]))
self.assertEqual(
choices,
OrderedDict(
[
("FOO", "foo"),
("BAR", "bar"),
]
),
)
choices = filtr.normalize_choices(OrderedDict([
('first', '1'),
('second', '2'),
]))
self.assertEqual(choices, OrderedDict([
('first', '1'),
('second', '2'),
]))
choices = filtr.normalize_choices(
OrderedDict(
[
("first", "1"),
("second", "2"),
]
)
)
self.assertEqual(
choices,
OrderedDict(
[
("first", "1"),
("second", "2"),
]
),
)
choices = filtr.normalize_choices({
'bbb': 'b',
'aaa': 'a',
})
self.assertEqual(choices, OrderedDict([
('aaa', 'a'),
('bbb', 'b'),
]))
choices = filtr.normalize_choices(
{
"bbb": "b",
"aaa": "a",
}
)
self.assertEqual(
choices,
OrderedDict(
[
("aaa", "a"),
("bbb", "b"),
]
),
)
choices = filtr.normalize_choices(['one', 'two', 'three'])
self.assertEqual(choices, OrderedDict([
('one', 'one'),
('two', 'two'),
('three', 'three'),
]))
choices = filtr.normalize_choices(["one", "two", "three"])
self.assertEqual(
choices,
OrderedDict(
[
("one", "one"),
("two", "two"),
("three", "three"),
]
),
)
def test_apply_filter(self):
model = self.app.model
@ -205,32 +240,46 @@ class TestGridFilter(WebTestCase):
# default verb used as fallback
# self.assertEqual(filtr.default_verb, 'contains')
filtr.default_verb = 'contains'
filtr.default_verb = "contains"
filtr.verb = None
with patch.object(filtr, 'filter_contains', side_effect=lambda q, v: q) as filter_contains:
filtered_query = filtr.apply_filter(self.sample_query, value='foo')
filter_contains.assert_called_once_with(self.sample_query, 'foo')
with patch.object(
filtr, "filter_contains", side_effect=lambda q, v: q
) as filter_contains:
filtered_query = filtr.apply_filter(self.sample_query, value="foo")
filter_contains.assert_called_once_with(self.sample_query, "foo")
self.assertIsNone(filtr.verb)
# filter verb used as fallback
filtr.verb = 'equal'
with patch.object(filtr, 'filter_equal', create=True, side_effect=lambda q, v: q) as filter_equal:
filtered_query = filtr.apply_filter(self.sample_query, value='foo')
filter_equal.assert_called_once_with(self.sample_query, 'foo')
filtr.verb = "equal"
with patch.object(
filtr, "filter_equal", create=True, side_effect=lambda q, v: q
) as filter_equal:
filtered_query = filtr.apply_filter(self.sample_query, value="foo")
filter_equal.assert_called_once_with(self.sample_query, "foo")
# filter value used as fallback
filtr.verb = 'contains'
filtr.value = 'blarg'
with patch.object(filtr, 'filter_contains', side_effect=lambda q, v: q) as filter_contains:
filtr.verb = "contains"
filtr.value = "blarg"
with patch.object(
filtr, "filter_contains", side_effect=lambda q, v: q
) as filter_contains:
filtered_query = filtr.apply_filter(self.sample_query)
filter_contains.assert_called_once_with(self.sample_query, 'blarg')
filter_contains.assert_called_once_with(self.sample_query, "blarg")
# error if invalid verb
self.assertRaises(mod.VerbNotSupported, filtr.apply_filter,
self.sample_query, verb='doesnotexist')
filtr.verbs = ['doesnotexist']
self.assertRaises(mod.VerbNotSupported, filtr.apply_filter,
self.sample_query, verb='doesnotexist')
self.assertRaises(
mod.VerbNotSupported,
filtr.apply_filter,
self.sample_query,
verb="doesnotexist",
)
filtr.verbs = ["doesnotexist"]
self.assertRaises(
mod.VerbNotSupported,
filtr.apply_filter,
self.sample_query,
verb="doesnotexist",
)
def test_filter_is_any(self):
model = self.app.model
@ -250,24 +299,24 @@ class TestAlchemyFilter(WebTestCase):
model = self.app.model
self.sample_data = [
{'name': 'foo1', 'value': 'ONE'},
{'name': 'foo2', 'value': 'two'},
{'name': 'foo3', 'value': 'ggg'},
{'name': 'foo4', 'value': 'ggg'},
{'name': 'foo5', 'value': 'ggg'},
{'name': 'foo6', 'value': 'six'},
{'name': 'foo7', 'value': 'seven'},
{'name': 'foo8', 'value': 'eight'},
{'name': 'foo9', 'value': None},
{"name": "foo1", "value": "ONE"},
{"name": "foo2", "value": "two"},
{"name": "foo3", "value": "ggg"},
{"name": "foo4", "value": "ggg"},
{"name": "foo5", "value": "ggg"},
{"name": "foo6", "value": "six"},
{"name": "foo7", "value": "seven"},
{"name": "foo8", "value": "eight"},
{"name": "foo9", "value": None},
]
for setting in self.sample_data:
self.app.save_setting(self.session, setting['name'], setting['value'])
self.app.save_setting(self.session, setting["name"], setting["value"])
self.session.commit()
self.sample_query = self.session.query(model.Setting)
def make_filter(self, model_property, **kwargs):
factory = kwargs.pop('factory', mod.AlchemyFilter)
kwargs['model_property'] = model_property
factory = kwargs.pop("factory", mod.AlchemyFilter)
kwargs["model_property"] = model_property
return factory(self.request, model_property.key, **kwargs)
def test_filter_equal(self):
@ -280,12 +329,12 @@ class TestAlchemyFilter(WebTestCase):
self.assertIs(filtered_query, self.sample_query)
# nb. by default, *is filtered* by empty string
filtered_query = filtr.filter_equal(self.sample_query, '')
filtered_query = filtr.filter_equal(self.sample_query, "")
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 0)
# filtered by value
filtered_query = filtr.filter_equal(self.sample_query, 'ggg')
filtered_query = filtr.filter_equal(self.sample_query, "ggg")
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 3)
@ -299,12 +348,12 @@ class TestAlchemyFilter(WebTestCase):
self.assertIs(filtered_query, self.sample_query)
# nb. by default, *is filtered* by empty string
filtered_query = filtr.filter_not_equal(self.sample_query, '')
filtered_query = filtr.filter_not_equal(self.sample_query, "")
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 9)
# filtered by value
filtered_query = filtr.filter_not_equal(self.sample_query, 'ggg')
filtered_query = filtr.filter_not_equal(self.sample_query, "ggg")
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 6)
@ -336,24 +385,24 @@ class TestStringAlchemyFilter(WebTestCase):
model = self.app.model
self.sample_data = [
{'name': 'foo1', 'value': 'ONE'},
{'name': 'foo2', 'value': 'two'},
{'name': 'foo3', 'value': 'ggg'},
{'name': 'foo4', 'value': 'ggg'},
{'name': 'foo5', 'value': 'ggg'},
{'name': 'foo6', 'value': 'six'},
{'name': 'foo7', 'value': 'seven'},
{'name': 'foo8', 'value': 'eight'},
{'name': 'foo9', 'value': 'nine'},
{"name": "foo1", "value": "ONE"},
{"name": "foo2", "value": "two"},
{"name": "foo3", "value": "ggg"},
{"name": "foo4", "value": "ggg"},
{"name": "foo5", "value": "ggg"},
{"name": "foo6", "value": "six"},
{"name": "foo7", "value": "seven"},
{"name": "foo8", "value": "eight"},
{"name": "foo9", "value": "nine"},
]
for setting in self.sample_data:
self.app.save_setting(self.session, setting['name'], setting['value'])
self.app.save_setting(self.session, setting["name"], setting["value"])
self.session.commit()
self.sample_query = self.session.query(model.Setting)
def make_filter(self, model_property, **kwargs):
factory = kwargs.pop('factory', mod.StringAlchemyFilter)
kwargs['model_property'] = model_property
factory = kwargs.pop("factory", mod.StringAlchemyFilter)
kwargs["model_property"] = model_property
return factory(self.request, model_property.key, **kwargs)
def test_filter_contains(self):
@ -364,11 +413,11 @@ class TestStringAlchemyFilter(WebTestCase):
# not filtered for empty value
filtered_query = filtr.filter_contains(self.sample_query, None)
self.assertIs(filtered_query, self.sample_query)
filtered_query = filtr.filter_contains(self.sample_query, '')
filtered_query = filtr.filter_contains(self.sample_query, "")
self.assertIs(filtered_query, self.sample_query)
# filtered by value
filtered_query = filtr.filter_contains(self.sample_query, 'ggg')
filtered_query = filtr.filter_contains(self.sample_query, "ggg")
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 3)
@ -380,11 +429,11 @@ class TestStringAlchemyFilter(WebTestCase):
# not filtered for empty value
filtered_query = filtr.filter_does_not_contain(self.sample_query, None)
self.assertIs(filtered_query, self.sample_query)
filtered_query = filtr.filter_does_not_contain(self.sample_query, '')
filtered_query = filtr.filter_does_not_contain(self.sample_query, "")
self.assertIs(filtered_query, self.sample_query)
# filtered by value
filtered_query = filtr.filter_does_not_contain(self.sample_query, 'ggg')
filtered_query = filtr.filter_does_not_contain(self.sample_query, "ggg")
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 6)
@ -392,8 +441,8 @@ class TestStringAlchemyFilter(WebTestCase):
class TestIntegerAlchemyFilter(WebTestCase):
def make_filter(self, model_property, **kwargs):
factory = kwargs.pop('factory', mod.IntegerAlchemyFilter)
kwargs['model_property'] = model_property
factory = kwargs.pop("factory", mod.IntegerAlchemyFilter)
kwargs["model_property"] = model_property
return factory(self.request, model_property.key, **kwargs)
def test_coerce_value(self):
@ -402,15 +451,15 @@ class TestIntegerAlchemyFilter(WebTestCase):
# null
self.assertIsNone(filtr.coerce_value(None))
self.assertIsNone(filtr.coerce_value(''))
self.assertIsNone(filtr.coerce_value(""))
# typical
self.assertEqual(filtr.coerce_value('42'), 42)
self.assertEqual(filtr.coerce_value('-42'), -42)
self.assertEqual(filtr.coerce_value("42"), 42)
self.assertEqual(filtr.coerce_value("-42"), -42)
# invalid
self.assertIsNone(filtr.coerce_value('42.12'))
self.assertIsNone(filtr.coerce_value('bogus'))
self.assertIsNone(filtr.coerce_value("42.12"))
self.assertIsNone(filtr.coerce_value("bogus"))
class TestBooleanAlchemyFilter(WebTestCase):
@ -420,15 +469,9 @@ class TestBooleanAlchemyFilter(WebTestCase):
model = self.app.model
self.sample_data = [
{'username': 'alice',
'prevent_edit': False,
'active': True},
{'username': 'bob',
'prevent_edit': True,
'active': True},
{'username': 'charlie',
'active': False,
'prevent_edit': None},
{"username": "alice", "prevent_edit": False, "active": True},
{"username": "bob", "prevent_edit": True, "active": True},
{"username": "charlie", "active": False, "prevent_edit": None},
]
for user in self.sample_data:
user = model.User(**user)
@ -437,37 +480,46 @@ class TestBooleanAlchemyFilter(WebTestCase):
self.sample_query = self.session.query(model.User)
def make_filter(self, model_property, **kwargs):
factory = kwargs.pop('factory', mod.BooleanAlchemyFilter)
kwargs['model_property'] = model_property
factory = kwargs.pop("factory", mod.BooleanAlchemyFilter)
kwargs["model_property"] = model_property
return factory(self.request, model_property.key, **kwargs)
def test_get_verbs(self):
model = self.app.model
# bool field, not nullable
filtr = self.make_filter(model.User.active,
factory=mod.BooleanAlchemyFilter,
nullable=False)
self.assertFalse(hasattr(filtr, 'verbs'))
self.assertEqual(filtr.default_verbs, ['is_true', 'is_false'])
filtr = self.make_filter(
model.User.active, factory=mod.BooleanAlchemyFilter, nullable=False
)
self.assertFalse(hasattr(filtr, "verbs"))
self.assertEqual(filtr.default_verbs, ["is_true", "is_false"])
# by default, returns default verbs (plus 'is_any')
self.assertEqual(filtr.get_verbs(), ['is_true', 'is_false', 'is_any'])
self.assertEqual(filtr.get_verbs(), ["is_true", "is_false", "is_any"])
# default verbs can be a callable
filtr.default_verbs = lambda: ['foo', 'bar']
self.assertEqual(filtr.get_verbs(), ['foo', 'bar', 'is_any'])
filtr.default_verbs = lambda: ["foo", "bar"]
self.assertEqual(filtr.get_verbs(), ["foo", "bar", "is_any"])
# bool field, *nullable*
filtr = self.make_filter(model.User.active,
factory=mod.BooleanAlchemyFilter,
nullable=True)
self.assertFalse(hasattr(filtr, 'verbs'))
self.assertEqual(filtr.default_verbs, ['is_true', 'is_false'])
filtr = self.make_filter(
model.User.active, factory=mod.BooleanAlchemyFilter, nullable=True
)
self.assertFalse(hasattr(filtr, "verbs"))
self.assertEqual(filtr.default_verbs, ["is_true", "is_false"])
# effective verbs also include is_false_null
self.assertEqual(filtr.get_verbs(), ['is_true', 'is_false', 'is_false_null',
'is_null', 'is_not_null', 'is_any'])
self.assertEqual(
filtr.get_verbs(),
[
"is_true",
"is_false",
"is_false_null",
"is_null",
"is_not_null",
"is_any",
],
)
def test_coerce_value(self):
model = self.app.model
@ -477,11 +529,11 @@ class TestBooleanAlchemyFilter(WebTestCase):
self.assertTrue(filtr.coerce_value(True))
self.assertTrue(filtr.coerce_value(1))
self.assertTrue(filtr.coerce_value('1'))
self.assertTrue(filtr.coerce_value("1"))
self.assertFalse(filtr.coerce_value(False))
self.assertFalse(filtr.coerce_value(0))
self.assertFalse(filtr.coerce_value(''))
self.assertFalse(filtr.coerce_value(""))
def test_filter_is_true(self):
model = self.app.model
@ -515,7 +567,7 @@ class TestBooleanAlchemyFilter(WebTestCase):
class TheLocalThing(Base):
__tablename__ = 'the_local_thing'
__tablename__ = "the_local_thing"
id = sa.Column(sa.Integer(), primary_key=True, autoincrement=False)
date = sa.Column(sa.DateTime(timezone=True), nullable=True)
@ -530,12 +582,12 @@ class TestDateAlchemyFilter(WebTestCase):
model.Base.metadata.create_all(bind=self.session.bind)
self.sample_data = [
{'id': 1, 'date': datetime.date(2024, 1, 1)},
{'id': 2, 'date': datetime.date(2024, 1, 1)},
{'id': 3, 'date': datetime.date(2024, 3, 1)},
{'id': 4, 'date': datetime.date(2024, 3, 1)},
{'id': 5, 'date': None},
{'id': 6, 'date': None},
{"id": 1, "date": datetime.date(2024, 1, 1)},
{"id": 2, "date": datetime.date(2024, 1, 1)},
{"id": 3, "date": datetime.date(2024, 3, 1)},
{"id": 4, "date": datetime.date(2024, 3, 1)},
{"id": 5, "date": None},
{"id": 6, "date": None},
]
for thing in self.sample_data:
@ -546,8 +598,8 @@ class TestDateAlchemyFilter(WebTestCase):
self.sample_query = self.session.query(TheLocalThing)
def make_filter(self, model_property, **kwargs):
factory = kwargs.pop('factory', mod.DateAlchemyFilter)
kwargs['model_property'] = model_property
factory = kwargs.pop("factory", mod.DateAlchemyFilter)
kwargs["model_property"] = model_property
return factory(self.request, model_property.key, **kwargs)
def test_coerce_value(self):
@ -562,12 +614,12 @@ class TestDateAlchemyFilter(WebTestCase):
self.assertIs(value, result)
# value as string
result = filtr.coerce_value('2024-04-01')
result = filtr.coerce_value("2024-04-01")
self.assertIsInstance(result, datetime.date)
self.assertEqual(result, datetime.date(2024, 4, 1))
# invalid
result = filtr.coerce_value('thisinputisbad')
result = filtr.coerce_value("thisinputisbad")
self.assertIsNone(result)
def test_greater_than(self):
@ -582,12 +634,14 @@ class TestDateAlchemyFilter(WebTestCase):
self.assertEqual(filtered_query.count(), 6)
# value as date
filtered_query = filtr.filter_greater_than(self.sample_query, datetime.date(2024, 2, 1))
filtered_query = filtr.filter_greater_than(
self.sample_query, datetime.date(2024, 2, 1)
)
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 2)
# value as string
filtered_query = filtr.filter_greater_than(self.sample_query, '2024-02-01')
filtered_query = filtr.filter_greater_than(self.sample_query, "2024-02-01")
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 2)
@ -603,17 +657,21 @@ class TestDateAlchemyFilter(WebTestCase):
self.assertEqual(filtered_query.count(), 6)
# value as date (clear of boundary)
filtered_query = filtr.filter_greater_equal(self.sample_query, datetime.date(2024, 2, 1))
filtered_query = filtr.filter_greater_equal(
self.sample_query, datetime.date(2024, 2, 1)
)
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 2)
# value as date (at boundary)
filtered_query = filtr.filter_greater_equal(self.sample_query, datetime.date(2024, 3, 1))
filtered_query = filtr.filter_greater_equal(
self.sample_query, datetime.date(2024, 3, 1)
)
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 2)
# value as string
filtered_query = filtr.filter_greater_equal(self.sample_query, '2024-01-01')
filtered_query = filtr.filter_greater_equal(self.sample_query, "2024-01-01")
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 4)
@ -629,12 +687,14 @@ class TestDateAlchemyFilter(WebTestCase):
self.assertEqual(filtered_query.count(), 6)
# value as date
filtered_query = filtr.filter_less_than(self.sample_query, datetime.date(2024, 2, 1))
filtered_query = filtr.filter_less_than(
self.sample_query, datetime.date(2024, 2, 1)
)
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 2)
# value as string
filtered_query = filtr.filter_less_than(self.sample_query, '2024-04-01')
filtered_query = filtr.filter_less_than(self.sample_query, "2024-04-01")
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 4)
@ -650,17 +710,21 @@ class TestDateAlchemyFilter(WebTestCase):
self.assertEqual(filtered_query.count(), 6)
# value as date (clear of boundary)
filtered_query = filtr.filter_less_equal(self.sample_query, datetime.date(2024, 2, 1))
filtered_query = filtr.filter_less_equal(
self.sample_query, datetime.date(2024, 2, 1)
)
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 2)
# value as date (at boundary)
filtered_query = filtr.filter_less_equal(self.sample_query, datetime.date(2024, 3, 1))
filtered_query = filtr.filter_less_equal(
self.sample_query, datetime.date(2024, 3, 1)
)
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 2)
# value as string
filtered_query = filtr.filter_less_equal(self.sample_query, '2024-04-01')
filtered_query = filtr.filter_less_equal(self.sample_query, "2024-04-01")
self.assertIsNot(filtered_query, self.sample_query)
self.assertEqual(filtered_query.count(), 4)
@ -668,5 +732,5 @@ class TestDateAlchemyFilter(WebTestCase):
class TestVerbNotSupported(TestCase):
def test_basic(self):
error = mod.VerbNotSupported('equal')
error = mod.VerbNotSupported("equal")
self.assertEqual(str(error), "unknown filter verb not supported: equal")

View file

@ -36,34 +36,34 @@ class TestMakeWuttaConfig(FileTestCase):
def test_basic(self):
# mock path to config file
myconf = self.write_file('my.conf', '')
settings = {'wutta.config': myconf}
myconf = self.write_file("my.conf", "")
settings = {"wutta.config": myconf}
# can make a config okay
config = mod.make_wutta_config(settings)
# and that config is also stored in settings
self.assertIn('wutta_config', settings)
self.assertIs(settings['wutta_config'], config)
self.assertIn("wutta_config", settings)
self.assertIs(settings["wutta_config"], config)
class TestMakePyramidConfig(DataTestCase):
def test_basic(self):
with patch.object(AppHandler, 'make_session', return_value=self.session):
settings = {'wutta_config': self.config}
with patch.object(AppHandler, "make_session", return_value=self.session):
settings = {"wutta_config": self.config}
config = mod.make_pyramid_config(settings)
self.assertIsInstance(config, Configurator)
self.assertEqual(settings['wuttaweb.theme'], 'default')
self.assertEqual(settings["wuttaweb.theme"], "default")
class TestMain(DataTestCase):
def test_basic(self):
with patch.object(AppHandler, 'make_session', return_value=self.session):
with patch.object(AppHandler, "make_session", return_value=self.session):
global_config = None
myconf = self.write_file('my.conf', '')
settings = {'wutta.config': myconf}
myconf = self.write_file("my.conf", "")
settings = {"wutta.config": myconf}
app = mod.main(global_config, **settings)
self.assertIsInstance(app, Router)
@ -73,9 +73,9 @@ def mock_main(global_config, **settings):
wutta_config = mod.make_wutta_config(settings)
pyramid_config = mod.make_pyramid_config(settings)
pyramid_config.include('wuttaweb.static')
pyramid_config.include('wuttaweb.subscribers')
pyramid_config.include('wuttaweb.views')
pyramid_config.include("wuttaweb.static")
pyramid_config.include("wuttaweb.subscribers")
pyramid_config.include("wuttaweb.views")
return pyramid_config.make_wsgi_app()
@ -83,26 +83,26 @@ def mock_main(global_config, **settings):
class TestMakeWsgiApp(DataTestCase):
def test_with_callable(self):
with patch.object(self.app, 'make_session', return_value=self.session):
with patch.object(self.app, "make_session", return_value=self.session):
# specify config
wsgi = mod.make_wsgi_app(mock_main, config=self.config)
self.assertIsInstance(wsgi, Router)
# auto config
with patch.object(mod, 'make_config', return_value=self.config):
with patch.object(mod, "make_config", return_value=self.config):
wsgi = mod.make_wsgi_app(mock_main)
self.assertIsInstance(wsgi, Router)
def test_with_spec(self):
# specify config
wsgi = mod.make_wsgi_app('tests.test_app:mock_main', config=self.config)
wsgi = mod.make_wsgi_app("tests.test_app:mock_main", config=self.config)
self.assertIsInstance(wsgi, Router)
# auto config
with patch.object(mod, 'make_config', return_value=self.config):
wsgi = mod.make_wsgi_app('tests.test_app:mock_main')
with patch.object(mod, "make_config", return_value=self.config):
wsgi = mod.make_wsgi_app("tests.test_app:mock_main")
self.assertIsInstance(wsgi, Router)
def test_invalid(self):
@ -112,27 +112,27 @@ class TestMakeWsgiApp(DataTestCase):
class TestMakeAsgiApp(DataTestCase):
def test_with_callable(self):
with patch.object(self.app, 'make_session', return_value=self.session):
with patch.object(self.app, "make_session", return_value=self.session):
# specify config
asgi = mod.make_asgi_app(mock_main, config=self.config)
self.assertIsInstance(asgi, WsgiToAsgi)
# auto config
with patch.object(mod, 'make_config', return_value=self.config):
with patch.object(mod, "make_config", return_value=self.config):
asgi = mod.make_asgi_app(mock_main)
self.assertIsInstance(asgi, WsgiToAsgi)
def test_with_spec(self):
with patch.object(self.app, 'make_session', return_value=self.session):
with patch.object(self.app, "make_session", return_value=self.session):
# specify config
asgi = mod.make_asgi_app('tests.test_app:mock_main', config=self.config)
asgi = mod.make_asgi_app("tests.test_app:mock_main", config=self.config)
self.assertIsInstance(asgi, WsgiToAsgi)
# auto config
with patch.object(mod, 'make_config', return_value=self.config):
asgi = mod.make_asgi_app('tests.test_app:mock_main')
with patch.object(mod, "make_config", return_value=self.config):
asgi = mod.make_asgi_app("tests.test_app:mock_main")
self.assertIsInstance(asgi, WsgiToAsgi)
def test_invalid(self):
@ -143,53 +143,65 @@ class TestEstablishTheme(DataTestCase):
def test_default(self):
settings = {
'wutta_config': self.config,
'mako.directories': ['wuttaweb:templates'],
"wutta_config": self.config,
"mako.directories": ["wuttaweb:templates"],
}
mod.establish_theme(settings)
self.assertEqual(settings['wuttaweb.theme'], 'default')
self.assertEqual(settings['mako.directories'], [
resource_path('wuttaweb:templates/themes/default'),
'wuttaweb:templates',
])
self.assertEqual(settings["wuttaweb.theme"], "default")
self.assertEqual(
settings["mako.directories"],
[
resource_path("wuttaweb:templates/themes/default"),
"wuttaweb:templates",
],
)
def test_mako_dirs_as_string(self):
settings = {
'wutta_config': self.config,
'mako.directories': 'wuttaweb:templates',
"wutta_config": self.config,
"mako.directories": "wuttaweb:templates",
}
mod.establish_theme(settings)
self.assertEqual(settings['wuttaweb.theme'], 'default')
self.assertEqual(settings['mako.directories'], [
resource_path('wuttaweb:templates/themes/default'),
'wuttaweb:templates',
])
self.assertEqual(settings["wuttaweb.theme"], "default")
self.assertEqual(
settings["mako.directories"],
[
resource_path("wuttaweb:templates/themes/default"),
"wuttaweb:templates",
],
)
def test_butterfly(self):
settings = {
'wutta_config': self.config,
'mako.directories': 'wuttaweb:templates',
"wutta_config": self.config,
"mako.directories": "wuttaweb:templates",
}
self.app.save_setting(self.session, 'wuttaweb.theme', 'butterfly')
self.app.save_setting(self.session, "wuttaweb.theme", "butterfly")
self.session.commit()
mod.establish_theme(settings)
self.assertEqual(settings['wuttaweb.theme'], 'butterfly')
self.assertEqual(settings['mako.directories'], [
resource_path('wuttaweb:templates/themes/butterfly'),
'wuttaweb:templates',
])
self.assertEqual(settings["wuttaweb.theme"], "butterfly")
self.assertEqual(
settings["mako.directories"],
[
resource_path("wuttaweb:templates/themes/butterfly"),
"wuttaweb:templates",
],
)
def test_custom(self):
settings = {
'wutta_config': self.config,
'mako.directories': 'wuttaweb:templates',
"wutta_config": self.config,
"mako.directories": "wuttaweb:templates",
}
self.config.setdefault('wuttaweb.themes.keys', 'anotherone')
self.app.save_setting(self.session, 'wuttaweb.theme', 'anotherone')
self.config.setdefault("wuttaweb.themes.keys", "anotherone")
self.app.save_setting(self.session, "wuttaweb.theme", "anotherone")
self.session.commit()
mod.establish_theme(settings)
self.assertEqual(settings['wuttaweb.theme'], 'anotherone')
self.assertEqual(settings['mako.directories'], [
resource_path('wuttaweb:templates/themes/anotherone'),
'wuttaweb:templates',
])
self.assertEqual(settings["wuttaweb.theme"], "anotherone")
self.assertEqual(
settings["mako.directories"],
[
resource_path("wuttaweb:templates/themes/anotherone"),
"wuttaweb:templates",
],
)

View file

@ -18,10 +18,11 @@ class TestLoginUser(TestCase):
app = config.get_app()
model = app.model
request = testing.DummyRequest(wutta_config=config)
user = model.User(username='barney')
user = model.User(username="barney")
headers = mod.login_user(request, user)
self.assertEqual(headers, [])
class TestLogoutUser(TestCase):
def test_basic(self):
@ -36,20 +37,25 @@ class TestLogoutUser(TestCase):
class TestWuttaSecurityPolicy(TestCase):
def setUp(self):
self.config = WuttaConfig(defaults={
'wutta.db.default.url': 'sqlite://',
})
self.config = WuttaConfig(
defaults={
"wutta.db.default.url": "sqlite://",
}
)
self.request = testing.DummyRequest()
self.pyramid_config = testing.setUp(request=self.request, settings={
'wutta_config': self.config,
})
self.pyramid_config = testing.setUp(
request=self.request,
settings={
"wutta_config": self.config,
},
)
self.app = self.config.get_app()
model = self.app.model
model.Base.metadata.create_all(bind=self.config.appdb_engine)
self.session = self.app.make_session()
self.user = model.User(username='barney')
self.user = model.User(username="barney")
self.session.add(self.user)
self.session.commit()
@ -66,12 +72,16 @@ class TestWuttaSecurityPolicy(TestCase):
self.assertIsNotNone(uuid)
self.assertIsNone(self.policy.session_helper.authenticated_userid(self.request))
self.policy.remember(self.request, uuid)
self.assertEqual(self.policy.session_helper.authenticated_userid(self.request), uuid)
self.assertEqual(
self.policy.session_helper.authenticated_userid(self.request), uuid
)
def test_forget(self):
uuid = self.user.uuid
self.policy.remember(self.request, uuid)
self.assertEqual(self.policy.session_helper.authenticated_userid(self.request), uuid)
self.assertEqual(
self.policy.session_helper.authenticated_userid(self.request), uuid
)
self.policy.forget(self.request)
self.assertIsNone(self.policy.session_helper.authenticated_userid(self.request))
@ -91,7 +101,7 @@ class TestWuttaSecurityPolicy(TestCase):
# invalid identity yields no user
self.policy = self.make_policy()
self.policy.remember(self.request, _uuid.uuid4()) # random uuid
self.policy.remember(self.request, _uuid.uuid4()) # random uuid
user = self.policy.identity(self.request)
self.assertIsNone(user)
@ -112,59 +122,59 @@ class TestWuttaSecurityPolicy(TestCase):
model = self.app.model
# anon has no perms
self.assertFalse(self.policy.permits(self.request, None, 'foo.bar'))
self.assertFalse(self.policy.permits(self.request, None, "foo.bar"))
# but we can grant it
anons = auth.get_role_anonymous(self.session)
self.user.roles.append(anons)
auth.grant_permission(anons, 'foo.bar')
auth.grant_permission(anons, "foo.bar")
self.session.commit()
# and then perm check is satisfied
self.assertTrue(self.policy.permits(self.request, None, 'foo.bar'))
self.assertTrue(self.policy.permits(self.request, None, "foo.bar"))
# now, create a separate role and grant another perm
# (but user does not yet belong to this role)
role = model.Role(name='whatever')
role = model.Role(name="whatever")
self.session.add(role)
auth.grant_permission(role, 'baz.edit')
auth.grant_permission(role, "baz.edit")
self.session.commit()
# so far then, user does not have the permission
self.policy = self.make_policy()
self.policy.remember(self.request, self.user.uuid)
self.assertFalse(self.policy.permits(self.request, None, 'baz.edit'))
self.assertFalse(self.policy.permits(self.request, None, "baz.edit"))
# but if we assign user to role, perm check should pass
self.user.roles.append(role)
self.session.commit()
self.assertTrue(self.policy.permits(self.request, None, 'baz.edit'))
self.assertTrue(self.policy.permits(self.request, None, "baz.edit"))
# now let's try another perm - we won't grant it, but will
# confirm user is denied access unless they become root
self.assertFalse(self.policy.permits(self.request, None, 'some-root-perm'))
self.assertFalse(self.policy.permits(self.request, None, "some-root-perm"))
self.request.is_root = True
self.assertTrue(self.policy.permits(self.request, None, 'some-root-perm'))
self.assertTrue(self.policy.permits(self.request, None, "some-root-perm"))
class TestAddPermissionGroup(WebTestCase):
def test_basic(self):
permissions = self.pyramid_config.get_settings().get('wutta_permissions', {})
self.assertNotIn('widgets', permissions)
self.pyramid_config.add_wutta_permission_group('widgets')
permissions = self.pyramid_config.get_settings().get('wutta_permissions', {})
self.assertIn('widgets', permissions)
self.assertEqual(permissions['widgets']['label'], "Widgets")
permissions = self.pyramid_config.get_settings().get("wutta_permissions", {})
self.assertNotIn("widgets", permissions)
self.pyramid_config.add_wutta_permission_group("widgets")
permissions = self.pyramid_config.get_settings().get("wutta_permissions", {})
self.assertIn("widgets", permissions)
self.assertEqual(permissions["widgets"]["label"], "Widgets")
class TestAddPermission(WebTestCase):
def test_basic(self):
permissions = self.pyramid_config.get_settings().get('wutta_permissions', {})
self.assertNotIn('widgets', permissions)
self.pyramid_config.add_wutta_permission('widgets', 'widgets.polish')
permissions = self.pyramid_config.get_settings().get('wutta_permissions', {})
self.assertIn('widgets', permissions)
self.assertEqual(permissions['widgets']['label'], "Widgets")
self.assertIn('widgets.polish', permissions['widgets']['perms'])
permissions = self.pyramid_config.get_settings().get("wutta_permissions", {})
self.assertNotIn("widgets", permissions)
self.pyramid_config.add_wutta_permission("widgets", "widgets.polish")
permissions = self.pyramid_config.get_settings().get("wutta_permissions", {})
self.assertIn("widgets", permissions)
self.assertEqual(permissions["widgets"]["label"], "Widgets")
self.assertIn("widgets.polish", permissions["widgets"]["perms"])

View file

@ -17,7 +17,9 @@ class TestAllSettings(DataTestCase):
def test_all(self):
for name in dir(mod):
obj = getattr(mod, name)
if (isinstance(obj, type)
if (
isinstance(obj, type)
and obj is not EmailSetting
and issubclass(obj, EmailSetting)):
and issubclass(obj, EmailSetting)
):
self.check_setting(obj)

View file

@ -12,9 +12,11 @@ from wuttaweb.testing import WebTestCase
class MockMenuHandler(MenuHandler):
pass
class LegacyMenuHandler(MenuHandler):
pass
class AnotherMenuHandler(MenuHandler):
pass
@ -29,48 +31,48 @@ class TestWebHandler(WebTestCase):
# default with / root path
url = handler.get_fanstatic_url(self.request, static.logo)
self.assertEqual(url, '/fanstatic/wuttaweb_img/logo.png')
self.assertEqual(url, "/fanstatic/wuttaweb_img/logo.png")
# what about a subpath
self.request.script_name = '/testing'
self.request.script_name = "/testing"
url = handler.get_fanstatic_url(self.request, static.logo)
self.assertEqual(url, '/testing/fanstatic/wuttaweb_img/logo.png')
self.assertEqual(url, "/testing/fanstatic/wuttaweb_img/logo.png")
def test_get_favicon_url(self):
handler = self.make_handler()
# default
url = handler.get_favicon_url(self.request)
self.assertEqual(url, '/fanstatic/wuttaweb_img/favicon.ico')
self.assertEqual(url, "/fanstatic/wuttaweb_img/favicon.ico")
# config override
self.config.setdefault('wuttaweb.favicon_url', '/testing/other.ico')
self.config.setdefault("wuttaweb.favicon_url", "/testing/other.ico")
url = handler.get_favicon_url(self.request)
self.assertEqual(url, '/testing/other.ico')
self.assertEqual(url, "/testing/other.ico")
def test_get_header_logo_url(self):
handler = self.make_handler()
# default
url = handler.get_header_logo_url(self.request)
self.assertEqual(url, '/fanstatic/wuttaweb_img/favicon.ico')
self.assertEqual(url, "/fanstatic/wuttaweb_img/favicon.ico")
# config override
self.config.setdefault('wuttaweb.header_logo_url', '/testing/header.png')
self.config.setdefault("wuttaweb.header_logo_url", "/testing/header.png")
url = handler.get_header_logo_url(self.request)
self.assertEqual(url, '/testing/header.png')
self.assertEqual(url, "/testing/header.png")
def test_get_main_logo_url(self):
handler = self.make_handler()
# default
url = handler.get_main_logo_url(self.request)
self.assertEqual(url, '/fanstatic/wuttaweb_img/logo.png')
self.assertEqual(url, "/fanstatic/wuttaweb_img/logo.png")
# config override
self.config.setdefault('wuttaweb.logo_url', '/testing/other.png')
self.config.setdefault("wuttaweb.logo_url", "/testing/other.png")
url = handler.get_main_logo_url(self.request)
self.assertEqual(url, '/testing/other.png')
self.assertEqual(url, "/testing/other.png")
def test_get_menu_handler(self):
handler = self.make_handler()
@ -81,20 +83,23 @@ class TestWebHandler(WebTestCase):
self.assertIs(type(menus), MenuHandler)
# configured default
self.config.setdefault('wutta.web.menus.handler.default_spec',
'tests.test_handler:MockMenuHandler')
self.config.setdefault(
"wutta.web.menus.handler.default_spec", "tests.test_handler:MockMenuHandler"
)
menus = handler.get_menu_handler()
self.assertIsInstance(menus, MockMenuHandler)
# configured handler (legacy)
self.config.setdefault('wutta.web.menus.handler_spec',
'tests.test_handler:LegacyMenuHandler')
self.config.setdefault(
"wutta.web.menus.handler_spec", "tests.test_handler:LegacyMenuHandler"
)
menus = handler.get_menu_handler()
self.assertIsInstance(menus, LegacyMenuHandler)
# configued handler (proper)
self.config.setdefault('wutta.web.menus.handler.spec',
'tests.test_handler:AnotherMenuHandler')
self.config.setdefault(
"wutta.web.menus.handler.spec", "tests.test_handler:AnotherMenuHandler"
)
menus = handler.get_menu_handler()
self.assertIsInstance(menus, AnotherMenuHandler)
@ -103,40 +108,51 @@ class TestWebHandler(WebTestCase):
# at least one spec by default
specs = handler.get_menu_handler_specs()
self.assertIn('wuttaweb.menus:MenuHandler', specs)
self.assertIn("wuttaweb.menus:MenuHandler", specs)
# caller can specify default as string
specs = handler.get_menu_handler_specs(default='tests.test_handler:MockMenuHandler')
self.assertIn('wuttaweb.menus:MenuHandler', specs)
self.assertIn('tests.test_handler:MockMenuHandler', specs)
self.assertNotIn('tests.test_handler:AnotherMenuHandler', specs)
specs = handler.get_menu_handler_specs(
default="tests.test_handler:MockMenuHandler"
)
self.assertIn("wuttaweb.menus:MenuHandler", specs)
self.assertIn("tests.test_handler:MockMenuHandler", specs)
self.assertNotIn("tests.test_handler:AnotherMenuHandler", specs)
# caller can specify default as list
specs = handler.get_menu_handler_specs(default=[
'tests.test_handler:MockMenuHandler',
'tests.test_handler:AnotherMenuHandler'])
self.assertIn('wuttaweb.menus:MenuHandler', specs)
self.assertIn('tests.test_handler:MockMenuHandler', specs)
self.assertIn('tests.test_handler:AnotherMenuHandler', specs)
specs = handler.get_menu_handler_specs(
default=[
"tests.test_handler:MockMenuHandler",
"tests.test_handler:AnotherMenuHandler",
]
)
self.assertIn("wuttaweb.menus:MenuHandler", specs)
self.assertIn("tests.test_handler:MockMenuHandler", specs)
self.assertIn("tests.test_handler:AnotherMenuHandler", specs)
# default can be configured
self.config.setdefault('wutta.web.menus.handler.default_spec',
'tests.test_handler:AnotherMenuHandler')
self.config.setdefault(
"wutta.web.menus.handler.default_spec",
"tests.test_handler:AnotherMenuHandler",
)
specs = handler.get_menu_handler_specs()
self.assertIn('wuttaweb.menus:MenuHandler', specs)
self.assertNotIn('tests.test_handler:MockMenuHandler', specs)
self.assertIn('tests.test_handler:AnotherMenuHandler', specs)
self.assertIn("wuttaweb.menus:MenuHandler", specs)
self.assertNotIn("tests.test_handler:MockMenuHandler", specs)
self.assertIn("tests.test_handler:AnotherMenuHandler", specs)
# the rest come from entry points
with patch.object(mod, 'load_entry_points', return_value={
'legacy': LegacyMenuHandler,
}):
with patch.object(
mod,
"load_entry_points",
return_value={
"legacy": LegacyMenuHandler,
},
):
specs = handler.get_menu_handler_specs()
self.assertNotIn('wuttaweb.menus:MenuHandler', specs)
self.assertNotIn('tests.test_handler:MockMenuHandler', specs)
self.assertIn('tests.test_handler:LegacyMenuHandler', specs)
self.assertNotIn("wuttaweb.menus:MenuHandler", specs)
self.assertNotIn("tests.test_handler:MockMenuHandler", specs)
self.assertIn("tests.test_handler:LegacyMenuHandler", specs)
# nb. this remains from previous config default
self.assertIn('tests.test_handler:AnotherMenuHandler', specs)
self.assertIn("tests.test_handler:AnotherMenuHandler", specs)
def test_make_form(self):
handler = self.make_handler()

View file

@ -18,13 +18,13 @@ class TestMenuHandler(WebTestCase):
# 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)
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)
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)
@ -35,20 +35,20 @@ class TestMenuHandler(WebTestCase):
auth = self.app.get_auth_handler()
# user with perms
barney = model.User(username='barney')
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')
auth.grant_permission(blokes, "appinfo.list")
self.request.user = barney
# perm not granted to user
item = {'perm': 'appinfo.configure'}
item = {"perm": "appinfo.configure"}
self.assertFalse(self.handler._is_allowed(self.request, item))
# perm *is* granted to user
item = {'perm': 'appinfo.list'}
item = {"perm": "appinfo.list"}
self.assertTrue(self.handler._is_allowed(self.request, item))
# perm not required
@ -60,49 +60,49 @@ class TestMenuHandler(WebTestCase):
def make_menus():
return [
{
'type': 'menu',
'items': [
{'title': "Foo", 'url': '#'},
{'title': "Bar", 'url': '#'},
"type": "menu",
"items": [
{"title": "Foo", "url": "#"},
{"title": "Bar", "url": "#"},
],
},
]
mock_is_allowed = MagicMock()
with patch.object(self.handler, '_is_allowed', new=mock_is_allowed):
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'])
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'])
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": "Foo", "url": "#"},
{
'type': 'menu',
'items': [
{'title': "Bar", 'url': '#'},
"type": "menu",
"items": [
{"title": "Bar", "url": "#"},
],
},
],
@ -110,215 +110,215 @@ class TestMenuHandler(WebTestCase):
]
mock_is_allowed = MagicMock()
with patch.object(self.handler, '_is_allowed', new=mock_is_allowed):
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'])
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'])
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')
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': '#'}
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'])
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"}
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)
self.assertEqual(entry["type"], "item")
self.assertEqual(entry["title"], "Foo")
self.assertNotIn("url", entry)
# nb. still sets is_link = True; basically it's <a> with no href
self.assertTrue(entry['is_link'])
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'):
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'])
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):
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')
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'])
self.assertEqual(entry["url"], "home")
self.assertTrue(entry["is_link"])
def test_make_menu_entry_sep(self):
item = {'type': 'sep'}
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'])
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')
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': '#'},
"title": "First Menu",
"type": "menu",
"items": [
{"title": "Foo", "url": "#"},
{"title": "Bar", "url": "#"},
],
},
]
def is_allowed(request, item):
if item.get('title') == 'Bar':
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):
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')
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": "First Menu",
"type": "menu",
"items": [
{"title": "Foo", "url": "#"},
{"title": "Bar", "url": "#"},
],
},
{
'title': "Second Menu",
'type': 'menu',
'items': [
{'title': "Baz", 'url': '#'},
"title": "Second Menu",
"type": "menu",
"items": [
{"title": "Baz", "url": "#"},
],
},
]
def is_allowed(request, item):
if item.get('title') == 'Baz':
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):
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')
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": "First Menu",
"type": "menu",
"items": [
{"title": "Foo", "url": "#"},
{"title": "Bar", "url": "#"},
],
},
{
'title': "Second Link",
'type': 'link',
"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):
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")
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'},
"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):
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')
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 Menu",
"type": "menu",
"items": [
{
'title': "First Submenu",
'type': 'menu',
'items': [
{'title': "Foo", 'url': '#'},
"title": "First Submenu",
"type": "menu",
"items": [
{"title": "Foo", "url": "#"},
],
},
{
'title': "Second Submenu",
'type': 'menu',
'items': [
{'title': "Bar", 'url': '#'},
"title": "Second Submenu",
"type": "menu",
"items": [
{"title": "Bar", "url": "#"},
],
},
],
@ -326,20 +326,20 @@ class TestMenuHandler(WebTestCase):
]
def is_allowed(request, item):
if item.get('title') == 'Bar':
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):
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')
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")

View file

@ -27,10 +27,10 @@ class TestGetProgressSession(TestCase):
self.request = testing.DummyRequest()
def test_basic(self):
self.request.session.id = 'mockid'
session = mod.get_progress_session(self.request, 'foo')
self.request.session.id = "mockid"
session = mod.get_progress_session(self.request, "foo")
self.assertIsInstance(session, BeakerSession)
self.assertEqual(session.id, 'mockid.progress.foo')
self.assertEqual(session.id, "mockid.progress.foo")
class TestSessionProgress(ConfigTestCase):
@ -38,16 +38,16 @@ class TestSessionProgress(ConfigTestCase):
def setUp(self):
self.setup_config()
self.request = testing.DummyRequest(wutta_config=self.config)
self.request.session.id = 'mockid'
self.request.session.id = "mockid"
def test_error_url(self):
factory = mod.SessionProgress(self.request, 'foo', success_url='/blart')
self.assertEqual(factory.error_url, '/blart')
factory = mod.SessionProgress(self.request, "foo", success_url="/blart")
self.assertEqual(factory.error_url, "/blart")
def test_basic(self):
# sanity / coverage check
factory = mod.SessionProgress(self.request, 'foo')
factory = mod.SessionProgress(self.request, "foo")
prog = factory("doing things", 2)
prog.update(1)
prog.update(2)
@ -56,10 +56,10 @@ class TestSessionProgress(ConfigTestCase):
def test_error(self):
# sanity / coverage check
factory = mod.SessionProgress(self.request, 'foo')
factory = mod.SessionProgress(self.request, "foo")
prog = factory("doing things", 2)
prog.update(1)
try:
raise RuntimeError('omg')
raise RuntimeError("omg")
except Exception as error:
prog.handle_error(error)

View file

@ -11,4 +11,4 @@ class TestIncludeMe(TestCase):
with testing.testConfig() as pyramid_config:
# just ensure no error happens when included..
pyramid_config.include('wuttaweb.static')
pyramid_config.include("wuttaweb.static")

View file

@ -19,9 +19,12 @@ class TestNewRequest(TestCase):
def setUp(self):
self.config = WuttaConfig()
self.request = self.make_request()
self.pyramid_config = testing.setUp(request=self.request, settings={
'wutta_config': self.config,
})
self.pyramid_config = testing.setUp(
request=self.request,
settings={
"wutta_config": self.config,
},
)
def tearDown(self):
testing.tearDown()
@ -35,15 +38,15 @@ class TestNewRequest(TestCase):
event = MagicMock(request=self.request)
# request gets a new attr
self.assertFalse(hasattr(self.request, 'wutta_config'))
self.assertFalse(hasattr(self.request, "wutta_config"))
subscribers.new_request(event)
self.assertTrue(hasattr(self.request, 'wutta_config'))
self.assertTrue(hasattr(self.request, "wutta_config"))
self.assertIs(self.request.wutta_config, self.config)
def test_use_oruga_default(self):
# request gets a new attr, false by default
self.assertFalse(hasattr(self.request, 'use_oruga'))
self.assertFalse(hasattr(self.request, "use_oruga"))
event = MagicMock(request=self.request)
subscribers.new_request(event)
self.assertFalse(self.request.use_oruga)
@ -51,17 +54,20 @@ class TestNewRequest(TestCase):
# nb. using 'butterfly' theme should cause the 'use_oruga'
# flag to be turned on by default
self.request = self.make_request()
self.request.registry.settings['wuttaweb.theme'] = 'butterfly'
self.request.registry.settings["wuttaweb.theme"] = "butterfly"
event = MagicMock(request=self.request)
subscribers.new_request(event)
self.assertTrue(self.request.use_oruga)
def test_use_oruga_custom(self):
self.config.setdefault('wuttaweb.oruga_detector.spec', 'tests.test_subscribers:custom_oruga_detector')
self.config.setdefault(
"wuttaweb.oruga_detector.spec",
"tests.test_subscribers:custom_oruga_detector",
)
event = MagicMock(request=self.request)
# request gets a new attr, which should be true
self.assertFalse(hasattr(self.request, 'use_oruga'))
self.assertFalse(hasattr(self.request, "use_oruga"))
subscribers.new_request(event)
self.assertTrue(self.request.use_oruga)
@ -70,20 +76,24 @@ class TestNewRequest(TestCase):
subscribers.new_request(event)
# component tracking dict is missing at first
self.assertFalse(hasattr(self.request, '_wuttaweb_registered_components'))
self.assertFalse(hasattr(self.request, "_wuttaweb_registered_components"))
# registering a component
self.request.register_component('foo-example', 'FooExample')
self.assertTrue(hasattr(self.request, '_wuttaweb_registered_components'))
self.request.register_component("foo-example", "FooExample")
self.assertTrue(hasattr(self.request, "_wuttaweb_registered_components"))
self.assertEqual(len(self.request._wuttaweb_registered_components), 1)
self.assertIn('foo-example', self.request._wuttaweb_registered_components)
self.assertEqual(self.request._wuttaweb_registered_components['foo-example'], 'FooExample')
self.assertIn("foo-example", self.request._wuttaweb_registered_components)
self.assertEqual(
self.request._wuttaweb_registered_components["foo-example"], "FooExample"
)
# re-registering same name
self.request.register_component('foo-example', 'FooExample')
self.request.register_component("foo-example", "FooExample")
self.assertEqual(len(self.request._wuttaweb_registered_components), 1)
self.assertIn('foo-example', self.request._wuttaweb_registered_components)
self.assertEqual(self.request._wuttaweb_registered_components['foo-example'], 'FooExample')
self.assertIn("foo-example", self.request._wuttaweb_registered_components)
self.assertEqual(
self.request._wuttaweb_registered_components["foo-example"], "FooExample"
)
def test_get_referrer(self):
event = MagicMock(request=self.request)
@ -91,33 +101,33 @@ class TestNewRequest(TestCase):
def home(request):
pass
self.pyramid_config.add_route('home', '/')
self.pyramid_config.add_view(home, route_name='home')
self.pyramid_config.add_route("home", "/")
self.pyramid_config.add_view(home, route_name="home")
self.assertFalse(hasattr(self.request, 'get_referrer'))
self.assertFalse(hasattr(self.request, "get_referrer"))
subscribers.new_request(event)
self.assertTrue(hasattr(self.request, 'get_referrer'))
self.assertTrue(hasattr(self.request, "get_referrer"))
# default if no referrer, is home route
url = self.request.get_referrer()
self.assertEqual(url, self.request.route_url('home'))
self.assertEqual(url, self.request.route_url("home"))
# can specify another default
url = self.request.get_referrer(default='https://wuttaproject.org')
self.assertEqual(url, 'https://wuttaproject.org')
url = self.request.get_referrer(default="https://wuttaproject.org")
self.assertEqual(url, "https://wuttaproject.org")
# or referrer can come from user session
self.request.session['referrer'] = 'https://rattailproject.org'
self.assertIn('referrer', self.request.session)
self.request.session["referrer"] = "https://rattailproject.org"
self.assertIn("referrer", self.request.session)
url = self.request.get_referrer()
self.assertEqual(url, 'https://rattailproject.org')
self.assertEqual(url, "https://rattailproject.org")
# nb. referrer should also have been removed from user session
self.assertNotIn('referrer', self.request.session)
self.assertNotIn("referrer", self.request.session)
# or referrer can come from request params
self.request.params['referrer'] = 'https://kernel.org'
self.request.params["referrer"] = "https://kernel.org"
url = self.request.get_referrer()
self.assertEqual(url, 'https://kernel.org')
self.assertEqual(url, "https://kernel.org")
def custom_oruga_detector(request):
@ -127,30 +137,37 @@ def custom_oruga_detector(request):
class TestNewRequestSetUser(TestCase):
def setUp(self):
self.config = WuttaConfig(defaults={
'wutta.db.default.url': 'sqlite://',
})
self.config = WuttaConfig(
defaults={
"wutta.db.default.url": "sqlite://",
}
)
self.request = testing.DummyRequest(wutta_config=self.config)
self.pyramid_config = testing.setUp(request=self.request, settings={
'wutta_config': self.config,
})
self.pyramid_config = testing.setUp(
request=self.request,
settings={
"wutta_config": self.config,
},
)
self.app = self.config.get_app()
model = self.app.model
model.Base.metadata.create_all(bind=self.config.appdb_engine)
self.session = self.app.make_session()
self.user = model.User(username='barney')
self.user = model.User(username="barney")
self.session.add(self.user)
self.session.commit()
self.pyramid_config.set_security_policy(WuttaSecurityPolicy(db_session=self.session))
self.pyramid_config.set_security_policy(
WuttaSecurityPolicy(db_session=self.session)
)
def tearDown(self):
testing.tearDown()
def test_anonymous(self):
self.assertFalse(hasattr(self.request, 'user'))
self.assertFalse(hasattr(self.request, "user"))
event = MagicMock(request=self.request)
subscribers.new_request_set_user(event)
self.assertIsNone(self.request.user)
@ -167,8 +184,8 @@ class TestNewRequestSetUser(TestCase):
event = MagicMock(request=self.request)
# anonymous user
self.assertFalse(hasattr(self.request, 'user'))
self.assertFalse(hasattr(self.request, 'is_admin'))
self.assertFalse(hasattr(self.request, "user"))
self.assertFalse(hasattr(self.request, "is_admin"))
subscribers.new_request_set_user(event, db_session=self.session)
self.assertIsNone(self.request.user)
self.assertFalse(self.request.is_admin)
@ -198,8 +215,8 @@ class TestNewRequestSetUser(TestCase):
event = MagicMock(request=self.request)
# anonymous user
self.assertFalse(hasattr(self.request, 'user'))
self.assertFalse(hasattr(self.request, 'is_root'))
self.assertFalse(hasattr(self.request, "user"))
self.assertFalse(hasattr(self.request, "is_root"))
subscribers.new_request_set_user(event, db_session=self.session)
self.assertIsNone(self.request.user)
self.assertFalse(self.request.is_root)
@ -233,7 +250,7 @@ class TestNewRequestSetUser(TestCase):
del self.request.is_root
# root status flag lives in user session
self.request.session['is_root'] = True
self.request.session["is_root"] = True
subscribers.new_request_set_user(event, db_session=self.session)
self.assertTrue(self.request.is_admin)
self.assertTrue(self.request.is_root)
@ -244,7 +261,7 @@ class TestNewRequestSetUser(TestCase):
event = MagicMock(request=self.request)
# anonymous user
self.assertFalse(hasattr(self.request, 'user_permissions'))
self.assertFalse(hasattr(self.request, "user_permissions"))
subscribers.new_request_set_user(event, db_session=self.session)
self.assertEqual(self.request.user_permissions, set())
@ -254,14 +271,14 @@ class TestNewRequestSetUser(TestCase):
# add user to role with perms
blokes = model.Role(name="Blokes")
self.session.add(blokes)
auth.grant_permission(blokes, 'appinfo.list')
auth.grant_permission(blokes, "appinfo.list")
self.user.roles.append(blokes)
self.session.commit()
# authenticated user, with perms
self.request.user = self.user
subscribers.new_request_set_user(event, db_session=self.session)
self.assertEqual(self.request.user_permissions, {'appinfo.list'})
self.assertEqual(self.request.user_permissions, {"appinfo.list"})
def test_has_perm(self):
model = self.app.model
@ -269,9 +286,9 @@ class TestNewRequestSetUser(TestCase):
event = MagicMock(request=self.request)
# anonymous user
self.assertFalse(hasattr(self.request, 'has_perm'))
self.assertFalse(hasattr(self.request, "has_perm"))
subscribers.new_request_set_user(event, db_session=self.session)
self.assertFalse(self.request.has_perm('appinfo.list'))
self.assertFalse(self.request.has_perm("appinfo.list"))
# reset
del self.request.user_permissions
@ -281,14 +298,14 @@ class TestNewRequestSetUser(TestCase):
# add user to role with perms
blokes = model.Role(name="Blokes")
self.session.add(blokes)
auth.grant_permission(blokes, 'appinfo.list')
auth.grant_permission(blokes, "appinfo.list")
self.user.roles.append(blokes)
self.session.commit()
# authenticated user, with perms
self.request.user = self.user
subscribers.new_request_set_user(event, db_session=self.session)
self.assertTrue(self.request.has_perm('appinfo.list'))
self.assertTrue(self.request.has_perm("appinfo.list"))
# reset
del self.request.user_permissions
@ -299,7 +316,7 @@ class TestNewRequestSetUser(TestCase):
self.user.roles.remove(blokes)
self.session.commit()
subscribers.new_request_set_user(event, db_session=self.session)
self.assertFalse(self.request.has_perm('appinfo.list'))
self.assertFalse(self.request.has_perm("appinfo.list"))
# reset
del self.request.user_permissions
@ -312,9 +329,9 @@ class TestNewRequestSetUser(TestCase):
admin = auth.get_role_administrator(self.session)
self.user.roles.append(admin)
self.session.commit()
self.request.session['is_root'] = True
self.request.session["is_root"] = True
subscribers.new_request_set_user(event, db_session=self.session)
self.assertTrue(self.request.has_perm('appinfo.list'))
self.assertTrue(self.request.has_perm("appinfo.list"))
def test_has_any_perm(self):
model = self.app.model
@ -322,9 +339,9 @@ class TestNewRequestSetUser(TestCase):
event = MagicMock(request=self.request)
# anonymous user
self.assertFalse(hasattr(self.request, 'has_any_perm'))
self.assertFalse(hasattr(self.request, "has_any_perm"))
subscribers.new_request_set_user(event, db_session=self.session)
self.assertFalse(self.request.has_any_perm('appinfo.list'))
self.assertFalse(self.request.has_any_perm("appinfo.list"))
# reset
del self.request.user_permissions
@ -334,14 +351,14 @@ class TestNewRequestSetUser(TestCase):
# add user to role with perms
blokes = model.Role(name="Blokes")
self.session.add(blokes)
auth.grant_permission(blokes, 'appinfo.list')
auth.grant_permission(blokes, "appinfo.list")
self.user.roles.append(blokes)
self.session.commit()
# authenticated user, with perms
self.request.user = self.user
subscribers.new_request_set_user(event, db_session=self.session)
self.assertTrue(self.request.has_any_perm('appinfo.list', 'appinfo.view'))
self.assertTrue(self.request.has_any_perm("appinfo.list", "appinfo.view"))
# reset
del self.request.user_permissions
@ -352,7 +369,7 @@ class TestNewRequestSetUser(TestCase):
self.user.roles.remove(blokes)
self.session.commit()
subscribers.new_request_set_user(event, db_session=self.session)
self.assertFalse(self.request.has_any_perm('appinfo.list'))
self.assertFalse(self.request.has_any_perm("appinfo.list"))
# reset
del self.request.user_permissions
@ -365,64 +382,66 @@ class TestNewRequestSetUser(TestCase):
admin = auth.get_role_administrator(self.session)
self.user.roles.append(admin)
self.session.commit()
self.request.session['is_root'] = True
self.request.session["is_root"] = True
subscribers.new_request_set_user(event, db_session=self.session)
self.assertTrue(self.request.has_any_perm('appinfo.list'))
self.assertTrue(self.request.has_any_perm("appinfo.list"))
class TestBeforeRender(TestCase):
def setUp(self):
self.config = WuttaConfig(defaults={
'wutta.web.menus.handler.spec': 'tests.util:NullMenuHandler',
})
self.config = WuttaConfig(
defaults={
"wutta.web.menus.handler.spec": "tests.util:NullMenuHandler",
}
)
def make_request(self):
request = testing.DummyRequest(use_oruga=False)
request.registry.settings = {'wutta_config': self.config}
request.registry.settings = {"wutta_config": self.config}
request.wutta_config = self.config
return request
def test_basic(self):
request = self.make_request()
event = {'request': request}
event = {"request": request}
# event dict will get populated with more context
subscribers.before_render(event)
self.assertIn('config', event)
self.assertIs(event['config'], self.config)
self.assertIn("config", event)
self.assertIs(event["config"], self.config)
self.assertIn('app', event)
self.assertIs(event['app'], self.config.get_app())
self.assertIn("app", event)
self.assertIs(event["app"], self.config.get_app())
self.assertIn('h', event)
self.assertIs(event['h'], helpers)
self.assertIn("h", event)
self.assertIs(event["h"], helpers)
self.assertIn('url', event)
self.assertIn("url", event)
# TODO: not sure how to test this?
# self.assertIs(event['url'], request.route_url)
self.assertIn('json', event)
self.assertIs(event['json'], json)
self.assertIn("json", event)
self.assertIs(event["json"], json)
# current theme should be 'default' and picker not exposed
self.assertEqual(event['theme'], 'default')
self.assertFalse(event['expose_theme_picker'])
self.assertNotIn('available_themes', event)
self.assertEqual(event["theme"], "default")
self.assertFalse(event["expose_theme_picker"])
self.assertNotIn("available_themes", event)
def test_custom_theme(self):
self.config.setdefault('wuttaweb.themes.expose_picker', 'true')
self.config.setdefault("wuttaweb.themes.expose_picker", "true")
request = self.make_request()
request.registry.settings['wuttaweb.theme'] = 'butterfly'
event = {'request': request}
request.registry.settings["wuttaweb.theme"] = "butterfly"
event = {"request": request}
# event dict will get populated with more context
subscribers.before_render(event)
self.assertEqual(event['theme'], 'butterfly')
self.assertTrue(event['expose_theme_picker'])
self.assertIn('available_themes', event)
self.assertEqual(event['available_themes'], ['default', 'butterfly'])
self.assertEqual(event["theme"], "butterfly")
self.assertTrue(event["expose_theme_picker"])
self.assertIn("available_themes", event)
self.assertEqual(event["available_themes"], ["default", "butterfly"])
class TestIncludeMe(TestCase):
@ -431,4 +450,4 @@ class TestIncludeMe(TestCase):
with testing.testConfig() as pyramid_config:
# just ensure no error happens when included..
pyramid_config.include('wuttaweb.subscribers')
pyramid_config.include("wuttaweb.subscribers")

View file

@ -22,40 +22,40 @@ from wuttaweb.testing import WebTestCase
class TestFieldList(TestCase):
def test_insert_before(self):
fields = mod.FieldList(['f1', 'f2'])
self.assertEqual(fields, ['f1', 'f2'])
fields = mod.FieldList(["f1", "f2"])
self.assertEqual(fields, ["f1", "f2"])
# typical
fields.insert_before('f1', 'XXX')
self.assertEqual(fields, ['XXX', 'f1', 'f2'])
fields.insert_before('f2', 'YYY')
self.assertEqual(fields, ['XXX', 'f1', 'YYY', 'f2'])
fields.insert_before("f1", "XXX")
self.assertEqual(fields, ["XXX", "f1", "f2"])
fields.insert_before("f2", "YYY")
self.assertEqual(fields, ["XXX", "f1", "YYY", "f2"])
# appends new field if reference field is invalid
fields.insert_before('f3', 'ZZZ')
self.assertEqual(fields, ['XXX', 'f1', 'YYY', 'f2', 'ZZZ'])
fields.insert_before("f3", "ZZZ")
self.assertEqual(fields, ["XXX", "f1", "YYY", "f2", "ZZZ"])
def test_insert_after(self):
fields = mod.FieldList(['f1', 'f2'])
self.assertEqual(fields, ['f1', 'f2'])
fields = mod.FieldList(["f1", "f2"])
self.assertEqual(fields, ["f1", "f2"])
# typical
fields.insert_after('f1', 'XXX')
self.assertEqual(fields, ['f1', 'XXX', 'f2'])
fields.insert_after('XXX', 'YYY')
self.assertEqual(fields, ['f1', 'XXX', 'YYY', 'f2'])
fields.insert_after("f1", "XXX")
self.assertEqual(fields, ["f1", "XXX", "f2"])
fields.insert_after("XXX", "YYY")
self.assertEqual(fields, ["f1", "XXX", "YYY", "f2"])
# appends new field if reference field is invalid
fields.insert_after('f3', 'ZZZ')
self.assertEqual(fields, ['f1', 'XXX', 'YYY', 'f2', 'ZZZ'])
fields.insert_after("f3", "ZZZ")
self.assertEqual(fields, ["f1", "XXX", "YYY", "f2", "ZZZ"])
def test_set_sequence(self):
fields = mod.FieldList(['f5', 'f1', 'f3', 'f4', 'f2'])
fields = mod.FieldList(["f5", "f1", "f3", "f4", "f2"])
# setting sequence will only "sort" for explicit fields.
# other fields remain in original order, but at the end.
fields.set_sequence(['f1', 'f2', 'f3'])
self.assertEqual(fields, ['f1', 'f2', 'f3', 'f5', 'f4'])
fields.set_sequence(["f1", "f2", "f3"])
self.assertEqual(fields, ["f1", "f2", "f3", "f5", "f4"])
class TestGetLibVer(TestCase):
@ -66,169 +66,169 @@ class TestGetLibVer(TestCase):
self.request.wutta_config = self.config
def test_buefy_default(self):
version = mod.get_libver(self.request, 'buefy')
self.assertEqual(version, '0.9.25')
version = mod.get_libver(self.request, "buefy")
self.assertEqual(version, "0.9.25")
def test_buefy_custom_old(self):
self.config.setdefault('wuttaweb.buefy_version', '0.9.29')
version = mod.get_libver(self.request, 'buefy')
self.assertEqual(version, '0.9.29')
self.config.setdefault("wuttaweb.buefy_version", "0.9.29")
version = mod.get_libver(self.request, "buefy")
self.assertEqual(version, "0.9.29")
def test_buefy_custom_old_tailbone(self):
self.config.setdefault('tailbone.libver.buefy', '0.9.28')
version = mod.get_libver(self.request, 'buefy', prefix='tailbone')
self.assertEqual(version, '0.9.28')
self.config.setdefault("tailbone.libver.buefy", "0.9.28")
version = mod.get_libver(self.request, "buefy", prefix="tailbone")
self.assertEqual(version, "0.9.28")
def test_buefy_custom_new(self):
self.config.setdefault('wuttaweb.libver.buefy', '0.9.29')
version = mod.get_libver(self.request, 'buefy')
self.assertEqual(version, '0.9.29')
self.config.setdefault("wuttaweb.libver.buefy", "0.9.29")
version = mod.get_libver(self.request, "buefy")
self.assertEqual(version, "0.9.29")
def test_buefy_configured_only(self):
version = mod.get_libver(self.request, 'buefy', configured_only=True)
version = mod.get_libver(self.request, "buefy", configured_only=True)
self.assertIsNone(version)
def test_buefy_default_only(self):
self.config.setdefault('wuttaweb.libver.buefy', '0.9.29')
version = mod.get_libver(self.request, 'buefy', default_only=True)
self.assertEqual(version, '0.9.25')
self.config.setdefault("wuttaweb.libver.buefy", "0.9.29")
version = mod.get_libver(self.request, "buefy", default_only=True)
self.assertEqual(version, "0.9.25")
def test_buefy_css_default(self):
version = mod.get_libver(self.request, 'buefy.css')
self.assertEqual(version, '0.9.25')
version = mod.get_libver(self.request, "buefy.css")
self.assertEqual(version, "0.9.25")
def test_buefy_css_custom_old(self):
# nb. this uses same setting as buefy (js)
self.config.setdefault('wuttaweb.buefy_version', '0.9.29')
version = mod.get_libver(self.request, 'buefy.css')
self.assertEqual(version, '0.9.29')
self.config.setdefault("wuttaweb.buefy_version", "0.9.29")
version = mod.get_libver(self.request, "buefy.css")
self.assertEqual(version, "0.9.29")
def test_buefy_css_custom_new(self):
# nb. this uses same setting as buefy (js)
self.config.setdefault('wuttaweb.libver.buefy', '0.9.29')
version = mod.get_libver(self.request, 'buefy.css')
self.assertEqual(version, '0.9.29')
self.config.setdefault("wuttaweb.libver.buefy", "0.9.29")
version = mod.get_libver(self.request, "buefy.css")
self.assertEqual(version, "0.9.29")
def test_buefy_css_configured_only(self):
version = mod.get_libver(self.request, 'buefy.css', configured_only=True)
version = mod.get_libver(self.request, "buefy.css", configured_only=True)
self.assertIsNone(version)
def test_buefy_css_default_only(self):
self.config.setdefault('wuttaweb.libver.buefy', '0.9.29')
version = mod.get_libver(self.request, 'buefy.css', default_only=True)
self.assertEqual(version, '0.9.25')
self.config.setdefault("wuttaweb.libver.buefy", "0.9.29")
version = mod.get_libver(self.request, "buefy.css", default_only=True)
self.assertEqual(version, "0.9.25")
def test_vue_default(self):
version = mod.get_libver(self.request, 'vue')
self.assertEqual(version, '2.6.14')
version = mod.get_libver(self.request, "vue")
self.assertEqual(version, "2.6.14")
def test_vue_custom_old(self):
self.config.setdefault('wuttaweb.vue_version', '3.4.31')
version = mod.get_libver(self.request, 'vue')
self.assertEqual(version, '3.4.31')
self.config.setdefault("wuttaweb.vue_version", "3.4.31")
version = mod.get_libver(self.request, "vue")
self.assertEqual(version, "3.4.31")
def test_vue_custom_new(self):
self.config.setdefault('wuttaweb.libver.vue', '3.4.31')
version = mod.get_libver(self.request, 'vue')
self.assertEqual(version, '3.4.31')
self.config.setdefault("wuttaweb.libver.vue", "3.4.31")
version = mod.get_libver(self.request, "vue")
self.assertEqual(version, "3.4.31")
def test_vue_configured_only(self):
version = mod.get_libver(self.request, 'vue', configured_only=True)
version = mod.get_libver(self.request, "vue", configured_only=True)
self.assertIsNone(version)
def test_vue_default_only(self):
self.config.setdefault('wuttaweb.libver.vue', '3.4.31')
version = mod.get_libver(self.request, 'vue', default_only=True)
self.assertEqual(version, '2.6.14')
self.config.setdefault("wuttaweb.libver.vue", "3.4.31")
version = mod.get_libver(self.request, "vue", default_only=True)
self.assertEqual(version, "2.6.14")
def test_vue_resource_default(self):
version = mod.get_libver(self.request, 'vue_resource')
self.assertEqual(version, '1.5.3')
version = mod.get_libver(self.request, "vue_resource")
self.assertEqual(version, "1.5.3")
def test_vue_resource_custom(self):
self.config.setdefault('wuttaweb.libver.vue_resource', '1.5.3')
version = mod.get_libver(self.request, 'vue_resource')
self.assertEqual(version, '1.5.3')
self.config.setdefault("wuttaweb.libver.vue_resource", "1.5.3")
version = mod.get_libver(self.request, "vue_resource")
self.assertEqual(version, "1.5.3")
def test_fontawesome_default(self):
version = mod.get_libver(self.request, 'fontawesome')
self.assertEqual(version, '5.3.1')
version = mod.get_libver(self.request, "fontawesome")
self.assertEqual(version, "5.3.1")
def test_fontawesome_custom(self):
self.config.setdefault('wuttaweb.libver.fontawesome', '5.6.3')
version = mod.get_libver(self.request, 'fontawesome')
self.assertEqual(version, '5.6.3')
self.config.setdefault("wuttaweb.libver.fontawesome", "5.6.3")
version = mod.get_libver(self.request, "fontawesome")
self.assertEqual(version, "5.6.3")
def test_bb_vue_default(self):
version = mod.get_libver(self.request, 'bb_vue')
self.assertEqual(version, '3.5.18')
version = mod.get_libver(self.request, "bb_vue")
self.assertEqual(version, "3.5.18")
def test_bb_vue_custom(self):
self.config.setdefault('wuttaweb.libver.bb_vue', '3.4.30')
version = mod.get_libver(self.request, 'bb_vue')
self.assertEqual(version, '3.4.30')
self.config.setdefault("wuttaweb.libver.bb_vue", "3.4.30")
version = mod.get_libver(self.request, "bb_vue")
self.assertEqual(version, "3.4.30")
def test_bb_oruga_default(self):
version = mod.get_libver(self.request, 'bb_oruga')
self.assertEqual(version, '0.11.4')
version = mod.get_libver(self.request, "bb_oruga")
self.assertEqual(version, "0.11.4")
def test_bb_oruga_custom(self):
self.config.setdefault('wuttaweb.libver.bb_oruga', '0.8.11')
version = mod.get_libver(self.request, 'bb_oruga')
self.assertEqual(version, '0.8.11')
self.config.setdefault("wuttaweb.libver.bb_oruga", "0.8.11")
version = mod.get_libver(self.request, "bb_oruga")
self.assertEqual(version, "0.8.11")
def test_bb_oruga_bulma_default(self):
version = mod.get_libver(self.request, 'bb_oruga_bulma')
self.assertEqual(version, '0.7.3')
version = mod.get_libver(self.request, 'bb_oruga_bulma_css')
self.assertEqual(version, '0.7.3')
version = mod.get_libver(self.request, "bb_oruga_bulma")
self.assertEqual(version, "0.7.3")
version = mod.get_libver(self.request, "bb_oruga_bulma_css")
self.assertEqual(version, "0.7.3")
def test_bb_oruga_bulma_custom(self):
self.config.setdefault('wuttaweb.libver.bb_oruga_bulma', '0.2.11')
version = mod.get_libver(self.request, 'bb_oruga_bulma')
self.assertEqual(version, '0.2.11')
self.config.setdefault("wuttaweb.libver.bb_oruga_bulma", "0.2.11")
version = mod.get_libver(self.request, "bb_oruga_bulma")
self.assertEqual(version, "0.2.11")
def test_bb_fontawesome_svg_core_default(self):
version = mod.get_libver(self.request, 'bb_fontawesome_svg_core')
self.assertEqual(version, '7.0.0')
version = mod.get_libver(self.request, "bb_fontawesome_svg_core")
self.assertEqual(version, "7.0.0")
def test_bb_fontawesome_svg_core_custom(self):
self.config.setdefault('wuttaweb.libver.bb_fontawesome_svg_core', '6.5.1')
version = mod.get_libver(self.request, 'bb_fontawesome_svg_core')
self.assertEqual(version, '6.5.1')
self.config.setdefault("wuttaweb.libver.bb_fontawesome_svg_core", "6.5.1")
version = mod.get_libver(self.request, "bb_fontawesome_svg_core")
self.assertEqual(version, "6.5.1")
def test_bb_free_solid_svg_icons_default(self):
version = mod.get_libver(self.request, 'bb_free_solid_svg_icons')
self.assertEqual(version, '7.0.0')
version = mod.get_libver(self.request, "bb_free_solid_svg_icons")
self.assertEqual(version, "7.0.0")
def test_bb_free_solid_svg_icons_custom(self):
self.config.setdefault('wuttaweb.libver.bb_free_solid_svg_icons', '6.5.1')
version = mod.get_libver(self.request, 'bb_free_solid_svg_icons')
self.assertEqual(version, '6.5.1')
self.config.setdefault("wuttaweb.libver.bb_free_solid_svg_icons", "6.5.1")
version = mod.get_libver(self.request, "bb_free_solid_svg_icons")
self.assertEqual(version, "6.5.1")
def test_bb_vue_fontawesome_default(self):
version = mod.get_libver(self.request, 'bb_vue_fontawesome')
self.assertEqual(version, '3.1.1')
version = mod.get_libver(self.request, "bb_vue_fontawesome")
self.assertEqual(version, "3.1.1")
def test_bb_vue_fontawesome_custom(self):
self.config.setdefault('wuttaweb.libver.bb_vue_fontawesome', '3.0.8')
version = mod.get_libver(self.request, 'bb_vue_fontawesome')
self.assertEqual(version, '3.0.8')
self.config.setdefault("wuttaweb.libver.bb_vue_fontawesome", "3.0.8")
version = mod.get_libver(self.request, "bb_vue_fontawesome")
self.assertEqual(version, "3.0.8")
libcache = Library('testing', 'libcache')
vue_js = Resource(libcache, 'vue.js')
vue_resource_js = Resource(libcache, 'vue_resource.js')
buefy_js = Resource(libcache, 'buefy.js')
buefy_css = Resource(libcache, 'buefy.css')
fontawesome_js = Resource(libcache, 'fontawesome.js')
bb_vue_js = Resource(libcache, 'bb_vue.js')
bb_oruga_js = Resource(libcache, 'bb_oruga.js')
bb_oruga_bulma_js = Resource(libcache, 'bb_oruga_bulma.js')
bb_oruga_bulma_css = Resource(libcache, 'bb_oruga_bulma.css')
bb_fontawesome_svg_core_js = Resource(libcache, 'bb_fontawesome_svg_core.js')
bb_free_solid_svg_icons_js = Resource(libcache, 'bb_free_solid_svg_icons.js')
bb_vue_fontawesome_js = Resource(libcache, 'bb_vue_fontawesome.js')
libcache = Library("testing", "libcache")
vue_js = Resource(libcache, "vue.js")
vue_resource_js = Resource(libcache, "vue_resource.js")
buefy_js = Resource(libcache, "buefy.js")
buefy_css = Resource(libcache, "buefy.css")
fontawesome_js = Resource(libcache, "fontawesome.js")
bb_vue_js = Resource(libcache, "bb_vue.js")
bb_oruga_js = Resource(libcache, "bb_oruga.js")
bb_oruga_bulma_js = Resource(libcache, "bb_oruga_bulma.js")
bb_oruga_bulma_css = Resource(libcache, "bb_oruga_bulma.css")
bb_fontawesome_svg_core_js = Resource(libcache, "bb_fontawesome_svg_core.js")
bb_free_solid_svg_icons_js = Resource(libcache, "bb_free_solid_svg_icons.js")
bb_vue_fontawesome_js = Resource(libcache, "bb_vue_fontawesome.js")
class TestGetLibUrl(TestCase):
@ -242,203 +242,226 @@ class TestGetLibUrl(TestCase):
testing.tearDown()
def setup_fanstatic(self, register=True):
self.pyramid_config.include('pyramid_fanstatic')
self.pyramid_config.include("pyramid_fanstatic")
if register:
self.config.setdefault('wuttaweb.static_libcache.module',
'tests.test_util')
self.config.setdefault("wuttaweb.static_libcache.module", "tests.test_util")
needed = MagicMock()
needed.library_url = MagicMock(return_value='/fanstatic')
self.request.environ['fanstatic.needed'] = needed
self.request.script_name = '/wutta'
needed.library_url = MagicMock(return_value="/fanstatic")
self.request.environ["fanstatic.needed"] = needed
self.request.script_name = "/wutta"
def test_buefy_default(self):
url = mod.get_liburl(self.request, 'buefy')
self.assertEqual(url, 'https://unpkg.com/buefy@0.9.25/dist/buefy.min.js')
url = mod.get_liburl(self.request, "buefy")
self.assertEqual(url, "https://unpkg.com/buefy@0.9.25/dist/buefy.min.js")
def test_buefy_custom(self):
self.config.setdefault('wuttaweb.liburl.buefy', '/lib/buefy.js')
url = mod.get_liburl(self.request, 'buefy')
self.assertEqual(url, '/lib/buefy.js')
self.config.setdefault("wuttaweb.liburl.buefy", "/lib/buefy.js")
url = mod.get_liburl(self.request, "buefy")
self.assertEqual(url, "/lib/buefy.js")
def test_buefy_custom_tailbone(self):
self.config.setdefault('tailbone.liburl.buefy', '/tailbone/buefy.js')
url = mod.get_liburl(self.request, 'buefy', prefix='tailbone')
self.assertEqual(url, '/tailbone/buefy.js')
self.config.setdefault("tailbone.liburl.buefy", "/tailbone/buefy.js")
url = mod.get_liburl(self.request, "buefy", prefix="tailbone")
self.assertEqual(url, "/tailbone/buefy.js")
def test_buefy_default_only(self):
self.config.setdefault('wuttaweb.liburl.buefy', '/lib/buefy.js')
url = mod.get_liburl(self.request, 'buefy', default_only=True)
self.assertEqual(url, 'https://unpkg.com/buefy@0.9.25/dist/buefy.min.js')
self.config.setdefault("wuttaweb.liburl.buefy", "/lib/buefy.js")
url = mod.get_liburl(self.request, "buefy", default_only=True)
self.assertEqual(url, "https://unpkg.com/buefy@0.9.25/dist/buefy.min.js")
def test_buefy_configured_only(self):
url = mod.get_liburl(self.request, 'buefy', configured_only=True)
url = mod.get_liburl(self.request, "buefy", configured_only=True)
self.assertIsNone(url)
def test_buefy_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'buefy')
self.assertEqual(url, '/wutta/fanstatic/buefy.js')
url = mod.get_liburl(self.request, "buefy")
self.assertEqual(url, "/wutta/fanstatic/buefy.js")
def test_buefy_fanstatic_tailbone(self):
self.setup_fanstatic(register=False)
self.config.setdefault('tailbone.static_libcache.module', 'tests.test_util')
url = mod.get_liburl(self.request, 'buefy', prefix='tailbone')
self.assertEqual(url, '/wutta/fanstatic/buefy.js')
self.config.setdefault("tailbone.static_libcache.module", "tests.test_util")
url = mod.get_liburl(self.request, "buefy", prefix="tailbone")
self.assertEqual(url, "/wutta/fanstatic/buefy.js")
def test_buefy_css_default(self):
url = mod.get_liburl(self.request, 'buefy.css')
self.assertEqual(url, 'https://unpkg.com/buefy@0.9.25/dist/buefy.min.css')
url = mod.get_liburl(self.request, "buefy.css")
self.assertEqual(url, "https://unpkg.com/buefy@0.9.25/dist/buefy.min.css")
def test_buefy_css_custom(self):
self.config.setdefault('wuttaweb.liburl.buefy.css', '/lib/buefy.css')
url = mod.get_liburl(self.request, 'buefy.css')
self.assertEqual(url, '/lib/buefy.css')
self.config.setdefault("wuttaweb.liburl.buefy.css", "/lib/buefy.css")
url = mod.get_liburl(self.request, "buefy.css")
self.assertEqual(url, "/lib/buefy.css")
def test_buefy_css_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'buefy.css')
self.assertEqual(url, '/wutta/fanstatic/buefy.css')
url = mod.get_liburl(self.request, "buefy.css")
self.assertEqual(url, "/wutta/fanstatic/buefy.css")
def test_vue_default(self):
url = mod.get_liburl(self.request, 'vue')
self.assertEqual(url, 'https://unpkg.com/vue@2.6.14/dist/vue.min.js')
url = mod.get_liburl(self.request, "vue")
self.assertEqual(url, "https://unpkg.com/vue@2.6.14/dist/vue.min.js")
def test_vue_custom(self):
self.config.setdefault('wuttaweb.liburl.vue', '/lib/vue.js')
url = mod.get_liburl(self.request, 'vue')
self.assertEqual(url, '/lib/vue.js')
self.config.setdefault("wuttaweb.liburl.vue", "/lib/vue.js")
url = mod.get_liburl(self.request, "vue")
self.assertEqual(url, "/lib/vue.js")
def test_vue_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'vue')
self.assertEqual(url, '/wutta/fanstatic/vue.js')
url = mod.get_liburl(self.request, "vue")
self.assertEqual(url, "/wutta/fanstatic/vue.js")
def test_vue_resource_default(self):
url = mod.get_liburl(self.request, 'vue_resource')
self.assertEqual(url, 'https://cdn.jsdelivr.net/npm/vue-resource@1.5.3')
url = mod.get_liburl(self.request, "vue_resource")
self.assertEqual(url, "https://cdn.jsdelivr.net/npm/vue-resource@1.5.3")
def test_vue_resource_custom(self):
self.config.setdefault('wuttaweb.liburl.vue_resource', '/lib/vue-resource.js')
url = mod.get_liburl(self.request, 'vue_resource')
self.assertEqual(url, '/lib/vue-resource.js')
self.config.setdefault("wuttaweb.liburl.vue_resource", "/lib/vue-resource.js")
url = mod.get_liburl(self.request, "vue_resource")
self.assertEqual(url, "/lib/vue-resource.js")
def test_vue_resource_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'vue_resource')
self.assertEqual(url, '/wutta/fanstatic/vue_resource.js')
url = mod.get_liburl(self.request, "vue_resource")
self.assertEqual(url, "/wutta/fanstatic/vue_resource.js")
def test_fontawesome_default(self):
url = mod.get_liburl(self.request, 'fontawesome')
self.assertEqual(url, 'https://use.fontawesome.com/releases/v5.3.1/js/all.js')
url = mod.get_liburl(self.request, "fontawesome")
self.assertEqual(url, "https://use.fontawesome.com/releases/v5.3.1/js/all.js")
def test_fontawesome_custom(self):
self.config.setdefault('wuttaweb.liburl.fontawesome', '/lib/fontawesome.js')
url = mod.get_liburl(self.request, 'fontawesome')
self.assertEqual(url, '/lib/fontawesome.js')
self.config.setdefault("wuttaweb.liburl.fontawesome", "/lib/fontawesome.js")
url = mod.get_liburl(self.request, "fontawesome")
self.assertEqual(url, "/lib/fontawesome.js")
def test_fontawesome_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'fontawesome')
self.assertEqual(url, '/wutta/fanstatic/fontawesome.js')
url = mod.get_liburl(self.request, "fontawesome")
self.assertEqual(url, "/wutta/fanstatic/fontawesome.js")
def test_bb_vue_default(self):
url = mod.get_liburl(self.request, 'bb_vue')
self.assertEqual(url, 'https://unpkg.com/vue@3.5.18/dist/vue.esm-browser.prod.js')
url = mod.get_liburl(self.request, "bb_vue")
self.assertEqual(
url, "https://unpkg.com/vue@3.5.18/dist/vue.esm-browser.prod.js"
)
def test_bb_vue_custom(self):
self.config.setdefault('wuttaweb.liburl.bb_vue', '/lib/vue.js')
url = mod.get_liburl(self.request, 'bb_vue')
self.assertEqual(url, '/lib/vue.js')
self.config.setdefault("wuttaweb.liburl.bb_vue", "/lib/vue.js")
url = mod.get_liburl(self.request, "bb_vue")
self.assertEqual(url, "/lib/vue.js")
def test_bb_vue_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'bb_vue')
self.assertEqual(url, '/wutta/fanstatic/bb_vue.js')
url = mod.get_liburl(self.request, "bb_vue")
self.assertEqual(url, "/wutta/fanstatic/bb_vue.js")
def test_bb_oruga_default(self):
url = mod.get_liburl(self.request, 'bb_oruga')
self.assertEqual(url, 'https://unpkg.com/@oruga-ui/oruga-next@0.11.4/dist/oruga.mjs')
url = mod.get_liburl(self.request, "bb_oruga")
self.assertEqual(
url, "https://unpkg.com/@oruga-ui/oruga-next@0.11.4/dist/oruga.mjs"
)
def test_bb_oruga_custom(self):
self.config.setdefault('wuttaweb.liburl.bb_oruga', '/lib/oruga.js')
url = mod.get_liburl(self.request, 'bb_oruga')
self.assertEqual(url, '/lib/oruga.js')
self.config.setdefault("wuttaweb.liburl.bb_oruga", "/lib/oruga.js")
url = mod.get_liburl(self.request, "bb_oruga")
self.assertEqual(url, "/lib/oruga.js")
def test_bb_oruga_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'bb_oruga')
self.assertEqual(url, '/wutta/fanstatic/bb_oruga.js')
url = mod.get_liburl(self.request, "bb_oruga")
self.assertEqual(url, "/wutta/fanstatic/bb_oruga.js")
def test_bb_oruga_bulma_default(self):
url = mod.get_liburl(self.request, 'bb_oruga_bulma')
self.assertEqual(url, 'https://unpkg.com/@oruga-ui/theme-bulma@0.7.3/dist/bulma.js')
url = mod.get_liburl(self.request, "bb_oruga_bulma")
self.assertEqual(
url, "https://unpkg.com/@oruga-ui/theme-bulma@0.7.3/dist/bulma.js"
)
def test_bb_oruga_bulma_custom(self):
self.config.setdefault('wuttaweb.liburl.bb_oruga_bulma', '/lib/oruga_bulma.js')
url = mod.get_liburl(self.request, 'bb_oruga_bulma')
self.assertEqual(url, '/lib/oruga_bulma.js')
self.config.setdefault("wuttaweb.liburl.bb_oruga_bulma", "/lib/oruga_bulma.js")
url = mod.get_liburl(self.request, "bb_oruga_bulma")
self.assertEqual(url, "/lib/oruga_bulma.js")
def test_bb_oruga_bulma_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'bb_oruga_bulma')
self.assertEqual(url, '/wutta/fanstatic/bb_oruga_bulma.js')
url = mod.get_liburl(self.request, "bb_oruga_bulma")
self.assertEqual(url, "/wutta/fanstatic/bb_oruga_bulma.js")
def test_bb_oruga_bulma_css_default(self):
url = mod.get_liburl(self.request, 'bb_oruga_bulma_css')
self.assertEqual(url, 'https://unpkg.com/@oruga-ui/theme-bulma@0.7.3/dist/bulma.css')
url = mod.get_liburl(self.request, "bb_oruga_bulma_css")
self.assertEqual(
url, "https://unpkg.com/@oruga-ui/theme-bulma@0.7.3/dist/bulma.css"
)
def test_bb_oruga_bulma_css_custom(self):
self.config.setdefault('wuttaweb.liburl.bb_oruga_bulma_css', '/lib/oruga-bulma.css')
url = mod.get_liburl(self.request, 'bb_oruga_bulma_css')
self.assertEqual(url, '/lib/oruga-bulma.css')
self.config.setdefault(
"wuttaweb.liburl.bb_oruga_bulma_css", "/lib/oruga-bulma.css"
)
url = mod.get_liburl(self.request, "bb_oruga_bulma_css")
self.assertEqual(url, "/lib/oruga-bulma.css")
def test_bb_oruga_bulma_css_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'bb_oruga_bulma_css')
self.assertEqual(url, '/wutta/fanstatic/bb_oruga_bulma.css')
url = mod.get_liburl(self.request, "bb_oruga_bulma_css")
self.assertEqual(url, "/wutta/fanstatic/bb_oruga_bulma.css")
def test_bb_fontawesome_svg_core_default(self):
url = mod.get_liburl(self.request, 'bb_fontawesome_svg_core')
self.assertEqual(url, 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-svg-core@7.0.0/+esm')
url = mod.get_liburl(self.request, "bb_fontawesome_svg_core")
self.assertEqual(
url,
"https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-svg-core@7.0.0/+esm",
)
def test_bb_fontawesome_svg_core_custom(self):
self.config.setdefault('wuttaweb.liburl.bb_fontawesome_svg_core', '/lib/fontawesome-svg-core.js')
url = mod.get_liburl(self.request, 'bb_fontawesome_svg_core')
self.assertEqual(url, '/lib/fontawesome-svg-core.js')
self.config.setdefault(
"wuttaweb.liburl.bb_fontawesome_svg_core", "/lib/fontawesome-svg-core.js"
)
url = mod.get_liburl(self.request, "bb_fontawesome_svg_core")
self.assertEqual(url, "/lib/fontawesome-svg-core.js")
def test_bb_fontawesome_svg_core_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'bb_fontawesome_svg_core')
self.assertEqual(url, '/wutta/fanstatic/bb_fontawesome_svg_core.js')
url = mod.get_liburl(self.request, "bb_fontawesome_svg_core")
self.assertEqual(url, "/wutta/fanstatic/bb_fontawesome_svg_core.js")
def test_bb_free_solid_svg_icons_default(self):
url = mod.get_liburl(self.request, 'bb_free_solid_svg_icons')
self.assertEqual(url, 'https://cdn.jsdelivr.net/npm/@fortawesome/free-solid-svg-icons@7.0.0/+esm')
url = mod.get_liburl(self.request, "bb_free_solid_svg_icons")
self.assertEqual(
url,
"https://cdn.jsdelivr.net/npm/@fortawesome/free-solid-svg-icons@7.0.0/+esm",
)
def test_bb_free_solid_svg_icons_custom(self):
self.config.setdefault('wuttaweb.liburl.bb_free_solid_svg_icons', '/lib/free-solid-svg-icons.js')
url = mod.get_liburl(self.request, 'bb_free_solid_svg_icons')
self.assertEqual(url, '/lib/free-solid-svg-icons.js')
self.config.setdefault(
"wuttaweb.liburl.bb_free_solid_svg_icons", "/lib/free-solid-svg-icons.js"
)
url = mod.get_liburl(self.request, "bb_free_solid_svg_icons")
self.assertEqual(url, "/lib/free-solid-svg-icons.js")
def test_bb_free_solid_svg_icons_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'bb_free_solid_svg_icons')
self.assertEqual(url, '/wutta/fanstatic/bb_free_solid_svg_icons.js')
url = mod.get_liburl(self.request, "bb_free_solid_svg_icons")
self.assertEqual(url, "/wutta/fanstatic/bb_free_solid_svg_icons.js")
def test_bb_vue_fontawesome_default(self):
url = mod.get_liburl(self.request, 'bb_vue_fontawesome')
self.assertEqual(url, 'https://cdn.jsdelivr.net/npm/@fortawesome/vue-fontawesome@3.1.1/+esm')
url = mod.get_liburl(self.request, "bb_vue_fontawesome")
self.assertEqual(
url, "https://cdn.jsdelivr.net/npm/@fortawesome/vue-fontawesome@3.1.1/+esm"
)
def test_bb_vue_fontawesome_custom(self):
self.config.setdefault('wuttaweb.liburl.bb_vue_fontawesome', '/lib/vue-fontawesome.js')
url = mod.get_liburl(self.request, 'bb_vue_fontawesome')
self.assertEqual(url, '/lib/vue-fontawesome.js')
self.config.setdefault(
"wuttaweb.liburl.bb_vue_fontawesome", "/lib/vue-fontawesome.js"
)
url = mod.get_liburl(self.request, "bb_vue_fontawesome")
self.assertEqual(url, "/lib/vue-fontawesome.js")
def test_bb_vue_fontawesome_fanstatic(self):
self.setup_fanstatic()
url = mod.get_liburl(self.request, 'bb_vue_fontawesome')
self.assertEqual(url, '/wutta/fanstatic/bb_vue_fontawesome.js')
url = mod.get_liburl(self.request, "bb_vue_fontawesome")
self.assertEqual(url, "/wutta/fanstatic/bb_vue_fontawesome.js")
class TestGetFormData(TestCase):
@ -447,25 +470,25 @@ class TestGetFormData(TestCase):
self.config = WuttaConfig()
def make_request(self, **kwargs):
kwargs.setdefault('wutta_config', self.config)
kwargs.setdefault('POST', {'foo1': 'bar'})
kwargs.setdefault('json_body', {'foo2': 'baz'})
kwargs.setdefault("wutta_config", self.config)
kwargs.setdefault("POST", {"foo1": "bar"})
kwargs.setdefault("json_body", {"foo2": "baz"})
return testing.DummyRequest(**kwargs)
def test_default(self):
request = self.make_request()
data = mod.get_form_data(request)
self.assertEqual(data, {'foo1': 'bar'})
self.assertEqual(data, {"foo1": "bar"})
def test_is_xhr(self):
request = self.make_request(POST=None, is_xhr=True)
data = mod.get_form_data(request)
self.assertEqual(data, {'foo2': 'baz'})
self.assertEqual(data, {"foo2": "baz"})
def test_content_type(self):
request = self.make_request(POST=None, content_type='application/json')
request = self.make_request(POST=None, content_type="application/json")
data = mod.get_form_data(request)
self.assertEqual(data, {'foo2': 'baz'})
self.assertEqual(data, {"foo2": "baz"})
class TestGetModelFields(ConfigTestCase):
@ -481,41 +504,47 @@ class TestGetModelFields(ConfigTestCase):
def test_basic(self):
model = self.app.model
fields = mod.get_model_fields(self.config, model.Setting)
self.assertEqual(fields, ['name', 'value'])
self.assertEqual(fields, ["name", "value"])
def test_include_fk(self):
model = self.app.model
# fk excluded by default
fields = mod.get_model_fields(self.config, model.User)
self.assertNotIn('person_uuid', fields)
self.assertIn('person', fields)
self.assertNotIn("person_uuid", fields)
self.assertIn("person", fields)
# fk can be included
fields = mod.get_model_fields(self.config, model.User, include_fk=True)
self.assertIn('person_uuid', fields)
self.assertIn('person', fields)
self.assertIn("person_uuid", fields)
self.assertIn("person", fields)
def test_avoid_versions(self):
model = self.app.model
mapper = MagicMock(iterate_properties = [
MagicMock(key='uuid'),
MagicMock(key='full_name'),
MagicMock(key='first_name'),
MagicMock(key='middle_name'),
MagicMock(key='last_name'),
MagicMock(key='versions'),
])
mapper = MagicMock(
iterate_properties=[
MagicMock(key="uuid"),
MagicMock(key="full_name"),
MagicMock(key="first_name"),
MagicMock(key="middle_name"),
MagicMock(key="last_name"),
MagicMock(key="versions"),
]
)
with patch.object(mod, 'sa') as sa:
with patch.object(mod, "sa") as sa:
sa.inspect.return_value = mapper
with patch.object(self.app, 'continuum_is_enabled', return_value=True):
with patch.object(self.app, "continuum_is_enabled", return_value=True):
fields = mod.get_model_fields(self.config, model.Person)
# nb. no versions field
self.assertEqual(set(fields), set(['uuid', 'full_name', 'first_name',
'middle_name', 'last_name']))
self.assertEqual(
set(fields),
set(
["uuid", "full_name", "first_name", "middle_name", "last_name"]
),
)
class TestGetCsrfToken(TestCase):
@ -541,7 +570,7 @@ class TestGetCsrfToken(TestCase):
# nb. dummy request always returns same token, so must
# trick it into thinking it doesn't have one yet
with patch.object(self.request.session, 'get_csrf_token', return_value=None):
with patch.object(self.request.session, "get_csrf_token", return_value=None):
token = mod.get_csrf_token(self.request)
self.assertIsNotNone(token)
@ -577,7 +606,7 @@ class TestMakeJsonSafe(TestCase):
model = self.app.model
person = model.Person(full_name="Betty Boop")
self.assertRaises(TypeError, json.dumps, person)
value = mod.make_json_safe(person, key='person')
value = mod.make_json_safe(person, key="person")
self.assertEqual(value, "Betty Boop")
def test_uuid(self):
@ -586,7 +615,7 @@ class TestMakeJsonSafe(TestCase):
self.assertEqual(value, uuid.hex)
def test_decimal(self):
value = decimal.Decimal('42.42')
value = decimal.Decimal("42.42")
self.assertNotEqual(value, 42.42)
result = mod.make_json_safe(value)
self.assertEqual(result, 42.42)
@ -596,34 +625,40 @@ class TestMakeJsonSafe(TestCase):
person = model.Person(full_name="Betty Boop")
data = {
'foo': 'bar',
'person': person,
"foo": "bar",
"person": person,
}
self.assertRaises(TypeError, json.dumps, data)
value = mod.make_json_safe(data)
self.assertEqual(value, {
'foo': 'bar',
'person': "Betty Boop",
})
self.assertEqual(
value,
{
"foo": "bar",
"person": "Betty Boop",
},
)
def test_list(self):
model = self.app.model
person = model.Person(full_name="Betty Boop")
data = [
'foo',
'bar',
"foo",
"bar",
person,
]
self.assertRaises(TypeError, json.dumps, data)
value = mod.make_json_safe(data)
self.assertEqual(value, [
'foo',
'bar',
"Betty Boop",
])
self.assertEqual(
value,
[
"foo",
"bar",
"Betty Boop",
],
)
class TestGetAvailableThemes(TestCase):
@ -634,63 +669,65 @@ class TestGetAvailableThemes(TestCase):
def test_defaults(self):
themes = mod.get_available_themes(self.config)
self.assertEqual(themes, ['default', 'butterfly'])
self.assertEqual(themes, ["default", "butterfly"])
def test_sorting(self):
self.config.setdefault('wuttaweb.themes.keys', 'default, foo2, foo4, foo1')
self.config.setdefault("wuttaweb.themes.keys", "default, foo2, foo4, foo1")
themes = mod.get_available_themes(self.config)
self.assertEqual(themes, ['default', 'foo1', 'foo2', 'foo4'])
self.assertEqual(themes, ["default", "foo1", "foo2", "foo4"])
def test_default_omitted(self):
self.config.setdefault('wuttaweb.themes.keys', 'butterfly, foo')
self.config.setdefault("wuttaweb.themes.keys", "butterfly, foo")
themes = mod.get_available_themes(self.config)
self.assertEqual(themes, ['default', 'butterfly', 'foo'])
self.assertEqual(themes, ["default", "butterfly", "foo"])
def test_default_notfirst(self):
self.config.setdefault('wuttaweb.themes.keys', 'butterfly, foo, default')
self.config.setdefault("wuttaweb.themes.keys", "butterfly, foo, default")
themes = mod.get_available_themes(self.config)
self.assertEqual(themes, ['default', 'butterfly', 'foo'])
self.assertEqual(themes, ["default", "butterfly", "foo"])
class TestGetEffectiveTheme(DataTestCase):
def test_default(self):
theme = mod.get_effective_theme(self.config)
self.assertEqual(theme, 'default')
self.assertEqual(theme, "default")
def test_override_config(self):
self.app.save_setting(self.session, 'wuttaweb.theme', 'butterfly')
self.app.save_setting(self.session, "wuttaweb.theme", "butterfly")
self.session.commit()
theme = mod.get_effective_theme(self.config)
self.assertEqual(theme, 'butterfly')
self.assertEqual(theme, "butterfly")
def test_override_param(self):
theme = mod.get_effective_theme(self.config, theme='butterfly')
self.assertEqual(theme, 'butterfly')
theme = mod.get_effective_theme(self.config, theme="butterfly")
self.assertEqual(theme, "butterfly")
def test_invalid(self):
self.assertRaises(ValueError, mod.get_effective_theme, self.config, theme='invalid')
self.assertRaises(
ValueError, mod.get_effective_theme, self.config, theme="invalid"
)
class TestThemeTemplatePath(DataTestCase):
def test_default(self):
path = mod.get_theme_template_path(self.config, theme='default')
path = mod.get_theme_template_path(self.config, theme="default")
# nb. even though the path does not exist, we still want to
# pretend like it does, hence prev call should return this:
expected = resource_path('wuttaweb:templates/themes/default')
expected = resource_path("wuttaweb:templates/themes/default")
self.assertEqual(path, expected)
def test_default(self):
path = mod.get_theme_template_path(self.config, theme='butterfly')
expected = resource_path('wuttaweb:templates/themes/butterfly')
path = mod.get_theme_template_path(self.config, theme="butterfly")
expected = resource_path("wuttaweb:templates/themes/butterfly")
self.assertEqual(path, expected)
def test_custom(self):
self.config.setdefault('wuttaweb.themes.keys', 'default, butterfly, poser')
self.config.setdefault('wuttaweb.theme.poser', '/tmp/poser-theme')
path = mod.get_theme_template_path(self.config, theme='poser')
self.assertEqual(path, '/tmp/poser-theme')
self.config.setdefault("wuttaweb.themes.keys", "default, butterfly, poser")
self.config.setdefault("wuttaweb.theme.poser", "/tmp/poser-theme")
path = mod.get_theme_template_path(self.config, theme="poser")
self.assertEqual(path, "/tmp/poser-theme")
class TestSetAppTheme(WebTestCase):
@ -699,14 +736,14 @@ class TestSetAppTheme(WebTestCase):
# establish default
settings = self.request.registry.settings
self.assertNotIn('wuttaweb.theme', settings)
self.assertNotIn("wuttaweb.theme", settings)
establish_theme(settings)
self.assertEqual(settings['wuttaweb.theme'], 'default')
self.assertEqual(settings["wuttaweb.theme"], "default")
# set to butterfly
mod.set_app_theme(self.request, 'butterfly', session=self.session)
self.assertEqual(settings['wuttaweb.theme'], 'butterfly')
mod.set_app_theme(self.request, "butterfly", session=self.session)
self.assertEqual(settings["wuttaweb.theme"], "butterfly")
# set back to default
mod.set_app_theme(self.request, 'default', session=self.session)
self.assertEqual(settings['wuttaweb.theme'], 'default')
mod.set_app_theme(self.request, "default", session=self.session)
self.assertEqual(settings["wuttaweb.theme"], "default")

View file

@ -15,9 +15,11 @@ class DataTestCase(FileConfigTestCase):
def setup_db(self):
self.setup_files()
self.config = WuttaConfig(defaults={
'wutta.db.default.url': 'sqlite://',
})
self.config = WuttaConfig(
defaults={
"wutta.db.default.url": "sqlite://",
}
)
self.app = self.config.get_app()
# init db
@ -36,5 +38,6 @@ class NullMenuHandler(MenuHandler):
"""
Dummy menu handler for testing.
"""
def make_menus(self, request, **kwargs):
return []

View file

@ -7,4 +7,4 @@ class TestIncludeMe(WebTestCase):
def test_basic(self):
# just ensure no error happens when included..
self.pyramid_config.include('wuttaweb.views')
self.pyramid_config.include("wuttaweb.views")

View file

@ -12,13 +12,13 @@ class TestAuthView(WebTestCase):
def setUp(self):
self.setup_web()
self.pyramid_config.include('wuttaweb.views.common')
self.pyramid_config.include("wuttaweb.views.common")
def make_view(self):
return mod.AuthView(self.request)
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.auth')
self.pyramid_config.include("wuttaweb.views.auth")
def test_login(self):
model = self.app.model
@ -31,37 +31,37 @@ class TestAuthView(WebTestCase):
self.assertEqual(response.status_code, 302)
# make a user
barney = model.User(username='barney')
auth.set_user_password(barney, 'testpass')
barney = model.User(username="barney")
auth.set_user_password(barney, "testpass")
self.session.add(barney)
self.session.commit()
# now since user exists, form will display
context = view.login(session=self.session)
self.assertIn('form', context)
self.assertIn("form", context)
# redirect if user already logged in
with patch.object(self.request, 'user', new=barney):
with patch.object(self.request, "user", new=barney):
view = self.make_view()
response = view.login(session=self.session)
self.assertEqual(response.status_code, 302)
# login fails w/ wrong password
self.request.method = 'POST'
self.request.POST = {'username': 'barney', 'password': 'WRONG'}
self.request.method = "POST"
self.request.POST = {"username": "barney", "password": "WRONG"}
view = self.make_view()
context = view.login(session=self.session)
self.assertIn('form', context)
self.assertIn("form", context)
# redirect if login succeeds
self.request.method = 'POST'
self.request.POST = {'username': 'barney', 'password': 'testpass'}
self.request.method = "POST"
self.request.POST = {"username": "barney", "password": "testpass"}
view = self.make_view()
response = view.login(session=self.session)
self.assertEqual(response.status_code, 302)
def test_logout(self):
self.pyramid_config.add_route('login', '/login')
self.pyramid_config.add_route("login", "/login")
view = self.make_view()
self.request.session.delete = MagicMock()
response = view.logout()
@ -71,7 +71,7 @@ class TestAuthView(WebTestCase):
def test_change_password(self):
model = self.app.model
auth = self.app.get_auth_handler()
barney = model.User(username='barney')
barney = model.User(username="barney")
self.session.add(barney)
self.session.commit()
view = self.make_view()
@ -81,7 +81,7 @@ class TestAuthView(WebTestCase):
self.assertIsInstance(redirect, HTTPFound)
# set initial password
auth.set_user_password(barney, 'foo')
auth.set_user_password(barney, "foo")
self.session.commit()
# forbidden if prevent_edit is set for user
@ -94,24 +94,24 @@ class TestAuthView(WebTestCase):
# view should now return context w/ form
context = view.change_password()
self.assertIn('form', context)
self.assertIn("form", context)
# submit valid form, ensure password is changed
# (nb. this also would redirect user to home page)
self.request.method = 'POST'
self.request.method = "POST"
self.request.POST = {
'current_password': 'foo',
"current_password": "foo",
# nb. new_password requires colander mapping structure
'__start__': 'new_password:mapping',
'new_password': 'bar',
'new_password-confirm': 'bar',
'__end__': 'new_password:mapping',
"__start__": "new_password:mapping",
"new_password": "bar",
"new_password-confirm": "bar",
"__end__": "new_password:mapping",
}
redirect = view.change_password()
self.assertIsInstance(redirect, HTTPFound)
self.session.commit()
self.assertFalse(auth.check_user_password(barney, 'foo'))
self.assertTrue(auth.check_user_password(barney, 'bar'))
self.assertFalse(auth.check_user_password(barney, "foo"))
self.assertTrue(auth.check_user_password(barney, "bar"))
# at this point 'foo' is the password, now let's submit some
# invalid forms and make sure we get back a context w/ form
@ -119,72 +119,77 @@ class TestAuthView(WebTestCase):
# first try empty data
self.request.POST = {}
context = view.change_password()
self.assertIn('form', context)
dform = context['form'].get_deform()
self.assertEqual(dform['current_password'].errormsg, "Required")
self.assertEqual(dform['new_password'].errormsg, "Required")
self.assertIn("form", context)
dform = context["form"].get_deform()
self.assertEqual(dform["current_password"].errormsg, "Required")
self.assertEqual(dform["new_password"].errormsg, "Required")
# now try bad current password
self.request.POST = {
'current_password': 'blahblah',
'__start__': 'new_password:mapping',
'new_password': 'baz',
'new_password-confirm': 'baz',
'__end__': 'new_password:mapping',
"current_password": "blahblah",
"__start__": "new_password:mapping",
"new_password": "baz",
"new_password-confirm": "baz",
"__end__": "new_password:mapping",
}
context = view.change_password()
self.assertIn('form', context)
dform = context['form'].get_deform()
self.assertEqual(dform['current_password'].errormsg, "Current password is incorrect.")
self.assertIn("form", context)
dform = context["form"].get_deform()
self.assertEqual(
dform["current_password"].errormsg, "Current password is incorrect."
)
# now try bad new password
self.request.POST = {
'current_password': 'bar',
'__start__': 'new_password:mapping',
'new_password': 'bar',
'new_password-confirm': 'bar',
'__end__': 'new_password:mapping',
"current_password": "bar",
"__start__": "new_password:mapping",
"new_password": "bar",
"new_password-confirm": "bar",
"__end__": "new_password:mapping",
}
context = view.change_password()
self.assertIn('form', context)
dform = context['form'].get_deform()
self.assertEqual(dform['new_password'].errormsg, "New password must be different from old password.")
self.assertIn("form", context)
dform = context["form"].get_deform()
self.assertEqual(
dform["new_password"].errormsg,
"New password must be different from old password.",
)
def test_become_root(self):
view = mod.AuthView(self.request)
# GET not allowed
self.request.method = 'GET'
self.request.method = "GET"
self.assertRaises(HTTPForbidden, view.become_root)
# non-admin users also not allowed
self.request.method = 'POST'
self.request.method = "POST"
self.request.is_admin = False
self.assertRaises(HTTPForbidden, view.become_root)
# but admin users can become root
self.request.is_admin = True
self.assertNotIn('is_root', self.request.session)
self.assertNotIn("is_root", self.request.session)
redirect = view.become_root()
self.assertIsInstance(redirect, HTTPFound)
self.assertTrue(self.request.session['is_root'])
self.assertTrue(self.request.session["is_root"])
def test_stop_root(self):
view = mod.AuthView(self.request)
# GET not allowed
self.request.method = 'GET'
self.request.method = "GET"
self.assertRaises(HTTPForbidden, view.stop_root)
# non-admin users also not allowed
self.request.method = 'POST'
self.request.method = "POST"
self.request.is_admin = False
self.assertRaises(HTTPForbidden, view.stop_root)
# but admin users can stop being root
# (nb. there is no check whether user is currently root)
self.request.is_admin = True
self.assertNotIn('is_root', self.request.session)
self.assertNotIn("is_root", self.request.session)
redirect = view.stop_root()
self.assertIsInstance(redirect, HTTPFound)
self.assertFalse(self.request.session['is_root'])
self.assertFalse(self.request.session["is_root"])

View file

@ -36,7 +36,7 @@ class TestView(WebTestCase):
def test_make_grid_action(self):
view = self.make_view()
action = view.make_grid_action('view')
action = view.make_grid_action("view")
self.assertIsInstance(action, GridAction)
def test_notfound(self):
@ -46,31 +46,31 @@ class TestView(WebTestCase):
def test_redirect(self):
view = self.make_view()
error = view.redirect('/')
error = view.redirect("/")
self.assertIsInstance(error, HTTPFound)
self.assertEqual(error.location, '/')
self.assertEqual(error.location, "/")
def test_file_response(self):
view = self.make_view()
# default uses attachment behavior
datfile = self.write_file('dat.txt', 'hello')
datfile = self.write_file("dat.txt", "hello")
response = view.file_response(datfile)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_disposition, 'attachment; filename="dat.txt"')
# but can disable attachment behavior
datfile = self.write_file('dat.txt', 'hello')
datfile = self.write_file("dat.txt", "hello")
response = view.file_response(datfile, attachment=False)
self.assertEqual(response.status_code, 200)
self.assertIsNone(response.content_disposition)
# path not found
crapfile = '/does/not/exist'
crapfile = "/does/not/exist"
response = view.file_response(crapfile)
self.assertEqual(response.status_code, 404)
def test_json_response(self):
view = self.make_view()
response = view.json_response({'foo': 'bar'})
response = view.json_response({"foo": "bar"})
self.assertEqual(response.status_code, 200)

View file

@ -14,14 +14,17 @@ from wuttaweb.testing import WebTestCase
class MockBatch(model.BatchMixin, model.Base):
__tablename__ = 'testing_batch_mock'
__tablename__ = "testing_batch_mock"
class MockBatchRow(model.BatchRowMixin, model.Base):
__tablename__ = 'testing_batch_mock_row'
__tablename__ = "testing_batch_mock_row"
__batch_class__ = MockBatch
MockBatch.__row_class__ = MockBatchRow
class MockBatchHandler(BatchHandler):
model_class = MockBatch
@ -43,43 +46,52 @@ class TestBatchMasterView(WebTestCase):
def test_get_batch_handler(self):
self.assertRaises(NotImplementedError, mod.BatchMasterView, self.request)
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=42):
with patch.object(mod.BatchMasterView, "get_batch_handler", return_value=42):
view = mod.BatchMasterView(self.request)
self.assertEqual(view.batch_handler, 42)
def test_get_fallback_templates(self):
handler = MockBatchHandler(self.config)
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
view = self.make_view()
templates = view.get_fallback_templates('view')
self.assertEqual(templates, [
'/batch/view.mako',
'/master/view.mako',
])
templates = view.get_fallback_templates("view")
self.assertEqual(
templates,
[
"/batch/view.mako",
"/master/view.mako",
],
)
def test_render_to_response(self):
model = self.app.model
handler = MockBatchHandler(self.config)
user = model.User(username='barney')
user = model.User(username="barney")
self.session.add(user)
batch = handler.make_batch(self.session, created_by=user)
self.session.add(batch)
self.session.flush()
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.object(MasterView, 'render_to_response') as render_to_response:
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
with patch.object(MasterView, "render_to_response") as render_to_response:
view = self.make_view()
response = view.render_to_response('view', {'instance': batch})
response = view.render_to_response("view", {"instance": batch})
self.assertTrue(render_to_response.called)
context = render_to_response.call_args[0][1]
self.assertIs(context['batch'], batch)
self.assertIs(context['batch_handler'], handler)
self.assertIs(context["batch"], batch)
self.assertIs(context["batch_handler"], handler)
def test_configure_grid(self):
handler = MockBatchHandler(self.config)
with patch.multiple(mod.BatchMasterView, create=True, model_class=MockBatch):
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
view = mod.BatchMasterView(self.request)
grid = view.make_model_grid()
# nb. coverage only; tests nothing
@ -87,19 +99,23 @@ class TestBatchMasterView(WebTestCase):
def test_render_batch_id(self):
handler = MockBatchHandler(self.config)
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
view = mod.BatchMasterView(self.request)
batch = MockBatch(id=42)
result = view.render_batch_id(batch, 'id', 42)
self.assertEqual(result, '00000042')
result = view.render_batch_id(batch, "id", 42)
self.assertEqual(result, "00000042")
result = view.render_batch_id(batch, 'id', None)
result = view.render_batch_id(batch, "id", None)
self.assertIsNone(result)
def test_get_instance_title(self):
handler = MockBatchHandler(self.config)
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
view = mod.BatchMasterView(self.request)
batch = MockBatch(id=42)
@ -113,46 +129,52 @@ class TestBatchMasterView(WebTestCase):
def test_configure_form(self):
handler = MockBatchHandler(self.config)
with patch.multiple(mod.BatchMasterView, create=True, model_class=MockBatch):
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
view = mod.BatchMasterView(self.request)
# creating
with patch.object(view, 'creating', new=True):
with patch.object(view, "creating", new=True):
form = view.make_model_form(model_instance=None)
view.configure_form(form)
batch = MockBatch(id=42)
# viewing
with patch.object(view, 'viewing', new=True):
with patch.object(view, "viewing", new=True):
form = view.make_model_form(model_instance=batch)
view.configure_form(form)
# editing
with patch.object(view, 'editing', new=True):
with patch.object(view, "editing", new=True):
form = view.make_model_form(model_instance=batch)
view.configure_form(form)
# deleting
with patch.object(view, 'deleting', new=True):
with patch.object(view, "deleting", new=True):
form = view.make_model_form(model_instance=batch)
view.configure_form(form)
# viewing (executed)
batch.executed = datetime.datetime.now()
with patch.object(view, 'viewing', new=True):
with patch.object(view, "viewing", new=True):
form = view.make_model_form(model_instance=batch)
view.configure_form(form)
def test_objectify(self):
handler = MockBatchHandler(self.config)
with patch.multiple(mod.BatchMasterView, create=True, model_class=MockBatch):
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.object(mod.BatchMasterView, 'Session', return_value=self.session):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
with patch.object(
mod.BatchMasterView, "Session", return_value=self.session
):
view = mod.BatchMasterView(self.request)
# create batch
with patch.object(view, 'creating', new=True):
with patch.object(view, "creating", new=True):
form = view.make_model_form(model_instance=None)
form.validated = {}
batch = view.objectify(form)
@ -160,21 +182,28 @@ class TestBatchMasterView(WebTestCase):
self.assertTrue(batch.id > 0)
# edit batch
with patch.object(view, 'editing', new=True):
with patch.object(view.batch_handler, 'make_batch') as make_batch:
with patch.object(view, "editing", new=True):
with patch.object(
view.batch_handler, "make_batch"
) as make_batch:
form = view.make_model_form(model_instance=batch)
form.validated = {'description': 'foo'}
form.validated = {"description": "foo"}
self.assertIsNone(batch.description)
batch = view.objectify(form)
self.assertEqual(batch.description, 'foo')
self.assertEqual(batch.description, "foo")
def test_redirect_after_create(self):
self.pyramid_config.add_route('mock_batches.view', '/batch/mock/{uuid}')
self.pyramid_config.add_route("mock_batches.view", "/batch/mock/{uuid}")
handler = MockBatchHandler(self.config)
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.multiple(mod.BatchMasterView, create=True,
model_class=MockBatch,
route_prefix='mock_batches'):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
with patch.multiple(
mod.BatchMasterView,
create=True,
model_class=MockBatch,
route_prefix="mock_batches",
):
view = mod.BatchMasterView(self.request)
batch = MockBatch(id=42)
@ -183,12 +212,14 @@ class TestBatchMasterView(WebTestCase):
self.assertIsInstance(result, HTTPFound)
# unless populating in which case thread is launched
self.request.session.id = 'abcdefghijk'
with patch.object(mod, 'threading') as threading:
self.request.session.id = "abcdefghijk"
with patch.object(mod, "threading") as threading:
thread = MagicMock()
threading.Thread.return_value = thread
with patch.object(view.batch_handler, 'should_populate', return_value=True):
with patch.object(view, 'render_progress') as render_progress:
with patch.object(
view.batch_handler, "should_populate", return_value=True
):
with patch.object(view, "render_progress") as render_progress:
view.redirect_after_create(batch)
self.assertTrue(threading.Thread.called)
thread.start.assert_called_once_with()
@ -198,14 +229,16 @@ class TestBatchMasterView(WebTestCase):
model = self.app.model
handler = self.make_handler()
user = model.User(username='barney')
user = model.User(username="barney")
self.session.add(user)
batch = handler.make_batch(self.session, created_by=user)
self.session.add(batch)
self.session.flush()
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
view = self.make_view()
self.assertEqual(self.session.query(MockBatch).count(), 1)
@ -215,20 +248,24 @@ class TestBatchMasterView(WebTestCase):
def test_populate_thread(self):
model = self.app.model
handler = MockBatchHandler(self.config)
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.multiple(mod.BatchMasterView, create=True, model_class=MockBatch):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
with patch.multiple(
mod.BatchMasterView, create=True, model_class=MockBatch
):
view = mod.BatchMasterView(self.request)
user = model.User(username='barney')
user = model.User(username="barney")
self.session.add(user)
batch = MockBatch(id=42, created_by=user)
self.session.add(batch)
self.session.commit()
# nb. use our session within thread method
with patch.object(self.app, 'make_session', return_value=self.session):
with patch.object(self.app, "make_session", return_value=self.session):
# nb. prevent closing our session
with patch.object(self.session, 'close') as close:
with patch.object(self.session, "close") as close:
# without progress
view.populate_thread(batch.uuid)
@ -236,24 +273,34 @@ class TestBatchMasterView(WebTestCase):
close.reset_mock()
# with progress
self.request.session.id = 'abcdefghijk'
view.populate_thread(batch.uuid,
progress=SessionProgress(self.request,
'populate_mock_batch'))
self.request.session.id = "abcdefghijk"
view.populate_thread(
batch.uuid,
progress=SessionProgress(
self.request, "populate_mock_batch"
),
)
close.assert_called_once_with()
close.reset_mock()
# failure to populate, without progress
with patch.object(view.batch_handler, 'do_populate', side_effect=RuntimeError):
with patch.object(
view.batch_handler, "do_populate", side_effect=RuntimeError
):
view.populate_thread(batch.uuid)
close.assert_called_once_with()
close.reset_mock()
# failure to populate, with progress
with patch.object(view.batch_handler, 'do_populate', side_effect=RuntimeError):
view.populate_thread(batch.uuid,
progress=SessionProgress(self.request,
'populate_mock_batch'))
with patch.object(
view.batch_handler, "do_populate", side_effect=RuntimeError
):
view.populate_thread(
batch.uuid,
progress=SessionProgress(
self.request, "populate_mock_batch"
),
)
close.assert_called_once_with()
close.reset_mock()
@ -261,53 +308,64 @@ class TestBatchMasterView(WebTestCase):
self.session.delete(batch)
self.session.commit()
# nb. should give up waiting after 1 second
self.assertRaises(RuntimeError, view.populate_thread, batch.uuid)
self.assertRaises(
RuntimeError, view.populate_thread, batch.uuid
)
def test_execute(self):
self.pyramid_config.add_route('mock_batches.view', '/batch/mock/{uuid}')
self.pyramid_config.add_route("mock_batches.view", "/batch/mock/{uuid}")
model = self.app.model
handler = MockBatchHandler(self.config)
user = model.User(username='barney')
user = model.User(username="barney")
self.session.add(user)
batch = handler.make_batch(self.session, created_by=user)
self.session.add(batch)
self.session.commit()
with patch.multiple(mod.BatchMasterView, create=True,
model_class=MockBatch,
route_prefix='mock_batches',
get_batch_handler=MagicMock(return_value=handler),
get_instance=MagicMock(return_value=batch)):
with patch.multiple(
mod.BatchMasterView,
create=True,
model_class=MockBatch,
route_prefix="mock_batches",
get_batch_handler=MagicMock(return_value=handler),
get_instance=MagicMock(return_value=batch),
):
view = self.make_view()
# batch executes okay
response = view.execute()
self.assertEqual(response.status_code, 302) # redirect to "view batch"
self.assertFalse(self.request.session.peek_flash('error'))
self.assertEqual(response.status_code, 302) # redirect to "view batch"
self.assertFalse(self.request.session.peek_flash("error"))
# but cannot be executed again
response = view.execute()
self.assertEqual(response.status_code, 302) # redirect to "view batch"
self.assertEqual(response.status_code, 302) # redirect to "view batch"
# nb. flash has error this time
self.assertTrue(self.request.session.peek_flash('error'))
self.assertTrue(self.request.session.peek_flash("error"))
def test_get_row_model_class(self):
handler = MockBatchHandler(self.config)
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
view = self.make_view()
self.assertRaises(AttributeError, view.get_row_model_class)
# row class determined from batch class
with patch.object(mod.BatchMasterView, 'model_class', new=MockBatch, create=True):
with patch.object(
mod.BatchMasterView, "model_class", new=MockBatch, create=True
):
cls = view.get_row_model_class()
self.assertIs(cls, MockBatchRow)
self.assertRaises(AttributeError, view.get_row_model_class)
# view may specify row class
with patch.object(mod.BatchMasterView, 'row_model_class', new=MockBatchRow, create=True):
with patch.object(
mod.BatchMasterView, "row_model_class", new=MockBatchRow, create=True
):
cls = view.get_row_model_class()
self.assertIs(cls, MockBatchRow)
@ -315,7 +373,7 @@ class TestBatchMasterView(WebTestCase):
handler = MockBatchHandler(self.config)
model = self.app.model
user = model.User(username='barney')
user = model.User(username="barney")
self.session.add(user)
batch = handler.make_batch(self.session, created_by=user)
@ -324,16 +382,18 @@ class TestBatchMasterView(WebTestCase):
handler.add_row(batch, row)
self.session.flush()
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
view = self.make_view()
self.assertRaises(AttributeError, view.get_row_grid_data, batch)
Session = MagicMock(return_value=self.session)
Session.query.side_effect = lambda m: self.session.query(m)
with patch.multiple(mod.BatchMasterView, create=True,
Session=Session,
model_class=MockBatch):
with patch.multiple(
mod.BatchMasterView, create=True, Session=Session, model_class=MockBatch
):
view = self.make_view()
data = view.get_row_grid_data(batch)
@ -344,7 +404,7 @@ class TestBatchMasterView(WebTestCase):
handler = MockBatchHandler(self.config)
model = self.app.model
user = model.User(username='barney')
user = model.User(username="barney")
self.session.add(user)
batch = handler.make_batch(self.session, created_by=user)
@ -353,27 +413,31 @@ class TestBatchMasterView(WebTestCase):
handler.add_row(batch, row)
self.session.flush()
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=handler):
with patch.object(
mod.BatchMasterView, "get_batch_handler", return_value=handler
):
Session = MagicMock(return_value=self.session)
Session.query.side_effect = lambda m: self.session.query(m)
with patch.multiple(mod.BatchMasterView, create=True,
Session=Session,
model_class=MockBatch):
with patch.multiple(
mod.BatchMasterView, create=True, Session=Session, model_class=MockBatch
):
with patch.object(self.request, 'matchdict', new={'uuid': batch.uuid}):
with patch.object(self.request, "matchdict", new={"uuid": batch.uuid}):
view = self.make_view()
grid = view.make_row_model_grid(batch)
self.assertIn('sequence', grid.labels)
self.assertEqual(grid.labels['sequence'], "Seq.")
self.assertIn("sequence", grid.labels)
self.assertEqual(grid.labels["sequence"], "Seq.")
def test_render_row_status(self):
with patch.object(mod.BatchMasterView, 'get_batch_handler', return_value=None):
with patch.object(mod.BatchMasterView, "get_batch_handler", return_value=None):
view = self.make_view()
row = MagicMock(foo=1, STATUS={1: 'bar'})
self.assertEqual(view.render_row_status(row, 'foo', 1), 'bar')
row = MagicMock(foo=1, STATUS={1: "bar"})
self.assertEqual(view.render_row_status(row, "foo", 1), "bar")
def test_defaults(self):
# nb. coverage only
with patch.object(mod.BatchMasterView, 'model_class', new=MockBatch, create=True):
with patch.object(
mod.BatchMasterView, "model_class", new=MockBatch, create=True
):
mod.BatchMasterView.defaults(self.pyramid_config)

View file

@ -15,21 +15,21 @@ class TestCommonView(WebTestCase):
return mod.CommonView(self.request)
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.common')
self.pyramid_config.include("wuttaweb.views.common")
def test_forbidden_view(self):
view = self.make_view()
context = view.forbidden_view()
self.assertEqual(context['index_title'], self.app.get_title())
self.assertEqual(context["index_title"], self.app.get_title())
def test_notfound_view(self):
view = self.make_view()
context = view.notfound_view()
self.assertEqual(context['index_title'], self.app.get_title())
self.assertEqual(context["index_title"], self.app.get_title())
def test_home(self):
self.pyramid_config.add_route('setup', '/setup')
self.pyramid_config.add_route('login', '/login')
self.pyramid_config.add_route("setup", "/setup")
self.pyramid_config.add_route("login", "/login")
model = self.app.model
view = self.make_view()
@ -38,50 +38,50 @@ class TestCommonView(WebTestCase):
self.assertEqual(response.status_code, 302)
# so add a user
user = model.User(username='foo')
user = model.User(username="foo")
self.session.add(user)
self.session.commit()
# now we see the home page
context = view.home(session=self.session)
self.assertEqual(context['index_title'], self.app.get_title())
self.assertEqual(context["index_title"], self.app.get_title())
# but if configured, anons will be redirected to login
self.config.setdefault('wuttaweb.home_redirect_to_login', 'true')
self.config.setdefault("wuttaweb.home_redirect_to_login", "true")
response = view.home(session=self.session)
self.assertEqual(response.status_code, 302)
# now only an auth'ed user can see home page
self.request.user = user
context = view.home(session=self.session)
self.assertEqual(context['index_title'], self.app.get_title())
self.assertEqual(context["index_title"], self.app.get_title())
def test_feedback_make_schema(self):
view = self.make_view()
schema = view.feedback_make_schema()
self.assertIsInstance(schema, colander.Schema)
self.assertIn('message', schema)
self.assertIn("message", schema)
def test_feedback(self):
self.pyramid_config.add_route('users.view', '/users/{uuid}')
self.pyramid_config.add_route("users.view", "/users/{uuid}")
model = self.app.model
user = model.User(username='barney')
user = model.User(username="barney")
self.session.add(user)
self.session.commit()
view = self.make_view()
with patch.object(view, 'feedback_send') as feedback_send:
with patch.object(view, "feedback_send") as feedback_send:
# basic send, no user
self.request.client_addr = '127.0.0.1'
self.request.method = 'POST'
self.request.client_addr = "127.0.0.1"
self.request.method = "POST"
self.request.POST = {
'referrer': '/foo',
'user_name': "Barney Rubble",
'message': "hello world",
"referrer": "/foo",
"user_name": "Barney Rubble",
"message": "hello world",
}
context = view.feedback()
self.assertEqual(context, {'ok': True})
self.assertEqual(context, {"ok": True})
feedback_send.assert_called_once()
# reset
@ -89,10 +89,10 @@ class TestCommonView(WebTestCase):
# basic send, with user
self.request.user = user
self.request.POST['user_uuid'] = str(user.uuid)
with patch.object(mod, 'Session', return_value=self.session):
self.request.POST["user_uuid"] = str(user.uuid)
with patch.object(mod, "Session", return_value=self.session):
context = view.feedback()
self.assertEqual(context, {'ok': True})
self.assertEqual(context, {"ok": True})
feedback_send.assert_called_once()
# reset
@ -100,37 +100,35 @@ class TestCommonView(WebTestCase):
feedback_send.reset_mock()
# invalid form data
self.request.POST = {'message': 'hello world'}
self.request.POST = {"message": "hello world"}
context = view.feedback()
self.assertEqual(list(context), ['error'])
self.assertIn('Required', context['error'])
self.assertEqual(list(context), ["error"])
self.assertIn("Required", context["error"])
feedback_send.assert_not_called()
# error on send
self.request.POST = {
'referrer': '/foo',
'user_name': "Barney Rubble",
'message': "hello world",
"referrer": "/foo",
"user_name": "Barney Rubble",
"message": "hello world",
}
feedback_send.side_effect = RuntimeError
context = view.feedback()
feedback_send.assert_called_once()
self.assertEqual(list(context), ['error'])
self.assertIn('RuntimeError', context['error'])
self.assertEqual(list(context), ["error"])
self.assertIn("RuntimeError", context["error"])
def test_feedback_send(self):
view = self.make_view()
with patch.object(self.app, 'send_email') as send_email:
view.feedback_send({'user_name': "Barney",
'message': "hello world"})
send_email.assert_called_once_with('feedback', {
'user_name': "Barney",
'message': "hello world"
})
with patch.object(self.app, "send_email") as send_email:
view.feedback_send({"user_name": "Barney", "message": "hello world"})
send_email.assert_called_once_with(
"feedback", {"user_name": "Barney", "message": "hello world"}
)
def test_setup(self):
self.pyramid_config.add_route('home', '/')
self.pyramid_config.add_route('login', '/login')
self.pyramid_config.add_route("home", "/")
self.pyramid_config.add_route("login", "/login")
model = self.app.model
auth = self.app.get_auth_handler()
view = self.make_view()
@ -138,10 +136,10 @@ class TestCommonView(WebTestCase):
# at first, can see the setup page
self.assertEqual(self.session.query(model.User).count(), 0)
context = view.setup(session=self.session)
self.assertEqual(context['index_title'], self.app.get_title())
self.assertEqual(context["index_title"], self.app.get_title())
# so add a user
user = model.User(username='foo')
user = model.User(username="foo")
self.session.add(user)
self.session.commit()
@ -155,25 +153,25 @@ class TestCommonView(WebTestCase):
# so we can see the setup page again
context = view.setup(session=self.session)
self.assertEqual(context['index_title'], self.app.get_title())
self.assertEqual(context["index_title"], self.app.get_title())
# and finally, post data to create admin user
self.request.method = 'POST'
self.request.method = "POST"
self.request.POST = {
'username': 'barney',
'__start__': 'password:mapping',
'password': 'testpass',
'password-confirm': 'testpass',
'__end__': 'password:mapping',
'first_name': "Barney",
'last_name': "Rubble",
"username": "barney",
"__start__": "password:mapping",
"password": "testpass",
"password-confirm": "testpass",
"__end__": "password:mapping",
"first_name": "Barney",
"last_name": "Rubble",
}
response = view.setup(session=self.session)
# nb. redirects on success
self.assertEqual(response.status_code, 302)
barney = self.session.query(model.User).one()
self.assertEqual(barney.username, 'barney')
self.assertTrue(auth.check_user_password(barney, 'testpass'))
self.assertEqual(barney.username, "barney")
self.assertTrue(auth.check_user_password(barney, "testpass"))
admin = auth.get_role_administrator(self.session)
self.assertIn(admin, barney.roles)
self.assertIsNotNone(barney.person)
@ -183,30 +181,30 @@ class TestCommonView(WebTestCase):
self.assertEqual(person.full_name, "Barney Rubble")
def test_change_theme(self):
self.pyramid_config.add_route('home', '/')
self.pyramid_config.add_route("home", "/")
settings = self.request.registry.settings
establish_theme(settings)
view = self.make_view()
# theme is not changed if not provided by caller
self.assertEqual(settings['wuttaweb.theme'], 'default')
with patch.object(mod, 'set_app_theme') as set_app_theme:
self.assertEqual(settings["wuttaweb.theme"], "default")
with patch.object(mod, "set_app_theme") as set_app_theme:
view.change_theme()
set_app_theme.assert_not_called()
self.assertEqual(settings['wuttaweb.theme'], 'default')
self.assertEqual(settings["wuttaweb.theme"], "default")
# but theme will change if provided
with patch.object(self.request, 'params', new={'theme': 'butterfly'}):
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(self.request, "params", new={"theme": "butterfly"}):
with patch.object(mod, "Session", return_value=self.session):
view.change_theme()
self.assertEqual(settings['wuttaweb.theme'], 'butterfly')
self.assertEqual(settings["wuttaweb.theme"], "butterfly")
# flash error if invalid theme is provided
self.assertFalse(self.request.session.peek_flash('error'))
with patch.object(self.request, 'params', new={'theme': 'anotherone'}):
with patch.object(mod, 'Session', return_value=self.session):
self.assertFalse(self.request.session.peek_flash("error"))
with patch.object(self.request, "params", new={"theme": "anotherone"}):
with patch.object(mod, "Session", return_value=self.session):
view.change_theme()
self.assertEqual(settings['wuttaweb.theme'], 'butterfly')
self.assertTrue(self.request.session.peek_flash('error'))
messages = self.request.session.pop_flash('error')
self.assertIn('Failed to set theme', messages[0])
self.assertEqual(settings["wuttaweb.theme"], "butterfly")
self.assertTrue(self.request.session.peek_flash("error"))
messages = self.request.session.pop_flash("error")
self.assertIn("Failed to set theme", messages[0])

View file

@ -18,194 +18,232 @@ class TestEmailSettingViews(WebTestCase):
return mod.EmailSettingView(self.request)
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.email')
self.pyramid_config.include("wuttaweb.views.email")
def test_get_grid_data(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
self.config.setdefault("wutta.email.default.sender", "test@example.com")
view = self.make_view()
data = view.get_grid_data()
self.assertIsInstance(data, list)
self.assertTrue(data) # 1+ items
self.assertTrue(data) # 1+ items
setting = data[0]
self.assertIn('key', setting)
self.assertIn('subject', setting)
self.assertIn('sender', setting)
self.assertIn('to', setting)
self.assertIn('cc', setting)
self.assertIn('notes', setting)
self.assertIn("key", setting)
self.assertIn("subject", setting)
self.assertIn("sender", setting)
self.assertIn("to", setting)
self.assertIn("cc", setting)
self.assertIn("notes", setting)
def test_configure_grid(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
self.config.setdefault("wutta.email.default.sender", "test@example.com")
view = self.make_view()
grid = view.make_model_grid()
self.assertIn('key', grid.searchable_columns)
self.assertIn('subject', grid.searchable_columns)
self.assertIn("key", grid.searchable_columns)
self.assertIn("subject", grid.searchable_columns)
def test_render_to_short(self):
view = self.make_view()
setting = EmailSetting(self.config)
# more than 2 recips
result = view.render_to_short(setting, 'to', [
'alice@example.com',
'bob@example.com',
'charlie@example.com',
'diana@example.com',
])
self.assertEqual(result, 'alice@example.com, bob@example.com, ...')
result = view.render_to_short(
setting,
"to",
[
"alice@example.com",
"bob@example.com",
"charlie@example.com",
"diana@example.com",
],
)
self.assertEqual(result, "alice@example.com, bob@example.com, ...")
# just 2 recips
result = view.render_to_short(setting, 'to', [
'alice@example.com',
'bob@example.com',
])
self.assertEqual(result, 'alice@example.com, bob@example.com')
result = view.render_to_short(
setting,
"to",
[
"alice@example.com",
"bob@example.com",
],
)
self.assertEqual(result, "alice@example.com, bob@example.com")
# just 1 recip
result = view.render_to_short(setting, 'to', ['alice@example.com'])
self.assertEqual(result, 'alice@example.com')
result = view.render_to_short(setting, "to", ["alice@example.com"])
self.assertEqual(result, "alice@example.com")
# no recips
result = view.render_to_short(setting, 'to', [])
result = view.render_to_short(setting, "to", [])
self.assertIsNone(result)
def test_get_instance(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
self.config.setdefault("wutta.email.default.sender", "test@example.com")
view = self.make_view()
# normal
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
with patch.object(self.request, "matchdict", new={"key": "feedback"}):
setting = view.get_instance()
self.assertIsInstance(setting, dict)
self.assertIn('key', setting)
self.assertIn('sender', setting)
self.assertIn('subject', setting)
self.assertIn('to', setting)
self.assertIn('cc', setting)
self.assertIn('notes', setting)
self.assertIn('enabled', setting)
self.assertIn("key", setting)
self.assertIn("sender", setting)
self.assertIn("subject", setting)
self.assertIn("to", setting)
self.assertIn("cc", setting)
self.assertIn("notes", setting)
self.assertIn("enabled", setting)
# not found
with patch.object(self.request, 'matchdict', new={'key': 'this-should_notEXIST'}):
with patch.object(
self.request, "matchdict", new={"key": "this-should_notEXIST"}
):
self.assertRaises(HTTPNotFound, view.get_instance)
def test_get_instance_title(self):
view = self.make_view()
result = view.get_instance_title({'subject': 'whatever'})
self.assertEqual(result, 'whatever')
result = view.get_instance_title({"subject": "whatever"})
self.assertEqual(result, "whatever")
def test_configure_form(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
self.config.setdefault("wutta.email.default.sender", "test@example.com")
view = self.make_view()
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
with patch.object(self.request, "matchdict", new={"key": "feedback"}):
setting = view.get_instance()
form = view.make_model_form(setting)
self.assertIn('description', form.readonly_fields)
self.assertFalse(form.required_fields['replyto'])
self.assertIn("description", form.readonly_fields)
self.assertFalse(form.required_fields["replyto"])
def test_persist(self):
model = self.app.model
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
self.config.setdefault("wutta.email.default.sender", "test@example.com")
view = self.make_view()
# start w/ no settings in db
self.assertEqual(self.session.query(model.Setting).count(), 0)
# "edit" settings for feedback email
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
with patch.object(self.request, "matchdict", new={"key": "feedback"}):
setting = view.get_instance()
setting['subject'] = 'Testing Feedback'
setting['sender'] = 'feedback@example.com'
setting['replyto'] = 'feedback4@example.com'
setting['to'] = 'feedback@example.com'
setting['cc'] = 'feedback2@example.com'
setting['bcc'] = 'feedback3@example.com'
setting['notes'] = "did this work?"
setting['enabled'] = True
setting["subject"] = "Testing Feedback"
setting["sender"] = "feedback@example.com"
setting["replyto"] = "feedback4@example.com"
setting["to"] = "feedback@example.com"
setting["cc"] = "feedback2@example.com"
setting["bcc"] = "feedback3@example.com"
setting["notes"] = "did this work?"
setting["enabled"] = True
# persist email settings
with patch.object(view, 'Session', return_value=self.session):
with patch.object(view, "Session", return_value=self.session):
view.persist(setting)
self.session.commit()
# check settings in db
self.assertEqual(self.session.query(model.Setting).count(), 8)
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.subject'),
"Testing Feedback")
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.sender'),
'feedback@example.com')
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.replyto'),
'feedback4@example.com')
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.to'),
'feedback@example.com')
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.cc'),
'feedback2@example.com')
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.bcc'),
'feedback3@example.com')
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.notes'),
"did this work?")
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.enabled'),
'true')
self.assertEqual(
self.app.get_setting(self.session, "wutta.email.feedback.subject"),
"Testing Feedback",
)
self.assertEqual(
self.app.get_setting(self.session, "wutta.email.feedback.sender"),
"feedback@example.com",
)
self.assertEqual(
self.app.get_setting(self.session, "wutta.email.feedback.replyto"),
"feedback4@example.com",
)
self.assertEqual(
self.app.get_setting(self.session, "wutta.email.feedback.to"),
"feedback@example.com",
)
self.assertEqual(
self.app.get_setting(self.session, "wutta.email.feedback.cc"),
"feedback2@example.com",
)
self.assertEqual(
self.app.get_setting(self.session, "wutta.email.feedback.bcc"),
"feedback3@example.com",
)
self.assertEqual(
self.app.get_setting(self.session, "wutta.email.feedback.notes"),
"did this work?",
)
self.assertEqual(
self.app.get_setting(self.session, "wutta.email.feedback.enabled"), "true"
)
# "edit" settings for feedback email
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
with patch.object(self.request, "matchdict", new={"key": "feedback"}):
setting = view.get_instance()
setting['subject'] = None
setting['sender'] = None
setting['replyto'] = None
setting['to'] = None
setting['cc'] = None
setting['bcc'] = None
setting['notes'] = None
setting['enabled'] = False
setting["subject"] = None
setting["sender"] = None
setting["replyto"] = None
setting["to"] = None
setting["cc"] = None
setting["bcc"] = None
setting["notes"] = None
setting["enabled"] = False
# persist email settings
with patch.object(view, 'Session', return_value=self.session):
with patch.object(view, "Session", return_value=self.session):
view.persist(setting)
self.session.commit()
# check settings in db
self.assertEqual(self.session.query(model.Setting).count(), 1)
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.subject'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.sender'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.replyto'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.to'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.cc'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.bcc'))
self.assertIsNone(self.app.get_setting(self.session, 'wutta.email.feedback.notes'))
self.assertEqual(self.app.get_setting(self.session, 'wutta.email.feedback.enabled'),
'false')
self.assertIsNone(
self.app.get_setting(self.session, "wutta.email.feedback.subject")
)
self.assertIsNone(
self.app.get_setting(self.session, "wutta.email.feedback.sender")
)
self.assertIsNone(
self.app.get_setting(self.session, "wutta.email.feedback.replyto")
)
self.assertIsNone(self.app.get_setting(self.session, "wutta.email.feedback.to"))
self.assertIsNone(self.app.get_setting(self.session, "wutta.email.feedback.cc"))
self.assertIsNone(
self.app.get_setting(self.session, "wutta.email.feedback.bcc")
)
self.assertIsNone(
self.app.get_setting(self.session, "wutta.email.feedback.notes")
)
self.assertEqual(
self.app.get_setting(self.session, "wutta.email.feedback.enabled"), "false"
)
def test_render_to_response(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
self.pyramid_config.add_route('home', '/')
self.pyramid_config.add_route('login', '/auth/login')
self.pyramid_config.add_route('email_settings', '/email/settings')
self.pyramid_config.add_route('email_settings.preview', '/email/settings/{key}/preview')
self.config.setdefault("wutta.email.default.sender", "test@example.com")
self.pyramid_config.add_route("home", "/")
self.pyramid_config.add_route("login", "/auth/login")
self.pyramid_config.add_route("email_settings", "/email/settings")
self.pyramid_config.add_route(
"email_settings.preview", "/email/settings/{key}/preview"
)
view = self.make_view()
# nb. this gives coverage, but tests nothing..
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
with patch.object(self.request, "matchdict", new={"key": "feedback"}):
setting = view.get_instance()
with patch.object(view, 'viewing', new=True):
context = {'instance': setting}
response = view.render_to_response('view', context)
with patch.object(view, "viewing", new=True):
context = {"instance": setting}
response = view.render_to_response("view", context)
self.assertIsInstance(response, Response)
def test_preview(self):
self.config.setdefault('wutta.email.default.sender', 'test@example.com')
self.config.setdefault("wutta.email.default.sender", "test@example.com")
view = self.make_view()
# nb. this gives coverage, but tests nothing..
with patch.object(self.request, 'matchdict', new={'key': 'feedback'}):
with patch.object(self.request, "matchdict", new={"key": "feedback"}):
# html
with patch.object(self.request, 'params', new={'mode': 'html'}):
with patch.object(self.request, "params", new={"mode": "html"}):
response = view.preview()
self.assertEqual(response.content_type, 'text/html')
self.assertEqual(response.content_type, "text/html")
# txt
with patch.object(self.request, 'params', new={'mode': 'txt'}):
with patch.object(self.request, "params", new={"mode": "txt"}):
response = view.preview()
self.assertEqual(response.content_type, 'text/plain')
self.assertEqual(response.content_type, "text/plain")

View file

@ -7,4 +7,4 @@ from wuttaweb.testing import WebTestCase
class TestEssentialViews(WebTestCase):
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.essential')
self.pyramid_config.include("wuttaweb.views.essential")

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,7 @@ class TestPersonView(WebTestCase):
return people.PersonView(self.request)
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.people')
self.pyramid_config.include("wuttaweb.views.people")
def test_get_query(self):
view = self.make_view()
@ -31,7 +31,7 @@ class TestPersonView(WebTestCase):
grid = view.make_grid(model_class=model.Setting)
self.assertEqual(grid.linked_columns, [])
view.configure_grid(grid)
self.assertIn('full_name', grid.linked_columns)
self.assertIn("full_name", grid.linked_columns)
def test_configure_form(self):
model = self.app.model
@ -39,19 +39,19 @@ class TestPersonView(WebTestCase):
# full_name
form = view.make_form(model_class=model.Person)
self.assertIn('full_name', form)
with patch.object(view, 'creating', new=True):
self.assertIn("full_name", form)
with patch.object(view, "creating", new=True):
view.configure_form(form)
self.assertNotIn('full_name', form)
self.assertNotIn("full_name", form)
# users
person = model.Person()
form = view.make_form(model_instance=person)
self.assertNotIn('users', form.widgets)
with patch.object(view, 'viewing', new=True):
self.assertNotIn("users", form.widgets)
with patch.object(view, "viewing", new=True):
view.configure_form(form)
self.assertIn('users', form.widgets)
self.assertIsInstance(form.widgets['users'], GridWidget)
self.assertIn("users", form.widgets)
self.assertIsInstance(form.widgets["users"], GridWidget)
def test_make_users_grid(self):
model = self.app.model
@ -65,13 +65,13 @@ class TestPersonView(WebTestCase):
self.assertFalse(grid.actions)
# view + edit actions
with patch.object(self.request, 'is_root', new=True):
with patch.object(self.request, "is_root", new=True):
grid = view.make_users_grid(person)
self.assertIsInstance(grid, Grid)
self.assertIn('username', grid.linked_columns)
self.assertIn("username", grid.linked_columns)
self.assertEqual(len(grid.actions), 2)
self.assertEqual(grid.actions[0].key, 'view')
self.assertEqual(grid.actions[1].key, 'edit')
self.assertEqual(grid.actions[0].key, "view")
self.assertEqual(grid.actions[1].key, "edit")
def test_objectify(self):
model = self.app.model
@ -79,15 +79,15 @@ class TestPersonView(WebTestCase):
# creating
form = view.make_model_form()
form.validated = {'first_name': 'Barney', 'last_name': 'Rubble'}
form.validated = {"first_name": "Barney", "last_name": "Rubble"}
person = view.objectify(form)
self.assertEqual(person.full_name, 'Barney Rubble')
self.assertEqual(person.full_name, "Barney Rubble")
# editing
form = view.make_model_form(model_instance=person)
form.validated = {'first_name': 'Betty', 'last_name': 'Rubble'}
form.validated = {"first_name": "Betty", "last_name": "Rubble"}
person2 = view.objectify(form)
self.assertEqual(person2.full_name, 'Betty Rubble')
self.assertEqual(person2.full_name, "Betty Rubble")
self.assertIs(person2, person)
def test_autocomplete_query(self):
@ -100,24 +100,24 @@ class TestPersonView(WebTestCase):
self.session.commit()
view = self.make_view()
with patch.object(view, 'Session', return_value=self.session):
with patch.object(view, "Session", return_value=self.session):
# both people match
query = view.autocomplete_query('george')
query = view.autocomplete_query("george")
self.assertEqual(query.count(), 2)
# just 1 match
query = view.autocomplete_query('jones')
query = view.autocomplete_query("jones")
self.assertEqual(query.count(), 1)
# no matches
query = view.autocomplete_query('sally')
query = view.autocomplete_query("sally")
self.assertEqual(query.count(), 0)
def test_view_profile(self):
self.pyramid_config.include('wuttaweb.views.common')
self.pyramid_config.include('wuttaweb.views.auth')
self.pyramid_config.add_route('people', '/people/')
self.pyramid_config.include("wuttaweb.views.common")
self.pyramid_config.include("wuttaweb.views.auth")
self.pyramid_config.add_route("people", "/people/")
model = self.app.model
person = model.Person(full_name="Barney Rubble")
@ -126,12 +126,12 @@ class TestPersonView(WebTestCase):
# sanity check
view = self.make_view()
self.request.matchdict = {'uuid': person.uuid}
self.request.matchdict = {"uuid": person.uuid}
response = view.view_profile(session=self.session)
self.assertEqual(response.status_code, 200)
def test_make_user(self):
self.pyramid_config.include('wuttaweb.views.common')
self.pyramid_config.include("wuttaweb.views.common")
model = self.app.model
person = model.Person(full_name="Barney Rubble")
@ -140,7 +140,7 @@ class TestPersonView(WebTestCase):
# sanity check
view = self.make_view()
self.request.matchdict = {'uuid': person.uuid}
self.request.matchdict = {"uuid": person.uuid}
response = view.make_user()
# nb. this always redirects for now
self.assertEqual(response.status_code, 302)

View file

@ -10,11 +10,11 @@ from wuttaweb.testing import WebTestCase
class TestProgressView(WebTestCase):
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.progress')
self.pyramid_config.include("wuttaweb.views.progress")
def test_basic(self):
self.request.session.id = 'mockid'
self.request.matchdict = {'key': 'foo'}
self.request.session.id = "mockid"
self.request.matchdict = {"key": "foo"}
# first call with no setup, will create the progress session
# but it should be "empty" - except not really since beaker
@ -23,40 +23,40 @@ class TestProgressView(WebTestCase):
self.assertIsInstance(context, dict)
# now let's establish a progress session of our own
progsess = get_progress_session(self.request, 'bar')
progsess['maximum'] = 2
progsess['value'] = 1
progsess = get_progress_session(self.request, "bar")
progsess["maximum"] = 2
progsess["value"] = 1
progsess.save()
# then call view, check results
self.request.matchdict = {'key': 'bar'}
self.request.matchdict = {"key": "bar"}
context = mod.progress(self.request)
self.assertEqual(context['maximum'], 2)
self.assertEqual(context['value'], 1)
self.assertNotIn('complete', context)
self.assertEqual(context["maximum"], 2)
self.assertEqual(context["value"], 1)
self.assertNotIn("complete", context)
# now mark it as complete, check results
progsess['complete'] = True
progsess['success_msg'] = "yay!"
progsess["complete"] = True
progsess["success_msg"] = "yay!"
progsess.save()
context = mod.progress(self.request)
self.assertTrue(context['complete'])
self.assertEqual(context['success_msg'], "yay!")
self.assertTrue(context["complete"])
self.assertEqual(context["success_msg"], "yay!")
# now do that all again, with error
progsess = get_progress_session(self.request, 'baz')
progsess['maximum'] = 2
progsess['value'] = 1
progsess = get_progress_session(self.request, "baz")
progsess["maximum"] = 2
progsess["value"] = 1
progsess.save()
self.request.matchdict = {'key': 'baz'}
self.request.matchdict = {"key": "baz"}
context = mod.progress(self.request)
self.assertEqual(context['maximum'], 2)
self.assertEqual(context['value'], 1)
self.assertNotIn('complete', context)
self.assertNotIn('error', context)
progsess['error'] = True
progsess['error_msg'] = "omg!"
self.assertEqual(context["maximum"], 2)
self.assertEqual(context["value"], 1)
self.assertNotIn("complete", context)
self.assertNotIn("error", context)
progsess["error"] = True
progsess["error_msg"] = "omg!"
progsess.save()
context = mod.progress(self.request)
self.assertTrue(context['error'])
self.assertEqual(context['error_msg'], "omg!")
self.assertTrue(context["error"])
self.assertEqual(context["error_msg"], "omg!")

View file

@ -16,28 +16,29 @@ class SomeRandomReport(Report):
"""
This report shows something random.
"""
report_key = 'testing_some_random'
report_key = "testing_some_random"
report_title = "Random Test Report"
def add_params(self, schema):
schema.add(colander.SchemaNode(
colander.String(),
name='foo',
missing=colander.null))
schema.add(
colander.SchemaNode(colander.String(), name="foo", missing=colander.null)
)
schema.add(colander.SchemaNode(
colander.Date(),
name='start_date',
missing=colander.null))
schema.add(
colander.SchemaNode(
colander.Date(), name="start_date", missing=colander.null
)
)
def get_output_columns(self):
return ['foo']
return ["foo"]
def make_data(self, params, **kwargs):
return {
'output_title': "Testing Output",
'data': [{'foo': 'bar'}],
"output_title": "Testing Output",
"data": [{"foo": "bar"}],
}
@ -47,68 +48,77 @@ class TestReportViews(WebTestCase):
return mod.ReportView(self.request)
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.reports')
self.pyramid_config.include("wuttaweb.views.reports")
def test_get_grid_data(self):
view = self.make_view()
providers = dict(self.app.providers)
providers['wuttatest'] = MagicMock(report_modules=['tests.views.test_reports'])
with patch.object(self.app, 'providers', new=providers):
providers["wuttatest"] = MagicMock(report_modules=["tests.views.test_reports"])
with patch.object(self.app, "providers", new=providers):
data = view.get_grid_data()
self.assertIsInstance(data, list)
self.assertTrue(data) # 1+ reports
self.assertTrue(data) # 1+ reports
def test_normalize_report(self):
view = self.make_view()
report = SomeRandomReport(self.config)
normal = view.normalize_report(report)
help_text = normal.pop('help_text').strip()
help_text = normal.pop("help_text").strip()
self.assertEqual(help_text, "This report shows something random.")
self.assertEqual(normal, {
'report_key': 'testing_some_random',
'report_title': "Random Test Report",
})
self.assertEqual(
normal,
{
"report_key": "testing_some_random",
"report_title": "Random Test Report",
},
)
def test_configure_grid(self):
view = self.make_view()
grid = view.make_model_grid()
self.assertIn('report_title', grid.searchable_columns)
self.assertIn('help_text', grid.searchable_columns)
self.assertIn("report_title", grid.searchable_columns)
self.assertIn("help_text", grid.searchable_columns)
def test_get_instance(self):
view = self.make_view()
providers = {
'wuttatest': MagicMock(report_modules=['tests.views.test_reports']),
"wuttatest": MagicMock(report_modules=["tests.views.test_reports"]),
}
with patch.object(self.app, 'providers', new=providers):
with patch.object(self.app, "providers", new=providers):
# normal
with patch.object(self.request, 'matchdict', new={'report_key': 'testing_some_random'}):
with patch.object(
self.request, "matchdict", new={"report_key": "testing_some_random"}
):
report = view.get_instance()
self.assertIsInstance(report, dict)
self.assertEqual(report['report_key'], 'testing_some_random')
self.assertEqual(report['report_title'], "Random Test Report")
self.assertEqual(report["report_key"], "testing_some_random")
self.assertEqual(report["report_title"], "Random Test Report")
# not found
with patch.object(self.request, 'matchdict', new={'report_key': 'this-should_notEXIST'}):
with patch.object(
self.request, "matchdict", new={"report_key": "this-should_notEXIST"}
):
self.assertRaises(HTTPNotFound, view.get_instance)
def test_get_instance_title(self):
view = self.make_view()
result = view.get_instance_title({'report_title': 'whatever'})
self.assertEqual(result, 'whatever')
result = view.get_instance_title({"report_title": "whatever"})
self.assertEqual(result, "whatever")
def test_view(self):
self.pyramid_config.add_route('home', '/')
self.pyramid_config.add_route('login', '/auth/login')
self.pyramid_config.add_route('reports', '/reports/')
self.pyramid_config.add_route('reports.view', '/reports/{report_key}')
self.pyramid_config.add_route("home", "/")
self.pyramid_config.add_route("login", "/auth/login")
self.pyramid_config.add_route("reports", "/reports/")
self.pyramid_config.add_route("reports.view", "/reports/{report_key}")
view = self.make_view()
providers = dict(self.app.providers)
providers['wuttatest'] = MagicMock(report_modules=['tests.views.test_reports'])
with patch.object(self.app, 'providers', new=providers):
with patch.object(self.request, 'matchdict', new={'report_key': 'testing_some_random'}):
providers["wuttatest"] = MagicMock(report_modules=["tests.views.test_reports"])
with patch.object(self.app, "providers", new=providers):
with patch.object(
self.request, "matchdict", new={"report_key": "testing_some_random"}
):
# initial view
response = view.view()
@ -118,11 +128,15 @@ class TestReportViews(WebTestCase):
self.assertNotIn("Testing Output", response.text)
# run the report
with patch.object(self.request, 'GET', new={
'__start__': 'start_date:mapping',
'date': '2025-01-11',
'__end__': 'start_date',
}):
with patch.object(
self.request,
"GET",
new={
"__start__": "start_date:mapping",
"date": "2025-01-11",
"__end__": "start_date",
},
):
response = view.view()
self.assertEqual(response.status_code, 200)
# nb. there's a button in there somewhere, *and* an output title
@ -132,105 +146,142 @@ class TestReportViews(WebTestCase):
def test_configure_form(self):
view = self.make_view()
providers = dict(self.app.providers)
providers['wuttatest'] = MagicMock(report_modules=['tests.views.test_reports'])
with patch.object(self.app, 'providers', new=providers):
providers["wuttatest"] = MagicMock(report_modules=["tests.views.test_reports"])
with patch.object(self.app, "providers", new=providers):
with patch.object(self.request, 'matchdict', new={'report_key': 'testing_some_random'}):
with patch.object(
self.request, "matchdict", new={"report_key": "testing_some_random"}
):
report = view.get_instance()
form = view.make_model_form(report)
self.assertIn('help_text', form.readonly_fields)
self.assertIn('foo', form)
self.assertIn("help_text", form.readonly_fields)
self.assertIn("foo", form)
def test_normalize_columns(self):
view = self.make_view()
columns = view.normalize_columns(['foo'])
self.assertEqual(columns, [
{'name': 'foo', 'label': 'foo'},
])
columns = view.normalize_columns(["foo"])
self.assertEqual(
columns,
[
{"name": "foo", "label": "foo"},
],
)
columns = view.normalize_columns([{'name': 'foo'}])
self.assertEqual(columns, [
{'name': 'foo', 'label': 'foo'},
])
columns = view.normalize_columns([{"name": "foo"}])
self.assertEqual(
columns,
[
{"name": "foo", "label": "foo"},
],
)
columns = view.normalize_columns([{'name': 'foo', 'label': "FOO"}])
self.assertEqual(columns, [
{'name': 'foo', 'label': 'FOO'},
])
columns = view.normalize_columns([{"name": "foo", "label": "FOO"}])
self.assertEqual(
columns,
[
{"name": "foo", "label": "FOO"},
],
)
columns = view.normalize_columns([{'name': 'foo', 'label': "FOO", 'numeric': True}])
self.assertEqual(columns, [
{'name': 'foo', 'label': 'FOO', 'numeric': True},
])
columns = view.normalize_columns(
[{"name": "foo", "label": "FOO", "numeric": True}]
)
self.assertEqual(
columns,
[
{"name": "foo", "label": "FOO", "numeric": True},
],
)
def test_run_report(self):
view = self.make_view()
providers = dict(self.app.providers)
providers['wuttatest'] = MagicMock(report_modules=['tests.views.test_reports'])
with patch.object(self.app, 'providers', new=providers):
providers["wuttatest"] = MagicMock(report_modules=["tests.views.test_reports"])
with patch.object(self.app, "providers", new=providers):
with patch.object(self.request, 'matchdict', new={'report_key': 'testing_some_random'}):
report = view.report_handler.get_report('testing_some_random')
with patch.object(
self.request, "matchdict", new={"report_key": "testing_some_random"}
):
report = view.report_handler.get_report("testing_some_random")
normal = view.normalize_report(report)
form = view.make_model_form(normal)
# typical
context = view.run_report(report, {'form': form})
self.assertEqual(sorted(context['report_params']), ['foo', 'start_date'])
self.assertEqual(context['report_data'], {
'output_title': "Testing Output",
'data': [{'foo': 'bar'}],
})
self.assertIn('report_generated', context)
context = view.run_report(report, {"form": form})
self.assertEqual(
sorted(context["report_params"]), ["foo", "start_date"]
)
self.assertEqual(
context["report_data"],
{
"output_title": "Testing Output",
"data": [{"foo": "bar"}],
},
)
self.assertIn("report_generated", context)
# invalid params
with patch.object(self.request, 'GET', new={'start_date': 'NOT_GOOD'}):
context = view.run_report(report, {'form': form})
self.assertNotIn('report_params', context)
self.assertNotIn('report_data', context)
self.assertNotIn('report_generated', context)
with patch.object(self.request, "GET", new={"start_date": "NOT_GOOD"}):
context = view.run_report(report, {"form": form})
self.assertNotIn("report_params", context)
self.assertNotIn("report_data", context)
self.assertNotIn("report_generated", context)
# custom formatter
with patch.object(report, 'get_output_columns') as get_output_columns:
with patch.object(report, "get_output_columns") as get_output_columns:
get_output_columns.return_value = [
'foo',
{'name': 'start_date',
'formatter': lambda val: "FORMATTED VALUE"},
"foo",
{
"name": "start_date",
"formatter": lambda val: "FORMATTED VALUE",
},
]
with patch.object(report, 'make_data') as make_data:
with patch.object(report, "make_data") as make_data:
make_data.return_value = [
{'foo': 'bar', 'start_date': datetime.date(2025, 1, 11)},
{"foo": "bar", "start_date": datetime.date(2025, 1, 11)},
]
context = view.run_report(report, {'form': form})
context = view.run_report(report, {"form": form})
get_output_columns.assert_called_once_with()
self.assertEqual(len(context['report_columns']), 2)
self.assertEqual(context['report_columns'][0]['name'], 'foo')
self.assertEqual(context['report_columns'][1]['name'], 'start_date')
self.assertEqual(context['report_data'], {
'output_title': "Random Test Report",
'data': [{'foo': 'bar', 'start_date': 'FORMATTED VALUE'}],
})
self.assertEqual(len(context["report_columns"]), 2)
self.assertEqual(context["report_columns"][0]["name"], "foo")
self.assertEqual(
context["report_columns"][1]["name"], "start_date"
)
self.assertEqual(
context["report_data"],
{
"output_title": "Random Test Report",
"data": [
{"foo": "bar", "start_date": "FORMATTED VALUE"}
],
},
)
def test_download_data(self):
view = self.make_view()
providers = dict(self.app.providers)
providers['wuttatest'] = MagicMock(report_modules=['tests.views.test_reports'])
with patch.object(self.app, 'providers', new=providers):
with patch.object(self.request, 'matchdict', new={'report_key': 'testing_some_random'}):
providers["wuttatest"] = MagicMock(report_modules=["tests.views.test_reports"])
with patch.object(self.app, "providers", new=providers):
with patch.object(
self.request, "matchdict", new={"report_key": "testing_some_random"}
):
params, columns, data = view.get_download_data()
self.assertEqual(params, {})
self.assertEqual(columns, [{'name': 'foo', 'label': 'foo'}])
self.assertEqual(data, {
'output_title': "Testing Output",
'data': [{'foo': 'bar'}],
})
self.assertEqual(columns, [{"name": "foo", "label": "foo"}])
self.assertEqual(
data,
{
"output_title": "Testing Output",
"data": [{"foo": "bar"}],
},
)
def test_download_path(self):
view = self.make_view()
data = {'output_title': "My Report"}
path = view.get_download_path(data, 'csv')
self.assertTrue(path.endswith('My Report.csv'))
data = {"output_title": "My Report"}
path = view.get_download_path(data, "csv")
self.assertTrue(path.endswith("My Report.csv"))

View file

@ -18,7 +18,7 @@ class TestRoleView(WebTestCase):
return mod.RoleView(self.request)
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.roles')
self.pyramid_config.include("wuttaweb.views.roles")
def test_get_query(self):
view = self.make_view()
@ -29,9 +29,9 @@ class TestRoleView(WebTestCase):
model = self.app.model
view = self.make_view()
grid = view.make_grid(model_class=model.Role)
self.assertFalse(grid.is_linked('name'))
self.assertFalse(grid.is_linked("name"))
view.configure_grid(grid)
self.assertTrue(grid.is_linked('name'))
self.assertTrue(grid.is_linked("name"))
def test_is_editable(self):
model = self.app.model
@ -56,10 +56,10 @@ class TestRoleView(WebTestCase):
# reset
del self.request.user_permissions
barney = model.User(username='barney')
barney = model.User(username="barney")
self.session.add(barney)
barney.roles.append(blokes)
auth.grant_permission(blokes, 'roles.edit_builtin')
auth.grant_permission(blokes, "roles.edit_builtin")
self.session.commit()
# user with perms can edit *some* built-in
@ -90,9 +90,9 @@ class TestRoleView(WebTestCase):
role = model.Role(name="Foo")
view = self.make_view()
form = view.make_form(model_instance=role)
self.assertNotIn('name', form.validators)
self.assertNotIn("name", form.validators)
view.configure_form(form)
self.assertIsNotNone(form.validators['name'])
self.assertIsNotNone(form.validators["name"])
def test_make_users_grid(self):
model = self.app.model
@ -106,48 +106,48 @@ class TestRoleView(WebTestCase):
self.assertFalse(grid.actions)
# view + edit actions
with patch.object(self.request, 'is_root', new=True):
with patch.object(self.request, "is_root", new=True):
grid = view.make_users_grid(role)
self.assertIsInstance(grid, Grid)
self.assertIn('person', grid.linked_columns)
self.assertIn('username', grid.linked_columns)
self.assertIn("person", grid.linked_columns)
self.assertIn("username", grid.linked_columns)
self.assertEqual(len(grid.actions), 2)
self.assertEqual(grid.actions[0].key, 'view')
self.assertEqual(grid.actions[1].key, 'edit')
self.assertEqual(grid.actions[0].key, "view")
self.assertEqual(grid.actions[1].key, "edit")
def test_unique_name(self):
model = self.app.model
view = self.make_view()
role = model.Role(name='Foo')
role = model.Role(name="Foo")
self.session.add(role)
self.session.commit()
with patch.object(mod, 'Session', return_value=self.session):
with patch.object(mod, "Session", return_value=self.session):
# invalid if same name in data
node = colander.SchemaNode(colander.String(), name='name')
self.assertRaises(colander.Invalid, view.unique_name, node, 'Foo')
node = colander.SchemaNode(colander.String(), name="name")
self.assertRaises(colander.Invalid, view.unique_name, node, "Foo")
# but not if name belongs to current role
view.editing = True
self.request.matchdict = {'uuid': role.uuid}
node = colander.SchemaNode(colander.String(), name='name')
self.assertIsNone(view.unique_name(node, 'Foo'))
self.request.matchdict = {"uuid": role.uuid}
node = colander.SchemaNode(colander.String(), name="name")
self.assertIsNone(view.unique_name(node, "Foo"))
def get_permissions(self):
return {
'widgets': {
'label': "Widgets",
'perms': {
'widgets.list': {
'label': "List widgets",
"widgets": {
"label": "Widgets",
"perms": {
"widgets.list": {
"label": "List widgets",
},
'widgets.polish': {
'label': "Polish the widgets",
"widgets.polish": {
"label": "Polish the widgets",
},
'widgets.view': {
'label': "View widget",
"widgets.view": {
"label": "View widget",
},
},
},
@ -157,55 +157,59 @@ class TestRoleView(WebTestCase):
model = self.app.model
auth = self.app.get_auth_handler()
blokes = model.Role(name="Blokes")
auth.grant_permission(blokes, 'widgets.list')
auth.grant_permission(blokes, "widgets.list")
self.session.add(blokes)
barney = model.User(username='barney')
barney = model.User(username="barney")
barney.roles.append(blokes)
self.session.add(barney)
self.session.commit()
view = self.make_view()
all_perms = self.get_permissions()
self.request.registry.settings['wutta_permissions'] = all_perms
self.request.registry.settings["wutta_permissions"] = all_perms
def has_perm(perm):
if perm == 'widgets.list':
if perm == "widgets.list":
return True
return False
with patch.object(self.request, 'has_perm', new=has_perm, create=True):
with patch.object(self.request, "has_perm", new=has_perm, create=True):
# sanity check; current request has 1 perm
self.assertTrue(self.request.has_perm('widgets.list'))
self.assertFalse(self.request.has_perm('widgets.polish'))
self.assertFalse(self.request.has_perm('widgets.view'))
self.assertTrue(self.request.has_perm("widgets.list"))
self.assertFalse(self.request.has_perm("widgets.polish"))
self.assertFalse(self.request.has_perm("widgets.view"))
# when editing, user sees only the 1 perm
with patch.object(view, 'editing', new=True):
with patch.object(view, "editing", new=True):
perms = view.get_available_permissions()
self.assertEqual(list(perms), ['widgets'])
self.assertEqual(list(perms['widgets']['perms']), ['widgets.list'])
self.assertEqual(list(perms), ["widgets"])
self.assertEqual(list(perms["widgets"]["perms"]), ["widgets.list"])
# but when viewing, same user sees all perms
with patch.object(view, 'viewing', new=True):
with patch.object(view, "viewing", new=True):
perms = view.get_available_permissions()
self.assertEqual(list(perms), ['widgets'])
self.assertEqual(list(perms['widgets']['perms']),
['widgets.list', 'widgets.polish', 'widgets.view'])
self.assertEqual(list(perms), ["widgets"])
self.assertEqual(
list(perms["widgets"]["perms"]),
["widgets.list", "widgets.polish", "widgets.view"],
)
# also, when admin user is editing, sees all perms
self.request.is_admin = True
with patch.object(view, 'editing', new=True):
with patch.object(view, "editing", new=True):
perms = view.get_available_permissions()
self.assertEqual(list(perms), ['widgets'])
self.assertEqual(list(perms['widgets']['perms']),
['widgets.list', 'widgets.polish', 'widgets.view'])
self.assertEqual(list(perms), ["widgets"])
self.assertEqual(
list(perms["widgets"]["perms"]),
["widgets.list", "widgets.polish", "widgets.view"],
)
def test_objectify(self):
model = self.app.model
auth = self.app.get_auth_handler()
blokes = model.Role(name="Blokes")
self.session.add(blokes)
barney = model.User(username='barney')
barney = model.User(username="barney")
barney.roles.append(blokes)
self.session.add(barney)
self.session.commit()
@ -213,56 +217,62 @@ class TestRoleView(WebTestCase):
permissions = self.get_permissions()
# sanity check, role has just 1 perm
auth.grant_permission(blokes, 'widgets.list')
auth.grant_permission(blokes, "widgets.list")
self.session.commit()
self.assertEqual(blokes.permissions, ['widgets.list'])
self.assertEqual(blokes.permissions, ["widgets.list"])
# form can update role perms
view.editing = True
self.request.matchdict = {'uuid': blokes.uuid}
with patch.object(view, 'get_available_permissions', return_value=permissions):
self.request.matchdict = {"uuid": blokes.uuid}
with patch.object(view, "get_available_permissions", return_value=permissions):
form = view.make_model_form(model_instance=blokes)
form.validated = {'name': 'Blokes',
'permissions': {'widgets.list', 'widgets.polish', 'widgets.view'}}
form.validated = {
"name": "Blokes",
"permissions": {"widgets.list", "widgets.polish", "widgets.view"},
}
role = view.objectify(form)
self.session.commit()
self.assertIs(role, blokes)
self.assertEqual(blokes.permissions, ['widgets.list', 'widgets.polish', 'widgets.view'])
self.assertEqual(
blokes.permissions, ["widgets.list", "widgets.polish", "widgets.view"]
)
def test_update_permissions(self):
model = self.app.model
auth = self.app.get_auth_handler()
blokes = model.Role(name="Blokes")
auth.grant_permission(blokes, 'widgets.list')
auth.grant_permission(blokes, "widgets.list")
self.session.add(blokes)
barney = model.User(username='barney')
barney = model.User(username="barney")
barney.roles.append(blokes)
self.session.add(barney)
self.session.commit()
view = self.make_view()
permissions = self.get_permissions()
with patch.object(view, 'get_available_permissions', return_value=permissions):
with patch.object(view, "get_available_permissions", return_value=permissions):
# no error if data is missing perms
form = view.make_model_form(model_instance=blokes)
form.validated = {'name': 'BloX'}
form.validated = {"name": "BloX"}
role = view.objectify(form)
self.session.commit()
self.assertIs(role, blokes)
self.assertEqual(blokes.name, 'BloX')
self.assertEqual(blokes.name, "BloX")
# sanity check, role has just 1 perm
self.assertEqual(blokes.permissions, ['widgets.list'])
self.assertEqual(blokes.permissions, ["widgets.list"])
# role perms are updated
form = view.make_model_form(model_instance=blokes)
form.validated = {'name': 'Blokes',
'permissions': {'widgets.polish', 'widgets.view'}}
form.validated = {
"name": "Blokes",
"permissions": {"widgets.polish", "widgets.view"},
}
role = view.objectify(form)
self.session.commit()
self.assertIs(role, blokes)
self.assertEqual(blokes.permissions, ['widgets.polish', 'widgets.view'])
self.assertEqual(blokes.permissions, ["widgets.polish", "widgets.view"])
class TestPermissionView(WebTestCase):
@ -279,17 +289,17 @@ class TestPermissionView(WebTestCase):
model = self.app.model
view = self.make_view()
grid = view.make_grid(model_class=model.Permission)
self.assertFalse(grid.is_linked('role'))
self.assertFalse(grid.is_linked("role"))
view.configure_grid(grid)
self.assertTrue(grid.is_linked('role'))
self.assertTrue(grid.is_linked("role"))
def test_configure_form(self):
model = self.app.model
role = model.Role(name="Foo")
perm = model.Permission(role=role, permission='whatever')
perm = model.Permission(role=role, permission="whatever")
view = self.make_view()
form = view.make_form(model_instance=perm)
self.assertIsNone(form.schema)
view.configure_form(form)
schema = form.get_schema()
self.assertIsInstance(schema['role'].typ, RoleRef)
self.assertIsInstance(schema["role"].typ, RoleRef)

View file

@ -13,7 +13,7 @@ class TestAppInfoView(WebTestCase):
def setUp(self):
self.setup_web()
self.pyramid_config.include('wuttaweb.views.essential')
self.pyramid_config.include("wuttaweb.views.essential")
def make_view(self):
return mod.AppInfoView(self.request)
@ -26,7 +26,7 @@ class TestAppInfoView(WebTestCase):
self.assertEqual(data, [])
# 'partial' request returns data
self.request.GET = {'partial': '1'}
self.request.GET = {"partial": "1"}
data = view.get_grid_data()
self.assertIsInstance(data, list)
self.assertTrue(data)
@ -61,7 +61,7 @@ class TestSettingView(WebTestCase):
self.assertEqual(len(data), 0)
# unless we save some settings
self.app.save_setting(self.session, 'foo', 'bar')
self.app.save_setting(self.session, "foo", "bar")
self.session.commit()
query = view.get_grid_data(session=self.session)
data = query.all()
@ -71,34 +71,34 @@ class TestSettingView(WebTestCase):
model = self.app.model
view = self.make_view()
grid = view.make_grid(model_class=model.Setting)
self.assertFalse(grid.is_linked('name'))
self.assertFalse(grid.is_linked("name"))
view.configure_grid(grid)
self.assertTrue(grid.is_linked('name'))
self.assertTrue(grid.is_linked("name"))
def test_configure_form(self):
view = self.make_view()
form = view.make_form(fields=view.get_form_fields())
self.assertNotIn('value', form.required_fields)
self.assertNotIn("value", form.required_fields)
view.configure_form(form)
self.assertIn('value', form.required_fields)
self.assertFalse(form.required_fields['value'])
self.assertIn("value", form.required_fields)
self.assertFalse(form.required_fields["value"])
def test_unique_name(self):
model = self.app.model
view = self.make_view()
setting = model.Setting(name='foo')
setting = model.Setting(name="foo")
self.session.add(setting)
self.session.commit()
with patch.object(view, 'Session', return_value=self.session):
with patch.object(view, "Session", return_value=self.session):
# invalid if same name in data
node = colander.SchemaNode(colander.String(), name='name')
self.assertRaises(colander.Invalid, view.unique_name, node, 'foo')
node = colander.SchemaNode(colander.String(), name="name")
self.assertRaises(colander.Invalid, view.unique_name, node, "foo")
# but not if name belongs to current setting
view.editing = True
self.request.matchdict = {'name': 'foo'}
node = colander.SchemaNode(colander.String(), name='name')
self.assertIsNone(view.unique_name(node, 'foo'))
self.request.matchdict = {"name": "foo"}
node = colander.SchemaNode(colander.String(), name="name")
self.assertIsNone(view.unique_name(node, "foo"))

View file

@ -17,7 +17,7 @@ class TestUpgradeView(WebTestCase):
return mod.UpgradeView(self.request)
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.upgrades')
self.pyramid_config.include("wuttaweb.views.upgrades")
def test_configure_grid(self):
model = self.app.model
@ -37,74 +37,79 @@ class TestUpgradeView(WebTestCase):
self.assertIsNone(view.grid_row_class(upgrade, data, 1))
upgrade.status = enum.UpgradeStatus.EXECUTING
self.assertEqual(view.grid_row_class(upgrade, data, 1), 'has-background-warning')
self.assertEqual(
view.grid_row_class(upgrade, data, 1), "has-background-warning"
)
upgrade.status = enum.UpgradeStatus.SUCCESS
self.assertIsNone(view.grid_row_class(upgrade, data, 1))
upgrade.status = enum.UpgradeStatus.FAILURE
self.assertEqual(view.grid_row_class(upgrade, data, 1), 'has-background-warning')
self.assertEqual(
view.grid_row_class(upgrade, data, 1), "has-background-warning"
)
def test_configure_form(self):
self.pyramid_config.add_route('upgrades.download', '/upgrades/{uuid}/download')
self.pyramid_config.add_route("upgrades.download", "/upgrades/{uuid}/download")
model = self.app.model
enum = self.app.enum
user = model.User(username='barney')
user = model.User(username="barney")
self.session.add(user)
upgrade = model.Upgrade(description='test', created_by=user,
status=enum.UpgradeStatus.PENDING)
upgrade = model.Upgrade(
description="test", created_by=user, status=enum.UpgradeStatus.PENDING
)
self.session.add(upgrade)
self.session.commit()
view = self.make_view()
# some fields exist when viewing
with patch.object(view, 'viewing', new=True):
with patch.object(view, "viewing", new=True):
form = view.make_form(model_class=model.Upgrade, model_instance=upgrade)
self.assertIn('created', form)
self.assertIn("created", form)
view.configure_form(form)
self.assertIn('created', form)
self.assertIn("created", form)
# but then are removed when creating
with patch.object(view, 'creating', new=True):
with patch.object(view, "creating", new=True):
form = view.make_form(model_class=model.Upgrade)
self.assertIn('created', form)
self.assertIn("created", form)
view.configure_form(form)
self.assertNotIn('created', form)
self.assertNotIn("created", form)
# test executed, stdout/stderr when viewing
with patch.object(view, 'viewing', new=True):
with patch.object(view, "viewing", new=True):
# executed is *not* shown by default
form = view.make_form(model_class=model.Upgrade, model_instance=upgrade)
self.assertIn('executed', form)
self.assertIn("executed", form)
view.configure_form(form)
self.assertNotIn('executed', form)
self.assertNotIn('stdout_file', form)
self.assertNotIn('stderr_file', form)
self.assertNotIn("executed", form)
self.assertNotIn("stdout_file", form)
self.assertNotIn("stderr_file", form)
# but it *is* shown if upgrade is executed
upgrade.executed = datetime.datetime.now()
upgrade.status = enum.UpgradeStatus.SUCCESS
form = view.make_form(model_class=model.Upgrade, model_instance=upgrade)
self.assertIn('executed', form)
self.assertIn("executed", form)
view.configure_form(form)
self.assertIn('executed', form)
self.assertIn('stdout_file', form)
self.assertIn('stderr_file', form)
self.assertIn("executed", form)
self.assertIn("stdout_file", form)
self.assertIn("stderr_file", form)
def test_objectify(self):
model = self.app.model
enum = self.app.enum
user = model.User(username='barney')
user = model.User(username="barney")
self.session.add(user)
self.session.commit()
view = self.make_view()
# user and status are auto-set when creating
self.request.user = user
self.request.method = 'POST'
self.request.POST = {'description': "new one"}
with patch.object(view, 'creating', new=True):
self.request.method = "POST"
self.request.POST = {"description": "new one"}
with patch.object(view, "creating", new=True):
form = view.make_model_form()
self.assertTrue(form.validate())
upgrade = view.objectify(form)
@ -116,13 +121,14 @@ class TestUpgradeView(WebTestCase):
model = self.app.model
enum = self.app.enum
appdir = self.mkdir('app')
self.config.setdefault('wutta.appdir', appdir)
appdir = self.mkdir("app")
self.config.setdefault("wutta.appdir", appdir)
self.assertEqual(self.app.get_appdir(), appdir)
user = model.User(username='barney')
upgrade = model.Upgrade(description='test', created_by=user,
status=enum.UpgradeStatus.PENDING)
user = model.User(username="barney")
upgrade = model.Upgrade(
description="test", created_by=user, status=enum.UpgradeStatus.PENDING
)
self.session.add(upgrade)
self.session.commit()
@ -134,21 +140,24 @@ class TestUpgradeView(WebTestCase):
self.assertIsNone(path)
# with filename
path = view.download_path(upgrade, 'foo.txt')
self.assertEqual(path, os.path.join(appdir, 'data', 'upgrades',
uuid[:2], uuid[2:], 'foo.txt'))
path = view.download_path(upgrade, "foo.txt")
self.assertEqual(
path,
os.path.join(appdir, "data", "upgrades", uuid[:2], uuid[2:], "foo.txt"),
)
def test_get_upgrade_filepath(self):
model = self.app.model
enum = self.app.enum
appdir = self.mkdir('app')
self.config.setdefault('wutta.appdir', appdir)
appdir = self.mkdir("app")
self.config.setdefault("wutta.appdir", appdir)
self.assertEqual(self.app.get_appdir(), appdir)
user = model.User(username='barney')
upgrade = model.Upgrade(description='test', created_by=user,
status=enum.UpgradeStatus.PENDING)
user = model.User(username="barney")
upgrade = model.Upgrade(
description="test", created_by=user, status=enum.UpgradeStatus.PENDING
)
self.session.add(upgrade)
self.session.commit()
@ -157,25 +166,29 @@ class TestUpgradeView(WebTestCase):
# no filename
path = view.get_upgrade_filepath(upgrade)
self.assertEqual(path, os.path.join(appdir, 'data', 'upgrades',
uuid[:2], uuid[2:]))
self.assertEqual(
path, os.path.join(appdir, "data", "upgrades", uuid[:2], uuid[2:])
)
# with filename
path = view.get_upgrade_filepath(upgrade, 'foo.txt')
self.assertEqual(path, os.path.join(appdir, 'data', 'upgrades',
uuid[:2], uuid[2:], 'foo.txt'))
path = view.get_upgrade_filepath(upgrade, "foo.txt")
self.assertEqual(
path,
os.path.join(appdir, "data", "upgrades", uuid[:2], uuid[2:], "foo.txt"),
)
def test_delete_instance(self):
model = self.app.model
enum = self.app.enum
appdir = self.mkdir('app')
self.config.setdefault('wutta.appdir', appdir)
appdir = self.mkdir("app")
self.config.setdefault("wutta.appdir", appdir)
self.assertEqual(self.app.get_appdir(), appdir)
user = model.User(username='barney')
upgrade = model.Upgrade(description='test', created_by=user,
status=enum.UpgradeStatus.PENDING)
user = model.User(username="barney")
upgrade = model.Upgrade(
description="test", created_by=user, status=enum.UpgradeStatus.PENDING
)
self.session.add(upgrade)
self.session.commit()
@ -183,19 +196,19 @@ class TestUpgradeView(WebTestCase):
# mock stdout/stderr files
upgrade_dir = view.get_upgrade_filepath(upgrade)
stdout = view.get_upgrade_filepath(upgrade, 'stdout.log')
with open(stdout, 'w') as f:
f.write('stdout')
stderr = view.get_upgrade_filepath(upgrade, 'stderr.log')
with open(stderr, 'w') as f:
f.write('stderr')
stdout = view.get_upgrade_filepath(upgrade, "stdout.log")
with open(stdout, "w") as f:
f.write("stdout")
stderr = view.get_upgrade_filepath(upgrade, "stderr.log")
with open(stderr, "w") as f:
f.write("stderr")
# both upgrade and files are deleted
self.assertTrue(os.path.exists(upgrade_dir))
self.assertTrue(os.path.exists(stdout))
self.assertTrue(os.path.exists(stderr))
self.assertEqual(self.session.query(model.Upgrade).count(), 1)
with patch.object(view, 'Session', return_value=self.session):
with patch.object(view, "Session", return_value=self.session):
view.delete_instance(upgrade)
self.assertFalse(os.path.exists(upgrade_dir))
self.assertFalse(os.path.exists(stdout))
@ -206,13 +219,14 @@ class TestUpgradeView(WebTestCase):
model = self.app.model
enum = self.app.enum
appdir = self.mkdir('app')
self.config.setdefault('wutta.appdir', appdir)
appdir = self.mkdir("app")
self.config.setdefault("wutta.appdir", appdir)
self.assertEqual(self.app.get_appdir(), appdir)
user = model.User(username='barney')
upgrade = model.Upgrade(description='test', created_by=user,
status=enum.UpgradeStatus.PENDING)
user = model.User(username="barney")
upgrade = model.Upgrade(
description="test", created_by=user, status=enum.UpgradeStatus.PENDING
)
self.session.add(upgrade)
self.session.commit()
@ -224,139 +238,153 @@ class TestUpgradeView(WebTestCase):
self.assertRaises(ConfigurationError, view.execute_instance, upgrade, user)
# script w/ success
goodpy = self.write_file('good.py', """
goodpy = self.write_file(
"good.py",
"""
import sys
sys.stdout.write('hello from good.py')
sys.exit(0)
""")
self.app.save_setting(self.session, 'wutta.upgrades.command', f'{python} {goodpy}')
""",
)
self.app.save_setting(
self.session, "wutta.upgrades.command", f"{python} {goodpy}"
)
self.assertIsNone(upgrade.executed)
self.assertIsNone(upgrade.executed_by)
self.assertEqual(upgrade.status, enum.UpgradeStatus.PENDING)
with patch.object(view, 'Session', return_value=self.session):
with patch.object(self.config, 'usedb', new=True):
with patch.object(view, "Session", return_value=self.session):
with patch.object(self.config, "usedb", new=True):
view.execute_instance(upgrade, user)
self.assertIsNotNone(upgrade.executed)
self.assertIs(upgrade.executed_by, user)
self.assertEqual(upgrade.status, enum.UpgradeStatus.SUCCESS)
with open(view.get_upgrade_filepath(upgrade, 'stdout.log')) as f:
self.assertEqual(f.read(), 'hello from good.py')
with open(view.get_upgrade_filepath(upgrade, 'stderr.log')) as f:
self.assertEqual(f.read(), '')
with open(view.get_upgrade_filepath(upgrade, "stdout.log")) as f:
self.assertEqual(f.read(), "hello from good.py")
with open(view.get_upgrade_filepath(upgrade, "stderr.log")) as f:
self.assertEqual(f.read(), "")
# need a new record for next test
upgrade = model.Upgrade(description='test', created_by=user,
status=enum.UpgradeStatus.PENDING)
upgrade = model.Upgrade(
description="test", created_by=user, status=enum.UpgradeStatus.PENDING
)
self.session.add(upgrade)
self.session.commit()
# script w/ failure
badpy = self.write_file('bad.py', """
badpy = self.write_file(
"bad.py",
"""
import sys
sys.stderr.write('hello from bad.py')
sys.exit(42)
""")
self.app.save_setting(self.session, 'wutta.upgrades.command', f'{python} {badpy}')
""",
)
self.app.save_setting(
self.session, "wutta.upgrades.command", f"{python} {badpy}"
)
self.assertIsNone(upgrade.executed)
self.assertIsNone(upgrade.executed_by)
self.assertEqual(upgrade.status, enum.UpgradeStatus.PENDING)
with patch.object(view, 'Session', return_value=self.session):
with patch.object(self.config, 'usedb', new=True):
with patch.object(view, "Session", return_value=self.session):
with patch.object(self.config, "usedb", new=True):
view.execute_instance(upgrade, user)
self.assertIsNotNone(upgrade.executed)
self.assertIs(upgrade.executed_by, user)
self.assertEqual(upgrade.status, enum.UpgradeStatus.FAILURE)
with open(view.get_upgrade_filepath(upgrade, 'stdout.log')) as f:
self.assertEqual(f.read(), '')
with open(view.get_upgrade_filepath(upgrade, 'stderr.log')) as f:
self.assertEqual(f.read(), 'hello from bad.py')
with open(view.get_upgrade_filepath(upgrade, "stdout.log")) as f:
self.assertEqual(f.read(), "")
with open(view.get_upgrade_filepath(upgrade, "stderr.log")) as f:
self.assertEqual(f.read(), "hello from bad.py")
def test_execute_progress(self):
model = self.app.model
enum = self.app.enum
view = self.make_view()
user = model.User(username='barney')
user = model.User(username="barney")
self.session.add(user)
upgrade = model.Upgrade(description='test', created_by=user,
status=enum.UpgradeStatus.PENDING)
upgrade = model.Upgrade(
description="test", created_by=user, status=enum.UpgradeStatus.PENDING
)
self.session.add(upgrade)
self.session.commit()
stdout = self.write_file('stdout.log', 'hello 001\n')
stdout = self.write_file("stdout.log", "hello 001\n")
self.request.matchdict = {'uuid': upgrade.uuid}
with patch.multiple(mod.UpgradeView,
Session=MagicMock(return_value=self.session),
get_upgrade_filepath=MagicMock(return_value=stdout)):
self.request.matchdict = {"uuid": upgrade.uuid}
with patch.multiple(
mod.UpgradeView,
Session=MagicMock(return_value=self.session),
get_upgrade_filepath=MagicMock(return_value=stdout),
):
# nb. this is used to identify progress tracker
self.request.session.id = 'mockid#1'
self.request.session.id = "mockid#1"
# first call should get the full contents
context = view.execute_progress()
self.assertFalse(context.get('complete'))
self.assertFalse(context.get('error'))
self.assertFalse(context.get("complete"))
self.assertFalse(context.get("error"))
# nb. newline is converted to <br>
self.assertEqual(context['stdout'], 'hello 001<br />')
self.assertEqual(context["stdout"], "hello 001<br />")
# next call should get any new contents
with open(stdout, 'a') as f:
f.write('hello 002\n')
with open(stdout, "a") as f:
f.write("hello 002\n")
context = view.execute_progress()
self.assertFalse(context.get('complete'))
self.assertFalse(context.get('error'))
self.assertEqual(context['stdout'], 'hello 002<br />')
self.assertFalse(context.get("complete"))
self.assertFalse(context.get("error"))
self.assertEqual(context["stdout"], "hello 002<br />")
# nb. switch to a different progress tracker
self.request.session.id = 'mockid#2'
self.request.session.id = "mockid#2"
# first call should get the full contents
context = view.execute_progress()
self.assertFalse(context.get('complete'))
self.assertFalse(context.get('error'))
self.assertEqual(context['stdout'], 'hello 001<br />hello 002<br />')
self.assertFalse(context.get("complete"))
self.assertFalse(context.get("error"))
self.assertEqual(context["stdout"], "hello 001<br />hello 002<br />")
# mark progress complete
session = get_progress_session(self.request, 'upgrades.execute')
session = get_progress_session(self.request, "upgrades.execute")
session.load()
session['complete'] = True
session['success_msg'] = 'yay!'
session["complete"] = True
session["success_msg"] = "yay!"
session.save()
# next call should reflect that
self.assertEqual(self.request.session.pop_flash(), [])
context = view.execute_progress()
self.assertTrue(context.get('complete'))
self.assertFalse(context.get('error'))
self.assertTrue(context.get("complete"))
self.assertFalse(context.get("error"))
# nb. this is missing b/c we already got all contents
self.assertNotIn('stdout', context)
self.assertEqual(self.request.session.pop_flash(), ['yay!'])
self.assertNotIn("stdout", context)
self.assertEqual(self.request.session.pop_flash(), ["yay!"])
# nb. switch to a different progress tracker
self.request.session.id = 'mockid#3'
self.request.session.id = "mockid#3"
# first call should get the full contents
context = view.execute_progress()
self.assertFalse(context.get('complete'))
self.assertFalse(context.get('error'))
self.assertEqual(context['stdout'], 'hello 001<br />hello 002<br />')
self.assertFalse(context.get("complete"))
self.assertFalse(context.get("error"))
self.assertEqual(context["stdout"], "hello 001<br />hello 002<br />")
# mark progress error
session = get_progress_session(self.request, 'upgrades.execute')
session = get_progress_session(self.request, "upgrades.execute")
session.load()
session['error'] = True
session['error_msg'] = 'omg!'
session["error"] = True
session["error_msg"] = "omg!"
session.save()
# next call should reflect that
self.assertEqual(self.request.session.pop_flash('error'), [])
self.assertEqual(self.request.session.pop_flash("error"), [])
context = view.execute_progress()
self.assertFalse(context.get('complete'))
self.assertTrue(context.get('error'))
self.assertFalse(context.get("complete"))
self.assertTrue(context.get("error"))
# nb. this is missing b/c we already got all contents
self.assertNotIn('stdout', context)
self.assertEqual(self.request.session.pop_flash('error'), ['omg!'])
self.assertNotIn("stdout", context)
self.assertEqual(self.request.session.pop_flash("error"), ["omg!"])
def test_configure_get_simple_settings(self):
# sanity/coverage check

View file

@ -17,7 +17,7 @@ class TestUserView(WebTestCase):
return mod.UserView(self.request)
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.users')
self.pyramid_config.include("wuttaweb.views.users")
def test_get_query(self):
view = self.make_view()
@ -28,35 +28,35 @@ class TestUserView(WebTestCase):
model = self.app.model
view = self.make_view()
grid = view.make_grid(model_class=model.User)
self.assertFalse(grid.is_linked('person'))
self.assertFalse(grid.is_linked("person"))
view.configure_grid(grid)
self.assertTrue(grid.is_linked('person'))
self.assertTrue(grid.is_linked("person"))
def test_grid_row_class(self):
model = self.app.model
user = model.User(username='barney', active=True)
user = model.User(username="barney", active=True)
data = dict(user)
view = self.make_view()
self.assertIsNone(view.grid_row_class(user, data, 1))
user.active = False
self.assertEqual(view.grid_row_class(user, data, 1), 'has-background-warning')
self.assertEqual(view.grid_row_class(user, data, 1), "has-background-warning")
def test_is_editable(self):
model = self.app.model
view = self.make_view()
# active user is editable
user = model.User(username='barney', active=True)
user = model.User(username="barney", active=True)
self.assertTrue(view.is_editable(user))
# inactive also editable
user = model.User(username='barney', active=False)
user = model.User(username="barney", active=False)
self.assertTrue(view.is_editable(user))
# but not if prevent_edit flag is set
user = model.User(username='barney', prevent_edit=True)
user = model.User(username="barney", prevent_edit=True)
self.assertFalse(view.is_editable(user))
# unless request user is root
@ -65,95 +65,97 @@ class TestUserView(WebTestCase):
def test_configure_form(self):
model = self.app.model
person = model.Person(first_name='Barney', last_name='Rubble', full_name='Barney Rubble')
barney = model.User(username='barney', person=person)
person = model.Person(
first_name="Barney", last_name="Rubble", full_name="Barney Rubble"
)
barney = model.User(username="barney", person=person)
self.session.add(barney)
self.session.commit()
view = self.make_view()
# person replaced with first/last name when creating or editing
with patch.object(view, 'viewing', new=True):
with patch.object(view, "viewing", new=True):
form = view.make_form(model_instance=barney)
self.assertIn('person', form)
self.assertNotIn('first_name', form)
self.assertNotIn('last_name', form)
self.assertIn("person", form)
self.assertNotIn("first_name", form)
self.assertNotIn("last_name", form)
view.configure_form(form)
self.assertIn('person', form)
self.assertNotIn('first_name', form)
self.assertNotIn('last_name', form)
with patch.object(view, 'creating', new=True):
self.assertIn("person", form)
self.assertNotIn("first_name", form)
self.assertNotIn("last_name", form)
with patch.object(view, "creating", new=True):
form = view.make_form(model_instance=barney)
self.assertIn('person', form)
self.assertNotIn('first_name', form)
self.assertNotIn('last_name', form)
self.assertIn("person", form)
self.assertNotIn("first_name", form)
self.assertNotIn("last_name", form)
view.configure_form(form)
self.assertNotIn('person', form)
self.assertIn('first_name', form)
self.assertIn('last_name', form)
with patch.object(view, 'editing', new=True):
self.assertNotIn("person", form)
self.assertIn("first_name", form)
self.assertIn("last_name", form)
with patch.object(view, "editing", new=True):
form = view.make_form(model_instance=barney)
self.assertIn('person', form)
self.assertNotIn('first_name', form)
self.assertNotIn('last_name', form)
self.assertIn("person", form)
self.assertNotIn("first_name", form)
self.assertNotIn("last_name", form)
view.configure_form(form)
self.assertNotIn('person', form)
self.assertIn('first_name', form)
self.assertIn('last_name', form)
self.assertNotIn("person", form)
self.assertIn("first_name", form)
self.assertIn("last_name", form)
# first/last name have default values when editing
with patch.object(view, 'editing', new=True):
with patch.object(view, "editing", new=True):
form = view.make_form(model_instance=barney)
self.assertNotIn('first_name', form.defaults)
self.assertNotIn('last_name', form.defaults)
self.assertNotIn("first_name", form.defaults)
self.assertNotIn("last_name", form.defaults)
view.configure_form(form)
self.assertIn('first_name', form.defaults)
self.assertEqual(form.defaults['first_name'], 'Barney')
self.assertIn('last_name', form.defaults)
self.assertEqual(form.defaults['last_name'], 'Rubble')
self.assertIn("first_name", form.defaults)
self.assertEqual(form.defaults["first_name"], "Barney")
self.assertIn("last_name", form.defaults)
self.assertEqual(form.defaults["last_name"], "Rubble")
# password removed (always, for now)
with patch.object(view, 'viewing', new=True):
with patch.object(view, "viewing", new=True):
form = view.make_form(model_instance=barney)
self.assertIn('password', form)
self.assertIn("password", form)
view.configure_form(form)
self.assertNotIn('password', form)
with patch.object(view, 'editing', new=True):
self.assertNotIn("password", form)
with patch.object(view, "editing", new=True):
form = view.make_form(model_instance=barney)
self.assertIn('password', form)
self.assertIn("password", form)
view.configure_form(form)
self.assertNotIn('password', form)
self.assertNotIn("password", form)
# api tokens grid shown only if current user has perm
with patch.object(view, 'viewing', new=True):
with patch.object(view, "viewing", new=True):
form = view.make_form(model_instance=barney)
self.assertIn('api_tokens', form)
self.assertIn("api_tokens", form)
view.configure_form(form)
self.assertNotIn('api_tokens', form)
with patch.object(self.request, 'is_root', new=True):
self.assertNotIn("api_tokens", form)
with patch.object(self.request, "is_root", new=True):
form = view.make_form(model_instance=barney)
self.assertIn('api_tokens', form)
self.assertIn("api_tokens", form)
view.configure_form(form)
self.assertIn('api_tokens', form)
self.assertIn("api_tokens", form)
def test_unique_username(self):
model = self.app.model
view = self.make_view()
user = model.User(username='foo')
user = model.User(username="foo")
self.session.add(user)
self.session.commit()
with patch.object(view, 'Session', return_value=self.session):
with patch.object(view, "Session", return_value=self.session):
# invalid if same username in data
node = colander.SchemaNode(colander.String(), name='username')
self.assertRaises(colander.Invalid, view.unique_username, node, 'foo')
node = colander.SchemaNode(colander.String(), name="username")
self.assertRaises(colander.Invalid, view.unique_username, node, "foo")
# but not if username belongs to current user
view.editing = True
self.request.matchdict = {'uuid': user.uuid}
node = colander.SchemaNode(colander.String(), name='username')
self.assertIsNone(view.unique_username(node, 'foo'))
self.request.matchdict = {"uuid": user.uuid}
node = colander.SchemaNode(colander.String(), name="username")
self.assertIsNone(view.unique_username(node, "foo"))
def test_objectify(self):
model = self.app.model
@ -164,14 +166,14 @@ class TestUserView(WebTestCase):
self.session.add(blokes)
others = model.Role(name="Others")
self.session.add(others)
barney = model.User(username='barney')
auth.set_user_password(barney, 'testpass')
barney = model.User(username="barney")
auth.set_user_password(barney, "testpass")
barney.roles.append(blokes)
self.session.add(barney)
self.session.commit()
with patch.object(self.request, 'matchdict', new={'uuid': barney.uuid}):
with patch.object(view, 'editing', new=True):
with patch.object(self.request, "matchdict", new={"uuid": barney.uuid}):
with patch.object(view, "editing", new=True):
# sanity check, user is just in 'blokes' role
self.session.refresh(barney)
@ -179,18 +181,18 @@ class TestUserView(WebTestCase):
self.assertEqual(barney.roles[0].name, "Blokes")
# form can update user password
self.assertTrue(auth.check_user_password(barney, 'testpass'))
self.assertTrue(auth.check_user_password(barney, "testpass"))
form = view.make_model_form(model_instance=barney)
form.validated = {'username': 'barney', 'set_password': 'testpass2'}
with patch.object(view, 'Session', return_value=self.session):
form.validated = {"username": "barney", "set_password": "testpass2"}
with patch.object(view, "Session", return_value=self.session):
user = view.objectify(form)
self.assertIs(user, barney)
self.assertTrue(auth.check_user_password(barney, 'testpass2'))
self.assertTrue(auth.check_user_password(barney, "testpass2"))
# form can update user roles
form = view.make_model_form(model_instance=barney)
form.validated = {'username': 'barney', 'roles': {others.uuid}}
with patch.object(view, 'Session', return_value=self.session):
form.validated = {"username": "barney", "roles": {others.uuid}}
with patch.object(view, "Session", return_value=self.session):
user = view.objectify(form)
self.assertIs(user, barney)
self.assertEqual(len(user.roles), 1)
@ -199,19 +201,27 @@ class TestUserView(WebTestCase):
# person is auto-created
self.assertIsNone(barney.person)
form = view.make_model_form(model_instance=barney)
form.validated = {'username': 'barney', 'first_name': 'Barney', 'last_name': 'Rubble'}
with patch.object(view, 'Session', return_value=self.session):
form.validated = {
"username": "barney",
"first_name": "Barney",
"last_name": "Rubble",
}
with patch.object(view, "Session", return_value=self.session):
user = view.objectify(form)
self.assertIsNotNone(barney.person)
self.assertEqual(barney.person.first_name, 'Barney')
self.assertEqual(barney.person.last_name, 'Rubble')
self.assertEqual(barney.person.full_name, 'Barney Rubble')
self.assertEqual(barney.person.first_name, "Barney")
self.assertEqual(barney.person.last_name, "Rubble")
self.assertEqual(barney.person.full_name, "Barney Rubble")
# person is auto-removed
self.assertIsNotNone(barney.person)
form = view.make_model_form(model_instance=barney)
form.validated = {'username': 'barney', 'first_name': '', 'last_name': ''}
with patch.object(view, 'Session', return_value=self.session):
form.validated = {
"username": "barney",
"first_name": "",
"last_name": "",
}
with patch.object(view, "Session", return_value=self.session):
user = view.objectify(form)
self.assertIsNone(barney.person)
@ -219,37 +229,45 @@ class TestUserView(WebTestCase):
barney.person = self.session.query(model.Person).one()
# person name is updated
self.assertEqual(barney.person.first_name, 'Barney')
self.assertEqual(barney.person.last_name, 'Rubble')
self.assertEqual(barney.person.full_name, 'Barney Rubble')
self.assertEqual(barney.person.first_name, "Barney")
self.assertEqual(barney.person.last_name, "Rubble")
self.assertEqual(barney.person.full_name, "Barney Rubble")
form = view.make_model_form(model_instance=barney)
form.validated = {'username': 'barney', 'first_name': 'Fred', 'last_name': 'Flintstone'}
with patch.object(view, 'Session', return_value=self.session):
form.validated = {
"username": "barney",
"first_name": "Fred",
"last_name": "Flintstone",
}
with patch.object(view, "Session", return_value=self.session):
user = view.objectify(form)
self.assertIsNotNone(barney.person)
self.assertEqual(barney.person.first_name, 'Fred')
self.assertEqual(barney.person.last_name, 'Flintstone')
self.assertEqual(barney.person.full_name, 'Fred Flintstone')
self.assertEqual(barney.person.first_name, "Fred")
self.assertEqual(barney.person.last_name, "Flintstone")
self.assertEqual(barney.person.full_name, "Fred Flintstone")
with patch.object(view, 'creating', new=True):
with patch.object(view, "creating", new=True):
# person is auto-created when making new user
form = view.make_model_form()
form.validated = {'username': 'betty', 'first_name': 'Betty', 'last_name': 'Boop'}
with patch.object(view, 'Session', return_value=self.session):
form.validated = {
"username": "betty",
"first_name": "Betty",
"last_name": "Boop",
}
with patch.object(view, "Session", return_value=self.session):
user = view.objectify(form)
self.assertIsNotNone(user.person)
self.assertEqual(user.person.first_name, 'Betty')
self.assertEqual(user.person.last_name, 'Boop')
self.assertEqual(user.person.full_name, 'Betty Boop')
self.assertEqual(user.person.first_name, "Betty")
self.assertEqual(user.person.last_name, "Boop")
self.assertEqual(user.person.full_name, "Betty Boop")
# nb. keep ref to last user
last_user = user
# person is *not* auto-created if no name provided
form = view.make_model_form()
form.validated = {'username': 'betty', 'first_name': '', 'last_name': ''}
with patch.object(view, 'Session', return_value=self.session):
form.validated = {"username": "betty", "first_name": "", "last_name": ""}
with patch.object(view, "Session", return_value=self.session):
user = view.objectify(form)
self.assertIsNone(user.person)
self.assertIsNot(user, last_user)
@ -264,20 +282,20 @@ class TestUserView(WebTestCase):
self.session.add(blokes)
others = model.Role(name="Others")
self.session.add(others)
barney = model.User(username='barney')
barney = model.User(username="barney")
barney.roles.append(blokes)
self.session.add(barney)
self.session.commit()
view = self.make_view()
view.editing = True
self.request.matchdict = {'uuid': barney.uuid}
self.request.matchdict = {"uuid": barney.uuid}
# no error if data is missing roles
form = view.make_model_form(model_instance=barney)
form.validated = {'username': 'barneyx'}
form.validated = {"username": "barneyx"}
user = view.objectify(form)
self.assertIs(user, barney)
self.assertEqual(barney.username, 'barneyx')
self.assertEqual(barney.username, "barneyx")
# sanity check, user is just in 'blokes' role
self.session.refresh(barney)
@ -289,9 +307,11 @@ class TestUserView(WebTestCase):
# - authed / anon roles are not added
# - admin role not added if current user is not root
form = view.make_model_form(model_instance=barney)
form.validated = {'username': 'barney',
'roles': {admin.uuid, authed.uuid, anon.uuid, others.uuid}}
with patch.object(view, 'Session', return_value=self.session):
form.validated = {
"username": "barney",
"roles": {admin.uuid, authed.uuid, anon.uuid, others.uuid},
}
with patch.object(view, "Session", return_value=self.session):
user = view.objectify(form)
self.assertIs(user, barney)
self.assertEqual(len(user.roles), 1)
@ -302,9 +322,11 @@ class TestUserView(WebTestCase):
# - admin role is added if current user is root
self.request.is_root = True
form = view.make_model_form(model_instance=barney)
form.validated = {'username': 'barney',
'roles': {admin.uuid, blokes.uuid, others.uuid}}
with patch.object(view, 'Session', return_value=self.session):
form.validated = {
"username": "barney",
"roles": {admin.uuid, blokes.uuid, others.uuid},
}
with patch.object(view, "Session", return_value=self.session):
user = view.objectify(form)
self.assertIs(user, barney)
self.assertEqual(len(user.roles), 3)
@ -314,9 +336,8 @@ class TestUserView(WebTestCase):
# admin role not removed if current user is not root
self.request.is_root = False
form = view.make_model_form(model_instance=barney)
form.validated = {'username': 'barney',
'roles': {blokes.uuid, others.uuid}}
with patch.object(view, 'Session', return_value=self.session):
form.validated = {"username": "barney", "roles": {blokes.uuid, others.uuid}}
with patch.object(view, "Session", return_value=self.session):
user = view.objectify(form)
self.assertIs(user, barney)
self.assertEqual(len(user.roles), 3)
@ -324,9 +345,8 @@ class TestUserView(WebTestCase):
# admin role is removed if current user is root
self.request.is_root = True
form = view.make_model_form(model_instance=barney)
form.validated = {'username': 'barney',
'roles': {blokes.uuid, others.uuid}}
with patch.object(view, 'Session', return_value=self.session):
form.validated = {"username": "barney", "roles": {blokes.uuid, others.uuid}}
with patch.object(view, "Session", return_value=self.session):
user = view.objectify(form)
self.assertIs(user, barney)
self.assertEqual(len(user.roles), 2)
@ -336,27 +356,27 @@ class TestUserView(WebTestCase):
auth = self.app.get_auth_handler()
view = self.make_view()
user = model.User(username='foo')
user = model.User(username="foo")
self.session.add(user)
token = auth.add_api_token(user, 'test token')
token = auth.add_api_token(user, "test token")
self.session.commit()
normal = view.normalize_api_token(token)
self.assertIn('uuid', normal)
self.assertEqual(normal['uuid'], token.uuid.hex)
self.assertIn('description', normal)
self.assertEqual(normal['description'], 'test token')
self.assertIn('created', normal)
self.assertIn("uuid", normal)
self.assertEqual(normal["uuid"], token.uuid.hex)
self.assertIn("description", normal)
self.assertEqual(normal["description"], "test token")
self.assertIn("created", normal)
def test_make_api_tokens_grid(self):
model = self.app.model
auth = self.app.get_auth_handler()
view = self.make_view()
user = model.User(username='foo')
user = model.User(username="foo")
self.session.add(user)
token1 = auth.add_api_token(user, 'test1')
token2 = auth.add_api_token(user, 'test2')
token1 = auth.add_api_token(user, "test1")
token2 = auth.add_api_token(user, "test2")
self.session.commit()
# grid should have 2 records but no tools/actions
@ -367,52 +387,60 @@ class TestUserView(WebTestCase):
self.assertEqual(len(grid.actions), 0)
# create + delete allowed
with patch.object(self.request, 'is_root', new=True):
with patch.object(self.request, "is_root", new=True):
grid = view.make_api_tokens_grid(user)
self.assertEqual(len(grid.tools), 1)
self.assertIn('create', grid.tools)
self.assertIn("create", grid.tools)
self.assertEqual(len(grid.actions), 1)
self.assertEqual(grid.actions[0].key, 'delete')
self.assertEqual(grid.actions[0].key, "delete")
def test_add_api_token(self):
model = self.app.model
view = self.make_view()
user = model.User(username='foo')
user = model.User(username="foo")
self.session.add(user)
self.session.commit()
self.session.refresh(user)
self.assertEqual(len(user.api_tokens), 0)
with patch.object(view, 'Session', return_value=self.session):
with patch.object(self.request, 'matchdict', new={'uuid': user.uuid}):
with patch.object(self.request, 'json_body', create=True,
new={'description': 'testing'}):
with patch.object(view, "Session", return_value=self.session):
with patch.object(self.request, "matchdict", new={"uuid": user.uuid}):
with patch.object(
self.request,
"json_body",
create=True,
new={"description": "testing"},
):
result = view.add_api_token()
self.assertEqual(len(user.api_tokens), 1)
token = user.api_tokens[0]
self.assertEqual(result['token_string'], token.token_string)
self.assertEqual(result['description'], 'testing')
self.assertEqual(result["token_string"], token.token_string)
self.assertEqual(result["description"], "testing")
def test_delete_api_token(self):
model = self.app.model
auth = self.app.get_auth_handler()
view = self.make_view()
user = model.User(username='foo')
user = model.User(username="foo")
self.session.add(user)
token1 = auth.add_api_token(user, 'test1')
token2 = auth.add_api_token(user, 'test2')
token1 = auth.add_api_token(user, "test1")
token2 = auth.add_api_token(user, "test2")
self.session.commit()
self.session.refresh(user)
self.assertEqual(len(user.api_tokens), 2)
with patch.object(view, 'Session', return_value=self.session):
with patch.object(self.request, 'matchdict', new={'uuid': user.uuid}):
with patch.object(view, "Session", return_value=self.session):
with patch.object(self.request, "matchdict", new={"uuid": user.uuid}):
# normal behavior
with patch.object(self.request, 'json_body', create=True,
new={'uuid': token1.uuid.hex}):
with patch.object(
self.request,
"json_body",
create=True,
new={"uuid": token1.uuid.hex},
):
result = view.delete_api_token()
self.assertEqual(result, {})
self.session.refresh(user)
@ -421,17 +449,25 @@ class TestUserView(WebTestCase):
self.assertIs(token, token2)
# token for wrong user
user2 = model.User(username='bar')
user2 = model.User(username="bar")
self.session.add(user2)
token3 = auth.add_api_token(user2, 'test3')
token3 = auth.add_api_token(user2, "test3")
self.session.commit()
with patch.object(self.request, 'json_body', create=True,
new={'uuid': token3.uuid.hex}):
with patch.object(
self.request,
"json_body",
create=True,
new={"uuid": token3.uuid.hex},
):
result = view.delete_api_token()
self.assertEqual(result, {'error': "API token not found"})
self.assertEqual(result, {"error": "API token not found"})
# token not found
with patch.object(self.request, 'json_body', create=True,
new={'uuid': self.app.make_true_uuid().hex}):
with patch.object(
self.request,
"json_body",
create=True,
new={"uuid": self.app.make_true_uuid().hex},
):
result = view.delete_api_token()
self.assertEqual(result, {'error': "API token not found"})
self.assertEqual(result, {"error": "API token not found"})