Skip to content

Commit 99aa164

Browse files
author
Filip Schouwenaars
authored
Merge pull request #167 from datacamp/fix-test-funciton-highlight
Fix test function highlight *decision needed*
2 parents cae6f5f + 9c53e2b commit 99aa164

8 files changed

Lines changed: 117 additions & 76 deletions

File tree

pythonwhat/State.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def __init__(self,
102102
self.student_context = Context(student_context) if student_context is None else student_context
103103
self.solution_context = Context(solution_context) if solution_context is None else solution_context
104104

105-
self.highlight = self.student_tree if highlight is None else highlight
105+
self.highlight = self.student_tree if (not highlight) and self.parent_state else highlight
106106

107107
self.converters = get_manual_converters() # accessed only from root state
108108

pythonwhat/test_funcs/test_function.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def test_function(name,
1919
args_not_specified_msg=None,
2020
incorrect_msg=None,
2121
add_more=False,
22+
highlight=False,
2223
state=None):
2324
"""Test if function calls match.
2425
@@ -128,7 +129,7 @@ def test_function(name,
128129
if feedback is None:
129130
if not args_not_specified_msg:
130131
args_not_specified_msg = dflt
131-
feedback = Feedback(args_not_specified_msg, student_call)
132+
feedback = Feedback(args_not_specified_msg, student_call if highlight else None)
132133
success = False
133134
continue
134135

@@ -148,7 +149,8 @@ def test_function(name,
148149

149150
test = build_test(arg_student, arg_solution,
150151
state,
151-
do_eval, eq_fun, msg, add_more=add_more)
152+
do_eval, eq_fun, msg, add_more=add_more,
153+
highlight=arg_student if highlight else None)
152154
test.test()
153155

154156
if not test.result:
@@ -170,7 +172,8 @@ def test_function(name,
170172

171173
test = build_test(key_student, key_solution,
172174
state,
173-
do_eval, eq_fun, msg, add_more=add_more)
175+
do_eval, eq_fun, msg, add_more=add_more,
176+
highlight=key_student if highlight else None)
174177
test.test()
175178

176179
if not test.result:
@@ -197,6 +200,7 @@ def test_print(index = 1,
197200
params_not_matched_msg="Have you correctly called `print()`?",
198201
params_not_specified_msg="Have you correctly called `print()`?",
199202
incorrect_msg="Have you printed out the correct object?",
203+
highlight=False,
200204
state=None):
201205
test_function_v2("print",
202206
index=index,
@@ -207,7 +211,8 @@ def test_print(index = 1,
207211
not_called_msg=not_called_msg,
208212
params_not_matched_msg=params_not_matched_msg,
209213
params_not_specified_msg=params_not_specified_msg,
210-
incorrect_msg=incorrect_msg, state=state)
214+
incorrect_msg=incorrect_msg,
215+
highlight=highlight, state=state)
211216
"""Test print() calls
212217
213218
Utility function to test the print() function. For arguments, check test_function_v2()
@@ -224,6 +229,7 @@ def test_function_v2(name,
224229
params_not_specified_msg=None,
225230
incorrect_msg=None,
226231
add_more=False,
232+
highlight=False,
227233
state=None):
228234
"""Test if function calls match (v2).
229235
@@ -342,7 +348,7 @@ def test_function_v2(name,
342348
sub_tests = [partial(test_call, name, call_ind, signature, params, do_eval, solution_args,
343349
eq_fun, add_more, index,
344350
params_not_specified_msg, params_not_matched_msg, incorrect_msg,
345-
keywords, state=state)
351+
keywords, state=state, highlight = highlight)
346352
for call_ind in call_indices]
347353
test_or(*sub_tests, state=state)
348354

@@ -356,7 +362,7 @@ def test_call(name, call_ind, signature, params, do_eval, solution_args,
356362
eq_fun, add_more, index,
357363
params_not_specified_msg, params_not_matched_msg, incorrect_msg,
358364
keywords, # pulled from solution process
359-
state):
365+
state, highlight):
360366
#stud_name = get_mapped_name(name, state.student_mappings)
361367

362368
rep = Reporter.active_reporter
@@ -374,7 +380,7 @@ def test_call(name, call_ind, signature, params, do_eval, solution_args,
374380
params_not_matched_msg = ("Something went wrong in figuring out how you specified the " + \
375381
"arguments for `%s()`; have another look at your code and its output.") % stud_name
376382
_msg = state.build_message(params_not_matched_msg)
377-
feedback = Feedback(_msg, student_call)
383+
feedback = Feedback(_msg, student_call if highlight else None)
378384
# run subtest
379385
rep.do_test(Test(feedback)) # TODO: sub_call
380386

@@ -392,7 +398,7 @@ def test_call(name, call_ind, signature, params, do_eval, solution_args,
392398
else:
393399
msg = params_not_specified_msg[param_ind]
394400
_msg = state.build_message(msg)
395-
feedback = Feedback(_msg, student_call)
401+
feedback = Feedback(_msg, student_call if highlight else None)
396402
# run subtest
397403
rep.do_test(Test(feedback)) # TODO: sub_call
398404

@@ -405,15 +411,15 @@ def test_call(name, call_ind, signature, params, do_eval, solution_args,
405411
test_arg(param, do_eval[ind],
406412
arg_student, arg_solution, param_kind, stud_name,
407413
eq_fun, add_more,
408-
incorrect_msg[ind], state=state)
414+
incorrect_msg[ind], state=state, highlight = arg_student if highlight else None)
409415

410416
# If all is still good, we have a winner!
411417
state.set_used(name, call_ind, index)
412418

413419
def test_arg(param, do_eval,
414420
arg_student, arg_solution, param_kind, stud_name,
415421
eq_fun, add_more,
416-
incorrect_msg, state=None):
422+
incorrect_msg, state=None, highlight = None):
417423
rep = Reporter.active_reporter
418424

419425
if incorrect_msg is None:
@@ -426,7 +432,7 @@ def test_arg(param, do_eval,
426432

427433
test = build_test(arg_student, arg_solution,
428434
state,
429-
do_eval, eq_fun, msg, add_more = add_more)
435+
do_eval, eq_fun, msg, add_more = add_more, highlight=highlight)
430436
# TODO
431437
rep.do_test(test)
432438

@@ -443,7 +449,7 @@ def bind_args(signature, arguments, keyws):
443449
bound_args = signature.bind(*arguments, **keyws)
444450
return(bound_args.arguments, signature.parameters)
445451

446-
def build_test(stud, sol, state, do_eval, eq_fun, feedback_msg, add_more):
452+
def build_test(stud, sol, state, do_eval, eq_fun, feedback_msg, add_more, highlight = False):
447453
got_error = False
448454
if do_eval:
449455

@@ -472,8 +478,8 @@ def build_test(stud, sol, state, do_eval, eq_fun, feedback_msg, add_more):
472478
eval_solution = ast.dump(sol)
473479

474480
_msg = state.build_message(feedback_msg)
475-
return(Test(Feedback(_msg, stud)) if got_error else
476-
eq_fun(eval_student, eval_solution, Feedback(_msg, stud)))
481+
return(Test(Feedback(_msg, stud if highlight else None)) if got_error else
482+
eq_fun(eval_student, eval_solution, Feedback(_msg, stud if highlight else None)))
477483

478484

479485

tests/test_test_comp.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ def setUp(self):
1515
iter_vars_names=True,
1616
incorrect_iter_vars_msg=None,
1717
body=lambda: test_expression_result(context_vals = ['a', 2]),
18-
ifs=[lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False]),
19-
lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False])],
18+
ifs=[lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False], highlight=True),
19+
lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False], highlight=True)],
2020
insufficient_ifs_msg=None,
2121
expand_message=True)
2222
'''
@@ -96,8 +96,8 @@ def test_pass_mix_lam(self):
9696
iter_vars_names=True,
9797
incorrect_iter_vars_msg=None,
9898
body=test_expression_result(context_vals = ['a', 2]),
99-
ifs=[test_function_v2('isinstance', params = ['obj'], do_eval = [False]),
100-
test_function_v2('isinstance', params = ['obj'], do_eval = [False])],
99+
ifs=[test_function_v2('isinstance', params = ['obj'], do_eval = [False], highlight=True),
100+
test_function_v2('isinstance', params = ['obj'], do_eval = [False], highlight=True)],
101101
insufficient_ifs_msg=None,
102102
expand_message=True)
103103
'''
@@ -124,8 +124,8 @@ def setUp(self):
124124
iter_vars_names=True,
125125
incorrect_iter_vars_msg='incorrectitervars',
126126
body=lambda: test_expression_result(context_vals = ['a', 2], incorrect_msg = 'bodyincorrect'),
127-
ifs=[lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False], not_called_msg = 'notcalled1', incorrect_msg = 'incorrect2'),
128-
lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False], not_called_msg = 'notcalled2', incorrect_msg = 'incorrect2')],
127+
ifs=[lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False], not_called_msg = 'notcalled1', incorrect_msg = 'incorrect2', highlight=True),
128+
lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False], not_called_msg = 'notcalled2', incorrect_msg = 'incorrect2', highlight=True)],
129129
insufficient_ifs_msg='insufficientifs')
130130
'''
131131
}
@@ -311,7 +311,7 @@ def setUp(self):
311311
incorrect_iter_vars_msg=None,
312312
key=lambda: test_expression_result(context_vals = ['a']),
313313
value=lambda: test_expression_result(context_vals = ['a']),
314-
ifs=[lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False])],
314+
ifs=[lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False], highlight=True)],
315315
insufficient_ifs_msg=None,
316316
expand_message=True)
317317
'''
@@ -395,8 +395,8 @@ def setUp(self):
395395
iter_vars_names=True,
396396
incorrect_iter_vars_msg=None,
397397
body=lambda: test_expression_result(context_vals = ['a', 2]),
398-
ifs=[lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False]),
399-
lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False])],
398+
ifs=[lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False], highlight=True),
399+
lambda: test_function_v2('isinstance', params = ['obj'], do_eval = [False], highlight=True)],
400400
insufficient_ifs_msg=None,
401401
expand_message=True)
402402
'''

tests/test_test_for_loop.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def setUp(self):
1515
''',
1616
"DC_SCT": '''
1717
test_for_loop(1,
18-
lambda: test_function("range"),
18+
lambda: test_function("range", highlight=True),
1919
lambda: test_object_after_expression("size", {"size": 1}, [1]))
2020
success_msg("Great!")
2121
'''
@@ -88,7 +88,7 @@ def setUp(self):
8888
''',
8989
"DC_SCT": '''
9090
msg = "loopinggonewrong"
91-
test_for_loop(1, for_iter=lambda msg=msg: test_function("enumerate", incorrect_msg = msg))
91+
test_for_loop(1, for_iter=lambda msg=msg: test_function("enumerate", incorrect_msg = msg, highlight=True))
9292
9393
msg = "blabla"
9494
test_for_loop(1, body=lambda msg=msg: test_expression_output(incorrect_msg = msg, context_vals = [2, "test"]))
@@ -137,7 +137,7 @@ def test_Pass_spec(self):
137137
forl = Ex().check_for_loop(0)
138138
139139
forl.check_iter()\
140-
.multi(test_function("enumerate", incorrect_msg=msg))
140+
.multi(test_function("enumerate", incorrect_msg=msg, highlight=True))
141141
142142
msg = "blabla"
143143
forl.check_body()\
@@ -165,7 +165,7 @@ def setUp(self):
165165
.check_for_loop(0)\
166166
.check_body()\
167167
.set_context(jj=2)\
168-
.multi(test_function('sum', incorrect_msg="wronginnerfor"))
168+
.multi(test_function('sum', incorrect_msg="wronginnerfor", highlight=True))
169169
'''
170170
}
171171

tests/test_test_function.py

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ def test_line_numbers1(self):
458458
self.data = {"DC_PEC": '',
459459
"DC_SOLUTION": "round(1.23456, ndigits = 1)",
460460
"DC_CODE": "round(1.34567, ndigits = 1)",
461-
"DC_SCT": "test_function('round', index = 1)"}
461+
"DC_SCT": "test_function('round', index = 1, highlight=True)"}
462462
sct_payload = helper.run(self.data)
463463
self.assertFalse(sct_payload['correct'])
464464
self.assertIn("Did you call <code>round()</code> with the correct arguments? The first argument seems to be incorrect.", sct_payload['message'])
@@ -468,7 +468,7 @@ def test_line_numbers(self):
468468
self.data = {"DC_PEC": '',
469469
"DC_SOLUTION": "round(1.23456, ndigits = 1)",
470470
"DC_CODE": "round(1.23456, ndigits = 3)",
471-
"DC_SCT": "test_function('round', index = 1)"}
471+
"DC_SCT": "test_function('round', index = 1, highlight=True)"}
472472
sct_payload = helper.run(self.data)
473473
self.assertFalse(sct_payload['correct'])
474474
self.assertIn("Did you call <code>round()</code> with the correct arguments? Keyword <code>ndigits</code> seems to be incorrect.", sct_payload['message'])
@@ -488,7 +488,7 @@ def test_nested_arg2(self):
488488
self.data = {"DC_PEC": '',
489489
"DC_SOLUTION": "print(type([1, 2, 3]))",
490490
"DC_CODE": "print(type([1, 2, 4]))",
491-
"DC_SCT": "test_function('type')"}
491+
"DC_SCT": "test_function('type', highlight=True)"}
492492
sct_payload = helper.run(self.data)
493493
self.assertFalse(sct_payload['correct'])
494494
helper.test_lines(self, sct_payload, 1, 1, 12, 20)
@@ -497,15 +497,15 @@ def test_nested_keyw1(self):
497497
self.data = {"DC_PEC": '',
498498
"DC_SOLUTION": "round(1.1234, ndigits = max([1, 2, 3]))",
499499
"DC_CODE": "round(1.1234, ndigits = max([1, 2, 3]))",
500-
"DC_SCT": "test_function('max')"}
500+
"DC_SCT": "test_function('max', highlight=True)"}
501501
sct_payload = helper.run(self.data)
502502
self.assertTrue(sct_payload['correct'])
503503

504504
def test_nested_keyw2(self):
505505
self.data = {"DC_PEC": '',
506506
"DC_SOLUTION": "round(1.1234, ndigits = max([1, 2, 3]))",
507507
"DC_CODE": "round(1.1234, ndigits = max([1, 2]))",
508-
"DC_SCT": "test_function('max')"}
508+
"DC_SCT": "test_function('max', highlight=True)"}
509509
sct_payload = helper.run(self.data)
510510
self.assertFalse(sct_payload['correct'])
511511
helper.test_lines(self, sct_payload, 1, 1, 29, 34)
@@ -558,7 +558,7 @@ def test_do_eval_none_fail1(self):
558558
self.data = {"DC_PEC": '',
559559
"DC_SOLUTION": "round(123.123, ndigits = 2)",
560560
"DC_CODE": "round(123.123)",
561-
"DC_SCT": "test_function('round', do_eval = None)"}
561+
"DC_SCT": "test_function('round', do_eval = None, highlight=True)"}
562562
sct_payload = helper.run(self.data)
563563
self.assertFalse(sct_payload['correct'])
564564
self.assertEqual("Have you specified all required arguments inside <code>round()</code>?", sct_payload['message'])
@@ -568,7 +568,7 @@ def test_do_eval_none_fail2(self):
568568
self.data = {"DC_PEC": '',
569569
"DC_SOLUTION": "round(123.123)", # args = [0]
570570
"DC_CODE": "round(number = 123.123)", # student args is len 0
571-
"DC_SCT": "test_function('round', do_eval = None)"}
571+
"DC_SCT": "test_function('round', do_eval = None, highlight=True)"}
572572
sct_payload = helper.run(self.data)
573573
self.assertFalse(sct_payload['correct'])
574574
self.assertEqual("Have you specified all required arguments inside <code>round()</code>?", sct_payload['message'])
@@ -578,7 +578,7 @@ def test_do_eval_none_fail3(self):
578578
self.data = {"DC_PEC": '',
579579
"DC_SOLUTION": "round(123.123, 2)", # args = [0, 1]
580580
"DC_CODE": "round(123.123)", # student_args is len 1
581-
"DC_SCT": "test_function('round', do_eval = None)"}
581+
"DC_SCT": "test_function('round', do_eval = None, highlight=True)"}
582582
sct_payload = helper.run(self.data)
583583
self.assertFalse(sct_payload['correct'])
584584
self.assertEqual("Have you specified all required arguments inside <code>round()</code>?", sct_payload['message'])
@@ -594,9 +594,9 @@ def setUp(self):
594594
print([1, 2, 3])
595595
''',
596596
"DC_SCT": '''
597-
test_function("print", index = 1)
598-
test_function("print", index = 2)
599-
test_function("print", index = 3)
597+
test_function("print", index = 1, highlight=True)
598+
test_function("print", index = 2, highlight=True)
599+
test_function("print", index = 3, highlight=True)
600600
'''
601601
}
602602
self.DC_SCT_SPEC2 = '''
@@ -626,6 +626,18 @@ def test_multiple_4(self):
626626
self.assertIn("Did you call <code>print()</code> with the correct arguments? The first argument seems to be incorrect.", sct_payload['message'])
627627
helper.test_lines(self, sct_payload, 1, 1, 7, 11)
628628

629+
def test_multiple_4_no_highlight(self):
630+
self.data["DC_CODE"] = 'print("acb")\nprint(1234)\nprint([1, 2, 3])'
631+
self.data["DC_SCT"] = """
632+
test_function("print", index = 1, highlight = False)
633+
test_function("print", index = 2)
634+
test_function("print", index = 3)
635+
"""
636+
sct_payload = helper.run(self.data)
637+
self.assertFalse(sct_payload['correct'])
638+
self.assertIn("Did you call <code>print()</code> with the correct arguments? The first argument seems to be incorrect.", sct_payload['message'])
639+
self.assertEqual(sct_payload.get('line_start'), None)
640+
629641
def test_multiple_5(self):
630642
self.data["DC_CODE"] = 'print("abc")\nprint(1234)\nprint([1, 2, 3])'
631643
sct_payload = helper.run(self.data)
@@ -640,6 +652,13 @@ def test_multiple_6(self):
640652
self.assertIn("Did you call <code>print()</code> with the correct arguments? The first argument seems to be incorrect.", sct_payload['message'])
641653
helper.test_lines(self, sct_payload, 3, 3, 7, 18)
642654

655+
def test_nohighlight_too_few_calls(self):
656+
self.data["DC_SCT"] = 'test_function("print", index = 3, args = [], keywords = [])\n' + self.data["DC_SCT"]
657+
self.data["DC_CODE"] = 'print("abc")\nprint(1234)'
658+
sct_payload = helper.run(self.data)
659+
self.assertFalse(sct_payload['correct'])
660+
self.assertEqual(sct_payload.get('line_start'), None)
661+
643662

644663

645664
if __name__ == "__main__":

0 commit comments

Comments
 (0)