All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fj.test.Shrink Maven / Gradle / Ivy

package fj.test;

import fj.*;

import static fj.P.p;
import static fj.P.p2;
import static fj.P.p3;
import static fj.P.p4;
import static fj.P.p5;
import static fj.P.p6;
import static fj.P.p7;
import static fj.P.p8;

import static fj.Primitive.Byte_Long;
import static fj.Primitive.Character_Long;
import static fj.Primitive.Double_Long;
import static fj.Primitive.Float_Long;
import static fj.Primitive.Integer_Long;
import static fj.Primitive.Long_Byte;
import static fj.Primitive.Long_Character;
import static fj.Primitive.Long_Double;
import static fj.Primitive.Long_Float;
import static fj.Primitive.Long_Integer;
import static fj.Primitive.Long_Short;
import static fj.Primitive.Short_Long;
import static fj.data.Array.array;
import fj.data.Conversions;
import static fj.data.List.isNotEmpty_;
import fj.data.Array;
import fj.data.Either;
import fj.data.Java;
import fj.data.List;
import fj.data.Option;
import fj.data.Stream;

import static fj.data.Stream.cons;
import static fj.data.Stream.iterate;
import static fj.data.Stream.nil;

import static java.lang.System.arraycopy;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Properties;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
import java.util.WeakHashMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;

/**
 * Represents a shrinking strategy over the given type parameter if that type can be represented as
 * a tree structure. This is used in falsification to produce the smallest counter-example, rather
 * than the first counter-example.
 *
 * @version %build.number%
 */
public final class Shrink {
  private final F> f;

  private Shrink(final F> f) {
    this.f = f;
  }

  /**
   * Returns a shrink of the given argument.
   *
   * @param a The argument to shrink.
   * @return A shrink of the given argument.
   */
  public Stream shrink(final A a) {
    return f.f(a);
  }

  /**
   * Creates a shrink from this shrink and the given symmetric transformations.
   *
   * @param f A transformation from this shrink type to the new shrink type.
   * @param g A transformation from the new shrink type to this shrink type.
   * @return A shrink from this shrink and the given symmetric transformations.
   */
  public  Shrink map(final F f, final F g) {
    return shrink(b -> Shrink.this.f.f(g.f(b)).map(f));
  }


  /**
   * Constructs a shrink strategy from the given function that produces a tree of values given a
   * value.
   *
   * @param f A function that produces a tree of values given a value.
   * @return A shrink strategy from the given function that produces a tree of values given a
   *         value.
   */
  public static  Shrink shrink(final F> f) {
    return new Shrink(f);
  }

  /**
   * Returns a shrink strategy that cannot be reduced further.
   *
   * @return A shrink strategy that cannot be reduced further.
   */
  public static  Shrink empty() {
    return shrink(a -> nil());
  }

  /**
   * A shrink strategy for longs using 0 as the bottom of the shrink.
   */
  public static final Shrink shrinkLong = shrink(i -> {
    if (i == 0L)
      return nil();
    else {
      final Stream is = cons(0L, P.lazy(() -> iterate(x -> x / 2L, i).takeWhile(x2 -> x2 != 0L).map(x1 -> i - x1)));

      return i < 0L ? cons(-i, P.lazy(() -> is)) : is;
    }
  });

  /**
   * A shrink strategy for booleans using false as the bottom of the shrink.
   */
  public static final Shrink shrinkBoolean =
      shrink(Function.>constant(Stream.single(false)));

  /**
   * A shrink strategy for integers using 0 as the bottom of the shrink.
   */
  public static final Shrink shrinkInteger = shrinkLong.map(Long_Integer, Integer_Long);

  /**
   * A shrink strategy for bytes using 0 as the bottom of the shrink.
   */
  public static final Shrink shrinkByte = shrinkLong.map(Long_Byte, Byte_Long);

  /**
   * A shrink strategy for characters using 0 as the bottom of the shrink.
   */
  public static final Shrink shrinkCharacter = shrinkLong.map(Long_Character, Character_Long);

  /**
   * A shrink strategy for shorts using 0 as the bottom of the shrink.
   */
  public static final Shrink shrinkShort = shrinkLong.map(Long_Short, Short_Long);

