Testing and Debugging Strategies

1. Test Case Generation Strategies

Strategy Description Application
Equivalence Partitioning Divide input domain into classes where behavior is same Test one value from each partition instead of all values
Boundary Testing Test at and around boundaries of input ranges min-1, min, min+1, max-1, max, max+1
Random Testing Generate random inputs to find unexpected failures Fuzzing, stress testing with random data
Property-based Testing Define properties that should hold for all inputs Idempotence, commutativity, reversibility
Coverage-driven Generate tests to maximize code coverage Branch coverage, path coverage metrics

Example 1: Test Case Generator for Sorting Function

class SortTestGenerator {
  // Equivalence partitioning
  static getPartitions() {
    return {
      empty: [],
      single: [42],
      sorted: [1, 2, 3, 4, 5],
      reverse: [5, 4, 3, 2, 1],
      duplicates: [3, 1, 4, 1, 5, 9, 2, 6, 5],
      allSame: [7, 7, 7, 7],
      negative: [-5, -1, -10, 3, 0]
    };
  }
  
  // Boundary value testing
  static getBoundaryTests() {
    return [
      [],                    // min size (0)
      [1],                   // min size + 1 (1)
      [1, 2],                // 2 elements
      Array(1000).fill(0).map((_, i) => i),  // large sorted
      [Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER],
      [0, -0, 0.1, -0.1]    // floating point boundaries
    ];
  }
  
  // Random test generation
  static generateRandomTests(count = 100) {
    const tests = [];
    for (let i = 0; i < count; i++) {
      const size = Math.floor(Math.random() * 1000);
      const arr = Array(size).fill(0).map(() => 
        Math.floor(Math.random() * 2000) - 1000
      );
      tests.push(arr);
    }
    return tests;
  }
  
  // Property-based: sort should be idempotent
  static verifyIdempotence(sortFn, arr) {
    const sorted1 = sortFn([...arr]);
    const sorted2 = sortFn([...sorted1]);
    return JSON.stringify(sorted1) === JSON.stringify(sorted2);
  }
  
  // Property-based: sort should preserve elements
  static verifyPreservation(sortFn, arr) {
    const original = [...arr].sort();
    const result = sortFn([...arr]).sort();
    return JSON.stringify(original) === JSON.stringify(result);
  }
  
  // Run comprehensive test suite
  static runAllTests(sortFn) {
    console.log('Testing Partitions...');
    const partitions = this.getPartitions();
    for (const [name, arr] of Object.entries(partitions)) {
      const sorted = sortFn([...arr]);
      const passed = this.isSorted(sorted) && 
                     this.verifyPreservation(sortFn, arr);
      console.log(`  ${name}: ${passed ? 'PASS' : 'FAIL'}`);
    }
    
    console.log('Testing Boundaries...');
    const boundaries = this.getBoundaryTests();
    boundaries.forEach((arr, i) => {
      const sorted = sortFn([...arr]);
      const passed = this.isSorted(sorted);
      console.log(`  Boundary ${i}: ${passed ? 'PASS' : 'FAIL'}`);
    });
    
    console.log('Random Testing...');
    const randomTests = this.generateRandomTests(50);
    let passCount = 0;
    randomTests.forEach(arr => {
      if (this.isSorted(sortFn([...arr])) && 
          this.verifyPreservation(sortFn, arr)) {
        passCount++;
      }
    });
    console.log(`  Random: ${passCount}/50 PASS`);
  }
  
  static isSorted(arr) {
    for (let i = 1; i < arr.length; i++) {
      if (arr[i] < arr[i-1]) return false;
    }
    return true;
  }
}

// Example usage
function bubbleSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  return arr;
}

SortTestGenerator.runAllTests(bubbleSort);

Example 2: Automated Test Case Generator with Coverage

class TestCaseGenerator {
  constructor(targetFunction) {
    this.targetFunction = targetFunction;
    this.coverage = new Set();
  }
  
  // Generate tests to maximize branch coverage
  generateBranchCoverageTests(inputRanges) {
    const tests = [];
    
    // For each input parameter, try boundary values
    inputRanges.forEach((range, paramIndex) => {
      const { min, max, type } = range;
      
      if (type === 'number') {
        // Boundary values for numbers
        const values = [
          min - 1,           // below range
          min,               // minimum
          min + 1,           // just above min
          Math.floor((min + max) / 2),  // middle
          max - 1,           // just below max
          max,               // maximum
          max + 1,           // above range
          0,                 // zero (special)
          -1,                // negative boundary
          null,              // null check
          undefined,         // undefined check
          NaN                // NaN check
        ];
        
        values.forEach(val => {
          const testCase = this.createTestCase(paramIndex, val, inputRanges);
          tests.push(testCase);
        });
      } else if (type === 'array') {
        // Array-specific test cases
        const arrayTests = [
          [],                // empty
          [min],             // single element
          [min, max],        // two elements
          Array(max).fill(min),  // large array
          null,              // null array
          undefined          // undefined array
        ];
        
        arrayTests.forEach(arr => {
          const testCase = this.createTestCase(paramIndex, arr, inputRanges);
          tests.push(testCase);
        });
      }
    });
    
    return tests;
  }
  
  createTestCase(targetParam, value, ranges) {
    // Create test case with one parameter varied
    const testCase = ranges.map((range, i) => {
      if (i === targetParam) return value;
      
      // Use middle value for other params
      if (range.type === 'number') {
        return Math.floor((range.min + range.max) / 2);
      } else if (range.type === 'array') {
        return [range.min, range.max];
      }
    });
    
    return testCase;
  }
  
  // Execute tests and track coverage
  runTests(testCases) {
    const results = [];
    
    testCases.forEach((testCase, index) => {
      try {
        const result = this.targetFunction(...testCase);
        const branchId = this.getBranchSignature(testCase, result);
        this.coverage.add(branchId);
        
        results.push({
          index,
          input: testCase,
          output: result,
          passed: true,
          branch: branchId
        });
      } catch (error) {
        results.push({
          index,
          input: testCase,
          error: error.message,
          passed: false
        });
      }
    });
    
    return {
      results,
      coverage: this.coverage.size,
      totalTests: testCases.length,
      passRate: results.filter(r => r.passed).length / results.length
    };
  }
  
  getBranchSignature(input, output) {
    // Simple branch signature based on input/output characteristics
    return `${input.map(i => typeof i).join(',')}->${typeof output}`;
  }
  
