Skip to content

Commit 214d87a

Browse files
kjcmpirnat
authored andcommitted
Importer (gregmalcolm#146)
* New koan loader: path_to_enlightenment.koans(). path_to_enlightenment.py now loads koans by name from a text file, instead of having them hard-coded. The names are stored in the python[23]/koans.txt file. koans calls a few helper functions to import all the actual koans. This includes a temporary test in python[23]/runner/runner_tests/test_path_to_enlightenment.py to verify the new test suite matches the original. * path_to_enlightenment: Now uses loadTestsFromName(). unittest.TestLoader already _has_ methods to load TestCases by name. * path_to_enlightenment.py: Added _useful_ tests. 2 new TestCase classes: TestFilterKoanNames and TestKoansSuite. TestKoansSuite needs more and better tests, but TestCase and TestSuite objects are hard to test without importing every constituent test by hand. That would require hard-coding the koans into the tests, which would break the instant someone adds a new koan... which is what loading the koans from a config file is supposed to fix in the first place. * Removed TestPathToEnlightenment. It was only temporary. * test_path_to_enlightenment: Safe for Python 3.1. The Unicode literal syntax requires Python 3.3+. TestCase.assertIsInstance requires Python 3.2+.
1 parent 3fe14a4 commit 214d87a

8 files changed

Lines changed: 403 additions & 164 deletions

File tree

python2/_runner_tests.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@
77
from runner.runner_tests.test_mountain import TestMountain
88
from runner.runner_tests.test_sensei import TestSensei
99
from runner.runner_tests.test_helper import TestHelper
10+
from runner.runner_tests.test_path_to_enlightenment import TestFilterKoanNames
11+
from runner.runner_tests.test_path_to_enlightenment import TestKoansSuite
12+
1013

1114
def suite():
1215
suite = unittest.TestSuite()
1316
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMountain))
1417
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestSensei))
1518
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestHelper))
19+
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestFilterKoanNames))
20+
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestKoansSuite))
1621
return suite
1722

23+
1824
if __name__ == '__main__':
1925
res = unittest.TextTestRunner(verbosity=2).run(suite())
2026
sys.exit(not res.wasSuccessful())

python2/koans.txt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Lines starting with # are ignored.
2+
koans.about_asserts.AboutAsserts
3+
koans.about_strings.AboutStrings
4+
koans.about_none.AboutNone
5+
koans.about_lists.AboutLists
6+
koans.about_list_assignments.AboutListAssignments
7+
koans.about_dictionaries.AboutDictionaries
8+
koans.about_string_manipulation.AboutStringManipulation
9+
koans.about_tuples.AboutTuples
10+
koans.about_methods.AboutMethods
11+
koans.about_control_statements.AboutControlStatements
12+
koans.about_true_and_false.AboutTrueAndFalse
13+
koans.about_sets.AboutSets
14+
koans.about_triangle_project.AboutTriangleProject
15+
koans.about_exceptions.AboutExceptions
16+
koans.about_triangle_project2.AboutTriangleProject2
17+
koans.about_iteration.AboutIteration
18+
koans.about_comprehension.AboutComprehension
19+
koans.about_generators.AboutGenerators
20+
koans.about_lambdas.AboutLambdas
21+
koans.about_scoring_project.AboutScoringProject
22+
koans.about_classes.AboutClasses
23+
koans.about_new_style_classes.AboutNewStyleClasses
24+
koans.about_with_statements.AboutWithStatements
25+
koans.about_monkey_patching.AboutMonkeyPatching
26+
koans.about_dice_project.AboutDiceProject
27+
koans.about_method_bindings.AboutMethodBindings
28+
koans.about_decorating_with_functions.AboutDecoratingWithFunctions
29+
koans.about_decorating_with_classes.AboutDecoratingWithClasses
30+
koans.about_inheritance.AboutInheritance
31+
koans.about_multiple_inheritance.AboutMultipleInheritance
32+
koans.about_scope.AboutScope
33+
koans.about_modules.AboutModules
34+
koans.about_packages.AboutPackages
35+
koans.about_class_attributes.AboutClassAttributes
36+
koans.about_attribute_access.AboutAttributeAccess
37+
koans.about_deleting_objects.AboutDeletingObjects
38+
koans.about_proxy_object_project.AboutProxyObjectProject
39+
koans.about_proxy_object_project.TelevisionTest
40+
koans.about_extra_credit.AboutExtraCredit
41+
koans.about_regex.AboutRegex
Lines changed: 52 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,62 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
# The path to enlightenment starts with the following:
4+
'''
5+
Functions to load the test cases ("koans") that make up the
6+
Path to Enlightenment.
7+
'''
58

