Algoritmo Palindrome e testes JUnit 5

Aug 27 2020

Eu tenho uma classe "Palindrome" que possui algumas funções para verificar se certas coisas são palíndromos. Para a verificação, tenho 2 algoritmos diferentes, sendo um recursivo e outro iterativo.

Estou feliz com os algoritmos, no entanto, não tenho certeza se a maneira como faço a sobrecarga e, eventualmente, a análise de tudo para a função check charArray é uma coisa inteligente.

Também tenho alguns testes Junit 5 que provam que tudo funciona. Aqui, estou apenas inseguro se é um bom código com os vários ninhos e os métodos/testes que escolhi e se praticamente ter código duplicado para o algoritmo iterativo e recursivo é bom. Agradeço antecipadamente.

Classe Palíndromo

package com.gr;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Lucifer Uchiha
 * @version 1.0
 */
public class Palindrome {

    /* Iterative */

    /**
     * Returns a boolean of whether the char array is a palindrome or not.
     * This is determined by using the iterative algorithm.
     *
     * @param chars char array containing the characters to be checked.
     * @return boolean of whether the char array is a palindrome or not.
     */
    public static boolean isCharArrayPalindromeIterative(char[] chars) {
        if (chars.length < 1)
            return false;
        char[] formattedChars = convertAllCharsToUpperCase(chars);
        boolean isPalindrome = true;
        for (int i = 0; i != formattedChars.length / 2; i++)
            if (formattedChars[i] != formattedChars[(formattedChars.length - 1) - i]) {
                isPalindrome = false;
                break;
            }
        return isPalindrome;
    }

    /**
     * Returns a boolean of whether the word of type String is a palindrome or not.
     * This is determined by using the iterative algorithm.
     *
     * @param word the word to be checked.
     * @return boolean of whether the word is a palindrome or not.
     */
    public static boolean isWordPalindromeIterative(String word) {
        return isCharArrayPalindromeIterative(word.toCharArray());
    }

    /**
     * Returns a boolean of whether the sentence of type String is a palindrome or not.
     * This is determined by using the iterative algorithm.
     *
     * @param sentence the sentence to be checked.
     * @return boolean of whether the sentence is a palindrome or not.
     */
    public static boolean isSentencePalindromeIterative(String sentence) {
        String newSentence = sentence.replaceAll("[^a-zA-Z]", "");
        return isWordPalindromeIterative(newSentence);
    }

    /**
     * Returns a boolean of whether the number of type byte (-128 to 127) is a palindrome or not.
     * This is determined by using the iterative algorithm.
     *
     * @param number the number to be checked.
     * @return boolean of whether the number is a palindrome or not.
     */
    public static boolean isNumberPalindromeIterative(byte number) {
        return isWordPalindromeIterative(String.valueOf(number));
    }

    /**
     * Returns a boolean of whether the number of type short (32,768 to 32,767) is a palindrome or not.
     * This is determined by using the iterative algorithm.
     *
     * @param number the number to be checked.
     * @return boolean of whether the number is a palindrome or not.
     */
    public static boolean isNumberPalindromeIterative(short number) {
        return isWordPalindromeIterative(String.valueOf(number));
    }

    /**
     * Returns a boolean of whether the number of type int (-2,147,483,648 to 2,147,483,647) is a palindrome or not.
     * This is determined by using the iterative algorithm.
     *
     * @param number the number to be checked.
     * @return boolean of whether the number is a palindrome or not.
     */
    public static boolean isNumberPalindromeIterative(int number) {
        return isWordPalindromeIterative(String.valueOf(number));
    }

    /**
     * Returns a boolean of whether the number of type long (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807) is a palindrome or not.
     * This is determined by using the iterative algorithm.
     *
     * @param number the number to be checked.
     * @return boolean of whether the number is a palindrome or not.
     */
    public static boolean isNumberPalindromeIterative(long number) {
        return isWordPalindromeIterative(String.valueOf(number));
    }

    /**
     * Returns a List containing all the numbers that are palindromes in the range that is given from
     * start of type long to end of type long.
     * This is determined by using the iterative algorithm.
     *
     * @param start the start of the range, inclusive.
     * @param end   the end of the range, exclusive.
     * @return List containing all the numbers that are palindromes in the given range.
     */
    public static List<Long> getAllNumberPalindromesInRangeIterative(long start, long end) {
        List<Long> results = new ArrayList<>();
        for (long number = start; number != end; number++)
            if (isNumberPalindromeIterative(number))
                results.add(number);
        return results;
    }

