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

import java.util.Scanner;

import org.junit.jupiter.api.Test;

/**
 * Test class for the RobustPaycheck program.
 * 
 * @author Sarah Heckman
 * @author Jessica Young Schmidt
 */
public class RobustPaycheckTest {
    /** Delta for comparing doubles */
    public static final double DELTA = 0.0001;

    /**
     * Test the constants for correct value
     */
    @Test
    public void testConstants() {
        assertEquals(1, RobustPaycheck.LEVEL_1, "Level 1");
        assertEquals(2, RobustPaycheck.LEVEL_2, "Level 2");
        assertEquals(3, RobustPaycheck.LEVEL_3, "Level 3");
        assertEquals(1900, RobustPaycheck.LEVEL_1_PAY_RATE, "Level 1 pay rate");
        assertEquals(2250, RobustPaycheck.LEVEL_2_PAY_RATE, "Level 2 pay rate");
        assertEquals(2575, RobustPaycheck.LEVEL_3_PAY_RATE, "Level 3 pay rate");
    }

    /**
     * Test the RobustPaycheck.getPayRate() method.
     */
    @Test
    public void testGetPayRate() {
        // Test level 1
        assertEquals(RobustPaycheck.LEVEL_1_PAY_RATE,
                RobustPaycheck.getPayRate(RobustPaycheck.LEVEL_1),
                "RobustPaycheck.getPayRate(RobustPaycheck.LEVEL_1)");

        // Test level 2
        assertEquals(RobustPaycheck.LEVEL_2_PAY_RATE,
                RobustPaycheck.getPayRate(RobustPaycheck.LEVEL_2),
                "RobustPaycheck.getPayRate(RobustPaycheck.LEVEL_2)");

        // Test level 3
        assertEquals(RobustPaycheck.LEVEL_3_PAY_RATE,
                RobustPaycheck.getPayRate(RobustPaycheck.LEVEL_3),
                "RobustPaycheck.getPayRate(RobustPaycheck.LEVEL_3)");

        // Test level 0 - invalid lower boundary
        Exception exception = assertThrows(IllegalArgumentException.class,
            () -> RobustPaycheck.getPayRate(0), "Testing level 0");
        assertEquals("Invalid Level", exception.getMessage(),
                "Testing level 0 - exception message");

        // Test level 4 - invalid upper boundary
        exception = assertThrows(IllegalArgumentException.class,
            () -> RobustPaycheck.getPayRate(4), "Testing level 4");
        assertEquals("Invalid Level", exception.getMessage(),
                "Testing level 4 - exception message");

    }

    /**
     * Test the RobustPaycheck.calculateRegularPay() method.
     */
    @Test
    public void testCalculateRegularPay() {

        // Less than 40 hours
        // Regular Level 1 36 hours
        assertEquals(68400,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_1_PAY_RATE, 36),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_1_PAY_RATE, 36)");

