@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullMatrix() {
    rewriteMatrix.rewrite(null);
}

public void rewrite(int[][] matrix) {
    validateInput(matrix);
    Set<Integer> rowsToSkip = new HashSet<Integer>();
    Set<Integer> columnsToSkip = new HashSet<Integer>();
    for (int i = 0; i < matrix.length; i++) {
        for (int j = 0; j < matrix[i].length; j++) {
            if (shouldPaintRowAndColumn(matrix, i, j, rowsToSkip, columnsToSkip)) {
                rewriteRow(matrix, i, rowsToSkip);
                rewriteColumn(matrix, j, columnsToSkip);
            }
        }
    }
}

@Test
public void shouldRewritePositionsEvenWithAOneDimensionMatrix() {
    int[][] matrix = { { 1, 0 }, {} };
    rewriteMatrix.rewrite(matrix);
    int[][] expectedMatrix = { { 0, 0 }, {} };
    assertArrayEquals(expectedMatrix, matrix);
}

@Test
public void hsouldRewriteJustCenterRowAndCoulmnWithZeros() {
    int[][] matrix = { { 1, 1, 1 }, { 1, 0, 1 }, { 1, 1, 1 } };
    rewriteMatrix.rewrite(matrix);
    int[][] expectedMatrix = { { 1, 0, 1 }, { 0, 0, 0 }, { 1, 0, 1 } };
    assertArrayEquals(expectedMatrix, matrix);
}

@Test
public void shouldNotRewritePositionsWithNonZeroElements() {
    int[][] matrix = { { 1, 1 }, { 1, 1 } };
    rewriteMatrix.rewrite(matrix);
    int[][] expectedMatrix = { { 1, 1 }, { 1, 1 } };
    assertArrayEquals(expectedMatrix, matrix);
}

@Test
public void shouldRewriteRowAndColumnsWithZeros() {
    int[][] matrix = { { 1, 1, 0 }, { 1, 0, 1 }, { 1, 1, 1 } };
    rewriteMatrix.rewrite(matrix);
    int[][] expectedMatrix = { { 0, 0, 0 }, { 0, 0, 0 }, { 1, 0, 0 } };
    assertArrayEquals(expectedMatrix, matrix);
}


@Test
public void shouldReturnLastNodeIfPositionIsZero2() {
    ListNode result = findElement.find2(new ListNode<Integer>(1), 0);
    ListNode<Integer> expectedNode = new ListNode<Integer>(1);
    assertEquals(expectedNode, result);
}

