@@ -173,6 +173,76 @@ def test_fail(self):
173173 self .assertFalse (sct_payload ['correct' ])
174174
175175
176+ class TestOverride (unittest .TestCase ):
177+ """
178+ This class is used to test overriding w/ correct and incorrect code. Tests are
179+ run for entire nodes (e.g. an if block) and their parts (e.g. body of if block)
180+ """
181+
182+ def do_exercise (self , code , base_check , parts , override = None , part_name = None , part_index = "" , passes = True ):
183+ """High level function used to generate tests"""
184+ if part_name :
185+ if not override : override = parts [part_name ]
186+ sct = base_check + '.check_{}({}).override("""{}""").has_equal_ast()' \
187+ .format (part_name , part_index , override )
188+ else :
189+ # whole code (e.g. if expression, or for loop)
190+ if not override : override = code .format (** parts )
191+ sct = base_check + '.override("""{}""").has_equal_ast()' .format (override )
192+
193+ data = {
194+ "DC_SOLUTION" : code .format (** parts ),
195+ "DC_CODE" : code .format (** parts ),
196+ "DC_SCT" : sct
197+ }
198+ sct_payload = helper .run (data )
199+ self .assertTrue (sct_payload ['correct' ]) if passes else self .assertFalse (sct_payload ['correct' ])
200+
201+ # used to generate tests
202+ EXPRESSIONS = {
203+ 'if_exp' : "{body} if {test} else {orelse}" ,
204+ 'list_comp' : "[{body} for i in {iter}]" ,
205+ 'dict_comp' : "{{ {key}: {value} for i in {iter} }}" ,
206+ 'for_loop' : "for i in {iter}: {body}" ,
207+ 'while' : "while {test}: {body}" ,
208+ 'try_except' : "try: {body}\n except: pass\n else: {orelse}" ,
209+ 'lambda_function' : "lambda a={args}: {body}" ,
210+ 'function_def' : ["'sum'" , "def sum(a={args}): {body}" ],
211+ 'function' : ["'sum', 0" , "sum({args})" ]
212+ }
213+
214+ PARTS = {'body' : "1" , "test" : "False" , 'orelse' : "2" , 'iter' : "range(3)" ,
215+ 'key' : "3" , 'value' : "4" , 'args' : "(1,2,3)" }
216+
217+ import re
218+ def gen_exercise (* args , ** kwargs ):
219+ return lambda self : TestOverride .do_exercise (self , * args , ** kwargs )
220+
221+ for k , code in TestOverride .EXPRESSIONS .items ():
222+ # base SCT, w/ special indexing if function checks
223+ if isinstance (code , list ): indx , code = code
224+ else : indx = '0'
225+ base_check = "Ex().check_{}({})" .format (k , indx )
226+ # pass overall test ----
227+ pf = gen_exercise (code , base_check , TestOverride .PARTS )
228+ setattr (TestOverride , 'test_{}_pass' .format (k ), pf )
229+ # fail overall test ----
230+ pf = gen_exercise (code , base_check , TestOverride .PARTS , override = "'WRONG ANSWER'" , passes = False )
231+ setattr (TestOverride , 'test_{}_fail' .format (k ), pf )
232+ # test individual pieces --------------------------------------------------
233+ for part in re .findall ("\{([^{]*?)\}" , code ): # find all str.format vars, e.g. {body}
234+ part_index = "" if part != 'args' else 0
235+ # pass individual piece ----
236+ test_name = 'test_{}_{}_pass' .format (k , part )
237+ pf = gen_exercise (code , base_check , TestOverride .PARTS , part_name = part , part_index = part_index )
238+ setattr (TestOverride , test_name , pf )
239+ # fail individual piece ----
240+ test_name = 'test_{}_{}_fail' .format (k , part )
241+ bad_code = code .format (** {part : "[]" , ** TestOverride .PARTS })
242+ pf = gen_exercise (code , base_check , TestOverride .PARTS , part_name = part , part_index = part_index , override = bad_code , passes = False )
243+ setattr (TestOverride , test_name , pf )
244+
245+
176246#class TestSetContext(unittest.TestCase):
177247# def setUp(self):
178248# self.data = {
0 commit comments