package fr.umlv.conc;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import java.util.Optional;
import java.util.OptionalInt;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static fr.umlv.conc.AnyOpForkJoin.*;
import static org.junit.jupiter.api.Assertions.*;

public class AnyOpForkJoinTest {
  @Test @Tag("Q1")
  public void testAnyOpForkJoinIntSimple() {
    assertAll(
        () -> assertTrue(anyOpForkJoinInt(IntStream.empty(), (a, b) -> fail()).isEmpty()),
        () -> assertEquals(OptionalInt.of(42), anyOpForkJoinInt(IntStream.of(42), Integer::sum)),
        () -> assertEquals(OptionalInt.of(64), anyOpForkJoinInt(IntStream.of(56, 8), Integer::sum))
    );
  }
  @Test @Tag("Q1")
  public void testAnyOpForkJoinInt() {
    var stream = new Random(0).ints(1_000_000, 0, Integer.MAX_VALUE);
    assertEquals(665, anyOpForkJoinInt(stream, Math::min).orElseThrow());
  }
  @Test @Tag("Q1")
  public void testAnyOpForkJoinIntPrecondition() {
    assertAll(
        () -> assertThrows(NullPointerException.class, () -> anyOpForkJoinInt(null, Integer::sum)),
        () -> assertThrows(NullPointerException.class, () -> anyOpForkJoinInt(IntStream.empty(), null))
    );
  }


  @Test @Tag("Q2")
  public void testAnyOpForkJoinObjSimple() {
    assertAll(
        () -> assertTrue(anyOpForkJoinObj(Stream.empty(), (a, b) -> fail()).isEmpty()),
        () -> assertEquals(Optional.of(42), anyOpForkJoinObj(Stream.of(42), Integer::sum)),
        () -> assertEquals(Optional.of(64), anyOpForkJoinObj(Stream.of(56, 8), Integer::sum)),
        () -> assertEquals(Optional.of("foo"), anyOpForkJoinObj(Stream.of("foo"), String::concat)),
        () -> assertEquals(Optional.of("foobar"), anyOpForkJoinObj(Stream.of("foo", "bar"), String::concat))
    );
  }
  @Test @Tag("Q2")
  public void testAnyOpForkJoinObj() {
    var stream = new Random(0).ints(1_000_000, 0, Integer.MAX_VALUE).boxed();
    assertEquals(665, anyOpForkJoinObj(stream, Math::min).orElseThrow());
  }
  @Test @Tag("Q2")
  public void testAnyOpForkJoinObjPrecondition() {
    assertAll(
        () -> assertThrows(NullPointerException.class, () -> anyOpForkJoinObj(null, Integer::sum)),
        () -> assertThrows(NullPointerException.class, () -> anyOpForkJoinObj(Stream.empty(), null))
    );
  }
}