public ListNode find2(ListNode listNode, int k) {
    validateInput(listNode, k);
    int size = calculateListSize(listNode);
    if (k > (size - 1)) {
        throw new IndexOutOfBoundsException();
    }
    ListNode result = listNode;
    int n = size - 1 - k;
    while (n > 0) {
        result = result.getNext();
        n--;
    }
    return result;
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullListNodes2() {
    findElement.find2(null, 4);
}

@Test
public void shouldReturnKthToLastElement2() {
    ListNode<Integer> list = createList(new int[] { 1, 2, 3 });
    ListNode result = findElement.find2(list, 1);
    ListNode<Integer> expectedNode = new ListNode<Integer>(2);
    assertEquals(expectedNode, result);
}

@Test
public void shouldReturnFirstElementIfPositionIsEqualsToListSizeMinusOne2() {
    ListNode<Integer> list = createList(new int[] { 1, 2, 3 });
    ListNode result = findElement.find2(list, 2);
    ListNode<Integer> expectedNode = new ListNode<Integer>(1);
    assertEquals(expectedNode, result);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNegativePositions2() {
    findElement.find2(new ListNode<Integer>(3), -1);
}

@Test(expected = IndexOutOfBoundsException.class)
public void shouldNotAcceptPositionsGreaterThanListSize2() {
    findElement.find2(new ListNode<Integer>(3), 2);
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNegativePositions3() {
    findElement.find3(new ListNode<Integer>(3), -1);
}

public ListNode find3(ListNode listNode, int k) {
    validateInput(listNode, k);
    ListNode pointer2 = listNode;
    for (int i = 0; i <= k; i++) {
        if (pointer2 == null) {
            throw new IndexOutOfBoundsException();
        }
        pointer2 = pointer2.getNext();
    }
    ListNode result = listNode;
    while (pointer2 != null) {
        result = result.getNext();
        pointer2 = pointer2.getNext();
    }
    return result;
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullListNodes3() {
    findElement.find3(null, 4);
}

@Test
public void shouldReturnLastNodeIfPositionIsZero3() {
    ListNode result = findElement.find3(new ListNode<Integer>(1), 0);
    ListNode<Integer> expectedNode = new ListNode<Integer>(1);
    assertEquals(expectedNode, result);
}

@Test
public void shouldReturnKthToLastElement3() {
    ListNode<Integer> list = createList(new int[] { 1, 2, 3 });
    ListNode result = findElement.find3(list, 1);
    ListNode<Integer> expectedNode = new ListNode<Integer>(2);
    assertEquals(expectedNode, result);
}

@Test
public void shouldReturnFirstElementIfPositionIsEqualsToListSizeMinusOne3() {
    ListNode<Integer> list = createList(new int[] { 1, 2, 3 });
    ListNode result = findElement.find3(list, 2);
    ListNode<Integer> expectedNode = new ListNode<Integer>(1);
    assertEquals(expectedNode, result);
}

@Test(expected = IndexOutOfBoundsException.class)
public void shouldNotAcceptPositionsGreaterThanListSize3() {
    findElement.find3(new ListNode<Integer>(3), 2);
}


@Test
public void shouldReturnTheSameStringIfTheInputStringContainsJustOneChar() {
    String result = reverseString.reverse("a");
    assertEquals("a", result);
}

public String reverse(String input) {
    validateInput(input);
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = input.length() - 1; i >= 0; i--) {
        stringBuilder.append(input.charAt(i));
    }
    return stringBuilder.toString();
}

@Test
public void shouldReturnAnEmptyStringIfTheInputIsEmpty() {
    String result = reverseString.reverse("");
    assertEquals("", result);
}

@Test
public void shouldReverseString() {
    String result = reverseString.reverse("Pedro");
    assertEquals("ordeP", result);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullStrings() {
    reverseString.reverse(null);
}


@Test
public void shouldPaintSelectedZoneUsingIndicatedColor() {
    int[][] picture = { { 1, 1, 1, 1 }, { 1, 0, 0, 1 }, { 1, 0, 0, 1 }, { 1, 1, 1, 1 } };
    int colorToReplace = 0;
    int colorToPaint = 1;
    int x = 1;
    int y = 1;
    floodFill.apply(picture, colorToReplace, colorToPaint, x, y);
    int[][] expectedResult = { { 1, 1, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 1, 1 } };
    assertArrayEquals(expectedResult, picture);
}

public void apply(int[][] picture, int colorToReplace, int colorToPaint, int x, int y) {
    validatePicture(picture);
    int currentColor = getValueAt(picture, x, y);
    if (currentColor == colorToReplace) {
        picture[x][y] = colorToPaint;
        apply(picture, colorToReplace, colorToPaint, x + 1, y);
        apply(picture, colorToReplace, colorToPaint, x - 1, y);
        apply(picture, colorToReplace, colorToPaint, x, y + 1);
        apply(picture, colorToReplace, colorToPaint, x, y - 1);
    }
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullInstances() {
    floodFill.apply(null, 0, 1, 0, 0);
}

@Test
public void shouldNotModifyIfStartPaintingInOnePixelWithTheColorToPaint() {
    int[][] picture = { { 1, 1, 1, 1 }, { 1, 0, 0, 1 }, { 1, 0, 0, 1 }, { 1, 1, 1, 1 } };
    int colorToReplace = 0;
    int colorToPaint = 1;
    int x = 0;
    int y = 0;
    floodFill.apply(picture, colorToReplace, colorToPaint, x, y);
    int[][] expectedResult = { { 1, 1, 1, 1 }, { 1, 0, 0, 1 }, { 1, 0, 0, 1 }, { 1, 1, 1, 1 } };
    assertArrayEquals(expectedResult, picture);
}


@Test
public void shouldCalculatePath() {
    String finalPath = pathCalculator.calculate("/usr/bin/mail", "../../../etc/xyz", "../abc");
    assertEquals("/etc/abc/", finalPath);
}

public String calculate(String absolute, String r1, String r2) {
    if (absolute == null || r1 == null || r2 == null) {
        throw new IllegalArgumentException("You can't pass null strings as input.");
    }
    String[] absolutePath = absolute.split(DIR_SEPARATOR);
    String[] r1Path = r1.split(DIR_SEPARATOR);
    String[] r2Path = r2.split(DIR_SEPARATOR);
    String[] result = calculatePath(absolutePath, r1Path, r2Path);
    StringBuilder stringBuilder = new StringBuilder(DIR_SEPARATOR);
    for (String dir : result) {
        stringBuilder.append(dir);
        stringBuilder.append("/");
    }
    return stringBuilder.toString();
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullPaths() {
    pathCalculator.calculate(null, null, null);
}


@Test
public void shouldMergeBinaryNumbersUsingPointers() {
    int n = 1024;
    int m = 19;
    int result = mergeBinaryNumbers.merge(n, m, 2, 6);
    int expectedResult = 1100;
    assertEquals(expectedResult, result);
}

public int merge(int n, int m, int i, int j) {
    int maskFullOfOnes = ~0;
    int fullOfOnesBeforeJ = maskFullOfOnes << (j + 1);
    int fullOfOnesAfterI = ((1 << i) - 1);
    int allOnesExceptIandJ = fullOfOnesBeforeJ | fullOfOnesAfterI;
    int clearBitsBetweenIandJ = n & allOnesExceptIandJ;
    int moveMToTheCorrectPosition = m << i;
    return clearBitsBetweenIandJ | moveMToTheCorrectPosition;
}


@Test
public void shouldReturnOneIfInputIsTwo() {
    int input = 2;
    int result = reverseBinaryNumber.reverse(input);
    assertEquals(1, result);
}

public int reverse(int input) {
    int result = 1;
    do {
        result <<= 1;
        result |= (input & 1) == 1 ? 0 : 1;
        input >>= 1;
    } while (input != 0);
    result = reverseBitsOrder(result);
    result = removeFirstOne(result);
    return result;
}

@Test
public void shouldReturnTheReverseBinaryNumber() {
    int input = 11;
    int result = reverseBinaryNumber.reverse(input);
    assertEquals(4, result);
}

@Test
public void shouldReturnZeroIfInputIsOne() {
    int input = 1;
    int result = reverseBinaryNumber.reverse(input);
    assertEquals(0, result);
}

@Test
public void shouldReturnZeroIfInputIsFullOfOnes() {
    int input = 63;
    int result = reverseBinaryNumber.reverse(input);
    assertEquals(0, result);
}

@Test
public void shouldReturnOneIfInputIsZero() {
    int input = 0;
    int result = reverseBinaryNumber.reverse(input);
    assertEquals(1, result);
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullWordsToSearchInTheMatrix() {
    wordSearch.contains(new char[0][0], null);
}

public boolean contains(char[][] wordSearch, String word) {
    validateInputData(wordSearch, word);
    for (int i = 0; i < wordSearch.length; i++) {
        for (int j = 0; j < wordSearch[i].length; j++) {
            if (matches(wordSearch, i, j, word.charAt(0))) {
                if (isWordInWordSearchInner(wordSearch, word, i, j)) {
                    return true;
                }
            }
        }
    }
    return false;
}

@Test
public void shouldReturnFalseIfWordSearchIsEmpty() {
    char[][] matrix = { { 'a', 'a', 'c', 'd', 'e' }, { 'a', 'd', 'a', 'r', 'c' }, { 'a', 'd', 'a', 'c', 'c' }, { 'b', 'a', 'c', 'o', 'o' } };
    boolean result = wordSearch.contains(matrix, "pedro");
    assertFalse(result);
}

@Test
public void shouldReturnTrueIfWordToSearchIsInsideWordSearch() {
    char[][] matrix = { { 'a', 'a', 'c', 'd', 'e' }, { 'a', 'd', 'a', 'r', 'c' }, { 'a', 'd', 'a', 'c', 'c' }, { 'b', 'a', 'c', 'o', 'o' } };
    boolean result = wordSearch.contains(matrix, "baco");
    assertTrue(result);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullWordSearch() {
    wordSearch.contains(null, "word");
}


@Test
public void shouldReturnFalseIfTreeIsNotBalanced() {
    BinaryNode<Integer> root = new BinaryNode<Integer>(0);
    BinaryNode<Integer> n1 = new BinaryNode<Integer>(1);
    BinaryNode<Integer> n2 = new BinaryNode<Integer>(2);
    BinaryNode<Integer> n3 = new BinaryNode<Integer>(3);
    BinaryNode<Integer> n4 = new BinaryNode<Integer>(4);
    root.setLeft(n1);
    root.setRight(n2);
    n1.setLeft(n3);
    n3.setLeft(n4);
    boolean isBalanced = isTreeBalanced.check(root);
    assertFalse(isBalanced);
}

public boolean check(BinaryNode root) {
    if (root == null) {
        return true;
    } else {
        int heightDifference = getRootHeight(root.getLeft()) - getRootHeight(root.getRight());
        return Math.abs(heightDifference) <= 1;
    }
}

@Test
public void shouldReturnTrueIfTreeIsBalanced() {
    BinaryNode<Integer> root = new BinaryNode<Integer>(0);
    BinaryNode<Integer> n1 = new BinaryNode<Integer>(1);
    BinaryNode<Integer> n2 = new BinaryNode<Integer>(2);
    BinaryNode<Integer> n3 = new BinaryNode<Integer>(3);
    BinaryNode<Integer> n4 = new BinaryNode<Integer>(4);
    root.setLeft(n1);
    root.setRight(n2);
    n1.setLeft(n3);
    n2.setRight(n4);
    boolean isBalanced = isTreeBalanced.check(root);
    assertTrue(isBalanced);
}

@Test
public void shouldReturnTrueIfTreeIsNull() {
    boolean isBalanced = isTreeBalanced.check(null);
    assertTrue(isBalanced);
}


@Test
public void shouldRemoveDuplicatedElements2() {
    ListNode<Integer> head = createList(new Integer[] { 0, 1, 0, 2, 2, 3, 4, 4 });
    removeDuplicates.remove2(head);
    assertListContainsElements(new Integer[] { 0, 1, 2, 3, 4 }, head);
}

public void remove2(ListNode<Integer> head) {
    validateInput(head);
    ListNode<Integer> node = head;
    while (node != null) {
        removeNextNodesWithValue(node);
        node = node.getNext();
    }
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullInstancesAsParameter2() {
    removeDuplicates.remove2(null);
}

@Test
public void shouldNotModifyListIfThereAreNotDuplicatedElements2() {
    ListNode<Integer> head = createList(new Integer[] { 0, 1, 2, 3, 4 });
    removeDuplicates.remove2(head);
    assertListContainsElements(new Integer[] { 0, 1, 2, 3, 4 }, head);
}


@Test
public void shouldTakeIntoAccountNegativeNumbers() {
    String number = "-9.18E+09";
    long result = cientificNotation.calculate(number);
    assertEquals(-9180000000L, result);
}

public long calculate(String number) {
    if (number == null || number.indexOf("E") == -1) {
        throw new IllegalArgumentException("Invalid format for number " + number);
    }
    String[] splittedNumber = number.split("E");
    double first = Double.parseDouble(splittedNumber[0]);
    int sign = splittedNumber[1].charAt(0) == '+' ? 1 : -1;
    int pow = Integer.parseInt(splittedNumber[1].substring(1, splittedNumber[1].length()));
    Double result = sign * first * Math.pow(10, pow);
    return result.longValue();
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullStringAsInput() {
    cientificNotation.calculate(null);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptMalformedScientificNumbers() {
    cientificNotation.calculate("9.18F+09");
}

@Test
public void shouldReturnTheValueOfTheNumber() {
    String number = "9.18E+09";
    long result = cientificNotation.calculate(number);
    assertEquals(9180000000L, result);
}


@Test
public void shouldReturnFalseButReturnsTrue() {
    assertTrue(autoBoxingTrick.compare(1, 1));
}

public boolean compare(Integer n1, Integer n2) {
    return n1 == n2;
}

@Test
public void shouldReturnFalseAndReturnsFalse() {
    assertFalse(autoBoxingTrick.compare(1000, 1000));
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullTrees() {
    avlTreeMedian.find(null);
}

public double find(BinaryNode<Integer> root) {
    if (root == null) {
        throw new IllegalArgumentException("You can't pass a null binary tree to this method.");
    }
    List<BinaryNode<Integer>> sortedElements = binaryTreeInOrder.getIterative(root);
    double median = 0;
    if (sortedElements.size() % 2 == 0) {
        median = (sortedElements.get(sortedElements.size() / 2).getData() + sortedElements.get(sortedElements.size() / 2 - 1).getData()) / 2;
    } else {
        median = sortedElements.get(sortedElements.size() / 2).getData();
    }
    return median;
}

@Test
public void shouldReturnRootElementIfTheTreeContainsTFiveElements() {
    BinaryNode<Integer> root = new BinaryNode<Integer>(2);
    BinaryNode<Integer> n1 = new BinaryNode<Integer>(1);
    BinaryNode<Integer> n3 = new BinaryNode<Integer>(3);
    BinaryNode<Integer> n4 = new BinaryNode<Integer>(4);
    BinaryNode<Integer> n5 = new BinaryNode<Integer>(-1);
    root.setLeft(n1);
    root.setRight(n3);
    n3.setRight(n4);
    n1.setLeft(n5);
    double median = avlTreeMedian.find(root);
    assertEquals(2, median, DELTA);
}

@Test
public void shouldReturnRootElementIfTheTreeContainsJustOneElement() {
    BinaryNode<Integer> root = new BinaryNode<Integer>(1);
    double median = avlTreeMedian.find(root);
    assertEquals(1, median, DELTA);
}

@Test
public void shouldFindMedianWithAnOddNumberOfElements() {
    BinaryNode<Integer> root = new BinaryNode<Integer>(50);
    BinaryNode<Integer> n17 = new BinaryNode<Integer>(17);
    BinaryNode<Integer> n76 = new BinaryNode<Integer>(76);
    BinaryNode<Integer> n9 = new BinaryNode<Integer>(9);
    BinaryNode<Integer> n14 = new BinaryNode<Integer>(14);
    BinaryNode<Integer> n23 = new BinaryNode<Integer>(23);
    BinaryNode<Integer> n54 = new BinaryNode<Integer>(54);
    BinaryNode<Integer> n72 = new BinaryNode<Integer>(72);
    BinaryNode<Integer> n90 = new BinaryNode<Integer>(90);
    BinaryNode<Integer> n89 = new BinaryNode<Integer>(89);
    BinaryNode<Integer> n91 = new BinaryNode<Integer>(91);
    root.setLeft(n17);
    root.setRight(n76);
    n17.setLeft(n9);
    n9.setRight(n14);
    n17.setRight(n23);
    n76.setLeft(n54);
    n54.setRight(n72);
    n76.setRight(n90);
    n90.setLeft(n89);
    n90.setRight(n91);
    double median = avlTreeMedian.find(root);
    assertEquals(54, median, DELTA);
}

@Test
public void shouldFindMedianWithAEvenNumberOfElements() {
    BinaryNode<Integer> root = new BinaryNode<Integer>(50);
    BinaryNode<Integer> n17 = new BinaryNode<Integer>(17);
    BinaryNode<Integer> n76 = new BinaryNode<Integer>(76);
    BinaryNode<Integer> n9 = new BinaryNode<Integer>(9);
    BinaryNode<Integer> n14 = new BinaryNode<Integer>(14);
    BinaryNode<Integer> n23 = new BinaryNode<Integer>(23);
    BinaryNode<Integer> n54 = new BinaryNode<Integer>(54);
    BinaryNode<Integer> n72 = new BinaryNode<Integer>(72);
    BinaryNode<Integer> n90 = new BinaryNode<Integer>(90);
    BinaryNode<Integer> n89 = new BinaryNode<Integer>(89);
    BinaryNode<Integer> n91 = new BinaryNode<Integer>(91);
    BinaryNode<Integer> n92 = new BinaryNode<Integer>(93);
    root.setLeft(n17);
    root.setRight(n76);
    n17.setLeft(n9);
    n9.setRight(n14);
    n17.setRight(n23);
    n76.setLeft(n54);
    n54.setRight(n72);
    n76.setRight(n90);
    n90.setLeft(n89);
    n90.setRight(n91);
    n91.setRight(n92);
    double median = avlTreeMedian.find(root);
    assertEquals(63, median, DELTA);
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullListAsInputIterative() {
    palindromeList.checkIterative(null);
}

public boolean checkIterative(ListNode list) {
    validateInput(list);
    Stack<ListNode> stack = new Stack<ListNode>();
    ListNode fastPointer = list;
    ListNode slowPointer = list;
    while (fastPointer != null && fastPointer.getNext() != null) {
        stack.add(slowPointer);
        slowPointer = slowPointer.getNext();
        fastPointer = fastPointer.getNext().getNext();
    }
    if (fastPointer != null) {
        slowPointer = slowPointer.getNext();
    }
    boolean isPalindrome = true;
    while (slowPointer != null) {
        if (!stack.pop().equals(slowPointer)) {
            isPalindrome = false;
            break;
        }
        slowPointer = slowPointer.getNext();
    }
    return isPalindrome;
}

@Test
public void shouldReturnFalseIfListIsNotPalindromeIterative() {
    ListNode<Integer> list = createList(new int[] { 1, 1, 3 });
    boolean result = palindromeList.checkIterative(list);
    assertFalse(result);
}

@Test
public void shouldReturnTrueIfListIsPalindromeIterative() {
    ListNode<Integer> list = createList(new int[] { 1, 2, 1 });
    boolean result = palindromeList.checkIterative(list);
    assertTrue(result);
}

@Test
public void shouldReturnTrueIfListContainsJustOneNodeIterative() {
    ListNode<Integer> list = new ListNode<Integer>(1);
    boolean result = palindromeList.checkIterative(list);
    assertTrue(result);
}

@Test
public void shouldRturnTrueIfListContainsTwoElementsWithTheSameValueIterative() {
    ListNode<Integer> list = createList(new int[] { 1, 1 });
    boolean result = palindromeList.checkIterative(list);
    assertTrue(result);
}


@Test
public void shouldReturnZeroIfThereIsNoAnyConsecutiveSequenceIterative() {
    int[] array = { 6, 5, 4, 3, 2, 1 };
    int sequenceLength = lcs.findIterative(array);
    assertEquals(0, sequenceLength);
}

public int findIterative(int[] numbers) {
    if (numbers == null) {
        throw new IllegalArgumentException("You can't pass a null array as input.");
    }
    if (numbers.length == 0) {
        return 0;
    }
    int result = 0;
    int start = 0, end = 0;
    for (int i = 1; i < numbers.length; i++) {
        if (numbers[i - 1] < numbers[i]) {
            end = i;
        } else {
            start = i;
        }
        if (end - start > result) {
            result = end - start;
        }
    }
    return result + 1;
}

public int findIterative(int[] numbers) {
    if (numbers == null) {
        throw new IllegalArgumentException("You can't pass a null array as input.");
    }
    if (numbers.length == 0) {
        return 0;
    }
    boolean consecutiveSequenceFound = false;
    int result = 0;
    int start = 0, end = 0;
    for (int i = 1; i < numbers.length; i++) {
        if (numbers[i - 1] < numbers[i]) {
            end = i;
        } else {
            start = i;
        }
        if (end - start > result) {
            consecutiveSequenceFound = true;
            result = end - start;
        }
    }
    if (consecutiveSequenceFound) {
        return result + 1;
    } else {
        return result;
    }
}


@Test
public void shouldReturnFalseIfOneWordIsEmptyAndTheOtherNo() {
    assertFalse(areAnagrams.check("", "pedro"));
}

public boolean check(String a, String b) {
    if (a == null || b == null) {
        throw new IllegalArgumentException("You can't use null Strings as input.");
    }
    if (a.length() != b.length()) {
        return false;
    }
    int[] lettersA = getLettersAsArray(a);
    int[] lettersB = getLettersAsArray(b);
    int valuesA = getSumOfArray(lettersA);
    int valuesB = getSumOfArray(lettersB);
    return valuesA == valuesB;
}

@Test
public void shouldReturnTrueIfBothWordsAreEmpty() {
    assertTrue(areAnagrams.check("", ""));
}

@Test
public void shouldReturnTrueIfWordsAreAnagrams() {
    assertTrue(areAnagrams.check("ana", "naa"));
}

@Test
public void shouldReturnFalseIfWordsAreNotAnagrams() {
    assertFalse(areAnagrams.check("ana", "pedro"));
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullStringsAsInput() {
    areAnagrams.check(null, null);
}


@Test
public void shouldNotCompressEmptyWords() {
    String wordToCompress = "";
    String result = compressString.compress(wordToCompress);
    assertEquals("", result);
}

public String compress(String src) {
    validateInput(src);
    if (src.isEmpty() || src.length() == 1) {
        return src;
    }
    StringBuilder stringBuilder = new StringBuilder();
    int repeatedCharCounter = 1;
    char previousChar = src.charAt(0);
    for (int i = 1; i < src.length(); i++) {
        char currentChar = src.charAt(i);
        if (currentChar != previousChar) {
            stringBuilder.append(previousChar);
            if (repeatedCharCounter > 1) {
                stringBuilder.append(repeatedCharCounter);
                repeatedCharCounter = 1;
            }
            previousChar = currentChar;
        } else {
            repeatedCharCounter++;
        }
    }
    if (repeatedCharCounter > 1) {
        stringBuilder.append(previousChar);
        stringBuilder.append(repeatedCharCounter);
    }
    return stringBuilder.toString();
}

@Test
public void shouldNotCompressWordsWithJustOneChar() {
    String wordToCompress = "a";
    String result = compressString.compress(wordToCompress);
    assertEquals("a", result);
}

@Test
public void shouldCompressWordsFullOfTheSameChars() {
    String wordToCompress = "aaa";
    String result = compressString.compress(wordToCompress);
    assertEquals("a3", result);
}

@Test
public void shouldCompressWords() {
    String wordToCompress = "aabcccccaaa";
    String result = compressString.compress(wordToCompress);
    assertEquals("a2bc5a3", result);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullStringsAsInput() {
    compressString.compress(null);
}


@Test
public void shouldReturnAnEmptyStringIfTheInputIsEmptyIterative() {
    String result = reverseString.reverseIterative("");
    assertEquals("", result);
}

public String reverseIterative(String input) {
    validateInput(input);
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = input.length() - 1; i >= 0; i--) {
        stringBuilder.append(input.charAt(i));
    }
    return stringBuilder.toString();
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullStringsIterative() {
    reverseString.reverseIterative(null);
}

@Test
public void shouldReturnTheSameStringIfTheInputStringContainsJustOneCharIterative() {
    String result = reverseString.reverseIterative("a");
    assertEquals("a", result);
}

@Test
public void shouldReverseStringIterative() {
    String result = reverseString.reverseIterative("Pedro");
    assertEquals("ordeP", result);
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullListInstances() {
    getTheElementInTheMiddleOfTheList.get(null);
}

public ListNode<Integer> get(ListNode<Integer> list) {
    validateInput(list);
    int size = getListSize(list);
    int middleElementPosition = size % 2 != 0 ? size / 2 : (size / 2) - 1;
    ListNode middleElement = list;
    for (int i = 0; i < middleElementPosition; i++) {
        middleElement = middleElement.getNext();
    }
    return middleElement;
}


@Test
public void shouldReturnTheElementInTheMiddleOfAListWithAnEvenNumberOfElements2() {
    ListNode<Integer> list = createList(new int[] { 1, 2, 3 });
    ListNode<Integer> middleElement = getTheElementInTheMiddleOfTheList.get2(list);
    assertEquals(Integer.valueOf(2), middleElement.getData());
}

public ListNode<Integer> get2(ListNode<Integer> list) {
    validateInput(list);
    ListNode<Integer> currentNode = list;
    ListNode<Integer> fastNode = list.getNext();
    while (fastNode != null && fastNode.getNext() != null) {
        currentNode = currentNode.getNext();
        fastNode = fastNode.getNext().getNext();
    }
    return currentNode;
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullListInstances2() {
    getTheElementInTheMiddleOfTheList.get2(null);
}

@Test
public void shouldReturnTheElementInTheMiddleOfTheListWithAnOddNumberOfElements2() {
    ListNode<Integer> list = createList(new int[] { 1, 2, 3, 4 });
    ListNode<Integer> middleElement = getTheElementInTheMiddleOfTheList.get2(list);
    assertEquals(Integer.valueOf(2), middleElement.getData());
}


@Test
public void shouldReturnMinElementInTheStack1EvenAfterModifyStackContent() {
    stack1.push(1);
    stack1.push(2);
    stack1.push(3);
    stack1.push(-1);
    stack1.pop();
    assertEquals(1, stack1.getMin());
}

public int getMin() {
    if (isEmpty()) {
        return Integer.MAX_VALUE;
    } else {
        return peek().minValue;
    }
}

@Test
public void shouldReturnMinElementInTheStack2EvenAfterModifyStackContent() {
    stack2.push(1);
    stack2.push(2);
    stack2.push(3);
    stack2.push(-1);
    stack2.pop();
    assertEquals(1, stack2.getMin());
}

public int getMin() {
    if (innerStack.isEmpty()) {
        return Integer.MAX_VALUE;
    } else {
        return innerStack.peek();
    }
}

@Test
public void shouldReturnMinElementInTheStack2() {
    stack2.push(1);
    stack2.push(2);
    stack2.push(3);
    stack2.push(-1);
    assertEquals(-1, stack2.getMin());
}

@Test
public void shouldReturnMinElementInTheStack1() {
    stack1.push(1);
    stack1.push(2);
    stack1.push(3);
    stack1.push(-1);
    assertEquals(-1, stack1.getMin());
}


@Test
public void shouldReturnFalseIfInputStringContainsDuplicatedChars2() {
    assertFalse(uniqueChars.evaluate2("vicente"));
}

public boolean evaluate2(String input) {
    validateInput(input);
    int[] chars = new int[256];
    for (char c : input.toCharArray()) {
        if (chars[c] >= 1) {
            return false;
        } else {
            chars[c]++;
        }
    }
    return true;
}

@Test
public void shouldReturnTrueIfInputStringDoesNotContainDuplicatedChars2() {
    assertTrue(uniqueChars.evaluate2("pedro"));
}

@Test
public void shouldReturnTrueIfInputStringIsEmpty2() {
    assertTrue(uniqueChars.evaluate2(""));
}

@Test
public void shouldReturnTrueIfInputStringContainsDuplicatedChars() {
    assertFalse(uniqueChars.evaluate("vicente"));
}

public boolean evaluate(String input) {
    validateInput(input);
    Map<String, Integer> chars = countCharAppearances(input);
    return containsDuplicatedChars(chars);
}

public boolean evaluate(String input) {
    validateInput(input);
    Map<String, Integer> chars = countCharAppearances(input);
    return !containsDuplicatedChars(chars);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullStringsAsInput2() {
    uniqueChars.evaluate2(null);
}


@Test
public void shouldReturnBinaryNumberOrder() {
    int input = 13;
    int result = reverseOrder.reverse(input);
    assertEquals(11, result);
}

public int reverse(int number) {
    int result = 0;
    while (number != 0) {
        result <<= 1;
        result |= number & 1;
        number >>= 1;
    }
    return result;
}

@Test
public void shouldReturnTheSameNumberIfIsFullOfOnes() {
    int input = 7;
    int result = reverseOrder.reverse(input);
    assertEquals(7, result);
}

@Test
public void shouldReturnOneIfInputIsOne() {
    int input = 1;
    int result = reverseOrder.reverse(input);
    assertEquals(1, result);
}

@Test
public void shouldReturnZeroIfInputIsZero() {
    int input = 0;
    int result = reverseOrder.reverse(input);
    assertEquals(0, result);
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNegativeValuesAsInputValue() {
    returnChange.calculate(new int[0], -7);
}

public List<Integer> calculate(int[] moneys, int billAmount) {
    validateInputData(moneys, billAmount);
    List<Integer> change = new LinkedList<Integer>();
    while (billAmount > 0 && moneys.length > 0) {
        for (int i = moneys.length - 1; i >= 0; i--) {
            if (billAmount - moneys[i] >= 0) {
                change.add(moneys[i]);
                billAmount -= moneys[i];
                break;
            }
        }
    }
    return change;
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptZeroAsInputValue() {
    returnChange.calculate(new int[0], 0);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullArrayOfMoneys() {
    returnChange.calculate(null, 7);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptEmptyArrayOfMoneys() {
    returnChange.calculate(new int[0], 7);
}


@Test
public void shouldReturnFalseIfDoesNotMatchUsingAsterisk() {
    String input = "aaa";
    String regularExpression = "b*";
    boolean result = simpleRegularExpression.evaluate(input, regularExpression);
    assertFalse(result);
}

public boolean evaluate(String source, String pattern) {
    if (source == null || pattern == null) {
        throw new IllegalArgumentException("You can't pass a null strings as input");
    }
    if (pattern.length() == 0)
        return source.length() == 0;
    if (pattern.length() == 1 || pattern.charAt(1) != '*') {
        if (source.length() < 1 || (pattern.charAt(0) != '.' && source.charAt(0) != pattern.charAt(0))) {
            return false;
        }
        return evaluate(source.substring(1), pattern.substring(1));
    } else {
        int len = source.length();
        int i = -1;
        while (i < len && (i < 0 || pattern.charAt(0) == '.' || pattern.charAt(0) == source.charAt(i))) {
            if (evaluate(source.substring(i + 1), pattern.substring(2)))
                return true;
            i++;
        }
        return false;
    }
}

@Test
public void shouldReturnTrueIfInputMatchesAndDoesNotContainKeyElements() {
    String input = "aaa";
    String regularExpression = "aaa";
    boolean result = simpleRegularExpression.evaluate(input, regularExpression);
    assertTrue(result);
}

@Test
public void shouldReturnTrueIfMatchesUsingAsteriskAndDot() {
    String input = "aaa";
    String regularExpression = ".a*";
    boolean result = simpleRegularExpression.evaluate(input, regularExpression);
    assertTrue(result);
}

@Test
public void shouldReturnFalseIfInputDoesNotMatchesAndDoesNotContainKeyElements() {
    String input = "aaa";
    String regularExpression = "a";
    boolean result = simpleRegularExpression.evaluate(input, regularExpression);
    assertFalse(result);
}

@Test
public void shouldReturnFalseIfDoesNotMatchUsingAsteriskAndDot() {
    String input = "aaa";
    String regularExpression = ".b*";
    boolean result = simpleRegularExpression.evaluate(input, regularExpression);
    assertFalse(result);
}

@Test
public void shouldReturnTrueIfMatchesUsingDot() {
    String input = "aa";
    String regularExpression = "a.";
    boolean result = simpleRegularExpression.evaluate(input, regularExpression);
    assertTrue(result);
}

@Test
public void shouldReturnFalseIfDoesNotMatchUsingDot() {
    String input = "aaa";
    String regularExpression = "a.";
    boolean result = simpleRegularExpression.evaluate(input, regularExpression);
    assertFalse(result);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullStringsAsInput() {
    simpleRegularExpression.evaluate(null, null);
}

@Test
public void shouldReturnTrueIfMatchesUsingAsterisk() {
    String input = "aaa";
    String regularExpression = "a*";
    boolean result = simpleRegularExpression.evaluate(input, regularExpression);
    assertTrue(result);
}


@Test
public void shouldFindLongestConsecutiveSequenceRecursive() {
    int[] array = { 1, 3, 4, 5, 64, 4, 5, 6, 7, 8, 9, 98, -1, -2 };
    int sequenceLength = lcs.findRecursive(array);
    assertEquals(7, sequenceLength);
}

public int findRecursive(int[] array) {
    validateInput(array);
    return findRecursiveInner(array, 1, 0, 0);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullArraysRecursive() {
    lcs.findRecursive(null);
}

@Test
public void shouldReturnZeroIfThereIsNoAnyConsecutiveSequenceRecursive() {
    int[] array = { 6, 5, 4, 3, 2, 1 };
    int sequenceLength = lcs.findRecursive(array);
    assertEquals(0, sequenceLength);
}

@Test
public void shouldReturnLengthArrayIfTheArrayIsOneConsecutiveSequenceRecursive() {
    int[] array = { 1, 2, 3, 4, 5, 6 };
    int sequenceLength = lcs.findRecursive(array);
    assertEquals(6, sequenceLength);
}

@Test
public void shouldReturnZeroIfTheArrayIsEmptyRecursive() {
    int[] array = {};
    int sequenceLength = lcs.findRecursive(array);
    assertEquals(0, sequenceLength);
}


@Test
public void shouldFindLongestConsecutiveSequenceRecursiveSupportingEqualsConsecutiveNumbers() {
    int[] array = { 1, 1, 1, 1, 3, 4, 5, 64, 4, 5, 6, 7, 8, 9, 98, -1, -2 };
    int sequenceLength = lcs.findRecursive(array);
    assertEquals(7, sequenceLength);
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullStrings() {
    anagrams.get(null);
}

public List<String> get(String input) {
    List<String> result = null;
    if (input == null) {
        throw new IllegalArgumentException("You can't pass a null String as input.");
    } else if (input.isEmpty()) {
        result = new LinkedList<String>();
    } else {
        result = getAnagramsInner("", input);
    }
    return result;
}

@Test
public void shouldCalculateEveryAnagram() {
    String input = "abc";
    List<String> result = anagrams.get(input);
    String[] arrayResult = new String[result.size()];
    result.toArray(arrayResult);
    String[] expectedArray = { "abc", "acb", "bac", "bca", "cab", "cba" };
    assertArrayEquals(expectedArray, arrayResult);
}

@Test
public void shouldReturnAnEmptyListIfInputStringIsEmpty() {
    assertTrue(anagrams.get("").isEmpty());
}


@Test
public void shouldReturnLengthArrayIfTheArrayIsOneConsecutiveSequence() {
    int[] array = { 1, 3, 4, 5, 64, 4, 5, 6, 7, 8, 9, 98, -1, -2 };
    int sequenceLength = lcs.find(array);
    assertEquals(7, sequenceLength);
}

public int find(int[] numbers) {
    if (numbers == null) {
        throw new IllegalArgumentException("You can't pass a null array as input.");
    }
    if (numbers.length == 0) {
        return 0;
    }
    int result = 0;
    int start = 0, end = 0;
    for (int i = 1; i < numbers.length; i++) {
        if (numbers[i - 1] < numbers[i]) {
            end = i;
        } else {
            start = i;
        }
        if (end - start > result) {
            result = end - start;
        }
    }
    return result + 1;
}

@Test
public void shouldReturnZeroIfTheArrayIsEmpty() {
    int[] array = {};
    int sequenceLength = lcs.find(array);
    assertEquals(0, sequenceLength);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullArrays() {
    lcs.find(null);
}

@Test
public void shouldReturnZeroIfThereIsNoAnyConsecutiveSequence() {
    int[] array = { 1, 2, 3, 4, 5, 6 };
    int sequenceLength = lcs.find(array);
    assertEquals(6, sequenceLength);
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullArrays() {
    multiplyArrayElements.multiply(null);
}

public int[] multiply(int[] input) {
    if (input == null) {
        throw new IllegalArgumentException("You can't pass a null array as input.");
    }
    if (input.length == 0) {
        return input;
    }
    int[] front = new int[input.length];
    int[] rear = new int[input.length];
    int[] output = new int[input.length];
    front[0] = 1;
    rear[input.length - 1] = 1;
    for (int i = 1; i < input.length; i++) {
        front[i] = front[i - 1] * input[i - 1];
    }
    for (int i = input.length - 2; i >= 0; i--) {
        rear[i] = rear[i + 1] * input[i + 1];
    }
    for (int i = 0; i < input.length; i++) {
        output[i] = front[i] * rear[i];
    }
    return output;
}

@Test
public void shouldDoNothingIfTheArrayWithJustOneElement() {
    int[] array = { 1 };
    int[] result = multiplyArrayElements.multiply(array);
    int[] expected = { 1 };
    assertArrayEquals(expected, result);
}

@Test
public void shouldMultiplyEveryElementByTheRest() {
    int[] array = { 1, 2, 3 };
    int[] result = multiplyArrayElements.multiply(array);
    int[] expected = { 6, 3, 2 };
    assertArrayEquals(expected, result);
}

@Test
public void shouldSupportEmptyArrays() {
    int[] array = new int[0];
    int[] result = multiplyArrayElements.multiply(array);
    assertEquals(0, result.length);
}


@Test
public void shouldReturnListWithTreeElementsByLevel() {
    BinaryNode<Integer> root = new BinaryNode<Integer>(0);
    BinaryNode<Integer> n1 = new BinaryNode<Integer>(1);
    BinaryNode<Integer> n2 = new BinaryNode<Integer>(2);
    BinaryNode<Integer> n3 = new BinaryNode<Integer>(3);
    root.setLeft(n1);
    root.setRight(n2);
    n1.setLeft(n3);
    List<BinaryNode> result = toList.transform(root);
    assertEquals(4, result.size());
    assertEquals(root, result.get(0));
    assertEquals(n1, result.get(1));
    assertEquals(n2, result.get(2));
    assertEquals(n3, result.get(3));
}

public List<BinaryNode> transform(BinaryNode tree) {
    if (tree == null) {
        return Collections.EMPTY_LIST;
    }
    List<BinaryNode> nodesByLevel = new LinkedList<BinaryNode>();
    Queue<BinaryNode> stack = new LinkedList<BinaryNode>();
    stack.add(tree);
    while (!stack.isEmpty()) {
        BinaryNode node = stack.remove();
        nodesByLevel.add(node);
        if (node.getLeft() != null) {
            stack.add(node.getLeft());
        }
        if (node.getRight() != null) {
            stack.add(node.getRight());
        }
    }
    return nodesByLevel;
}

@Test
public void shouldReturnEmptyListIfTreeIsNull() {
    List<BinaryNode> result = toList.transform(null);
    assertTrue(result.isEmpty());
}

@Test
public void shouldReturnListWithJustOneNodeIfTreeContainsJustOneNode() {
    BinaryNode<Integer> root = new BinaryNode<Integer>(0);
    List<BinaryNode> result = toList.transform(root);
    assertEquals(1, result.size());
    assertTrue(result.contains(root));
}


@Test(expected = IndexOutOfBoundsException.class)
public void shouldNotAcceptPositionsGreaterThanListSize() {
    findElement.find(new ListNode<Integer>(3), 2);
}

public ListNode find(ListNode listNode, int k) {
    validateInput(listNode, k);
    ListNode reversedList = reverseLinkedList.reverseIterative(listNode);
    ListNode result = reversedList;
    while (k > 0) {
        result = result.getNext();
        if (result == null) {
            throw new IndexOutOfBoundsException();
        }
        k--;
    }
    return result;
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNegativePositions() {
    findElement.find(new ListNode<Integer>(3), -1);
}

@Test
public void shouldReturnLastNodeIfPositionIsZero() {
    ListNode result = findElement.find(new ListNode<Integer>(1), 0);
    ListNode<Integer> expectedNode = new ListNode<Integer>(1);
    assertEquals(expectedNode, result);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullListNodes() {
    findElement.find(null, 4);
}


@Test
public void shouldReplaceAllTheContentIfTheArrayIsFullOfSpaces2() {
    char[] input = new char[6];
    input[0] = ' ';
    input[1] = ' ';
    replaceSpaces.replace2(input);
    assertArrayEquals(new char[] { '%', '2', '0', '%', '2', '0' }, input);
}

public void replace2(char[] input) {
    validateInput(input);
    int i = getLastCharPosition(input);
    for (int j = input.length - 1; i >= 0 && j >= 0; i--, j--) {
        if (input[i] == ' ') {
            input[j--] = '0';
            input[j--] = '2';
            input[j] = '%';
        } else {
            input[j] = input[i];
        }
    }
}

@Test
public void shouldReplaceSpacesWithTheStatementCharWithJustOneSpaceAtTheEndOfTheContent2() {
    char[] input = new char[8];
    input[0] = 'p';
    input[1] = 'e';
    input[2] = 'd';
    input[3] = 'r';
    input[4] = 'o';
    input[5] = ' ';
    replaceSpaces.replace2(input);
    assertArrayEquals(new char[] { 'p', 'e', 'd', 'r', 'o', '%', '2', '0' }, input);
}

@Test
public void shouldReplaceSpacesWithTheStatementCharWithMoreThanOneSpace2() {
    char[] input = new char[13];
    input[0] = 'p';
    input[1] = 'e';
    input[2] = ' ';
    input[3] = 'd';
    input[4] = 'r';
    input[5] = 'o';
    input[6] = ' ';
    input[7] = 'g';
    input[8] = 's';
    replaceSpaces.replace2(input);
    assertArrayEquals(new char[] { 'p', 'e', '%', '2', '0', 'd', 'r', 'o', '%', '2', '0', 'g', 's' }, input);
}

@Test
public void shouldReplaceSpacesWithTheStatementCharWithJustOneSpace2() {
    char[] input = new char[8];
    input[0] = 'p';
    input[1] = 'e';
    input[2] = ' ';
    input[3] = 'd';
    input[4] = 'r';
    input[5] = 'o';
    replaceSpaces.replace2(input);
    assertArrayEquals(new char[] { 'p', 'e', '%', '2', '0', 'd', 'r', 'o' }, input);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullArrays2() {
    replaceSpaces.replace2(null);
}


public int[] go(int[][] matrix) {
    if (matrix == null) {
        throw new IllegalArgumentException("You can't pass a null insantece as input.");
    }
    if (matrix.length == 0) {
        return new int[0];
    }
    int m = matrix.length;
    int n = matrix[0].length;
    int resultIndex = 0;
    int[] result = new int[m * n];
    int x = 0;
    int y = 0;
    while (m > 0 && n > 0) {
        if (m == 1) {
            for (int i = 0; i < n; i++) {
                result[resultIndex++] = matrix[x][y];
                y++;
            }
            break;
        } else if (n == 1) {
            for (int i = 0; i < m; i++) {
                result[resultIndex++] = matrix[x][y];
                x++;
            }
            break;
        }
        for (int i = 0; i < n - 1; i++) {
            result[resultIndex++] = matrix[x][y];
            y++;
        }
        for (int i = 0; i < m - 1; i++) {
            result[resultIndex++] = matrix[x][y];
            x++;
        }
        for (int i = 0; i < n - 1; i++) {
            result[resultIndex++] = matrix[x][y];
            y--;
        }
        for (int i = 0; i < m - 1; i++) {
            result[resultIndex++] = matrix[x][y];
            x--;
        }
        x++;
        y++;
        m = m - 2;
        n = n - 2;
    }
    return result;
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullInstancesAsInput() {
    goThroughMatrixInSpiral.go(null);
}

@Test
public void shouldReturnEmptyArrayIfMatrixIsEmpty() {
    int[][] matrix = {};
    int[] result = goThroughMatrixInSpiral.go(matrix);
    assertEquals(0, result.length);
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullListAsSecondParameterReverse() {
    sumLists.sumReverse(new ListNode<Integer>(0), null);
}

public int sumReverse(ListNode<Integer> n1, ListNode<Integer> n2) {
    validateInput(n1, n2);
    int n1Value = calculateReverseNumber(n1);
    int n2Value = calculateReverseNumber(n2);
    return n1Value + n2Value;
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullListAsFirstParameterReverse() {
    sumLists.sumReverse(null, new ListNode<Integer>(0));
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptAnEmtpyMatrix() {
    int[][] matrix = new int[0][0];
    rotateMatrix.rotate(matrix);
}

public void rotate(int[][] matrix) {
    validateInput(matrix);
    int length = matrix.length;
    for (int i = 0; i < length / 2; ++i) {
        int first = i;
        int last = length - 1 - i;
        for (int j = first; j < last; ++j) {
            int offset = j - first;
            int top = matrix[first][j];
            moveLeftToTop(matrix, first, last, j, offset);
            moveBottomToLeft(matrix, first, last, offset);
            moveRithToBottom(matrix, last, j, offset);
            moveTopToRight(matrix, last, j, top);
        }
    }
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptMatrixWithDifferentHeightAndWidth() {
    int[][] matrix = new int[6][3];
    rotateMatrix.rotate(matrix);
}

@Test
public void shouldRotateMatrix() {
    int[][] matrix = { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 } };
    rotateMatrix.rotate(matrix);
    int[][] expectedResult = { { 6, 3, 0 }, { 7, 4, 1 }, { 8, 5, 2 } };
    assertArrayEquals(expectedResult, matrix);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullMatrix() {
    rotateMatrix.rotate(null);
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptEmptyArrays() {
    findMissingNumber.find(new int[0]);
}

public int find(int[] numbers) {
    validateInput(numbers);
    int length = numbers.length;
    int idealSum = length * (length + 1) / 2;
    int sum = calculateSum(numbers);
    int missingNumber = idealSum - sum;
    return missingNumber;
}

@Test
public void shouldFindMissingNumber() {
    int[] numbers = { 0, 1, 2, 4 };
    int missingNumber = findMissingNumber.find(numbers);
    assertEquals(3, missingNumber);
}

@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullInstances() {
    findMissingNumber.find(null);
}


@Test(expected = IllegalArgumentException.class)
public void shouldNotAcceptNullLists() {
    partitionList.split(null, 1);
}

public ListNode<Integer> split(ListNode<Integer> list, int x) {
    validateInput(list);
    ListNode<Integer> before = null;
    ListNode<Integer> after = null;
    while (list != null) {
        ListNode<Integer> next = list.getNext();
        if (list.getData() < x) {
            list.setNext(before);
            before = list;
        } else {
            list.setNext(after);
            after = list;
        }
        list = next;
    }
    if (before == null) {
        return after;
    }
    ListNode<Integer> result = mergeLists(before, after);
    return result;
}


@Test
void compareSnapshotVersion() {
    assertTrue(versionManager.compareVersions("1.1.0", "1.0.0-SNAPSHOT") > 0);
    assertTrue(versionManager.compareVersions("1.1.0", "1.2.0-SNAPSHOT") < 0);
    assertTrue(versionManager.compareVersions("1.0.0-SNAPSHOT", "1.1.0-SNAPSHOT") < 0);
    assertEquals(0, versionManager.compareVersions("1.0.0-SNAPSHOT", "1.0.0-SNAPSHOT"));
}

@Override
public int compareVersions(String v1, String v2) {
    return Version.valueOf(v1).compareTo(Version.valueOf(v2));
}

@Override
public int compareVersions(String v1, String v2) {
    return Version.parse(v1).compareTo(Version.parse(v2));
}


@Test
public void getExtensionsByType() {
    AbstractPluginManager pluginManager = mock(AbstractPluginManager.class, CALLS_REAL_METHODS);
    ExtensionFinder extensionFinder = mock(ExtensionFinder.class);
    List<ExtensionWrapper<TestExtensionPoint>> extensionList = new ArrayList<>(1);
    extensionList.add(new ExtensionWrapper<>(new ExtensionDescriptor(0, TestExtension.class), new DefaultExtensionFactory()));
    when(extensionFinder.find(TestExtensionPoint.class)).thenReturn(extensionList);
    pluginManager.extensionFinder = extensionFinder;
    List<TestExtensionPoint> extensions = pluginManager.getExtensions(TestExtensionPoint.class);
    assertEquals(1, extensions.size());
}

@Override
public <T> List<T> getExtensions(Class<T> type) {
    List<ExtensionWrapper<T>> extensionsWrapper = extensionFinder.find(type);
    List<T> extensions = new ArrayList<>(extensionsWrapper.size());
    for (ExtensionWrapper<T> extensionWrapper : extensionsWrapper) {
        extensions.add(extensionWrapper.getExtension());
    }
    return extensions;
}

@Override
public <T> List<T> getExtensions(Class<T> type) {
    List<ExtensionWrapper<T>> extensionsWrapper = extensionFinder.find(type);
    List<T> extensions = new ArrayList<>(extensionsWrapper.size());
    for (ExtensionWrapper<T> extensionWrapper : extensionsWrapper) {
        try {
            extensions.add(extensionWrapper.getExtension());
        } catch (PluginException e) {
            log.error("Cannot retrieve extension", e);
        }
    }
    return extensions;
}


@Test
void isClosed() throws IOException {
    parentLastPluginClassLoader.close();
    assertTrue(parentLastPluginClassLoader.isClosed());
}

public boolean isClosed() {
    return closed;
}


@Test
public void testGetDoubles() {
    Mockito.doReturn(" [1234, 123, value3]").when(pippoSettings).getString("key", null);
    Mockito.doCallRealMethod().when(pippoSettings).getStrings("key", ",");
    Mockito.doCallRealMethod().when(pippoSettings).getDoubles("key", ",");
    List<Double> values = pippoSettings.getDoubles("key", ",");
    assertEquals(Arrays.asList(1234d, 123d), values);
    Mockito.doReturn(Collections.emptyList()).when(pippoSettings).getStrings("key", ",");
    values = pippoSettings.getDoubles("key", ",");
    assertTrue(values.isEmpty());
}

public List<Double> getDoubles(String name, String delimiter) {
    List<String> strings = getStrings(name, delimiter);
    List<Double> doubles = new ArrayList<>(strings.size());
    for (String value : strings) {
        try {
            double i = Double.parseDouble(value);
            doubles.add(i);
        } catch (NumberFormatException e) {
        }
    }
    return Collections.unmodifiableList(doubles);
}


@Test
public void testAcceptGzipEncoding() {
    GZipRequestResponseFactory requestResponseFactory = new GZipRequestResponseFactory(new Application());
    HttpServletRequest httpServletRequest = Mockito.mock(HttpServletRequest.class);
    Mockito.doReturn(null).when(httpServletRequest).getHeader("accept-encoding");
    assertFalse(requestResponseFactory.acceptsGZipEncoding(httpServletRequest));
    Mockito.doReturn("gzip,deflate,identity").when(httpServletRequest).getHeader("accept-encoding");
    assertTrue(requestResponseFactory.acceptsGZipEncoding(httpServletRequest));
    Mockito.doReturn("*").when(httpServletRequest).getHeader("accept-encoding");
    assertTrue(requestResponseFactory.acceptsGZipEncoding(httpServletRequest));
    Mockito.doReturn("deflate,identity").when(httpServletRequest).getHeader("accept-encoding");
    assertFalse(requestResponseFactory.acceptsGZipEncoding(httpServletRequest));
}

protected boolean acceptsGZipEncoding(HttpServletRequest httpServletRequest) {
    String acceptEncoding = httpServletRequest.getHeader("accept-encoding");
    return acceptEncoding != null && acceptEncoding.contains("gzip");
}

protected boolean acceptsGZipEncoding(HttpServletRequest httpServletRequest) {
    String acceptEncoding = httpServletRequest.getHeader("accept-encoding");
    return !StringUtils.isNullOrEmpty(acceptEncoding) && (acceptEncoding.contains("gzip") || acceptEncoding.contains("*"));
}


@Test
void testTemplateNormalization() {
    final String yamlTemplate = "id: template-id\n" + "info:\n" + "  name: Template Name\n" + "  author: istvan\n" + "  severity: info\n" + "requests:\n" + "- raw:\n" + "  - |+\n" + "    GET / HTTP/1.1\n" + "    Host: http://localhost:8080\n" + "  matchers-condition: and\n" + "  matchers:\n" + "  - type: word\n" + "    part: body\n" + "    condition: or\n" + "    words:\n" + "    - f=\"bin.bin\">bin.bin
\n" + "    -
dns.yaml
";
    final String expected = "id: template-id\n" + "\n" + "info:\n" + "  name: Template Name\n" + "  author: istvan\n" + "  severity: info\n" + "\n" + "requests:\n" + "- raw:\n" + "  - |+\n" + "    GET / HTTP/1.1\n" + "    Host: http://localhost:8080\n" + "\n" + "  matchers-condition: and\n" + "  matchers:\n" + "  - type: word\n" + "    part: body\n" + "    condition: or\n" + "    words:\n" + "    - f=\"bin.bin\">bin.bin
\n" + "    -
dns.yaml
";
    Assertions.assertEquals(expected, Utils.normalizeTemplate(yamlTemplate));
}

public static String normalizeTemplate(String yamlTemplate) {
    String result = yamlTemplate;
    for (String fieldName : Arrays.asList("info", "requests", "extractors")) {
        result = addNewLineBeforeProperty(result, fieldName);
    }
    result = result.contains("matchers-condition: ") ? addNewLineBeforeProperty(result, "matchers-condition", getEnumValues(Requests.MatchersCondition.class)) : addNewLineBeforeProperty(result, "matchers");
    result = result.contains("attack: ") ? addNewLineBeforeProperty(result, "attack", getEnumValues(Requests.AttackType.class)) : addNewLineBeforeProperty(result, "payloads");
    return result;
}


@Test
public void shouldDescribeListContentsUsingProvidedSource() {
    Source<String> sourceWithCustomDescription = Arbitrary.constant("x").describedAs(x -> "custom description for x");
    Source<String[]> testee = Arrays.arraysOf(sourceWithCustomDescription, String.class, 2, 2);
    String[] anArray = { "foo", "bar" };
    assertThat(testee.asString(anArray)).isEqualTo("[custom description for x, custom description for x]");
}

@SuppressWarnings("unchecked")
static <T> Source<T[]> arraysOf(Source<T> values, Class<T> c, int minLength, int maxLength) {
    return Lists.listsOf(values, Lists.arrayListCollector(), minLength, maxLength).as(l -> l.toArray((T[]) Array.newInstance(c, 0)), a -> java.util.Arrays.asList(a)).describedAs(arrayDescriber());
}

@SuppressWarnings("unchecked")
static <T> Source<T[]> arraysOf(Source<T> values, Class<T> c, int minLength, int maxLength) {
    return Lists.listsOf(values, Lists.arrayListCollector(), minLength, maxLength).as(l -> l.toArray((T[]) Array.newInstance(c, 0)), a -> java.util.Arrays.asList(a)).describedAs(arrayDescriber(values::asString));
}


@Test
public void shouldDescribeListContentsUsingProvidedSource() {
    Source<String> sourceWithCustomDescription = Arbitrary.constant("x").describedAs(x -> "custom description for x");
    Source<List<String>> testee = listsOf(sourceWithCustomDescription, arrayListCollector(), 2, 3);
    List<String> aList = new ArrayList<String>(Arrays.asList("x", "x"));
    assertThat(testee.asString(aList)).isEqualTo("[custom description for x, custom description for x]");
}

static <T> Source<List<T>> listsOf(Source<T> generator, Collector<T, List<T>, List<T>> collector, int minimumSize, int maximumSize) {
    return Source.of((prng, step) -> Collections.nCopies((int) prng.generateRandomLongWithinInterval(minimumSize, maximumSize), prng).stream().map(p -> generator.next(p, step)).collect(collector)).withShrinker(shrinkBoundedList(generator, collector, minimumSize));
}

static <T> Source<List<T>> listsOf(Source<T> generator, Collector<T, List<T>, List<T>> collector, int minimumSize, int maximumSize) {
    return Source.of((prng, step) -> Collections.nCopies((int) prng.generateRandomLongWithinInterval(minimumSize, maximumSize), prng).stream().map(p -> generator.next(p, step)).collect(collector)).withShrinker(shrinkBoundedList(generator, collector, minimumSize)).describedAs(listDescriber(generator::asString));
}


@Test
public void shouldNotShrinkEpochWhenMilliSecondsBetweenTwoValues() {
    Source<Date> testee = Dates.withMilliSecondsBetween(0, 8687689756l);
    assertThatSource(testee).cannotShrink(new Date(0));
}

static Source<Date> withMilliSecondsBetween(long milliSecondsFromEpochStartInclusive, long milliSecondsFromEpochEndInclusive) {
    return Longs.range(milliSecondsFromEpochStartInclusive, milliSecondsFromEpochEndInclusive).as(l -> new Date(l), d -> d.getTime());
}

@Test
public void shouldShrinkBoundedDateByOneWhenWithinRemainingCycles() {
    Source<Date> testee = Dates.withMilliSecondsBetween(0, 40);
    assertThatSource(testee).shrinksValueTo(new Date(7), new Date(6));
}


@Test
public void shouldShrinkBoundedLocalDateByOneWhenWithinRemainingCycles() {
    Source<LocalDate> testee = LocalDates.withDaysBetween(-30, -2);
    assertThatSource(testee).shrinksValueTo(LocalDate.ofEpochDay(-6), LocalDate.ofEpochDay(-5));
}

static Source<LocalDate> withDaysBetween(long daysFromEpochStartInclusive, long daysFromEpochEndInclusive) {
    return Longs.range(daysFromEpochStartInclusive, daysFromEpochEndInclusive).as(l -> LocalDate.ofEpochDay(l), d -> d.toEpochDay());
}

@Test
public void shouldShrinkLocalDateByOneWhenWithinRemainingCycles() {
    Source<LocalDate> testee = LocalDates.withDays(30);
    assertThatSource(testee).shrinksValueTo(LocalDate.ofEpochDay(6), LocalDate.ofEpochDay(5));
}

static Source<LocalDate> withDays(long daysFromEpoch) {
    if (daysFromEpoch < 0) {
        return Longs.range(daysFromEpoch, 0).as(l -> LocalDate.ofEpochDay(l), d -> d.toEpochDay());
    }
    return Longs.range(0, daysFromEpoch).as(l -> LocalDate.ofEpochDay(l), d -> d.toEpochDay());
}

@Test
public void shouldNotShrinkEpoch() {
    Source<LocalDate> testee = LocalDates.withDays(70978);
    assertThatSource(testee).cannotShrink(LocalDate.ofEpochDay(0));
}

@Test
public void shouldNotShrinkEpochWhenDaysAreBetweenTwoValues() {
    Source<LocalDate> testee = LocalDates.withDaysBetween(-324235, 70978);
    assertThatSource(testee).cannotShrink(LocalDate.ofEpochDay(0));
}


@SuppressWarnings("unused")
@Test
public void shouldNotCatchWhenCreatingADateWithLongOfZero() {
    try {
        Source<Date> testee = dates().withMilliSeconds(0);
    } catch (IllegalArgumentException expected) {
        fail("Threw an exception for an acceptable input!");
    }
}

public static DatesDSL dates() {
    return new DatesDSL();
}

@Test
public void shouldGenerateLocalDateAtStartAndEndInclusive() {
    Source<LocalDate> testee = localDates().withDaysBetween(3245352, 729385723);
    assertThatSource(testee).generatesAllOf(LocalDate.ofEpochDay(3245352), LocalDate.ofEpochDay(729385723));
}

public static LocalDatesDSL localDates() {
    return new LocalDatesDSL();
}

@SuppressWarnings("unused")
@Test
public void shouldCatchWhenCreatingAnInclusiveLongIntervalForDatesWithMaxLessThanMin() {
    try {
        Source<Date> testee = dates().withMilliSecondsBetween(342, 3);
        fail("Created a Date where max long is less than min long!");
    } catch (IllegalArgumentException expected) {
    }
}

@Test
public void shouldGenerateLocalDateMax() {
    Source<LocalDate> testee = localDates().withDays(7890789);
    assertThatSource(testee).generatesAllOf(LocalDate.ofEpochDay(7890789));
}

@SuppressWarnings("unused")
@Test
public void shouldCatchWhenCreatingADateOfNegativeLong() {
    try {
        Source<Date> testee = dates().withMilliSeconds(-234);
        fail("Created a date with a negative number of milliseconds");
    } catch (IllegalArgumentException expected) {
        assertTrue("Expected exception message to relate to negative long argument", expected.getMessage().indexOf("not an accepted number of milliseconds") >= 0);
    }
}

@SuppressWarnings("unused")
@Test
public void shouldNotCatchWhenCreatingAnInclusiveLongIntervalForDatesWithMaxEqualToMin() {
    try {
        Source<Date> testee = dates().withMilliSecondsBetween(352, 352);
    } catch (IllegalArgumentException expected) {
        fail("Threw an exception for an acceptable interval!");
    }
}

@SuppressWarnings("unused")
@Test
public void shouldNotCatchWhenCreatingALocalDateAtMaxEpochDayCount() {
    try {
        Source<LocalDate> testee = localDates().withDays(LOCAL_DATE_MAX_EPOCH_DAY_COUNT);
    } catch (IllegalArgumentException expected) {
        fail("Threw an exception for an acceptable input!");
    }
}

@SuppressWarnings("unused")
@Test
public void shouldNotCatchWhenCreatingAnInclusiveLongIntervalForDatesWithMinEqualToZero() {
    try {
        Source<Date> testee = dates().withMilliSecondsBetween(0, 5);
    } catch (IllegalArgumentException expected) {
        fail("Threw an exception for an acceptable interval!");
    }
}

@SuppressWarnings("unused")
@Test
public void shouldNotCatchWhenCreatingALocalDateAtMinEpochDayCount() {
    try {
        Source<LocalDate> testee = localDates().withDays(LOCAL_DATE_MIN_EPOCH_DAY_COUNT);
    } catch (IllegalArgumentException expected) {
        fail("Threw an exception for an acceptable input!");
    }
}

@SuppressWarnings("unused")
@Test
public void shouldCatchWhenCreatingAnInclusiveLongIntervalForLocalDatesWithMinLessThanMinEpochDayCount() {
    try {
        Source<LocalDate> testee = localDates().withDaysBetween(LOCAL_DATE_MIN_EPOCH_DAY_COUNT - 1, LOCAL_DATE_MAX_EPOCH_DAY_COUNT + 1);
        fail("Created a Date where min long is less than zero!");
    } catch (IllegalArgumentException expected) {
    }
}

@SuppressWarnings("unused")
@Test
public void shouldNotCatchWhenCreatingAnInclusiveLongIntervalForLocalDatesWithMaxEqualToMin() {
    try {
        Source<LocalDate> testee = localDates().withDaysBetween(352, 352);
    } catch (IllegalArgumentException expected) {
        fail("Threw an exception for an acceptable interval!");
    }
}

@SuppressWarnings("unused")
@Test
public void shouldCatchWhenCreatingAnInclusiveLongIntervalForLocalDatesWithMaxLessThanMin() {
    try {
        Source<LocalDate> testee = localDates().withDaysBetween(342, 3);
        fail("Created a localDate where max long is less than min long!");
    } catch (IllegalArgumentException expected) {
    }
}

@SuppressWarnings("unused")
@Test
public void shouldCatchWhenCreatingALocalDateBelowMinEpochDayCount() {
    try {
        Source<LocalDate> testee = localDates().withDays(LOCAL_DATE_MIN_EPOCH_DAY_COUNT - 1);
        fail("Created a localDate with an improper value");
    } catch (IllegalArgumentException expected) {
        assertTrue("Expected exception message to relate to out of suitable range long argument", expected.getMessage().indexOf("The long value representing the number of days from the epoch must be bounded") >= 0);
    }
}

@SuppressWarnings("unused")
@Test
public void shouldCatchWhenCreatingALocalDateAboveMaxEpochDayCount() {
    try {
        Source<LocalDate> testee = localDates().withDays(LOCAL_DATE_MAX_EPOCH_DAY_COUNT + 1);
        fail("Created a localDate with an improper value");
    } catch (IllegalArgumentException expected) {
    }
}

@Test
public void shouldGenerateDateAtStartAndEndInclusive() {
    Source<Date> testee = dates().withMilliSecondsBetween(3245352, 72938572398752l);
    assertThatSource(testee).generatesAllOf(new Date(3245352), new Date(72938572398752l));
}

@SuppressWarnings("unused")
@Test
public void shouldCatchWhenCreatingAnInclusiveLongIntervalForDatesWithMinLessThanZero() {
    try {
        Source<Date> testee = dates().withMilliSecondsBetween(-5, 6);
        fail("Created a Date where min long is less than zero!");
    } catch (IllegalArgumentException expected) {
    }
}

@SuppressWarnings("unused")
@Test
public void shouldNotCatchWhenCreatingAnInclusiveLongIntervalForDatesWithMinEqualToMinEpochDayCount() {
    try {
        Source<LocalDate> testee = localDates().withDaysBetween(LOCAL_DATE_MIN_EPOCH_DAY_COUNT, LOCAL_DATE_MAX_EPOCH_DAY_COUNT);
    } catch (IllegalArgumentException expected) {
        fail("Threw an exception for an acceptable interval!");
    }
}

@Test
public void shouldGenerateDateMax() {
    Source<Date> testee = dates().withMilliSeconds(7890789);
    assertThatSource(testee).generatesAllOf(new Date(7890789));
}


@Test
public void shouldPrintArrayAsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(bigIntegers().ofBytes(5)).as(b -> b.toByteArray()).describedAs(a -> Arrays.toString(a)).check(i -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 0 }));
    }
}

public <N> TheoryBuilder<Pair<P, T>, N> as(Function<T, N> mapping) {
    return new TheoryBuilder<Pair<P, T>, N>(state, convertedSource(mapping), convertedPredicate(mapping), internalConversion(mapping));
}

public <N> TheoryBuilder<Pair<P, T>, N> as(Function<T, N> mapping) {
    return new TheoryBuilder<Pair<P, T>, N>(state, convertedSource(mapping), convertedPredicate(mapping), internalConversion(mapping), n -> n.toString());
}

@Test
public void shouldPrintArrayFromAsWithPrecursorOfThreeElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive()).asWithPrecursor((i, j, k) -> new Integer[] { i, j, k }).describedAs(i -> i.toString(), j -> j.toString(), k -> k.toString(), a -> Arrays.deepToString(a)).check((i, j, k, a) -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("1, 1, 1, " + Arrays.deepToString(new Integer[] { 1, 1, 1 }));
    }
}

public <T> Subject4<A, B, C, T> asWithPrecursor(Function3<A, B, C, T> mapping) {
    Shrink<Tuple4<A, B, C, T>> shrink = (original, context) -> combineShrinks().shrink(Tuple3.of(original._1, original._2, original._3), context).map(precursor -> precursor.extend(mapping));
    Source<Tuple4<A, B, C, T>> gen = Source.of(generatePrecursorValueTuple(mapping)).withShrinker(shrink);
    return new PrecursorTheoryBuilder3<A, B, C, T>(state, gen, assumptions);
}

public <T> Subject4<A, B, C, T> asWithPrecursor(Function3<A, B, C, T> mapping) {
    Shrink<Tuple4<A, B, C, T>> shrink = (original, context) -> combineShrinks().shrink(Tuple3.of(original._1, original._2, original._3), context).map(precursor -> precursor.extend(mapping));
    Source<Tuple4<A, B, C, T>> gen = Source.of(generatePrecursorValueTuple(mapping)).withShrinker(shrink);
    return new PrecursorTheoryBuilder3<A, B, C, T>(state, gen, assumptions, a -> a.toString(), b -> b.toString(), c -> c.toString(), t -> t.toString());
}

@Test
public void shouldPrintArrayFromAsWithPrecursorOfFourElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive(), integers().allPositive()).asWithPrecursor((i, j, k, l) -> new Integer[] { i, j, k, l }).describedAs(i -> i.toString(), j -> j.toString(), k -> k.toString(), l -> l.toString(), a -> Arrays.deepToString(a)).check((i, j, k, l, a) -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("1, 1, 1, 1, " + Arrays.deepToString(new Integer[] { 1, 1, 1, 1 }));
    }
}

public <T> Subject5<A, B, C, D, T> asWithPrecursor(Function4<A, B, C, D, T> mapping) {
    Shrink<Tuple5<A, B, C, D, T>> shrink = (original, context) -> combineShrinks().shrink(Tuple4.of(original._1, original._2, original._3, original._4), context).map(precursor -> precursor.extend(mapping));
    Source<Tuple5<A, B, C, D, T>> gen = Source.of(generatePrecursorValueTuple(mapping)).withShrinker(shrink);
    return new PrecursorTheoryBuilder4<A, B, C, D, T>(state, gen, assumptions);
}

public <T> Subject5<A, B, C, D, T> asWithPrecursor(Function4<A, B, C, D, T> mapping) {
    Shrink<Tuple5<A, B, C, D, T>> shrink = (original, context) -> combineShrinks().shrink(Tuple4.of(original._1, original._2, original._3, original._4), context).map(precursor -> precursor.extend(mapping));
    Source<Tuple5<A, B, C, D, T>> gen = Source.of(generatePrecursorValueTuple(mapping)).withShrinker(shrink);
    return new PrecursorTheoryBuilder4<A, B, C, D, T>(state, gen, assumptions, a -> a.toString(), b -> b.toString(), c -> c.toString(), d -> d.toString(), t -> t.toString());
}

@Test
public void shouldPrintArrayFromAsOfFourElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive(), integers().allPositive()).as((i, j, k, l) -> new Integer[] { i, j, k, l }).describedAs(a -> Arrays.deepToString(a)).check(i -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 1, 1, 1, 1 }));
    }
}

public <T> Subject1<T> as(Function4<A, B, C, D, T> mapping) {
    return new MappingTheoryBuilder<>(state, combine(), precursor -> assumptions.test(precursor._1, precursor._2, precursor._3, precursor._4), tuple -> mapping.apply(tuple._1, tuple._2, tuple._3, tuple._4));
}

public <T> Subject1<T> as(Function4<A, B, C, D, T> mapping) {
    return new MappingTheoryBuilder<>(state, combine(), precursor -> assumptions.test(precursor._1, precursor._2, precursor._3, precursor._4), tuple -> mapping.apply(tuple._1, tuple._2, tuple._3, tuple._4), t -> t.toString());
}

@Test
public void shouldPrintArrayDeepToString() {
    try {
        qt().withFixedSeed(5).forAll(arrays().ofStrings(strings().ascii().ofLength(1)).withLength(1)).describedAs(a -> Arrays.deepToString(a)).check(i -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new String[] { "!" }));
    }
}

public <A> TheoryBuilder<A, A> forAll(final Source<A> values) {
    return new TheoryBuilder<>(state, values, a -> true, x -> x);
}

public <A> TheoryBuilder<A, A> forAll(final Source<A> values) {
    return new TheoryBuilder<>(state, values, a -> true, x -> x, a -> a.toString());
}

@Test
public void shouldPrintTwoIntegersAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(integers().all(), integers().allPositive()).check((i, j) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{0, 1}");
    }
}

public void check(final BiPredicate<A, B> property) {
    final TheoryRunner<Pair<A, B>, Pair<A, B>> qc = new TheoryRunner<>(this.state.get(), combine(), convertPredicate(), x -> x);
    qc.check(x -> property.test(x._1, x._2));
}

public void check(final BiPredicate<A, B> property) {
    final TheoryRunner<Pair<A, B>, Pair<A, B>> qc = new TheoryRunner<>(this.state.get(), combine(), convertPredicate(), x -> x, pair -> "{" + pair._1.toString() + ", " + pair._2.toString() + "}");
    qc.check(x -> property.test(x._1, x._2));
}

@Test
public void shouldPrintFailingThreeCharactersAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(characters().ascii(), characters().ascii(), characters().ascii()).check((i, j, k) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{\u0000, \u0000, \u0000}");
    }
}

public void check(final Predicate3<A, B, C> property) {
    final TheoryRunner<Tuple3<A, B, C>, Tuple3<A, B, C>> qc = new TheoryRunner<>(this.state.get(), combine(), convertPredicate(), x -> x);
    qc.check(x -> property.test(x._1, x._2, x._3));
}

public void check(final Predicate3<A, B, C> property) {
    final TheoryRunner<Tuple3<A, B, C>, Tuple3<A, B, C>> qc = new TheoryRunner<>(this.state.get(), combine(), convertPredicate(), x -> x, tuple3 -> "{" + tuple3._1.toString() + ", " + tuple3._2.toString() + ", " + tuple3._3.toString() + "}");
    qc.check(x -> property.test(x._1, x._2, x._3));
}

@Test
public void shouldPrintThreeCharactersAsStringAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(characters().ascii(), characters().ascii(), characters().ascii()).as((i, j, k) -> Character.toString(i) + Character.toString(j) + Character.toString(k)).check(s -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("\u0000\u0000\u0000");
    }
}

public <T> Subject1<T> as(Function3<A, B, C, T> mapping) {
    return new MappingTheoryBuilder<>(state, combine(), precursor -> assumptions.test(precursor._1, precursor._2, precursor._3), tuple -> mapping.apply(tuple._1, tuple._2, tuple._3));
}

public <T> Subject1<T> as(Function3<A, B, C, T> mapping) {
    return new MappingTheoryBuilder<>(state, combine(), precursor -> assumptions.test(precursor._1, precursor._2, precursor._3), tuple -> mapping.apply(tuple._1, tuple._2, tuple._3), t -> t.toString());
}

@Test
public void shouldPrintSingleLongAsLongAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(longs().all()).as(l -> l).check(i -> i < i + 1);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("9223372036854775807");
    }
}

@Test
public void shouldPrintArrayFromAsOfThreeElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive()).as((i, j, k) -> new Integer[] { i, j, k }).describedAs(a -> Arrays.deepToString(a)).check(i -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 1, 1, 1 }));
    }
}

@Test
public void shouldPrintTwoIntegersAsWithPrecursorIntegerAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(integers().all(), integers().allPositive()).asWithPrecursor((i, j) -> i + j).check((i, j, k) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{0, 1, 1}");
    }
}

public <T> Subject3<A, B, T> asWithPrecursor(BiFunction<A, B, T> mapping) {
    Generator<Tuple3<A, B, T>> g = (prng, step) -> {
        A a = this.as.next(prng, step);
        B b = this.bs.next(prng, step);
        return Tuple3.of(a, b, mapping.apply(a, b));
    };
    Shrink<Tuple3<A, B, T>> s = (original, context) -> joinShrunkStreams().shrink(Pair.of(original._1, original._2), context).map(p -> Tuple3.of(p._1, p._2, mapping.apply(p._1, p._2)));
    Source<Tuple3<A, B, T>> gen = Source.of(g).withShrinker(s);
    return new PrecursorTheoryBuilder2<A, B, T>(state, gen, assumptions);
}

public <T> Subject3<A, B, T> asWithPrecursor(BiFunction<A, B, T> mapping) {
    Generator<Tuple3<A, B, T>> g = (prng, step) -> {
        A a = this.as.next(prng, step);
        B b = this.bs.next(prng, step);
        return Tuple3.of(a, b, mapping.apply(a, b));
    };
    Shrink<Tuple3<A, B, T>> s = (original, context) -> joinShrunkStreams().shrink(Pair.of(original._1, original._2), context).map(p -> Tuple3.of(p._1, p._2, mapping.apply(p._1, p._2)));
    Source<Tuple3<A, B, T>> gen = Source.of(g).withShrinker(s);
    return new PrecursorTheoryBuilder2<A, B, T>(state, gen, assumptions, a -> a.toString(), b -> b.toString(), t -> t.toString());
}

@Test
public void shouldPrintArraysAsWithPrecursorToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(arrays().ofIntegers(integers().all()).withLengthBetween(1, 100)).asWithPrecursor(a -> Arrays.asList(a)).describedAs(a -> Arrays.deepToString(a), l -> l.toString()).check((a, l) -> integerListIsReducedByRemovingAnItem().test(l));
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 0 }));
    }
}

public <N> Subject2<P, N> asWithPrecursor(Function<T, N> mapping) {
    Generator<Pair<P, N>> g = (prng, step) -> {
        P p = this.ps.next(prng, step);
        T t = this.conversion.apply(p);
        return Pair.of(p, mapping.apply(t));
    };
    Shrink<Pair<P, N>> s = (original, context) -> ps.shrink(original._1, context).map(p -> Pair.of(p, conversion.andThen(mapping).apply(p)));
    Source<Pair<P, N>> gen = Source.of(g).withShrinker(s);
    return new PrecursorTheoryBuilder1<P, N>(state, gen, assumptions);
}

public <N> Subject2<P, N> asWithPrecursor(Function<T, N> mapping) {
    Generator<Pair<P, N>> g = (prng, step) -> {
        P p = this.ps.next(prng, step);
        T t = this.conversion.apply(p);
        return Pair.of(p, mapping.apply(t));
    };
    Shrink<Pair<P, N>> s = (original, context) -> ps.shrink(original._1, context).map(p -> Pair.of(p, conversion.andThen(mapping).apply(p)));
    Source<Pair<P, N>> gen = Source.of(g).withShrinker(s);
    return new PrecursorTheoryBuilder1<P, N>(state, gen, assumptions, a -> a.toString(), b -> b.toString());
}

@Test
public void shouldPrintFourFailingIntegersAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(integers().all(), integers().all(), integers().all(), integers().all()).check((i, j, k, l) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{0, 0, 0, 0}");
    }
}

public void check(final Predicate4<A, B, C, D> property) {
    final TheoryRunner<Tuple4<A, B, C, D>, Tuple4<A, B, C, D>> qc = new TheoryRunner<>(this.state.get(), combine(), convertPredicate(), x -> x);
    qc.check(x -> property.test(x._1, x._2, x._3, x._4));
}

public void check(final Predicate4<A, B, C, D> property) {
    final TheoryRunner<Tuple4<A, B, C, D>, Tuple4<A, B, C, D>> qc = new TheoryRunner<>(this.state.get(), combine(), convertPredicate(), x -> x, tuple4 -> "{" + tuple4._1.toString() + ", " + tuple4._2.toString() + ", " + tuple4._3.toString() + ", " + tuple4._4.toString() + "}");
    qc.check(x -> property.test(x._1, x._2, x._3, x._4));
}

@Test
public void shouldPrintFourIntegersAsWithPrecursorLongAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(integers().all(), integers().all(), integers().all(), integers().all()).asWithPrecursor((i, j, k, l) -> (long) i + j + k + l).check((i, j, k, l, s) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{0, 0, 0, 0, 0}");
    }
}

@Test
public void shouldPrintThreeCharactersAsWithPrecursorStringAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(characters().ascii(), characters().ascii(), characters().ascii()).asWithPrecursor((i, j, k) -> Character.toString(i) + Character.toString(j) + Character.toString(k)).check((i, j, k, s) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{\u0000, \u0000, \u0000, \u0000\u0000\u0000}");
    }
}

@Test
public void shouldUseCustomToStringForStringAndIntAsPerson() {
    try {
        qt().withFixedSeed(5).forAll(strings().basicLatinAlphabet().ofLengthBetween(3, 12), integers().between(0, 140)).assuming((s, i) -> s.codePoints().allMatch(j -> Character.isLetter(j))).as((i, j) -> new Person(i, j)).describedAs(p -> p.toUseToString()).check(i -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("Name:");
    }
}

public <T> Subject1<T> as(BiFunction<A, B, T> mapping) {
    return new MappingTheoryBuilder<>(state, combine(), precursor -> assumptions.test(precursor._1, precursor._2), precursor -> mapping.apply(precursor._1, precursor._2));
}

public <T> Subject1<T> as(BiFunction<A, B, T> mapping) {
    return new MappingTheoryBuilder<>(state, combine(), precursor -> assumptions.test(precursor._1, precursor._2), precursor -> mapping.apply(precursor._1, precursor._2), t -> t.toString());
}

@Test
public void shouldPrintSingleLongAsWithPrecursorLongAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(longs().all()).asWithPrecursor(l -> l).check((h, i) -> i < i + 1);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{9223372036854775807, 9223372036854775807}");
    }
}

@Test
public void shouldUseCustomToStringForStringAndIntAsWithPrecursorPerson() {
    try {
        qt().withFixedSeed(5).forAll(strings().basicLatinAlphabet().ofLengthBetween(3, 12), integers().between(0, 140)).assuming((s, i) -> s.codePoints().allMatch(j -> Character.isLetter(j))).asWithPrecursor((i, j) -> new Person(i, j)).describedAs(s -> s.toString(), i -> i.toString(), p -> p.toUseToString()).check((i, s, p) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("Name:");
    }
}


@Test
public void shouldPrintArrayAsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(bigIntegers().ofBytes(5)).as(b -> b.toByteArray()).describedAs(a -> Arrays.toString(a)).check(i -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 0 }));
    }
}


