diff --git a/exercises/concept/meltdown-mitigation/.docs/instructions.md b/exercises/concept/meltdown-mitigation/.docs/instructions.md index ab5dfea2db..ed95da65b8 100644 --- a/exercises/concept/meltdown-mitigation/.docs/instructions.md +++ b/exercises/concept/meltdown-mitigation/.docs/instructions.md @@ -30,13 +30,15 @@ True Once the reactor has started producing power its efficiency needs to be determined. Efficiency can be grouped into 4 bands: -1. green -> 80-100% efficiency -2. orange -> 60-79% efficiency -3. red -> 30-59% efficiency -4. black -> <30% efficient - -These percentage ranges are calculated as `(generated_power/theoretical_max_power)*100` -where `generated_power = voltage * current` +1. green -> efficiency of 80% or more, +2. orange -> efficiency of less than 80% but at least 60%, +3. red -> efficiency below 60%, but still 30% or more, +4. black -> less than 30% efficient. + +The percentage value can be calculated as `(generated_power/theoretical_max_power)*100` +where `generated_power = voltage * current`. +Note that the percentage value is usually not an integer number, so make sure to consider the +proper use of the `<` and `<=` comparisons. Implement the function `reactor_efficiency()`, with three parameters: `voltage`, `current`, and `theoretical_max_power`. diff --git a/exercises/concept/meltdown-mitigation/.meta/config.json b/exercises/concept/meltdown-mitigation/.meta/config.json index 9348eabdb6..78c54743d0 100644 --- a/exercises/concept/meltdown-mitigation/.meta/config.json +++ b/exercises/concept/meltdown-mitigation/.meta/config.json @@ -2,6 +2,7 @@ "blurb": "Learn about conditionals and avoid a meltdown by developing a simple control system for a Nuclear Reactor.", "icon": "circular-buffer", "authors": ["sachsom95", "BethanyG"], + "contributors": ["kbuc"], "files": { "solution": ["conditionals.py"], "test": ["conditionals_test.py"], diff --git a/exercises/concept/meltdown-mitigation/.meta/exemplar.py b/exercises/concept/meltdown-mitigation/.meta/exemplar.py index 064ab56200..43d3060b1d 100644 --- a/exercises/concept/meltdown-mitigation/.meta/exemplar.py +++ b/exercises/concept/meltdown-mitigation/.meta/exemplar.py @@ -1,14 +1,14 @@ def is_criticality_balanced(temperature, neutrons_emitted): """Verify criticality is balanced. - :param temperature: int - :param neutrons_emitted: int + :param temperature: temperature value (integer or float) + :param neutrons_emitted: number of neutrons emitted per second (integer or float) :return: boolean True if conditions met, False if not A reactor is said to be critical if it satisfies the following conditions: - - The temperature less than 800. - - The number of neutrons emitted per second greater than 500. - - The product of temperature and neutrons emitted per second less than 500000. + - The temperature is less than 800. + - The number of neutrons emitted per second is greater than 500. + - The product of temperature and neutrons emitted per second is less than 500000. """ output = temperature * neutrons_emitted balanced = False @@ -22,19 +22,19 @@ def is_criticality_balanced(temperature, neutrons_emitted): def reactor_efficiency(voltage, current, theoretical_max_power): """Assess reactor efficiency zone. - :param voltage: int - :param current: int - :param theoretical_max_power: int + :param voltage: voltage value (integer or float) + :param current: current value (integer or float) + :param theoretical_max_power: power that corresponds to a 100% efficiency (integer or float) :return: str one of 'green', 'orange', 'red', or 'black' Efficiency can be grouped into 4 bands: - 1. green -> 80-100% efficiency - 2. orange -> 60-79% efficiency - 3. red -> 30-59% efficiency - 4. black -> <30% efficient + 1. green -> efficiency of 80% or more, + 2. orange -> efficiency of less than 80% but at least 60%, + 3. red -> efficiency below 60%, but still 30% or more, + 4. black -> less than 30% efficient. - These percentage ranges are calculated as + The percentage value is calculated as (generated power/ theoretical max power)*100 where generated power = voltage * current """ @@ -44,9 +44,9 @@ def reactor_efficiency(voltage, current, theoretical_max_power): if 80 <= percentage_range <= 100: efficiency_level = 'green' - elif 60 <= percentage_range <= 79: + elif 60 <= percentage_range < 80: efficiency_level = 'orange' - elif 30 <= percentage_range <= 59: + elif 30 <= percentage_range < 60: efficiency_level = 'red' else: efficiency_level = 'black' @@ -57,9 +57,9 @@ def reactor_efficiency(voltage, current, theoretical_max_power): def fail_safe(temperature, neutrons_produced_per_second, threshold): """Assess and return safety range. - :param temperature: - :param neutrons_produced_per_second: - :param threshold: + :param temperature: value of the temperature (integer or float) + :param neutrons_produced_per_second: neutron flux (integer or float) + :param threshold: threshold (integer or float) :return: str one of: 'LOW', 'NORMAL', 'DANGER' - `temperature * neutrons per second` < 40% of `threshold` == 'LOW' @@ -67,7 +67,7 @@ def fail_safe(temperature, neutrons_produced_per_second, threshold): - `temperature * neutron per second` is not in the above-stated ranges == 'DANGER' """ output = temperature * neutrons_produced_per_second - operational_percentage = int((output / threshold) * 100) + operational_percentage = (output / threshold) * 100 safety_range = 'UNKNOWN' if operational_percentage < 40: diff --git a/exercises/concept/meltdown-mitigation/conditionals.py b/exercises/concept/meltdown-mitigation/conditionals.py index 05889df956..f6e7453d99 100644 --- a/exercises/concept/meltdown-mitigation/conditionals.py +++ b/exercises/concept/meltdown-mitigation/conditionals.py @@ -1,8 +1,11 @@ +""" Meltdown Mitigation exercise """ + + def is_criticality_balanced(temperature, neutrons_emitted): """Verify criticality is balanced. - :param temperature: int - :param neutrons_emitted: int + :param temperature: temperature value (integer or float) + :param neutrons_emitted: number of neutrons emitted per second (integer or float) :return: boolean True if conditions met, False if not A reactor is said to be critical if it satisfies the following conditions: @@ -17,19 +20,19 @@ def is_criticality_balanced(temperature, neutrons_emitted): def reactor_efficiency(voltage, current, theoretical_max_power): """Assess reactor efficiency zone. - :param voltage: int - :param current: int - :param theoretical_max_power: int + :param voltage: voltage value (integer or float) + :param current: current value (integer or float) + :param theoretical_max_power: power that corresponds to a 100% efficiency (integer or float) :return: str one of 'green', 'orange', 'red', or 'black' Efficiency can be grouped into 4 bands: - 1. green -> 80-100% efficiency - 2. orange -> 60-79% efficiency - 3. red -> 30-59% efficiency - 4. black -> <30% efficient + 1. green -> efficiency of 80% or more, + 2. orange -> efficiency of less than 80% but at least 60%, + 3. red -> efficiency below 60%, but still 30% or more, + 4. black -> less than 30% efficient. - These percentage ranges are calculated as + The percentage value is calculated as (generated power/ theoretical max power)*100 where generated power = voltage * current """ @@ -40,12 +43,12 @@ def reactor_efficiency(voltage, current, theoretical_max_power): def fail_safe(temperature, neutrons_produced_per_second, threshold): """Assess and return safety range. - :param temperature: - :param neutrons_produced_per_second: - :param threshold: + :param temperature: value of the temperature (integer or float) + :param neutrons_produced_per_second: neutron flux (integer or float) + :param threshold: threshold (integer or float) :return: str one of: 'LOW', 'NORMAL', 'DANGER' - - `temperature * neutrons per second` < 40% of threshold == 'LOW' + - `temperature * neutrons per second` < 40% of `threshold` == 'LOW' - `temperature * neutrons per second` +/- 10% of `threshold` == 'NORMAL' - `temperature * neutron per second` is not in the above-stated ranges == 'DANGER' """ diff --git a/exercises/concept/meltdown-mitigation/conditionals_test.py b/exercises/concept/meltdown-mitigation/conditionals_test.py index 596ab4e25a..acb83cd021 100644 --- a/exercises/concept/meltdown-mitigation/conditionals_test.py +++ b/exercises/concept/meltdown-mitigation/conditionals_test.py @@ -1,4 +1,3 @@ -# unit test here import unittest import pytest from conditionals import (is_criticality_balanced, @@ -7,164 +6,71 @@ class TestConditionals(unittest.TestCase): - # Checking the first condition using assertTrue and assertFalse - # The values for arguments is not final and should be considered as placeholders - # More test-cases required for full testing + """Test cases for Meltdown mitigation exercise. + """ @pytest.mark.task(taskno=1) - def test_is_criticality_balanced_set1(self): - self.assertTrue(is_criticality_balanced( - temperature=750, neutrons_emitted=650), msg="Expected True but returned False") + def test_is_criticality_balanced(self): + """Testing border cases around typical points. + T, n == (800, 500), (625, 800), (500, 1000), etc. - @pytest.mark.task(taskno=1) - def test_is_criticality_balanced_set2(self): - self.assertTrue(is_criticality_balanced( - temperature=799, neutrons_emitted=501), msg="Expected True but returned False") - - - @pytest.mark.task(taskno=1) - def test_is_criticality_balanced_set3(self): - self.assertTrue( - is_criticality_balanced(temperature=500, neutrons_emitted=600), msg="Expected True but returned False" - ) - - - @pytest.mark.task(taskno=1) - def test_is_criticality_balanced_set4(self): - self.assertFalse( - is_criticality_balanced(temperature=800, neutrons_emitted=500), msg="Expected False but returned True" - ) - - # End of first functions testing - - # Test case for reactor_ efficiency() - # Checking the second condition using assertEqual - # The values for arguments is not final and should be considered as placeholders - # More test-cases required for full testing - # need to add more info to messages - # Need to verify if f-string based errors allowed - - @pytest.mark.task(taskno=2) - def test_reactor_efficiency_set1(self): - test_return = reactor_efficiency( - voltage=100, current=50, theoretical_max_power=5000) - self.assertEqual( - test_return, 'green', msg=f"Expected green but returned {test_return}" - ) + """ + test_data = ((750, 650, True), (799, 501, True), (500, 600, True), + (1000, 800, False), (800, 500, False), (800, 500.01, False), + (799.99, 500, False), (500.01, 999.99, False), (625, 800, False), + (625.99, 800, False), (625.01, 799.99, False), (799.99, 500.01, True), + (624.99, 799.99, True), (500, 1000, False), (500.01, 1000, False), + (499.99, 1000, True)) - @pytest.mark.task(taskno=2) - def test_reactor_efficiency_set2(self): - test_return = reactor_efficiency( - voltage=100, current=30, theoretical_max_power=5000) - self.assertEqual( - test_return, 'orange', msg=f"Expected orange but returned {test_return}" - ) + for variant, data in enumerate(test_data, start=1): + temperature, neutrons_emitted, expected = data + with self.subTest(f"variation #{variant}", temperature=temperature, neutrons_emitted=neutrons_emitted, expected=expected): + got = is_criticality_balanced(temperature, neutrons_emitted) + msg=f"Expected {expected} but returned {got} with T={temperature} and neutrinos={neutrons_emitted}" + self.assertEqual(got, expected, msg) @pytest.mark.task(taskno=2) - def test_reactor_efficiency_set3(self): - test_return = reactor_efficiency( - voltage=100, current=28, theoretical_max_power=5000) - self.assertEqual( - test_return, 'red', msg=f"Expected red but returned {test_return}" - ) + def test_reactor_efficiency(self): + voltage = 10 + theoretical_max_power = 10000 + # The numbers are chosen so that current == 10 x percentage + test_data = ((1000, 'green'), (999, 'green'), (800, 'green'), + (799, 'orange'), (700, 'orange'), (600, 'orange'), + (599, 'red'), (560, 'red'), (400, 'red'), (300, 'red'), + (299, 'black'), (200, 'black'), (0, 'black')) - @pytest.mark.task(taskno=2) - def test_reactor_efficiency_set4(self): - test_return = reactor_efficiency( - voltage=100, current=10, theoretical_max_power=5000) - self.assertEqual( - test_return, 'black', msg=f"Expected black but returned {test_return}" - ) - - # End of second function testing - - # Test case for fail_safe() - # Checking the third condition using assertEqual - # The values for arguments is not final and should be considered as placeholders - # More test-cases required for full testing - # need to add more info to messages - # Need to verify if f-string based errors allowed - - @pytest.mark.task(taskno=3) - def test_fail_safe_set1(self): - test_return = fail_safe( - temperature=100, neutrons_produced_per_second=18, threshold=5000) - self.assertEqual( - test_return, 'LOW', msg=f"Expected LOW but returned {test_return}" - ) - - - @pytest.mark.task(taskno=3) - def test_fail_safe_set2(self): - test_return = fail_safe( - temperature=100, neutrons_produced_per_second=12, threshold=4000) - self.assertEqual( - test_return, 'LOW', msg=f"Expected LOW but returned {test_return}" - ) + for variant, data in enumerate(test_data, start=1): + current, expected = data + with self.subTest(f"variation #{variant}", voltage=voltage, current=current, + theoretical_max_power=theoretical_max_power, expected=expected): + got = reactor_efficiency(voltage, current, theoretical_max_power) + msg=f"Expected {expected} but returned {got} with voltage={voltage}, current={current}, " \ + f"max_pow={theoretical_max_power}" + self.assertEqual(got, expected, msg) - @pytest.mark.task(taskno=3) - def test_fail_safe_set3(self): - test_return = fail_safe( - temperature=100, neutrons_produced_per_second=10, threshold=3000) - self.assertEqual( - test_return, 'LOW', msg=f"Expected LOW but returned {test_return}" - ) - - - @pytest.mark.task(taskno=3) - def test_fail_safe_set4(self): - test_return = fail_safe( - temperature=100, neutrons_produced_per_second=55, threshold=5000) - self.assertEqual( - test_return, 'NORMAL', msg=f"Expected NORMAL but returned {test_return}" - ) - - - @pytest.mark.task(taskno=3) - def test_fail_safe_set5(self): - test_return = fail_safe( - temperature=100, neutrons_produced_per_second=45, threshold=5000) - self.assertEqual( - test_return, 'NORMAL', msg=f"Expected NORMAL but returned {test_return}" - ) - - - @pytest.mark.task(taskno=3) - def test_fail_safe_set6(self): - test_return = fail_safe( - temperature=100, neutrons_produced_per_second=50, threshold=5000) - self.assertEqual( - test_return, 'NORMAL', msg=f"Expected NORMAL but returned {test_return}" - ) - - - @pytest.mark.task(taskno=3) - def test_fail_safe_set7(self): - test_return = fail_safe( - temperature=1000, neutrons_produced_per_second=35, threshold=5000) - self.assertEqual( - test_return, 'DANGER', msg=f"Expected DANGER but returned {test_return}" - ) - - - @pytest.mark.task(taskno=3) - def test_fail_safe_set8(self): - test_return = fail_safe( - temperature=1000, neutrons_produced_per_second=30, threshold=5000) - self.assertEqual( - test_return, 'DANGER', msg=f"Expected DANGER but returned {test_return}" - ) - @pytest.mark.task(taskno=3) - def test_fail_safe_set9(self): - test_return = fail_safe( - temperature=1000, neutrons_produced_per_second=25, threshold=5000) - self.assertEqual( - test_return, 'DANGER', msg=f"Expected DANGER but returned {test_return}" - ) + def test_fail_safe(self): + temperature = 10 + threshold = 10000 + test_data = ((399, 'LOW'), (300, 'LOW'),(1, 'LOW'), + (0, 'LOW'), (901, 'NORMAL'), (1000, 'NORMAL'), + (1099, 'NORMAL'), (899, 'DANGER'), (700, 'DANGER'), + (400, 'DANGER'), (1101, 'DANGER'), (1200, 'DANGER')) + + for variant, data in enumerate(test_data, start=1): + neutrons_produced_per_second, expected = data + + with self.subTest(f"variation #{variant}", temperature=temperature, + neutrons_produced_per_second=neutrons_produced_per_second, + threshold=threshold, expected=expected): + + got = fail_safe(temperature, neutrons_produced_per_second, threshold) + msg = f"Expected {expected} but returned {got} with T={temperature}, " \ + f"neutrons={neutrons_produced_per_second}, threshold={threshold}" + self.assertEqual(got, expected, msg)