  /**
   * A shrink strategy for floats using 0 as the bottom of the shrink.
   */
  public static final Shrink shrinkFloat = shrinkLong.map(Long_Float, Float_Long);

  /**
   * A shrink strategy for doubles using 0 as the bottom of the shrink.
   */
  public static final Shrink shrinkDouble = shrinkLong.map(Long_Double, Double_Long);

  /**
   * Returns a shrink strategy for optional values. A 'no value' is already fully
   * shrunk, otherwise, the shrinking occurs on the value with the given shrink strategy.
   *
   * @param sa The shrink strategy for the potential value.
   * @return A shrink strategy for optional values.
   */
  public static  Shrink> shrinkOption(final Shrink sa) {
    return shrink(o -> o.isNone() ?
           Stream.>nil() :
           cons(Option.none(), new P1>>() {
             public Stream> _1() {
               return sa.shrink(o.some()).map(Option.some_());
             }
           }));
  }

  /**
   * Returns a shrink strategy for either values.
   *
   * @param sa The shrinking strategy for left values.
   * @param sb The shrinking strategy for right values.
   * @return A shrink strategy for either values.
   */
  public static  Shrink> shrinkEither(final Shrink sa, final Shrink sb) {
    return shrink(e -> e.isLeft() ?
           sa.shrink(e.left().value()).map(Either.left_()) :
           sb.shrink(e.right().value()).map(Either.right_()));
  }

  /**
   * Returns a shrink strategy for lists. An empty list is fully shrunk.
   *
   * @param sa The shrink strategy for the elements of the list.
   * @return A shrink strategy for lists.
   */
  public static  Shrink> shrinkList(final Shrink sa) {
    final class Util {
      Stream> removeChunks(final int n, final List as) {
        if (as.isEmpty())
          return nil();
        else if (as.tail().isEmpty())
          return cons(List.nil(), Stream.>nil_());
        else {
          final int n1 = n / 2;
          final int n2 = n - n1;

          final List as1 = as.take(n1);
          final F, Boolean> isNotEmpty = isNotEmpty_();
          return cons(
                  as1,
                  P.lazy(() ->
                  {
                          final List as2 = as.drop(n1);
                          return cons(as2, P.lazy(() -> removeChunks(n1, as1)
                                                           .filter(isNotEmpty)
                                                           .map(aas1 -> aas1.append(as2))
                                                           .interleave(removeChunks(n2, as2)
                                                                   .filter(isNotEmpty)
                                                                   .map(aas -> as1.append(aas)))));
                  })
          );
        }
      }

      @SuppressWarnings({"IfMayBeConditional"})
      Stream> shrinkOne(final List as) {
        if (as.isEmpty())
          return nil();
        else
          return sa.shrink(as.head()).map(a -> as.tail().cons(a)).append(shrinkOne(as.tail()).map(aas -> aas.cons(as.head())));
      }
    }

    return shrink(as -> {
      final Util u = new Util();
      return u.removeChunks(as.length(), as).append(u.shrinkOne(as));
    });
  }

  /**
   * Returns a shrink strategy for arrays. An empty array is fully shrunk.
   *
   * @param sa The shrink strategy for the elements of the array.
   * @return A shrink strategy for arrays.
   */
  public static  Shrink> shrinkArray(final Shrink sa) {
    return shrinkList(sa).map(Conversions.List_Array(), Conversions.Array_List());
  }

  /**
   * Returns a shrink strategy for streams. An empty stream is fully shrunk.
   *
   * @param sa The shrink strategy for the elements of the stream.
   * @return A shrink strategy for streams.
   */
  public static  Shrink> shrinkStream(final Shrink sa) {
    return shrinkList(sa).map(Conversions.List_Stream(), Conversions.Stream_List());
  }

  /**
   * A shrink strategy for strings using the empty string as the bottom of the shrink.
   */
  public static final Shrink shrinkString =
      shrinkList(shrinkCharacter).map(Conversions.List_String, Conversions.String_List);

  /**
   * A shrink strategy for string buffers using the empty string as the bottom of the shrink.
   */
  public static final Shrink shrinkStringBuffer =
      shrinkList(shrinkCharacter).map(Conversions.List_StringBuffer, Conversions.StringBuffer_List);