@Test
public void shouldPrintSingleLongAsExpected() {
    try {
        qt().forAll(longs().all()).as(l -> l).check(i -> i < i + 1);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("9223372036854775807");
    }
}


@Test
public void shouldPrintArrayFromAsWithPrecursorOfThreeElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive()).asWithPrecursor((i, j, k) -> new Integer[] { i, j, k }).withStringFormat(i -> i.toString(), j -> j.toString(), k -> k.toString(), a -> Arrays.deepToString(a)).check((i, j, k, a) -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("1, 1, 1, " + Arrays.deepToString(new Integer[] { 1, 1, 1 }));
    }
}

@Test
public void shouldPrintArrayFromAsWithPrecursorOfFourElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive(), integers().allPositive()).asWithPrecursor((i, j, k, l) -> new Integer[] { i, j, k, l }).withStringFormat(i -> i.toString(), j -> j.toString(), k -> k.toString(), l -> l.toString(), a -> Arrays.deepToString(a)).check((i, j, k, l, a) -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("1, 1, 1, 1, " + Arrays.deepToString(new Integer[] { 1, 1, 1, 1 }));
    }
}

@Test
public void shouldPrintArrayFromAsOfFourElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive(), integers().allPositive()).as((i, j, k, l) -> new Integer[] { i, j, k, l }).withStringFormat(a -> Arrays.deepToString(a)).check(i -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 1, 1, 1, 1 }));
    }
}

