package arez;

import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import org.testng.annotations.Test;
import static org.testng.Assert.*;

public class ObserverErrorHandlerSupportTest
  extends AbstractArezTest
{
  @Test
  public void basicOperation()
  {
    final ObserverErrorHandlerSupport support = new ObserverErrorHandlerSupport();

    final ArezContext context = new ArezContext();
    final Observer observer = newReadOnlyObserver( context );
    final ObserverError error = ObserverError.ON_ACTIVATE_ERROR;
    final Throwable throwable = null;

    final AtomicInteger callCount = new AtomicInteger();

    final ObserverErrorHandler handler = ( observerArg, errorArg, throwableArg ) -> {
      callCount.incrementAndGet();
      assertEquals( observerArg, observer );
      assertEquals( errorArg, error );
      assertEquals( throwableArg, throwable );
    };
    support.addObserverErrorHandler( handler );
    assertEquals( support.getObserverErrorHandlers().size(), 1 );

    support.onObserverError( observer, error, throwable );

    assertEquals( callCount.get(), 1 );

    support.onObserverError( observer, error, throwable );

    assertEquals( callCount.get(), 2 );

    support.removeObserverErrorHandler( handler );

    assertEquals( support.getObserverErrorHandlers().size(), 0 );

    support.onObserverError( observer, error, throwable );

    // Not called again
    assertEquals( callCount.get(), 2 );
  }

  @Test
  public void addObserverErrorHandler_alreadyExists()
    throws Exception
  {
    final ObserverErrorHandlerSupport support = new ObserverErrorHandlerSupport();

    final ObserverErrorHandler handler = ( observerArg, errorArg, throwableArg ) -> {
    };
    support.addObserverErrorHandler( handler );

    final IllegalStateException exception =
      expectThrows( IllegalStateException.class, () -> support.addObserverErrorHandler( handler ) );

    assertEquals( exception.getMessage(),
                  "Arez-0096: Attempting to add handler " + handler + " that is already in " +
                  "the list of error handlers." );
  }

  @Test
  public void removeObserverErrorHandler_noExists()
    throws Exception
  {
    final ObserverErrorHandlerSupport support = new ObserverErrorHandlerSupport();

    final ObserverErrorHandler handler = ( observerArg, errorArg, throwableArg ) -> {
    };

    final IllegalStateException exception =
      expectThrows( IllegalStateException.class, () -> support.removeObserverErrorHandler( handler ) );

    assertEquals( exception.getMessage(),
                  "Arez-0097: Attempting to remove handler " + handler + " that is not in " +
                  "the list of error handlers." );
  }

  @Test
  public void multipleHandlers()
  {
    final ObserverErrorHandlerSupport support = new ObserverErrorHandlerSupport();

    final ArezContext context = new ArezContext();
    final Observer observer = newReadOnlyObserver( context );
    final ObserverError error = ObserverError.ON_ACTIVATE_ERROR;
    final Throwable throwable = null;

    final AtomicInteger callCount1 = new AtomicInteger();
    final AtomicInteger callCount2 = new AtomicInteger();
    final AtomicInteger callCount3 = new AtomicInteger();

    final ObserverErrorHandler handler1 = ( observerArg, errorArg, throwableArg ) -> callCount1.incrementAndGet();
    final ObserverErrorHandler handler2 = ( observerArg, errorArg, throwableArg ) -> callCount2.incrementAndGet();
    final ObserverErrorHandler handler3 = ( observerArg, errorArg, throwableArg ) -> callCount3.incrementAndGet();
    support.addObserverErrorHandler( handler1 );
    support.addObserverErrorHandler( handler2 );
    support.addObserverErrorHandler( handler3 );

    assertEquals( support.getObserverErrorHandlers().size(), 3 );

    support.onObserverError( observer, error, throwable );

    assertEquals( callCount1.get(), 1 );
    assertEquals( callCount2.get(), 1 );
    assertEquals( callCount3.get(), 1 );

    support.onObserverError( observer, error, throwable );

    assertEquals( callCount1.get(), 2 );
    assertEquals( callCount2.get(), 2 );
    assertEquals( callCount3.get(), 2 );
  }

  @Test
  public void onObserverError_whereOneHandlerGeneratesError()
  {
    final ObserverErrorHandlerSupport support = new ObserverErrorHandlerSupport();

    final ArezContext context = new ArezContext();
    final Observer observer = newReadOnlyObserver( context );
    final ObserverError error = ObserverError.ON_ACTIVATE_ERROR;
    final Throwable throwable = null;

    final AtomicInteger callCount1 = new AtomicInteger();
    final AtomicInteger callCount3 = new AtomicInteger();

    final RuntimeException exception = new RuntimeException( "X" );

    final ObserverErrorHandler handler1 = ( observerArg, errorArg, throwableArg ) -> callCount1.incrementAndGet();
    final ObserverErrorHandler handler2 = ( observerArg, errorArg, throwableArg ) -> {
      throw exception;
    };
    final ObserverErrorHandler handler3 = ( observerArg, errorArg, throwableArg ) -> callCount3.incrementAndGet();
    support.addObserverErrorHandler( handler1 );
    support.addObserverErrorHandler( handler2 );
    support.addObserverErrorHandler( handler3 );

    support.onObserverError( observer, error, throwable );

    assertEquals( callCount1.get(), 1 );
    assertEquals( callCount3.get(), 1 );

    final ArrayList<TestLogger.LogEntry> entries = getTestLogger().getEntries();
    assertEquals( entries.size(), 1 );
    final TestLogger.LogEntry entry1 = entries.get( 0 );
    assertEquals( entry1.getMessage(),
                  "Exception when notifying error handler '" + handler2 + "' of 'ON_ACTIVATE_ERROR' error " +
                  "in observer named '" + observer.getName() + "'." );
    assertEquals( entry1.getThrowable(), exception );

    support.onObserverError( observer, error, throwable );

    assertEquals( callCount1.get(), 2 );
    assertEquals( callCount3.get(), 2 );

    assertEquals( getTestLogger().getEntries().size(), 2 );
  }
}

