package toothpick.concurrency;

import java.util.ArrayList;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import toothpick.ToothPick;
import toothpick.concurrency.threads.AddNodeThread;
import toothpick.concurrency.threads.RemoveNodeThread;
import toothpick.concurrency.threads.TestableThread;

import static org.junit.Assert.assertTrue;
import static toothpick.concurrency.utils.ThreadTestUtil.STANDARD_THREAD_COUNT;

public class ScopeTreeManipulationsMultiThreadTest {

  static final String ROOT_SCOPE = "ROOT_SCOPE";

  @Before
  public void setUp() throws Exception {
    ToothPick.openScope(ROOT_SCOPE);
  }

  @After
  public void tearDown() throws Exception {
    ToothPick.reset();
  }

  @Test
  public void concurrentScopeAdditions_shouldNotCrash() throws InterruptedException {
    //GIVEN
    final int addNodeThreadCount = STANDARD_THREAD_COUNT;
    List<TestableThread> threadList = new ArrayList<>();

    //WHEN
    for (int indexThread = 0; indexThread < addNodeThreadCount; indexThread++) {
      AddNodeThread addNodeThread = new AddNodeThread(ROOT_SCOPE);
      threadList.add(addNodeThread);
      addNodeThread.start();
    }

    //THEN
    //we simply should not have crashed when all threads are done
    for (TestableThread thread : threadList) {
      thread.join();
      assertTrue(String.format("test of thread %s failed", thread.getName()), thread.isSuccessful());
    }
  }

  @Test
  public void concurrentScopeRemovals_shouldNotCrash() throws InterruptedException {
    //GIVEN
    final int removalNodeThreadCount = STANDARD_THREAD_COUNT;
    List<TestableThread> threadList = new ArrayList<>();

    //WHEN
    for (int indexThread = 0; indexThread < removalNodeThreadCount; indexThread++) {
      RemoveNodeThread removeNodeThread = new RemoveNodeThread(ROOT_SCOPE);
      threadList.add(removeNodeThread);
      removeNodeThread.start();
    }

    //THEN
    //we simply should not have crashed when all threads are done
    for (TestableThread thread : threadList) {
      thread.join();
      assertTrue(String.format("test of thread %s failed", thread.getName()), thread.isSuccessful());
    }
  }
}

@@ -72,24 +72,49 @@
 .util.List;%0A
+import java.util.Random;%0A
 import org.j
@@ -1944,32 +1944,1036 @@
 start();%0A    %7D%0A%0A
+    //THEN%0A    //we simply should not have crashed when all threads are done%0A    for (TestableThread thread : threadList) %7B%0A      thread.join();%0A      assertTrue(String.format(%22test of thread %25s failed%22, thread.getName()), thread.isSuccessful());%0A    %7D%0A  %7D%0A%0A  @Test%0A  public void concurrentScopeAdditionsAndRemovals_shouldNotCrash() throws InterruptedException %7B%0A    //GIVEN%0A    final int removalNodeThreadCount = STANDARD_THREAD_COUNT;%0A    final int addNodeThreadCount = STANDARD_THREAD_COUNT;%0A    List%3CTestableThread%3E threadList = new ArrayList%3C%3E();%0A    final Random random = new Random();%0A%0A    //WHEN%0A    for (int indexThread = 0; indexThread %3C addNodeThreadCount + removalNodeThreadCount; indexThread++) %7B%0A      final TestableThread testableThread;%0A      if (random.nextInt(100) %3C 50) %7B%0A        testableThread = new RemoveNodeThread(ROOT_SCOPE);%0A      %7D else %7B%0A        testableThread = new AddNodeThread(ROOT_SCOPE);%0A      %7D%0A      threadList.add(testableThread);%0A      testableThread.start();%0A    %7D%0A%0A
     //THEN%0A    /

add test