##// END OF EJS Templates
update 'tools and libraries available...' example in doc
MinRK -
Show More
@@ -1,368 +1,368 b''
1 .. _testing:
1 .. _testing:
2
2
3 ==========================================
3 ==========================================
4 Testing IPython for users and developers
4 Testing IPython for users and developers
5 ==========================================
5 ==========================================
6
6
7 Overview
7 Overview
8 ========
8 ========
9
9
10 It is extremely important that all code contributed to IPython has tests.
10 It is extremely important that all code contributed to IPython has tests.
11 Tests should be written as unittests, doctests or other entities that the
11 Tests should be written as unittests, doctests or other entities that the
12 IPython test system can detect. See below for more details on this.
12 IPython test system can detect. See below for more details on this.
13
13
14 Each subpackage in IPython should have its own :file:`tests` directory that
14 Each subpackage in IPython should have its own :file:`tests` directory that
15 contains all of the tests for that subpackage. All of the files in the
15 contains all of the tests for that subpackage. All of the files in the
16 :file:`tests` directory should have the word "tests" in them to enable
16 :file:`tests` directory should have the word "tests" in them to enable
17 the testing framework to find them.
17 the testing framework to find them.
18
18
19 In docstrings, examples (either using IPython prompts like ``In [1]:`` or
19 In docstrings, examples (either using IPython prompts like ``In [1]:`` or
20 'classic' python ``>>>`` ones) can and should be included. The testing system
20 'classic' python ``>>>`` ones) can and should be included. The testing system
21 will detect them as doctests and will run them; it offers control to skip parts
21 will detect them as doctests and will run them; it offers control to skip parts
22 or all of a specific doctest if the example is meant to be informative but
22 or all of a specific doctest if the example is meant to be informative but
23 shows non-reproducible information (like filesystem data).
23 shows non-reproducible information (like filesystem data).
24
24
25 If a subpackage has any dependencies beyond the Python standard library, the
25 If a subpackage has any dependencies beyond the Python standard library, the
26 tests for that subpackage should be skipped if the dependencies are not found.
26 tests for that subpackage should be skipped if the dependencies are not found.
27 This is very important so users don't get tests failing simply because they
27 This is very important so users don't get tests failing simply because they
28 don't have dependencies.
28 don't have dependencies.
29
29
30 The testing system we use is an extension of the nose_ test runner.
30 The testing system we use is an extension of the nose_ test runner.
31 In particular we've
31 In particular we've
32 developed a nose plugin that allows us to paste verbatim IPython sessions and
32 developed a nose plugin that allows us to paste verbatim IPython sessions and
33 test them as doctests, which is extremely important for us.
33 test them as doctests, which is extremely important for us.
34
34
35 .. _nose: http://code.google.com/p/python-nose
35 .. _nose: http://code.google.com/p/python-nose
36
36
37
37
38 For the impatient: running the tests
38 For the impatient: running the tests
39 ====================================
39 ====================================
40
40
41 You can run IPython from the source download directory without even installing
41 You can run IPython from the source download directory without even installing
42 it system-wide or having configure anything, by typing at the terminal:
42 it system-wide or having configure anything, by typing at the terminal:
43
43
44 .. code-block:: bash
44 .. code-block:: bash
45
45
46 python ipython.py
46 python ipython.py
47
47
48 In order to run the test suite, you must at least be able to import IPython,
48 In order to run the test suite, you must at least be able to import IPython,
49 even if you haven't fully installed the user-facing scripts yet (common in a
49 even if you haven't fully installed the user-facing scripts yet (common in a
50 development environment). You can then run the tests with:
50 development environment). You can then run the tests with:
51
51
52 .. code-block:: bash
52 .. code-block:: bash
53
53
54 python -c "import IPython; IPython.test()"
54 python -c "import IPython; IPython.test()"
55
55
56 Once you have installed IPython either via a full install or using:
56 Once you have installed IPython either via a full install or using:
57
57
58 .. code-block:: bash
58 .. code-block:: bash
59
59
60 python setup.py develop
60 python setup.py develop
61
61
62 you will have available a system-wide script called :file:`iptest` that runs
62 you will have available a system-wide script called :file:`iptest` that runs
63 the full test suite. You can then run the suite with:
63 the full test suite. You can then run the suite with:
64
64
65 .. code-block:: bash
65 .. code-block:: bash
66
66
67 iptest [args]
67 iptest [args]
68
68
69
69
70 Regardless of how you run things, you should eventually see something like:
70 Regardless of how you run things, you should eventually see something like:
71
71
72 .. code-block:: bash
72 .. code-block:: bash
73
73
74 **********************************************************************
74 **********************************************************************
75 Test suite completed for system with the following information:
75 Test suite completed for system with the following information:
76 {'commit_hash': '144fdae',
76 {'commit_hash': '144fdae',
77 'commit_source': 'repository',
77 'commit_source': 'repository',
78 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython',
78 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython',
79 'ipython_version': '0.11.dev',
79 'ipython_version': '0.11.dev',
80 'os_name': 'posix',
80 'os_name': 'posix',
81 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick',
81 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick',
82 'sys_executable': '/usr/bin/python',
82 'sys_executable': '/usr/bin/python',
83 'sys_platform': 'linux2',
83 'sys_platform': 'linux2',
84 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \n[GCC 4.4.5]'}
84 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \n[GCC 4.4.5]'}
85
85
86 Tools and libraries available at test time:
86 Tools and libraries available at test time:
87 curses foolscap gobject gtk pexpect twisted wx wx.aui zope.interface
87 curses matplotlib pymongo qt sqlite3 tornado wx wx.aui zmq
88
88
89 Ran 9 test groups in 67.213s
89 Ran 9 test groups in 67.213s
90
90
91 Status:
91 Status:
92 OK
92 OK
93
93
94
94
95 If not, there will be a message indicating which test group failed and how to
95 If not, there will be a message indicating which test group failed and how to
96 rerun that group individually. For example, this tests the
96 rerun that group individually. For example, this tests the
97 :mod:`IPython.utils` subpackage, the :option:`-v` option shows progress
97 :mod:`IPython.utils` subpackage, the :option:`-v` option shows progress
98 indicators:
98 indicators:
99
99
100 .. code-block:: bash
100 .. code-block:: bash
101
101
102 $ iptest -v IPython.utils
102 $ iptest -v IPython.utils
103 ..........................SS..SSS............................S.S...
103 ..........................SS..SSS............................S.S...
104 .........................................................
104 .........................................................
105 ----------------------------------------------------------------------
105 ----------------------------------------------------------------------
106 Ran 125 tests in 0.119s
106 Ran 125 tests in 0.119s
107
107
108 OK (SKIP=7)
108 OK (SKIP=7)
109
109
110
110
111 Because the IPython test machinery is based on nose, you can use all nose
111 Because the IPython test machinery is based on nose, you can use all nose
112 options and syntax, typing ``iptest -h`` shows all available options. For
112 options and syntax, typing ``iptest -h`` shows all available options. For
113 example, this lets you run the specific test :func:`test_rehashx` inside the
113 example, this lets you run the specific test :func:`test_rehashx` inside the
114 :mod:`test_magic` module:
114 :mod:`test_magic` module:
115
115
116 .. code-block:: bash
116 .. code-block:: bash
117
117
118 $ iptest -vv IPython.core.tests.test_magic:test_rehashx
118 $ iptest -vv IPython.core.tests.test_magic:test_rehashx
119 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
119 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
120 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
120 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
121
121
122 ----------------------------------------------------------------------
122 ----------------------------------------------------------------------
123 Ran 2 tests in 0.100s
123 Ran 2 tests in 0.100s
124
124
125 OK
125 OK
126
126
127 When developing, the :option:`--pdb` and :option:`--pdb-failures` of nose are
127 When developing, the :option:`--pdb` and :option:`--pdb-failures` of nose are
128 particularly useful, these drop you into an interactive pdb session at the
128 particularly useful, these drop you into an interactive pdb session at the
129 point of the error or failure respectively.
129 point of the error or failure respectively.
130
130
131 .. note::
131 .. note::
132
132
133 The system information summary printed above is accessible from the top
133 The system information summary printed above is accessible from the top
134 level package. If you encounter a problem with IPython, it's useful to
134 level package. If you encounter a problem with IPython, it's useful to
135 include this information when reporting on the mailing list; use::
135 include this information when reporting on the mailing list; use::
136
136
137 from IPython import sys_info
137 from IPython import sys_info
138 print sys_info()
138 print sys_info()
139
139
140 and include the resulting information in your query.
140 and include the resulting information in your query.
141
141
142 For developers: writing tests
142 For developers: writing tests
143 =============================
143 =============================
144
144
145 By now IPython has a reasonable test suite, so the best way to see what's
145 By now IPython has a reasonable test suite, so the best way to see what's
146 available is to look at the :file:`tests` directory in most subpackages. But
146 available is to look at the :file:`tests` directory in most subpackages. But
147 here are a few pointers to make the process easier.
147 here are a few pointers to make the process easier.
148
148
149
149
150 Main tools: :mod:`IPython.testing`
150 Main tools: :mod:`IPython.testing`
151 ----------------------------------
151 ----------------------------------
152
152
153 The :mod:`IPython.testing` package is where all of the machinery to test
153 The :mod:`IPython.testing` package is where all of the machinery to test
154 IPython (rather than the tests for its various parts) lives. In particular,
154 IPython (rather than the tests for its various parts) lives. In particular,
155 the :mod:`iptest` module in there has all the smarts to control the test
155 the :mod:`iptest` module in there has all the smarts to control the test
156 process. In there, the :func:`make_exclude` function is used to build a
156 process. In there, the :func:`make_exclude` function is used to build a
157 blacklist of exclusions, these are modules that do not get even imported for
157 blacklist of exclusions, these are modules that do not get even imported for
158 tests. This is important so that things that would fail to even import because
158 tests. This is important so that things that would fail to even import because
159 of missing dependencies don't give errors to end users, as we stated above.
159 of missing dependencies don't give errors to end users, as we stated above.
160
160
161 The :mod:`decorators` module contains a lot of useful decorators, especially
161 The :mod:`decorators` module contains a lot of useful decorators, especially
162 useful to mark individual tests that should be skipped under certain conditions
162 useful to mark individual tests that should be skipped under certain conditions
163 (rather than blacklisting the package altogether because of a missing major
163 (rather than blacklisting the package altogether because of a missing major
164 dependency).
164 dependency).
165
165
166 Our nose plugin for doctests
166 Our nose plugin for doctests
167 ----------------------------
167 ----------------------------
168
168
169 The :mod:`plugin` subpackage in testing contains a nose plugin called
169 The :mod:`plugin` subpackage in testing contains a nose plugin called
170 :mod:`ipdoctest` that teaches nose about IPython syntax, so you can write
170 :mod:`ipdoctest` that teaches nose about IPython syntax, so you can write
171 doctests with IPython prompts. You can also mark doctest output with ``#
171 doctests with IPython prompts. You can also mark doctest output with ``#
172 random`` for the output corresponding to a single input to be ignored (stronger
172 random`` for the output corresponding to a single input to be ignored (stronger
173 than using ellipsis and useful to keep it as an example). If you want the
173 than using ellipsis and useful to keep it as an example). If you want the
174 entire docstring to be executed but none of the output from any input to be
174 entire docstring to be executed but none of the output from any input to be
175 checked, you can use the ``# all-random`` marker. The
175 checked, you can use the ``# all-random`` marker. The
176 :mod:`IPython.testing.plugin.dtexample` module contains examples of how to use
176 :mod:`IPython.testing.plugin.dtexample` module contains examples of how to use
177 these; for reference here is how to use ``# random``::
177 these; for reference here is how to use ``# random``::
178
178
179 def ranfunc():
179 def ranfunc():
180 """A function with some random output.
180 """A function with some random output.
181
181
182 Normal examples are verified as usual:
182 Normal examples are verified as usual:
183 >>> 1+3
183 >>> 1+3
184 4
184 4
185
185
186 But if you put '# random' in the output, it is ignored:
186 But if you put '# random' in the output, it is ignored:
187 >>> 1+3
187 >>> 1+3
188 junk goes here... # random
188 junk goes here... # random
189
189
190 >>> 1+2
190 >>> 1+2
191 again, anything goes #random
191 again, anything goes #random
192 if multiline, the random mark is only needed once.
192 if multiline, the random mark is only needed once.
193
193
194 >>> 1+2
194 >>> 1+2
195 You can also put the random marker at the end:
195 You can also put the random marker at the end:
196 # random
196 # random
197
197
198 >>> 1+2
198 >>> 1+2
199 # random
199 # random
200 .. or at the beginning.
200 .. or at the beginning.
201
201
202 More correct input is properly verified:
202 More correct input is properly verified:
203 >>> ranfunc()
203 >>> ranfunc()
204 'ranfunc'
204 'ranfunc'
205 """
205 """
206 return 'ranfunc'
206 return 'ranfunc'
207
207
208 and an example of ``# all-random``::
208 and an example of ``# all-random``::
209
209
210 def random_all():
210 def random_all():
211 """A function where we ignore the output of ALL examples.
211 """A function where we ignore the output of ALL examples.
212
212
213 Examples:
213 Examples:
214
214
215 # all-random
215 # all-random
216
216
217 This mark tells the testing machinery that all subsequent examples
217 This mark tells the testing machinery that all subsequent examples
218 should be treated as random (ignoring their output). They are still
218 should be treated as random (ignoring their output). They are still
219 executed, so if a they raise an error, it will be detected as such,
219 executed, so if a they raise an error, it will be detected as such,
220 but their output is completely ignored.
220 but their output is completely ignored.
221
221
222 >>> 1+3
222 >>> 1+3
223 junk goes here...
223 junk goes here...
224
224
225 >>> 1+3
225 >>> 1+3
226 klasdfj;
226 klasdfj;
227
227
228 In [8]: print 'hello'
228 In [8]: print 'hello'
229 world # random
229 world # random
230
230
231 In [9]: iprand()
231 In [9]: iprand()
232 Out[9]: 'iprand'
232 Out[9]: 'iprand'
233 """
233 """
234 return 'iprand'
234 return 'iprand'
235
235
236
236
237 When writing docstrings, you can use the ``@skip_doctest`` decorator to
237 When writing docstrings, you can use the ``@skip_doctest`` decorator to
238 indicate that a docstring should *not* be treated as a doctest at all. The
238 indicate that a docstring should *not* be treated as a doctest at all. The
239 difference between ``# all-random`` and ``@skip_doctest`` is that the former
239 difference between ``# all-random`` and ``@skip_doctest`` is that the former
240 executes the example but ignores output, while the latter doesn't execute any
240 executes the example but ignores output, while the latter doesn't execute any
241 code. ``@skip_doctest`` should be used for docstrings whose examples are
241 code. ``@skip_doctest`` should be used for docstrings whose examples are
242 purely informational.
242 purely informational.
243
243
244 If a given docstring fails under certain conditions but otherwise is a good
244 If a given docstring fails under certain conditions but otherwise is a good
245 doctest, you can use code like the following, that relies on the 'null'
245 doctest, you can use code like the following, that relies on the 'null'
246 decorator to leave the docstring intact where it works as a test::
246 decorator to leave the docstring intact where it works as a test::
247
247
248 # The docstring for full_path doctests differently on win32 (different path
248 # The docstring for full_path doctests differently on win32 (different path
249 # separator) so just skip the doctest there, and use a null decorator
249 # separator) so just skip the doctest there, and use a null decorator
250 # elsewhere:
250 # elsewhere:
251
251
252 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
252 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
253
253
254 @doctest_deco
254 @doctest_deco
255 def full_path(startPath,files):
255 def full_path(startPath,files):
256 """Make full paths for all the listed files, based on startPath..."""
256 """Make full paths for all the listed files, based on startPath..."""
257
257
258 # function body follows...
258 # function body follows...
259
259
260 With our nose plugin that understands IPython syntax, an extremely effective
260 With our nose plugin that understands IPython syntax, an extremely effective
261 way to write tests is to simply copy and paste an interactive session into a
261 way to write tests is to simply copy and paste an interactive session into a
262 docstring. You can writing this type of test, where your docstring is meant
262 docstring. You can writing this type of test, where your docstring is meant
263 *only* as a test, by prefixing the function name with ``doctest_`` and leaving
263 *only* as a test, by prefixing the function name with ``doctest_`` and leaving
264 its body *absolutely empty* other than the docstring. In
264 its body *absolutely empty* other than the docstring. In
265 :mod:`IPython.core.tests.test_magic` you can find several examples of this, but
265 :mod:`IPython.core.tests.test_magic` you can find several examples of this, but
266 for completeness sake, your code should look like this (a simple case)::
266 for completeness sake, your code should look like this (a simple case)::
267
267
268 def doctest_time():
268 def doctest_time():
269 """
269 """
270 In [10]: %time None
270 In [10]: %time None
271 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
271 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
272 Wall time: 0.00 s
272 Wall time: 0.00 s
273 """
273 """
274
274
275 This function is only analyzed for its docstring but it is not considered a
275 This function is only analyzed for its docstring but it is not considered a
276 separate test, which is why its body should be empty.
276 separate test, which is why its body should be empty.
277
277
278
278
279 Parametric tests done right
279 Parametric tests done right
280 ---------------------------
280 ---------------------------
281
281
282 If you need to run multiple tests inside the same standalone function or method
282 If you need to run multiple tests inside the same standalone function or method
283 of a :class:`unittest.TestCase` subclass, IPython provides the ``parametric``
283 of a :class:`unittest.TestCase` subclass, IPython provides the ``parametric``
284 decorator for this purpose. This is superior to how test generators work in
284 decorator for this purpose. This is superior to how test generators work in
285 nose, because IPython's keeps intact your stack, which makes debugging vastly
285 nose, because IPython's keeps intact your stack, which makes debugging vastly
286 easier. For example, these are some parametric tests both in class form and as
286 easier. For example, these are some parametric tests both in class form and as
287 a standalone function (choose in each situation the style that best fits the
287 a standalone function (choose in each situation the style that best fits the
288 problem at hand, since both work)::
288 problem at hand, since both work)::
289
289
290 from IPython.testing import decorators as dec
290 from IPython.testing import decorators as dec
291
291
292 def is_smaller(i,j):
292 def is_smaller(i,j):
293 assert i<j,"%s !< %s" % (i,j)
293 assert i<j,"%s !< %s" % (i,j)
294
294
295 class Tester(ParametricTestCase):
295 class Tester(ParametricTestCase):
296
296
297 def test_parametric(self):
297 def test_parametric(self):
298 yield is_smaller(3, 4)
298 yield is_smaller(3, 4)
299 x, y = 1, 2
299 x, y = 1, 2
300 yield is_smaller(x, y)
300 yield is_smaller(x, y)
301
301
302 @dec.parametric
302 @dec.parametric
303 def test_par_standalone():
303 def test_par_standalone():
304 yield is_smaller(3, 4)
304 yield is_smaller(3, 4)
305 x, y = 1, 2
305 x, y = 1, 2
306 yield is_smaller(x, y)
306 yield is_smaller(x, y)
307
307
308
308
309 Design requirements
309 Design requirements
310 ===================
310 ===================
311
311
312 This section is a set of notes on the key points of the IPython testing needs,
312 This section is a set of notes on the key points of the IPython testing needs,
313 that were used when writing the system and should be kept for reference as it
313 that were used when writing the system and should be kept for reference as it
314 eveolves.
314 eveolves.
315
315
316 Testing IPython in full requires modifications to the default behavior of nose
316 Testing IPython in full requires modifications to the default behavior of nose
317 and doctest, because the IPython prompt is not recognized to determine Python
317 and doctest, because the IPython prompt is not recognized to determine Python
318 input, and because IPython admits user input that is not valid Python (things
318 input, and because IPython admits user input that is not valid Python (things
319 like ``%magics`` and ``!system commands``.
319 like ``%magics`` and ``!system commands``.
320
320
321 We basically need to be able to test the following types of code:
321 We basically need to be able to test the following types of code:
322
322
323 1. Pure Python files containing normal tests. These are not a problem, since
323 1. Pure Python files containing normal tests. These are not a problem, since
324 Nose will pick them up as long as they conform to the (flexible) conventions
324 Nose will pick them up as long as they conform to the (flexible) conventions
325 used by nose to recognize tests.
325 used by nose to recognize tests.
326
326
327 2. Python files containing doctests. Here, we have two possibilities:
327 2. Python files containing doctests. Here, we have two possibilities:
328
328
329 - The prompts are the usual ``>>>`` and the input is pure Python.
329 - The prompts are the usual ``>>>`` and the input is pure Python.
330 - The prompts are of the form ``In [1]:`` and the input can contain extended
330 - The prompts are of the form ``In [1]:`` and the input can contain extended
331 IPython expressions.
331 IPython expressions.
332
332
333 In the first case, Nose will recognize the doctests as long as it is called
333 In the first case, Nose will recognize the doctests as long as it is called
334 with the ``--with-doctest`` flag. But the second case will likely require
334 with the ``--with-doctest`` flag. But the second case will likely require
335 modifications or the writing of a new doctest plugin for Nose that is
335 modifications or the writing of a new doctest plugin for Nose that is
336 IPython-aware.
336 IPython-aware.
337
337
338 3. ReStructuredText files that contain code blocks. For this type of file, we
338 3. ReStructuredText files that contain code blocks. For this type of file, we
339 have three distinct possibilities for the code blocks:
339 have three distinct possibilities for the code blocks:
340
340
341 - They use ``>>>`` prompts.
341 - They use ``>>>`` prompts.
342 - They use ``In [1]:`` prompts.
342 - They use ``In [1]:`` prompts.
343 - They are standalone blocks of pure Python code without any prompts.
343 - They are standalone blocks of pure Python code without any prompts.
344
344
345 The first two cases are similar to the situation #2 above, except that in
345 The first two cases are similar to the situation #2 above, except that in
346 this case the doctests must be extracted from input code blocks using
346 this case the doctests must be extracted from input code blocks using
347 docutils instead of from the Python docstrings.
347 docutils instead of from the Python docstrings.
348
348
349 In the third case, we must have a convention for distinguishing code blocks
349 In the third case, we must have a convention for distinguishing code blocks
350 that are meant for execution from others that may be snippets of shell code
350 that are meant for execution from others that may be snippets of shell code
351 or other examples not meant to be run. One possibility is to assume that
351 or other examples not meant to be run. One possibility is to assume that
352 all indented code blocks are meant for execution, but to have a special
352 all indented code blocks are meant for execution, but to have a special
353 docutils directive for input that should not be executed.
353 docutils directive for input that should not be executed.
354
354
355 For those code blocks that we will execute, the convention used will simply
355 For those code blocks that we will execute, the convention used will simply
356 be that they get called and are considered successful if they run to
356 be that they get called and are considered successful if they run to
357 completion without raising errors. This is similar to what Nose does for
357 completion without raising errors. This is similar to what Nose does for
358 standalone test functions, and by putting asserts or other forms of
358 standalone test functions, and by putting asserts or other forms of
359 exception-raising statements it becomes possible to have literate examples
359 exception-raising statements it becomes possible to have literate examples
360 that double as lightweight tests.
360 that double as lightweight tests.
361
361
362 4. Extension modules with doctests in function and method docstrings.
362 4. Extension modules with doctests in function and method docstrings.
363 Currently Nose simply can't find these docstrings correctly, because the
363 Currently Nose simply can't find these docstrings correctly, because the
364 underlying doctest DocTestFinder object fails there. Similarly to #2 above,
364 underlying doctest DocTestFinder object fails there. Similarly to #2 above,
365 the docstrings could have either pure python or IPython prompts.
365 the docstrings could have either pure python or IPython prompts.
366
366
367 Of these, only 3-c (reST with standalone code blocks) is not implemented at
367 Of these, only 3-c (reST with standalone code blocks) is not implemented at
368 this point.
368 this point.
General Comments 0
You need to be logged in to leave comments. Login now