  /**
   * A shrink strategy for string builders using the empty string as the bottom of the shrink.
   */
  public static final Shrink shrinkStringBuilder =
      shrinkList(shrinkCharacter).map(Conversions.List_StringBuilder, Conversions.StringBuilder_List);

  /**
   * A shrink strategy for throwables.
   *
   * @param ss A shrink strategy for throwable messages.
   * @return A shrink strategy for throwables.
   */
  public static Shrink shrinkThrowable(final Shrink ss) {
    return ss.map(s -> new Throwable(s), t -> t.getMessage());
  }

  /**
   * A shrink strategy for throwables.
   */
  public static final Shrink shrinkThrowable = shrinkThrowable(shrinkString);

  // BEGIN java.util

  /**
   * Returns a shrink strategy for array lists. An empty array list is fully shrunk.
   *
   * @param sa The shrink strategy for the elements of the array list.
   * @return A shrink strategy for array lists.
   */
  public static  Shrink> shrinkArrayList(final Shrink sa) {
    return shrinkList(sa).map(Java.List_ArrayList(), Java.ArrayList_List());
  }

  /**
   * A shrink strategy for bit sets.
   */
  public static final Shrink shrinkBitSet =
      shrinkList(shrinkBoolean).map(Java.List_BitSet, Java.BitSet_List);

  /**
   * A shrink strategy for calendars.
   */
  public static final Shrink shrinkCalendar =
      shrinkLong.map(i -> {
        final Calendar c = Calendar.getInstance();
        c.setTimeInMillis(i);
        return c;
      }, c -> c.getTime().getTime());

  /**
   * A shrink strategy for dates.
   */
  public static final Shrink shrinkDate =
      shrinkLong.map(i -> new Date(i), d -> d.getTime());

  /**
   * A shrink strategy for enum maps.
   *
   * @param sk The shrink strategy for keys.
   * @param sv The shrink stratgey for values.
   * @return A shrink strategy for enum maps.
   */
  public static , V> Shrink> shrinkEnumMap(final Shrink sk, final Shrink sv) {
    return shrinkHashtable(sk, sv).map(h -> new EnumMap(h), m -> new Hashtable(m));
  }

  /**
   * A shrink strategy for enum sets.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for enum sets.
   */
  public static > Shrink> shrinkEnumSet(final Shrink sa) {
    return shrinkList(sa).map(Java.List_EnumSet(), Java.EnumSet_List());
  }

  /**
   * A shrink strategy for gregorian calendars.
   */
  public static final Shrink shrinkGregorianCalendar =
      shrinkLong.map(i -> {
        final GregorianCalendar c = new GregorianCalendar();
        c.setTimeInMillis(i);
        return c;
      }, c -> c.getTime().getTime());

  /**
   * A shrink strategy for hash maps.
   *
   * @param sk The shrink strategy for keys.
   * @param sv The shrink stratgey for values.
   * @return A shrink strategy for hash maps.
   */
  public static  Shrink> shrinkHashMap(final Shrink sk, final Shrink sv) {
    return shrinkHashtable(sk, sv).map(h -> new HashMap(h), m -> new Hashtable(m));
  }

  /**
   * A shrink strategy for hash sets.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for hash sets.
   */
  public static  Shrink> shrinkHashSet(final Shrink sa) {
    return shrinkList(sa).map(Java.List_HashSet(), Java.HashSet_List());
  }

  /**
   * A shrink strategy for hash tables.
   *
   * @param sk The shrink strategy for keys.
   * @param sv The shrink stratgey for values.
   * @return A shrink strategy for hash tables.
   */
  @SuppressWarnings({"UseOfObsoleteCollectionType"})
  public static  Shrink> shrinkHashtable(final Shrink sk, final Shrink sv) {
    return shrinkList(shrinkP2(sk, sv)).map(kvs -> {
      final Hashtable h = new Hashtable();
      kvs.foreachDoEffect(kv -> h.put(kv._1(), kv._2()));
      return h;
    }, h -> {
      List> x = List.nil();

      for (final K k : h.keySet()) {
        x = x.snoc(p(k, h.get(k)));
      }

      return x;
    });
  }