  // Report coverage gaps
  suggestAdditionalTests() {
    // Suggest tests for uncovered scenarios
    return [
      'Test with null inputs',
      'Test with extreme values',
      'Test with empty collections',
      'Test with duplicate elements',
      'Test with negative numbers'
    ];
  }
}

// Example: Testing binary search function
function binarySearch(arr, target) {
  let left = 0, right = arr.length - 1;
  
  while (left <= right) {
    const mid = Math.floor((left + right) / 2);
    if (arr[mid] === target) return mid;
    if (arr[mid] < target) left = mid + 1;
    else right = mid - 1;
  }
  
  return -1;
}

const generator = new TestCaseGenerator(binarySearch);
const testCases = generator.generateBranchCoverageTests([
  { min: 0, max: 100, type: 'array' },  // array parameter
  { min: -100, max: 100, type: 'number' }  // target parameter
]);

const report = generator.runTests(testCases);
console.log(`Coverage: ${report.coverage} branches`);
console.log(`Pass Rate: ${(report.passRate * 100).toFixed(2)}%`);
Note: Effective test generation combines multiple strategies. Start with equivalence partitioning for broad coverage, add boundary tests for edge cases, then use random testing to find unexpected failures. Property-based testing ensures algorithmic correctness across all inputs.

2. Edge Case Identification Techniques

Edge Case Category Examples Why Critical
Empty/Null Input [], null, undefined, "" Most functions fail without proper checks
Single Element [1], "a", single node Breaks algorithms expecting pairs/comparisons
Duplicates [1,1,1], "aaa" Unique vs non-unique assumptions
Sorted/Reverse [1,2,3], [3,2,1] Best/worst case performance
Numeric Extremes MAX_INT, MIN_INT, 0, -0, Infinity Overflow, underflow, division by zero
Special Characters whitespace, unicode, emoji String processing edge cases

Example 1: Comprehensive Edge Case Checker

class EdgeCaseIdentifier {
  static identifyArrayEdgeCases(arr) {
    const edgeCases = [];
    
    // Empty check
    if (arr === null || arr === undefined) {
      edgeCases.push({ type: 'NULL_INPUT', severity: 'HIGH' });
    }
    
    if (arr && arr.length === 0) {
      edgeCases.push({ type: 'EMPTY_ARRAY', severity: 'HIGH' });
    }
    
    // Single element
    if (arr && arr.length === 1) {
      edgeCases.push({ type: 'SINGLE_ELEMENT', severity: 'MEDIUM' });
    }
    
    // All duplicates
    if (arr && new Set(arr).size === 1) {
      edgeCases.push({ type: 'ALL_DUPLICATES', severity: 'MEDIUM' });
    }
    
    // Already sorted
    if (arr && this.isSorted(arr)) {
      edgeCases.push({ type: 'ALREADY_SORTED', severity: 'LOW' });
    }
    
    // Reverse sorted
    if (arr && this.isSorted([...arr].reverse())) {
      edgeCases.push({ type: 'REVERSE_SORTED', severity: 'MEDIUM' });
    }
    
    // Contains extremes
    if (arr && arr.some(x => 
      x === Number.MAX_SAFE_INTEGER || 
      x === Number.MIN_SAFE_INTEGER ||
      x === Infinity ||
      x === -Infinity
    )) {
      edgeCases.push({ type: 'EXTREME_VALUES', severity: 'HIGH' });
    }
    
    // Contains special values
    if (arr && arr.some(x => 
      x === 0 || x === -0 || Number.isNaN(x) || x === null
    )) {
      edgeCases.push({ type: 'SPECIAL_VALUES', severity: 'HIGH' });
    }
    
    // Very large array
    if (arr && arr.length > 100000) {
      edgeCases.push({ type: 'LARGE_INPUT', severity: 'MEDIUM' });
    }
    
    return edgeCases;
  }
  
  static isSorted(arr) {
    for (let i = 1; i < arr.length; i++) {
      if (arr[i] < arr[i-1]) return false;
    }
    return true;
  }
  
  static identifyStringEdgeCases(str) {
    const edgeCases = [];
    
    if (str === null || str === undefined) {
      edgeCases.push({ type: 'NULL_STRING', severity: 'HIGH' });
    }
    
    if (str === '') {
      edgeCases.push({ type: 'EMPTY_STRING', severity: 'HIGH' });
    }
    
    if (str && str.length === 1) {
      edgeCases.push({ type: 'SINGLE_CHAR', severity: 'MEDIUM' });
    }
    
    // All same character
    if (str && new Set(str).size === 1) {
      edgeCases.push({ type: 'ALL_SAME_CHAR', severity: 'MEDIUM' });
    }
    
    // Contains whitespace
    if (str && /\s/.test(str)) {
      edgeCases.push({ type: 'CONTAINS_WHITESPACE', severity: 'LOW' });
    }
    
    // Contains unicode/emoji
    if (str && /[^\x00-\x7F]/.test(str)) {
      edgeCases.push({ type: 'UNICODE_CHARACTERS', severity: 'MEDIUM' });
    }
    
    // Very long string
    if (str && str.length > 100000) {
      edgeCases.push({ type: 'LARGE_STRING', severity: 'MEDIUM' });
    }
    
    return edgeCases;
  }
  
  // Generate test cases for identified edge cases
  static generateEdgeCaseTests(dataType) {
    if (dataType === 'array') {
      return [
        { input: null, description: 'Null array' },
        { input: undefined, description: 'Undefined array' },
        { input: [], description: 'Empty array' },
        { input: [42], description: 'Single element' },
        { input: [5, 5, 5, 5], description: 'All duplicates' },
        { input: [1, 2, 3, 4, 5], description: 'Already sorted' },
        { input: [5, 4, 3, 2, 1], description: 'Reverse sorted' },
        { input: [Number.MAX_SAFE_INTEGER], description: 'Max value' },
        { input: [Number.MIN_SAFE_INTEGER], description: 'Min value' },
        { input: [0, -0], description: 'Zero and negative zero' },
        { input: [NaN, null, undefined], description: 'Special values' },
        { input: Array(100000).fill(1), description: 'Large array' }
      ];
    } else if (dataType === 'string') {
      return [
        { input: null, description: 'Null string' },
        { input: undefined, description: 'Undefined string' },
        { input: '', description: 'Empty string' },
        { input: 'a', description: 'Single character' },
        { input: 'aaaa', description: 'All same character' },
        { input: '   ', description: 'Only whitespace' },
        { input: 'hello world', description: 'Contains spaces' },
        { input: '你好', description: 'Unicode characters' },
        { input: '👋🌍', description: 'Emoji characters' },
        { input: 'a'.repeat(100000), description: 'Very long string' }
      ];
    }
    
    return [];
  }
}