@@ -5957,24 +5957,1304 @@
 et(), 2 );%0A%0A
+    assertEquals( getTestLogger().getEntries().size(), 2 );%0A  %7D%0A%0A  @Test%0A  public void onObserverError_whereOneHandlerGeneratesError_but_Arez_areNamesEnabled_is_false()%0A  %7B%0A    ArezTestUtil.disableNames();%0A%0A    final ObserverErrorHandlerSupport support = new ObserverErrorHandlerSupport();%0A%0A    final ArezContext context = new ArezContext();%0A    final Observer observer =%0A      new Observer( context, null, null, null, TransactionMode.READ_ONLY, new TestReaction(), false );%0A    final ObserverError error = ObserverError.ON_ACTIVATE_ERROR;%0A    final Throwable throwable = null;%0A%0A    final RuntimeException exception = new RuntimeException( %22X%22 );%0A%0A    final ObserverErrorHandler handler2 = ( observerArg, errorArg, throwableArg ) -%3E %7B%0A      throw exception;%0A    %7D;%0A    support.addObserverErrorHandler( handler2 );%0A%0A    support.onObserverError( observer, error, throwable );%0A%0A    final ArrayList%3CTestLogger.LogEntry%3E entries = getTestLogger().getEntries();%0A    assertEquals( entries.size(), 1 );%0A    final TestLogger.LogEntry entry1 = entries.get( 0 );%0A    assertEquals( entry1.getMessage(), %22Error triggered when invoking ObserverErrorHandler.onObserverError()%22 );%0A    assertEquals( entry1.getThrowable(), exception );%0A%0A    support.onObserverError( observer, error, throwable );%0A%0A
     assertEq

Add additional test