[tor-commits] [stem/master] Refactoring version functions into module

atagar at torproject.org atagar at torproject.org
Sat Nov 26 18:28:32 UTC 2011


commit 62ecde1d4432eb96a3346289c8257561baa4faff
Author: Damian Johnson <atagar at torproject.org>
Date:   Fri Nov 25 22:13:56 2011 -0800

    Refactoring version functions into module
    
    Moving the last of the types.py contents and a related function from process.py
    into a module specifically for handling tor versions and requirements (the
    later part will grow as the library matures).
---
 run_tests.py                         |    4 +-
 stem/__init__.py                     |    2 +-
 stem/connection.py                   |   16 ++--
 stem/process.py                      |   48 -----------
 stem/types.py                        |   98 ---------------------
 stem/version.py                      |  156 ++++++++++++++++++++++++++++++++++
 test/integ/socket/control_message.py |    7 +-
 test/unit/connection/protocolinfo.py |    5 +-
 test/unit/types/__init__.py          |    6 --
 test/unit/types/version.py           |  133 -----------------------------
 test/unit/version.py                 |  133 +++++++++++++++++++++++++++++
 11 files changed, 307 insertions(+), 301 deletions(-)

diff --git a/run_tests.py b/run_tests.py
index ba74b66..8fa7107 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -13,9 +13,9 @@ import unittest
 import StringIO
 
 import test.runner
+import test.unit.version
 import test.unit.socket.control_message
 import test.unit.socket.control_line
-import test.unit.types.version
 import test.unit.connection.protocolinfo
 import test.unit.util.enum
 import test.unit.util.system