  /**
   * A shrink strategy for identity hash maps.
   *
   * @param sk The shrink strategy for keys.
   * @param sv The shrink stratgey for values.
   * @return A shrink strategy for identity hash maps.
   */
  public static  Shrink> shrinkIdentityHashMap(final Shrink sk, final Shrink sv) {
    return shrinkHashtable(sk, sv).map(h -> new IdentityHashMap(h), m -> new Hashtable(m));
  }

  /**
   * A shrink strategy for linked hash maps.
   *
   * @param sk The shrink strategy for keys.
   * @param sv The shrink stratgey for values.
   * @return A shrink strategy for linked hash maps.
   */
  public static  Shrink> shrinkLinkedHashMap(final Shrink sk, final Shrink sv) {
    return shrinkHashtable(sk, sv).map(h -> new LinkedHashMap(h), m -> new Hashtable(m));
  }

  /**
   * A shrink strategy for linked hash sets.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for linked hash sets.
   */
  public static  Shrink> shrinkLinkedHashSet(final Shrink sa) {
    return shrinkList(sa).map(Java.List_LinkedHashSet(), Java.LinkedHashSet_List());
  }

  /**
   * A shrink strategy for linked lists.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for linked lists.
   */
  public static  Shrink> shrinkLinkedList(final Shrink sa) {
    return shrinkList(sa).map(Java.List_LinkedList(), Java.LinkedList_List());
  }

  /**
   * A shrink strategy for priority queues.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for priority queues.
   */
  public static  Shrink> shrinkPriorityQueue(final Shrink sa) {
    return shrinkList(sa).map(Java.List_PriorityQueue(), Java.PriorityQueue_List());
  }

  /**
   * A shrink strategy for properties.
   */
  public static final Shrink shrinkProperties = shrinkHashtable(shrinkString, shrinkString)
      .map(h -> {
        final Properties p = new Properties();

        for (final String k : h.keySet()) {
          p.setProperty(k, h.get(k));
        }

        return p;
      }, p -> {
        final Hashtable t = new Hashtable();

        for (final Object s : p.keySet()) {
          t.put((String) s, p.getProperty((String) s));
        }

        return t;
      });

  /**
   * A shrink strategy for stacks.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for stacks.
   */
  public static  Shrink> shrinkStack(final Shrink sa) {
    return shrinkList(sa).map(Java.List_Stack(), Java.Stack_List());
  }

  /**
   * A shrink strategy for tree maps.
   *
   * @param sk The shrink strategy for keys.
   * @param sv The shrink stratgey for values.
   * @return A shrink strategy for tree maps.
   */
  public static  Shrink> shrinkTreeMap(final Shrink sk, final Shrink sv) {
    return shrinkHashtable(sk, sv).map(h -> new TreeMap(h), m -> new Hashtable(m));
  }

  /**
   * A shrink strategy for tree sets.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for tree sets.
   */
  public static  Shrink> shrinkTreeSet(final Shrink sa) {
    return shrinkList(sa).map(Java.List_TreeSet(), Java.TreeSet_List());
  }

  /**
   * A shrink strategy for vectors.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for vectors.
   */
  public static  Shrink> shrinkVector(final Shrink sa) {
    return shrinkList(sa).map(Java.List_Vector(), Java.Vector_List());
  }

  /**
   * A shrink strategy for weak hash maps.
   *
   * @param sk The shrink strategy for keys.
   * @param sv The shrink stratgey for values.
   * @return A shrink strategy for weak hash maps.
   */
  public static  Shrink> shrinkWeakHashMap(final Shrink sk, final Shrink sv) {
    return shrinkHashtable(sk, sv).map(h -> new WeakHashMap(h), m -> new Hashtable(m));
  }

  // END java.util

  // BEGIN java.util.concurrent

  /**
   * A shrink strategy for array blocking queues.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for array blocking queues.
   */
  public static  Shrink> shrinkArrayBlockingQueue(final Shrink sa) {
    return shrinkList(sa).map(Java.List_ArrayBlockingQueue(false), Java.ArrayBlockingQueue_List());
  }

  /**
   * A shrink strategy for concurrent hash maps.
   *
   * @param sk The shrink strategy for keys.
   * @param sv The shrink stratgey for values.
   * @return A shrink strategy for concurrent hash maps.
   */
  public static  Shrink> shrinkConcurrentHashMap(final Shrink sk, final Shrink sv) {
    return shrinkHashtable(sk, sv).map(h -> new ConcurrentHashMap(h), m -> new Hashtable(m));
  }

