[tor-commits] [nyx/master] Adding @require_curses decorator

atagar at torproject.org atagar at torproject.org
Fri Apr 8 06:18:49 UTC 2016


commit 60a576541d981ec8304cc91c2cf3f536f9bc7cbb
Author: Damian Johnson <atagar at torproject.org>
Date:   Thu Apr 7 10:34:22 2016 -0700

    Adding @require_curses decorator
    
    Similar to the @require_controller and @require_online of Stem, adding a
    decorator for our tests that do curses operations. This skips the test if the
    screen size is too small, and mocks out a size that works even on my tiny
    netbook.
---
 test/__init__.py | 31 ++++++++++++++++++++++++++++---
 test/popups.py   | 28 ++++++++++++++--------------
 2 files changed, 42 insertions(+), 17 deletions(-)

diff --git a/test/__init__.py b/test/__init__.py
index 705e9b1..b606b4a 100644
--- a/test/__init__.py
+++ b/test/__init__.py
@@ -9,7 +9,6 @@ import unittest
 import nyx.curses
 
 from nyx import expand_path, join, uses_settings
-
 from mock import patch, Mock
 
 __all__ = [
@@ -20,13 +19,39 @@ __all__ = [
   'tracker',
 ]
 
-# If set we make test content we render for this many seconds.
+SHOW_RENDERED_CONTENT = None  # if set, tests render content this many seconds
 
-SHOW_RENDERED_CONTENT = None
+OUR_SCREEN_SIZE = None
+TEST_SCREEN_SIZE = nyx.curses.Dimensions(80, 25)
 
 RenderResult = collections.namedtuple('RenderResult', ['content', 'return_value', 'runtime'])
 
 
+def require_curses(func):
+  """
+  Skips the test unless curses is available with a minimal dimension needed by
+  our tests.
+  """
+
+  if OUR_SCREEN_SIZE is None:
+    def _check_screen_size():
+      global OUR_SCREEN_SIZE
+      OUR_SCREEN_SIZE = nyx.curses.screen_size()
+
+    nyx.curses.start(_check_screen_size)
+
+  def wrapped(self, *args, **kwargs):
+    if OUR_SCREEN_SIZE.width < TEST_SCREEN_SIZE.width:
+      self.skipTest("screen isn't wide enough")
+    elif OUR_SCREEN_SIZE.height < TEST_SCREEN_SIZE.height:
+      self.skipTest("screen isn't tall enough")
+    else:
+      with patch('nyx.curses.screen_size', Mock(return_value = TEST_SCREEN_SIZE)):
+        return func(self, *args, **kwargs)
+
+  return wrapped
+
+
 def render(func, *args, **kwargs):
   """
   Runs the given curses function, providing content that's rendered on the
diff --git a/test/popups.py b/test/popups.py
index 0394003..f38cb45 100644
--- a/test/popups.py
+++ b/test/popups.py
@@ -5,10 +5,12 @@ Unit tests for nyx.popups.
 import curses
 import unittest
 
+import nyx.curses
 import nyx.panel
 import nyx.popups
 import test
 
+from test import require_curses
 from mock import patch, Mock
 
 EXPECTED_HELP_POPUP = """
@@ -187,15 +189,13 @@ Consensus Descriptor (29787760145CD1A473552A2FC64C72A9A130820E):---------------+
 | 20 -----BEGIN SIGNATURE-----                                                 |
 | 21 EUFm38gONCoDuY7ZWHyJtBKuvk6Xi1MPuKuecS5frP3fX0wiZSrOVcpX0X8J+4Hr          |
 | 22 Fb5i+yuMIAXeEn6UhtjqhhZBbY9PW9GdZOMTH8hJpG+evURyr+10PZq6UElg86rA          |
-| 23 NCGI042p6+7UgCVT1x3WcLnq3ScV//s1wXHrUXa7vi0=                              |
-| 24 -----END SIGNATURE-----                                                   |
 +------------------------------------------------------------------------------+
 """.strip()
 
 
 class TestPopups(unittest.TestCase):
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   @patch('nyx.controller.get_controller')
   def test_help(self, get_controller_mock):
     header_panel = Mock()
@@ -230,20 +230,20 @@ class TestPopups(unittest.TestCase):
     rendered = test.render(nyx.popups.show_help)
     self.assertEqual(EXPECTED_HELP_POPUP, rendered.content)
 
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   def test_about(self):
     rendered = test.render(nyx.popups.show_about)
     self.assertEqual(EXPECTED_ABOUT_POPUP, rendered.content)
 
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   def test_counts_when_empty(self):
     rendered = test.render(nyx.popups.show_counts, 'Client Locales', {})
     self.assertEqual(EXPECTED_EMPTY_COUNTS, rendered.content)
 
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   def test_counts(self):
     clients = {
       'fr': 5,
@@ -256,16 +256,16 @@ class TestPopups(unittest.TestCase):
     rendered = test.render(nyx.popups.show_counts, 'Client Locales', clients, fill_char = '*')
     self.assertEqual(EXPECTED_COUNTS, rendered.content)
 
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   def test_select_from_list(self):
     options = ['each second', '5 seconds', '30 seconds', 'minutely', '15 minute', '30 minute', 'hourly', 'daily']
     rendered = test.render(nyx.popups.select_from_list, 'Update Interval:', options, 'each second')
     self.assertEqual(EXPECTED_LIST_SELECTOR, rendered.content)
     self.assertEqual('each second', rendered.return_value)
 
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   def test_select_sort_order(self):
     previous_order = ['Man Page Entry', 'Name', 'Is Set']
     options = ['Name', 'Value', 'Value Type', 'Category', 'Usage', 'Summary', 'Description', 'Man Page Entry', 'Is Set']
@@ -274,8 +274,8 @@ class TestPopups(unittest.TestCase):
     self.assertEqual(EXPECTED_SORT_DIALOG_START, rendered.content)
     self.assertEqual(None, rendered.return_value)
 
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   def test_select_sort_order_usage(self):
     # Use the dialog to make a selection. At the end we render two options as
     # being selected (rather than three) because the act of selecing the third
@@ -299,24 +299,24 @@ class TestPopups(unittest.TestCase):
     self.assertEqual(EXPECTED_SORT_DIALOG_END, rendered.content)
     self.assertEqual(['Name', 'Summary', 'Description'], rendered.return_value)
 
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   @patch('nyx.controller.input_prompt', Mock(return_value = None))
   def test_select_event_types_when_canceled(self):
     rendered = test.render(nyx.popups.select_event_types)
     self.assertEqual(EXPECTED_EVENT_SELECTOR, rendered.content)
     self.assertEqual(None, rendered.return_value)
 
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   @patch('nyx.controller.input_prompt', Mock(return_value = '2bwe'))
   def test_select_event_types_with_input(self):
     rendered = test.render(nyx.popups.select_event_types)
     self.assertEqual(EXPECTED_EVENT_SELECTOR, rendered.content)
     self.assertEqual(set(['NYX_INFO', 'ERR', 'WARN', 'BW', 'NYX_ERR', 'NYX_WARN', 'NYX_NOTICE']), rendered.return_value)
 
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   def test_confirm_save_torrc(self):
     rendered = test.render(nyx.popups.confirm_save_torrc, TORRC)
     self.assertEqual(EXPECTED_SAVE_TORRC_CONFIRMATION, rendered.content)
@@ -330,15 +330,15 @@ class TestPopups(unittest.TestCase):
     self.assertEqual(EXPECTED_SAVE_TORRC_CONFIRMATION, rendered.content)
     self.assertEqual(True, rendered.return_value)
 
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   def test_descriptor_without_fingerprint(self):
     rendered = test.render(nyx.popups.show_descriptor, None, nyx.curses.Color.RED, lambda key: key.match('esc'))
     self.assertEqual(EXPECTED_DESCRIPTOR_WITHOUT_FINGERPRINT, rendered.content)
     self.assertEqual(nyx.curses.KeyInput(27), rendered.return_value)
 
+  @require_curses
   @patch('nyx.popups._top', Mock(return_value = 0))
-  @patch('nyx.curses.screen_size', Mock(return_value = nyx.curses.Dimensions(80, 60)))
   @patch('nyx.popups._descriptor_text', Mock(return_value = DESCRIPTOR_TEXT))
   def test_descriptor(self):
     rendered = test.render(nyx.popups.show_descriptor, '29787760145CD1A473552A2FC64C72A9A130820E', nyx.curses.Color.RED, lambda key: key.match('esc'))



More information about the tor-commits mailing list