9+
import io
610
import unittest
711

8-
from koans.about_asserts import AboutAsserts
9-
from koans.about_strings import AboutStrings
10-
from koans.about_none import AboutNone
11-
from koans.about_lists import AboutLists
12-
from koans.about_list_assignments import AboutListAssignments
13-
from koans.about_dictionaries import AboutDictionaries
14-
from koans.about_string_manipulation import AboutStringManipulation
15-
from koans.about_tuples import AboutTuples
16-
from koans.about_methods import AboutMethods
17-
from koans.about_control_statements import AboutControlStatements
18-
from koans.about_true_and_false import AboutTrueAndFalse
19-
from koans.about_sets import AboutSets
20-
from koans.about_triangle_project import AboutTriangleProject
21-
from koans.about_exceptions import AboutExceptions
22-
from koans.about_triangle_project2 import AboutTriangleProject2
23-
from koans.about_iteration import AboutIteration
24-
from koans.about_comprehension import AboutComprehension
25-
from koans.about_generators import AboutGenerators
26-
from koans.about_lambdas import AboutLambdas
27-
from koans.about_scoring_project import AboutScoringProject
28-
from koans.about_classes import AboutClasses
29-
from koans.about_new_style_classes import AboutNewStyleClasses
30-
from koans.about_with_statements import AboutWithStatements
31-
from koans.about_monkey_patching import AboutMonkeyPatching
32-
from koans.about_dice_project import AboutDiceProject
33-
from koans.about_method_bindings import AboutMethodBindings
34-
from koans.about_decorating_with_functions import AboutDecoratingWithFunctions
35-
from koans.about_decorating_with_classes import AboutDecoratingWithClasses
36-
from koans.about_inheritance import AboutInheritance
37-
from koans.about_multiple_inheritance import AboutMultipleInheritance
38-
from koans.about_regex import AboutRegex
39-
from koans.about_scope import AboutScope
40-
from koans.about_modules import AboutModules
41-
from koans.about_packages import AboutPackages
42-
from koans.about_class_attributes import AboutClassAttributes
43-
from koans.about_attribute_access import AboutAttributeAccess
44-
from koans.about_deleting_objects import AboutDeletingObjects
45-
from koans.about_proxy_object_project import *
46-
from koans.about_extra_credit import AboutExtraCredit
4712