    /**
     * Returns a List containing all the numbers that are palindromes in the range that is given from
     * start of type int to end of type int.
     * This is determined by using the iterative algorithm.
     *
     * @param start the start of the range, inclusive.
     * @param end   the end of the range, exclusive.
     * @return List containing all the numbers that are palindromes in the given range.
     */
    public static List<Integer> getAllNumberPalindromesInRangeIterative(int start, int end) {
        return convertLongListToIntegerList(getAllNumberPalindromesInRangeIterative((long) start, (long) end));
    }

    /**
     * Returns a List containing all the numbers that are palindromes in the range that is given from
     * start of type short to end of type short.
     * This is determined by using the iterative algorithm.
     *
     * @param start the start of the range, inclusive.
     * @param end   the end of the range, exclusive.
     * @return List containing all the numbers that are palindromes in the given range.
     */
    public static List<Short> getAllNumberPalindromesInRangeIterative(short start, short end) {
        return convertLongListToShortList(getAllNumberPalindromesInRangeIterative((long) start, (long) end));
    }

    /**
     * Returns a List containing all the numbers that are palindromes in the range that is given from
     * start of type byte to end of type byte.
     * This is determined by using the iterative algorithm.
     *
     * @param start the start of the range, inclusive.
     * @param end   the end of the range, exclusive.
     * @return List containing all the numbers that are palindromes in the given range.
     */
    public static List<Byte> getAllNumberPalindromesInRangeIterative(byte start, byte end) {
        return convertLongListToByteList(getAllNumberPalindromesInRangeIterative((long) start, (long) end));
    }

    /* Recursive */

    /**
     * Returns a boolean of whether the char array is a palindrome or not.
     * This is determined by using the recursive algorithm.
     *
     * @param chars char array containing the characters to be checked.
     * @return boolean of whether the char array is a palindrome or not.
     */
    public static boolean isCharArrayPalindromeRecursive(char[] chars) {
        if (chars.length < 1)
            return false;
        char[] formattedChars = convertAllCharsToUpperCase(chars);
        return recursion(formattedChars, 0, formattedChars.length - 1);
    }

    /**
     * The recursive algorithm.
     *
     * @param chars char array containing the characters to be checked.
     * @param start the left char being compared.
     * @param end   the right char being compared.
     * @return boolean of whether the char array is a palindrome or not.
     */
    private static boolean recursion(char[] chars, int start, int end) {
        if (start == end)
            return true;
        if (chars[start] != chars[end])
            return false;
        if (start < end + 1)
            return recursion(chars, ++start, --end);
        return true;
    }

    /**
     * Returns a boolean of whether the word of type String is a palindrome or not.
     * This is determined by using the recursive algorithm.
     *
     * @param word the word to be checked.
     * @return boolean of whether the word is a palindrome or not.
     */
    public static boolean isWordPalindromeRecursive(String word) {
        return isCharArrayPalindromeRecursive(word.toCharArray());
    }

    /**
     * Returns a boolean of whether the sentence of type String is a palindrome or not.
     * This is determined by using the recursive algorithm.
     *
     * @param sentence the sentence to be checked.
     * @return boolean of whether the sentence is a palindrome or not.
     */
    public static boolean isSentencePalindromeRecursive(String sentence) {
        String newSentence = sentence.replaceAll("[^a-zA-Z]", "");
        return isWordPalindromeRecursive(newSentence);
    }

    /**
     * Returns a boolean of whether the number of type byte (-128 to 127) is a palindrome or not.
     * This is determined by using the recursive algorithm.
     *
     * @param number the number to be checked.
     * @return boolean of whether the number is a palindrome or not.
     */
    public static boolean isNumberPalindromeRecursive(byte number) {
        return isWordPalindromeRecursive(String.valueOf(number));
    }

    /**
     * Returns a boolean of whether the number of type short (32,768 to 32,767) is a palindrome or not.
     * This is determined by using the recursive algorithm.
     *
     * @param number the number to be checked.
     * @return boolean of whether the number is a palindrome or not.
     */
    public static boolean isNumberPalindromeRecursive(short number) {
        return isWordPalindromeRecursive(String.valueOf(number));
    }

