Recursion: Basic Implementation Tasks

Recursive implementations of factorial function and palindrome test.

To explore recursion in Java, we’ll complete the implementations for two of the examples described in the introduction: factorials and palindromes. As you work through the tasks below, don’t forget to commit frequently—especially prior to making a potentially breaking change to code that is (at least partially) working.

Preparation

Use the URL provided by your instructor to accept the GitHub Classroom assignment for this exercise, clone the repository that’s created automatically for you to your local system, and open it in your IDE.

Factorials

Implementation

Declaration

In the edu.cnm.deepdive.Factorials class, the longRecursive method is declared as follows:

public static long longRecursive(int n) throws IllegalArgumentException

Please do not change the modifiers, return type, method name, parameter type/number/order, or throws clause shown above.

For more method declaration details, see the Javadoc documentation.

Specifications

  1. If n < 0 or n > 20, the longRecursive method must throw an IllegalArgumentException;

  2. otherwise, if (n == 0) (the stopping condition), longRecursive must return a value of 1;

  3. otherwise, longRecursive must return the correct factorial function value, using the recursive definition.

Tips

Tests

  1. Create a test class (in the src/test/java source root) with the fully qualified name edu.cnm.deepdive.FactorialsTest.

    Hint: IntelliJ IDEA can create the test class, with the required name, in the required location, using the Code/Generate/Test command, or the Create Test context action (accessed by clicking on the class name in the class declaration, then typing [Alt]-[Enter] on Windows and Linux, or [Option]-[Return] on OS X.)

    To avoid confusion, don’t check any of the method names at the bottom of the Create Test dialog.

  2. In the test class, define a test method with the appropriate name (following the usual conventions for naming a test method) and annotations for the following specifications:

    1. The method must serve as a parameterized test, reading and testing all test cases in the factorials-long.csv file, located in the edu/cnm/deepdive subdirectory of the src/test/resources root.

    2. Each row of the factorials-long.csv file (after the header row, which must be skipped) contains a single test case, with the value of n in the first column, and the correct (i.e. expected) value of n! in the second column.

    3. The test method must receive the data for a single test case as parameters (remember that these must be in the same order as they appear in the CSV file).

    4. The test method must invoke the Factorials.longRecursive method with the value of n specified in the current test case, and use the appropriate JUnit5 assertion to compare the result returned (i.e. the actual value) with the expected value specified in the test case.

    5. Optionally, you may use the useHeadersInDisplayName element of the @CsvFileSource annotation, or the name element of the @ParameterizedTest annotation, to include test case values in the name displayed for each test method invocation. For more information, see @CsvFileSource and “Customizing Display Names”. This option applies to all of the test methods created in this exercise.

  3. Define an additional test method (following the usual conventions for naming a test method) to test exceptional cases (that is, where n < 0 or n > 20):

    1. The method must serve as a parameterized test, reading and testing all test cases in the factorials-negative.csv and factorials-long-overflow.csv files, located in the edu/cnm/deepdive subdirectory of the src/test/resources root.

      Tip: The resources element of the @CsvFileSource annotation is array-valued: It can take one or more filenames as a value; in the latter case, the multiple filenames (each quoted separately) must be enclosed in a set of curly braces.

    2. Each row of the factorials-invalid.csv and factorials-long-overflow.csv file (after the header row, which must be used in the display names or skipped) contains a single test case, with the value of n in the first column, and the expected exception in the second column.

    3. The test method must receive the data for a single test case as parameters (remember that these must be in the same order as they appear in the CSV file). Note that the property parameter type for an exception class is Class<? extends Throwable>—that is, an instance of the Class type, for a subclass of Throwable.

    4. The test method must use the JUnit5 assertThrows method to assert that when the Factorials.longRecursive method is invoked for the given value of n, an instance of the specified exception class is thrown. Remember that the test method must not invoke the method prior to making this assertion, but must instead include the invocation in the execute method of an instance of Executable (usually specified as a lambda) passed as an argument to assertThrows.

Palindromes

Implementation

Declaration

In the edu.cnm.deepdive.Palindromes class, the recursive method is declared as follows:

public static boolean recursive(String input)

Please do not change the modifiers, return type, method name, or parameter type/number/order shown above.

For more method declaration details, see the Javadoc documentation.

Specifications

  1. The recursive method must follow the definition shown in (4), using recursion to determine whether input is a palindrome.

  2. If input is a palindrome, the recursive method must return true; otherwise, the method must return false.

  3. For now, the method must assume that input will not contain any punctuation or spaces, and that all characters will use the same letter case. More specifically, this method must not (at this time) attempt to deal with (by removing or altering) any whitespace or punctuation characters, or any mixed letter-casing.

Tests

  1. Create a test class (in the src/test/java source root) with the fully qualified name edu.cnm.deepdive.PalindromesTest.

    (See test steps for factorials for tips on using IntelliJ IDEA shortcuts to simplify this step.)

  2. In the test class, define a test method with the appropriate name (following the usual conventions for naming a test method) and annotations for the following specifications:

    1. The method must serve as a parameterized test, reading and testing all test cases in the palindromes-normalized.csv file, located in the edu/cnm/deepdive subdirectory of the src/test/resources root. All test cases in this file are palindromes.

    2. Each row of the palindromes-normalized.csv file (after the header row, which must be used in the display names or skipped) contains a single test case, with the value of input in the only column.

    3. The test method must receive the data for a single test case as a parameter.

    4. The test method must invoke the Palindromes.recursive method with the value of input specified in the current test case, and use the appropriate JUnit5 method to assert that the result returned (i.e. the actual value) is true.

  3. Define a second test method with the appropriate name (following the usual conventions for naming a test method) and annotations for the following specifications:

    1. The method must serve as a parameterized test, reading and testing all test cases in the non-palindromes-normalized.csv file, located in the edu/cnm/deepdive subdirectory of the src/test/resources root. None of the test cases in this file are palindromes.

    2. Each row of the palindromes-normalized.csv file (after the header row, which must be skipped) contains a single test case, with the value of input in the only column.

    3. The test method must receive the data for a single test case as a parameter.

    4. The test method must invoke the Palindromes.recursive method with the value of input specified in the current test case, and use the appropriate JUnit5 method to assert that the result returned (i.e. the actual value) is false.