        // Regular Level 2 36 hours
        assertEquals(81000,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_2_PAY_RATE, 36),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_2_PAY_RATE, 36)");

        // Regular Level 3 36 hours
        assertEquals(92700,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, 36),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_3_PAY_RATE, 36)");

        // Over 40 hours
        // Regular Level 1 46 hours
        assertEquals(76000,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_1_PAY_RATE, 46),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_1_PAY_RATE, 46)");

        // Regular Level 2 46 hours
        assertEquals(90000,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_2_PAY_RATE, 46),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_2_PAY_RATE, 46)");

        // Regular Level 3 46 hours
        assertEquals(103000,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, 46),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_3_PAY_RATE, 46)");

        // Fractional hours less than 40
        // Regular Level 1 36.5 hours
        assertEquals(69350,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_1_PAY_RATE, 36.5),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_1_PAY_RATE, 36.5)");

        // Regular Level 2 36.5 hours
        assertEquals(82125,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_2_PAY_RATE, 36.5),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_2_PAY_RATE, 36.5)");

        // Regular Level 3 36.5 hours
        assertEquals(93987,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, 36.5),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_3_PAY_RATE, 36.5)");

        // Test a payrate other than a given constant Regular
        assertEquals(34950, RobustPaycheck.calculateRegularPay(1376, 25.4),
                "RobustPaycheck.calculateRegularPay(1376, 25.4)");

        // Testing boundary
        // Less than 40 hours
        // Regular Level 1 39 hours
        assertEquals(74100,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_1_PAY_RATE, 39),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_1_PAY_RATE, 39)");

        // Regular Level 2 39 hours
        assertEquals(87750,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_2_PAY_RATE, 39),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_2_PAY_RATE, 39)");

        // Regular Level 3 39 hours
        assertEquals(100425,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, 39),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_3_PAY_RATE, 39)");

        // Regular Level 1 40 hours
        assertEquals(76000,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_1_PAY_RATE, 40),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_1_PAY_RATE, 40)");

        // Regular Level 2 40 hours
        assertEquals(90000,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_2_PAY_RATE, 40),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_2_PAY_RATE, 40)");

        // Regular Level 3 40 hours
        assertEquals(103000,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, 40),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_3_PAY_RATE, 40)");

        // Over 40 hours
        // Regular Level 1 41 hours
        assertEquals(76000,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_1_PAY_RATE, 41),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_1_PAY_RATE, 41)");

        // Regular Level 2 41 hours
        assertEquals(90000,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_2_PAY_RATE, 41),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_2_PAY_RATE, 41)");

        // Regular Level 3 41 hours
        assertEquals(103000,
                RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, 41),
                "RobustPaycheck.calculateRegularPay(RobustPaycheck.LEVEL_3_PAY_RATE, 41)");

        // Test negative hours
        Exception exception = assertThrows(IllegalArgumentException.class,
            () -> RobustPaycheck.calculateRegularPay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, -1),
                "Testing negative hours worked");
        assertEquals("Negative pay rate and/or hours worked",
                exception.getMessage(),
                "Testing negative hours worked - exception message");

        // Test negative pay rate
        exception = assertThrows(IllegalArgumentException.class,
            () -> RobustPaycheck.calculateRegularPay(-20, 20),
                "Testing negative pay rate");
        assertEquals("Negative pay rate and/or hours worked",
                exception.getMessage(),
                "Testing negative pay rate - exception message");
    }

    /**
     * Test the RobustPaycheck.calculateOvertimePay() method.
     */
    @Test
    public void testCalculateOvertimePay() {

        // Less than 40 hours
        // Overtime Level 1 36 hours
        assertEquals(0,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_1_PAY_RATE, 36),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_1_PAY_RATE, 36)");

        // Overtime Level 2 36 hours
        assertEquals(0,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_2_PAY_RATE, 36),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_2_PAY_RATE, 36)");

        // Overtime Level 3 36 hours
        assertEquals(0,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, 36),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_3_PAY_RATE, 36)");

        // Over 40 hours
        // Overtime Level 1 46 hours
        assertEquals(17100,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_1_PAY_RATE, 46),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_1_PAY_RATE, 46)");

        // Overtime Level 2 46 hours
        assertEquals(20250,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_2_PAY_RATE, 46),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_2_PAY_RATE, 46)");

        // Overtime Level 3 46 hours
        assertEquals(23172,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, 46),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_3_PAY_RATE, 46)");

        // Fractional hours less than 40
        // Overtime Level 1 36.5 hours
        assertEquals(0,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_1_PAY_RATE, 36.5),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_1_PAY_RATE, 36.5)");

        // Overtime Level 2 36.5 hours
        assertEquals(0,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_2_PAY_RATE, 36.5),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_2_PAY_RATE, 36.5)");

        // Overtime Level 3 36.5 hours
        assertEquals(0,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, 36.5),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_3_PAY_RATE, 36.5)");

        // Fractional hours over 40 hours
        // Overtime Level 1 46.5 hours
        assertEquals(18525,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_1_PAY_RATE, 46.5),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_1_PAY_RATE, 46.5)");

        // Overtime Level 2 46.5 hours
        assertEquals(21937,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_2_PAY_RATE, 46.5),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_2_PAY_RATE, 46.5)");

        // Overtime Level 3 46 hours
        assertEquals(

                25103,
                RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, 46.5),
                "RobustPaycheck.calculateOvertimePay(RobustPaycheck.LEVEL_3_PAY_RATE, 46.5)");

        // Test a payrate other than a given constant Regular
        assertEquals(14964, RobustPaycheck.calculateOvertimePay(1376, 47.25),
                "RobustPaycheck.calculateOvertimePay(1376, 47.25)");

        // Test negative hours
        Exception exception = assertThrows(IllegalArgumentException.class,
            () -> RobustPaycheck.calculateOvertimePay(
                        RobustPaycheck.LEVEL_3_PAY_RATE, -1),
                "Testing negative hours worked");
        assertEquals("Negative pay rate and/or hours worked",
                exception.getMessage(),
                "Testing negative hours worked - exception message");

        // Test negative pay rate
        exception = assertThrows(IllegalArgumentException.class,
            () -> RobustPaycheck.calculateOvertimePay(-20, 20),
                "Testing negative pay rate");
        assertEquals("Negative pay rate and/or hours worked",
                exception.getMessage(),
                "Testing negative pay rate - exception message");
    }

    /**
     * Test the RobustPaycheck.calculateGrossPay() method.
     */
    @Test
    public void testCalculateGrossPay() {

        // Less than 40 hours
        // Gross Level 1 36 hours
        assertEquals(68400, RobustPaycheck.calculateGrossPay(68400, 0),
                "RobustPaycheck.calculateGrossPay(68400, 0)");

        // Gross Level 2 36 hours
        assertEquals(81000, RobustPaycheck.calculateGrossPay(81000, 0),
                "RobustPaycheck.calculateGrossPay(81000, 0)");

        // Gross Level 3 36 hours
        assertEquals(92700, RobustPaycheck.calculateGrossPay(92700, 0),
                "RobustPaycheck.calculateGrossPay(92700, 0)");

        // Over 40 hours
        // Gross Level 1 46 hours
        assertEquals(93100, RobustPaycheck.calculateGrossPay(76000, 17100),
                "RobustPaycheck.calculateGrossPay(76000, 17100)");

        // Gross Level 2 46 hours
        assertEquals(110250, RobustPaycheck.calculateGrossPay(90000, 20250),
                "RobustPaycheck.calculateGrossPay(90000, 20250)");

        // Gross Level 3 46 hours
        assertEquals(126172, RobustPaycheck.calculateGrossPay(103000, 23172),
                "RobustPaycheck.calculateGrossPay(103000, 23172)");

        // Fractional hours less than 40
        // Gross Level 1 36.5 hours
        assertEquals(69350, RobustPaycheck.calculateGrossPay(69350, 0),
                "RobustPaycheck.calculateGrossPay(69350, 0)");

        // Overtime Level 2 36.5 hours
        assertEquals(82125, RobustPaycheck.calculateGrossPay(82125, 0),
                "RobustPaycheck.calculateGrossPay(82125, 0)");

        // Gross Level 3 36.5 hours
        assertEquals(93987, RobustPaycheck.calculateGrossPay(93987, 0),
                "RobustPaycheck.calculateGrossPay(93987, 0)");

        // Fractional hours over 40 hours
        // Gross Level 1 46.5 hours
        assertEquals(94525, RobustPaycheck.calculateGrossPay(76000, 18525),
                "RobustPaycheck.calculateGrossPay(76000, 18525)");

        // Gross Level 2 46.5 hours
        assertEquals(111937, RobustPaycheck.calculateGrossPay(90000, 21937),
                "RobustPaycheck.calculateGrossPay(90000, 21937)");

        // Gross Level 3 46 hours
        assertEquals(128103, RobustPaycheck.calculateGrossPay(103000, 25103),
                "RobustPaycheck.calculateGrossPay(103000, 25103)");

        // Test a payrate other than a given constant Gross
        assertEquals(49914, RobustPaycheck.calculateGrossPay(34950, 14964),
                "RobustPaycheck.calculateGrossPay(34950, 14964)");

        // Test negative regular
        Exception exception = assertThrows(IllegalArgumentException.class,
            () -> RobustPaycheck.calculateGrossPay(-103000, 25103),
                "Testing negative regular pay");
        assertEquals("Invalid regular and/or overtime pay.",
                exception.getMessage(),
                "Testing negative regular pay - exception message");

        // Test negative overtime
        exception = assertThrows(IllegalArgumentException.class,
            () -> RobustPaycheck.calculateGrossPay(103000, -25103),
                "Testing negative overtime pay");
        assertEquals("Invalid regular and/or overtime pay.",
                exception.getMessage(),
                "Testing negative overtime pay - exception message");
    }

    /**
     * Test the RobustPaycheck.calculateTotalDeductions() method.
     */
    @Test
    public void testCalculateRetirement() {

        // Zero percent retirement
        assertEquals(0, RobustPaycheck.calculateRetirement(92700, 0),
                "RobustPaycheck.calculateRetirement(92700, 0)");

        // One percent retirement
        assertEquals(927, RobustPaycheck.calculateRetirement(92700, 1),
                "RobustPaycheck.calculateRetirement(92700, 1)");

        // Two percent retirement
        assertEquals(1854, RobustPaycheck.calculateRetirement(92700, 2),
                "RobustPaycheck.calculateRetirement(92700, 2)");

        // Three percent retirement
        assertEquals(2781, RobustPaycheck.calculateRetirement(92700, 3),
                "RobustPaycheck.calculateRetirement(92700, 3)");

        // Four percent retirement
        assertEquals(3708, RobustPaycheck.calculateRetirement(92700, 4),
                "RobustPaycheck.calculateRetirement(92700, 4)");

        // Five percent retirement
        assertEquals(4635, RobustPaycheck.calculateRetirement(92700, 5),
                "RobustPaycheck.calculateRetirement(92700, 5)");

        // Six percent retirement
        assertEquals(5562, RobustPaycheck.calculateRetirement(92700, 6),
                "RobustPaycheck.calculateRetirement(92700, 6)");

        // Test negative gross pay
        Exception exception = assertThrows(IllegalArgumentException.class,
            () -> RobustPaycheck.calculateRetirement(-92700, 6),
                "Testing negative gross pay");
        assertEquals("Invalid gross pay and/or retirement percentage.",
                exception.getMessage(),
                "Testing negative gross pay - exception message");

        // Test invalid retirement percentage
        exception = assertThrows(IllegalArgumentException.class,
            () -> RobustPaycheck.calculateRetirement(92700, 7),
                "Testing invalid retirement percentage");
        assertEquals("Invalid gross pay and/or retirement percentage.",
                exception.getMessage(),
                "Testing invalid retirement percentage - exception message");
        exception = assertThrows(IllegalArgumentException.class,
            () -> RobustPaycheck.calculateRetirement(92700, -1),
                "Testing invalid retirement percentage");
        assertEquals("Invalid gross pay and/or retirement percentage.",
                exception.getMessage(),
                "Testing invalid retirement percentage - exception message");
    }

    /**
     * Test the RobustPaycheck.calculateNetPay() method.
     */
    @Test
    public void testCalculateNetPay() {

        // Calculate net pay with deductions
        assertEquals(86211, RobustPaycheck.calculateNetPay(92700, 6489),
                "RobustPaycheck.calculateNetPay(92700, 6489)");

        // Calculate net pay without deductions
        assertEquals(92700, RobustPaycheck.calculateNetPay(92700, 0),
                "RobustPaycheck.calculateNetPay(92700, 0)");

        // Calculate net pay - negative
        assertEquals(-1100, RobustPaycheck.calculateNetPay(92700, 93800),
                "RobustPaycheck.calculateNetPay(92700, 93800)");
    }

    /**
     * Test the RobustPaycheck.selectInsurance() method.
     */
    @Test
    public void testSelectInsurance() {
        // Test Y
        Scanner input = new Scanner("Y\n");
        assertTrue(RobustPaycheck.selectInsurance("M", input),
                "Test Y for insurance");
        // Test y
        input = new Scanner("y\n");
        assertTrue(RobustPaycheck.selectInsurance("M", input),
                "Test y for insurance");

        // Test N
        input = new Scanner("N\n");
        assertFalse(RobustPaycheck.selectInsurance("M", input),
                "Test N for insurance");
        // Test n
        input = new Scanner("n\n");
        assertFalse(RobustPaycheck.selectInsurance("M", input),
                "Test n for insurance");

        // Test Yes
        input = new Scanner("Yes\n");
        assertTrue(RobustPaycheck.selectInsurance("M", input),
                "Test Y for insurance");

        // Test never
        input = new Scanner("never\n");
        assertFalse(RobustPaycheck.selectInsurance("M", input),
                "Test n for insurance");

        // Test Yes after invalid
        input = new Scanner("whatever never\n Yes  \n");
        assertTrue(RobustPaycheck.selectInsurance("M", input),
                "Test Y for insurance");

        // Test never
        input = new Scanner("wolfpack, yay! \n never\n");
        assertFalse(RobustPaycheck.selectInsurance("M", input),
                "Test n for insurance");
    }

    /**
     * Test the RobustPaycheck.getTotalDeductions() method.
     */
    @Test
    public void testGetTotalDeductions() {
        // Test no insurance
        Scanner input = new Scanner("N\n never\n nc");
        assertEquals(0, RobustPaycheck.getTotalDeductions(input));
        // Test all insurances
        input = new Scanner("Y\n yes\n yellow");
        assertEquals(4505, RobustPaycheck.getTotalDeductions(input));
        // Test one insurance
        input = new Scanner("N\n yell\n nc");
        assertEquals(1530, RobustPaycheck.getTotalDeductions(input));
    }

    /**
     * Test the RobustPaycheck.getName() method.
     */
    @Test
    public void testGetName() {
        // Test valid name with multiple tokens
        Scanner input = new Scanner("\t Jessica Young Schmidt  \n");
        assertEquals("Jessica Young Schmidt", RobustPaycheck.getName(input),
                "Test valid name with multiple tokens");

        // Test valid name with single token
        input = new Scanner("  Wolfpack  \n");
        assertEquals("Wolfpack", RobustPaycheck.getName(input),
                "Test valid name with single token");

        // Test whitespace line before valid name with multiple tokens
        input = new Scanner("      \t \n\t Jessica Young Schmidt  \n");
        assertEquals("Jessica Young Schmidt", RobustPaycheck.getName(input),
                "Test whitespace line before valid name with multiple tokens");

        // Test whitespace line before valid name with multiple tokens
        input = new Scanner("\n\t Jessica Young Schmidt  \n");
        assertEquals("Jessica Young Schmidt", RobustPaycheck.getName(input),
                "Test whitespace line before valid name with multiple tokens");
    }

    /**
     * Test the RobustPaycheck.getLevel() method.
     */
    @Test
    public void testGetLevel() {
        // Test valid value
        Scanner input = new Scanner("1\n");
        assertEquals(1, RobustPaycheck.getLevel(input),
                "Test valid value of 1");

        // Test valid value
        input = new Scanner("2\n");
        assertEquals(2, RobustPaycheck.getLevel(input),
                "Test valid value of 2");

        // Test valid value
        input = new Scanner("3\n");
        assertEquals(3, RobustPaycheck.getLevel(input),
                "Test valid value of 3");

        // Test invalid value first
        input = new Scanner("level 2\n  3\n");
        assertEquals(3, RobustPaycheck.getLevel(input),
                "Test invalid value then 3");

        // Test invalid value first
        input = new Scanner("0 level\n  3\n");
        assertEquals(3, RobustPaycheck.getLevel(input),
                "Test invalid value then 3");

        // Test invalid value first
        input = new Scanner("0 \n  3\n");
        assertEquals(3, RobustPaycheck.getLevel(input),
                "Test invalid value then 3");

        // Test invalid value first
        input = new Scanner("4\n  3\n");
        assertEquals(3, RobustPaycheck.getLevel(input),
                "Test invalid value then 3");
    }

    /**
     * Test the RobustPaycheck.getHoursWorked() method.
     */
    @Test
    public void testGetHoursWorked() {
        // Test boundary value
        Scanner input = new Scanner("1\n");
        assertEquals(1, RobustPaycheck.getHoursWorked(input), DELTA,
                "Test boundary value for get hours worked");

        // Test boundary value
        input = new Scanner("0.1\n");
        assertEquals(0.1, RobustPaycheck.getHoursWorked(input), DELTA,
                "Test boundary value for get hours worked");

        // Test mid regular value
        input = new Scanner("20.5\n");
        assertEquals(20.5, RobustPaycheck.getHoursWorked(input), DELTA,
                "Test mid regular value for get hours worked");

        // Test max regular value
        input = new Scanner("40.0\n");
        assertEquals(40, RobustPaycheck.getHoursWorked(input), DELTA,
                "Test max regular value for get hours worked");

        // Test overtime value
        input = new Scanner("60\n");
        assertEquals(60, RobustPaycheck.getHoursWorked(input), DELTA,
                "Test overtime value for get hours worked");

        // Test invalid first value
        input = new Scanner("0\n 60\n");
        assertEquals(60, RobustPaycheck.getHoursWorked(input), DELTA,
                "Test invalid first value for get hours worked");

        // Test invalid first value
        input = new Scanner("-1\n 60\n");
        assertEquals(60, RobustPaycheck.getHoursWorked(input), DELTA,
                "Test invalid first value for get hours worked");

        // Test invalid first value
        input = new Scanner("four\n 60\n");
        assertEquals(60, RobustPaycheck.getHoursWorked(input), DELTA,
                "Test invalid first value for get hours worked");

        // Test invalid first value
        input = new Scanner("number 3\n 60\n");
        assertEquals(60, RobustPaycheck.getHoursWorked(input), DELTA,
                "Test invalid first value for get hours worked");
    }

    /**
     * Test the RobustPaycheck.getRetirementPercentage() method.
     */
    @Test
    public void testGetRetirementPercentage() {
        // Test boundary value
        Scanner input = new Scanner("0\n");
        assertEquals(0, RobustPaycheck.getRetirementPercentage(input),
                "Test boundary value for get retirement percentage");

        // Test boundary value
        input = new Scanner("1\n");
        assertEquals(1, RobustPaycheck.getRetirementPercentage(input),
                "Test boundary value for get retirement percentage");

        // Test boundary value
        input = new Scanner("5\n");
        assertEquals(5, RobustPaycheck.getRetirementPercentage(input),
                "Test boundary value for get retirement percentage");

        // Test boundary value
        input = new Scanner("6\n");
        assertEquals(6, RobustPaycheck.getRetirementPercentage(input),
                "Test boundary value for get retirement percentage");

        // Test mid value
        input = new Scanner("3\n");
        assertEquals(3, RobustPaycheck.getRetirementPercentage(input),
                "Test mid value for get retirement percentage");

        // Test with invalid value before valid
        input = new Scanner("words 1\n 7 \n 3 \n");
        assertEquals(3, RobustPaycheck.getRetirementPercentage(input),
                "Test mid value for get retirement percentage");

        // Test with invalid value before valid
        input = new Scanner("words 1\n 3 \n");
        assertEquals(3, RobustPaycheck.getRetirementPercentage(input),
                "Test mid value for get retirement percentage");
    }

    /**
     * Test the RobustPaycheck.isValidRetirementPercentage() method.
     */
    @Test
    public void testIsValidRetirementPercentage() {
        // Test 0%
        assertTrue(RobustPaycheck.isValidRetirementPercentage(0),
                "0% Retirement");

        // Test 1%
        assertTrue(RobustPaycheck.isValidRetirementPercentage(0),
                "1% Retirement");

        // Test 3%
        assertTrue(RobustPaycheck.isValidRetirementPercentage(3),
                "3% Retirement");

        // Test 5%
        assertTrue(RobustPaycheck.isValidRetirementPercentage(0),
                "5% Retirement");

        // Test 6%
        assertTrue(RobustPaycheck.isValidRetirementPercentage(6),
                "6% Retirement");

        // Test -1% - invalid lower boundary
        assertFalse(RobustPaycheck.isValidRetirementPercentage(-1),
                "-1% Retirement");

        // Test 7% - invalid upper boundary
        assertFalse(RobustPaycheck.isValidRetirementPercentage(7),
                "7% Retirement");
    }
}