    /**
     * Returns a boolean of whether the number of type int (-2,147,483,648 to 2,147,483,647) is a palindrome or not.
     * This is determined by using the recursive algorithm.
     *
     * @param number the number to be checked.
     * @return boolean of whether the number is a palindrome or not.
     */
    public static boolean isNumberPalindromeRecursive(int number) {
        return isWordPalindromeRecursive(String.valueOf(number));
    }

    /**
     * Returns a boolean of whether the number of type long (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807) is a palindrome or not.
     * This is determined by using the recursive algorithm.
     *
     * @param number the number to be checked.
     * @return boolean of whether the number is a palindrome or not.
     */
    public static boolean isNumberPalindromeRecursive(long number) {
        return isWordPalindromeRecursive(String.valueOf(number));
    }

    /**
     * Returns a List containing all the numbers that are palindromes in the range that is given from
     * start of type long to end of type long.
     * This is determined by using the recursive algorithm.
     *
     * @param start the start of the range, inclusive.
     * @param end   the end of the range, exclusive.
     * @return List containing all the numbers that are palindromes in the given range.
     */
    public static List<Long> getAllNumberPalindromesInRangeRecursive(long start, long end) {
        List<Long> results = new ArrayList<>();
        for (long number = start; number != end; number++)
            if (isNumberPalindromeRecursive(number))
                results.add(number);
        return results;
    }

    /**
     * Returns a List containing all the numbers that are palindromes in the range that is given from
     * start of type int to end of type int.
     * This is determined by using the recursive algorithm.
     *
     * @param start the start of the range, inclusive.
     * @param end   the end of the range, exclusive.
     * @return List containing all the numbers that are palindromes in the given range.
     */
    public static List<Integer> getAllNumberPalindromesInRangeRecursive(int start, int end) {
        return convertLongListToIntegerList(getAllNumberPalindromesInRangeRecursive((long) start, (long) end));
    }

    /**
     * Returns a List containing all the numbers that are palindromes in the range that is given from
     * start of type short to end of type short.
     * This is determined by using the recursive algorithm.
     *
     * @param start the start of the range, inclusive.
     * @param end   the end of the range, exclusive.
     * @return List containing all the numbers that are palindromes in the given range.
     */
    public static List<Short> getAllNumberPalindromesInRangeRecursive(short start, short end) {
        return convertLongListToShortList(getAllNumberPalindromesInRangeRecursive((long) start, (long) end));
    }

    /**
     * Returns a List containing all the numbers that are palindromes in the range that is given from
     * start of type byte to end of type byte.
     * This is determined by using the recursive algorithm.
     *
     * @param start the start of the range, inclusive.
     * @param end   the end of the range, exclusive.
     * @return List containing all the numbers that are palindromes in the given range.
     */
    public static List<Byte> getAllNumberPalindromesInRangeRecursive(byte start, byte end) {
        return convertLongListToByteList(getAllNumberPalindromesInRangeRecursive((long) start, (long) end));
    }

    /**
     * Converts all letters in the given char array to capital letters if they aren't already.
     *
     * @param chars the start of the range, inclusive.
     * @return char array with the capitalized letters.
     */
    private static char[] convertAllCharsToUpperCase(char[] chars) {
        char[] formattedChars = new char[chars.length];
        for (int i = 0; i != chars.length; i++)
            if (Character.isLetter(chars[i]) && Character.isLowerCase(chars[i]))
                formattedChars[i] = Character.toUpperCase(chars[i]);
            else
                formattedChars[i] = chars[i];
        return formattedChars;
    }

    /**
     * Converts a List containing Long values to a List of Bytes.
     *
     * @param listOfLongs the List containing the Long values
     * @return the List containing the Byte values
     */
    private static List<Byte> convertLongListToByteList(List<Long> listOfLongs) {
        List<Byte> result = new ArrayList<>();
        for (Long i : listOfLongs)
            result.add(i.byteValue());
        return result;
    }

    /**
     * Converts a List containing Long values to a List of Shorts.
     *
     * @param listOfLongs the List containing the Long values
     * @return the List containing the Shorts values
     */
    private static List<Short> convertLongListToShortList(List<Long> listOfLongs) {
        List<Short> result = new ArrayList<>();
        for (Long i : listOfLongs)
            result.add(i.shortValue());
        return result;
    }

    /**
     * Converts a List containing Long values to a List of Integers.
     *
     * @param listOfLongs the List containing the Long values
     * @return the List containing the Integers values
     */
    private static List<Integer> convertLongListToIntegerList(List<Long> listOfLongs) {
        List<Integer> result = new ArrayList<>();
        for (Long i : listOfLongs)
            result.add(i.intValue());
        return result;
    }
}

