<commit_before>package org.realityforge.arez;

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

public class TransactionTest
  extends AbstractArezTest
{
  @Test
  public void construction()
  {
    final ArezContext context = new ArezContext();
    final String name1 = ValueUtil.randomString();
    final int nextNodeId = context.currentNextNodeId();

    final Transaction transaction = new Transaction( context, null, name1, TransactionMode.READ_ONLY, null );

    assertEquals( transaction.getName(), name1 );
    assertEquals( transaction.getContext(), context );
    assertEquals( transaction.getId(), nextNodeId );
    assertEquals( transaction.getPrevious(), null );
    assertEquals( transaction.getTracker(), null );
    assertEquals( transaction.getObservables(), null );
    assertEquals( transaction.getPendingDeactivations(), null );
    assertEquals( transaction.getMode(), TransactionMode.READ_ONLY );

    assertEquals( context.currentNextNodeId(), nextNodeId + 1 );
  }

  @Test
  public void construction_with_READ_WRITE_OWNED_but_no_tracker()
  {
    final ArezContext context = new ArezContext();
    final String name = ValueUtil.randomString();

    final IllegalStateException exception =
      expectThrows( IllegalStateException.class,
                    () -> new Transaction( context, null, name, TransactionMode.READ_WRITE_OWNED, null ) );

    assertEquals( exception.getMessage(),
                  "Attempted to create transaction named '" + name +
                  "' with mode READ_WRITE_OWNED but no tracker specified." );
  }

  @Test
  public void rootTransaction()
  {
    final ArezContext context = new ArezContext();

    final Transaction transaction1 =
      new Transaction( context, null, ValueUtil.randomString(), TransactionMode.READ_ONLY, null );
    final Transaction transaction2 =
      new Transaction( context, transaction1, ValueUtil.randomString(), TransactionMode.READ_ONLY, null );

    assertEquals( transaction1.isRootTransaction(), true );
    assertEquals( transaction1.getRootTransaction(), transaction1 );

    assertEquals( transaction2.isRootTransaction(), false );
    assertEquals( transaction2.getRootTransaction(), transaction1 );
  }

  @Test
  public void begin()
  {
    final ArezContext context = new ArezContext();
    final Observer tracker = newDerivation( context );
    final Transaction transaction =
      new Transaction( context, null, ValueUtil.randomString(), TransactionMode.READ_ONLY, tracker );
    context.setTransaction( transaction );

    assertEquals( tracker.getState(), ObserverState.INACTIVE );

    transaction.begin();

    //Just verify that it ultimately invokes beginTracking
    assertEquals( tracker.getState(), ObserverState.UP_TO_DATE );
  }

  @Test
  public void commit()
  {
    final ArezContext context = new ArezContext();
    final Observer tracker = newDerivation( context );

    final Transaction transaction =
      new Transaction( context, null, ValueUtil.randomString(), TransactionMode.READ_ONLY, tracker );
    context.setTransaction( transaction );

    tracker.setState( ObserverState.UP_TO_DATE );

    ensureDerivationHasObserver( tracker );

    final Observable observable1 = new Observable( context, ValueUtil.randomString() );
    final Observer derivation = newDerivation( context );
    derivation.setState( ObserverState.UP_TO_DATE );
    final Observable observable2 = derivation.getDerivedValue();

    tracker.getDependencies().add( observable2 );
    observable2.getObservers().add( tracker );

    observable2.markAsPendingDeactivation();
    transaction.queueForDeactivation( observable2 );

    assertNotNull( transaction.getPendingDeactivations() );
    assertEquals( transaction.getPendingDeactivations().size(), 1 );
    assertEquals( observable2.isActive(), true );
    assertEquals( observable2.isPendingDeactivation(), true );

    transaction.safeGetObservables().add( observable1 );
    final ArrayList<Observable> dependencies = tracker.getDependencies();

    transaction.commit();

    // The next code block essentially verifies it calls completeTracking
    assertEquals( tracker.getState(), ObserverState.UP_TO_DATE );
    assertTrue( tracker.getDependencies() != dependencies );
    assertEquals( tracker.getDependencies().size(), 1 );
    assertEquals( tracker.getDependencies().contains( observable1 ), true );
    assertEquals( observable1.getWorkState(), Observable.NOT_IN_CURRENT_TRACKING );

    // This section essentially verifies processPendingDeactivations() is called
    assertEquals( observable2.isPendingDeactivation(), false );
    assertEquals( observable2.isActive(), false );
    assertEquals( observable2.getOwner(), derivation );
    assertEquals( derivation.getState(), ObserverState.INACTIVE );
  }

  @Test
  public void trackingCycleWithNoTracker()
  {
    final ArezContext context = new ArezContext();
    final Transaction transaction =
      new Transaction( context, null, ValueUtil.randomString(), TransactionMode.READ_ONLY, null );

    final Observable observable = new Observable( context, ValueUtil.randomString() );

    assertEquals( observable.getObservers().size(), 0 );
    assertEquals( transaction.getObservables(), null );

    //Transaction should perform no action during tracking if there is no associated tracker
    transaction.beginTracking();
    transaction.observe( observable );
    transaction.completeTracking();

    assertEquals( observable.getObservers().size(), 0 );
    assertEquals( transaction.getObservables(), null );
  }

  @Test
  public void beginTracking()
  {
    final ArezContext context = new ArezContext();
    final Observer tracker = newDerivation( context );
    final Transaction transaction =
      new Transaction( context, null, ValueUtil.randomString(), TransactionMode.READ_ONLY, tracker );
    context.setTransaction( transaction );<commit_msg>Rename test for clarity<commit_after>package org.realityforge.arez;

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

public class TransactionTest
  extends AbstractArezTest
{
  @Test
  public void construction()
  {
    final ArezContext context = new ArezContext();
    final String name1 = ValueUtil.randomString();
    final int nextNodeId = context.currentNextNodeId();

    final Transaction transaction = new Transaction( context, null, name1, TransactionMode.READ_ONLY, null );

    assertEquals( transaction.getName(), name1 );
    assertEquals( transaction.getContext(), context );
    assertEquals( transaction.getId(), nextNodeId );
    assertEquals( transaction.getPrevious(), null );
    assertEquals( transaction.getTracker(), null );
    assertEquals( transaction.getObservables(), null );
    assertEquals( transaction.getPendingDeactivations(), null );
    assertEquals( transaction.getMode(), TransactionMode.READ_ONLY );

    assertEquals( context.currentNextNodeId(), nextNodeId + 1 );
  }

  @Test
  public void construction_with_READ_WRITE_OWNED_but_no_tracker()
  {
    final ArezContext context = new ArezContext();
    final String name = ValueUtil.randomString();

    final IllegalStateException exception =
      expectThrows( IllegalStateException.class,
                    () -> new Transaction( context, null, name, TransactionMode.READ_WRITE_OWNED, null ) );

    assertEquals( exception.getMessage(),
                  "Attempted to create transaction named '" + name +
                  "' with mode READ_WRITE_OWNED but no tracker specified." );
  }

  @Test
  public void rootTransaction()
  {
    final ArezContext context = new ArezContext();

    final Transaction transaction1 =
      new Transaction( context, null, ValueUtil.randomString(), TransactionMode.READ_ONLY, null );
    final Transaction transaction2 =
      new Transaction( context, transaction1, ValueUtil.randomString(), TransactionMode.READ_ONLY, null );

    assertEquals( transaction1.isRootTransaction(), true );
    assertEquals( transaction1.getRootTransaction(), transaction1 );

    assertEquals( transaction2.isRootTransaction(), false );
    assertEquals( transaction2.getRootTransaction(), transaction1 );
  }

  @Test
  public void begin()
  {
    final ArezContext context = new ArezContext();
    final Observer tracker = newDerivation( context );
    final Transaction transaction =
      new Transaction( context, null, ValueUtil.randomString(), TransactionMode.READ_ONLY, tracker );
    context.setTransaction( transaction );

    assertEquals( tracker.getState(), ObserverState.INACTIVE );

    transaction.begin();

    //Just verify that it ultimately invokes beginTracking
    assertEquals( tracker.getState(), ObserverState.UP_TO_DATE );
  }

  @Test
  public void commit()
  {
    final ArezContext context = new ArezContext();
    final Observer tracker = newDerivation( context );

    final Transaction transaction =
      new Transaction( context, null, ValueUtil.randomString(), TransactionMode.READ_ONLY, tracker );
    context.setTransaction( transaction );

    tracker.setState( ObserverState.UP_TO_DATE );

    ensureDerivationHasObserver( tracker );

    final Observable observable1 = new Observable( context, ValueUtil.randomString() );
    final Observer derivation = newDerivation( context );
    derivation.setState( ObserverState.UP_TO_DATE );
    final Observable observable2 = derivation.getDerivedValue();

    tracker.getDependencies().add( observable2 );
    observable2.getObservers().add( tracker );

    observable2.markAsPendingDeactivation();
    transaction.queueForDeactivation( observable2 );

    assertNotNull( transaction.getPendingDeactivations() );
    assertEquals( transaction.getPendingDeactivations().size(), 1 );
    assertEquals( observable2.isActive(), true );
    assertEquals( observable2.isPendingDeactivation(), true );

    transaction.safeGetObservables().add( observable1 );
    final ArrayList<Observable> dependencies = tracker.getDependencies();

    transaction.commit();

    // The next code block essentially verifies it calls completeTracking
    assertEquals( tracker.getState(), ObserverState.UP_TO_DATE );
    assertTrue( tracker.getDependencies() != dependencies );
    assertEquals( tracker.getDependencies().size(), 1 );
    assertEquals( tracker.getDependencies().contains( observable1 ), true );
    assertEquals( observable1.getWorkState(), Observable.NOT_IN_CURRENT_TRACKING );

    // This section essentially verifies processPendingDeactivations() is called
    assertEquals( observable2.isPendingDeactivation(), false );
    assertEquals( observable2.isActive(), false );
    assertEquals( observable2.getOwner(), derivation );
    assertEquals( derivation.getState(), ObserverState.INACTIVE );
  }

  @Test
  public void trackingCycleWithNoTracker()
  {
    final ArezContext context = new ArezContext();
    final Transaction transaction =
      new Transaction( context, null, ValueUtil.randomString(), TransactionMode.READ_ONLY, null );

    final Observable observable = new Observable( context, ValueUtil.randomString() );

    assertEquals( observable.getObservers().size(), 0 );
    assertEquals( transaction.getObservables(), null );

    //Transaction should perform no action during tracking if there is no associated tracker
    transaction.beginTracking();
    transaction.observe( observable );
    transaction.completeTracking();

    assertEquals( observable.getObservers().size(), 0 );
    assertEquals( transaction.getObservables(), null );
  }

  @Test
  public void beginTracking_firstTracking()
  {
    final ArezContext context = new ArezContext();
    final Observer tracker = newDerivation( context );
    final Transaction transaction =
      new Transaction( context, null, ValueUtil.randomString(), TransactionMode.READ_ONLY, tracker );
    context.setTransaction( transaction );
{'fraction_non_alphanumeric': 0.0981269683407923, 'fraction_numerical': 0.005138405436764462, 'mean_word_length': 4.391867739052725, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, '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': '1461419', 'n_tokens_mistral': 3095, 'n_tokens_neox': 2914, 'n_words': 787}