import static org.junit.Assert.*;

import java.io.*;
import java.util.*;

import org.junit.Test;

public class CalculatorTest {

    // déclarer une variable de notre classe 
    // pour accéder à ses méthodes
    Calculator calc = new Calculator();

    @Test
    public void testAdd() {
        /*
         * Cas de tests pour int add(int, int)
         * 
         * Descr.   Entrées  Sortie attendue
         * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         * base     1, 2    3
         */

        assertEquals(3, calc.add(1, 2));
    }

    @Test
    public void testGetNameUsingGlobalScanner() {
        /*
         * Cas de test pour String getName() qui utilise un
         * Scanner déclaré globalement
         * 
         * Descr.           Entrée          Sortie attendue
         * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         * normal           "david"         "david"
         * un caractère     "A"             "A"
         * plusieurs mots   "David Crowley" "David"
         */

        /* PRÉPARATION */

        // garder une référence au Scanner original de Calculator
        Scanner original = calc.console;

        // définir les cas de test
        String testInput = "david\n" +
                "A\n" +
                "David Crowley\n"; // les \n sont les `Entrée` de l'utilisateur

        // créer une source d'entrées qui contient nos cas de tests
        InputStream testStream = new ByteArrayInputStream(testInput.getBytes());

        // passer la nouvelle source d'entrées au Scanner de Calculator
        calc.console = new Scanner(testStream); 

        /* TESTS */
        
        assertEquals("david", calc.getNameUsingGlobalScanner());
        assertEquals("A", calc.getNameUsingGlobalScanner());
        assertEquals("David", calc.getNameUsingGlobalScanner());

        /* NETTOYAGE */

        // rediriger le Scanner global de Calculator à lire sa source originale
        calc.console = original;
    }

    @Test
    public void testGetName() {
        /*
         * Cas de test pour String getName(Scanner)
         * 
         * Descr.           Entrée          Sortie attendue
         * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         * normal           "david"         "david"
         * un caractère     "A"             "A"
         * plusieurs mots   "David Crowley" "David"
         */

        /* PRÉPARATION */

        // définir les cas de test
        String testInput = "david\n" +
                "A\n" +
                "David Crowley\n"; // les \n sont les `Entrée` de l'utilisateur

        // créer un Scanner qui lit nos entrées de test au lieu de l'entrée standard
        InputStream testStream = new ByteArrayInputStream(testInput.getBytes());
        Scanner testScanner = new Scanner(testStream);

        /* TESTS */

        assertEquals("david", calc.getName(testScanner));
        assertEquals("A", calc.getName(testScanner));
        assertEquals("David", calc.getName(testScanner));

        /* NETTOYAGE */

        // Le nouveau Scanner est détruit automatiquement à la fin de cette méthode
    }

    @Test
    public void testSayName() {
        /*
         * Cas de test pour void sayName(String)
         * 
         * Descr.           Entrée          Sortie attendue
         * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         * normal           "David"         "Bonjour David"
         * un caractère     "A"             "Bonjour A"
         * plusieurs mots   "David Crowley" "Bonjour David Crowley"
         * 
         */

        /* PRÉPARATION */

        // garder une référence à la sortie standard originale
        PrintStream original = System.out;

        // rediriger la sortie standard vers un flux de sortie temporaire
        OutputStream outContent = new ByteArrayOutputStream();
        System.setOut(new PrintStream(outContent));
    
        /* TESTS */

        calc.sayName("David");
        calc.sayName("A");
        calc.sayName("David Crowley");

        String expectedOutput = "Bonjour David\nBonjour A\nBonjour David Crowley\n";

        assertEquals(expectedOutput, outContent.toString().replace("\r\n", "\n")); // le replace() est nécessaire sur Windows (encodage de fin de ligne différent)

        /* NETTOYAGE */

        // rétablir la sortie standard originale
        System.setOut(original);
    }
}
