Commit ce02817c authored by Barry Warsaw's avatar Barry Warsaw

Clean up of style test code, along with refactoring of corner cases to

unittests where they belong.
parent 3fe7d15a
......@@ -43,6 +43,7 @@ Table of Contents
src/mailman/model/docs/*
src/mailman/core/docs/*
src/mailman/app/docs/*
src/mailman/styles/docs/*
src/mailman/runners/docs/*
src/mailman/pipeline/docs/*
src/mailman/rest/docs/*
......
......@@ -21,6 +21,7 @@ from __future__ import absolute_import, unicode_literals
__metaclass__ = type
__all__ = [
'TestUser',
]
......@@ -36,6 +37,8 @@ from mailman.utilities.datetime import now
class TestUser(unittest.TestCase):
"""Test users."""
layer = ConfigLayer
def setUp(self):
......
......@@ -2,9 +2,10 @@
List styles
===========
List styles are a way to name and apply a canned collection of attribute
settings. Every style has a name, which must be unique within the context of
a specific style manager. There is usually only one global style manager.
List styles are a way to name and apply a template of attribute settings to
new mailing lists. Every style has a name, which must be unique within the
context of a specific style manager. There is usually only one global style
manager.
Styles also have a priority, which allows you to specify the order in which
multiple styles will be applied. A style has a `match` function which is used
......@@ -22,26 +23,26 @@ Let's start with a vanilla mailing list and a default style manager.
>>> from mailman.styles.manager import StyleManager
>>> style_manager = StyleManager()
>>> style_manager.populate()
>>> sorted(style.name for style in style_manager.styles)
['default']
>>> styles = sorted(style.name for style in style_manager.styles)
>>> len(styles)
1
>>> print styles[0]
default
The default style
=================
There is a default style which implements the legacy application of list
defaults from previous versions of Mailman. This style only matching a
mailing list when no other styles match, and it has the lowest priority. The
low priority means that it is matched last and if it matches, it is applied
last.
There is a default style which implements a legacy style roughly corresponding
to discussion mailing lists. This style matches when no other styles match,
and it has the lowest priority. The low priority means that it is matched
last and if it matches, it is applied last.
>>> default_style = style_manager.get('default')
>>> default_style.name
'default'
>>> print default_style.name
default
>>> default_style.priority
0
>>> sorted(style.name for style in style_manager.styles)
['default']
Given a mailing list, you can ask the style manager to find all the styles
that match the list. The registered styles will be sorted by decreasing
......@@ -49,8 +50,11 @@ priority and each style's ``match()`` method will be called in turn. The
sorted list of matching styles will be returned -- but not applied -- by the
style manager's ``lookup()`` method.
>>> [style.name for style in style_manager.lookup(mlist)]
['default']
>>> matched_styles = [style.name for style in style_manager.lookup(mlist)]
>>> len(matched_styles)
1
>>> print matched_styles[0]
default
Registering styles
......@@ -60,13 +64,13 @@ New styles must implement the ``IStyle`` interface.
>>> from zope.interface import implements
>>> from mailman.interfaces.styles import IStyle
>>> class TestStyle(object):
>>> class TestStyle:
... implements(IStyle)
... name = 'test'
... priority = 10
... def apply(self, mailing_list):
... # Just does something very simple.
... mailing_list.msg_footer = 'test footer'
... mailing_list.style_thing = 'thing 1'
... def match(self, mailing_list, styles):
... # Applies to any test list
... if 'test' in mailing_list.fqdn_listname:
......@@ -76,16 +80,20 @@ You can register a new style with the style manager.
>>> style_manager.register(TestStyle())
And now if you lookup matching styles, you should find only the new test
And now if you look up matching styles, you should find only the new test
style. This is because the default style only gets applied when no other
styles match the mailing list.
>>> sorted(style.name for style in style_manager.lookup(mlist))
[u'test']
>>> matched_styles = sorted(
... style.name for style in style_manager.lookup(mlist))
>>> len(matched_styles)
1
>>> print matched_styles[0]
test
>>> for style in style_manager.lookup(mlist):
... style.apply(mlist)
>>> print mlist.msg_footer
test footer
>>> print mlist.style_thing
thing 1
Style priority
......@@ -101,16 +109,16 @@ applied last.
... priority = 5
... # Use the base class's match() method.
... def apply(self, mailing_list):
... mailing_list.msg_footer = 'another footer'
... mailing_list.style_thing = 'thing 2'
>>> mlist.msg_footer = ''
>>> mlist.msg_footer
u''
>>> mlist.style_thing = 'thing 0'
>>> print mlist.style_thing
thing 0
>>> style_manager.register(AnotherTestStyle())
>>> for style in style_manager.lookup(mlist):
... style.apply(mlist)
>>> print mlist.msg_footer
another footer
>>> print mlist.style_thing
thing 2
You can change the priority of a style, and if you reapply the styles, they
will take effect in the new priority order.
......@@ -121,8 +129,8 @@ will take effect in the new priority order.
>>> style_2.priority = 10
>>> for style in style_manager.lookup(mlist):
... style.apply(mlist)
>>> print mlist.msg_footer
test footer
>>> print mlist.style_thing
thing 1
Unregistering styles
......@@ -131,32 +139,9 @@ Unregistering styles
You can unregister a style, making it unavailable in the future.
>>> style_manager.unregister(style_2)
>>> sorted(style.name for style in style_manager.lookup(mlist))
[u'test']
Corner cases
============
If you register a style with the same name as an already registered style, you
get an exception.
>>> style_manager.register(TestStyle())
Traceback (most recent call last):
...
DuplicateStyleError: test
If you try to register an object that isn't a style, you get an exception.
>>> style_manager.register(object())
Traceback (most recent call last):
...
DoesNotImplement: An object does not implement interface
<InterfaceClass mailman.interfaces.styles.IStyle>
If you try to unregister a style that isn't registered, you get an exception.
>>> style_manager.unregister(style_2)
Traceback (most recent call last):
...
KeyError: u'another'
>>> matched_styles = sorted(
... style.name for style in style_manager.lookup(mlist))
>>> len(matched_styles)
1
>>> print matched_styles[0]
test
# Copyright (C) 2012 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
# GNU Mailman is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
"""Test styles."""
from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
'TestStyle',
]
import unittest
from zope.component import getUtility
from zope.interface import implements
from zope.interface.exceptions import DoesNotImplement
from mailman.interfaces.styles import (
DuplicateStyleError, IStyle, IStyleManager)
from mailman.testing.layers import ConfigLayer
class DummyStyle:
implements(IStyle)
name = 'dummy'
priority = 1
def apply(self, mlist):
pass
def match(self, mlist, styles):
styles.append(self)
class TestStyle(unittest.TestCase):
"""Test styles."""
layer = ConfigLayer
def setUp(self):
self.manager = getUtility(IStyleManager)
def test_register_style_again(self):
# Registering a style with the same name as a previous style raises an
# exception.
self.manager.register(DummyStyle())
try:
self.manager.register(DummyStyle())
except DuplicateStyleError:
pass
else:
raise AssertionError('DuplicateStyleError exception expected')
def test_register_a_non_style(self):
# You can't register something that doesn't implement the IStyle
# interface.
try:
self.manager.register(object())
except DoesNotImplement:
pass
else:
raise AssertionError('DoesNotImplement exception expected')
def test_unregister_a_non_registered_style(self):
# You cannot unregister a style that hasn't yet been registered.
try:
self.manager.unregister(DummyStyle())
except KeyError:
pass
else:
raise AssertionError('KeyError expected')
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment