Mutation Fuzzing for Jest Test Suites
Your task is to implement mutation fuzzing within a Jest test suite for a given TypeScript function. Mutation fuzzing is a technique to automatically generate variations of your input data to uncover edge cases and potential bugs that might be missed by manual test case creation. This challenge will test your understanding of Jest, TypeScript, and basic principles of generating mutated data.
Problem Description
You will be provided with a simple TypeScript function that performs some operation on an input value. Your goal is to:
- Define a Jest test suite for this function.
- Implement mutation fuzzing within the test suite. This involves generating multiple variations of a base input.
- Assert that the function behaves as expected for all generated mutated inputs.
The core idea is to take a "seed" input and apply small, systematic changes (mutations) to it. If the function's behavior changes unexpectedly after a mutation, it indicates a potential bug.
Key Requirements:
- Use Jest as the testing framework.
- Write tests in TypeScript.
- Define a clear set of mutations to apply to the input data.
- Each mutated input should be passed to the function under test.
- An assertion should be made for each mutated input. The assertion should be consistent with what a well-behaved function would produce.
Expected Behavior:
For a given "seed" input, the function should produce a predictable output. When mutations are applied to the seed, the output might change, but the change should be logical and consistent with the mutation. The fuzzing process should identify cases where the function crashes, throws unexpected errors, or returns an illogical result given the mutated input.
Edge Cases to Consider:
- Empty strings, null, undefined inputs.
- Extremely large or small numbers.
- Special characters in strings.
- Deeply nested data structures (if applicable to the function).
Examples
Let's assume our function under test is a simple string manipulation function:
// Function to be tested
function reverseString(str: string): string {
if (typeof str !== 'string') {
throw new Error('Input must be a string.');
}
return str.split('').reverse().join('');
}
Example 1: Basic Mutation
- Seed Input:
"hello" - Mutations:
- Append a character:
"hello!" - Prepend a character:
"-hello" - Change a character:
"hEllo"
- Append a character:
- Expected Behavior: The
reverseStringfunction should correctly reverse each mutated string.reverseString("hello!")should return"!olleh"reverseString("-hello")should return"olleh-"reverseString("hEllo")should return"ollEh"
Example 2: Edge Case Mutation
- Seed Input:
""(empty string) - Mutations:
- Add whitespace:
" " - Add special characters:
"!@#$"
- Add whitespace:
- Expected Behavior:
reverseString(" ")should return" "reverseString("!@#$")should return"$#@!"
Example 3: Invalid Input Mutation (Testing Error Handling)
- Seed Input:
"world"(This is a valid input for the initial seed) - Mutations:
nullundefined123(a number)
- Expected Behavior: The
reverseStringfunction should throw anErrorwith the message "Input must be a string." for these mutated inputs. Your test should assert that the function throws this specific error.
Constraints
- The function under test will be provided as a TypeScript module.
- Mutations should be applied to a single input parameter for the function.
- The fuzzing should cover at least 5 distinct mutation strategies (e.g., append, prepend, replace, delete, insert).
- The test suite should run efficiently; avoid excessively complex or computationally expensive mutations that would make the test suite impractical.
Notes
- Consider using libraries like
jest-eachfor cleaner iteration over multiple test cases. - Think about how to structure your mutation logic. You might want a set of functions, each responsible for a specific type of mutation.
- For the purpose of this challenge, the "expected output" for a mutated input is generally derived from applying the same logic as the original function, but to the mutated data. For error-throwing cases, your assertion should check for the specific error.
- The goal is to demonstrate the process of mutation fuzzing, not necessarily to find subtle bugs in a trivial function. Your solution should be extensible for more complex functions.