// Example usage
const testArray = [1, 1, 1, 1];
const arrayEdgeCases = EdgeCaseIdentifier.identifyArrayEdgeCases(testArray);
console.log('Array Edge Cases:', arrayEdgeCases);

const testString = '👋 Hello';
const stringEdgeCases = EdgeCaseIdentifier.identifyStringEdgeCases(testString);
console.log('String Edge Cases:', stringEdgeCases);

// Generate comprehensive test suite
const arrayTests = EdgeCaseIdentifier.generateEdgeCaseTests('array');
console.log(`Generated ${arrayTests.length} array edge case tests`);
Warning: Edge cases are where most bugs hide. Always test: null/undefined, empty inputs, single elements, all duplicates, already sorted data, extreme values (MAX/MIN), special values (0, NaN, Infinity), and very large inputs.

3. Boundary Value Testing

Boundary Type Test Values Pattern
Numeric Range [min, max] min-1, min, min+1, max-1, max, max+1 Test below, at, above boundaries
Array Size 0, 1, 2, n-1, n, n+1 Empty, single, pair, full, overflow
String Length 0, 1, max-1, max, max+1 Empty, single char, at limit
Loop Iterations 0, 1, n-1, n No iteration, single, last, complete
Index Access -1, 0, 1, length-2, length-1, length Below start, start, end, beyond end

Example 1: Boundary Value Test Generator

class BoundaryValueTester {
  // Generate boundary tests for numeric range
  static generateNumericBoundaryTests(min, max) {
    return {
      belowMin: min - 1,
      atMin: min,
      justAboveMin: min + 1,
      midpoint: Math.floor((min + max) / 2),
      justBelowMax: max - 1,
      atMax: max,
      aboveMax: max + 1,
      zero: 0,  // Special boundary
      negativeOne: -1  // Special boundary
    };
  }
  
  // Test array index boundaries
  static testArrayBoundaries(fn, arr) {
    const results = [];
    const indices = [
      -2, -1,                    // Below bounds
      0, 1,                      // Start
      arr.length - 2, arr.length - 1,  // End
      arr.length, arr.length + 1       // Beyond bounds
    ];
    
    indices.forEach(index => {
      try {
        const result = fn(arr, index);
        results.push({
          index,
          result,
          passed: true,
          boundary: this.classifyIndexBoundary(index, arr.length)
        });
      } catch (error) {
        results.push({
          index,
          error: error.message,
          passed: false,
          boundary: this.classifyIndexBoundary(index, arr.length)
        });
      }
    });
    
    return results;
  }
  
  static classifyIndexBoundary(index, length) {
    if (index < 0) return 'BELOW_START';
    if (index === 0) return 'AT_START';
    if (index === length - 1) return 'AT_END';
    if (index === length) return 'JUST_BEYOND_END';
    if (index > length) return 'BEYOND_END';
    return 'WITHIN_BOUNDS';
  }
  
  // Test loop boundary conditions
  static testLoopBoundaries(loopFn, maxIterations) {
    const iterationTests = [
      0,                    // No iterations
      1,                    // Single iteration
      2,                    // Two iterations
      maxIterations - 1,    // One before max
      maxIterations,        // Exactly max
      maxIterations + 1     // One beyond max
    ];
    
    const results = [];
    
    iterationTests.forEach(n => {
      try {
        const startTime = performance.now();
        const result = loopFn(n);
        const duration = performance.now() - startTime;
        
        results.push({
          iterations: n,
          result,
          duration,
          passed: true
        });
      } catch (error) {
        results.push({
          iterations: n,
          error: error.message,
          passed: false
        });
      }
    });
    
    return results;
  }
  
  // Comprehensive boundary test suite
  static runBoundaryTestSuite(functionUnderTest, config) {
    const report = {
      function: functionUnderTest.name,
      timestamp: new Date().toISOString(),
      tests: []
    };
    
    // Test numeric boundaries
    if (config.numericRange) {
      const { min, max } = config.numericRange;
      const boundaries = this.generateNumericBoundaryTests(min, max);
      
      Object.entries(boundaries).forEach(([label, value]) => {
        try {
          const result = functionUnderTest(value);
          report.tests.push({
            type: 'NUMERIC_BOUNDARY',
            label,
            input: value,
            output: result,
            passed: true
          });
        } catch (error) {
          report.tests.push({
            type: 'NUMERIC_BOUNDARY',
            label,
            input: value,
            error: error.message,
            passed: false
          });
        }
      });
    }
    
    // Test array size boundaries
    if (config.arrayTest) {
      const sizes = [0, 1, 2, 10, 100, 1000];
      
      sizes.forEach(size => {
        const testArray = Array(size).fill(0).map((_, i) => i);
        
        try {
          const result = functionUnderTest(testArray);
          report.tests.push({
            type: 'ARRAY_SIZE_BOUNDARY',
            size,
            output: result,
            passed: true
          });
        } catch (error) {
          report.tests.push({
            type: 'ARRAY_SIZE_BOUNDARY',
            size,
            error: error.message,
            passed: false
          });
        }
      });
    }
    
    // Calculate statistics
    const passedTests = report.tests.filter(t => t.passed).length;
    report.summary = {
      total: report.tests.length,
      passed: passedTests,
      failed: report.tests.length - passedTests,
      passRate: (passedTests / report.tests.length * 100).toFixed(2) + '%'
    };
    
    return report;
  }
}

// Example 1: Testing array access function
function getElement(arr, index) {
  if (index < 0 || index >= arr.length) {
    throw new Error('Index out of bounds');
  }
  return arr[index];
}

const arrayBoundaryTests = BoundaryValueTester.testArrayBoundaries(
  getElement,
  [10, 20, 30, 40, 50]
);
console.log('Array Boundary Tests:', arrayBoundaryTests);

// Example 2: Testing numeric function
function factorial(n) {
  if (n < 0) throw new Error('Negative input');
  if (n === 0 || n === 1) return 1;
  return n * factorial(n - 1);
}

const numericReport = BoundaryValueTester.runBoundaryTestSuite(
  factorial,
  { numericRange: { min: 0, max: 10 } }
);
console.log('Factorial Boundary Report:', numericReport.summary);
Note: Boundary value testing catches off-by-one errors and range validation bugs. Always test: minimum boundary (min, min-1, min+1), maximum boundary (max, max-1, max+1), zero/empty, and typical values. This reveals fencepost errors and improper range checking.

4. Performance Profiling and Optimization

Technique Measures Use Case
Time Complexity Measurement Execution time vs input size Verify O(n), O(n log n), O(n²) complexity
Space Complexity Profiling Memory allocation patterns Detect memory leaks, excessive allocations
Benchmarking Operations per second Compare algorithm implementations
Hotspot Analysis Time spent in each function Identify bottlenecks for optimization
Asymptotic Analysis Growth rate comparison Predict scalability to large inputs

Example 1: Performance Profiler with Time Complexity Verification

class PerformanceProfiler {
  constructor() {
    this.results = [];
  }
  
  // Measure execution time for various input sizes
  profileTimeComplexity(fn, inputGenerator, sizes = [10, 100, 1000, 10000]) {
    const measurements = [];
    
    sizes.forEach(size => {
      const input = inputGenerator(size);
      
      // Warmup
      for (let i = 0; i < 3; i++) {
        fn(inputGenerator(size));
      }
      
      // Actual measurement (multiple runs for accuracy)
      const times = [];
      for (let i = 0; i < 10; i++) {
        const testInput = inputGenerator(size);
        const start = performance.now();
        fn(testInput);
        const end = performance.now();
        times.push(end - start);
      }
      
      // Use median to reduce outlier impact
      times.sort((a, b) => a - b);
      const medianTime = times[Math.floor(times.length / 2)];
      
      measurements.push({
        size,
        time: medianTime,
        avgTime: times.reduce((a, b) => a + b) / times.length
      });
    });
    
    // Analyze complexity
    const complexity = this.inferComplexity(measurements);
    
    return {
      measurements,
      estimatedComplexity: complexity,
      report: this.generateReport(measurements, complexity)
    };
  }
  
  // Infer time complexity from measurements
  inferComplexity(measurements) {
    if (measurements.length < 2) return 'UNKNOWN';
    
    // Calculate ratios
    const ratios = [];
    for (let i = 1; i < measurements.length; i++) {
      const sizeRatio = measurements[i].size / measurements[i-1].size;
      const timeRatio = measurements[i].time / measurements[i-1].time;
      ratios.push({ sizeRatio, timeRatio });
    }
    
    const avgTimeRatio = ratios.reduce((sum, r) => sum + r.timeRatio, 0) / ratios.length;
    const avgSizeRatio = ratios.reduce((sum, r) => sum + r.sizeRatio, 0) / ratios.length;
    
    // Classify complexity
    if (Math.abs(avgTimeRatio - 1) < 0.3) return 'O(1)';
    if (Math.abs(avgTimeRatio - avgSizeRatio) < 0.3) return 'O(n)';
    if (Math.abs(avgTimeRatio - avgSizeRatio * Math.log2(avgSizeRatio)) < 0.5) return 'O(n log n)';
    if (Math.abs(avgTimeRatio - avgSizeRatio * avgSizeRatio) < 1) return 'O(n²)';
    if (avgTimeRatio > avgSizeRatio * avgSizeRatio) return 'O(n³) or worse';
    
    return 'COMPLEX';
  }
  
  generateReport(measurements, complexity) {
    let report = `Performance Profile:\n`;
    report += `Estimated Complexity: ${complexity}\n\n`;
    report += `Size\t\tTime (ms)\tGrowth\n`;
    report += `${'='.repeat(50)}\n`;
    
    measurements.forEach((m, i) => {
      const growth = i > 0 
        ? (m.time / measurements[i-1].time).toFixed(2) + 'x'
        : '-';
      report += `${m.size}\t\t${m.time.toFixed(4)}\t\t${growth}\n`;
    });
    
    return report;
  }
  
  // Memory profiling
  profileMemoryUsage(fn, input) {
    if (typeof performance.memory !== 'undefined') {
      const before = performance.memory.usedJSHeapSize;
      fn(input);
      const after = performance.memory.usedJSHeapSize;
      
      return {
        allocated: after - before,
        total: after,
        unit: 'bytes'
      };
    }
    
    return { error: 'Memory profiling not available' };
  }
  
  // Benchmark comparison
  benchmark(functions, input, iterations = 1000) {
    const results = [];
    
    functions.forEach(({ name, fn }) => {
      const times = [];
      
      for (let i = 0; i < iterations; i++) {
        const start = performance.now();
        fn([...input]);  // Copy to avoid mutation
        const end = performance.now();
        times.push(end - start);
      }
      
      times.sort((a, b) => a - b);
      const median = times[Math.floor(times.length / 2)];
      const mean = times.reduce((a, b) => a + b) / times.length;
      const min = Math.min(...times);
      const max = Math.max(...times);
      
      results.push({
        name,
        median,
        mean,
        min,
        max,
        opsPerSec: 1000 / mean
      });
    });
    
    // Sort by performance
    results.sort((a, b) => a.median - b.median);
    
    return results;
  }
  
  // Hotspot detection
  profileHotspots(fn, input) {
    const functionCalls = new Map();
    
    // Wrap function calls to track execution
    const originalFn = fn;
    const wrapper = (...args) => {
      const fnName = originalFn.name || 'anonymous';
      const start = performance.now();
      const result = originalFn(...args);
      const duration = performance.now() - start;
      
      if (!functionCalls.has(fnName)) {
        functionCalls.set(fnName, { count: 0, totalTime: 0 });
      }
      
      const stats = functionCalls.get(fnName);
      stats.count++;
      stats.totalTime += duration;
      
      return result;
    };
    
    wrapper(input);
    
    return Array.from(functionCalls.entries()).map(([name, stats]) => ({
      function: name,
      calls: stats.count,
      totalTime: stats.totalTime,
      avgTime: stats.totalTime / stats.count
    })).sort((a, b) => b.totalTime - a.totalTime);
  }
}

// Example usage
const profiler = new PerformanceProfiler();

// Test 1: Profile bubble sort time complexity
function bubbleSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  return arr;
}

const inputGenerator = size => Array(size).fill(0).map(() => Math.random());
const profile = profiler.profileTimeComplexity(bubbleSort, inputGenerator);
console.log(profile.report);

// Test 2: Benchmark multiple implementations
const quickSort = arr => {
  if (arr.length <= 1) return arr;
  const pivot = arr[0];
  const left = arr.slice(1).filter(x => x < pivot);
  const right = arr.slice(1).filter(x => x >= pivot);
  return [...quickSort(left), pivot, ...quickSort(right)];
};

