[Checkins] SVN: zc.recipe.macro/trunk/ Used manuel to put the Quickstart under test. Fixed bugs in Quickstart.

Aaron Lehmann aaron at zope.com
Mon Jan 19 01:21:26 EST 2009


Log message for revision 94823:
  Used manuel to put the Quickstart under test.  Fixed bugs in Quickstart.
  
  

Changed:
  U   zc.recipe.macro/trunk/CHANGES.txt
  U   zc.recipe.macro/trunk/setup.py
  U   zc.recipe.macro/trunk/src/zc/recipe/macro/QUICKSTART.txt
  U   zc.recipe.macro/trunk/src/zc/recipe/macro/tests.py

-=-
Modified: zc.recipe.macro/trunk/CHANGES.txt
===================================================================
--- zc.recipe.macro/trunk/CHANGES.txt	2009-01-18 19:35:22 UTC (rev 94822)
+++ zc.recipe.macro/trunk/CHANGES.txt	2009-01-19 06:21:25 UTC (rev 94823)
@@ -6,6 +6,7 @@
 
 - Removed version sections from the documentation.
 - Improved test coverage.
+- Put QUICKSTART.txt under test, using manuel.
 
 1.2.4 (2008-07-18)
 ------------------

Modified: zc.recipe.macro/trunk/setup.py
===================================================================
--- zc.recipe.macro/trunk/setup.py	2009-01-18 19:35:22 UTC (rev 94822)
+++ zc.recipe.macro/trunk/setup.py	2009-01-19 06:21:25 UTC (rev 94823)
@@ -108,6 +108,7 @@
         "setuptools",
         "zc.recipe.testrunner",
         "zope.testing",
+        "manuel",
         ],
     include_package_data=True,
     zip_safe=False,

Modified: zc.recipe.macro/trunk/src/zc/recipe/macro/QUICKSTART.txt
===================================================================
--- zc.recipe.macro/trunk/src/zc/recipe/macro/QUICKSTART.txt	2009-01-18 19:35:22 UTC (rev 94822)
+++ zc.recipe.macro/trunk/src/zc/recipe/macro/QUICKSTART.txt	2009-01-19 06:21:25 UTC (rev 94823)
@@ -9,7 +9,8 @@
 ---------
 
 In the most basic use of a macro, a section invokes the macro on itself, and
-uses itself as the parameter provider::
+uses itself as the parameter provider.
+Buildout::
 
     [buildout]
     parts = hard-rocker
@@ -22,12 +23,12 @@
     macro = rock
     rocking-style = so hard
 
-This will result in::
+Result::
 
     [hard-rocker]
     recipe = zc.recipe.macro:empty
+    rocking-style = so hard
     question = Why do I rock so hard?
-    rocking-style = so hard
 
 The recipe gets changed to zc.recipe.macro:empty, which is a do nothing recipe,
 because the invoking secion must be a part in order to execute recipes, and
@@ -36,18 +37,36 @@
 Default Values
 --------------
 
-It is possible to include default values for parameters in a macro, like so::
+It is possible to include default values for parameters in a macro.
 
+Buildout::
+
+    [buildout]
+    parts = hard-rocker
+
     [rock]
     question = Why do I rock $${:rocking-style}?
     rocking-style = so hard
 
+    [hard-rocker]
+    recipe = zc.recipe.macro
+    macro = rock
+
+Result::
+
+    [hard-rocker]
+    recipe = zc.recipe.macro:empty
+    rocking-style = so hard
+    question = Why do I rock so hard?
+
 Creating Parts
 --------------
 
 Of course, there wouldn't much point to this if one could only create sections
-with a dummy recipe.  This is where the result-recipe option comes in::
+with a dummy recipe.  This is where the result-recipe option comes in.
 
+Buildout::
+
     [buildout]
     parts = hard-rocker
 
@@ -56,14 +75,14 @@
 
     [hard-rocker]
     recipe = zc.recipe.macro
+    result-recipe = zc.recipe.macro:empty
     macro = rock
-    result-recipe = zc.recipe.its_still_rock_n_roll_to_me
     rocking-style = so hard
 
-That will result in::
+Result::
 
     [hard-rocker]
-    recipe = zc.recipe.its_still_rock_n_roll_to_me
+    recipe = zc.recipe.macro:empty
     question = Why do I rock so hard?
     rocking-style = so hard
 
@@ -73,13 +92,16 @@
 Often, one wants to create multiple new sections.  This is possible with the
 targets option.  This is only useful, however, if one can provide multiple
 sources for parameters.  Fortunately, you can.  Each new section can optionally
-be followed by a colon and the name of a section to use for parameters::
+be followed by a colon and the name of a section to use for parameters.
 
+Buildout::
+
     [buildout]
-    parts = rockers
+    parts = rockers hard-rocker socks-rocker tired-rocker
 
     [rock]
     question = Why do I rock $${:rocking-style}?
+    rocking-style = $${:rocking-style}
 
     [hard-rocker-parameters]
     rocking-style = so hard
@@ -92,13 +114,14 @@
 
     [rockers]
     recipe = zc.recipe.macro
+    result-recipe = zc.recipe.macro:empty
     macro = rock
     targets =
         hard-rocker:hard-rocker-parameters
         socks-rocker:socks-rocker-parameters
-        rocking-style:tired-rocker-parameters
+        tired-rocker:tired-rocker-parameters
 
-That will generate these rockers::
+Result::
 
     [hard-rocker]
     recipe = zc.recipe.macro:empty
@@ -117,8 +140,10 @@
 
 zc.recipe.macro uses __name__ to mean the name of the section the macro is
 being invoked upon.  This allows one to not know the name of particular
-section, but still use it in output::
+section, but still use it in output.
 
