├── coolstorybro ├── __init__.py ├── test │ ├── examples │ │ └── test_ex_coolstorybro.py │ └── test_coolstorybro.py └── coolstorybro.py ├── .gitignore ├── setup.py └── README.md /coolstorybro/__init__.py: -------------------------------------------------------------------------------- 1 | from coolstorybro import CoolStoryBroPlugin, CoolStoryBro 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.bak 4 | *.*~ 5 | MANIFEST 6 | build 7 | dist 8 | lib 9 | -------------------------------------------------------------------------------- /coolstorybro/test/examples/test_ex_coolstorybro.py: -------------------------------------------------------------------------------- 1 | import nose 2 | 3 | 4 | class TestCoolStoryBroExample(object): 5 | 6 | def test_ex_coolstorybro(self): 7 | 8 | assert 1 == 1 9 | assert 2 == 2 10 | assert 3 == 3 11 | assert 4 == 4 12 | assert 5 == 5 13 | assert 6 == 6 14 | assert 7 == 7 15 | assert 8 == 8 16 | assert 9 == 9 17 | assert 10 == 10 18 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from setuptools import setup 3 | 4 | setup( 5 | name='nose-coolstorybro', 6 | version='0.1', 7 | author='Benjamin W. Smith', 8 | author_email = 'benjaminwarfield@just-another.net', 9 | description = 'TL;DR', 10 | long_description=open('./README.md').read(), 11 | license = 'BSD', 12 | url='https://github.com/benjaminws/nose-coolstorybro', 13 | packages = ['coolstorybro'], 14 | entry_points = { 15 | 'nose.plugins': [ 16 | 'coolstorybro = coolstorybro:CoolStoryBroPlugin' 17 | ] 18 | }, 19 | classifiers = [ 20 | 'Intended Audience :: Developers', 21 | 'Natural Language :: English', 22 | 'Operating System :: OS Independent', 23 | 'Topic :: Software Development :: Testing', 24 | 'Programming Language :: Python :: 2' 25 | ], 26 | ) 27 | -------------------------------------------------------------------------------- /coolstorybro/test/test_coolstorybro.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import unittest 4 | from nose.plugins import PluginTester 5 | 6 | from coolstorybro import CoolStoryBroPlugin, CoolStoryBro 7 | 8 | 9 | class CoolStoryBroTest(PluginTester, unittest.TestCase): 10 | 11 | activate = '--with-coolstorybro' 12 | plugins = [CoolStoryBroPlugin()] 13 | suitepath = os.path.join(os.path.dirname(__file__), 'examples') 14 | 15 | def test_emits_coolstorybro_exception(self): 16 | assert "U MAD?" in self.output 17 | 18 | 19 | class CoolStoryBroTlDr(PluginTester, unittest.TestCase): 20 | 21 | activate = '--with-coolstorybro' 22 | args = ['--tl-dr'] 23 | plugins = [CoolStoryBroPlugin()] 24 | suitepath = os.path.join(os.path.dirname(__file__), 'examples') 25 | 26 | def test_emits_tl_dr(self): 27 | assert "TL;DR" in self.output 28 | 29 | if __name__ == '__main__': 30 | unittest.main() 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | COOL STORY BRO 2 | ============== 3 | 4 | [Someone](http://twitter.com/garybernhardt) once said [Resisting the urge to write a test runner that raises CoolStoryBro if your test is over eight lines long.](http://twitter.com/#!/garybernhardt/status/125711084878442496). 5 | 6 | You're welcome. 7 | 8 | INSTALL, BRO 9 | ============ 10 | 11 | $ pip install git+git://github.com/benjaminws/nose-coolstorybro.git 12 | 13 | USAGE, BRO 14 | ========== 15 | 16 | Your tests are too big, bro 17 | --------------------------- 18 | 19 | $ nosetests --with-coolstorybro test/examples 20 | E 21 | ====================================================================== 22 | ERROR: test_ex_coolstorybro.TestCoolStoryBroExample.test_ex_coolstorybro 23 | ---------------------------------------------------------------------- 24 | Traceback (most recent call last): 25 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/case.py", line 133, in run 26 | self.runTest(result) 27 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/case.py", line 151, in runTest 28 | test(result) 29 | File "/usr/lib/python2.7/unittest/case.py", line 385, in __call__ 30 | return self.run(*args, **kwds) 31 | File "/usr/lib/python2.7/unittest/case.py", line 296, in run 32 | result.startTest(self) 33 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/proxy.py", line 172, in startTest 34 | self.plugins.startTest(self.test) 35 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/plugins/manager.py", line 94, in __call__ 36 | return self.call(*arg, **kw) 37 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/plugins/manager.py", line 162, in simple 38 | result = meth(*arg, **kw) 39 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/plugins/manager.py", line 343, in startTest 40 | return self.plugin.startTest(test.test) 41 | File "build/bdist.linux-x86_64/egg/coolstorybro/coolstorybro.py", line 43, in startTest 42 | raise CoolStoryBro 43 | CoolStoryBro: U MAD? 44 | 45 | ---------------------------------------------------------------------- 46 | Ran 0 tests in 0.002s 47 | 48 | FAILED (errors=1) 49 | 50 | How many lines was that? 51 | ------------------------ 52 | 53 | $ nosetests --with-coolstorybro --tl-dr test/examples 54 | E 55 | ====================================================================== 56 | ERROR: test_ex_coolstorybro.TestCoolStoryBroExample.test_ex_coolstorybro 57 | ---------------------------------------------------------------------- 58 | Traceback (most recent call last): 59 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/case.py", line 133, in run 60 | self.runTest(result) 61 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/case.py", line 151, in runTest 62 | test(result) 63 | File "/usr/lib/python2.7/unittest/case.py", line 385, in __call__ 64 | return self.run(*args, **kwds) 65 | File "/usr/lib/python2.7/unittest/case.py", line 296, in run 66 | result.startTest(self) 67 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/proxy.py", line 172, in startTest 68 | self.plugins.startTest(self.test) 69 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/plugins/manager.py", line 94, in __call__ 70 | return self.call(*arg, **kw) 71 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/plugins/manager.py", line 162, in simple 72 | result = meth(*arg, **kw) 73 | File "/home/bsmith/Dev/python/nose-coolstorybro/lib/python2.7/site-packages/nose/plugins/manager.py", line 343, in startTest 74 | return self.plugin.startTest(test.test) 75 | File "build/bdist.linux-x86_64/egg/coolstorybro/coolstorybro.py", line 42, in startTest 76 | raise CoolStoryBro("TL;DR: %d lines" % test_length) 77 | CoolStoryBro: TL;DR: 12 lines 78 | 79 | ---------------------------------------------------------------------- 80 | Ran 0 tests in 0.002s 81 | 82 | FAILED (errors=1) 83 | -------------------------------------------------------------------------------- /coolstorybro/coolstorybro.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | import inspect 4 | import os 5 | 6 | from nose.case import MethodTestCase 7 | from nose.plugins import Plugin 8 | from unittest import TestResult, _TextTestResult 9 | 10 | CHUCK_TESTA = """ 11 | =II7$Z$$$$$? 12 | ?7$ZOIIZDDDD8O$ 13 | I$ZZOO$Z$$7II77$$ 14 | 7ZOO$777O??II7$$Z7$ 15 | $II777IIIZ8NMMNNDO$Z 16 | Z$$Z7+78MMMNNNNMMNNDO 17 | 8D$OI7DNNNNDDDDDNNNNNZ 18 | 8Z$DNNNDDO?~~~==?DDNZ 19 | 7$NNNNN$?==~=ZDD88DO+ 20 | ONDD8DDDNN7IDNNNOOI? 21 | +DO8D8NDD8+~IDDDDOZ~ 22 | ?OO$$DDDOI?:+++7Z8?= 23 | OOI8OZ+=IOI$+=+?+?= 24 | OZ8$?+=~=$+=~===I 25 | D O7?=+IZ888O+++7 26 | ODDO ZZI+IIIIII??$Z$ 27 | NNDD8 78D8OOOZ???+~~=7OO 28 | NNDDD8 ???III?8DND888OI=====$8O+~IOIO 29 | NNNDD8 ??IIIIIIIIII$8DDD88ZI?IODO$$$II7III 30 | ZONDDDD 7IIIIIIIIIIIIII77$ZNNNNNNMNNZ777777IIIII 31 | ZODDDD8 ODI77I7IIIIIIIIIII7I7$ONNMMMMN$77$ZZ$77IIIIII 32 | ZD788888 D8IIII777IIIIIIIIIIIIIII7$$O8Z$777IIIIIIIIIIIIII? 33 | 8D=?+8Z88 O77II77I777IIIIIIIIIIIIIII7777777777IIIIIIIIIIIIIIII 34 | $D8:==$=IZDD 7777777777777IIIIIIIIIIIIIIIIII7I77777IIIIIIIIIIIIIIIIII? 35 | D8+~~====77777777777777777IIIIIIIIIIIIIIIIIIIIIIIII~,=I+:=III7IIIIIIII 36 | OI++====77$$Z7777$7777777IIIIIIIIIIIIIIIIIIIIIIIIIII+.~:=:I7IIIIIIIII 37 | 8I++===$$7Z$Z8Z$$7777777IIIIIIIIIIIIIIIIIIIIIIIII?+==:+I+IIIIIIIIIII7 38 | $I?+++7$$ZZ$$$ZZ7777777IIIIIIIIIIIIIIIIIIIIIIII~~~???I~=7II777II77I? 39 | 8$7?+=7$$ZZZZZ$$$777777IIIIIIIIIIIIIIIIIIIIIII::?==~~+~I7I777777III?I 40 | 8Z$7?7Z$Z$ZZZ$$$7777777IIIIIIIIIIII777IIIIIIIII?I?=+7II7I7$7$IIIII?? 41 | OOZ$O?$Z$ZOZZZ$777$$7777777777777777777IIIIIIIIIIIII777$7$$7II???III 42 | MD?Z$ZZDOZ$$77$77$77777777I7777777777IIIIIIIIII77$$$7$7I7???III? 43 | OZ$DZZZ$$7$$$$7777777III77II77777$7777777II7$$$7777I??I????$ 44 | ODZZ$7$$7$$7777777IIIIIIIII777ZOZ$$77$DZ777$$Z7IIII?????I 45 | O$$$$777$77777I77IIIIIIIII7$777ZDZNZ7NZ777$Z7III??????? 46 | OZ$$$77$$77777I77IIIIIII77ZIIII$ODZNO7D$77$O7IIIII?????I 47 | Z$$7777777777II7IIII77IIIII77777777O87O77OO777IIIIII??? 48 | Z$77777777777IIIIIIII7IIIIIIIIII77777O$Z8NZ$$777III??I? 49 | Z$77777777777IIIIIIIII77IIIIIIIII777I7Z$M$Z77$$7IIIIIII7$ 50 | =77777777777IIIIIIIIIII77IIIII7777777I7$ZM87III777$ODMMMD 51 | $:I7777777777IIIIIIIIII7$$IIIIIII7777II7$Z$$O8+~==+7NMMN 52 | Z7+777777777777IIIIIIIIII777IIIIIIIIIII77ONZ+====+?Z8 53 | $77II777777777777777IIII77I77IIIIIII77777ZD+=~=++?77 54 | $7777=7777777777777777III777777IIII7777777+====++I7$ 55 | $777II:7777777777777777IIIIII777IIII777III=~===+I7$Z 56 | $877777I777777777$7$77777777$ZOO8O7IIIIII+=====+7$O 57 | 777Z$777$=77$$77777$$$777$$$7I777ZNDZ7II?==~=+?7$ 58 | Z77777877$$:77$7777777$$77777$$7777$8MNZI===++??I 59 | Z777777$8Z$7I?777$$$$$$$$$$777$$$$$Z$ZOI+===??I7 60 | 77I777777$$Z$7:$$$$$$$$$$$$777$$$$$77I+===+?IIZ 61 | 8 62 | OII?MM 63 | OO II??OM 64 | Z7III?MM II?7MM 65 | O7III???IOOM I?+MM 66 | ZIII????ZMMMM I+MM 67 | 7II??DMMM OI M ZOMMM 68 | $7IIIIIIM $II?$OIIII?ZM II?OM 69 | Z7III????II??MM II?II???ZMMMM O OI??ZMM 70 | III???I8MMM8I?+DM OII??MMMM O7II8M ZMMM 71 | OII??MM $I+?MM II??OMOIIII???IMM 72 | O7IIIIZ II??ZMOIII??$MM OII?III???ZNMMMM 73 | OIII????I?I?D II??I???ZMMMM I????ZMMMM 74 | ZII??$NMM8III??8M $II?7MMMM OOMMMM 75 | O7 $I??OMMM OII??MM II??8M 76 | II??MM 8II?$MM II?+MM OII?IMM 77 | O OII?ZM OII?ZMM OII?7MM I??I8M 78 | 7OIIII7M $I??MM II??8M ZII??MM MMM 79 | III??III?O II?IM OII??IIIIIII??OMM 80 | ZI??IIIIIII?ZZI??8M 8IIIII????IMMMM 81 | II??MM$IIIIIII???MM MD8DMMMMM 82 | OI??8M 8I?III??8M 83 | II??MM O7I?IOMM 84 | OII?OM MMM 85 | 7I??NM 86 | Z?OMMMM 87 | M 88 | """ 89 | 90 | FUUU = """ 91 | ,DNMM ,,.M. .,MD:. 92 | MM,,.,. ,M M..M. 93 | . NM .:M NMN, N. 94 | ,M: M.M,M. M. 95 | DM NDNM M,. 96 | M MD. .MM 97 | :...NNMN MMNMN. ,MM8. M. MM. 98 | .:..,MMMMMM. M,MNM. .N.. MN .M N. 99 | . ..MM.N. MMMM. .D:. N, NM..M:. 100 | M,.M. M. M M M M . .M.,MM 101 | NMM .... D, ,MM,,. .NMMMM.N..M 102 | M . NN MMM, MNM,M, M .N, 103 | MM M M .M. M..M, 104 | .M.,M M,. ,M M. N. M .MM: 105 | M. M N ... N M ,N 106 | .M.M. . M. M MM, N. M:M 107 | .M M ... M, MN.,MNMN,.MNM NM. MM 108 | .MM N .M MM. M.,,..M., M 109 | .MM . ,M . M. M,MM .,M:,MM, , 110 | .MM .N N N.. :MMMN. ..M.M. .M 111 | .MM. MMMMMM .. .M,..M M. MM. 112 | .MM M ,,MMM M. :M. 113 | .MM M M. .N .N, 114 | .MM .M.. MMM .M. .N, 115 | .M D .N ... . M. ... M. .M 116 | .M M. .M ., . ,, .M MM.M. .M 117 | ,D N. M . M,, M . M. .M 118 | M,M ,M, .M .MMM. . M M . .MM 119 | M.M M . N MN .DMMMMM. MM 120 | ,M. . M :, ..M .M,. MM 121 | .ND, M, ,M,,,... MM, .M, 122 | .. ,M ., .,.M M,N. .MM. 123 | ,M.: M,.MN:.M.M. ..M. MM 124 | ,... M M , M..,.M , M 125 | M M, ..,MNMM,.M:. MM 126 | ,M MM.. ,.M. 127 | M MM . .M 128 | ,M ,,: ,M 129 | """ 130 | 131 | TROLL = """ 132 | MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM 133 | MMMMMMM :MMMMM MM MM 134 | MMM .MMMMMM. M MMM 135 | MM MM M MM 136 | MM MMMMMN . ,M M MM 137 | MM M M M M Z M 138 | MM M M = M MM 139 | M MMMMMMMMMMM MM 140 | MMM .MMMMMMMN MMM MMMMMMMMM MMM 141 | MM NMMMMMOMMMMMMMMMMM MMM MMMMMMMMMMMM M :7+ MMM 142 | MM M MMMMMMM MMMMMM M .MMMM M MM 143 | MM M MM .MM MMMM MMM 8 MM 144 | MMM = MMMMMMMM .M MM MMMMMMM M .MM ? MM 145 | MM. M MMMMM MM MMM MM M M 146 | MMM M M ,MM MMMM M MMMM MMM M 8 M 147 | MM MMM MMMM MM MMMM. .MM. MM MM 148 | MM .M MMMM M MMM MMMMM MM8 .MMMMMM MM M8 . MM 149 | MM MMMMMM MMMMM MMMMMM MM MMMM M MM 150 | M MMM MMMMMM MMMMMMMM MMMMMMMMM MMM 151 | MM MMM MM MMMMMMMMMMMMMMMMMN MN OMMMMMM MM MM 152 | MM MMM MM MM MM M MMMMMMMMMMMM MM MM 153 | MM MMMMMMMMMM MM M .MMMMMMMMM MM MM MM 154 | MM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MM. MM 155 | MM MMMMMMMMMMMMMMMMMMMMMMMMMMM. MM MMM MM 156 | MM M.MM MMMMMMMMMMMMMN MM MM MMM MM 157 | MM MM+M :M MM MM MM MMMMM. MMM 158 | MM .MMM MM MM MM MM MMMMM M M MMM 159 | MM +MMMMMMMMMMMMMMMMMMMMMMMMM MM M MMM 160 | MM M M MMMM 161 | M M M M MMMM 162 | M M MM .$MMMMMN .MM MMMM 163 | M M .MM. MMMM 164 | MM MMMM 165 | MM MMMMM 166 | MMM ,MMMMMMM 167 | MMMMM. ~MMMMMMMM 168 | """ 169 | 170 | 171 | class CoolStoryBro(Exception): 172 | 173 | def __init__(self, tl_dr=None, fu=None): 174 | self.tl_dr = tl_dr 175 | self.fu = fu 176 | 177 | def __str__(self): 178 | if self.tl_dr: 179 | return self.tl_dr 180 | return FUUU if self.fu else TROLL 181 | 182 | 183 | class ChuckTesta(Exception): 184 | 185 | def __init__(self, tl_dr=None, fu=None): 186 | self.tl_dr = tl_dr 187 | self.fu = fu 188 | 189 | def __str__(self): 190 | if self.tl_dr: 191 | return self.tl_dr 192 | return CHUCK_TESTA 193 | 194 | 195 | class CoolStoryBroPlugin(Plugin): 196 | 197 | name = 'coolstorybro' 198 | enabled = True 199 | 200 | def options(self, parser, env=os.environ): 201 | parser.add_option('--tl-dr', action='store_true') 202 | parser.add_option('--fu', action='store_true') 203 | parser.add_option('--chuck-testa', action='store_true') 204 | super(CoolStoryBroPlugin, self).options(parser, env=env) 205 | 206 | def configure(self, options, config): 207 | super(CoolStoryBroPlugin, self).configure(options, config) 208 | self.config = config 209 | if not self.enabled: 210 | return 211 | 212 | self.tl_dr = options.tl_dr or None 213 | self.fu = options.fu or None 214 | self.chuck_testa = options.chuck_testa or None 215 | 216 | def startTest(self, test): 217 | if isinstance(test, MethodTestCase): 218 | source = inspect.getsourcelines(test.test) 219 | test_length = len(source[0]) 220 | exception = ChuckTesta if self.chuck_testa else CoolStoryBro 221 | if test_length > 8: 222 | if self.tl_dr: 223 | raise exception("TL;DR: %d lines" % test_length) 224 | raise exception(fu=self.fu) 225 | pass 226 | 227 | def prepareTestRunner(self, runner): 228 | self.runner = runner 229 | 230 | def setOutputStream(self, stream): 231 | self.stream = stream 232 | --------------------------------------------------------------------------------