@Test
public void shouldPrintArrayFromAsOfThreeElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive()).as((i, j, k) -> new Integer[] { i, j, k }).withStringFormat(a -> Arrays.deepToString(a)).check(i -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 1, 1, 1 }));
    }
}

@Test
public void shouldPrintArraysAsWithPrecursorToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(arrays().ofIntegers(integers().all()).withLengthBetween(1, 100)).asWithPrecursor(a -> Arrays.asList(a)).withStringFormat(a -> Arrays.deepToString(a), l -> l.toString()).check((a, l) -> integerListIsReducedByRemovingAnItem().test(l));
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 0 }));
    }
}


@Test
public void shouldPrintArrayAsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(bigIntegers().ofBytes(5)).as(b -> b.toByteArray()).withStringFormat(a -> Arrays.toString(a)).check(i -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 0 }));
    }
}

@Test
public void shouldPrintArrayDeepToString() {
    try {
        qt().withFixedSeed(5).forAll(arrays().ofStrings(strings().ascii().ofLength(1)).withLength(1)).withStringFormat(a -> Arrays.deepToString(a)).check(i -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new String[] { "!" }));
    }
}

@Test
public void shouldPrintArraysAsWithPrecursorToDeepString() {
    try {
        qt().forAll(arrays().ofIntegers(integers().all()).withLengthBetween(1, 100)).asWithPrecursor(a -> Arrays.asList(a)).withStringFormat(a -> Arrays.deepToString(a), l -> l.toString()).check((a, l) -> integerListIsReducedByRemovingAnItem().test(l));
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 0 }));
    }
}