const benchmarkResults = profiler.benchmark([
  { name: 'Bubble Sort', fn: bubbleSort },
  { name: 'Quick Sort', fn: quickSort },
  { name: 'Native Sort', fn: arr => arr.sort((a, b) => a - b) }
], inputGenerator(100));

console.log('Benchmark Results:');
benchmarkResults.forEach((r, i) => {
  console.log(`${i + 1}. ${r.name}: ${r.opsPerSec.toFixed(2)} ops/sec`);
});
Warning: Performance measurements can be noisy. Always: run warmup iterations, take multiple measurements, use median instead of mean to reduce outlier impact, test with realistic input sizes, and profile in production-like environment.

5. Algorithm Code Review Checklist

Category Check Items Common Issues
Correctness Logic errors, edge cases, algorithm correctness Off-by-one, null handling, boundary conditions
Performance Time/space complexity, optimization opportunities Nested loops, redundant operations, inefficient data structures
Readability Naming, comments, code structure Unclear variable names, missing documentation, complex logic
Error Handling Exception handling, validation, graceful degradation Missing null checks, unhandled exceptions, silent failures
Testing Test coverage, edge cases tested, assertions Incomplete tests, missing edge cases, no negative tests
Security Input validation, injection prevention, data exposure SQL injection, XSS, exposed sensitive data

Example 1: Automated Code Review Checker

class CodeReviewChecker {
  constructor(code) {
    this.code = code;
    this.issues = [];
  }
  
  // Check for common correctness issues
  checkCorrectness() {
    const correctnessIssues = [];
    
    // Check for potential null pointer issues
    const nullChecks = this.code.match(/\.\w+(?!\?\.)/g) || [];
    if (nullChecks.length > 0 && !this.code.includes('if (') && !this.code.includes('?.')) {
      correctnessIssues.push({
        type: 'NULL_SAFETY',
        severity: 'HIGH',
        message: 'Potential null pointer access without checks',
        suggestion: 'Use optional chaining (?.) or add null checks'
      });
    }
    
    // Check for array index access
    const arrayAccess = this.code.match(/\[\w+\]/g) || [];
    if (arrayAccess.length > 0 && !this.code.includes('< length') && !this.code.includes('<= length')) {
      correctnessIssues.push({
        type: 'BOUNDS_CHECK',
        severity: 'MEDIUM',
        message: 'Array access without bounds checking',
        suggestion: 'Validate index: if (i >= 0 && i < arr.length)'
      });
    }
    
    // Check for off-by-one in loops
    if (this.code.includes('i <= length') || this.code.includes('i <= arr.length')) {
      correctnessIssues.push({
        type: 'OFF_BY_ONE',
        severity: 'HIGH',
        message: 'Potential off-by-one error with <= length',
        suggestion: 'Use i < length instead of i <= length'
      });
    }
    
    // Check for missing base case in recursion
    if (this.code.includes('function') && this.code.match(/\w+\(.*\)/g)) {
      const funcName = this.code.match(/function\s+(\w+)/);
      if (funcName && this.code.includes(funcName[1] + '(')) {
        if (!this.code.includes('return') || !this.code.includes('if')) {
          correctnessIssues.push({
            type: 'RECURSION_BASE_CASE',
            severity: 'HIGH',
            message: 'Recursive function may lack base case',
            suggestion: 'Add base case: if (condition) return value;'
          });
        }
      }
    }
    
    return correctnessIssues;
  }
  
