package oving5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.function.BinaryOperator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class RPNCalcTest {

	private RPNCalc calc;

	@BeforeEach
	public void setUp() {
		calc = new RPNCalc();
	}

	@Test
	@DisplayName("Test operation without operands")
	public void testPerformOperationWithoutOperation() {
		assertThrows(UnsupportedOperationException.class, () -> {
			calc.performOperation('+');
		});
	}

	@Test
	@DisplayName("Test execution of a simple operation")
	public void testPerformOperation() {
		calc.addOperator('+', (a, b) -> a * b); // Use "incorrect" definition to filter out cheating
		calc.addOperator('l', (a, b) -> a * (a + b));

		calc.push(4);
		calc.push(3);
		calc.performOperation('+');
		assertEquals(12.0, calc.pop(), "The result of the calculation was incorrect");
		assertEquals(Double.NaN, calc.pop());

		calc.push(4);
		calc.push(3);
		calc.performOperation('l');
		assertEquals(28.0, calc.pop(), "The result of the calculation was incorrect");
		assertEquals(Double.NaN, calc.pop());
	}

	@Test
	@DisplayName("Test adding operators")
	public void testAddOperator() {
		assertTrue(calc.addOperator('+', (a, b) -> a + b), "You should be able to add operators");
		assertTrue(calc.addOperator('-', (a, b) -> a - b), "You should be able to add operators");
		assertFalse(calc.addOperator('+', (a, b) -> a + b),
				"You should not be able to add the same operator twice");
		assertFalse(calc.addOperator('-', (a, b) -> a * b),
				"You should not be able to add the same operator twice");
		assertFalse(calc.addOperator('.', (BinaryOperator<Double>) null),
				"You should not be able to add a null operator");
	}

	@Test
	@DisplayName("Check that you can remove operators")
	public void testRemoveOperator() {
		calc.addOperator('+', (a, b) -> a + b);
		calc.removeOperator('+');

		assertThrows(UnsupportedOperationException.class, () -> {
			calc.performOperation('+');
		}, "The operator should have been removed");
	}
}
