package com.remondis.remap;

import static com.remondis.remap.AssertMapping.DIFFERENT_NULL_STRATEGY;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

import java.util.Arrays;
import java.util.List;

import org.junit.Test;

import com.remondis.remap.flatCollectionMapping.Destination;
import com.remondis.remap.flatCollectionMapping.Id;
import com.remondis.remap.flatCollectionMapping.Source;

/**
 * This class documents a currently impossible mapping from a build-in/primitive type to a Java Bean. It would be nice
 * to support this kinds of mappings in a future release.
 *
 * @author schuettec
 *
 */
public class FlatCollectionMapping {

  @Test
  public void shouldDetectIllegalArguments() {
    assertThatThrownBy(() -> {
      Mapping.from(Source.class)
          .to(Destination.class)
          .replaceCollection(null, Destination::getIds);
    }).isInstanceOf(IllegalArgumentException.class)
        .hasNoCause();

    assertThatThrownBy(() -> {
      Mapping.from(Source.class)
          .to(Destination.class)
          .replaceCollection(Source::getIds, null);
    }).isInstanceOf(IllegalArgumentException.class)
        .hasNoCause();

    assertThatThrownBy(() -> {
      Mapping.from(Source.class)
          .to(Destination.class)
          .replaceCollection(Source::getIds, Destination::getIds)
          .with(null);
    }).isInstanceOf(IllegalArgumentException.class)
        .hasNoCause();
  }

  @Test
  public void shouldMapCollectionByFunction() {
    Mapper<Source, Destination> mapper = Mapping.from(Source.class)
        .to(Destination.class)
        .replaceCollection(Source::getIds, Destination::getIds)
        .with(idBuilder())
        .mapper();

    Source source = Source.builder()
        .ids(Arrays.asList(1L, 2L, 3L))
        .build();
    Destination map = mapper.map(source);
    List<Id> expected = Arrays.asList(idBuilder().transform(1L), idBuilder().transform(2L), idBuilder().transform(3L));
    List<Id> actual = map.getIds();
    assertEquals(expected, actual);

    // Assert the mapping
    AssertMapping.of(mapper)
        .expectReplaceCollection(Source::getIds, Destination::getIds)
        .andTest(idBuilder())
        .ensure();
  }

  @Test
  public void shouldSkipNullItems() {
    Mapper<Source, Destination> mapper = Mapping.from(Source.class)
        .to(Destination.class)
        .replaceCollection(Source::getIds, Destination::getIds)
        .withSkipWhenNull(idBuilder())
        .mapper();

    Source source = Source.builder()
        .ids(Arrays.asList(1L, null, 2L, null, 3L))
        .build();
    Destination map = mapper.map(source);

    List<Id> expected = Arrays.asList(idBuilder().transform(1L), idBuilder().transform(2L), idBuilder().transform(3L));
    List<Id> actual = map.getIds();
    assertEquals(expected, actual);

    // Assert the mapping
    AssertMapping.of(mapper)
        .expectReplaceCollection(Source::getIds, Destination::getIds)
        .andTestButSkipWhenNull(idBuilder())
        .ensure();
  }

  @Test
  public void nullCollection() {
    Mapper<Source, Destination> mapper = Mapping.from(Source.class)
        .to(Destination.class)
        .replaceCollection(Source::getIds, Destination::getIds)
        .with(idBuilder())
        .mapper();

    Source source = Source.builder()
        .ids(null)
        .build();
    Destination map = mapper.map(source);
    assertNull(map.getIds());
  }

  @Test
  public void shouldDetectDifferentNullStrategy() {
    Mapper<Source, Destination> mapper = Mapping.from(Source.class)
        .to(Destination.class)
        .replaceCollection(Source::getIds, Destination::getIds)
        .with(idBuilder())
        .mapper();

    assertThatThrownBy(() -> {
      AssertMapping.of(mapper)
          .expectReplaceCollection(Source::getIds, Destination::getIds)
          .andTestButSkipWhenNull(idBuilder())
          .ensure();
    }).isInstanceOf(AssertionError.class)
        .hasMessageContaining(DIFFERENT_NULL_STRATEGY)
        .hasNoCause();
  }

  public static Transform<Id, Long> idBuilder() {
    return id -> Id.builder()
        .id(id)
        .build();
  }

}

@@ -2285,32 +2285,879 @@
 .ensure();%0A  %7D%0A%0A
+  @Test%0A  public void shouldNotSkipNullItems() %7B%0A    Mapper%3CSource, Destination%3E mapper = Mapping.from(Source.class)%0A        .to(Destination.class)%0A        .replaceCollection(Source::getIds, Destination::getIds)%0A        .with(idBuilder())%0A        .mapper();%0A%0A    Source source = Source.builder()%0A        .ids(Arrays.asList(1L, null, 2L, null, 3L))%0A        .build();%0A    Destination map = mapper.map(source);%0A%0A    List%3CId%3E expected = Arrays.asList(idBuilder().transform(1L), idBuilder().transform(null), idBuilder().transform(2L),%0A        idBuilder().transform(null), idBuilder().transform(3L));%0A    List%3CId%3E actual = map.getIds();%0A    assertEquals(expected, actual);%0A%0A    // Assert the mapping%0A    AssertMapping.of(mapper)%0A        .expectReplaceCollection(Source::getIds, Destination::getIds)%0A        .andTest(idBuilder())%0A        .ensure();%0A  %7D%0A%0A
   @Test%0A  public

Allow mapping of collections using an item transformation