@Test
public void shouldUseCustomToStringForStringAndIntAsPerson() {
    try {
        qt().withFixedSeed(5).forAll(strings().basicLatinAlphabet().ofLengthBetween(3, 12), integers().between(0, 140)).assuming((s, i) -> s.codePoints().allMatch(j -> Character.isLetter(j))).as((i, j) -> new Person(i, j)).withStringFormat(p -> p.toUseToString()).check(i -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("Name:");
    }
}

@Test
public void shouldUseCustomToStringForStringAndIntAsWithPrecursorPerson() {
    try {
        qt().withFixedSeed(5).forAll(strings().basicLatinAlphabet().ofLengthBetween(3, 12), integers().between(0, 140)).assuming((s, i) -> s.codePoints().allMatch(j -> Character.isLetter(j))).asWithPrecursor((i, j) -> new Person(i, j)).withStringFormat(s -> s.toString(), i -> i.toString(), p -> p.toUseToString()).check((i, s, p) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("Name:");
    }
}


@Test
public void errorsNicelyWhenNonSensicalRangeRequested() {
    try {
        testee.nextLong(1, 0);
        fail();
    } catch (IllegalArgumentException ex) {
        assertThat(ex).hasMessageContaining("Invalid range 1 to 0");
    }
}

@Override
public long nextLong(long startInclusive, long endInclusive) {
    if (longRangeIsSmallerThanMax(startInclusive, endInclusive)) {
        return nextLongWithinCheckedInterval(startInclusive, endInclusive);
    }
    return generateRandomLongWhereRangeGEQMax(startInclusive, endInclusive);
}

@Override
public long nextLong(long startInclusive, long endInclusive) {
    if (endInclusive < startInclusive) {
        throw new IllegalArgumentException(String.format("Invalid range %d to %d", startInclusive, endInclusive));
    }
    if (longRangeIsSmallerThanMax(startInclusive, endInclusive)) {
        return nextLongWithinCheckedInterval(startInclusive, endInclusive);
    }
    return generateRandomLongWhereRangeGEQMax(startInclusive, endInclusive);
}


@Test
public void includesSomeOptionalsWhenPercentageIs1() {
    Gen<Optional<Integer>> testee = Generate.constant(1).toOptionals(1);
    assertThatGenerator(testee).generatesAllOf(Optional.empty(), Optional.of(1));
}

default Gen<Optional<T>> toOptionals(int percentEmpty) {
    Mod<T, Optional<T>> toOptional = (t, r) -> {
        boolean empty = r.next(Constraint.between(0, 100)) < percentEmpty;
        if (empty) {
            return Optional.empty();
        }
        return Optional.of(t);
    };
    return mutate(toOptional);
}

@SuppressWarnings("unchecked")
@Test
public void mapsToOnlyEmptyOptionalsWhenPercentageIs100() {
    Gen<Optional<Integer>> testee = Sequence.of(1, 2, 3).toOptionals(100);
    Stream<Optional<Integer>> actual = generate(testee).limit(3);
    assertThat(actual).containsExactly(Optional.empty(), Optional.empty(), Optional.empty());
}

@SuppressWarnings("unchecked")
@Test
public void mapsToOptionalsWithoutEmptyWhenPercentageIs0() {
    Gen<Optional<Integer>> testee = Sequence.of(1, 2, 3).toOptionals(0);
    Stream<Optional<Integer>> actual = generate(testee).limit(3);
    assertThat(actual).containsExactly(Optional.of(1), Optional.of(2), Optional.of(3));
}


@Test
public void shouldFalisyWhenAssertionsThrownAfterTypeConversion() {
    qt().forAll(arbitrary().sequence(1, 2, 3, 4, 5, 6, 7), arbitrary().sequence(1, 2, 3, 4, 5, 6, 7)).as((a, b) -> a.toString() + b).checkAssert(a -> assertEquals("11", a));
    verifier.isFalsifiedByException();
}

public <T> Subject1<T> as(BiFunction<A, B, T> mapping) {
    return new MappingTheoryBuilder<>(state, combine(), precursor -> assumptions.test(precursor._1, precursor._2), precursor -> mapping.apply(precursor._1, precursor._2), t -> t.toString());
}

public <T> Subject1<T> as(BiFunction<A, B, T> mapping) {
    return new MappingTheoryBuilder<>(this.state, combine(), precursor -> this.assumptions.test(precursor._1, precursor._2), precursor -> mapping.apply(precursor._1, precursor._2), t -> t.toString());
}


@Test
public void shouldPrintArrayAsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(bigIntegers().ofBytes(5)).as(b -> b.toByteArray()).describedAs(a -> Arrays.toString(a)).check(i -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 0 }));
    }
}

