Add power and modulus calculator operations with tests
#5
by Nafris - opened
- gradio_calculator.py +11 -1
- test_calculator.py +76 -0
gradio_calculator.py
CHANGED
|
@@ -16,10 +16,20 @@ def calculate(num1, num2, operation):
|
|
| 16 |
if num2 == 0:
|
| 17 |
return "Cannot divide by zero"
|
| 18 |
result = num1 / num2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
else:
|
| 20 |
return "Invalid operation"
|
| 21 |
|
| 22 |
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
except ValueError:
|
| 24 |
return "Please enter valid numbers"
|
| 25 |
|
|
@@ -29,7 +39,7 @@ with gr.Blocks() as demo:
|
|
| 29 |
|
| 30 |
with gr.Row():
|
| 31 |
num1 = gr.Number(label="First number")
|
| 32 |
-
operation = gr.Dropdown(["+", "-", "*", "/"], label="Operation", value="+")
|
| 33 |
num2 = gr.Number(label="Second number")
|
| 34 |
|
| 35 |
calc_button = gr.Button("Calculate")
|
|
|
|
| 16 |
if num2 == 0:
|
| 17 |
return "Cannot divide by zero"
|
| 18 |
result = num1 / num2
|
| 19 |
+
elif operation in ["Power (^)", "^"]:
|
| 20 |
+
result = num1 ** num2
|
| 21 |
+
elif operation in ["Modulus (%)", "%"]:
|
| 22 |
+
if num2 == 0:
|
| 23 |
+
return "Cannot divide by zero"
|
| 24 |
+
result = num1 % num2
|
| 25 |
else:
|
| 26 |
return "Invalid operation"
|
| 27 |
|
| 28 |
return result
|
| 29 |
+
except OverflowError:
|
| 30 |
+
return "Result too large"
|
| 31 |
+
except ZeroDivisionError:
|
| 32 |
+
return "Cannot divide by zero"
|
| 33 |
except ValueError:
|
| 34 |
return "Please enter valid numbers"
|
| 35 |
|
|
|
|
| 39 |
|
| 40 |
with gr.Row():
|
| 41 |
num1 = gr.Number(label="First number")
|
| 42 |
+
operation = gr.Dropdown(["+", "-", "*", "/", "Power (^)", "Modulus (%)"], label="Operation", value="+")
|
| 43 |
num2 = gr.Number(label="Second number")
|
| 44 |
|
| 45 |
calc_button = gr.Button("Calculate")
|
test_calculator.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import unittest
|
| 3 |
+
from unittest.mock import MagicMock
|
| 4 |
+
|
| 5 |
+
# Ensure tests run even when gradio is not installed in the execution environment
|
| 6 |
+
if "gradio" not in sys.modules:
|
| 7 |
+
sys.modules["gradio"] = MagicMock()
|
| 8 |
+
|
| 9 |
+
from gradio_calculator import calculate
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class TestAdvancedOperations(unittest.TestCase):
|
| 13 |
+
|
| 14 |
+
def test_addition(self):
|
| 15 |
+
self.assertEqual(calculate(10, 5, "+"), 15.0)
|
| 16 |
+
|
| 17 |
+
def test_subtraction(self):
|
| 18 |
+
self.assertEqual(calculate(10, 5, "-"), 5.0)
|
| 19 |
+
|
| 20 |
+
def test_multiplication(self):
|
| 21 |
+
self.assertEqual(calculate(10, 5, "*"), 50.0)
|
| 22 |
+
|
| 23 |
+
def test_division(self):
|
| 24 |
+
self.assertEqual(calculate(10, 5, "/"), 2.0)
|
| 25 |
+
|
| 26 |
+
def test_division_by_zero(self):
|
| 27 |
+
self.assertEqual(calculate(10, 0, "/"), "Cannot divide by zero")
|
| 28 |
+
self.assertEqual(calculate(10, 0.0, "/"), "Cannot divide by zero")
|
| 29 |
+
|
| 30 |
+
def test_power_calculation(self):
|
| 31 |
+
# Example from requirements: 2 ^ 3 = 8
|
| 32 |
+
self.assertEqual(calculate(2, 3, "Power (^)"), 8.0)
|
| 33 |
+
self.assertEqual(calculate(2, 3, "^"), 8.0)
|
| 34 |
+
|
| 35 |
+
def test_negative_exponent(self):
|
| 36 |
+
# Example from requirements: 2 ^ -2 = 0.25
|
| 37 |
+
self.assertEqual(calculate(2, -2, "Power (^)"), 0.25)
|
| 38 |
+
self.assertEqual(calculate(2, -2, "^"), 0.25)
|
| 39 |
+
|
| 40 |
+
def test_modulus(self):
|
| 41 |
+
# Example from requirements: 10 % 3 = 1
|
| 42 |
+
self.assertEqual(calculate(10, 3, "Modulus (%)"), 1.0)
|
| 43 |
+
self.assertEqual(calculate(10, 3, "%"), 1.0)
|
| 44 |
+
|
| 45 |
+
def test_modulus_by_zero(self):
|
| 46 |
+
self.assertEqual(calculate(10, 0, "Modulus (%)"), "Cannot divide by zero")
|
| 47 |
+
self.assertEqual(calculate(10, 0, "%"), "Cannot divide by zero")
|
| 48 |
+
|
| 49 |
+
def test_invalid_string_inputs(self):
|
| 50 |
+
self.assertEqual(calculate("abc", 5, "+"), "Please enter valid numbers")
|
| 51 |
+
self.assertEqual(calculate(10, "xyz", "Power (^)"), "Please enter valid numbers")
|
| 52 |
+
|
| 53 |
+
def test_numerical_overflow(self):
|
| 54 |
+
self.assertEqual(calculate(10, 1000, "Power (^)"), "Result too large")
|
| 55 |
+
|
| 56 |
+
def test_known_issue_empty_inputs_raise_type_error(self):
|
| 57 |
+
"""Documents Known Bug (Fix exists on nafris/fix-calculator):
|
| 58 |
+
|
| 59 |
+
When number fields are left blank, Gradio passes None. In gradio_calculator.py,
|
| 60 |
+
calling float(None) raises TypeError. Because gradio_calculator.py only catches
|
| 61 |
+
ValueError, an unhandled TypeError is raised.
|
| 62 |
+
|
| 63 |
+
Expected future behavior: return 'Please enter valid numbers'
|
| 64 |
+
Current branch behavior: raises TypeError (documented below).
|
| 65 |
+
"""
|
| 66 |
+
with self.assertRaises(TypeError):
|
| 67 |
+
calculate(None, 5, "+")
|
| 68 |
+
with self.assertRaises(TypeError):
|
| 69 |
+
calculate(10, None, "Power (^)")
|
| 70 |
+
with self.assertRaises(TypeError):
|
| 71 |
+
calculate(None, None, "Modulus (%)")
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
if __name__ == "__main__":
|
| 75 |
+
unittest.main()
|
| 76 |
+
|