From ab52b86164d5dfb947e21776359ae2d617720bbf Mon Sep 17 00:00:00 2001 From: BethanyG Date: Tue, 19 Oct 2021 18:31:09 -0700 Subject: [PATCH 01/11] Amended exercise to include error handling instructions and tests. --- .../affine-cipher/.docs/instructions.append.md | 13 +++++++++++++ .../practice/affine-cipher/.meta/example.py | 2 +- .../practice/affine-cipher/.meta/template.j2 | 6 +++--- .../practice/affine-cipher/affine_cipher_test.py | 16 ++++++---------- 4 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 exercises/practice/affine-cipher/.docs/instructions.append.md diff --git a/exercises/practice/affine-cipher/.docs/instructions.append.md b/exercises/practice/affine-cipher/.docs/instructions.append.md new file mode 100644 index 0000000000..f8d74235a7 --- /dev/null +++ b/exercises/practice/affine-cipher/.docs/instructions.append.md @@ -0,0 +1,13 @@ +# Instructions append + +## Exception messages + +Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message. + +This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" a `ValueError`. The tests will only pass if you both `raise` the `exception` and include a message with it. + +To raise a `ValueError` with a message, write the message as an argument to the `exception` type: + +```python +raise ValueError("a and m must be coprime.") +``` diff --git a/exercises/practice/affine-cipher/.meta/example.py b/exercises/practice/affine-cipher/.meta/example.py index 75700f9865..c655c4546a 100644 --- a/exercises/practice/affine-cipher/.meta/example.py +++ b/exercises/practice/affine-cipher/.meta/example.py @@ -13,7 +13,7 @@ def modInverse(a, ALPHSZ): def translate(text, a, b, mode): inv = modInverse(a, ALPHSZ) if inv == 1: - raise ValueError("a and alphabet size must be coprime.") + raise ValueError("a and m must be coprime.") chars = [] for c in text: diff --git a/exercises/practice/affine-cipher/.meta/template.j2 b/exercises/practice/affine-cipher/.meta/template.j2 index 63394fb644..b9b2256597 100644 --- a/exercises/practice/affine-cipher/.meta/template.j2 +++ b/exercises/practice/affine-cipher/.meta/template.j2 @@ -15,8 +15,10 @@ def test_{{ case["description"] | to_snake }}(self): {% set expected = case["expected"] -%} {% set function = case["property"] -%} {% if case is error_case -%} - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: {{ function }}("{{ phrase }}", {{ a }}, {{ b }}) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "a and m must be coprime.") {% else -%} self.assertEqual({{ function }}("{{ phrase }}", {{ a }}, {{ b }}), "{{ expected }}") {% endif -%} @@ -28,5 +30,3 @@ class {{ exercise | camel_case }}Test(unittest.TestCase): {% for supercase in cases -%} {{ test_supercase(supercase) }} {% endfor %} - -{{ macros.footer(True) }} diff --git a/exercises/practice/affine-cipher/affine_cipher_test.py b/exercises/practice/affine-cipher/affine_cipher_test.py index 4e9ca0b2b4..26d08437ac 100644 --- a/exercises/practice/affine-cipher/affine_cipher_test.py +++ b/exercises/practice/affine-cipher/affine_cipher_test.py @@ -39,8 +39,10 @@ def test_encode_all_the_letters(self): ) def test_encode_with_a_not_coprime_to_m(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: encode("This is a test.", 6, 17) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "a and m must be coprime.") def test_decode_exercism(self): self.assertEqual(decode("tytgn fjr", 3, 7), "exercism") @@ -72,13 +74,7 @@ def test_decode_with_too_many_spaces(self): ) def test_decode_with_a_not_coprime_to_m(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: decode("Test", 13, 5) - - # Utility functions - def assertRaisesWithMessage(self, exception): - return self.assertRaisesRegex(exception, r".+") - - -if __name__ == "__main__": - unittest.main() + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "a and m must be coprime.") From 14dbe0597f6c634d736b209b97cabc1f4615b5bd Mon Sep 17 00:00:00 2001 From: BethanyG Date: Tue, 19 Oct 2021 19:14:19 -0700 Subject: [PATCH 02/11] Adjustment to jinja2 template to programmatically pass through the expected error message. --- exercises/practice/affine-cipher/.meta/template.j2 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exercises/practice/affine-cipher/.meta/template.j2 b/exercises/practice/affine-cipher/.meta/template.j2 index b9b2256597..f64a722f37 100644 --- a/exercises/practice/affine-cipher/.meta/template.j2 +++ b/exercises/practice/affine-cipher/.meta/template.j2 @@ -13,12 +13,13 @@ def test_{{ case["description"] | to_snake }}(self): {% set a = input["key"]["a"] -%} {% set b = input["key"]["b"] -%} {% set expected = case["expected"] -%} + {% set exp_error = expected["error"] -%} {% set function = case["property"] -%} {% if case is error_case -%} with self.assertRaises(ValueError) as err: {{ function }}("{{ phrase }}", {{ a }}, {{ b }}) self.assertEqual(type(err.exception), ValueError) - self.assertEqual(err.exception.args[0], "a and m must be coprime.") + self.assertEqual(err.exception.args[0], "{{ exp_error }}") {% else -%} self.assertEqual({{ function }}("{{ phrase }}", {{ a }}, {{ b }}), "{{ expected }}") {% endif -%} From 7e7b9898d4fa52f95cbce88b855f9a2ed6e9fd84 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Tue, 19 Oct 2021 19:15:01 -0700 Subject: [PATCH 03/11] New instructions append for error handling. --- .../.docs/instructions.append.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 exercises/practice/all-your-base/.docs/instructions.append.md diff --git a/exercises/practice/all-your-base/.docs/instructions.append.md b/exercises/practice/all-your-base/.docs/instructions.append.md new file mode 100644 index 0000000000..af5e440685 --- /dev/null +++ b/exercises/practice/all-your-base/.docs/instructions.append.md @@ -0,0 +1,20 @@ +# Instructions append + +## Exception messages + +Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message. + +This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" a `ValueError` for different input and output bases. The tests will only pass if you both `raise` the `exception` and include a meaningful message with it. + +To raise a `ValueError` with a message, write the message as an argument to the `exception` type: + +```python +# for input. +raise ValueError("input base must be >= 2") + +# another example for input. +raise ValueError("all digits must satisfy 0 <= d < input base") + +# or, for output. +raise ValueError("output base must be >= 2") +``` From 566b5e839b6f85999ebdf7d5f7a51e24f8885c6d Mon Sep 17 00:00:00 2001 From: BethanyG Date: Tue, 19 Oct 2021 19:16:07 -0700 Subject: [PATCH 04/11] Adjusted example and template for expecte errors. Regenerated tests. --- .../practice/all-your-base/.meta/example.py | 6 +-- .../practice/all-your-base/.meta/template.j2 | 5 ++- .../all-your-base/all_your_base_test.py | 40 ++++++++++++++----- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/exercises/practice/all-your-base/.meta/example.py b/exercises/practice/all-your-base/.meta/example.py index cdf4f60a15..bce92f831b 100644 --- a/exercises/practice/all-your-base/.meta/example.py +++ b/exercises/practice/all-your-base/.meta/example.py @@ -14,12 +14,12 @@ def to_digits(number, base_to): def rebase(from_base, digits, to_base): if from_base < 2: - raise ValueError("Invalid input base.") + raise ValueError("input base must be >= 2") if to_base < 2: - raise ValueError("Invalid output base.") + raise ValueError("output base must be >= 2") if any(True for d in digits if d < 0 or d >= from_base): - raise ValueError("Invalid input digit.") + raise ValueError("all digits must satisfy 0 <= d < input base") return to_digits(from_digits(digits, from_base), to_base) diff --git a/exercises/practice/all-your-base/.meta/template.j2 b/exercises/practice/all-your-base/.meta/template.j2 index b13842331b..20684b546c 100644 --- a/exercises/practice/all-your-base/.meta/template.j2 +++ b/exercises/practice/all-your-base/.meta/template.j2 @@ -10,10 +10,13 @@ {%- macro test_case(case) -%} {%- set expected = case["expected"] -%} + {%- set exp_error = expected["error"] -%} def test_{{ case["description"] | to_snake }}(self): {%- if case is error_case %} - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: {{ func_call(case) }} + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "{{ exp_error }}") {%- else %} self.assertEqual({{ func_call(case) }}, {{ expected }}) {%- endif %} diff --git a/exercises/practice/all-your-base/all_your_base_test.py b/exercises/practice/all-your-base/all_your_base_test.py index a308261f40..04cf27dbae 100644 --- a/exercises/practice/all-your-base/all_your_base_test.py +++ b/exercises/practice/all-your-base/all_your_base_test.py @@ -45,40 +45,62 @@ def test_leading_zeros(self): self.assertEqual(rebase(7, [0, 6, 0], 10), [4, 2]) def test_input_base_is_one(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: rebase(1, [0], 10) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "input base must be >= 2") def test_input_base_is_zero(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: rebase(0, [], 10) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "input base must be >= 2") def test_input_base_is_negative(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: rebase(-2, [1], 10) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "input base must be >= 2") def test_negative_digit(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: rebase(2, [1, -1, 1, 0, 1, 0], 10) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual( + err.exception.args[0], "all digits must satisfy 0 <= d < input base" + ) def test_invalid_positive_digit(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: rebase(2, [1, 2, 1, 0, 1, 0], 10) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual( + err.exception.args[0], "all digits must satisfy 0 <= d < input base" + ) def test_output_base_is_one(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: rebase(2, [1, 0, 1, 0, 1, 0], 1) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "output base must be >= 2") def test_output_base_is_zero(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: rebase(10, [7], 0) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "output base must be >= 2") def test_output_base_is_negative(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: rebase(2, [1], -7) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "output base must be >= 2") def test_both_bases_are_negative(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: rebase(-2, [1], -7) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "input base must be >= 2") # Utility functions def assertRaisesWithMessage(self, exception): From b660da75fa2973a4598a0d3d3345a6263719d6f4 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Thu, 21 Oct 2021 12:20:41 -0700 Subject: [PATCH 05/11] Adjusted instructions and test file to add error handling instructions and scenarios. --- .../bank-account/.docs/instructions.append.md | 24 ++++++++++++ .../bank-account/bank_account_test.py | 38 ++++++++++++------- 2 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 exercises/practice/bank-account/.docs/instructions.append.md diff --git a/exercises/practice/bank-account/.docs/instructions.append.md b/exercises/practice/bank-account/.docs/instructions.append.md new file mode 100644 index 0000000000..1bd2a6ab9f --- /dev/null +++ b/exercises/practice/bank-account/.docs/instructions.append.md @@ -0,0 +1,24 @@ +# Instructions append + +## Exception messages + +Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message. + +This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" a `ValueError` for when an account is or is not open, or the withdrawal/deposit amounts are incorrect. The tests will only pass if you both `raise` the `exception` and include a message with it. + +To raise a `ValueError` with a message, write the message as an argument to the `exception` type: + + +```python +# account is not open +raise ValueError('account not open') + +# account is already open +raise ValueError('account already open') + +# incorrect withdrawal/deposit amount +raise ValueError('amount must be greater than 0') + +# withdrawal is too big +raise ValueError('amount must be less than balance') +``` diff --git a/exercises/practice/bank-account/bank_account_test.py b/exercises/practice/bank-account/bank_account_test.py index 8e6d8ce0bf..33440365e9 100644 --- a/exercises/practice/bank-account/bank_account_test.py +++ b/exercises/practice/bank-account/bank_account_test.py @@ -48,35 +48,46 @@ def test_checking_balance_of_closed_account_throws_error(self): account.open() account.close() - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: account.get_balance() + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "account not open") def test_deposit_into_closed_account(self): account = BankAccount() account.open() account.close() - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: account.deposit(50) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "account not open") + def test_withdraw_from_closed_account(self): account = BankAccount() account.open() account.close() - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: account.withdraw(50) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "account not open") def test_close_already_closed_account(self): account = BankAccount() - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: account.close() + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "account not open") def test_open_already_opened_account(self): account = BankAccount() account.open() - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: account.open() + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "account already open") def test_reopened_account_does_not_retain_balance(self): account = BankAccount() @@ -91,23 +102,29 @@ def test_cannot_withdraw_more_than_deposited(self): account.open() account.deposit(25) - with self.assertRaises(ValueError): + with self.assertRaises(ValueError) as err: account.withdraw(50) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "amount must be less than balance") def test_cannot_withdraw_negative(self): account = BankAccount() account.open() account.deposit(100) - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: account.withdraw(-50) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "amount must be greater than 0") def test_cannot_deposit_negative(self): account = BankAccount() account.open() - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: account.deposit(-50) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "amount must be greater than 0") def test_can_handle_concurrent_transactions(self): account = BankAccount() @@ -138,10 +155,5 @@ def transact(): for thread in threads: thread.join() - # Utility functions - def assertRaisesWithMessage(self, exception): - return self.assertRaisesRegex(exception, r".+") - - if __name__ == '__main__': unittest.main() From 649897c23cd752ba20bea368fcc9ea3d21eb1541 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Thu, 21 Oct 2021 12:59:16 -0700 Subject: [PATCH 06/11] Added an append for error handling and listed the error messages in a code example. --- exercises/practice/bank-account/.docs/instructions.append.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/bank-account/.docs/instructions.append.md b/exercises/practice/bank-account/.docs/instructions.append.md index 1bd2a6ab9f..6204bee7dd 100644 --- a/exercises/practice/bank-account/.docs/instructions.append.md +++ b/exercises/practice/bank-account/.docs/instructions.append.md @@ -21,4 +21,4 @@ raise ValueError('amount must be greater than 0') # withdrawal is too big raise ValueError('amount must be less than balance') -``` +``` \ No newline at end of file From 1aa9bbb37b6b4d0f03d9c6a8505ff8426f53c6ac Mon Sep 17 00:00:00 2001 From: BethanyG Date: Thu, 21 Oct 2021 13:00:08 -0700 Subject: [PATCH 07/11] Added instructions append, and adjusted JinJa2 template and examplar for error handling. Regenerated test file. --- .../.docs/instructions.append.md | 14 +++++++ .../practice/binary-search/.meta/example.py | 2 +- .../practice/binary-search/.meta/template.j2 | 10 +++-- .../binary-search/binary_search_test.py | 42 +++++++++++++------ 4 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 exercises/practice/binary-search/.docs/instructions.append.md diff --git a/exercises/practice/binary-search/.docs/instructions.append.md b/exercises/practice/binary-search/.docs/instructions.append.md new file mode 100644 index 0000000000..1fbf3f2fa6 --- /dev/null +++ b/exercises/practice/binary-search/.docs/instructions.append.md @@ -0,0 +1,14 @@ +# Instructions append + +## Exception messages + +Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message. + +This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" a `ValueError` when the given value is not found within the array. The tests will only pass if you both `raise` the `exception` and include a message with it. + +To raise a `ValueError` with a message, write the message as an argument to the `exception` type: + +```python +# example when value is not found in the array. +raise ValueError("value not in array") +``` diff --git a/exercises/practice/binary-search/.meta/example.py b/exercises/practice/binary-search/.meta/example.py index 0643ee62c0..c5fd05879e 100644 --- a/exercises/practice/binary-search/.meta/example.py +++ b/exercises/practice/binary-search/.meta/example.py @@ -9,4 +9,4 @@ def find(search_list, value): low = middle + 1 else: return middle - raise ValueError("Value not found.") + raise ValueError("value not in array") diff --git a/exercises/practice/binary-search/.meta/template.j2 b/exercises/practice/binary-search/.meta/template.j2 index e575269d08..05f2c48383 100644 --- a/exercises/practice/binary-search/.meta/template.j2 +++ b/exercises/practice/binary-search/.meta/template.j2 @@ -12,12 +12,14 @@ class {{ exercise | camel_case }}Test(unittest.TestCase): {% for case in cases -%} def test_{{ case["description"] | to_snake }}(self): + {% set expected = case["expected"] -%} + {% set exp_error = expected["error"] -%} {%- if case is error_case %} - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: {{- test_call(case) }} + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "{{ exp_error }}") {%- else %} - self.assertEqual({{- test_call(case) }}, {{ case["expected"] }}) + self.assertEqual({{- test_call(case) }}, {{ expected }}) {%- endif %} {% endfor %} - -{{ macros.footer() }} diff --git a/exercises/practice/binary-search/binary_search_test.py b/exercises/practice/binary-search/binary_search_test.py index b2ef00cb0b..e038c4e376 100644 --- a/exercises/practice/binary-search/binary_search_test.py +++ b/exercises/practice/binary-search/binary_search_test.py @@ -9,49 +9,67 @@ class BinarySearchTest(unittest.TestCase): def test_finds_a_value_in_an_array_with_one_element(self): + self.assertEqual(find([6], 6), 0) def test_finds_a_value_in_the_middle_of_an_array(self): + self.assertEqual(find([1, 3, 4, 6, 8, 9, 11], 6), 3) def test_finds_a_value_at_the_beginning_of_an_array(self): + self.assertEqual(find([1, 3, 4, 6, 8, 9, 11], 1), 0) def test_finds_a_value_at_the_end_of_an_array(self): + self.assertEqual(find([1, 3, 4, 6, 8, 9, 11], 11), 6) def test_finds_a_value_in_an_array_of_odd_length(self): + self.assertEqual( find([1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634], 144), 9 ) def test_finds_a_value_in_an_array_of_even_length(self): + self.assertEqual(find([1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377], 21), 5) def test_identifies_that_a_value_is_not_included_in_the_array(self): - with self.assertRaisesWithMessage(ValueError): + + with self.assertRaises(ValueError) as err: find([1, 3, 4, 6, 8, 9, 11], 7) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "value not in array") + def test_a_value_smaller_than_the_array_s_smallest_value_is_not_found(self): - with self.assertRaisesWithMessage(ValueError): + + with self.assertRaises(ValueError) as err: find([1, 3, 4, 6, 8, 9, 11], 0) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "value not in array") + def test_a_value_larger_than_the_array_s_largest_value_is_not_found(self): - with self.assertRaisesWithMessage(ValueError): + + with self.assertRaises(ValueError) as err: find([1, 3, 4, 6, 8, 9, 11], 13) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "value not in array") + def test_nothing_is_found_in_an_empty_array(self): - with self.assertRaisesWithMessage(ValueError): + + with self.assertRaises(ValueError) as err: find([], 1) - def test_nothing_is_found_when_the_left_and_right_bounds_cross(self): - with self.assertRaisesWithMessage(ValueError): - find([1, 2], 0) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "value not in array") - # Utility functions - def assertRaisesWithMessage(self, exception): - return self.assertRaisesRegex(exception, r".+") + def test_nothing_is_found_when_the_left_and_right_bounds_cross(self): + with self.assertRaises(ValueError) as err: + find([1, 2], 0) -if __name__ == "__main__": - unittest.main() + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "value not in array") From f24abb38a85f16a6ac47b0933a482984fbe508e4 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Thu, 21 Oct 2021 14:15:01 -0700 Subject: [PATCH 08/11] Added insructons append and altered test file to add error handling instrucitons and tests. --- .../binary/.docs/instructions.append.md | 14 +++++++++++++ exercises/practice/binary/binary_test.py | 21 +++++++++++-------- 2 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 exercises/practice/binary/.docs/instructions.append.md diff --git a/exercises/practice/binary/.docs/instructions.append.md b/exercises/practice/binary/.docs/instructions.append.md new file mode 100644 index 0000000000..32e304f553 --- /dev/null +++ b/exercises/practice/binary/.docs/instructions.append.md @@ -0,0 +1,14 @@ +# Instructions append + +## Exception messages + +Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message. + +This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" a `ValueError` when the argument passed is not a valid binary literal. The tests will only pass if you both `raise` the `exception` and include a message with it. + +To raise a `ValueError` with a message, write the message as an argument to the `exception` type: + +```python +# example when the argument passed is not a valid binary literal +raise ValueError("Invalid binary literal: " + digits) +``` diff --git a/exercises/practice/binary/binary_test.py b/exercises/practice/binary/binary_test.py index 3aa2985aa0..39bc095685 100644 --- a/exercises/practice/binary/binary_test.py +++ b/exercises/practice/binary/binary_test.py @@ -32,25 +32,28 @@ def test_binary_10001101000_is_decimal_1128(self): self.assertEqual(parse_binary("10001101000"), 1128) def test_invalid_binary_text_only(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: parse_binary("carrot") + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], f"Invalid binary literal: {digits}") def test_invalid_binary_number_not_base2(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: parse_binary("102011") + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], f"Invalid binary literal: {digits}") def test_invalid_binary_numbers_with_text(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError) as err: parse_binary("10nope") + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], f"Invalid binary literal: {digits}") def test_invalid_binary_text_with_numbers(self): - with self.assertRaisesWithMessage(ValueError): + with self.assertRaises(ValueError): parse_binary("nope10") - - # Utility functions - def assertRaisesWithMessage(self, exception): - return self.assertRaisesRegex(exception, r".+") - + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], f"Invalid binary literal: {digits}") if __name__ == '__main__': unittest.main() From 4daa30da7ea227141066c9b5de9d5b27292ddbe7 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Thu, 21 Oct 2021 14:25:20 -0700 Subject: [PATCH 09/11] The CI won't let me have nice things. --- exercises/practice/binary/binary_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exercises/practice/binary/binary_test.py b/exercises/practice/binary/binary_test.py index 39bc095685..02769d28f7 100644 --- a/exercises/practice/binary/binary_test.py +++ b/exercises/practice/binary/binary_test.py @@ -35,25 +35,25 @@ def test_invalid_binary_text_only(self): with self.assertRaises(ValueError) as err: parse_binary("carrot") self.assertEqual(type(err.exception), ValueError) - self.assertEqual(err.exception.args[0], f"Invalid binary literal: {digits}") + self.assertEqual(err.exception.args[0], "Invalid binary literal: " + digits) def test_invalid_binary_number_not_base2(self): with self.assertRaises(ValueError) as err: parse_binary("102011") self.assertEqual(type(err.exception), ValueError) - self.assertEqual(err.exception.args[0], f"Invalid binary literal: {digits}") + self.assertEqual(err.exception.args[0], "Invalid binary literal: " + digits) def test_invalid_binary_numbers_with_text(self): with self.assertRaises(ValueError) as err: parse_binary("10nope") self.assertEqual(type(err.exception), ValueError) - self.assertEqual(err.exception.args[0], f"Invalid binary literal: {digits}") + self.assertEqual(err.exception.args[0], "Invalid binary literal: " + digits) def test_invalid_binary_text_with_numbers(self): with self.assertRaises(ValueError): parse_binary("nope10") self.assertEqual(type(err.exception), ValueError) - self.assertEqual(err.exception.args[0], f"Invalid binary literal: {digits}") + self.assertEqual(err.exception.args[0], "Invalid binary literal: " + digits) if __name__ == '__main__': unittest.main() From b90dd6cc03c133e6c898898b49ee7cb45b4fee37 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Thu, 21 Oct 2021 14:32:02 -0700 Subject: [PATCH 10/11] Third times the charm. We hope. --- exercises/practice/binary/binary_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exercises/practice/binary/binary_test.py b/exercises/practice/binary/binary_test.py index 02769d28f7..d7bda627e0 100644 --- a/exercises/practice/binary/binary_test.py +++ b/exercises/practice/binary/binary_test.py @@ -35,25 +35,25 @@ def test_invalid_binary_text_only(self): with self.assertRaises(ValueError) as err: parse_binary("carrot") self.assertEqual(type(err.exception), ValueError) - self.assertEqual(err.exception.args[0], "Invalid binary literal: " + digits) + self.assertEqual(err.exception.args[0], "Invalid binary literal: 'carrot'") def test_invalid_binary_number_not_base2(self): with self.assertRaises(ValueError) as err: parse_binary("102011") self.assertEqual(type(err.exception), ValueError) - self.assertEqual(err.exception.args[0], "Invalid binary literal: " + digits) + self.assertEqual(err.exception.args[0], "Invalid binary literal: '102011'") def test_invalid_binary_numbers_with_text(self): with self.assertRaises(ValueError) as err: parse_binary("10nope") self.assertEqual(type(err.exception), ValueError) - self.assertEqual(err.exception.args[0], "Invalid binary literal: " + digits) + self.assertEqual(err.exception.args[0], "Invalid binary literal: '10nope'") def test_invalid_binary_text_with_numbers(self): with self.assertRaises(ValueError): parse_binary("nope10") self.assertEqual(type(err.exception), ValueError) - self.assertEqual(err.exception.args[0], "Invalid binary literal: " + digits) + self.assertEqual(err.exception.args[0], "Invalid binary literal: '10nope'") if __name__ == '__main__': unittest.main() From e2382d6080d964e85e13acc1dc0e18f19f08278d Mon Sep 17 00:00:00 2001 From: BethanyG Date: Thu, 21 Oct 2021 14:34:04 -0700 Subject: [PATCH 11/11] Ok. Maybe try number 4 will work. --- exercises/practice/binary/binary_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/binary/binary_test.py b/exercises/practice/binary/binary_test.py index d7bda627e0..f0b3ab5746 100644 --- a/exercises/practice/binary/binary_test.py +++ b/exercises/practice/binary/binary_test.py @@ -50,7 +50,7 @@ def test_invalid_binary_numbers_with_text(self): self.assertEqual(err.exception.args[0], "Invalid binary literal: '10nope'") def test_invalid_binary_text_with_numbers(self): - with self.assertRaises(ValueError): + with self.assertRaises(ValueError) as err: parse_binary("nope10") self.assertEqual(type(err.exception), ValueError) self.assertEqual(err.exception.args[0], "Invalid binary literal: '10nope'")