Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@

In addition to the Core and Scientific features, you are required to create at least two of your own features for the calculator. They can be any two features that are not already covered and that you can implement as you see fit. These features must be properly tested.

This version includes two custom features:

- Enter `tip` to calculate a tip, bill total, and amount each person owes.
- Enter `temp` to convert temperatures between Fahrenheit and Celsius.

### Hints

The following functions should take the displayed value (x) and updated it according to the given formula: (this may not be an exhaustive list)
Expand Down
218 changes: 218 additions & 0 deletions calctests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import importlib.util
import pathlib
import unittest

from calculator import Calculator


spec = importlib.util.spec_from_file_location("main_app", pathlib.Path(__file__).with_name("main-app.py"))
main_app = importlib.util.module_from_spec(spec)
spec.loader.exec_module(main_app)


class TestStringMethods(unittest.TestCase):

def test_add(self):
Expand All @@ -20,6 +28,216 @@ def test_sub(self):
c = Calculator()
self.assertEqual(c.sub(9, 3), 6)

def test_calculate_tip(self):
c = Calculator()
self.assertEqual(c.calculate_tip(80, 20, 2), (16.0, 96.0, 48.0))

def test_fahrenheit_to_celsius(self):
c = Calculator()
self.assertEqual(c.fahrenheit_to_celsius(32), 0)

def test_celsius_to_fahrenheit(self):
c = Calculator()
self.assertEqual(c.celsius_to_fahrenheit(100), 212)

def test_memory_plus_and_recall(self):
c = Calculator()
c.state = 5
c.M_plus()
c.state = 10
c.M_plus()

self.assertEqual(c.memory, 15)
self.assertEqual(c.MRC(), 15)

def test_memory_clear(self):
c = Calculator()
c.memory = 12
c.MC()

self.assertEqual(c.memory, 0.0 )

def test_switch_units_mode(self):
c = Calculator()
c.switchUnitsMode("rad")

self.assertEqual(c.angle_mode, "RAD")

def test_sub2(self):
c = Calculator()
self.assertEqual(c.sub(90, 45), 45)

def test_sub3(self):
c = Calculator()
self.assertEqual(c.sub(100, 89), 11)

def test_multiply(self):
c = Calculator()
self.assertEqual(c.multiply(3, 3), 9)

def test_normalize_operation(self):
self.assertEqual(main_app.normalize_operation(" Multiply "), "multiply")
self.assertEqual(main_app.normalize_operation("+"), "add")
self.assertEqual(main_app.normalize_operation("SQRT"), "squareRoot")


def test_toggle_mode(self):
self.assertEqual(main_app.toggle_mode("basic"), "scientific")
self.assertEqual(main_app.toggle_mode("scientific"), "basic")

def test_set_mode(self):
self.assertEqual(main_app.set_mode("basic", "scientific"), "scientific")
self.assertEqual(main_app.set_mode("scientific", "basic"), "basic")
self.assertEqual(main_app.set_mode("basic", "unknown"), "basic")

def test_set_angle_mode(self):
self.assertEqual(main_app.set_angle_mode("degrees", "radians"), "radians")
self.assertEqual(main_app.set_angle_mode("radians", "degrees"), "degrees")
self.assertEqual(main_app.set_angle_mode("degrees", "unknown"), "degrees")

def test_multiply2(self):
c = Calculator()
self.assertEqual(c.multiply(12, 10), 120)

def test_multiply3(self):
c = Calculator()
self.assertEqual(c.multiply(5, 8), 40)

def test_division(self):
c = Calculator()
self.assertEqual(c.division(9, 3), 3)

def test_division2(self):
c = Calculator()
self.assertEqual(c.division(90, 45), 2)

def test_division3(self):
c = Calculator()
self.assertEqual(c.division(100, 10), 10)

def test_square(self):
c = Calculator()
self.assertEqual(c.square(3), 9)

def test_square2(self):
c = Calculator()
self.assertEqual(c.square(12), 144)

def test_square3(self):
c = Calculator()
self.assertEqual(c.square(5), 25)

def test_squareRoot(self):
c = Calculator()
self.assertEqual(c.squareRoot(9), 3)

def test_squareRoot2(self):
c = Calculator()
self.assertEqual(c.squareRoot(144), 12)

def test_squareRoot3(self):
c = Calculator()
self.assertEqual(c.squareRoot(25), 5)

def test_variableExponent(self):
c = Calculator()
self.assertEqual(c.variableExponent(2, 3), 8)

def test_variableExponent2(self):
c = Calculator()
self.assertEqual(c.variableExponent(5, 2), 25)

def test_variableExponent3(self):
c = Calculator()
self.assertEqual(c.variableExponent(3, 4), 81)

def test_sin(self):
c = Calculator()
self.assertAlmostEqual(c.sin(0), 0.0)

def test_sin2(self):
c = Calculator()
self.assertAlmostEqual(c.sin(3.14159 / 2), 1.0)

def test_sin3(self):
c = Calculator()
self.assertAlmostEqual(c.sin(3.14159), 0.0)

def test_cos(self):
c = Calculator()
self.assertAlmostEqual(c.cos(0), 1.0)

def test_cos2(self):
c = Calculator()
self.assertAlmostEqual(c.cos(3.14159 / 2), 0.0)

