package examples.junit;        // update this line based on where your test class is

import sut.ArrayOperations;    // update this line based on where your subject under test is

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

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;       // for assertTrue

class ArrayOperationsNumZeroTest 
{
   @BeforeAll
   public static void setUpBeforeClass() throws Exception 
   {
   }

   @AfterAll
   public static void tearDownAfterClass() throws Exception 
   {
   }

   @BeforeEach
   void setUp() throws Exception 
   {
	  // prefix actions executed before each test	   
   }

   @AfterEach
   void tearDown() throws Exception 
   {
	  // postfix actions executed after each test
   }

   // purpose:
   // input: { }
   // expected output: 0 
   @Test
   public void testNumZeroEmptyArray() 
   {
      int x[] = {};                 // zero-sized array
      int n = ArrayOperations.numZero(x);
//      ArrayOperations myObj = new ArrayOperations();
//      int n = myObj.numZero(x);
      assertEquals(0, n, "test -- array is empty");           // assertEquals(expected, actual)
   }
	   
   @Test
   public void testNumZeroArrayWithNoZeros()
   {
      int[] x = {1, 2, 3};                  // 1. setup
      int n = ArrayOperations.numZero(x);   // 2. execute
      assertEquals(0, n);                   // 3. assertion
   }
   
   @Test
   @DisplayName("custom test name by อัปสร")
   public void testNumZeroArrayWithOneZero()
   {
      int[] x = {1, 2, 3, 0};                   // 1. setup
      int n = ArrayOperations.numZero(x);       // 2. execute
      assertTrue(1==n, "Zero not at index 0");  // 3. assertion
   }   
   
   @Test
   public void testNumZeroArrayWithMultipleZeros()
   {
      int[] x = {1, 0, 3, 0};                   // 1. setup
      int n = ArrayOperations.numZero(x);       // 2. execute
      assertTrue(2==n, "Zero not at index 0");  // 3. assertion
   }      
   
   @Test   // detect a fault
   public void testNumZeroArrayWithZeroAtIndexZeros()
   {
      int[] x = {0, 2, 3, 0};                   // 1. setup
      int n = ArrayOperations.numZero(x);       // 2. execute
      assertTrue(2==n, "Zero at index 0");      // 3. assertion
   }      

   
   // Two common used patterns to verify that an exception is thrown as expected.
   // Very often, just checking for an exception 
   // (or simply check if the program crashes) is wasteful. 
   // It is useful in situations when we wish to perform other assertions 
   // beyond the expected exception behavior.
   
   // Pattern #1
   // This pattern is more verbose and unnecessary in this case. 
   @Test
   public void testNumZeroWithNullArgument_1()
   {
      int[] x = null;
      try {
         ArrayOperations.numZero(x);
         // fail("expected NullPointerException");
      } catch (NullPointerException e) { }
   }
   
   // Pattern #2
   // Verify if a given exception is raised using assertThrows(expected_exception, actual output)
   @Test
   public void testNumZeroWihNullArgumant_2()
   {
      int[] x = null;
//      Assertions.assertThrows( NullPointerException.class,  
      assertThrows( NullPointerException.class,
         () -> { ArrayOperations.numZero(x); } );
   }
   
   @Test void testNumZeroWithNullArgument_verifyExceptionMessage() 
   {
      int[] x = null;
      Exception exception = assertThrows(NullPointerException.class,
         () -> { ArrayOperations.numZero(x); } ); 
      // verify the expected exception, then verify the expected message
      // using assertEquals(expected, actual)
      assertEquals("array is null", exception.getMessage());         
   }
   
}