Classe de teste palíndromo

package com.gr;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@DisplayName("Palindrome Class")
public class PalindromeTest {

    // Nested Iterative
    @Nested
    class Iterative {

        @Nested
        class Word {

            @Test
            void testEmptyString() {
                assertFalse(Palindrome.isWordPalindromeIterative(""));
            }

            @Test
            void testSingleLetter() {
                assertTrue(Palindrome.isWordPalindromeIterative("A"));
                assertTrue(Palindrome.isWordPalindromeIterative("a"));
            }

            @Test
            void testName() {
                assertTrue(Palindrome.isWordPalindromeIterative("ABBA"));
                assertTrue(Palindrome.isWordPalindromeIterative("Ava"));
                assertTrue(Palindrome.isWordPalindromeIterative("bob"));
                assertFalse(Palindrome.isWordPalindromeIterative("FAIL"));
                assertFalse(Palindrome.isWordPalindromeIterative("Fail"));
                assertFalse(Palindrome.isWordPalindromeIterative("fail"));
            }

            @Test
            void testWord() {
                assertTrue(Palindrome.isWordPalindromeIterative("madam"));
                assertTrue(Palindrome.isWordPalindromeIterative("Racecar"));
                assertTrue(Palindrome.isWordPalindromeIterative("RADAR"));
                assertFalse(Palindrome.isWordPalindromeIterative("FAIL"));
                assertFalse(Palindrome.isWordPalindromeIterative("Fail"));
                assertFalse(Palindrome.isWordPalindromeIterative("fail"));
            }
        }

        @Nested
        class Sentence {
            @Test
            void testEmptyString() {
                assertFalse(Palindrome.isSentencePalindromeIterative(""));
            }

            @Test
            void testSingleLetter() {
                assertTrue(Palindrome.isSentencePalindromeIterative("A"));
                assertTrue(Palindrome.isSentencePalindromeIterative("a"));
            }

            @Test
            void testSingleWord() {
                assertTrue(Palindrome.isSentencePalindromeIterative("madam"));
                assertTrue(Palindrome.isSentencePalindromeIterative("Racecar"));
                assertTrue(Palindrome.isSentencePalindromeIterative("RADAR"));
                assertFalse(Palindrome.isSentencePalindromeIterative("FAIL"));
                assertFalse(Palindrome.isSentencePalindromeIterative("Fail"));
                assertFalse(Palindrome.isSentencePalindromeIterative("fail"));
            }

            @Test
            void testSentence() {
                assertTrue(Palindrome.isSentencePalindromeIterative("Murder for a jar of red rum"));
                assertTrue(Palindrome.isSentencePalindromeIterative("Rats live on no evil star"));
                assertTrue(Palindrome.isSentencePalindromeIterative("step on no pets"));
                assertFalse(Palindrome.isSentencePalindromeIterative("This should fail"));
                assertFalse(Palindrome.isSentencePalindromeIterative("this should fail"));
            }

            @Test
            void testSentenceWithPunctuation() {
                assertTrue(Palindrome.isSentencePalindromeIterative("Do geese see God?"));
                assertTrue(Palindrome.isSentencePalindromeIterative("Live on time, emit no evil"));
                assertTrue(Palindrome.isSentencePalindromeIterative("live on time, emit no evil"));
                assertFalse(Palindrome.isSentencePalindromeIterative("Will this fail?"));
                assertFalse(Palindrome.isSentencePalindromeIterative("will this fail?"));
            }
        }

        @Nested
        class Number {

            @Test
            void testSingleLongNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative(0L));
                assertTrue(Palindrome.isNumberPalindromeIterative(1L));
                assertTrue(Palindrome.isNumberPalindromeIterative(3L));
            }

