def test_str(self): stack = Stack(int) self.assertEqual( str(stack), "[]", "String representation of stack doesn't work with empty stacks") stack.push(0) self.assertEqual( str(stack), "[0]", "String representation of stack doesn't work with singleton stacks" ) for i in [5, 20, 11, 34, 2]: stack.push(i) self.assertEqual( str(stack), "[0, 5, 20, 11, 34, 2]", "String representation of stack doesn't work with many elements") stack.peek() stack.pop() stack.pop() self.assertEqual( str(stack), "[0, 5, 20, 11]", "String representation of stack doesn't work after pop and peek operations" ) stack = Stack() stack.push(2.5) stack.push(0) self.assertEqual(str(stack), "[2.5, 0]")
def test_peek(self): stack = Stack() self.assertEqual( stack.peek(), None, "Top element of stack should be None at initialization") stack.push(2) stack.push("Tests") self.assertEqual(stack.peek(), "Tests", "Stack gives wrong peek") stack = Stack(float) self.assertEqual( stack.peek(), None, "Top element of stack should be None at initialization") stack.push(3.5) stack.push(1.27) stack.push(2.0) self.assertEqual(stack.peek(), 2.0, "Stack gives wrong peek")
def test_push(self): stack = Stack() stack.push(23) stack.push(20) self.assertEqual(stack.peek(), 20, "Wrong stack push implementation") self.assertEqual(len(stack), 2, "Wrong stack push implementation") stack = Stack(bool) with self.assertRaises(TypeError): stack.push("word") for i in range(10): if i % 2 == 0: stack.push(True) else: stack.push(False) self.assertEqual(stack.size(), 10, "Wrong stack push implementation")
def evaluate_expression(expression): assert type(expression) is str, "Expression must be a string object" # check for errors in parenthesis if not check_parenthesis(expression): raise ArithmeticError("Invalid parenthesis") # using the global variable operators_priorities global operators_priorities # tokenizing the expression and initializing the two stack for the operands and the operators tokens = tokenize(expression) operands = Stack(elements_type=float) operators = Stack(elements_type=str) # iterating through the the tokens of the expression for token in tokens: # pushing the token into the right stack try: # if the token is a number push into operands stack operands.push(float(token)) # if the token is one of these '(', ')', '*', '/', '+' or '-' except ValueError: try: # if the operators' stack is empty, add the token there if operators.is_empty(): operators.push(token) # if the operator is a '(', add the token to the stack elif token == "(": operators.push(token) # if the operator is a ')', call the adjust_parenthesis method elif token == ")": adjust_parenthesis(operands, operators) # if the last operator's priority is less than or equal to the priority of the current operator, # add the current operator to the stack again elif operators_priorities[operators.peek()] <= operators_priorities[token]: operators.push(token) # if the last operator's priority is greater than the priority of the current operator, # call the method adjust_stacks and push the operator into the operators' stack elif operators_priorities[operators.peek()] > operators_priorities[token]: adjust_stacks(operands, operators, token) operators.push(token) # if the token is not supported, raise a Value error except KeyError: raise ValueError("Non supported attribute in the expression") # when we went through all the tokens, check if there's only one value left in the operands' stack and 0 operators # in the operators' stack, only then we know we are finished if operands.size() != 1 and operators.size() != 0: # if the finishing property is not true, then we repeat the operation from the adjust_stacks method, # while we know that we are finished while operands.size() != 1 and operators.size() != 0: # popping the last operator with the last two operands operator = operators.pop() b = operands.pop() a = operands.pop() # evaluating the value of the simple expression and pushing it back in the stack if operator == "*": operands.push(a * b) elif operator == "/": operands.push(a / b) elif operator == "+": operands.push(a + b) elif operator == "-": operands.push(a - b) # if the operator is not from the supported ones, raise an exception else: raise ValueError("The attribute you are specifying is not supported") # when we are finished, the operands' stack contains only the result from the expression, so we pop it return operands.pop() # if we know we are finished, we directly pop the result, since the operands' stack contains only the # result from the expression else: return operands.pop()