  /**
   * A shrink strategy for concurrent linked queues.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for concurrent linked queues.
   */
  public static  Shrink> shrinkConcurrentLinkedQueue(final Shrink sa) {
    return shrinkList(sa).map(Java.List_ConcurrentLinkedQueue(), Java.ConcurrentLinkedQueue_List());
  }

  /**
   * A shrink strategy for copy on write array lists.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for copy on write array lists.
   */
  public static  Shrink> shrinkCopyOnWriteArrayList(final Shrink sa) {
    return shrinkList(sa).map(Java.List_CopyOnWriteArrayList(), Java.CopyOnWriteArrayList_List());
  }

  /**
   * A shrink strategy for copy on write array sets.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for copy on write array sets.
   */
  public static  Shrink> shrinkCopyOnWriteArraySet(final Shrink sa) {
    return shrinkList(sa).map(Java.List_CopyOnWriteArraySet(), Java.CopyOnWriteArraySet_List());
  }

  /**
   * A shrink strategy for delay queues.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for delay queues.
   */
  public static  Shrink> shrinkDelayQueue(final Shrink sa) {
    return shrinkList(sa).map(Java.List_DelayQueue(), Java.DelayQueue_List());
  }

  /**
   * A shrink strategy for linked blocking queues.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for linked blocking queues.
   */
  public static  Shrink> shrinkLinkedBlockingQueue(final Shrink sa) {
    return shrinkList(sa).map(Java.List_LinkedBlockingQueue(), Java.LinkedBlockingQueue_List());
  }

  /**
   * A shrink strategy for priority blocking queues.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for priority blocking queues.
   */
  public static  Shrink> shrinkPriorityBlockingQueue(final Shrink sa) {
    return shrinkList(sa).map(Java.List_PriorityBlockingQueue(), Java.PriorityBlockingQueue_List());
  }

  /**
   * A shrink strategy for synchronous queues.
   *
   * @param sa The shrink strategy for the elements.
   * @return A shrink strategy for synchronous queues.
   */
  public static  Shrink> shrinkSynchronousQueue(final Shrink sa) {
    return shrinkList(sa).map(Java.List_SynchronousQueue(false), Java.SynchronousQueue_List());
  }

  // END java.util.concurrent

  // BEGIN java.sql

  /**
   * A shrink strategy for SQL dates.
   */
  public static final Shrink shrinkSQLDate =
      shrinkLong.map(i -> new java.sql.Date(i), c -> c.getTime());

  /**
   * A shrink strategy for SQL times.
   */
  public static final Shrink Shrink> shrinkP1(final Shrink sa) {
    return shrink(p -> sa.shrink(p._1()).map(a -> p(a)));
  }

  /**
   * Returns a shrinking strategy for product-2 values.
   *
   * @param sa The shrinking strategy for the values.
   * @param sb The shrinking strategy for the values.
   * @return a shrinking strategy for product-2 values.
   */
  public static  Shrink> shrinkP2(final Shrink sa, final Shrink sb) {
    return shrink(p -> {
      final F>> p2 = p2();
      return sa.shrink(p._1()).bind(sb.shrink(p._2()), p2);
    });
  }

  /**
   * Returns a shrinking strategy for product-3 values.
   *
   * @param sa The shrinking strategy for the values.
   * @param sb The shrinking strategy for the values.
   * @param sc The shrinking strategy for the values.
   * @return a shrinking strategy for product-3 values.
   */
  public static  Shrink> shrinkP3(final Shrink sa, final Shrink sb, final Shrink sc) {
    return shrink(p -> {
      final F>>> p3 = p3();
      return sa.shrink(p._1()).bind(sb.shrink(p._2()), sc.shrink(p._3()), p3);
    });
  }

  /**
   * Returns a shrinking strategy for product-4 values.
   *
   * @param sa The shrinking strategy for the values.
   * @param sb The shrinking strategy for the values.
   * @param sc The shrinking strategy for the values.
   * @param sd The shrinking strategy for the values.
   * @return a shrinking strategy for product-4 values.
   */
  public static  Shrink> shrinkP4(final Shrink sa, final Shrink sb, final Shrink sc,
                                                             final Shrink sd) {
    return shrink(p -> {
      final F>>>> p4 = p4();
      return sa.shrink(p._1()).bind(sb.shrink(p._2()), sc.shrink(p._3()), sd.shrink(p._4()), p4);
    });
  }