            @Test
            void testBiggerLongNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative(123454321L));
                assertTrue(Palindrome.isNumberPalindromeIterative(1234567890987654321L));
                assertFalse(Palindrome.isNumberPalindromeIterative(123456789L));
                assertFalse(Palindrome.isNumberPalindromeIterative(1234567890123456789L));
            }

            @Test
            void testNegativeLongNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative(-0L));
                assertFalse(Palindrome.isNumberPalindromeIterative(-123454321L));
                assertFalse(Palindrome.isNumberPalindromeIterative(-1234567890987654321L));
                assertFalse(Palindrome.isNumberPalindromeIterative(-123456789L));
                assertFalse(Palindrome.isNumberPalindromeIterative(-1234567890123456789L));
            }

            @Test
            void testSingleIntegerNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative(0));
                assertTrue(Palindrome.isNumberPalindromeIterative(1));
                assertTrue(Palindrome.isNumberPalindromeIterative(3));
            }

            @Test
            void testBiggerIntegerNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative(123454321));
                assertFalse(Palindrome.isNumberPalindromeIterative(123456789));
            }

            @Test
            void testNegativeIntegerNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative(-0));
                assertFalse(Palindrome.isNumberPalindromeIterative(-123454321));
                assertFalse(Palindrome.isNumberPalindromeIterative(-123456789));
            }

            @Test
            void testSingleShortNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative((short) 0));
                assertTrue(Palindrome.isNumberPalindromeIterative((short) 1));
                assertTrue(Palindrome.isNumberPalindromeIterative((short) 3));
            }

            @Test
            void testBiggerShortNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative((short) 12321));
                assertFalse(Palindrome.isNumberPalindromeIterative((short) 12345));
            }

            @Test
            void testNegativeShortNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative((short) -0));
                assertFalse(Palindrome.isNumberPalindromeIterative((short) -12321));
                assertFalse(Palindrome.isNumberPalindromeIterative((short) -12345));
            }

            @Test
            void testSingleByteNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative((byte) 0));
                assertTrue(Palindrome.isNumberPalindromeIterative((byte) 1));
                assertTrue(Palindrome.isNumberPalindromeIterative((byte) 3));
            }

            @Test
            void testBiggerByteNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative((byte) 121));
                assertFalse(Palindrome.isNumberPalindromeIterative((byte) 123));
            }

            @Test
            void testNegativeByteNumber() {
                assertTrue(Palindrome.isNumberPalindromeIterative((byte) -0));
                assertFalse(Palindrome.isNumberPalindromeIterative((byte) -121));
                assertFalse(Palindrome.isNumberPalindromeIterative((byte) -123));
            }

        }

        @Nested
        class NumberInRange {
            @Test
            void testEmptyRangeLong() {
                List<Long> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative(122L, 130L));
            }

            @Test
            void testRangeSingleLong() {
                List<Long> expected = new ArrayList<>() {
                    {
                        add(1L);
                        add(2L);
                        add(3L);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative(1L, 4L));
            }

            @Test
            void testRangeLong() {
                List<Long> expected = new ArrayList<>() {
                    {
                        add(121L);
                        add(131L);
                        add(141L);
                        add(151L);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative(120L, 155L));
            }

            @Test
            void testNegativeRangeLong() {
                List<Long> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative(-131L, 0L));
            }

            @Test
            void testEmptyRangeInteger() {
                List<Integer> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative(122, 130));
            }

            @Test
            void testRangeSingleInteger() {
                List<Integer> expected = new ArrayList<>() {
                    {
                        add(1);
                        add(2);
                        add(3);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative(1, 4));
            }

            @Test
            void testRangeInteger() {
                List<Integer> expected = new ArrayList<>() {
                    {
                        add(121);
                        add(131);
                        add(141);
                        add(151);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative(120, 155));
            }

            @Test
            void testNegativeRangeInteger() {
                List<Integer> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative(-131, 0));
            }

            @Test
            void testEmptyRangeShort() {
                List<Short> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative((short) 122, (short) 130));
            }

            @Test
            void testRangeSingleShort() {
                List<Short> expected = new ArrayList<>() {
                    {
                        add((short) 1);
                        add((short) 2);
                        add((short) 3);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative((short) 1, (short) 4));
            }

            @Test
            void testRangeShort() {
                List<Short> expected = new ArrayList<>() {
                    {
                        add((short) 121);
                        add((short) 131);
                        add((short) 141);
                        add((short) 151);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative((short) 120, (short) 155));
            }

            @Test
            void testNegativeRangeShort() {
                List<Short> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative((short) -131, (short) 0));
            }

            @Test
            void testEmptyRangeByte() {
                List<Byte> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative((byte) 122, (byte) 125));
            }

            @Test
            void testRangeSingleByte() {
                List<Byte> expected = new ArrayList<>() {
                    {
                        add((byte) 1);
                        add((byte) 2);
                        add((byte) 3);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative((byte) 1, (byte) 4));
            }

            @Test
            void testRangeByte() {
                List<Byte> expected = new ArrayList<>() {
                    {
                        add((byte) 101);
                        add((byte) 111);
                        add((byte) 121);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative((byte) 100, (byte) 125));
            }

            @Test
            void testNegativeRangeByte() {
                List<Byte> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeIterative((byte) -125, (byte) 0));
            }
        }
    }

    @Nested
    class Recursive {
        @Nested
        class Word {

            @Test
            void testEmptyString() {
                assertFalse(Palindrome.isWordPalindromeRecursive(""));
            }

            @Test
            void testSingleLetter() {
                assertTrue(Palindrome.isWordPalindromeRecursive("A"));
                assertTrue(Palindrome.isWordPalindromeRecursive("a"));
            }

            @Test
            void testName() {
                assertTrue(Palindrome.isWordPalindromeRecursive("ABBA"));
                assertTrue(Palindrome.isWordPalindromeRecursive("Ava"));
                assertTrue(Palindrome.isWordPalindromeRecursive("bob"));
                assertFalse(Palindrome.isWordPalindromeRecursive("FAIL"));
                assertFalse(Palindrome.isWordPalindromeRecursive("Fail"));
                assertFalse(Palindrome.isWordPalindromeRecursive("fail"));
            }

            @Test
            void testWord() {
                assertTrue(Palindrome.isWordPalindromeRecursive("madam"));
                assertTrue(Palindrome.isWordPalindromeRecursive("Racecar"));
                assertTrue(Palindrome.isWordPalindromeRecursive("RADAR"));
                assertFalse(Palindrome.isWordPalindromeRecursive("FAIL"));
                assertFalse(Palindrome.isWordPalindromeRecursive("Fail"));
                assertFalse(Palindrome.isWordPalindromeRecursive("fail"));
            }
        }

        @Nested
        class Sentence {
            @Test
            void testEmptyString() {
                assertFalse(Palindrome.isSentencePalindromeRecursive(""));
            }

            @Test
            void testSingleLetter() {
                assertTrue(Palindrome.isSentencePalindromeRecursive("A"));
                assertTrue(Palindrome.isSentencePalindromeRecursive("a"));
            }

            @Test
            void testSingleWord() {
                assertTrue(Palindrome.isSentencePalindromeRecursive("madam"));
                assertTrue(Palindrome.isSentencePalindromeRecursive("Racecar"));
                assertTrue(Palindrome.isSentencePalindromeRecursive("RADAR"));
                assertFalse(Palindrome.isSentencePalindromeRecursive("FAIL"));
                assertFalse(Palindrome.isSentencePalindromeRecursive("Fail"));
                assertFalse(Palindrome.isSentencePalindromeRecursive("fail"));
            }

            @Test
            void testSentence() {
                assertTrue(Palindrome.isSentencePalindromeRecursive("Murder for a jar of red rum"));
                assertTrue(Palindrome.isSentencePalindromeRecursive("Rats live on no evil star"));
                assertTrue(Palindrome.isSentencePalindromeRecursive("step on no pets"));
                assertFalse(Palindrome.isSentencePalindromeRecursive("This should fail"));
                assertFalse(Palindrome.isSentencePalindromeRecursive("this should fail"));
            }

            @Test
            void testSentenceWithPunctuation() {
                assertTrue(Palindrome.isSentencePalindromeRecursive("Do geese see God?"));
                assertTrue(Palindrome.isSentencePalindromeRecursive("Live on time, emit no evil"));
                assertTrue(Palindrome.isSentencePalindromeRecursive("live on time, emit no evil"));
                assertFalse(Palindrome.isSentencePalindromeRecursive("Will this fail?"));
                assertFalse(Palindrome.isSentencePalindromeRecursive("will this fail?"));
            }
        }

        @Nested
        class Number {

            @Test
            void testSingleLongNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive(0L));
                assertTrue(Palindrome.isNumberPalindromeRecursive(1L));
                assertTrue(Palindrome.isNumberPalindromeRecursive(3L));
            }

            @Test
            void testBiggerLongNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive(123454321L));
                assertTrue(Palindrome.isNumberPalindromeRecursive(1234567890987654321L));
                assertFalse(Palindrome.isNumberPalindromeRecursive(123456789L));
                assertFalse(Palindrome.isNumberPalindromeRecursive(1234567890123456789L));
            }

            @Test
            void testNegativeLongNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive(-0L));
                assertFalse(Palindrome.isNumberPalindromeRecursive(-123454321L));
                assertFalse(Palindrome.isNumberPalindromeRecursive(-1234567890987654321L));
                assertFalse(Palindrome.isNumberPalindromeRecursive(-123456789L));
                assertFalse(Palindrome.isNumberPalindromeRecursive(-1234567890123456789L));
            }

            @Test
            void testSingleIntegerNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive(0));
                assertTrue(Palindrome.isNumberPalindromeRecursive(1));
                assertTrue(Palindrome.isNumberPalindromeRecursive(3));
            }

            @Test
            void testBiggerIntegerNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive(123454321));
                assertFalse(Palindrome.isNumberPalindromeRecursive(123456789));
            }

            @Test
            void testNegativeIntegerNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive(-0));
                assertFalse(Palindrome.isNumberPalindromeRecursive(-123454321));
                assertFalse(Palindrome.isNumberPalindromeRecursive(-123456789));
            }

            @Test
            void testSingleShortNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive((short) 0));
                assertTrue(Palindrome.isNumberPalindromeRecursive((short) 1));
                assertTrue(Palindrome.isNumberPalindromeRecursive((short) 3));
            }

            @Test
            void testBiggerShortNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive((short) 12321));
                assertFalse(Palindrome.isNumberPalindromeRecursive((short) 12345));
            }

            @Test
            void testNegativeShortNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive((short) -0));
                assertFalse(Palindrome.isNumberPalindromeRecursive((short) -12321));
                assertFalse(Palindrome.isNumberPalindromeRecursive((short) -12345));
            }

            @Test
            void testSingleByteNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive((byte) 0));
                assertTrue(Palindrome.isNumberPalindromeRecursive((byte) 1));
                assertTrue(Palindrome.isNumberPalindromeRecursive((byte) 3));
            }

            @Test
            void testBiggerByteNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive((byte) 121));
                assertFalse(Palindrome.isNumberPalindromeRecursive((byte) 123));
            }

            @Test
            void testNegativeByteNumber() {
                assertTrue(Palindrome.isNumberPalindromeRecursive((byte) -0));
                assertFalse(Palindrome.isNumberPalindromeRecursive((byte) -121));
                assertFalse(Palindrome.isNumberPalindromeRecursive((byte) -123));
            }

        }

        @Nested
        class NumberInRange {
            @Test
            void testEmptyRangeLong() {
                List<Long> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive(122L, 130L));
            }

            @Test
            void testRangeSingleLong() {
                List<Long> expected = new ArrayList<>() {
                    {
                        add(1L);
                        add(2L);
                        add(3L);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive(1L, 4L));
            }

            @Test
            void testRangeLong() {
                List<Long> expected = new ArrayList<>() {
                    {
                        add(121L);
                        add(131L);
                        add(141L);
                        add(151L);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive(120L, 155L));
            }

            @Test
            void testNegativeRangeLong() {
                List<Long> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive(-131L, 0L));
            }

            @Test
            void testEmptyRangeInteger() {
                List<Integer> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive(122, 130));
            }

            @Test
            void testRangeSingleInteger() {
                List<Integer> expected = new ArrayList<>() {
                    {
                        add(1);
                        add(2);
                        add(3);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive(1, 4));
            }

            @Test
            void testRangeInteger() {
                List<Integer> expected = new ArrayList<>() {
                    {
                        add(121);
                        add(131);
                        add(141);
                        add(151);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive(120, 155));
            }

            @Test
            void testNegativeRangeInteger() {
                List<Integer> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive(-131, 0));
            }

            @Test
            void testEmptyRangeShort() {
                List<Short> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive((short) 122, (short) 130));
            }

            @Test
            void testRangeSingleShort() {
                List<Short> expected = new ArrayList<>() {
                    {
                        add((short) 1);
                        add((short) 2);
                        add((short) 3);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive((short) 1, (short) 4));
            }

            @Test
            void testRangeShort() {
                List<Short> expected = new ArrayList<>() {
                    {
                        add((short) 121);
                        add((short) 131);
                        add((short) 141);
                        add((short) 151);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive((short) 120, (short) 155));
            }

            @Test
            void testNegativeRangeShort() {
                List<Short> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive((short) -131, (short) 0));
            }

            @Test
            void testEmptyRangeByte() {
                List<Byte> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive((byte) 122, (byte) 125));
            }

            @Test
            void testRangeSingleByte() {
                List<Byte> expected = new ArrayList<>() {
                    {
                        add((byte) 1);
                        add((byte) 2);
                        add((byte) 3);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive((byte) 1, (byte) 4));
            }

            @Test
            void testRangeByte() {
                List<Byte> expected = new ArrayList<>() {
                    {
                        add((byte) 101);
                        add((byte) 111);
                        add((byte) 121);
                    }
                };
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive((byte) 100, (byte) 125));
            }

            @Test
            void testNegativeRangeByte() {
                List<Byte> expected = new ArrayList<>();
                assertEquals(expected, Palindrome.getAllNumberPalindromesInRangeRecursive((byte) -125, (byte) 0));
            }
        }
    }
}
```

Respostas

2 Bobby Aug 27 2020 at 23:51

Isso parece ótimo, agradável de ler, apesar da repetição.


package com.gr;

Os pacotes devem ser associados ao autor, então devem ser algo como com.github.lucifer.palindromepor exemplo. Mas dependendo se este código está sendo publicado ou não, não importa neste caso.


Este seria um ótimo exercício para programação orientada a objetos, criando uma interface e tendo duas implementações separadas:

public interface PalindromeTester;
public class IterativePalindromeTester implements PalindromeTester;
public class RecursivePalindromeTester implements PalindromeTester;

Isso resolveria metade de sua pergunta sobrecarregada. A outra metade é a coisa Number/ CharArray/ Word, você deve descartar isso do nome, pois é óbvio pelos parâmetros aceitos. A TI também limparia um pouco seu caso de teste, pois seriam duas classes de teste diferentes. Você ainda tem uma abstractclasse de teste e a estende e define apenas uma instância diferente de PalindromeTesteron BeforeEach.

Outra coisa é, se você pode conviver com o alargamento de determinados valores, você só pode fornecer um único método aceitando um arquivo long. Qualquer short/ intserá convertido automaticamente, mas isso, é claro, requer uma operação de alargamento sob o capô.

Há também Number/ BigInteger, que você pode querer incluir.

Em outra nota, você pode cair char[]em favor de CharSequence. O último é a base para muitas classes diferentes (incluindo String, portanto, nenhuma sobrecarga é necessária) e representa a intenção um pouco melhor. Com relação a isso, se você aceitar qualquer carta, incluindo idiomas estrangeiros, provavelmente desejará trabalhar em code-points ( int) em vez de chars. Em UTF-8/UTF-16, nem todas as letras são apenas um único byte, mas podem ser compostas por múltiplos bytes (até quatro, portanto int).


 * Returns a boolean of whether the number of type short (32,768 to 32,767)

Não inclua valores min/max como esse na documentação. Primeiro, é redundante, pois é óbvio pelo tipo usado. Em segundo lugar, é propenso a erros de digitação, como neste caso.


        List<Long> results = new ArrayList<>();
        for (long number = start; number != end; number++)
            if (isNumberPalindromeRecursive(number))
                results.add(number);

Esteja ciente de que isso é autoboxing, o que significa que uma primitiva é convertida automaticamente em uma Objectinstância.


for (int i = 0; i != formattedChars.length / 2; i++)

Primeiro, sou um defensor persistente de nomes "reais" para variáveis ​​de loop, como indexou counter.

Em segundo lugar, você deve revisar a condição de interrupção para ser mais robusta, verificando se o valor é igual ou maior que a metade do comprimento.


        boolean isPalindrome = true;
        for (int i = 0; i != formattedChars.length / 2; i++)
            if (formattedChars[i] != formattedChars[(formattedChars.length - 1) - i]) {
                isPalindrome = false;
                break;
            }
        return isPalindrome;

Não armazene o resultado, devolva-o diretamente.

        for (int i = 0; i != formattedChars.length / 2; i++)
            if (formattedChars[i] != formattedChars[(formattedChars.length - 1) - i])
                return false;
        
        return true;
```
1 TorbenPutkonen Aug 27 2020 at 11:14

Ter uma interface comum para o algoritmo resolveria a duplicação de código entre testes para diferentes implementações. Você cria um conjunto de testes que qualquer implementação da interface deve atender e, em seguida, lança diferentes implementações nele (consulte o L em princípios SOLID ).

Para testar um grande conjunto de entradas de string simples, coloque as entradas válidas em uma matriz e as inválidas em outra e crie dois testes que fazem um loop em cada matriz.