+Buildout::
+
     [buildout]
     parts = rockers
 
@@ -136,13 +161,14 @@
 
     [rockers]
     recipe = zc.recipe.macro
+    result-recipe = zc.recipe.macro:empty
     macro = rock
     targets =
         hard-rocker:hard-rocker-parameters
         socks-rocker:socks-rocker-parameters
         rocking-style:tired-rocker-parameters
 
-This will result in rockers like these::
+Result::
 
     [hard-rocker]
     recipe = zc.recipe.macro:empty

Modified: zc.recipe.macro/trunk/src/zc/recipe/macro/tests.py
===================================================================
--- zc.recipe.macro/trunk/src/zc/recipe/macro/tests.py	2009-01-18 19:35:22 UTC (rev 94822)
+++ zc.recipe.macro/trunk/src/zc/recipe/macro/tests.py	2009-01-19 06:21:25 UTC (rev 94823)
@@ -20,8 +20,10 @@
 import zc.buildout.buildout
 import zc.buildout.testing
 import zc.buildout.tests
+import zc.buildout.easy_install
 import StringIO
 import sys
+import traceback
 
 import unittest
 import zc.recipe.egg
@@ -30,6 +32,11 @@
 import zope.testing
 import zope.testing.doctest
 import zope.testing.renormalizing
+import manuel
+import manuel.doctest
+import manuel.testing
+import textwrap
+import ConfigParser
 
 
 here = os.path.abspath(os.path.dirname(__file__))
@@ -73,6 +80,98 @@
     return buildout
 
 
+class BuildoutEvaluation(object):
+    def __init__(self, example, actual=None, desired=None, traceback=None):
+        self.example = example
+        self.traceback = traceback
+        if traceback:
+            self.passed = False
+        else:
+            self.passed = True
+            self.successes = dict(desired)
+            self.failures = {}
+            for section_key, section in desired.iteritems():
+                if section_key not in actual:
+                    self.failures[section_key] = self.successes.pop(
+                        section_key)
+                    self.passed = False
+                else:
+                    for key, value in section.iteritems():
+                        if (key not in actual[section_key] or
+                            value != actual[section_key][key]):
+                            self.failures[section_key][key] = self.successes[
+                                section_key].pop(key)
+                            self.passed = False
+
+    def test_sections(self, actual, desired):
+        return list(key for key in desired
+            if key in actual and actual[key] == desired[key])
+
+
+START_RE = re.compile(r'^Buildout::$', re.MULTILINE)
+END_RE = re.compile(r'(.+?)\n(?=\n\S).+?Result::(.+?)\n(?=\n\S*)',
+    re.DOTALL)
+
+class BuildoutManuel(object):
+    def parse(self, document):
+        document.regions = document.find_regions(START_RE, END_RE)
+        for region in document:
+            buildout, want = [textwrap.dedent(s.lstrip('\n'))
+                for s in region.end_match.groups()]
+            example = zope.testing.doctest.Example(
+                buildout, want, lineno=region.lineno + 2)
+            document.replace_region(region, example)
+            region.parsed = example
+
+    def evaluate(self, document):
+        setupBuildout = self.test.globs['setupBuildout']
+        sample_buildout = self.test.globs['sample_buildout']
+        rmdir = self.test.globs['rmdir']
+        for region in document:
+            example = region.parsed
+            if not isinstance(example, zope.testing.doctest.Example):
+                continue
+            buildout = setupBuildout(
+                sample_buildout, "buildout.cfg", example.source)
+            try:
+                buildout.install([])
+                result_buildout = dict(buildout)
+                config = ConfigParser.RawConfigParser()
+                config.readfp(StringIO.StringIO(example.want))
+                result_desired = dict(
+                    (section, dict(pair for pair in config.items(section)))
+                    for section in config.sections())
+                region.evaluated = BuildoutEvaluation(
+                    example, actual=result_buildout, desired=result_desired)
+            except zc.buildout.easy_install.MissingDistribution, md:
+                region.evaluated = BuildoutEvaluation(
+                    example, traceback=''.join(
+                        traceback.format_exception(*(sys.exc_info()))))
+
+    def format(self, document):
+        for region in document:
+            evaluation = region.evaluated
+            if not isinstance(evaluation, BuildoutEvaluation):
+                continue
+            if not evaluation.passed:
+                if evaluation.traceback:
+                    region.formatted = evaluation.traceback
+#            else:
+#                cp = ConfigParser.RawConfigParser()
+#                for section_name, section in evaluation.successes.iteritems():
+#                    cp.add_section(section_name)
+#                    for key, val in section.iteritems():
+#                        cp.set(section_name, key, val)
+#                sio = StringIO.StringIO()
+#                cp.write(sio)
+#                region.formatted = sio.getvalue()
+#                sio.close()
+
+    def setUp(self, test):
+        self.test = test
+        setUp(test)
+
+
 def setUp(test):
     zc.buildout.testing.buildoutSetUp(test)
 
@@ -105,6 +204,20 @@
                ]), optionflags=optionflags
             ),)
 
+    m = manuel.doctest.Manuel(
+        optionflags=(zope.testing.doctest.NORMALIZE_WHITESPACE |
+                     zope.testing.doctest.ELLIPSIS))
+
+    bm = BuildoutManuel()
+    manuel_test = manuel.Manuel()
+    manuel_test.parser(timing='early')(bm.parse)
+    manuel_test.evaluater(bm.evaluate)
+    manuel_test.formatter(bm.format)
+
+    m.extend(manuel_test)
+    quickstart = manuel.testing.TestSuite(m, 'QUICKSTART.txt', setUp=bm.setUp)
+    suite.addTest(quickstart)
+
     return suite
 
 if __name__ == '__main__':



More information about the Checkins mailing list