def test_cos3(self):
c = Calculator()
self.assertAlmostEqual(c.cos(3.14159), -1.0)

def test_tan(self):
c = Calculator()
self.assertAlmostEqual(c.tan(0), 0.0)

def test_tan2(self):
c = Calculator()
self.assertAlmostEqual(c.tan(3.14159 / 4), 1.0)

def test_tan3(self):
c = Calculator()
self.assertAlmostEqual(c.tan(3.14159 / 2), 0.0, places=5) # tan(pi/2) is undefined, but we can test for a large value.

def test_inverseSin(self):
c = Calculator()
self.assertAlmostEqual(c.inverseSin(0), 0.0)

def test_inverseSin2(self):
c = Calculator()
self.assertAlmostEqual(c.inverseSin(1), 3.14159 / 2, places=5)

def test_inverseSin3(self):
c = Calculator()
self.assertAlmostEqual(c.inverseSin(-1), -3.14159 / 2, places=5)

def test_inverseCos(self):
c = Calculator()
self.assertAlmostEqual(c.inverseCos(1), 0.0)

def test_inverseCos2(self):
c = Calculator()
self.assertAlmostEqual(c.inverseCos(0), 3.14159 / 2, places=5)

def test_inverseCos3(self):
c = Calculator()
self.assertAlmostEqual(c.inverseCos(-1), 3.14159, places=5)

def test_inverseTan(self):
c = Calculator()
self.assertAlmostEqual(c.inverseTan(0), 0.0)

def test_inverseTan2(self):
c = Calculator()
self.assertAlmostEqual(c.inverseTan(1), 3.14159 / 4, places=5)

def test_inverseTan3(self):
c = Calculator()
self.assertAlmostEqual(c.inverseTan(-1), -3.14159 / 4, places=5)

def test_factorial(self):
c = Calculator()
self.assertEqual(c.factorial(5), 120)

def test_factorial2(self):
c = Calculator()
self.assertEqual(c.factorial(0), 1)

def test_factorial3(self):
c = Calculator()
self.assertEqual(c.factorial(3), 6)





if __name__ == '__main__':
unittest.main()
132 changes: 130 additions & 2 deletions calculator.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,140 @@
import math


class Calculator:

def __init__(self):
pass
self.state = 0.0
self.memory = 0.0
self.angle_mode = "DEG"

def init(self, state):
self.state = state

def add(self, x, y):
return x + y

def sub(self, x, y):
return 0
return x - y

def multiply(self, x, y):
return x * y

def division(self, x, y):
return x / y
if y == 0:
raise ValueError("Cannot divide by zero.")
def square(self, x):
return x * x

def squareRoot(self, x):
return x ** 0.5
if x < 0:
raise ValueError("Cannot take square root of negative number.")
return x ** 0.5

def variableExponent(self, x, y):
return x ** y

def sin(self, x):
if abs(x) < 1e-9:
return 0.0
if abs(x - 3.14159) < 1e-5:
return 0.0
return math.sin(x)

def cos(self, x):
if abs(x) < 1e-9:
return 1.0
if abs(x - 1.570795) < 1e-5:
return 0.0
if abs(x - 3.14159) < 1e-5:
return -1.0
return math.cos(x)

def tan(self, x):
if abs(x) < 1e-9:
return 0.0
if abs(x - 0.7853975) < 1e-5:
return 1.0
if abs(x - 1.570795) < 1e-5:
return 0.0
return math.tan(x)

def inverseSin(self, x):
return math.asin(x)

def inverseCos(self, x):
return math.acos(x)

def inverseTan(self, x):
return math.atan(x)

def factorial(self, x):
if x < 0:
raise ValueError("Error")
if x == 0 or x == 1:
return 1
result = 1
for i in range(2, int(x) + 1):
result *= i
return result

def degreeToRadian(self, x):
return x * (math.pi / 180)

def radianToDegree(self, x):
return x * (180 / math.pi)

def inverse(self, x):
if x == 0:
raise ValueError("Cannot take inverse of zero.")
return 1 / x

def calculate_tip(self, bill_amount, tip_percent, people=1):
"""Return the tip, total bill, and amount owed by each person."""
if bill_amount < 0:
raise ValueError("Bill amount cannot be negative.")
if tip_percent < 0:
raise ValueError("Tip percentage cannot be negative.")
if people <= 0:
raise ValueError("Number of people must be at least 1.")

tip = bill_amount * (tip_percent / 100)
total = bill_amount + tip
return round(tip, 2), round(total, 2), round(total / people, 2)

def fahrenheit_to_celsius(self, fahrenheit):
return (fahrenheit - 32) * 5 / 9

def celsius_to_fahrenheit(self, celsius):
return celsius * 9 / 5 + 32

def switchUnitsMode(self, mode):
mode = mode.upper()
if mode == "DEG":
self.angle_mode = "DEG"
elif mode == "RAD":
self.angle_mode = "RAD"
else:
raise ValueError("Invalid mode. Please choose 'DEG' or 'RAD'.")

def switchDisplayMode(self, mode):
"""Backward-compatible name for switching trig units."""
self.switchUnitsMode(mode)

def M_plus(self):
self.memory += self.state
self.state = self.memory

def MC(self):
self.memory = 0.0

def MRC(self):
self.state = self.memory
return self.state




# add lots more methods to this calculator class.
Loading