[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Autocompletion unit tests
commit 6478057edcf83b1cfda1107dd78e290b1c102d0a
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Sat Apr 19 21:04:29 2014 -0700
Autocompletion unit tests
Unit tests for our autocompletion class and helper funtion for determine
options from tor. This didn't uncover any issues with that, but it *did* reveal
a bug with our util module. We didn't make a shallow copy of list config
values, so in place modifications edited the configuration's master value.
---
stem/interpretor/autocomplete.py | 3 +
stem/util/conf.py | 2 +-
test/settings.cfg | 1 +
test/unit/interpretor/__init__.py | 1 +
test/unit/interpretor/autocomplete.py | 130 +++++++++++++++++++++++++++++++++
5 files changed, 136 insertions(+), 1 deletion(-)
diff --git a/stem/interpretor/autocomplete.py b/stem/interpretor/autocomplete.py
index 7007be6..f42084e 100644
--- a/stem/interpretor/autocomplete.py
+++ b/stem/interpretor/autocomplete.py
@@ -19,6 +19,9 @@ def _get_commands(controller, config):
commands = config.get('autocomplete', [])
+ if controller is None:
+ return commands
+
# GETINFO commands. Lines are of the form '[option] -- [description]'. This
# strips '*' from options that accept values.
diff --git a/stem/util/conf.py b/stem/util/conf.py
index c232a2a..254e2a4 100644
--- a/stem/util/conf.py
+++ b/stem/util/conf.py
@@ -678,7 +678,7 @@ class Config(object):
log.debug("Config entry '%s' is expected to be a float, defaulting to '%f'" % (key, default))
val = default
elif isinstance(default, list):
- pass # nothing special to do (already a list)
+ val = list(val) # make a shallow copy
elif isinstance(default, tuple):
val = tuple(val)
elif isinstance(default, dict):
diff --git a/test/settings.cfg b/test/settings.cfg
index 684d40a..cf05541 100644
--- a/test/settings.cfg
+++ b/test/settings.cfg
@@ -184,6 +184,7 @@ test.unit_tests
|test.unit.connection.connect.TestConnect
|test.unit.control.controller.TestControl
|test.unit.interpretor.arguments.TestArgumentParsing
+|test.unit.interpretor.autocomplete.TestAutocompletion
|test.unit.doctest.TestDocumentation
test.integ_tests
diff --git a/test/unit/interpretor/__init__.py b/test/unit/interpretor/__init__.py
index e2ad715..62db05a 100644
--- a/test/unit/interpretor/__init__.py
+++ b/test/unit/interpretor/__init__.py
@@ -4,4 +4,5 @@ Unit tests for the stem's interpretor prompt.
__all__ = [
"arguments",
+ "autocomplete",
]
diff --git a/test/unit/interpretor/autocomplete.py b/test/unit/interpretor/autocomplete.py
new file mode 100644
index 0000000..579f177
--- /dev/null
+++ b/test/unit/interpretor/autocomplete.py
@@ -0,0 +1,130 @@
+import unittest
+
+from stem.interpretor.autocomplete import _get_commands, Autocompleter
+
+try:
+ # added in python 3.3
+ from unittest.mock import Mock
+except ImportError:
+ from mock import Mock
+
+GETINFO_NAMES = """
+info/names -- List of GETINFO options, types, and documentation.
+ip-to-country/* -- Perform a GEOIP lookup
+md/id/* -- Microdescriptors by ID
+""".strip()
+
+GETCONF_NAMES = """
+ExitNodes RouterList
+ExitPolicy LineList
+ExitPolicyRejectPrivate Boolean
+""".strip()
+
+
+class TestAutocompletion(unittest.TestCase):
+ def test_autocomplete_results_from_config(self):
+ """
+ Check that we load autocompletion results from our configuration.
+ """
+
+ commands = _get_commands(None)
+ self.assertTrue('PROTOCOLINFO' in commands)
+ self.assertTrue('/quit' in commands)
+
+ def test_autocomplete_results_from_tor(self):
+ """
+ Check our ability to determine autocompletion results based on our tor
+ instance's capabilities.
+ """
+
+ # Check that when GETINFO requests fail we have base commands, but nothing
+ # with arguments.
+
+ controller = Mock()
+ controller.get_info.return_value = None
+ commands = _get_commands(controller)
+
+ self.assertTrue('GETINFO ' in commands)
+ self.assertTrue('GETCONF ' in commands)
+ self.assertTrue('SIGNAL ' in commands)
+
+ self.assertFalse('GETINFO info/names' in commands)
+ self.assertFalse('GETCONF ExitPolicy' in commands)
+ self.assertFalse('SIGNAL SHUTDOWN' in commands)
+
+ # Now check where we should be able to determine tor's capabilities.
+
+ controller.get_info.side_effect = lambda arg, _: {
+ 'info/names': GETINFO_NAMES,
+ 'config/names': GETCONF_NAMES,
+ 'events/names': 'BW DEBUG INFO NOTICE',
+ 'features/names': 'VERBOSE_NAMES EXTENDED_EVENTS',
+ 'signal/names': 'RELOAD HUP SHUTDOWN',
+ }[arg]
+
+ commands = _get_commands(controller)
+
+ expected = (
+ 'GETINFO info/names',
+ 'GETINFO ip-to-country/',
+ 'GETINFO md/id/',
+
+ 'GETCONF ExitNodes',
+ 'GETCONF ExitPolicy',
+ 'SETCONF ExitPolicy',
+ 'RESETCONF ExitPolicy',
+
+ 'SETEVENTS BW',
+ 'SETEVENTS INFO',
+ 'USEFEATURE VERBOSE_NAMES',
+ 'USEFEATURE EXTENDED_EVENTS',
+ 'SIGNAL RELOAD',
+ 'SIGNAL SHUTDOWN',
+ )
+
+ for result in expected:
+ self.assertTrue(result in commands)
+
+ # We shouldn't include the base commands since we have results with
+ # their arguments.
+
+ self.assertFalse('GETINFO ' in commands)
+ self.assertFalse('GETCONF ' in commands)
+ self.assertFalse('SIGNAL ' in commands)
+
+ def test_autocompleter_match(self):
+ """
+ Exercise our Autocompleter's match method.
+ """
+
+ autocompleter = Autocompleter(None)
+
+ self.assertEqual(['/help'], autocompleter.matches('/help'))
+ self.assertEqual(['/help'], autocompleter.matches('/hel'))
+ self.assertEqual(['/help'], autocompleter.matches('/he'))
+ self.assertEqual(['/help'], autocompleter.matches('/h'))
+ self.assertEqual(['/help', '/events', '/info', '/quit'], autocompleter.matches('/'))
+
+ # check case sensitivity
+
+ self.assertEqual(['/help'], autocompleter.matches('/HELP'))
+ self.assertEqual(['/help'], autocompleter.matches('/HeLp'))
+
+ # check when we shouldn't have any matches
+
+ self.assertEqual([], autocompleter.matches('blarg'))
+
+ def test_autocompleter_complete(self):
+ """
+ Exercise our Autocompleter's complete method.
+ """
+
+ autocompleter = Autocompleter(None)
+
+ self.assertEqual('/help', autocompleter.complete('/', 0))
+ self.assertEqual('/events', autocompleter.complete('/', 1))
+ self.assertEqual('/info', autocompleter.complete('/', 2))
+ self.assertEqual('/quit', autocompleter.complete('/', 3))
+ self.assertEqual(None, autocompleter.complete('/', 4))
+
+ self.assertEqual(None, autocompleter.complete('blarg', 0))
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits