<commit_before>package org.realityforge.arez;

import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nonnull;
import org.realityforge.guiceyloops.shared.ValueUtil;
import org.testng.annotations.Test;
import static org.testng.Assert.*;

public class ReactionSchedulerTest
  extends AbstractArezTest
{
  @Test
  public void construction()
    throws Exception
  {
    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    assertEquals( scheduler.getContext(), context );

    assertEquals( scheduler.getPendingObservers().size(), 0 );

    assertEquals( scheduler.isRunningReactions(), false );
    assertEquals( scheduler.getCurrentReactionRound(), 0 );
    assertEquals( scheduler.getRemainingReactionsInCurrentRound(), 0 );
    assertEquals( scheduler.getMaxReactionRounds(), ReactionScheduler.DEFAULT_MAX_REACTION_ROUNDS );
  }

  @Test
  public void setMaxReactionRounds()
    throws Exception
  {
    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    assertEquals( scheduler.getMaxReactionRounds(), ReactionScheduler.DEFAULT_MAX_REACTION_ROUNDS );

    scheduler.setMaxReactionRounds( 0 );
    assertEquals( scheduler.getMaxReactionRounds(), 0 );

    scheduler.setMaxReactionRounds( 1234 );
    assertEquals( scheduler.getMaxReactionRounds(), 1234 );
  }

  @Test
  public void setMaxReactionRounds_negativeValue()
    throws Exception
  {
    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    assertEquals( scheduler.getMaxReactionRounds(), ReactionScheduler.DEFAULT_MAX_REACTION_ROUNDS );

    final IllegalStateException exception =
      expectThrows( IllegalStateException.class, () -> scheduler.setMaxReactionRounds( -1 ) );

    assertEquals( exception.getMessage(), "Attempting to set maxReactionRounds to negative value -1." );
  }

  @Test
  public void onRunawayReactionsDetected()
    throws Exception
  {
    getConfigProvider().setPurgeReactionsWhenRunawayDetected( true );

    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    final Observer observer = newReadOnlyObserver( context );
    scheduler.getPendingObservers().add( observer );

    final IllegalStateException exception =
      expectThrows( IllegalStateException.class, scheduler::onRunawayReactionsDetected );

    assertEquals( exception.getMessage(),
                  "Runaway reaction(s) detected. Observers still running after " +
                  scheduler.getMaxReactionRounds() + " rounds. Current observers include: [" +
                  observer.getName() + "]" );

    // Ensure observers purged
    assertEquals( scheduler.getPendingObservers().size(), 0 );
  }

  @Test
  public void onRunawayReactionsDetected_noPurgeCOnfigured()
    throws Exception
  {
    getConfigProvider().setPurgeReactionsWhenRunawayDetected( false );

    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    final Observer observer = newReadOnlyObserver( context );
    scheduler.getPendingObservers().add( observer );

    assertThrows( IllegalStateException.class, scheduler::onRunawayReactionsDetected );

    // Ensure observers not purged
    assertEquals( scheduler.getPendingObservers().size(), 1 );
  }

  @Test
  public void onRunawayReactionsDetected_invariantCheckingDisabled()
    throws Exception
  {
    getConfigProvider().setCheckInvariants( false );

    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    final Observer observer = new Observer( context, ValueUtil.randomString() );
    scheduler.getPendingObservers().add( observer );

    scheduler.onRunawayReactionsDetected();
  }

  @Test
  public void scheduleReaction()<commit_msg>Use factory methods where possible<commit_after>package org.realityforge.arez;

import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nonnull;
import org.realityforge.guiceyloops.shared.ValueUtil;
import org.testng.annotations.Test;
import static org.testng.Assert.*;

public class ReactionSchedulerTest
  extends AbstractArezTest
{
  @Test
  public void construction()
    throws Exception
  {
    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    assertEquals( scheduler.getContext(), context );

    assertEquals( scheduler.getPendingObservers().size(), 0 );

    assertEquals( scheduler.isRunningReactions(), false );
    assertEquals( scheduler.getCurrentReactionRound(), 0 );
    assertEquals( scheduler.getRemainingReactionsInCurrentRound(), 0 );
    assertEquals( scheduler.getMaxReactionRounds(), ReactionScheduler.DEFAULT_MAX_REACTION_ROUNDS );
  }

  @Test
  public void setMaxReactionRounds()
    throws Exception
  {
    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    assertEquals( scheduler.getMaxReactionRounds(), ReactionScheduler.DEFAULT_MAX_REACTION_ROUNDS );

    scheduler.setMaxReactionRounds( 0 );
    assertEquals( scheduler.getMaxReactionRounds(), 0 );

    scheduler.setMaxReactionRounds( 1234 );
    assertEquals( scheduler.getMaxReactionRounds(), 1234 );
  }

  @Test
  public void setMaxReactionRounds_negativeValue()
    throws Exception
  {
    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    assertEquals( scheduler.getMaxReactionRounds(), ReactionScheduler.DEFAULT_MAX_REACTION_ROUNDS );

    final IllegalStateException exception =
      expectThrows( IllegalStateException.class, () -> scheduler.setMaxReactionRounds( -1 ) );

    assertEquals( exception.getMessage(), "Attempting to set maxReactionRounds to negative value -1." );
  }

  @Test
  public void onRunawayReactionsDetected()
    throws Exception
  {
    getConfigProvider().setPurgeReactionsWhenRunawayDetected( true );

    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    final Observer observer = newReadOnlyObserver( context );
    scheduler.getPendingObservers().add( observer );

    final IllegalStateException exception =
      expectThrows( IllegalStateException.class, scheduler::onRunawayReactionsDetected );

    assertEquals( exception.getMessage(),
                  "Runaway reaction(s) detected. Observers still running after " +
                  scheduler.getMaxReactionRounds() + " rounds. Current observers include: [" +
                  observer.getName() + "]" );

    // Ensure observers purged
    assertEquals( scheduler.getPendingObservers().size(), 0 );
  }

  @Test
  public void onRunawayReactionsDetected_noPurgeCOnfigured()
    throws Exception
  {
    getConfigProvider().setPurgeReactionsWhenRunawayDetected( false );

    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    final Observer observer = newReadOnlyObserver( context );
    scheduler.getPendingObservers().add( observer );

    assertThrows( IllegalStateException.class, scheduler::onRunawayReactionsDetected );

    // Ensure observers not purged
    assertEquals( scheduler.getPendingObservers().size(), 1 );
  }

  @Test
  public void onRunawayReactionsDetected_invariantCheckingDisabled()
    throws Exception
  {
    getConfigProvider().setCheckInvariants( false );

    final ArezContext context = new ArezContext();
    final ReactionScheduler scheduler = new ReactionScheduler( context );

    final Observer observer = newReadOnlyObserver( context );
    scheduler.getPendingObservers().add( observer );

    scheduler.onRunawayReactionsDetected();
  }

  @Test
  public void scheduleReaction()
{'fraction_non_alphanumeric': 0.08625, 'fraction_numerical': 0.00425, 'mean_word_length': 4.472640218878249, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2370355', 'n_tokens_mistral': 2242, 'n_tokens_neox': 2139, 'n_words': 485}