// This file was generated by Mendix Modeler.
//
// WARNING: Only the following code will be retained when actions are regenerated:
// - the import list
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
// Special characters, e.g., é, ö, à, etc. are supported in comments.

package databaseconnectortest.actions;

import static java.lang.String.format;
import static java.util.stream.Collectors.joining;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.apache.commons.io.IOUtils;
import com.mendix.systemwideinterfaces.core.IContext;
import com.mendix.systemwideinterfaces.core.IMendixObject;
import com.mendix.systemwideinterfaces.core.IMendixObjectMember;
import com.mendix.webui.CustomJavaAction;
import unittesting.proxies.microflows.Microflows;

public class AssertEqualsListEntityValues extends CustomJavaAction<Boolean>
{
	private java.util.List<IMendixObject> Expected;
	private java.util.List<IMendixObject> Actual;

	public AssertEqualsListEntityValues(IContext context, java.util.List<IMendixObject> Expected, java.util.List<IMendixObject> Actual)
	{
		super(context);
		this.Expected = Expected;
		this.Actual = Actual;
	}

	@Override
	public Boolean executeAction() throws Exception
	{
		// BEGIN USER CODE
	  Consumer<String> assertMessage = a ->
	    Microflows.assertTrue2(getContext(), false, "The values of some entities in both lists do not match.\n" + a);
	  Optional<String> notEqualMessage = compare(Expected, Actual);
	  notEqualMessage.ifPresent(assertMessage);

    return !notEqualMessage.isPresent();
		// END USER CODE
	}

	/**
	 * Returns a string representation of this action
	 */
	@Override
	public String toString()
	{
		return "AssertEqualsListEntityValues";
	}

	// BEGIN EXTRA CODE
  private Optional<String> compare(List<IMendixObject> expected, List<IMendixObject> actual) {
    if (expected.size() != actual.size())
      return Optional.of(format("The list of expected items contains %s items,"
          + " the list of actual items %s", expected.size(), actual.size()));

    IntStream range = IntStream.range(0, expected.size());
    IntFunction<Optional<String>> compare = a -> compare(a + 1, expected.get(a), actual.get(a));
    String message = range.mapToObj(compare).flatMap(messagesFilter).collect(joining("," + System.lineSeparator()));

    return isEmpty(message) ? Optional.empty() : Optional.of(message);
  }

  private Optional<String> compare(int objectNr, IMendixObject expected, IMendixObject actual) {
    Function<IMendixObjectMember<?>, Optional<String>> compare = a -> compare(a, actual.getMember(getContext(), a.getName()));
    Stream<Optional<String>> potentialMessages = expected.getPrimitives(getContext()).stream().map(compare);
    String message = potentialMessages.flatMap(messagesFilter).collect(joining(", "));

    return isEmpty(message) ? Optional.empty() : Optional.of(format("Row %s: ", objectNr) + message);
  }

  private Optional<String> compare(IMendixObjectMember<?> expected, IMendixObjectMember<?> actual) {
    Object expectedValue = toComparableValue(expected.getValue(getContext()));
    Object actualValue = toComparableValue(actual.getValue(getContext()));
    boolean isEqual;

    if (expectedValue instanceof byte[] && actualValue instanceof byte[])
      isEqual = Arrays.equals((byte[]) expectedValue, (byte[]) actualValue);
    else
      isEqual = expectedValue == null ? actualValue == null : expectedValue.equals(actualValue);

    return isEqual ? Optional.empty() : Optional.of(format("%s (%s != %s)", expected.getName(), expectedValue, actualValue));
  }

  /**
   * Convert the value to a comparable value, like InputStream to byte array.
   */
  private Object toComparableValue(Object value) {
    if (value instanceof InputStream) try {
      return IOUtils.toByteArray((InputStream) value);
    } catch (IOException e) {
      throw new RuntimeException(e);
    } catch (NullPointerException e) {
      // this will occur in some kind of InputStream where an underlying input stream is null.
      return null;
    }

    return value;
  }

  private Function<Optional<String>, Stream<String>> messagesFilter = a -> a.map(Stream::of).orElseGet(Stream::empty);
	// END EXTRA CODE
}

@@ -660,32 +660,62 @@
 o.InputStream;%0D%0A
+import java.math.BigDecimal;%0D%0A
 import java.util
@@ -720,24 +720,24 @@
 il.Arrays;%0D%0A
-
 import java.
@@ -1175,24 +1175,104 @@
 ectMember;%0D%0A
+import com.mendix.systemwideinterfaces.core.meta.IMetaPrimitive.PrimitiveType;%0D%0A
 import com.m
@@ -3182,68 +3182,321 @@
 e = 
-a -%3E compare(a, actual.getMember(getContext(), a.getName()))
+expectedMember -%3E %7B%0D%0A      PrimitiveType primitiveType = expected.getMetaObject().getMetaPrimitive(expectedMember.getName()).getType();%0D%0A      IMendixObjectMember%3C?%3E actualMember = actual.getMember(getContext(), expectedMember.getName());%0D%0A      return compare(primitiveType, expectedMember, actualMember);%0D%0A    %7D
 ;%0D%0A 
@@ -3839,16 +3839,45 @@
 compare(
+PrimitiveType primitiveType, 
 IMendixO
@@ -4141,188 +4141,291 @@
 lue 
-instanceof byte%5B%5D && actualValue instanceof byte%5B%5D)%0D%0A      isEqual = Arrays.equals((byte%5B%5D) expectedValue, (byte%5B%5D) actualValue);%0D%0A    else%0D%0A      isEqual = expectedValue == null ?
+!= null && actualValue != null) %7B%0D%0A      switch (primitiveType) %7B%0D%0A        case Binary:%0D%0A          isEqual = Arrays.equals((byte%5B%5D) expectedValue, (byte%5B%5D) actualValue);%0D%0A          break;%0D%0A        case Decimal:%0D%0A          isEqual = ((BigDecimal) expectedValue).compareTo((BigDecimal)
  act
@@ -4436,18 +4436,72 @@
 alue
+)
  == 
-null :
+0;%0D%0A          break;%0D%0A        default:%0D%0A          isEqual =
  exp
@@ -4528,24 +4528,108 @@
 tualValue);%0D
+%0A      %7D%0D%0A    %7D else%0D%0A      isEqual = expectedValue == null && actualValue == null;%0D
 %0A%0D%0A    retur

Improve BigDecimal equality check.