def test_iteration_yields_cells(self): ws = Worksheet() ws[1, 1].formula = 'A1' ws[2, 4].formula = 'B4' ws.name = 'any old name' self.assertEquals(ws.items(), [((1, 1), ws[1, 1]), ((2, 4), ws[2, 4])])
def test_recalc_cell_catches_cell_errors_and_adds_them_to_console(self): cell = Cell() cell.formula = "=123" cell.python_formula = '_raise(Exception("OMGWTFBBQ"))' cell.error = 'old error, just hanging around...' worksheet = Worksheet() location = (1, 11) worksheet[location] = cell # Mocked out to avoid explosion -- tested in another unit test. node = Mock() node.parents = [] graph = {location: node} context = {'worksheet': worksheet, "_raise": _raise} worksheet.add_console_text = Mock() recalculate_cell(location, Mock(), graph, context) self.assertEqual(worksheet[location].error, 'Exception: OMGWTFBBQ') expected_error_text = "Exception: OMGWTFBBQ\n Formula '%s' in A11\n" % ( cell.formula) self.assertCalledOnce(worksheet.add_console_text, expected_error_text) self.assertEquals(worksheet[location].value, undefined)
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_api_view_should_return_errors_and_no_values_if_unjsonify_worksheet_result_has_errors(self, mock_get_object): mock_sheet = mock_get_object.return_value mock_sheet.owner = self.user worksheet = Worksheet() worksheet[1, 3].formula = '=string' worksheet[1, 3].value = 'test value' worksheet._usercode_error = { "message": "I am an error message", "line": 2 } mock_sheet.unjsonify_worksheet.side_effect = lambda: worksheet mock_sheet.allow_json_api_access = True self.request.method = 'POST' self.request.POST['api_key'] = mock_sheet.api_key = 'key' expected_json = { "usercode_error" : { "message": "I am an error message", "line": "2" } } actual = calculate_and_get_json_for_api(self.request, self.user.username, self.sheet.id) self.assertFalse(mock_sheet.save.called) self.assertTrue(isinstance(actual, HttpResponse)) self.assertEquals(actual.content, json.dumps(expected_json))
def test_clear_values_deletes_cells_with_empty_formula(self): ws = Worksheet() ws[1, 2].formula = '' ws[1, 2].value = "hello!" ws[1, 2].formatted_value = "Guten Tag!" ws.clear_values() self.assertFalse((1, 2) in ws)
def test_recalc_cell_catches_cell_errors_and_adds_them_to_console(self): cell = Cell() cell.formula = "=123" cell.python_formula = '_raise(Exception("OMGWTFBBQ"))' cell.error = 'old error, just hanging around...' worksheet = Worksheet() location = (1, 11) worksheet[location] = cell # Mocked out to avoid explosion -- tested in another unit test. node = Mock() node.parents = [] graph = {location: node } context = { 'worksheet': worksheet, "_raise": _raise } worksheet.add_console_text = Mock() recalculate_cell(location, Mock(), graph, context) self.assertEqual( worksheet[location].error, 'Exception: OMGWTFBBQ' ) expected_error_text = "Exception: OMGWTFBBQ\n Formula '%s' in A11\n" % ( cell.formula) self.assertCalledOnce(worksheet.add_console_text, expected_error_text) self.assertEquals(worksheet[location].value, undefined)
def test_two_tuple_parameters(self): ws = Worksheet() cell_range = ws.cell_range((2, 3), (5, 4)) self.assertEquals(cell_range.left, 2) self.assertEquals(cell_range.top, 3) self.assertEquals(cell_range.right, 5) self.assertEquals(cell_range.bottom, 4)
def test_mystdout_pushes_print_commands_to_worksheet(self): ws = Worksheet() mso = MyStdout(ws) mso.write('weeeeeee!') ws2 = Worksheet() ws2.add_console_text('weeeeeee!', log_type='output') self.assertEquals(ws._console_text, ws2._console_text)
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_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_setattr_should_not_delegate_to_setitem_if_attr_name_is_not_valid_cell_name(self): ws = Worksheet() ws.__setitem__ = Mock() ws.A1 = 23 self.assertEquals( ws.__setitem__.call_args_list, [] ) self.assertEquals( ws.A1, 23 )
def test_getattr_should_delegate_to_getitem(self): ws = Worksheet() ws.__getitem__ = Mock() retval = ws.A1 self.assertEquals( retval, ws.__getitem__.return_value ) self.assertEquals( ws.__getitem__.call_args_list, [(('A1',), {})] )
def test_setitem_on_locations_should_reject_non_cell_instances(self): ws = Worksheet() ws.to_location = Mock(return_value=(1, 2)) expected_message_re = "^Worksheet locations must be Cell objects" with self.assertRaisesRegexp(TypeError, expected_message_re): ws[3, 4] = 123 self.assertEquals(ws.to_location.call_args_list, [(((3, 4),), {})])
def test_setitem_on_locations_should_reject_non_cell_instances(self): ws = Worksheet() ws.to_location = Mock(return_value=(1, 2)) expected_message_re = "^Worksheet locations must be Cell objects" with self.assertRaisesRegexp(TypeError, expected_message_re): ws[3, 4] = 123 self.assertEquals(ws.to_location.call_args_list, [(((3, 4), ), {})])
def test_getattr_should_delegate_to_getitem(self): ws = Worksheet() ws.__getitem__ = Mock() retval = ws.A1 self.assertEquals(retval, ws.__getitem__.return_value) self.assertEquals(ws.__getitem__.call_args_list, [(('A1', ), {})])
def test_setitem_on_non_locations_raises_keyerror(self): ws = Worksheet() ws.to_location = Mock(return_value=None) with self.assertRaisesRegexp( InvalidKeyError, "^'random key' is not a valid cell location$"): ws['random key'] = 'sausages'
def test_run_worksheet_with_overrides(self, mock_urllib2): self.maxDiff = None cellA2 = Cell() cellA2.formula = '1' cellA2.value = 1 cellC3 = Cell() cellC3.formula = '5' cellC3.value = 5 cellE4 = Cell() cellE4.formula = '=A2 + C3' cellE4.value = 6 overrides = { (1, 2): '11', (3, 3): 55, (4, 1): '="abc"', 'dirigible_l337_private_key': sentinel.private_key } result_of_calculation_json = '''{ "name": "Untitled", "1": { "2": 11 }, "3": { "3": 55 }, "4": { "1": "abc" }, "5": { "4": 66 } }''' mock_opener = mock_urllib2.build_opener.return_value mock_urlopen_file = mock_opener.open.return_value mock_urlopen_file.read.return_value = result_of_calculation_json worksheet_url = 'ws_url/' result = run_worksheet(worksheet_url, overrides, sentinel.private_key) target_url = '%sv%s/json/' % (worksheet_url, CURRENT_API_VERSION) self.assertCalledOnce(mock_opener.open, target_url, data=urlencode(overrides)) self.assertEquals(type(result), Worksheet) expected_sheet = Worksheet() expected_sheet.name = 'Untitled' expected_sheet[1, 2].value = 11 expected_sheet[3, 3].value = 55 expected_sheet[4, 1].value = 'abc' expected_sheet[5, 4].value = 66 self.assertEquals(result, expected_sheet)
def test_setitem_on_locations_should_accept_cell_instances(self): ws = Worksheet() ws.to_location = Mock(return_value=(1, 2)) cell = Cell() ws[3, 4] = cell self.assertEquals(ws.to_location.call_args_list, [(((3, 4), ), {})]) self.assertEquals(ws.keys(), [(1, 2)])
def test_getitem_should_use_to_location_result_if_it_is_not_none(self): ws = Worksheet() ws.to_location = Mock(return_value=(1, 2)) ws[3, 4].formula = "hello" self.assertEquals(ws.to_location.call_args_list, [(((3, 4), ), {})]) self.assertEquals(ws.keys(), [(1, 2)]) self.assertEquals(ws.values()[0].formula, "hello")
def test_getitem_should_use_to_location_result_if_it_is_not_none(self): ws = Worksheet() ws.to_location = Mock(return_value=(1, 2)) ws[3, 4].formula = "hello" self.assertEquals(ws.to_location.call_args_list, [(((3, 4),), {})]) self.assertEquals(ws.keys(), [(1, 2)]) self.assertEquals(ws.values()[0].formula, "hello")
def test_getitem_should_use_original_key_if_to_location_gives_none(self): ws = Worksheet() ws.to_location = Mock(return_value=(3, 4)) ws[3, 4].formula = "hello" self.assertEquals(ws.to_location.call_args_list, [(((3, 4), ), {})]) self.assertEquals(ws.keys(), [(3, 4)]) self.assertEquals(ws.values()[0].formula, "hello")
def test_setattr_should_not_delegate_to_setitem_if_attr_name_is_not_valid_cell_name( self): ws = Worksheet() ws.__setitem__ = Mock() ws.A1 = 23 self.assertEquals(ws.__setitem__.call_args_list, []) self.assertEquals(ws.A1, 23)
def test_getitem_should_use_original_key_if_to_location_gives_none(self): ws = Worksheet() ws.to_location = Mock(return_value=(3, 4)) ws[3, 4].formula = "hello" self.assertEquals(ws.to_location.call_args_list, [(((3, 4),), {})]) self.assertEquals(ws.keys(), [(3, 4)]) self.assertEquals(ws.values()[0].formula, "hello")
def test_setitem_on_locations_should_accept_cell_instances(self): ws = Worksheet() ws.to_location = Mock(return_value=(1, 2)) cell = Cell() ws[3, 4] = cell self.assertEquals(ws.to_location.call_args_list, [(((3, 4),), {})]) self.assertEquals(ws.keys(), [(1, 2)])
def test_load_constants_should_clear_errors_for_constants(self): cell = Cell() cell.formula = "a constant" cell.error = 'Ohno!' worksheet = Worksheet() worksheet.A1 = cell load_constants(worksheet) self.assertIsNone(cell.error)
def test_to_ui_json_meta_data_includes_worksheet_console_text(self): sheet = Sheet(width=10, height=5) worksheet = Worksheet() worksheet._console_text = ['error1', 'error2'] expected = dict(width=sheet.width, height=sheet.height, name='Untitled', console_text=worksheet._console_text) self.assertEquals( json.loads(sheet_to_ui_json_meta_data(sheet, worksheet)), expected)
def test_to_ui_json_meta_data_includes_worksheet_console_text(self): sheet = Sheet(width=10, height=5) worksheet = Worksheet() worksheet._console_text = ['error1', 'error2'] expected = dict( width=sheet.width, height=sheet.height, name='Untitled', console_text=worksheet._console_text) self.assertEquals(json.loads(sheet_to_ui_json_meta_data(sheet, worksheet)), expected)
def test_sheet_to_ui_json_grid_data_should_not_include_totally_empty_cells(self): worksheet = Worksheet() worksheet.A1 = Cell() expected_json_contents = { 'bottom': 10, 'left': 0, 'right': 10, 'topmost': 0 } self.assertEquals(json.loads(sheet_to_ui_json_grid_data(worksheet, (0, 0, 10, 10))), expected_json_contents)
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_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_mixed_parameters(self): ws = Worksheet() cell_range = ws.cell_range((10, 10), 'C4') self.assertEquals(cell_range.left, 3) self.assertEquals(cell_range.top, 4) self.assertEquals(cell_range.right, 10) self.assertEquals(cell_range.bottom, 10) try: _ = ws.cell_range('wipple', (1, 2)) self.fail('should raise ValueError') except ValueError, e: self.assertEquals(str(e), "wipple is not a valid cell location")
def test_double_string_parameters_use_a1_notation(self): ws = Worksheet() cell_range = ws.cell_range('A2', 'C4') self.assertEquals(cell_range.left, 1) self.assertEquals(cell_range.top, 2) self.assertEquals(cell_range.right, 3) self.assertEquals(cell_range.bottom, 4) try: _ = ws.cell_range('wabble', 'C4') self.fail('should raise ValueError') except ValueError, e: self.assertEquals(str(e), "wabble is not a valid cell location")
def test_mixed_parameters(self): ws = Worksheet() cell_range = ws.cell_range((10, 10),'C4') self.assertEquals(cell_range.left, 3) self.assertEquals(cell_range.top, 4) self.assertEquals(cell_range.right, 10) self.assertEquals(cell_range.bottom, 10) try: _ = ws.cell_range('wipple',(1,2)) self.fail('should raise ValueError') except ValueError, e: self.assertEquals(str(e), "wipple is not a valid cell location")
def test_single_string_parameter_uses_formula_notation(self): ws = Worksheet() cell_range = ws.cell_range('A2:C4') self.assertEquals(cell_range.left, 1) self.assertEquals(cell_range.top, 2) self.assertEquals(cell_range.right, 3) self.assertEquals(cell_range.bottom, 4) try: _ = ws.cell_range('A1:wibble') self.fail('should raise ValueError') except ValueError, e: self.assertEquals(str(e), "Invalid cell range 'A1:wibble'")
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_double_string_parameters_use_a1_notation(self): ws = Worksheet() cell_range = ws.cell_range('A2','C4') self.assertEquals(cell_range.left, 1) self.assertEquals(cell_range.top, 2) self.assertEquals(cell_range.right, 3) self.assertEquals(cell_range.bottom, 4) try: _ = ws.cell_range('wabble','C4') self.fail('should raise ValueError') except ValueError, e: self.assertEquals(str(e), "wabble is not a valid cell location")
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_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_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_sheet_to_ui_json_grid_data_should_not_include_totally_empty_cells( self): worksheet = Worksheet() worksheet.A1 = Cell() expected_json_contents = { 'bottom': 10, 'left': 0, 'right': 10, 'topmost': 0 } self.assertEquals( json.loads(sheet_to_ui_json_grid_data(worksheet, (0, 0, 10, 10))), expected_json_contents)
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_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_to_location(self): ws = Worksheet() self.assertEquals(ws.to_location((1, 2)), (1, 2)) self.assertEquals(ws.to_location((1L, 2L)), (1L, 2L)) self.assertEquals(ws.to_location(('a', 2)), (1, 2)) self.assertEquals(ws.to_location(('A', 2)), (1, 2)) self.assertEquals(ws.to_location('a2'), (1, 2)) self.assertEquals(ws.to_location('A2'), (1, 2)) self.assertEquals(ws.to_location('A'), None) self.assertEquals(ws.to_location('1A'), None) self.assertEquals(ws.to_location((1, 'A')), None) self.assertEquals(ws.to_location(123), None) self.assertEquals(ws.to_location(object()), None)
def api_json_to_worksheet(sheet_json): sheet_values = jsonlib.loads(sheet_json) worksheet = Worksheet() worksheet.name = sheet_values.get('name', 'Untitled') for key, value in sheet_values.iteritems(): if key == "usercode_error": worksheet._usercode_error = value elif isinstance(value, dict): rows = value col = int(key) for row, value in rows.iteritems(): row = int(row) worksheet[col, row].value = value return worksheet
def test_should_put_data_into_existing_worksheet_with_offset_for_excel_and_auto( self): for excel_encoding in [True, False]: csv = StringIO() csv.write('abc,123\n') csv.write('def, \n') csv.size = 10 csv.seek(0) existing_worksheet = Worksheet() for row in range(1, 6): for col in range(1, 5): existing_worksheet[col, row].formula = 'old' worksheet = worksheet_from_csv(existing_worksheet, csv, 2, 3, excel_encoding) self.assertEquals(worksheet.A1.formula, 'old') self.assertEquals(worksheet.B1.formula, 'old') self.assertEquals(worksheet.A2.formula, 'old') self.assertEquals(worksheet.B3.formula, 'abc') self.assertEquals(worksheet.C3.formula, '123') self.assertEquals(worksheet.B4.formula, 'def') self.assertEquals(worksheet.C4.formula, ' ') self.assertEquals(worksheet.C5.formula, 'old') self.assertEquals(worksheet.D3.formula, 'old') self.assertEquals(worksheet.B5.formula, 'old')