/*
* Copyright (c) 2022, Antonio Gabriel Muñoz Conejo <antoniogmc at gmail dot com>
* Distributed under the terms of the MIT License
*/
package com.github.tonivade.vavr.effect;
import static com.github.tonivade.vavr.effect.Unit.unit;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.time.Duration;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import io.vavr.Tuple2;
import io.vavr.collection.List;
import io.vavr.collection.Seq;
import io.vavr.control.Either;
@ExtendWith(MockitoExtension.class)
class ScheduleTest {
@Test
void repeat(@Mock Consumer<String> console) {
IO<Unit> print = IO.exec(() -> console.accept("hola"));
Schedule<Unit, Unit> schedule = Schedule.<Unit>recurs(2).zipRight(Schedule.identity());
IO<Unit> repeat = print.repeat(schedule);
Unit result = repeat.unsafeRunSync();
assertEquals(unit(), result);
verify(console, times(3)).accept("hola");
}
@Test
void repeatDelay(@Mock Consumer<String> console) {
IO<Unit> print = IO.exec(() -> console.accept("hola"));
Schedule<Unit, Unit> recurs = Schedule.<Unit>recurs(2).zipRight(Schedule.identity());
Schedule<Unit, Integer> spaced = Schedule.spaced(Duration.ofMillis(500));
Schedule<Unit, Unit> schedule = recurs.zipLeft(spaced);
IO<Unit> repeat = print.repeat(schedule);
IO<Tuple2<Duration, Unit>> timed = repeat.timed();
Tuple2<Duration, Unit> result = timed.unsafeRunSync();
assertTrue(result._1().toMillis() > 1000);
verify(console, times(3)).accept("hola");
}
@Test
void noRepeat(@Mock Consumer<String> console) {
IO<Unit> print = IO.exec(() -> console.accept("hola"));
IO<Unit> repeat = print.repeat(Schedule.never());
Unit result = repeat.unsafeRunSync();
assertEquals(unit(), result);
verify(console).accept("hola");
}
@Test
void retry(@Mock Supplier<String> console) {
when(console.get())
.thenThrow(RuntimeException.class)
.thenReturn("hola");
IO<String> read = IO.task(console::get);
IO<String> retry = read.retry(Schedule.recurs(1));
String provide = retry.unsafeRunSync();
assertEquals("hola", provide);
verify(console, times(2)).get();
}
@Test
void retryDelay(@Mock Supplier<String> console) {
when(console.get()).thenThrow(RuntimeException.class).thenReturn("hola");
IO<String> read = IO.task(console::get);
Schedule<Throwable, Integer> recurs = Schedule.recurs(2);
Schedule<Throwable, Integer> spaced = Schedule.spaced(Duration.ofMillis(500));
IO<Tuple2<Duration, String>> retry = read.retry(recurs.zip(spaced)).timed();
Tuple2<Duration, String> result = retry.unsafeRunSync();
assertTrue(result._1().toMillis() > 500);
assertEquals("hola", result._2());
verify(console, times(2)).get();
}
@Test
void noRetry(@Mock Supplier<String> console) {
when(console.get()).thenThrow(UnsupportedOperationException.class).thenReturn("hola");
IO<String> read = IO.task(console::get);
IO<String> retry = read.retry(Schedule.never());
assertThrows(UnsupportedOperationException.class, retry::unsafeRunSync);
}
@Test
void andThen(@Mock Consumer<String> console) {
Schedule<Unit, Integer> two =
Schedule.<Unit>recurs(1).andThen(Schedule.<Unit>recurs(1));
IO<Unit> print = IO.exec(() -> console.accept("hola"));
IO<Integer> repeat = print.repeat(two);
Integer provide = repeat.unsafeRunSync();
assertEquals(1, provide);
verify(console, times(3)).accept("hola");
}
@Test
@Disabled("I don't understand very well this")
void compose(@Mock Consumer<String> console) {
Schedule<Unit, Integer> two =
Schedule.<Unit>recurs(1).compose(Schedule.<Integer>recurs(1));
IO<Unit> print = IO.exec(() -> console.accept("hola"));
IO<Integer> repeat = print.repeat(two);
Integer provide = repeat.unsafeRunSync();
assertEquals(Either.right(1), provide);
verify(console, times(3)).accept("hola");
}
@Test
void collect() {
IO<Unit> pure = IO.unit();
Schedule<Unit, Seq<Integer>> schedule = Schedule.<Unit>recurs(5).collectAll().zipLeft(Schedule.identity());
IO<Seq<Integer>> repeat = pure.repeat(schedule);
Seq<Integer> result = repeat.unsafeRunSync();
assertEquals(List.of(0, 1, 2, 3, 4), result);
}
}