@Test
public void shouldPrintArrayFromAsWithPrecursorOfThreeElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive()).asWithPrecursor((i, j, k) -> new Integer[] { i, j, k }).describedAs(i -> i.toString(), j -> j.toString(), k -> k.toString(), a -> Arrays.deepToString(a)).check((i, j, k, a) -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("1, 1, 1, " + Arrays.deepToString(new Integer[] { 1, 1, 1 }));
    }
}

@Test
public void shouldPrintArrayFromAsWithPrecursorOfFourElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive(), integers().allPositive()).asWithPrecursor((i, j, k, l) -> new Integer[] { i, j, k, l }).describedAs(i -> i.toString(), j -> j.toString(), k -> k.toString(), l -> l.toString(), a -> Arrays.deepToString(a)).check((i, j, k, l, a) -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("1, 1, 1, 1, " + Arrays.deepToString(new Integer[] { 1, 1, 1, 1 }));
    }
}

@Test
public void shouldPrintArrayFromAsOfFourElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive(), integers().allPositive()).as((i, j, k, l) -> new Integer[] { i, j, k, l }).describedAs(a -> Arrays.deepToString(a)).check(i -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 1, 1, 1, 1 }));
    }
}

@Test
public void shouldPrintArrayDeepToString() {
    try {
        qt().withFixedSeed(5).forAll(arrays().ofStrings(strings().ascii().ofLength(1)).withLength(1)).describedAs(a -> Arrays.deepToString(a)).check(i -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new String[] { "!" }));
    }
}

