package pl.touk.throwing;

import org.junit.Test;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Optional;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static pl.touk.throwing.TestCommons.givenThrowingFunction;
import static pl.touk.throwing.ThrowingFunction.*;

public class ThrowingFunctionTest {

    @Test
    public void shouldCompose() throws Exception {
        // given
        final ThrowingFunction<Integer, Integer, Exception> f1 = i -> 2 * i;
        final ThrowingFunction<Integer, Integer, Exception> f2 = i -> i + 10;

        // when
        final Integer result = f1.compose(f2).apply(3);

        // then
        assertThat(result).isEqualTo(26);
    }


    @Test
    public void shouldAndThen() throws Exception {
        // given
        final ThrowingFunction<Integer, Integer, Exception> f1 = i -> 2 * i;
        final ThrowingFunction<Integer, Integer, Exception> f2 = i -> i + 10;

        // when
        final Integer result = f1.andThen(f2).apply(3);

        // then
        assertThat(result).isEqualTo(16);
    }

    @Test
    public void shouldReturnOptional() throws Exception {
        // given
        final ThrowingFunction<Integer, Integer, Exception> f1 = ThrowingFunction.identity();

        // when
        final Optional<Integer> result = f1.lift().apply(42);

        // then
        assertThat(result.isPresent()).isTrue();
    }

    @Test
    public void shouldReturnEmptyOptional() throws Exception {
        // given
        final ThrowingFunction<Integer, Integer, Exception> f1 = givenThrowingFunction();

        // when
        final Optional<Integer> result = f1.lift().apply(42);

        // then
        assertThat(result.isPresent()).isFalse();
    }

    @Test(expected = Exception.class)
    public void shouldThrowEx() throws Exception {
        // given
        final ThrowingFunction<Integer, Integer, Exception> f1 = givenThrowingFunction();

        // when
        f1.apply(42);

        // then RuntimeException is thrown
    }

    @Test(expected = RuntimeException.class)
    public void shouldWrapInRuntimeEx() throws Exception {
        // given
        final ThrowingFunction<Integer, Integer, Exception> f1 = givenThrowingFunction();

        // when
        f1.unchecked().apply(42);

        // then RuntimeException is thrown
    }

    @Test(expected = RuntimeException.class)
    public void shouldWrapInRuntimeExWhenUsingStandardUtilsFunctions() throws Exception {

        // when
        Stream.of(". .").map(unchecked(URI::new)).collect(toList());

        // then RuntimeException is thrown
    }

    @Test(expected = URISyntaxException.class)
    public void shouldUnwrapOriginalExceptionWhenUsingStandardUtilsFunctions() throws URISyntaxException {

        // when
        checked(URISyntaxException.class,
                () -> Stream.of(". .")
                .map(unchecked(URI::new))
                        .collect(toList())
        );

        // then a checked exception is thrown
    }

    @Test(expected = URISyntaxException.class)
    public void shouldUnwrapOriginalExceptionWithTryCatch() throws Throwable {

        // when
        ThrowingFunction.checked(() -> Stream.of(". .").map(unchecked(URI::new)).collect(toList()));

        // then a checked exception is thrown
    }

    @Test
    public void shouldWrapInOptionalWhenUsingStandardUtilsFunctions() throws Exception {

        // when
        final Long result = Stream.of(". .")
                .map(lifted(URI::new))
                .filter(Optional::isPresent)
                .count();

        //then
        assertThat(result).isZero();
    }
}
@@ -161,16 +161,67 @@
 tream;%0A%0A
+import static java.util.stream.Collectors.joining;%0A
 import s
@@ -2574,38 +2574,25 @@
 henUsing
-StandardUtilsFunctions
+Unchecked
 () throw
@@ -2734,32 +2734,362 @@
 s thrown%0A    %7D%0A%0A
+    @Test(expected = RuntimeException.class)%0A    public void shouldWrapInRuntimeExWhenUsingUncheck() throws Exception %7B%0A        //given%0A        ThrowingFunction%3CString, URI, Exception%3E f = URI::new;%0A%0A        // when%0A        Stream.of(%22. .%22).map(f.unchecked()).collect(toList());%0A%0A        // then RuntimeException is thrown%0A    %7D%0A%0A
     @Test(expect
@@ -3715,24 +3715,24 @@
 oList()));%0A%0A
-
         // t
@@ -3764,32 +3764,637 @@
 s thrown%0A    %7D%0A%0A
+    @Test(expected = URISyntaxException.class)%0A    public void shouldUnwrapSpecifiedExceptionWithTryCatch() throws Throwable %7B%0A%0A        // when%0A        ThrowingFunction.checked(URISyntaxException.class, () -%3E Stream.of(%22. .%22).map(unchecked(URI::new)).collect(toList()));%0A%0A        // then a checked exception is thrown%0A    %7D%0A%0A    @Test%0A    public void shouldApplyAfterUnwrapping() throws Throwable %7B%0A%0A        // when%0A        final String result = ThrowingFunction.checked(() -%3E Stream.of(%22a%22).map(String::toUpperCase).collect(joining()));%0A%0A        // then%0A        assertThat(result).isEqualTo(%22A%22);%0A    %7D%0A%0A
     @Test%0A    pu

Add additional tests