48-
def koans():
49-
loader = unittest.TestLoader()
13+
# The path to enlightenment starts with the following:
14+
KOANS_FILENAME = 'koans.txt'
15+
16+
17+
def filter_koan_names(lines):
18+
'''
19+
Strips leading and trailing whitespace, then filters out blank
20+
lines and comment lines.
21+
'''
22+
for line in lines:
23+
line = line.strip()
24+
if line.startswith('#'):
25+
continue
26+
if line:
27+
yield line
28+
return
29+
30+
31+
def names_from_file(filename):
32+
'''
33+
Opens the given ``filename`` and yields the fully-qualified names
34+
of TestCases found inside (one per line).
35+
'''
36+
with io.open(filename, 'rt', encoding='utf8') as names_file:
37+
for name in filter_koan_names(names_file):
38+
yield name
39+
return
40+
41+
42+
def koans_suite(names):
43+
'''
44+
Returns a ``TestSuite`` loaded with all tests found in the given
45+
``names``, preserving the order in which they are found.
46+
'''
5047
suite = unittest.TestSuite()
48+
loader = unittest.TestLoader()
5149
loader.sortTestMethodsUsing = None
52-
suite.addTests(loader.loadTestsFromTestCase(AboutAsserts))
53-
suite.addTests(loader.loadTestsFromTestCase(AboutStrings))
54-
suite.addTests(loader.loadTestsFromTestCase(AboutNone))
55-
suite.addTests(loader.loadTestsFromTestCase(AboutLists))
56-
suite.addTests(loader.loadTestsFromTestCase(AboutListAssignments))
57-
suite.addTests(loader.loadTestsFromTestCase(AboutDictionaries))
58-
suite.addTests(loader.loadTestsFromTestCase(AboutStringManipulation))
59-
suite.addTests(loader.loadTestsFromTestCase(AboutTuples))
60-
suite.addTests(loader.loadTestsFromTestCase(AboutMethods))
61-
suite.addTests(loader.loadTestsFromTestCase(AboutControlStatements))
62-
suite.addTests(loader.loadTestsFromTestCase(AboutTrueAndFalse))
63-
suite.addTests(loader.loadTestsFromTestCase(AboutSets))
64-
suite.addTests(loader.loadTestsFromTestCase(AboutTriangleProject))
65-
suite.addTests(loader.loadTestsFromTestCase(AboutExceptions))
66-
suite.addTests(loader.loadTestsFromTestCase(AboutTriangleProject2))
67-
suite.addTests(loader.loadTestsFromTestCase(AboutIteration))
68-
suite.addTests(loader.loadTestsFromTestCase(AboutComprehension))
69-
suite.addTests(loader.loadTestsFromTestCase(AboutGenerators))
70-
suite.addTests(loader.loadTestsFromTestCase(AboutLambdas))
71-
suite.addTests(loader.loadTestsFromTestCase(AboutScoringProject))
72-
suite.addTests(loader.loadTestsFromTestCase(AboutClasses))
73-
suite.addTests(loader.loadTestsFromTestCase(AboutNewStyleClasses))
74-
suite.addTests(loader.loadTestsFromTestCase(AboutWithStatements))
75-
suite.addTests(loader.loadTestsFromTestCase(AboutMonkeyPatching))
76-
suite.addTests(loader.loadTestsFromTestCase(AboutDiceProject))
77-
suite.addTests(loader.loadTestsFromTestCase(AboutMethodBindings))
78-
suite.addTests(loader.loadTestsFromTestCase(AboutDecoratingWithFunctions))
79-
suite.addTests(loader.loadTestsFromTestCase(AboutDecoratingWithClasses))
80-
suite.addTests(loader.loadTestsFromTestCase(AboutInheritance))
81-
suite.addTests(loader.loadTestsFromTestCase(AboutMultipleInheritance))
82-
suite.addTests(loader.loadTestsFromTestCase(AboutScope))
83-
suite.addTests(loader.loadTestsFromTestCase(AboutModules))
84-
suite.addTests(loader.loadTestsFromTestCase(AboutPackages))
85-
suite.addTests(loader.loadTestsFromTestCase(AboutClassAttributes))
86-
suite.addTests(loader.loadTestsFromTestCase(AboutAttributeAccess))
87-
suite.addTests(loader.loadTestsFromTestCase(AboutDeletingObjects))
88-
suite.addTests(loader.loadTestsFromTestCase(AboutProxyObjectProject))
89-
suite.addTests(loader.loadTestsFromTestCase(TelevisionTest))
90-
suite.addTests(loader.loadTestsFromTestCase(AboutExtraCredit))
91-
suite.addTests(loader.loadTestsFromTestCase(AboutRegex))
92-
50+
for name in names:
51+
tests = loader.loadTestsFromName(name)
52+
suite.addTests(tests)
9353
return suite
54+
55+
56+
def koans(filename=KOANS_FILENAME):
57+
'''
58+
Returns a ``TestSuite`` loaded with all the koans (``TestCase``s)
59+
listed in ``filename``.
60+
'''
61+
names = names_from_file(filename)
62+
return koans_suite(names)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
import io
5+
import unittest
6+
7+
from runner import path_to_enlightenment as pte
8+
9+
10+
class TestFilterKoanNames(unittest.TestCase):
11+
12+
def test_empty_input_produces_empty_output(self):
13+
infile = io.StringIO(u'')
14+
expected = []
15+
received = list(pte.filter_koan_names(infile))
16+
self.assertListEqual(expected, received)
17+
return
18+
19+
def test_names_yielded_match_names_in_file(self):
20+
names = [
21+
u'this.is.a.test',
22+
u'this.is.only.a.test',
23+
]
24+
infile = io.StringIO(u'\n'.join(names))
25+
received = list(pte.filter_koan_names(infile))
26+
self.assertListEqual(names, received)
27+
return
28+
29+
def test_whitespace_is_stripped(self):
30+
names = [
31+
u'this.is.a.test',
32+
u' white.space.should.be.stripped',
33+
u'this.is.only.a.test',
34+
u'white.space.should.be.stripped ',
35+
]
36+
infile = io.StringIO(u'\n'.join(names))
37+
expected = [
38+
u'this.is.a.test',
39+
u'white.space.should.be.stripped',
40+
u'this.is.only.a.test',
41+
u'white.space.should.be.stripped',
42+
]
43+
received = list(pte.filter_koan_names(infile))
44+
self.assertListEqual(expected, received)
45+
return
46+
47+
def test_commented_out_names_are_excluded(self):
48+
names = [
49+
u'this.is.a.test',
50+
u'#this.is.a.comment',
51+
u'this.is.only.a.test',
52+
u' # this.is.also a.comment ',
53+
]
54+
infile = io.StringIO(u'\n'.join(names))
55+
expected = [
56+
u'this.is.a.test',
57+
u'this.is.only.a.test',
58+
]
59+
received = list(pte.filter_koan_names(infile))
60+
self.assertListEqual(expected, received)
61+
return
62+
63+
def all_blank_or_comment_lines_produce_empty_output(self):
64+
names = [
65+
u' ',
66+
u'# This is a comment.',
67+
u'\t',
68+
u' # This is also a comment.',
69+
]
70+
infile = io.StringIO(u'\n'.join(names))
71+
expected = []
72+
received = list(pte.filter_koan_names(infile))
73+
self.assertListEqual(expected, received)
74+
return
75+
76+
77+
class TestKoansSuite(unittest.TestCase):
78+
79+
def test_empty_input_produces_empty_testsuite(self):
80+
names = []
81+
suite = pte.koans_suite(names)
82+
self.assertIsInstance(suite, unittest.TestSuite)
83+
expected = []
84+
received = list(suite)
85+
self.assertListEqual(expected, received)
86+
return
87+
88+
def test_testcase_names_appear_in_testsuite(self):
89+
names = [
90+
'koans.about_asserts.AboutAsserts',
91+
'koans.about_none.AboutNone',
92+
'koans.about_strings.AboutStrings',
93+
]
94+
suite = pte.koans_suite(names)
95+
self.assertIsInstance(suite, unittest.TestSuite)
96+
expected = [
97+
'AboutAsserts',
98+
'AboutNone',
99+
'AboutStrings',
100+
]
101+
received = sorted(set(test.__class__.__name__ for test in suite))
102+
self.assertListEqual(expected, received)
103+
return