@Test
public void shouldPrintTwoIntegersAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(integers().all(), integers().allPositive()).check((i, j) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{0, 1}");
    }
}

@Test
public void shouldPrintFailingThreeCharactersAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(characters().ascii(), characters().ascii(), characters().ascii()).check((i, j, k) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{\u0000, \u0000, \u0000}");
    }
}

@Test
public void shouldPrintThreeCharactersAsStringAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(characters().ascii(), characters().ascii(), characters().ascii()).as((i, j, k) -> Character.toString(i) + Character.toString(j) + Character.toString(k)).check(s -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("\u0000\u0000\u0000");
    }
}

@Test
public void shouldPrintSingleLongAsLongAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(longs().all()).as(l -> l).check(i -> i < i + 1);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("9223372036854775807");
    }
}

@Test
public void shouldPrintArrayFromAsOfThreeElementsToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(integers().allPositive(), integers().allPositive(), integers().allPositive()).as((i, j, k) -> new Integer[] { i, j, k }).describedAs(a -> Arrays.deepToString(a)).check(i -> false);
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 1, 1, 1 }));
    }
}

@Test
public void shouldPrintTwoIntegersAsWithPrecursorIntegerAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(integers().all(), integers().allPositive()).asWithPrecursor((i, j) -> i + j).check((i, j, k) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{0, 1, 1}");
    }
}

