Revision: 143
Author: janne.t.harkonen
Date: Wed Aug 22 21:55:10 2012
Log: Add Configuration class
http://code.google.com/p/robotframework-sshlibrary/source/detail?r=143
Added:
/trunk/src/SSHLibrary/config.py
/trunk/utest/test_config.py
=======================================
--- /dev/null
+++ /trunk/src/SSHLibrary/config.py Wed Aug 22 21:55:10 2012
@@ -0,0 +1,106 @@
+from robot import utils
+
+
+class ConfigurationException(Exception):
+ """Raised when creating, updating or accessing a Configuration entry
fails."""
+ pass
+
+
+class Configuration(object):
+ """A simple configuration class.
+
+ Configuration is defined with keyword arguments, in which the value
must
+ be an instance of :py:class:`Entry`. Different subclasses of `Entry`
can
+ be used to handle common types and conversions.
+
+ Example::
+
+ cfg = Configuration(name=StringEntry('initial'),
+ age=IntegerEntry('42'))
+ assert cfg.name == initial
+ assert cfg.age == 42
+ cfg.update(name='John Doe')
+ assert cfg.name == 'John Doe'
+ """
+
+ def __init__(self, **config):
+ self._config = config
+
+ def update(self, **config):
+ """Update configuration entries. See `__init__` for an example."""
+ for name in config:
+ self._config[name].set(config[name])
+
+ def __getattr__(self, name):
+ if name in self._config:
+ return self._config[name].value
+ msg = "Configuration parameter '%s' is not defined" % name
+ raise ConfigurationException(msg)
+
+
+class Entry(object):
+ """A base class for values stored in :py:class:`Configuration`.
+
+ :param:`initial` the initial value of this entry.
+ """
+
+ def __init__(self, initial=None):
+ self._value = self._create_value(initial)
+
+ @property
+ def value(self):
+ return self._value
+
+ def set(self, value):
+ self._value = self._parse_value(value)
+
+ def _create_value(self, value):
+ if value is None:
+ return None
+ return self._parse_value(value)
+
+
+class StringEntry(Entry):
+ """String value to be stored in :py:class:`Configuration`."""
+ def _parse_value(self, value):
+ return value
+
+
+class IntegerEntry(Entry):
+ """Integer value to be stored in stored in :py:class:`Configuration`.
+
+ Given value is converted to string using `int()`.
+ """
+ def _parse_value(self, value):
+ return int(value)
+
+
+class TimeEntry(Entry):
+ """Time string to be stored in :py:class:`Configuration`.
+
+ Given time string will be converted to seconds using
+ :py:func:`robot.utils.timestr_to_secs`.
+ """
+ def _parse_value(self, value):
+ return utils.timestr_to_secs(value) if value else None
+
+
+class LogLevelEntry(Entry):
+ """Log level to be stored in :py:class:`Configuration`.
+
+ Given string must be on of 'TRACE', 'DEBUG', 'INFO' or 'WARN', case
+ insensitively.
+ """
+ def _parse_value(self, value):
+ return value.upper()
+
+
+class NewlineEntry(Entry):
+ """New line sequence to be stored in :py:class:`Configuration`.
+
+ Following conversion are performed on the given string:
+ * 'LF' -> '\n'
+ * 'CR' -> '\r'
+ """
+ def _parse_value(self, value):
+ return value.upper().replace('LF', '\n').replace('CR', '\r')
=======================================
--- /dev/null
+++ /trunk/utest/test_config.py Wed Aug 22 21:55:10 2012
@@ -0,0 +1,61 @@
+import unittest
+from SSHLibrary.config import (Configuration, StringEntry, TimeEntry,
+ IntegerEntry, LogLevelEntry, NewlineEntry, ConfigurationException)
+
+
+STRING_VALUE = 'some value'
+INTEGER_STRING = '42'
+INTEGER_VALUE = 42
+TIME_STRING = '3 minutes 25 seconds'
+TIME = 205
+
+
+class TestConfigurationEntries(unittest.TestCase):
+
+ def test_creating_with_initial_value(self):
+ entry = StringEntry(initial=STRING_VALUE)
+ self._assert_entry(entry, STRING_VALUE)
+
+ def test_setting_value(self):
+ entry = StringEntry()
+ entry.set(STRING_VALUE)
+ self._assert_entry(entry, STRING_VALUE)
+
+ def test_integer_entry(self):
+ entry = IntegerEntry(INTEGER_STRING)
+ self._assert_entry(entry, INTEGER_VALUE)
+
+ def test_time_entry(self):
+ entry = TimeEntry(TIME_STRING)
+ self._assert_entry(entry, 205)
+
+ def test_log_level_entry(self):
+ entry = LogLevelEntry('debug')
+ self._assert_entry(entry, 'DEBUG')
+
+ def test_newline_entry(self):
+ entry = NewlineEntry('crlf')
+ self._assert_entry(entry, '\r\n')
+
+ def _assert_entry(self, entry, expected_value):
+ self.assertEquals(entry.value, expected_value)
+
+
+class TestConfiguration(unittest.TestCase):
+
+ def test_creating_configuration(self):
+ cfg = Configuration(name=StringEntry(STRING_VALUE))
+ self.assertEquals(cfg.name, STRING_VALUE)
+
+ def test_updating_configuration_values(self):
+ cfg = Configuration(entry=StringEntry('other value'))
+ cfg.update(entry=STRING_VALUE)
+ self.assertEquals(cfg.entry, STRING_VALUE)
+
+ def test_missing_config_item(self):
+ self.assertRaises(ConfigurationException,
+ lambda: Configuration().missing)
+
+
+if __name__ == '__main__':
+ unittest.main()