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.
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.
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.
If n < 0
or n > 20
, the longRecursive
method must throw an IllegalArgumentException
;
otherwise, if (n == 0)
(the stopping condition), longRecursive
must return a value of 1;
otherwise, longRecursive
must return the correct factorial function value, using the recursive definition.
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.
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:
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.
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.
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).
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.
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.
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
):
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.
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.
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
.
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
.
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.
The recursive
method must follow the definition shown in (4), using recursion to determine whether input
is a palindrome.
If input
is a palindrome, the recursive
method must return true
; otherwise, the method must return false
.
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.
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.)
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:
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.
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.
The test method must receive the data for a single test case as a parameter.
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
.
Define a second test method with the appropriate name (following the usual conventions for naming a test method) and annotations for the following specifications:
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.
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.
The test method must receive the data for a single test case as a parameter.
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
.