@Test
public void shouldPrintArraysAsWithPrecursorToDeepString() {
    try {
        qt().withFixedSeed(5).forAll(arrays().ofIntegers(integers().all()).withLengthBetween(1, 100)).asWithPrecursor(a -> Arrays.asList(a)).describedAs(a -> Arrays.deepToString(a), l -> l.toString()).check((a, l) -> integerListIsReducedByRemovingAnItem().test(l));
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining(Arrays.deepToString(new Integer[] { 0 }));
    }
}

@Test
public void shouldPrintFourFailingIntegersAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(integers().all(), integers().all(), integers().all(), integers().all()).check((i, j, k, l) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{0, 0, 0, 0}");
    }
}

@Test
public void shouldPrintFourIntegersAsWithPrecursorLongAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(integers().all(), integers().all(), integers().all(), integers().all()).asWithPrecursor((i, j, k, l) -> (long) i + j + k + l).check((i, j, k, l, s) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{0, 0, 0, 0, 0}");
    }
}

@Test
public void shouldPrintThreeCharactersAsWithPrecursorStringAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(characters().ascii(), characters().ascii(), characters().ascii()).asWithPrecursor((i, j, k) -> Character.toString(i) + Character.toString(j) + Character.toString(k)).check((i, j, k, s) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{\u0000, \u0000, \u0000, \u0000\u0000\u0000}");
    }
}

@Test
public void shouldUseCustomToStringForStringAndIntAsPerson() {
    try {
        qt().withFixedSeed(5).forAll(strings().basicLatinAlphabet().ofLengthBetween(3, 12), integers().between(0, 140)).assuming((s, i) -> s.codePoints().allMatch(j -> Character.isLetter(j))).as((i, j) -> new Person(i, j)).describedAs(p -> p.toUseToString()).check(i -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("Name:");
    }
}

@Test
public void shouldPrintSingleLongAsWithPrecursorLongAsExpected() {
    try {
        qt().withFixedSeed(5).forAll(longs().all()).asWithPrecursor(l -> l).check((h, i) -> i < i + 1);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("{9223372036854775807, 9223372036854775807}");
    }
}

@Test
public void shouldUseCustomToStringForStringAndIntAsWithPrecursorPerson() {
    try {
        qt().withFixedSeed(5).forAll(strings().basicLatinAlphabet().ofLengthBetween(3, 12), integers().between(0, 140)).assuming((s, i) -> s.codePoints().allMatch(j -> Character.isLetter(j))).asWithPrecursor((i, j) -> new Person(i, j)).describedAs(s -> s.toString(), i -> i.toString(), p -> p.toUseToString()).check((i, s, p) -> false);
        throw (new AssertionError("Test didn't fail"));
    } catch (AssertionError error) {
        assertThat(error).hasMessageContaining("Name:");
    }
}