  /**
   * Returns a shrinking strategy for product-5 values.
   *
   * @param sa The shrinking strategy for the values.
   * @param sb The shrinking strategy for the values.
   * @param sc The shrinking strategy for the values.
   * @param sd The shrinking strategy for the values.
   * @param se The shrinking strategy for the values.
   * @return a shrinking strategy for product-5 values.
   */
  public static  Shrink> shrinkP5(final Shrink sa, final Shrink sb,
                                                                   final Shrink sc, final Shrink sd,
                                                                   final Shrink se) {
    return shrink(p -> {
      final F>>>>> p5 = p5();
      return sa.shrink(p._1()).bind(sb.shrink(p._2()), sc.shrink(p._3()), sd.shrink(p._4()), se.shrink(p._5()), p5);
    });
  }

  /**
   * Returns a shrinking strategy for product-6 values.
   *
   * @param sa The shrinking strategy for the values.
   * @param sb The shrinking strategy for the values.
   * @param sc The shrinking strategy for the values.
   * @param sd The shrinking strategy for the values.
   * @param se The shrinking strategy for the values.
   * @param sf The shrinking strategy for the values.
   * @return a shrinking strategy for product-6 values.
   */
  public static  Shrink> shrinkP6(final Shrink sa, final Shrink sb,
                                                                           final Shrink sc, final Shrink sd,
                                                                           final Shrink se, final Shrink sf) {
    return shrink(p -> {
      final F>>>>>> p6 = p6();
      return sa.shrink(p._1())
          .bind(sb.shrink(p._2()), sc.shrink(p._3()), sd.shrink(p._4()), se.shrink(p._5()), sf.shrink(p._6()), p6);
    });
  }

  /**
   * Returns a shrinking strategy for product-7 values.
   *
   * @param sa The shrinking strategy for the values.
   * @param sb The shrinking strategy for the values.
   * @param sc The shrinking strategy for the values.
   * @param sd The shrinking strategy for the values.
   * @param se The shrinking strategy for the values.
   * @param sf The shrinking strategy for the values.
   * @param sg The shrinking strategy for the values.
   * @return a shrinking strategy for product-7 values.
   */
  public static  Shrink> shrinkP7(final Shrink sa, final Shrink sb,
                                                                                 final Shrink sc, final Shrink sd,
                                                                                 final Shrink se,
                                                                                 final Shrink sf,
                                                                                 final Shrink sg) {
    return shrink(p -> {
      final F>>>>>>> p7 = p7();
      return sa.shrink(p._1())
          .bind(sb.shrink(p._2()), sc.shrink(p._3()), sd.shrink(p._4()), se.shrink(p._5()), sf.shrink(p._6()),
                  sg.shrink(p._7()), p7);
    });
  }

  /**
   * Returns a shrinking strategy for product-8 values.
   *
   * @param sa The shrinking strategy for the values.
   * @param sb The shrinking strategy for the values.
   * @param sc The shrinking strategy for the values.
   * @param sd The shrinking strategy for the values.
   * @param se The shrinking strategy for the values.
   * @param sf The shrinking strategy for the values.
   * @param sg The shrinking strategy for the values.
   * @param sh The shrinking strategy for the values.
   * @return a shrinking strategy for product-8 values.
   */
  public static  Shrink> shrinkP8(final Shrink sa,
                                                                                       final Shrink sb,
                                                                                       final Shrink sc,
                                                                                       final Shrink sd,
                                                                                       final Shrink se,
                                                                                       final Shrink sf,
                                                                                       final Shrink sg,
                                                                                       final Shrink sh) {
    return shrink(
            p -> {
              final F>>>>>>>> p8 = p8();
              return sa.shrink(p._1())
                  .bind(sb.shrink(p._2()), sc.shrink(p._3()), sd.shrink(p._4()), se.shrink(p._5()), sf.shrink(p._6()),
                          sg.shrink(p._7()), sh.shrink(p._8()), p8);
            });
  }
}