  // Check for performance issues
  checkPerformance() {
    const performanceIssues = [];
    
    // Check for nested loops
    const nestedLoops = this.code.match(/for\s*\([^)]*\)\s*{[^}]*for\s*\(/g);
    if (nestedLoops && nestedLoops.length > 0) {
      performanceIssues.push({
        type: 'NESTED_LOOPS',
        severity: 'MEDIUM',
        message: `Found ${nestedLoops.length} nested loop(s) - O(n²) or worse`,
        suggestion: 'Consider using hash map or two-pointer technique'
      });
    }
    
    // Check for repeated calculations
    const calculations = this.code.match(/arr\.length/g);
    if (calculations && calculations.length > 3) {
      performanceIssues.push({
        type: 'REPEATED_CALCULATION',
        severity: 'LOW',
        message: 'arr.length calculated multiple times',
        suggestion: 'Cache in variable: const n = arr.length;'
      });
    }
    
    // Check for inefficient string concatenation
    if (this.code.includes('+=') && this.code.includes('for')) {
      const stringConcat = this.code.match(/\w+\s*\+=\s*['"`]/);
      if (stringConcat) {
        performanceIssues.push({
          type: 'STRING_CONCATENATION',
          severity: 'MEDIUM',
          message: 'String concatenation in loop is O(n²)',
          suggestion: 'Use array.push() then join(): arr.push(s); arr.join("")'
        });
      }
    }
    
    // Check for creating new arrays unnecessarily
    const arrayCreations = this.code.match(/new Array|Array\(|\.map\(|\.filter\(/g);
    if (arrayCreations && arrayCreations.length > 2) {
      performanceIssues.push({
        type: 'EXCESSIVE_ALLOCATIONS',
        severity: 'LOW',
        message: 'Multiple array allocations detected',
        suggestion: 'Consider in-place operations or single pass'
      });
    }
    
    return performanceIssues;
  }
  
  // Check for readability issues
  checkReadability() {
    const readabilityIssues = [];
    
    // Check for single letter variables (except i, j, k in loops)
    const singleLetterVars = this.code.match(/\b[a-hln-z]\b/g);
    if (singleLetterVars && singleLetterVars.length > 3) {
      readabilityIssues.push({
        type: 'UNCLEAR_NAMING',
        severity: 'LOW',
        message: 'Too many single-letter variable names',
        suggestion: 'Use descriptive names: count, index, result'
      });
    }
    
    // Check for long functions
    const lines = this.code.split('\n').length;
    if (lines > 50) {
      readabilityIssues.push({
        type: 'LONG_FUNCTION',
        severity: 'MEDIUM',
        message: `Function is ${lines} lines - too long`,
        suggestion: 'Break into smaller functions with clear responsibilities'
      });
    }
    
    // Check for missing comments
    const hasComments = this.code.includes('//') || this.code.includes('/*');
    const complexity = this.code.split('if').length + this.code.split('for').length;
    if (complexity > 3 && !hasComments) {
      readabilityIssues.push({
        type: 'MISSING_COMMENTS',
        severity: 'LOW',
        message: 'Complex logic without comments',
        suggestion: 'Add comments explaining algorithm and edge cases'
      });
    }
    
    return readabilityIssues;
  }
  
  // Check error handling
  checkErrorHandling() {
    const errorIssues = [];
    
    // Check for missing input validation
    if (!this.code.includes('if (') && !this.code.includes('throw')) {
      errorIssues.push({
        type: 'NO_VALIDATION',
        severity: 'HIGH',
        message: 'No input validation detected',
        suggestion: 'Validate inputs: check null, bounds, types'
      });
    }
    
    // Check for try-catch in async code
    if ((this.code.includes('async') || this.code.includes('.then(')) && !this.code.includes('catch')) {
      errorIssues.push({
        type: 'UNHANDLED_ASYNC',
        severity: 'HIGH',
        message: 'Async code without error handling',
        suggestion: 'Add try-catch or .catch() handler'
      });
    }
    
    return errorIssues;
  }
  
  // Generate comprehensive review report
  generateReport() {
    const allIssues = [
      ...this.checkCorrectness(),
      ...this.checkPerformance(),
      ...this.checkReadability(),
      ...this.checkErrorHandling()
    ];
    
    // Group by severity
    const bySeverity = {
      HIGH: allIssues.filter(i => i.severity === 'HIGH'),
      MEDIUM: allIssues.filter(i => i.severity === 'MEDIUM'),
      LOW: allIssues.filter(i => i.severity === 'LOW')
    };
    
    return {
      totalIssues: allIssues.length,
      bySeverity,
      issues: allIssues,
      score: this.calculateScore(allIssues)
    };
  }
  
  calculateScore(issues) {
    const weights = { HIGH: 10, MEDIUM: 5, LOW: 1 };
    const totalPenalty = issues.reduce((sum, issue) => 
      sum + weights[issue.severity], 0
    );
    
    return Math.max(0, 100 - totalPenalty);
  }
}

// Example usage
const codeToReview = `
function findMax(arr) {
  let max = arr[0];
  for (let i = 1; i <= arr.length; i++) {
    if (arr[i] > max) {
      max = arr[i];
    }
  }
  return max;
}
`;

const reviewer = new CodeReviewChecker(codeToReview);
const report = reviewer.generateReport();

console.log('Code Review Report:');
console.log(`Score: ${report.score}/100`);
console.log(`Total Issues: ${report.totalIssues}`);
console.log('\nHigh Severity Issues:');
report.bySeverity.HIGH.forEach(issue => {
  console.log(`  - ${issue.message}`);
  console.log(`    ${issue.suggestion}`);
});
Note: Effective code reviews check: correctness (logic, edge cases, algorithms), performance (time/space complexity, bottlenecks), readability (naming, structure, comments), error handling (validation, exceptions), testing (coverage, edge cases), and security (input validation, injection prevention).

6. Stress Testing with Large Inputs

Stress Test Type Purpose Input Characteristics
Maximum Size Test Verify behavior at maximum input size n = 10^5, 10^6, or problem limit
Random Large Input Find bugs that appear only with large data Random values at maximum size
Worst Case Input Test worst-case time/space complexity Already sorted, all duplicates, nested structure
Memory Stress Test Detect memory leaks and excessive allocation Repeated operations on large data
Time Limit Test Ensure solution runs within time constraints Maximum input with time measurement

Example 1: Stress Test Framework

class StressTester {
  constructor(solutionFn, referenceFn = null) {
    this.solutionFn = solutionFn;
    this.referenceFn = referenceFn;  // Naive but correct solution
    this.results = [];
  }
  
  // Generate maximum size input
  generateMaxSizeInput(size, type = 'random') {
    if (type === 'random') {
      return Array(size).fill(0).map(() => 
        Math.floor(Math.random() * 1000000)
      );
    } else if (type === 'sorted') {
      return Array(size).fill(0).map((_, i) => i);
    } else if (type === 'reverse') {
      return Array(size).fill(0).map((_, i) => size - i);
    } else if (type === 'duplicates') {
      return Array(size).fill(42);
    } else if (type === 'alternating') {
      return Array(size).fill(0).map((_, i) => i % 2);
    }
    
    return [];
  }
  
  // Run stress test
  runStressTest(inputSize, iterations = 100, timeLimit = 1000) {
    console.log(`Running stress test: size=${inputSize}, iterations=${iterations}`);
    
    const testResults = {
      size: inputSize,
      iterations,
      passed: 0,
      failed: 0,
      timeouts: 0,
      errors: [],
      avgTime: 0,
      maxTime: 0
    };
    
    const times = [];
    
    for (let i = 0; i < iterations; i++) {
      // Generate random test case
      const input = this.generateMaxSizeInput(inputSize, 
        ['random', 'sorted', 'reverse', 'duplicates'][i % 4]
      );
      
      try {
        const start = performance.now();
        const result = this.solutionFn([...input]);
        const duration = performance.now() - start;
        
        times.push(duration);
        
        if (duration > timeLimit) {
          testResults.timeouts++;
        } else {
          // Verify against reference solution if available
          if (this.referenceFn) {
            const expected = this.referenceFn([...input]);
            const isCorrect = JSON.stringify(result) === JSON.stringify(expected);
            
            if (isCorrect) {
              testResults.passed++;
            } else {
              testResults.failed++;
              testResults.errors.push({
                iteration: i,
                input: input.slice(0, 10),  // Store first 10 elements
                expected: expected,
                got: result,
                message: 'Output mismatch'
              });
            }
          } else {
            testResults.passed++;
          }
        }
      } catch (error) {
        testResults.failed++;
        testResults.errors.push({
          iteration: i,
          message: error.message,
          stack: error.stack
        });
      }
    }
    
    testResults.avgTime = times.reduce((a, b) => a + b, 0) / times.length;
    testResults.maxTime = Math.max(...times);
    
    this.results.push(testResults);
    return testResults;
  }
  
  // Memory stress test
  runMemoryStressTest(inputSize, operations = 1000) {
    console.log(`Running memory stress test: ${operations} operations`);
    
    const memorySnapshots = [];
    
    for (let i = 0; i < operations; i++) {
      const input = this.generateMaxSizeInput(inputSize);
      
      if (typeof performance.memory !== 'undefined') {
        const before = performance.memory.usedJSHeapSize;
        this.solutionFn(input);
        const after = performance.memory.usedJSHeapSize;
        
        memorySnapshots.push({
          iteration: i,
          allocated: after - before,
          total: after
        });
      } else {
        this.solutionFn(input);
      }
      
      // Periodic garbage collection hint
      if (i % 100 === 0 && global.gc) {
        global.gc();
      }
    }
    
    return {
      operations,
      memoryAvailable: memorySnapshots.length > 0,
      avgAllocation: memorySnapshots.length > 0 
        ? memorySnapshots.reduce((s, m) => s + m.allocated, 0) / memorySnapshots.length
        : 'N/A',
      peakMemory: memorySnapshots.length > 0
        ? Math.max(...memorySnapshots.map(m => m.total))
        : 'N/A'
    };
  }
  
  // Comparative stress test
  compareWithReference(sizes = [100, 1000, 10000]) {
    if (!this.referenceFn) {
      return { error: 'No reference function provided' };
    }
    
    const comparison = [];
    
    sizes.forEach(size => {
      const input = this.generateMaxSizeInput(size);
      
      // Test solution
      const solStart = performance.now();
      const solResult = this.solutionFn([...input]);
      const solTime = performance.now() - solStart;
      
      // Test reference
      const refStart = performance.now();
      const refResult = this.referenceFn([...input]);
      const refTime = performance.now() - refStart;
      
      const isCorrect = JSON.stringify(solResult) === JSON.stringify(refResult);
      
      comparison.push({
        size,
        correct: isCorrect,
        solutionTime: solTime,
        referenceTime: refTime,
        speedup: refTime / solTime
      });
    });
    
    return comparison;
  }
  
  // Generate report
  generateReport() {
    console.log('\n=== Stress Test Report ===');
    
    this.results.forEach(result => {
      console.log(`\nInput Size: ${result.size}`);
      console.log(`Iterations: ${result.iterations}`);
      console.log(`Passed: ${result.passed} (${(result.passed/result.iterations*100).toFixed(1)}%)`);
      console.log(`Failed: ${result.failed}`);
      console.log(`Timeouts: ${result.timeouts}`);
      console.log(`Avg Time: ${result.avgTime.toFixed(2)}ms`);
      console.log(`Max Time: ${result.maxTime.toFixed(2)}ms`);
      
      if (result.errors.length > 0) {
        console.log(`\nFirst Error:`);
        console.log(result.errors[0]);
      }
    });
  }
}

// Example usage
function quickSort(arr) {
  if (arr.length <= 1) return arr;
  const pivot = arr[Math.floor(arr.length / 2)];
  const left = arr.filter(x => x < pivot);
  const middle = arr.filter(x => x === pivot);
  const right = arr.filter(x => x > pivot);
  return [...quickSort(left), ...middle, ...quickSort(right)];
}

function bubbleSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  return arr;
}

// Stress test quick sort
const tester = new StressTester(quickSort, bubbleSort);
tester.runStressTest(1000, 50);
tester.runStressTest(10000, 10);

// Compare performance
const comparison = tester.compareWithReference([100, 500, 1000]);
console.log('\nPerformance Comparison:');
comparison.forEach(c => {
  console.log(`Size ${c.size}: ${c.speedup.toFixed(2)}x faster, correct: ${c.correct}`);
});

tester.generateReport();
Warning: Stress testing reveals bugs that appear only with large inputs: stack overflow from deep recursion, timeout from poor complexity, memory exhaustion from leaks, integer overflow, and performance degradation. Always test at maximum problem constraints.

7. Corner Case Enumeration Methods

Corner Case Type Definition Examples
Minimum Input Smallest valid input Empty array [], single element [1], n=0
Maximum Input Largest valid input n = 10^5, max value array
All Same Elements No variation in input [5,5,5,5], "aaaa"
Extreme Values Boundary of data type MAX_INT, MIN_INT, Infinity, -Infinity
Special Patterns Input with known structure Sorted, reverse sorted, alternating
Invalid Input Outside problem constraints Negative when positive expected, null

Example: Corner Case Generator and Validator

class CornerCaseEnumerator {
  // Generate all corner cases for array problems
  static enumerateArrayCornerCases(maxSize = 5, valueRange = [-10, 10]) {
    const cornerCases = [];
    
    // 1. Empty array
    cornerCases.push({
      name: 'Empty Array',
      input: [],
      category: 'MINIMUM_INPUT'
    });
    
    // 2. Single element
    cornerCases.push({
      name: 'Single Element',
      input: [0],
      category: 'MINIMUM_INPUT'
    });
    
    // 3. Two elements - same
    cornerCases.push({
      name: 'Two Same Elements',
      input: [5, 5],
      category: 'DUPLICATES'
    });
    
    // 4. Two elements - different
    cornerCases.push({
      name: 'Two Different Elements',
      input: [1, 2],
      category: 'MINIMUM_VARIED'
    });
    
    // 5. All same elements
    cornerCases.push({
      name: 'All Same Elements',
      input: Array(maxSize).fill(7),
      category: 'NO_VARIATION'
    });
    
    // 6. Already sorted ascending
    cornerCases.push({
      name: 'Already Sorted Ascending',
      input: Array(maxSize).fill(0).map((_, i) => i),
      category: 'SORTED'
    });
    
    // 7. Already sorted descending
    cornerCases.push({
      name: 'Already Sorted Descending',
      input: Array(maxSize).fill(0).map((_, i) => maxSize - i),
      category: 'REVERSE_SORTED'
    });
    
    // 8. Alternating values
    cornerCases.push({
      name: 'Alternating Pattern',
      input: Array(maxSize).fill(0).map((_, i) => i % 2),
      category: 'PATTERN'
    });
    
    // 9. All zeros
    cornerCases.push({
      name: 'All Zeros',
      input: Array(maxSize).fill(0),
      category: 'SPECIAL_VALUE'
    });
    
    // 10. Contains negative numbers
    cornerCases.push({
      name: 'Mix of Positive and Negative',
      input: [-5, -1, 0, 3, 7],
      category: 'MIXED_SIGNS'
    });
    
    // 11. Extreme values
    const [min, max] = valueRange;
    cornerCases.push({
      name: 'Extreme Values',
      input: [min, max, min, max],
      category: 'EXTREME_VALUES'
    });
    
    // 12. Maximum size
    cornerCases.push({
      name: 'Maximum Size Random',
      input: Array(maxSize).fill(0).map(() => 
        Math.floor(Math.random() * (max - min + 1)) + min
      ),
      category: 'MAXIMUM_INPUT'
    });
    
    return cornerCases;
  }
  
  // Generate corner cases for string problems
  static enumerateStringCornerCases(maxLength = 10) {
    return [
      { name: 'Empty String', input: '', category: 'MINIMUM_INPUT' },
      { name: 'Single Character', input: 'a', category: 'MINIMUM_INPUT' },
      { name: 'Two Same Chars', input: 'aa', category: 'DUPLICATES' },
      { name: 'Two Different Chars', input: 'ab', category: 'MINIMUM_VARIED' },
      { name: 'All Same Character', input: 'a'.repeat(maxLength), category: 'NO_VARIATION' },
      { name: 'Palindrome', input: 'racecar', category: 'PATTERN' },
      { name: 'Already Sorted', input: 'abcdefgh', category: 'SORTED' },
      { name: 'Reverse Sorted', input: 'zyxwvu', category: 'REVERSE_SORTED' },
      { name: 'Contains Spaces', input: 'hello world', category: 'SPECIAL_CHARS' },
      { name: 'Only Spaces', input: '     ', category: 'SPECIAL_CHARS' },
      { name: 'Mixed Case', input: 'HeLLo', category: 'MIXED' },
      { name: 'Numbers and Letters', input: 'abc123', category: 'MIXED' },
      { name: 'Special Characters', input: '!@#$%', category: 'SPECIAL_CHARS' },
      { name: 'Unicode', input: '你好世界', category: 'UNICODE' },
      { name: 'Emoji', input: '🚀🌟💻', category: 'UNICODE' },
      { name: 'Maximum Length', input: 'x'.repeat(maxLength), category: 'MAXIMUM_INPUT' }
    ];
  }
  
  // Test function against all corner cases
  static validateAgainstCornerCases(fn, cornerCases, expectedBehavior = null) {
    const results = {
      total: cornerCases.length,
      passed: 0,
      failed: 0,
      errors: 0,
      details: []
    };
    
    cornerCases.forEach(testCase => {
      try {
        const result = fn(testCase.input);
        
        let passed = true;
        let message = 'Executed successfully';
        
        // Check expected behavior if provided
        if (expectedBehavior && expectedBehavior[testCase.name]) {
          const expected = expectedBehavior[testCase.name];
          passed = JSON.stringify(result) === JSON.stringify(expected);
          message = passed ? 'Matches expected output' : 'Output mismatch';
        }
        
        if (passed) {
          results.passed++;
        } else {
          results.failed++;
        }
        
        results.details.push({
          name: testCase.name,
          category: testCase.category,
          input: testCase.input,
          output: result,
          passed,
          message
        });
      } catch (error) {
        results.errors++;
        results.details.push({
          name: testCase.name,
          category: testCase.category,
          input: testCase.input,
          error: error.message,
          passed: false,
          message: 'Exception thrown'
        });
      }
    });
    
    return results;
  }
  
  // Generate test matrix (combinations of corner cases)
  static generateTestMatrix(dimensions) {
    // For functions with multiple parameters
    const matrix = [];
    
    function cartesianProduct(arrays, index = 0, current = []) {
      if (index === arrays.length) {
        matrix.push([...current]);
        return;
      }
      
      arrays[index].forEach(value => {
        current.push(value);
        cartesianProduct(arrays, index + 1, current);
        current.pop();
      });
    }
    
    cartesianProduct(dimensions);
    return matrix;
  }
}

// Example usage
function binarySearch(arr, target) {
  let left = 0, right = arr.length - 1;
  
  while (left <= right) {
    const mid = Math.floor((left + right) / 2);
    if (arr[mid] === target) return mid;
    if (arr[mid] < target) left = mid + 1;
    else right = mid - 1;
  }
  
  return -1;
}

// Generate array corner cases
const arrayCornerCases = CornerCaseEnumerator.enumerateArrayCornerCases(10, [0, 100]);

console.log(`Generated ${arrayCornerCases.length} array corner cases:`);
arrayCornerCases.forEach(tc => {
  console.log(`  ${tc.name} (${tc.category}): [${tc.input.slice(0, 5)}...]`);
});

// Test binary search with corner cases
const searchCornerCases = arrayCornerCases.map(tc => ({
  ...tc,
  input: tc.input.sort((a, b) => a - b)  // Binary search needs sorted array
}));

const results = CornerCaseEnumerator.validateAgainstCornerCases(
  arr => binarySearch(arr, arr.length > 0 ? arr[0] : 0),
  searchCornerCases
);

console.log(`\nTest Results: ${results.passed}/${results.total} passed`);
console.log(`Failed: ${results.failed}, Errors: ${results.errors}`);
Note: Systematic corner case enumeration prevents missing critical tests. For each problem, enumerate: minimum input (empty, single element), maximum input (at constraints), special values (0, null, duplicates), patterns (sorted, reverse), and extreme values (MAX_INT, MIN_INT). Create test matrix for multi-parameter functions.

Summary: Testing and Debugging Patterns

  • Equivalence Partitioning: Divide input domain into classes where behavior is identical - test one representative from each partition
  • Boundary Testing: Test at boundaries: min-1, min, min+1, max-1, max, max+1 to catch off-by-one and range errors
  • Property-based Testing: Define invariants (idempotence, commutativity, preservation) and verify they hold for random inputs
  • Edge Case Categories: Always test empty/null, single element, duplicates, sorted/reverse, extreme values, and special characters
  • Edge Case Identification: Use automated tools to detect null safety issues, bounds problems, special values, and large inputs
  • Boundary Value Analysis: Systematically test numeric ranges, array sizes, string lengths, loop iterations, and index access at boundaries
  • Time Complexity Profiling: Measure execution time vs input size, calculate growth ratios to infer O(1), O(n), O(n log n), O(n²)
  • Benchmarking: Compare multiple implementations with warmup runs, multiple measurements, and median statistics to reduce noise
  • Code Review Checklist: Check correctness (logic, edge cases), performance (complexity), readability (naming, structure), error handling, testing, security
  • Automated Code Review: Detect common issues: null pointer access, bounds checking, off-by-one, nested loops, string concatenation in loops
  • Stress Testing: Test at maximum constraints with random, sorted, reverse, and duplicate inputs to find scalability issues
  • Memory Stress Testing: Run repeated operations to detect memory leaks and excessive allocations - monitor heap size growth
  • Corner Case Enumeration: Systematically generate: empty, single, all-same, sorted, reverse, extreme values, special patterns
  • Test Matrix: For multi-parameter functions, create cartesian product of corner cases for each parameter to test all combinations
  • Validation Framework: Build automated test harness that runs all corner cases and reports pass/fail/error statistics