package testowanie;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class KontoTest_WersjaRozszerzona {
	private Konto konto;
	
	@BeforeEach
	void setUp() {
		// ta metoda zostanie uruchomiona bezpośrednio przed każdym testem
		// dokonuje się w niej inicjalizacji danych potrzebnych do testu - "stan początkowy" / "fixture"
		konto = new Konto(1234, 1000, "Ala Kowalska");
	}

	@Test
	void testConstructor() {
		assertEquals(1234, konto.getNumer());
		assertEquals(1000, konto.getSaldo());
		assertEquals("Ala Kowalska", konto.getWlasciciel());
	}
	
	@Test
	void testToString() {
		assertEquals("Konto nr 1234, saldo 1000, wł. Ala Kowalska", konto.toString());
	}
	
	@Test
	void testWplata() {
		konto.wplata(300);
		assertEquals(1300, konto.getSaldo());
	}
	
	@Test
	void testWyplata() throws BrakSrodkow {
		konto.wyplata(400);
		assertEquals(600, konto.getSaldo());
	}
	
	// Temat sprawdzania wyjątków w testach.
	
	// Aby stwierdzić, że w pewnej sytuacji metoda POWINNA skończyć się wyjątkiem,
	// możemy użyć odpowiednio try-catch (testWplataTry)
	// albo użyć dedykowanych rozwiązań JUnit - dalsze przykłady
	
	@Test
	void testWplataTry() {
		try {
			konto.wplata(-100);
			// Gdyby nie było wyjątku i program doszedłby do tego miejsca,
			// test powinien skończyć się porażką
			fail("Powinien być wyjątek, a nie ma.");
		} catch(IllegalArgumentException e) {
			// Jeśli wyłapiemy wyjątek, możemy sprawdzić w teście jego szczegóły,
			// np. jaki jest message (bardzo rzadko takie rzeczy sprawdza się w testach, ale można):
			assertEquals("Niedodatnia kwota w metodzie wplata", e.getMessage());
		} finally {
			// Możemy też upewnić się, że w przypadku wystąpienia wyjątku stan konta się nie zmienił.
			assertEquals(1000, konto.getSaldo());
		}
	}
	
	// Analogiczny test można też napisać wykorzystując nową funkcjonalność JUnit 5:
	@Test
	void testWplataUjemna_v1() {
		// assertThrows wykonuje podany fragment kodu (w praktyce podaje się wyrażenie lambda)
		// i sprawdza czy ten kończy się podanym rodzajem wyjątku.
		// Jeśli jest wyjątek - dobrze
		// Jeśli nie ma wyjątku - test failuje
		
		assertThrows(IllegalArgumentException.class, () -> {
			konto.wplata(-100);			
		});

		// Dodatkowo po wykonaniu assertThrows możemy sprawdzić jaki jest stan końcowy,
		// np. czy saldo się nie zmieniło.
		assertEquals(1000, konto.getSaldo());
	}
	
	// Aby sprawdzić jaki jest message w wyjątku itp, możemy odebrać obiekt wyjątku i sprawdzić bezpośrednio
	@Test
	void testWplataUjemna_v2() {
		IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
			konto.wplata(-100);			
		});

		assertEquals("Niedodatnia kwota w metodzie wplata", exception.getMessage());
		assertEquals(1000, konto.getSaldo());
	}
	
	@Test
	void testWyplataUjemna() {
		assertThrows(IllegalArgumentException.class, () -> {
			konto.wyplata(-100);			
		});
		assertEquals(1000, konto.getSaldo());
	}
	
	@Test
	void testBrakSrodkow() {
		assertThrows(BrakSrodkow.class, () -> {
			konto.wyplata(1300);			
		});
		assertEquals(1000, konto.getSaldo());
	}

}
