def test_calculate_should_execute_usercode_with_correct_context_and_curried_evaluate_formulae_in_context( self, mock_evaluate_formulae_in_context, mock_execute_usercode ): worksheet = Worksheet() calculate(worksheet, sentinel.usercode, sentinel.private_key) args, kwargs = mock_execute_usercode.call_args self.assertEquals(kwargs, {}) self.assertEquals(args[0], sentinel.usercode) context = args[1] self.assertEquals(context['CellRange'], CellRange) self.assertEquals(context['DateTime'], DateTime) self.assertEquals(context['FormulaError'], FormulaError) self.assertEquals(context['_raise'], _raise) self.assertEquals(context['sys'], sys) self.assertEquals(context['worksheet'], worksheet) self.assertEquals(context['load_constants'], load_constants) self.assertEquals(context['undefined'], undefined) evaluate_formulae = context['evaluate_formulae'] evaluate_formulae(sentinel.worksheet) self.assertEquals( mock_evaluate_formulae_in_context.call_args, ((sentinel.worksheet, context), {}) )
def test_calculate_should_execute_usercode_with_correct_context_and_curried_evaluate_formulae_in_context( self, mock_evaluate_formulae_in_context, mock_execute_usercode): worksheet = Worksheet() calculate(worksheet, sentinel.usercode, sentinel.private_key) args, kwargs = mock_execute_usercode.call_args self.assertEquals(kwargs, {}) self.assertEquals(args[0], sentinel.usercode) context = args[1] self.assertEquals(context['CellRange'], CellRange) self.assertEquals(context['DateTime'], DateTime) self.assertEquals(context['FormulaError'], FormulaError) self.assertEquals(context['_raise'], _raise) self.assertEquals(context['sys'], sys) self.assertEquals(context['worksheet'], worksheet) self.assertEquals(context['load_constants'], load_constants) self.assertEquals(context['undefined'], undefined) evaluate_formulae = context['evaluate_formulae'] evaluate_formulae(sentinel.worksheet) self.assertEquals(mock_evaluate_formulae_in_context.call_args, ((sentinel.worksheet, context), {}))
def test_calculate_catches_and_reports_exceptions_to_console(self): def patched_execute_usercode(_, context): exec( 'import sys\n' 'def func():\n' ' x = my_value\n' 'func()\n', context ) worksheet = Worksheet() worksheet.add_console_text = Mock() original_execute_usercode = calculate_module.execute_usercode calculate_module.execute_usercode = patched_execute_usercode try: calculate(worksheet, sentinel.usercode, sentinel.private_key) finally: calculate_module.execute_usercode = original_execute_usercode expected_error_text = dedent(""" NameError: global name \'my_value\' is not defined User code line 4 User code line 3, in func\n""")[1:] self.assertIn( call(expected_error_text), worksheet.add_console_text.call_args_list )
def test_calculate_clears_previous_worksheet_console_text_and_reports_time_when_theres_an_error( self, mock_time, mock_execute_usercode): recalc_times = [1.3245, 0] def mock_time_fn(): return recalc_times.pop() mock_time.side_effect = mock_time_fn def throw_error(_, __): raise Exception('argh') mock_execute_usercode.side_effect = throw_error worksheet = Worksheet() worksheet._console_text = 'previous errors\n' worksheet.add_console_text = Mock() calculate(worksheet, sentinel.usercode, sentinel.private_key) self.assertNotIn('previous errors', worksheet._console_text) self.assertEquals( worksheet.add_console_text.call_args_list[-1], (('Took 1.32s', ), { 'log_type': 'system' }), )
def test_constant(self): worksheet = Worksheet() worksheet[1, 2].formula = '3' calculate(worksheet, SANITY_CHECK_USERCODE % ('', ''), sentinel.private_key) self.assertEquals(worksheet.keys(), [(1, 2)]) self.assertEquals(worksheet[(1, 2)].formula, '3') self.assertEquals(worksheet[(1, 2)].value, 3)
def test_calculate_catches_usercode_exceptions(self, mock_execute_usercode): worksheet = Worksheet() def execute_usercode(_, __): exec('1/0\n') mock_execute_usercode.side_effect = execute_usercode try: calculate(worksheet, sentinel.usercode, sentinel.private_key) except: self.fail("Unhandled exception when executing broken usercode")
def test_python_formulae(self): worksheet = Worksheet() worksheet[1, 1].python_formula = '1' worksheet[1, 2].python_formula = '2' worksheet[1, 3].python_formula = '1 + 2' calculate(worksheet, SANITY_CHECK_USERCODE % ('', ''), sentinel.private_key) self.assertEquals(set(worksheet.keys()), set([(1, 1), (1, 2), (1, 3)])) self.assertEquals(worksheet[1, 1].value, 1) self.assertEquals(worksheet[1, 2].value, 2) self.assertEquals(worksheet[1, 3].value, 3)
def test_postformula_usercode(self): worksheet = Worksheet() worksheet[1, 1].formula = '=1' postformula_usercode = 'worksheet[1, 2].value = worksheet[1, 1].value + 1' calculate(worksheet, SANITY_CHECK_USERCODE % ('', postformula_usercode), sentinel.private_key) self.assertEquals(set(worksheet.keys()), set([(1, 1), (1, 2)])) self.assertEquals(worksheet[1, 1].value, 1) self.assertEquals(worksheet[1, 2].value, 2) self.assertEquals(worksheet[1, 1].formula, '=1') self.assertEquals(worksheet[1, 2].formula, None)
def test_calculate_patches_sys_stdout_in_context( self, mock_execute_usercode ): worksheet = Worksheet() def check_stdout(_, context): self.assertEquals(type(context['sys'].stdout), MyStdout) self.assertEquals(context['sys'].stdout.worksheet, worksheet) mock_execute_usercode.side_effect = check_stdout calculate(worksheet, sentinel.usercode, sentinel.private_key) self.assertNotEqual(type(sys.stdout), MyStdout)
def test_calculate_puts_curried_run_worksheet_into_context(self, mock_run_worksheet, mock_execute_usercode): worksheet = Worksheet() calculate(worksheet, sentinel.usercode, sentinel.private_key) args, kwargs = mock_execute_usercode.call_args context = args[1] curried_run_worksheet = context['run_worksheet'] self.assertEquals(mock_run_worksheet.call_args_list, []) curried_run_worksheet(sentinel.urls) self.assertCalledOnce(mock_run_worksheet, sentinel.urls, None, sentinel.private_key) mock_run_worksheet.reset_mock() curried_run_worksheet(sentinel.urls, sentinel.overrides) self.assertCalledOnce(mock_run_worksheet, sentinel.urls, sentinel.overrides, sentinel.private_key)
def test_calculate_clears_previous_worksheet_cell_values_before_executing_usercode( self, mock_execute_usercode ): calls_list = [] worksheet = Worksheet() worksheet.clear_values = Mock() worksheet.clear_values.side_effect = lambda *args : calls_list.append('clear values') mock_execute_usercode.side_effect = lambda *args : calls_list.append('execute usercode') calculate(worksheet, sentinel.usercode, sentinel.private_key) self.assertEquals(calls_list, ['clear values', 'execute usercode'])
def test_calculate_patches_sys_stdout_in_context(self, mock_execute_usercode): worksheet = Worksheet() def check_stdout(_, context): self.assertEquals(type(context['sys'].stdout), MyStdout) self.assertEquals(context['sys'].stdout.worksheet, worksheet) mock_execute_usercode.side_effect = check_stdout calculate(worksheet, sentinel.usercode, sentinel.private_key) self.assertNotEqual(type(sys.stdout), MyStdout)
def test_calculate_clears_previous_worksheet_console_text_and_reports_time(self, mock_time): recalc_times = [1.3245, 0] def mock_time_fn(): return recalc_times.pop() mock_time.side_effect = mock_time_fn worksheet = Worksheet() worksheet._console_text = 'previous errors' worksheet.add_console_text = Mock() calculate(worksheet, sentinel.usercode, sentinel.private_key) expected_text = 'Took 1.32s' self.assertEquals(worksheet.add_console_text.call_args_list[0], ((expected_text,),{'log_type':'system'}) )
def test_calculate_clears_previous_worksheet_cell_values_before_executing_usercode( self, mock_execute_usercode): calls_list = [] worksheet = Worksheet() worksheet.clear_values = Mock() worksheet.clear_values.side_effect = lambda *args: calls_list.append( 'clear values') mock_execute_usercode.side_effect = lambda *args: calls_list.append( 'execute usercode') calculate(worksheet, sentinel.usercode, sentinel.private_key) self.assertEquals(calls_list, ['clear values', 'execute usercode'])
def test_multiple_constants(self): worksheet = Worksheet() worksheet[1, 2].formula = '3' worksheet[3, 4].formula = '4+5' worksheet[2, 5].formula = 'blurgle' calculate(worksheet, SANITY_CHECK_USERCODE % ('', ''), sentinel.private_key) self.assertEquals(set(worksheet.keys()), set([(1, 2), (3, 4), (2, 5)])) self.assertEquals(worksheet[1, 2].formula, '3') self.assertEquals(worksheet[3, 4].formula, '4+5') self.assertEquals(worksheet[2, 5].formula, 'blurgle') self.assertEquals(worksheet[1, 2].value, 3) self.assertEquals(worksheet[3, 4].value, '4+5') self.assertEquals(worksheet[2, 5].value, 'blurgle')
def test_calculate_catches_and_reports_syntax_errors_to_console(self, mock_evaluate_formulae_in_context, mock_execute_usercode): worksheet = Worksheet() worksheet.add_console_text = Mock() def execute_usercode(_, __): exec('import sys:\nx == my_value') mock_execute_usercode.side_effect = execute_usercode calculate(worksheet, sentinel.usercode, sentinel.private_key) expected_error_text = 'Syntax error at character 11 (line 1)\n' self.assertIn( ((expected_error_text,), {}), worksheet.add_console_text.call_args_list )
def test_calculate_catches_and_reports_syntax_errors_to_console( self, mock_evaluate_formulae_in_context, mock_execute_usercode): worksheet = Worksheet() worksheet.add_console_text = Mock() def execute_usercode(_, __): exec('import sys:\nx == my_value') mock_execute_usercode.side_effect = execute_usercode calculate(worksheet, sentinel.usercode, sentinel.private_key) expected_error_text = 'Syntax error at character 11 (line 1)\n' self.assertIn(((expected_error_text, ), {}), worksheet.add_console_text.call_args_list)
def test_preformula_usercode(self): worksheet = Worksheet() worksheet[1, 1].formula = '3' worksheet[1, 3].formula = '=A2 + 1' preformula_usercode = "worksheet[1, 2].value = worksheet[1, 1].value + 1" calculate(worksheet, SANITY_CHECK_USERCODE % (preformula_usercode, ''), sentinel.private_key) self.assertEquals(set(worksheet.keys()), set([(1, 1), (1, 2), (1, 3)])) self.assertEquals(worksheet[1, 1].value, 3) self.assertEquals(worksheet[1, 2].value, 4) self.assertEquals(worksheet[1, 3].value, 5) self.assertEquals(worksheet[1, 1].formula, '3') self.assertEquals(worksheet[1, 2].formula, None) self.assertEquals(worksheet[1, 3].formula, '=A2 + 1')
def test_arithmetic(self): worksheet = Worksheet() worksheet[1, 2].formula = '=3' worksheet[3, 4].formula = '=4+5' worksheet[4, 4].formula = '=1/10' calculate(worksheet, SANITY_CHECK_USERCODE % ('', ''), sentinel.private_key) self.assertEquals(set(worksheet.keys()), set([(1, 2), (3, 4), (4, 4)])) self.assertEquals(worksheet[1, 2].value, 3) self.assertEquals(worksheet[3, 4].value, 9) self.assertEquals(worksheet[4, 4].value, 0.1) self.assertEquals(worksheet[1, 2].formula, '=3') self.assertEquals(worksheet[3, 4].formula, '=4+5') self.assertEquals(worksheet[4, 4].formula, '=1/10')
def test_calculate_catches_and_reports_syntax_errors_with_special_message_in_worksheet_usercode_error_field( self): def patched_execute_usercode(_, __): exec('import sys:\nx == my_value') worksheet = Worksheet() original_execute_usercode = calculate_module.execute_usercode calculate_module.execute_usercode = patched_execute_usercode try: calculate(worksheet, sentinel.usercode, sentinel.private_key) finally: calculate_module.execute_usercode = original_execute_usercode expected = {'message': 'Syntax error at character 11', 'line': 1} self.assertEquals(worksheet._usercode_error, expected)
def test_calculate_puts_curried_run_worksheet_into_context( self, mock_run_worksheet, mock_execute_usercode): worksheet = Worksheet() calculate(worksheet, sentinel.usercode, sentinel.private_key) args, kwargs = mock_execute_usercode.call_args context = args[1] curried_run_worksheet = context['run_worksheet'] self.assertEquals(mock_run_worksheet.call_args_list, []) curried_run_worksheet(sentinel.urls) self.assertCalledOnce(mock_run_worksheet, sentinel.urls, None, sentinel.private_key) mock_run_worksheet.reset_mock() curried_run_worksheet(sentinel.urls, sentinel.overrides) self.assertCalledOnce(mock_run_worksheet, sentinel.urls, sentinel.overrides, sentinel.private_key)
def test_calculate_catches_and_reports_exceptions_in_worksheet_usercode_error_field(self, mock_evaluate_formulae_in_context, mock_execute_usercode): worksheet = Worksheet() def execute_usercode(_, __): exec( 'import sys\n' 'def func():\n' ' x = my_value\n' 'func()\n' ) mock_execute_usercode.side_effect = execute_usercode calculate(worksheet, sentinel.usercode, sentinel.private_key) expected = { 'message': 'NameError: global name \'my_value\' is not defined', 'line': 3, } self.assertEquals(worksheet._usercode_error, expected)
def test_preformula_usercode_functions(self): worksheet = Worksheet() worksheet[1, 1].formula = '1' worksheet[1, 2].formula = '=foo(3)' preformula_usercode = dedent(''' def foo(value): return worksheet[1, 1].value + value ''') calculate(worksheet, SANITY_CHECK_USERCODE % (preformula_usercode, ''), sentinel.private_key) self.assertEquals(set(worksheet.keys()), set([(1, 1), (1, 2)])) self.assertEquals(worksheet[1, 1].value, 1) self.assertEquals(worksheet[1, 2].value, 4) self.assertEquals(worksheet[1, 1].formula, '1') self.assertEquals(worksheet[1, 2].formula, '=foo(3)')
def test_calculate_catches_and_reports_exceptions_in_worksheet_usercode_error_field( self, mock_evaluate_formulae_in_context, mock_execute_usercode): worksheet = Worksheet() def execute_usercode(_, __): exec('import sys\n' 'def func():\n' ' x = my_value\n' 'func()\n') mock_execute_usercode.side_effect = execute_usercode calculate(worksheet, sentinel.usercode, sentinel.private_key) expected = { 'message': 'NameError: global name \'my_value\' is not defined', 'line': 3, } self.assertEquals(worksheet._usercode_error, expected)
def test_calculate_clears_previous_worksheet_console_text_and_reports_time( self, mock_time): recalc_times = [1.3245, 0] def mock_time_fn(): return recalc_times.pop() mock_time.side_effect = mock_time_fn worksheet = Worksheet() worksheet._console_text = 'previous errors' worksheet.add_console_text = Mock() calculate(worksheet, sentinel.usercode, sentinel.private_key) expected_text = 'Took 1.32s' self.assertEquals(worksheet.add_console_text.call_args_list[0], ((expected_text, ), { 'log_type': 'system' }))
def test_formulae(self): worksheet = Worksheet() worksheet[1, 1].formula = '=1' worksheet[1, 2].formula = '=2' worksheet[1, 3].formula = '=A1 + A2' worksheet[1, 4].formula = '=DateTime(2000, 1, 2, 3, 4, 5)' calculate(worksheet, SANITY_CHECK_USERCODE % ('', ''), sentinel.private_key) self.assertEquals(set(worksheet.keys()), set([(1, 1), (1, 2), (1, 3), (1, 4)])) self.assertEquals(worksheet[1, 1].value, 1) self.assertEquals(worksheet[1, 2].value, 2) self.assertEquals(worksheet[1, 3].value, 3) self.assertEquals(worksheet[1, 4].value, datetime(2000, 1, 2, 3, 4, 5)) self.assertEquals(worksheet[1, 1].formula, '=1') self.assertEquals(worksheet[1, 2].formula, '=2') self.assertEquals(worksheet[1, 3].formula, '=A1 + A2') self.assertEquals(worksheet[1, 4].formula, '=DateTime(2000, 1, 2, 3, 4, 5)')
def test_calculate_catches_and_reports_syntax_errors_with_special_message_in_worksheet_usercode_error_field(self): def patched_execute_usercode(_, __): exec('import sys:\nx == my_value') worksheet = Worksheet() original_execute_usercode = calculate_module.execute_usercode calculate_module.execute_usercode = patched_execute_usercode try: calculate(worksheet, sentinel.usercode, sentinel.private_key) finally: calculate_module.execute_usercode = original_execute_usercode expected = { 'message': 'Syntax error at character 11', 'line': 1 } self.assertEquals(worksheet._usercode_error, expected)
def test_calculate_clears_previous_worksheet_console_text_and_reports_time_when_theres_an_error(self, mock_time, mock_execute_usercode): recalc_times = [1.3245, 0] def mock_time_fn(): return recalc_times.pop() mock_time.side_effect = mock_time_fn def throw_error(_, __): raise Exception('argh') mock_execute_usercode.side_effect = throw_error worksheet = Worksheet() worksheet._console_text = 'previous errors\n' worksheet.add_console_text = Mock() calculate(worksheet, sentinel.usercode, sentinel.private_key) self.assertNotIn('previous errors', worksheet._console_text) self.assertEquals( worksheet.add_console_text.call_args_list[-1], (('Took 1.32s',),{'log_type':'system'}), )
def test_calculate_catches_and_reports_exceptions_to_console(self): def patched_execute_usercode(_, context): exec( 'import sys\n' 'def func():\n' ' x = my_value\n' 'func()\n', context) worksheet = Worksheet() worksheet.add_console_text = Mock() original_execute_usercode = calculate_module.execute_usercode calculate_module.execute_usercode = patched_execute_usercode try: calculate(worksheet, sentinel.usercode, sentinel.private_key) finally: calculate_module.execute_usercode = original_execute_usercode expected_error_text = dedent(""" NameError: global name \'my_value\' is not defined User code line 4 User code line 3, in func\n""")[1:] self.assertIn(call(expected_error_text), worksheet.add_console_text.call_args_list)
def test_calculate_clears_previous_worksheet_usercode_error( self, mock_evaluate_formulae_in_context, mock_execute_usercode): worksheet = Worksheet() worksheet._usercode_error = "Argh!" calculate(worksheet, sentinel.usercode, sentinel.private_key) self.assertEquals(worksheet._usercode_error, None)
def test_totally_empty(self): worksheet = Worksheet() calculate(worksheet, '', sentinel.private_key) self.assertEquals(worksheet, Worksheet())
def test_empty_worksheet(self): worksheet = Worksheet() calculate(worksheet, SANITY_CHECK_USERCODE % ('', ''), sentinel.private_key) self.assertEquals(worksheet, Worksheet())
def test_calculate_clears_previous_worksheet_usercode_error(self, mock_evaluate_formulae_in_context, mock_execute_usercode): worksheet = Worksheet() worksheet._usercode_error = "Argh!" calculate(worksheet, sentinel.usercode, sentinel.private_key) self.assertEquals(worksheet._usercode_error, None)