python3/_runner_tests.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@
77
from runner.runner_tests.test_mountain import TestMountain
88
from runner.runner_tests.test_sensei import TestSensei
99
from runner.runner_tests.test_helper import TestHelper
10+
from runner.runner_tests.test_path_to_enlightenment import TestFilterKoanNames
11+
from runner.runner_tests.test_path_to_enlightenment import TestKoansSuite
12+
1013

1114
def suite():
1215
suite = unittest.TestSuite()
1316
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMountain))
1417
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestSensei))
1518
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestHelper))
19+
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestFilterKoanNames))
20+
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestKoansSuite))
1621
return suite
1722

23+
1824
if __name__ == '__main__':
1925
res = unittest.TextTestRunner(verbosity=2).run(suite())
2026
sys.exit(not res.wasSuccessful())

python3/koans.txt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Lines starting with # are ignored.
2+
koans.about_asserts.AboutAsserts
3+
koans.about_strings.AboutStrings
4+
koans.about_none.AboutNone
5+
koans.about_lists.AboutLists
6+
koans.about_list_assignments.AboutListAssignments
7+
koans.about_dictionaries.AboutDictionaries
8+
koans.about_string_manipulation.AboutStringManipulation
9+
koans.about_tuples.AboutTuples
10+
koans.about_methods.AboutMethods
11+
koans.about_control_statements.AboutControlStatements
12+
koans.about_true_and_false.AboutTrueAndFalse
13+
koans.about_sets.AboutSets
14+
koans.about_triangle_project.AboutTriangleProject
15+
koans.about_exceptions.AboutExceptions
16+
koans.about_triangle_project2.AboutTriangleProject2
17+
koans.about_iteration.AboutIteration
18+
koans.about_comprehension.AboutComprehension
19+
koans.about_generators.AboutGenerators
20+
koans.about_lambdas.AboutLambdas
21+
koans.about_scoring_project.AboutScoringProject
22+
koans.about_classes.AboutClasses
23+
koans.about_with_statements.AboutWithStatements
24+
koans.about_monkey_patching.AboutMonkeyPatching
25+
koans.about_dice_project.AboutDiceProject
26+
koans.about_method_bindings.AboutMethodBindings
27+
koans.about_decorating_with_functions.AboutDecoratingWithFunctions
28+
koans.about_decorating_with_classes.AboutDecoratingWithClasses
29+
koans.about_inheritance.AboutInheritance
30+
koans.about_multiple_inheritance.AboutMultipleInheritance
31+
koans.about_scope.AboutScope
32+
koans.about_modules.AboutModules
33+
koans.about_packages.AboutPackages
34+
koans.about_class_attributes.AboutClassAttributes
35+
koans.about_attribute_access.AboutAttributeAccess
36+
koans.about_deleting_objects.AboutDeletingObjects
37+
koans.about_proxy_object_project.AboutProxyObjectProject
38+
koans.about_proxy_object_project.TelevisionTest
39+
koans.about_extra_credit.AboutExtraCredit
40+
koans.about_regex.AboutRegex

0 commit comments

Comments
 (0)