Commits

Victor Stinner committed 3f183fe

Write unit tests for the README file

  • Participants
  • Parent commits dd3a4a9

Comments (0)

Files changed (3)

 
  * Optimize loops (range => xrange needs "builtin_funcs" features). Examples:
 
-   - ``while True: ...`` => ``while 1: ...``
-   - ``for x in range(3): ...`` => ``for x in (0, 1, 2): ...``
-   - ``for x in range(1000): ...`` => ``for x in xrange(1000): ...`` (Python 2)
+   - ``while True: pass`` => ``while 1: pass``
+   - ``for x in range(3): pass`` => ``for x in (0, 1, 2): pass``
+   - ``for x in range(1000): pass`` => ``for x in xrange(1000): pass`` (Python 2)
 
  * Optimize list comprehension and generators (need "builtin_funcs" feature).
    Examples:
 
    - ``iter(set())`` => ``iter(())``
    - ``frozenset("")`` => ``frozenset()``
-   - ``(x for x in "abc" if False)`` => ``iter(())``
-   - ``(x*2 for x in "abc" if True)`` => ``(x*2 for x in "abc")``
+   - ``(x for x in "abc" if False)`` => ``(None for x in ())``
+   - ``(x*2 for x in "abc" if True)`` => ``(x*2 for x in ("a", "b", "c"))``
+   - ``list(x for x in iterable)`` => ``list(iterable)``
    - ``tuple(x for x in "abc")`` => ``("a", "b", "c")``
+   - ``list(x for x in range(3))`` => ``[0, 1, 2]``
    - ``[x for x in ""]`` => ``[]``
    - ``[x for x in iterable]`` => ``list(iterable)``
    - ``set([x for x in "abc"])`` => ``set(("a", "b", "c"))``
 
  * Replace list with tuple (need "builtin_funcs" feature). Examples:
 
-   - ``for x in [1, 2, 3]: ...`` => ``for x in (1, 2, 3): ...``
+   - ``for x in [1, 2, 3]: pass`` => ``for x in (1, 2, 3): pass``
    - ``list([x, y, z])`` => ``[x, y, z]``
-   - ``set([1, 2, 3])`` => ``{1, 2, 3}``
+   - ``set([1, 2, 3])`` => ``{1, 2, 3}`` (Python 2.7+)
 
  * Evaluate unary and binary operators, subscript and comparaison if all
    arguments are constants. Examples:
    - ``1 + 2 * 3`` => ``7``
    - ``not True`` => ``False``
    - ``"abc" * 3`` => ``"abcabcabc"``
-   - ``"abcdef"[:3]`` => ``abc``
+   - ``"abcdef"[:3]`` => ``"abc"``
    - ``(2, 7, 3)[1]`` => ``7``
    - ``frozenset("ab") | frozenset("bc")`` => ``frozenset("abc")``
    - ``None is None`` => ``True``
 
    - ``def f(): return 1; return 2`` => ``def f(): return 1``
    - ``if DEBUG: print("debug")`` => ``pass`` with DEBUG declared as False
-   - ``while 0: ...`` => ``pass``
+   - ``while 0: print("never executed")`` => ``pass``
 
 
 Use astoptimizer in your project
    build options. Allow to optimize non-BMP unicode strings on Python < 3.3.
    Enable the ``"platform"`` feature. Examples:
 
-   - ``u"\\U0010ffff"[0]`` => ``u"\\udbff`` or ``u"\\U0010ffff"`` (depending on
+   - ``u"\\U0010ffff"[0]`` => ``u"\\udbff"`` or ``u"\\U0010ffff"`` (depending on
      build options, narrow or wide Unicode)
    - ``sys.version_info.major`` => ``2``
    - ``sys.maxunicode`` => ``0x10ffff``

astoptimizer/tests.py

 import ast
 import math
+import os
 import re
 import sys
 import unittest
 class TestCase(unittest.TestCase):
     if not hasattr(unittest.TestCase, 'skipTest'):
         def skipTest(self, reason):
+            print("skip test: %s" % reason)
             return reason
 
     if not hasattr(unittest.TestCase, 'assertIn'):
             warning='Disable optimizations because of "from re import *"')
 
 
+class TestREADME(BaseTestCase):
+    def create_default_config(self):
+        config = BaseTestCase.create_default_config(self)
+        config.enable('builtin_funcs')
+        config.enable('pythonenv')
+        config._constants['__debug__'] = True
+        config._constants['sys.flags.optimize'] = 0
+        return config
+
+    def check_line(self, line):
+        if not line.startswith('   - ``'):
+            return
+        line = line[7:].rstrip()
+        line = line.replace(r'\\', '\\')
+        parts = line.split('``')
+        before = parts[0]
+        after = parts[2]
+
+        if (sys.version_info < (2, 7)
+        and ('.bit_length()' in before
+             or 'sys.version_info.major' in before
+             or after == '{1, 2, 3}')):
+            return self.skipTest("need python 2.7+")
+        elif (PYTHON3
+        and 'string.atoi' in before):
+            return self.skipTest("specific to Python 2")
+
+        if 'if DEBUG:' in before:
+            config = self.create_default_config()
+            config.add_constant('DEBUG', False)
+        else:
+            config = None
+        if len(parts) >= 5 and parts[3] == ' or ':
+            after2 = parts[4]
+        else:
+            after2 = None
+        try:
+            self.check(before, self.text_ast(after), config)
+        except AssertionError:
+            if after2 is not None:
+                self.check(before, self.text_ast(after2), config)
+            else:
+                raise
+
+    def test_readme_file(self):
+        filename = os.path.join(os.path.dirname(__file__), '..', 'README')
+        with open(filename) as fp:
+            for line in fp:
+                self.check_line(line)
+
+
 class TestStruct(BaseTestCase):
     def create_default_config(self):
         config = BaseTestCase.create_default_config(self)
         help='Disable all configuration features',
         action="store_true", default=False)
     parser.add_option("-f", "--features",
-        help='Enable configuration features FEATURES',
+        help='Enable configuration features FEATURES (default: builtin_funcs and pythonbin)',
         action="store", type="str", default="builtin_funcs,pythonbin")
     parser.add_option("-a", "--all",
         help="Enable all optimizations",