@@ -34,7 +34,7 @@ DIVIDER = "=" * 70
 # (name, class) tuples for all of our unit and integration tests
 UNIT_TESTS = (("stem.socket.ControlMessage", test.unit.socket.control_message.TestControlMessage),
               ("stem.socket.ControlLine", test.unit.socket.control_line.TestControlLine),
-              ("stem.types.Version", test.unit.types.version.TestVerion),
+              ("stem.types.Version", test.unit.version.TestVerion),
               ("stem.connection.ProtocolInfoResponse", test.unit.connection.protocolinfo.TestProtocolInfoResponse),
               ("stem.util.enum", test.unit.util.enum.TestEnum),
               ("stem.util.system", test.unit.util.system.TestSystem),
diff --git a/stem/__init__.py b/stem/__init__.py
index d4ede49..5b2cdd0 100644
--- a/stem/__init__.py
+++ b/stem/__init__.py
@@ -4,5 +4,5 @@ Library for working with the tor process.
 
 import stem.util # suppresses log handler warnings
 
-__all__ = ["connection", "process", "socket", "types"]
+__all__ = ["connection", "process", "socket", "version"]
 
diff --git a/stem/connection.py b/stem/connection.py
index ac548aa..ba851a2 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -21,7 +21,7 @@ import logging
 import threading
 
 import stem.socket
-import stem.types
+import stem.version
 import stem.util.enum
 import stem.util.system
 
@@ -176,12 +176,12 @@ class ProtocolInfoResponse(stem.socket.ControlMessage):
   response, so all other values are None if undefined or empty if a collecion.
   
   Attributes:
-    protocol_version (int)           - protocol version of the response
-    tor_version (stem.types.Version) - version of the tor process
-    auth_methods (tuple)             - AuthMethod types that tor will accept
-    unknown_auth_methods (tuple)     - strings of unrecognized auth methods
-    cookie_path (str)                - path of tor's authentication cookie
-    socket (socket.socket)           - socket used to make the query
+    protocol_version (int)             - protocol version of the response
+    tor_version (stem.version.Version) - version of the tor process
+    auth_methods (tuple)               - AuthMethod types that tor will accept
+    unknown_auth_methods (tuple)       - strings of unrecognized auth methods
+    cookie_path (str)                  - path of tor's authentication cookie
+    socket (socket.socket)             - socket used to make the query
   """
   
   def convert(control_message):
@@ -302,7 +302,7 @@ class ProtocolInfoResponse(stem.socket.ControlMessage):
         torversion = line.pop_mapping(True)[1]
         
         try:
-          self.tor_version = stem.types.Version(torversion)
+          self.tor_version = stem.version.Version(torversion)
         except ValueError, exc:
           raise stem.socket.ProtocolError(exc)
       else:
diff --git a/stem/process.py b/stem/process.py
index 2974989..0bb9740 100644
--- a/stem/process.py
+++ b/stem/process.py
@@ -2,7 +2,6 @@
 Helper functions for working with tor as a process. These are mostly os
 dependent, only working on linux, osx, and bsd.
 
-get_tor_version - gets the version of our system's tor installation
 launch_tor - starts up a tor process
 """
 
@@ -11,56 +10,9 @@ import os
 import signal
 import subprocess
 
-import stem.types
-import stem.util.system
-
 # number of seconds before we time out our attempt to start a tor instance
 DEFAULT_INIT_TIMEOUT = 90
 
-# cache for the get_tor_version function
-VERSION_CACHE = {}
-
-def get_tor_version(tor_cmd = "tor"):
-  """
-  Queries tor for its version.
-  
-  Arguments:
-    tor_cmd (str) - command used to run tor
-  
-  Returns:
-    stem.types.Version provided by the tor command
-  
-  Raises:
-    IOError if unable to query or parse the version
-  """
-  
-  if not tor_cmd in VERSION_CACHE:
-    try:
-      version_cmd = "%s --version" % tor_cmd
-      version_output = stem.util.system.call(version_cmd)
-    except OSError, exc:
-      raise IOError(exc)
-    
-    if version_output:
-      # output example:
-      # Oct 21 07:19:27.438 [notice] Tor v0.2.1.30. This is experimental software. Do not rely on it for strong anonymity. (Running on Linux i686)
-      # Tor version 0.2.1.30.
-      
-      last_line = version_output[-1]
-      
-      if last_line.startswith("Tor version ") and last_line.endswith("."):
-        try:
-          version_str = last_line[12:-1]
-          VERSION_CACHE[tor_cmd] = stem.types.Version(version_str)
-        except ValueError, exc:
-          raise IOError(exc)
-      else:
-        raise IOError("Unexpected response from '%s': %s" % (version_cmd, last_line))
-    else:
-      raise IOError("'%s' didn't have any output" % version_cmd)
-  
-  return VERSION_CACHE[tor_cmd]
-
 def launch_tor(torrc_path, completion_percent = 100, init_msg_handler = None, timeout = DEFAULT_INIT_TIMEOUT):
   """
   Initializes a tor process. This blocks until initialization completes or we
diff --git a/stem/types.py b/stem/types.py
deleted file mode 100644
index 3d62582..0000000
--- a/stem/types.py
+++ /dev/null
@@ -1,98 +0,0 @@
-"""
-Class representations for a variety of tor objects. These are most commonly
-return values rather than being instantiated by users directly.
-
-Version - Tor versioning information.
-  |- __str__ - string representation
-  +- __cmp__ - compares with another Version
-"""
-
-import re
-import socket
-import logging
-import threading
-
-LOGGER = logging.getLogger("stem")
-
-class Version:
-  """
-  Comparable tor version, as per the 'new version' of the version-spec...
-  https://gitweb.torproject.org/torspec.git/blob/HEAD:/version-spec.txt
-  
-  Attributes:
-    major (int)  - major version
-    minor (int)  - minor version
-    micro (int)  - micro version
-    patch (int)  - optional patch level (None if undefined)
-    status (str) - optional status tag without the preceding dash such as
-                   'alpha', 'beta-dev', etc (None if undefined)
-  """
-  
-  def __init__(self, version_str):
-    """
-    Parses a valid tor version string, for instance "0.1.4" or
-    "0.2.2.23-alpha".
-    
-    Raises:
-      ValueError if input isn't a valid tor version
-    """
-    
-    m = re.match(r'^([0-9]+).([0-9]+).([0-9]+)(.[0-9]+)?(-\S*)?$', version_str)
-    
-    if m:
-      major, minor, micro, patch, status = m.groups()
-      
-      # The patch and status matches are optional (may be None) and have an extra
-      # proceeding period or dash if they exist. Stripping those off.
-      
-      if patch: patch = int(patch[1:])
-      if status: status = status[1:]
-      
-      self.major = int(major)
-      self.minor = int(minor)
-      self.micro = int(micro)
-      self.patch = patch
-      self.status = status
-    else: raise ValueError("'%s' isn't a properly formatted tor version" % version_str)
-  
-  def __str__(self):
-    """
-    Provides the normal representation for the version, for instance:
-    "0.2.2.23-alpha"
-    """
-    
-    suffix = ""
-    
-    if self.patch:
-      suffix += ".%i" % self.patch
-    
-    if self.status:
-      suffix += "-%s" % self.status
-    
-    return "%i.%i.%i%s" % (self.major, self.minor, self.micro, suffix)
-  
-  def __cmp__(self, other):
-    """
-    Simple comparison of versions. An undefined patch level is treated as zero
-    and status tags are compared lexically (as per the version spec).
-    """
-    
-    if not isinstance(other, Version):
-      return 1 # this is also used for equality checks
-    
-    for attr in ("major", "minor", "micro", "patch"):
-      my_version = max(0, self.__dict__[attr])
-      other_version = max(0, other.__dict__[attr])
-      
-      if my_version > other_version: return 1
-      elif my_version < other_version: return -1
-    
-    my_status = self.status if self.status else ""
-    other_status = other.status if other.status else ""
-    
-    return cmp(my_status, other_status)
-
-# TODO: version requirements will probably be moved to another module later
-REQ_GETINFO_CONFIG_TEXT = Version("0.2.2.7-alpha")
-REQ_CONTROL_SOCKET = Version("0.2.0.30")
-
diff --git a/stem/version.py b/stem/version.py
new file mode 100644
index 0000000..d417934
--- /dev/null
+++ b/stem/version.py
@@ -0,0 +1,156 @@
+"""
+Tor versioning information and requirements for its features. These can be
+easily parsed and compared, for instance...
+
+>>> my_version = stem.version.get_system_tor_version()
+>>> print my_version
+0.2.1.30
+>>> my_version > stem.version.Requirement.CONTROL_SOCKET
+True
+
+get_system_tor_version - gets the version of our system's tor installation
+Version - Tor versioning information.
+  |- __str__ - string representation
+  +- __cmp__ - compares with another Version
+
+Requirement - Enumerations for the version requirements of features.
+  |- GETINFO_CONFIG_TEXT - 'GETINFO config-text' query
+  +- CONTROL_SOCKET      - 'ControlSocket <path>' config option
+"""
+
+import re
+import logging
+
+import stem.util.enum
+import stem.util.system
+
+LOGGER = logging.getLogger("stem")
+
+# cache for the get_tor_version function
+VERSION_CACHE = {}
+
+def get_system_tor_version(tor_cmd = "tor"):
+  """
+  Queries tor for its version. This is os dependent, only working on linux,
+  osx, and bsd.
+  
+  Arguments:
+    tor_cmd (str) - command used to run tor
+  
+  Returns:
+    stem.version.Version provided by the tor command
+  
+  Raises:
+    IOError if unable to query or parse the version
+  """
+  
+  if not tor_cmd in VERSION_CACHE:
+    try:
+      version_cmd = "%s --version" % tor_cmd
+      version_output = stem.util.system.call(version_cmd)
+    except OSError, exc:
+      raise IOError(exc)
+    
+    if version_output:
+      # output example:
+      # Oct 21 07:19:27.438 [notice] Tor v0.2.1.30. This is experimental software. Do not rely on it for strong anonymity. (Running on Linux i686)
+      # Tor version 0.2.1.30.
+      
+      last_line = version_output[-1]
+      
+      if last_line.startswith("Tor version ") and last_line.endswith("."):
+        try:
+          version_str = last_line[12:-1]
+          VERSION_CACHE[tor_cmd] = Version(version_str)
+        except ValueError, exc:
+          raise IOError(exc)
+      else:
+        raise IOError("Unexpected response from '%s': %s" % (version_cmd, last_line))
+    else:
+      raise IOError("'%s' didn't have any output" % version_cmd)
+  
+  return VERSION_CACHE[tor_cmd]
+
+class Version:
+  """
+  Comparable tor version, as per the 'new version' of the version-spec...
+  https://gitweb.torproject.org/torspec.git/blob/HEAD:/version-spec.txt
+  
+  Attributes:
+    major (int)  - major version
+    minor (int)  - minor version
+    micro (int)  - micro version
+    patch (int)  - optional patch level (None if undefined)
+    status (str) - optional status tag without the preceding dash such as
+                   'alpha', 'beta-dev', etc (None if undefined)
+  """
+  
+  def __init__(self, version_str):
+    """
+    Parses a valid tor version string, for instance "0.1.4" or
+    "0.2.2.23-alpha".
+    
+    Raises:
+      ValueError if input isn't a valid tor version
+    """
+    
+    m = re.match(r'^([0-9]+).([0-9]+).([0-9]+)(.[0-9]+)?(-\S*)?$', version_str)
+    
+    if m:
+      major, minor, micro, patch, status = m.groups()
+      
+      # The patch and status matches are optional (may be None) and have an extra
+      # proceeding period or dash if they exist. Stripping those off.
+      
+      if patch: patch = int(patch[1:])
+      if status: status = status[1:]
+      
+      self.major = int(major)
+      self.minor = int(minor)
+      self.micro = int(micro)
+      self.patch = patch
+      self.status = status
+    else: raise ValueError("'%s' isn't a properly formatted tor version" % version_str)
+  
+  def __str__(self):
+    """
+    Provides the normal representation for the version, for instance:
+    "0.2.2.23-alpha"
+    """
+    
+    suffix = ""
+    
+    if self.patch:
+      suffix += ".%i" % self.patch
+    
+    if self.status:
+      suffix += "-%s" % self.status
+    
+    return "%i.%i.%i%s" % (self.major, self.minor, self.micro, suffix)
+  
+  def __cmp__(self, other):
+    """
+    Simple comparison of versions. An undefined patch level is treated as zero
+    and status tags are compared lexically (as per the version spec).
+    """
+    
+    if not isinstance(other, Version):
+      return 1 # this is also used for equality checks
+    
+    for attr in ("major", "minor", "micro", "patch"):
+      my_version = max(0, self.__dict__[attr])
+      other_version = max(0, other.__dict__[attr])
+      
+      if my_version > other_version: return 1
+      elif my_version < other_version: return -1
+    
+    my_status = self.status if self.status else ""
+    other_status = other.status if other.status else ""
+    
+    return cmp(my_status, other_status)
+
+Requirement = stem.util.enum.Enum(
+  ("GETINFO_CONFIG_TEXT", Version("0.2.2.7-alpha")),
+  ("CONTROL_SOCKET", Version("0.2.0.30")),
+)
+
diff --git a/test/integ/socket/control_message.py b/test/integ/socket/control_message.py
index bbcd222..2cdb96c 100644
--- a/test/integ/socket/control_message.py
+++ b/test/integ/socket/control_message.py
@@ -7,7 +7,7 @@ import socket
 import unittest
 
 import stem.socket
-import stem.types
+import stem.version
 import test.runner
 
 class TestControlMessage(unittest.TestCase):
@@ -139,8 +139,9 @@ class TestControlMessage(unittest.TestCase):
     Parses the 'GETINFO config-text' response.
     """
     
-    if stem.process.get_tor_version() < stem.types.REQ_GETINFO_CONFIG_TEXT:
-      self.skipTest("(requires %s)" % stem.types.REQ_GETINFO_CONFIG_TEXT)
+    req_version = stem.version.Requirement.GETINFO_CONFIG_TEXT
+    if stem.version.get_system_tor_version() < req_version:
+      self.skipTest("(requires %s)" % req_version)
     
     # We can't be certain of the order, and there may be extra config-text
     # entries as per...
diff --git a/test/unit/connection/protocolinfo.py b/test/unit/connection/protocolinfo.py
index b597981..ecca8b6 100644
--- a/test/unit/connection/protocolinfo.py
+++ b/test/unit/connection/protocolinfo.py
@@ -4,9 +4,10 @@ Unit tests for the stem.connection.ProtocolInfoResponse class.
 
 import unittest
 import StringIO
+
 import stem.connection
 import stem.socket
-import stem.types
+import stem.version
 
 NO_AUTH = """250-PROTOCOLINFO 1
 250-AUTH METHODS=NULL
@@ -87,7 +88,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
     stem.connection.ProtocolInfoResponse.convert(control_message)
     
     self.assertEquals(1, control_message.protocol_version)
-    self.assertEquals(stem.types.Version("0.2.1.30"), control_message.tor_version)
+    self.assertEquals(stem.version.Version("0.2.1.30"), control_message.tor_version)
     self.assertEquals((stem.connection.AuthMethod.NONE, ), control_message.auth_methods)
     self.assertEquals((), control_message.unknown_auth_methods)
     self.assertEquals(None, control_message.cookie_path)
diff --git a/test/unit/types/__init__.py b/test/unit/types/__init__.py
deleted file mode 100644
index 95da593..0000000
--- a/test/unit/types/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""
-Unit tests for stem.types.
-"""
-
-__all__ = ["version"]
-
diff --git a/test/unit/types/version.py b/test/unit/types/version.py
deleted file mode 100644
index 067759b..0000000
--- a/test/unit/types/version.py
+++ /dev/null
@@ -1,133 +0,0 @@
-"""
-Unit tests for the stem.types.Version parsing and class.
-"""
-
-import unittest
-import stem.types
-
-class TestVerion(unittest.TestCase):
-  """
-  Tests methods and functions related to 'stem.types.Version'.
-  """
-  
-  def test_parsing(self):
-    """
-    Tests parsing by the Version class constructor.
-    """
-    
-    # valid versions with various number of compontents to the version
-    version = stem.types.Version("0.1.2.3-tag")
-    self.assert_versions_match(version, 0, 1, 2, 3, "tag")
-    
-    version = stem.types.Version("0.1.2.3")
-    self.assert_versions_match(version, 0, 1, 2, 3, None)
-    
-    version = stem.types.Version("0.1.2-tag")
-    self.assert_versions_match(version, 0, 1, 2, None, "tag")
-    
-    version = stem.types.Version("0.1.2")
-    self.assert_versions_match(version, 0, 1, 2, None, None)
-    
-    # checks an empty tag
-    version = stem.types.Version("0.1.2.3-")
-    self.assert_versions_match(version, 0, 1, 2, 3, "")
-    
-    version = stem.types.Version("0.1.2-")
-    self.assert_versions_match(version, 0, 1, 2, None, "")
-    
-    # checks invalid version strings
-    self.assertRaises(ValueError, stem.types.Version, "")
-    self.assertRaises(ValueError, stem.types.Version, "1.2.3.4nodash")
-    self.assertRaises(ValueError, stem.types.Version, "1.2.3.a")
-    self.assertRaises(ValueError, stem.types.Version, "1.2.a.4")
-    self.assertRaises(ValueError, stem.types.Version, "12.3")
-    self.assertRaises(ValueError, stem.types.Version, "1.-2.3")
-  
-  def test_comparison(self):
-    """
-    Tests comparision between Version instances.
-    """
-    
-    # check for basic incrementing in each portion
-    self.assert_version_is_greater("1.1.2.3-tag", "0.1.2.3-tag")
-    self.assert_version_is_greater("0.2.2.3-tag", "0.1.2.3-tag")
-    self.assert_version_is_greater("0.1.3.3-tag", "0.1.2.3-tag")
-    self.assert_version_is_greater("0.1.2.4-tag", "0.1.2.3-tag")
-    self.assert_version_is_greater("0.1.2.3-ugg", "0.1.2.3-tag")
-    self.assert_version_is_equal("0.1.2.3-tag", "0.1.2.3-tag")
-    
-    # checks that a missing patch level equals zero
-    self.assert_version_is_equal("0.1.2", "0.1.2.0")
-    self.assert_version_is_equal("0.1.2-tag", "0.1.2.0-tag")
-    
-    # checks for missing patch or status
-    self.assert_version_is_greater("0.1.2.3-tag", "0.1.2.3")
-    self.assert_version_is_greater("0.1.2.3-tag", "0.1.2-tag")
-    self.assert_version_is_greater("0.1.2.3-tag", "0.1.2")
-    
-    self.assert_version_is_equal("0.1.2.3", "0.1.2.3")
-    self.assert_version_is_equal("0.1.2", "0.1.2")
-  
-  def test_nonversion_comparison(self):
-    """
-    Checks that we can be compared with other types.
-    """
-    
-    test_version = stem.types.Version("0.1.2.3")
-    self.assertNotEqual(test_version, None)
-    self.assertTrue(test_version > None)
-    
-    self.assertNotEqual(test_version, 5)
-    self.assertTrue(test_version > 5)
-  
-  def test_string(self):
-    """
-    Tests the Version -> string conversion.
-    """
-    
-    # checks conversion with various numbers of arguments
-    
-    self.assert_string_matches("0.1.2.3-tag")
-    self.assert_string_matches("0.1.2.3")
-    self.assert_string_matches("0.1.2")
-  
-  def assert_versions_match(self, version, major, minor, micro, patch, status):
-    """
-    Asserts that the values for a types.Version instance match the given
-    values.
-    """
-    
-    self.assertEqual(version.major, major)
-    self.assertEqual(version.minor, minor)
-    self.assertEqual(version.micro, micro)
-    self.assertEqual(version.patch, patch)
-    self.assertEqual(version.status, status)
-  
-  def assert_version_is_greater(self, first_version, second_version):
-    """
-    Asserts that the parsed version of the first version is greate than the
-    second (also checking the inverse).
-    """
-    
-    version1 = stem.types.Version(first_version)
-    version2 = stem.types.Version(second_version)
-    self.assertEqual(version1 > version2, True)
-    self.assertEqual(version1 < version2, False)
-  
-  def assert_version_is_equal(self, first_version, second_version):
-    """
-    Asserts that the parsed version of the first version equals the second.
-    """
-    
-    version1 = stem.types.Version(first_version)
-    version2 = stem.types.Version(second_version)
-    self.assertEqual(version1, version2)
-  
-  def assert_string_matches(self, version):
-    """
-    Parses the given version string then checks that its string representation
-    matches the input.
-    """
-    
-    self.assertEqual(version, str(stem.types.Version(version)))
-
diff --git a/test/unit/version.py b/test/unit/version.py
new file mode 100644
index 0000000..2845ad3
--- /dev/null
+++ b/test/unit/version.py
@@ -0,0 +1,133 @@
+"""
+Unit tests for the stem.version.Version parsing and class.
+"""
+
+import unittest
+import stem.version
+
+class TestVerion(unittest.TestCase):
+  """
+  Tests methods and functions related to 'stem.version.Version'.
+  """
+  
+  def test_parsing(self):
+    """
+    Tests parsing by the Version class constructor.
+    """
+    
+    # valid versions with various number of compontents to the version
+    version = stem.version.Version("0.1.2.3-tag")
+    self.assert_versions_match(version, 0, 1, 2, 3, "tag")
+    
+    version = stem.version.Version("0.1.2.3")
+    self.assert_versions_match(version, 0, 1, 2, 3, None)
+    
+    version = stem.version.Version("0.1.2-tag")
+    self.assert_versions_match(version, 0, 1, 2, None, "tag")
+    
+    version = stem.version.Version("0.1.2")
+    self.assert_versions_match(version, 0, 1, 2, None, None)
+    
+    # checks an empty tag
+    version = stem.version.Version("0.1.2.3-")
+    self.assert_versions_match(version, 0, 1, 2, 3, "")
+    
+    version = stem.version.Version("0.1.2-")
+    self.assert_versions_match(version, 0, 1, 2, None, "")
+    
+    # checks invalid version strings
+    self.assertRaises(ValueError, stem.version.Version, "")
+    self.assertRaises(ValueError, stem.version.Version, "1.2.3.4nodash")
+    self.assertRaises(ValueError, stem.version.Version, "1.2.3.a")
+    self.assertRaises(ValueError, stem.version.Version, "1.2.a.4")
+    self.assertRaises(ValueError, stem.version.Version, "12.3")
+    self.assertRaises(ValueError, stem.version.Version, "1.-2.3")
+  
+  def test_comparison(self):
+    """
+    Tests comparision between Version instances.
+    """
+    
+    # check for basic incrementing in each portion
+    self.assert_version_is_greater("1.1.2.3-tag", "0.1.2.3-tag")
+    self.assert_version_is_greater("0.2.2.3-tag", "0.1.2.3-tag")
+    self.assert_version_is_greater("0.1.3.3-tag", "0.1.2.3-tag")
+    self.assert_version_is_greater("0.1.2.4-tag", "0.1.2.3-tag")
+    self.assert_version_is_greater("0.1.2.3-ugg", "0.1.2.3-tag")
+    self.assert_version_is_equal("0.1.2.3-tag", "0.1.2.3-tag")
+    
+    # checks that a missing patch level equals zero
+    self.assert_version_is_equal("0.1.2", "0.1.2.0")
+    self.assert_version_is_equal("0.1.2-tag", "0.1.2.0-tag")
+    
+    # checks for missing patch or status
+    self.assert_version_is_greater("0.1.2.3-tag", "0.1.2.3")
+    self.assert_version_is_greater("0.1.2.3-tag", "0.1.2-tag")
+    self.assert_version_is_greater("0.1.2.3-tag", "0.1.2")
+    
+    self.assert_version_is_equal("0.1.2.3", "0.1.2.3")
+    self.assert_version_is_equal("0.1.2", "0.1.2")
+  
+  def test_nonversion_comparison(self):
+    """
+    Checks that we can be compared with other types.
+    """
+    
+    test_version = stem.version.Version("0.1.2.3")
+    self.assertNotEqual(test_version, None)
+    self.assertTrue(test_version > None)
+    
+    self.assertNotEqual(test_version, 5)
+    self.assertTrue(test_version > 5)
+  
+  def test_string(self):
+    """
+    Tests the Version -> string conversion.
+    """
+    
+    # checks conversion with various numbers of arguments
+    
+    self.assert_string_matches("0.1.2.3-tag")
+    self.assert_string_matches("0.1.2.3")
+    self.assert_string_matches("0.1.2")
+  
+  def assert_versions_match(self, version, major, minor, micro, patch, status):
+    """
+    Asserts that the values for a types.Version instance match the given
+    values.
+    """
+    
+    self.assertEqual(version.major, major)
+    self.assertEqual(version.minor, minor)
+    self.assertEqual(version.micro, micro)
+    self.assertEqual(version.patch, patch)
+    self.assertEqual(version.status, status)
+  
+  def assert_version_is_greater(self, first_version, second_version):
+    """
+    Asserts that the parsed version of the first version is greate than the
+    second (also checking the inverse).
+    """
+    
+    version1 = stem.version.Version(first_version)
+    version2 = stem.version.Version(second_version)
+    self.assertEqual(version1 > version2, True)
+    self.assertEqual(version1 < version2, False)
+  
+  def assert_version_is_equal(self, first_version, second_version):
+    """
+    Asserts that the parsed version of the first version equals the second.
+    """
+    
+    version1 = stem.version.Version(first_version)
+    version2 = stem.version.Version(second_version)
+    self.assertEqual(version1, version2)
+  
+  def assert_string_matches(self, version):
+    """
+    Parses the given version string then checks that its string representation
+    matches the input.
+    """
+    
+    self.assertEqual(version, str(stem.version.Version(version)))
+





More information about the tor-commits mailing list