Merge lp:~methanal-developers/methanal/844872-lazy-expander-content-updates into lp:methanal

Proposed by Jonathan Jacobs
Status: Merged
Approved by: Tristan Seligmann
Approved revision: 192
Merged at revision: 191
Proposed branch: lp:~methanal-developers/methanal/844872-lazy-expander-content-updates
Merge into: lp:methanal
Diff against target: 208 lines (+140/-4)
2 files modified
methanal/test/test_widgets.py (+87/-0)
methanal/widgets.py (+53/-4)
To merge this branch: bzr merge lp:~methanal-developers/methanal/844872-lazy-expander-content-updates
Reviewer Review Type Date Requested Status
Tristan Seligmann Approve
Review via email: mp+74747@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Tristan Seligmann (mithrandi) wrote :

getHeaderContent and getExpanderContent should have unit tests; these shouldn't be too hard to set up.

review: Needs Fixing
192. By Jonathan Jacobs

Unit tests.

Revision history for this message
Jonathan Jacobs (jjacobs) wrote :

> getHeaderContent and getExpanderContent should have unit tests; these
> shouldn't be too hard to set up.

Done.

Revision history for this message
Tristan Seligmann (mithrandi) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'methanal/test/test_widgets.py'
2--- methanal/test/test_widgets.py 2010-04-25 13:48:14 +0000
3+++ methanal/test/test_widgets.py 2011-09-09 14:38:49 +0000
4@@ -1,10 +1,14 @@
5 """
6 Unit tests for L{methanal.widgets}.
7 """
8+from functools import partial
9+
10 from twisted.trial import unittest
11
12 from nevow import inevow
13
14+from xmantissa.webtheme import ThemedElement
15+
16 from methanal import widgets, errors
17
18
19@@ -250,3 +254,86 @@
20 self.assertEquals(
21 repr(tabGroup),
22 "<TabGroup id=u'id' title=u'Title' tabs=%r>" % tabs)
23+
24+
25+
26+class ComparableLiveElement(ThemedElement):
27+ """
28+ C{LiveElement} implementing C{__eq__} comparing C{self.value}.
29+ """
30+ def __init__(self, value):
31+ self.value = value
32+
33+
34+ def __eq__(self, other):
35+ try:
36+ return self.value == other.value
37+ except AttributeError:
38+ return False
39+
40+
41+
42+class ExpanderTests(unittest.TestCase):
43+ """
44+ Tests for L{methanal.widgets.Expander}.
45+ """
46+ def test_getContent(self):
47+ """
48+ L{Expander.getContent} returns the content for the specified node ID,
49+ C{KeyError} is raised if an unknown node ID is specified.
50+ """
51+ expander = widgets.Expander(
52+ headerFactory=partial(ComparableLiveElement, u'foo'),
53+ contentFactory=partial(ComparableLiveElement, u'bar'))
54+ self.assertEqual(
55+ expander.getContent(u'header').value, u'foo')
56+ self.assertEqual(
57+ expander.getContent(u'content').value, u'bar')
58+ self.assertRaises(
59+ KeyError, expander.getContent, u'not_a_thing')
60+
61+
62+ def test_lazyHeaderContent(self):
63+ """
64+ L{Expander.getHeaderContent} returns the result of
65+ L{Expander.headerFactory} if C{currentContent == newContent} returns
66+ C{False}, otherwise C{None} is returned.
67+ """
68+ expander = widgets.Expander(
69+ headerFactory=partial(ComparableLiveElement, u'content'),
70+ contentFactory=None)
71+
72+ # Fresh.
73+ content = expander.getHeaderContent()
74+ self.assertNotIdentical(None, content)
75+ self.assertEqual(u'content', content.value)
76+ # Same as last time
77+ self.assertIdentical(None, expander.getHeaderContent())
78+ # New value.
79+ expander.headerFactory = partial(ComparableLiveElement, u'other')
80+ content = expander.getHeaderContent()
81+ self.assertNotIdentical(None, content)
82+ self.assertEqual(u'other', content.value)
83+
84+
85+ def test_lazyExpanderContent(self):
86+ """
87+ L{Expander.getExpanderContent} returns the result of
88+ L{Expander.contentFactory} if C{currentContent == newContent} returns
89+ C{False}, otherwise C{None} is returned.
90+ """
91+ expander = widgets.Expander(
92+ headerFactory=None,
93+ contentFactory=partial(ComparableLiveElement, u'content'))
94+
95+ # Fresh.
96+ content = expander.getExpanderContent()
97+ self.assertNotIdentical(None, content)
98+ self.assertEqual(u'content', content.value)
99+ # Same as last time
100+ self.assertIdentical(None, expander.getExpanderContent())
101+ # New value.
102+ expander.contentFactory = partial(ComparableLiveElement, u'other')
103+ content = expander.getExpanderContent()
104+ self.assertNotIdentical(None, content)
105+ self.assertEqual(u'other', content.value)
106
107=== modified file 'methanal/widgets.py'
108--- methanal/widgets.py 2011-07-11 11:00:11 +0000
109+++ methanal/widgets.py 2011-09-09 14:38:49 +0000
110@@ -1083,6 +1083,10 @@
111
112 @type expanded: C{bool}
113 @ivar expanded: Is the content visible?
114+
115+ @ivar currentHeaderContent: Current header renderable.
116+
117+ @ivar currentExpanderContent: Current header renderable.
118 """
119 fragmentName = 'methanal-expander'
120 jsClass = u'Methanal.Widgets.Expander'
121@@ -1093,6 +1097,8 @@
122 self.headerFactory = headerFactory
123 self.contentFactory = contentFactory
124 self.expanded = expanded
125+ self.currentHeaderContent = None
126+ self.currentExpanderContent = None
127
128
129 def getInitialArguments(self):
130@@ -1101,31 +1107,74 @@
131
132 @expose
133 def getContent(self, nodeID):
134+ """
135+ Get the content for C{nodeID}.
136+
137+ @rtype: I{renderable}
138+ """
139 return {
140 'header': self.getHeaderContent,
141 'content': self.getExpanderContent}[nodeID]()
142
143
144 def getHeaderContent(self):
145+ """
146+ Get the content for the expander header.
147+
148+ The content factory is invoked and its result compared to
149+ L{currentHeaderContent}, with C{__eq__}, if the result is C{True}
150+ then C{None} is returned.
151+
152+ @return: Renderable or C{None} if the content hasn't changed.
153+ """
154 content = self.headerFactory()
155+ if content == self.currentHeaderContent:
156+ return None
157 content.setFragmentParent(self)
158+ self.currentHeaderContent = content
159 return content
160
161
162 def getExpanderContent(self):
163+ """
164+ Get the content for the expander body.
165+
166+ The content factory is invoked and its result compared to
167+ L{currentExpanderContent}, with C{__eq__}, if the result is C{True}
168+ then C{None} is returned.
169+
170+ @return: Renderable or C{None} if the content hasn't changed.
171+ """
172 content = self.contentFactory()
173+ if content == self.currentExpanderContent:
174+ return None
175 content.setFragmentParent(self)
176+ self.currentExpanderContent = content
177 return content
178
179
180 def updateRemoteHeaderContent(self):
181- return self.callRemote(
182- 'setContentFromWidgetInfo', self.getHeaderContent(), u'header')
183+ """
184+ Update the client-side header content.
185+
186+ If L{getHeaderContent} returns C{None} no update is performed.
187+ """
188+ content = self.getHeaderContent()
189+ if content is not None:
190+ return self.callRemote(
191+ 'setContentFromWidgetInfo', content, u'header')
192
193
194 def updateRemoteContent(self):
195- return self.callRemote(
196- 'setContentFromWidgetInfo', self.getExpanderContent(), u'content')
197+ """
198+ Update the client-side body content.
199+
200+ If L{getExpanderContent} returns C{None} no update is performed.
201+ """
202+ content = self.getExpanderContent()
203+ if content is not None:
204+ return self.callRemote(
205+ 'setContentFromWidgetInfo', content, u'content')
206
207
208 @renderer

Subscribers

People subscribed via source and target branches

to all changes: