[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