diff --git a/Sprint-3/3-stretch/creditCard-validator.js b/Sprint-3/3-stretch/creditCard-validator.js new file mode 100644 index 000000000..4b8a9e018 --- /dev/null +++ b/Sprint-3/3-stretch/creditCard-validator.js @@ -0,0 +1,41 @@ +function creditCardValidator(cardNumber) { + // declare the length of valid card number + const VALID_LENGTH = 16; + const minimumSum = 16; + + // Remove all - and spaces from the input + const sanitized = cardNumber.replace(/[-\s]/g, ""); + + //check if the length of the sanitized input is 16 + if (sanitized.length !== VALID_LENGTH) { + return false; + } + // check if the sanitized input contains only digits + if (!new RegExp(`^\\d{${VALID_LENGTH}}$`).test(sanitized)) { + return false; + } + + // check if there ara at least two different digits + const uniqueDigits = new Set(sanitized); + if (uniqueDigits.size < 2) { + return false; + } + + // check if the last digit is even + const lastDigit = Number(sanitized[sanitized.length - 1]); + if (lastDigit % 2 !== 0) { + return false; + } + + // check if the sum of all digits is greater than 16 + const sum = sanitized + .split("") + .reduce((total, digit) => total + Number(digit), 0); + if (sum <= minimumSum) { + return false; + } + + return true; +} + +module.exports = creditCardValidator; diff --git a/Sprint-3/3-stretch/creditCard-validator.test.js b/Sprint-3/3-stretch/creditCard-validator.test.js new file mode 100644 index 000000000..3ca84af5d --- /dev/null +++ b/Sprint-3/3-stretch/creditCard-validator.test.js @@ -0,0 +1,48 @@ +const creditCardValidator = require("./creditCard-validator"); + +describe("creditCardValidator", () => { + test("should return true for a 16 digit long card number", () => { + expect(creditCardValidator("1234-5678-9012-3456")).toBe(true); + expect(creditCardValidator("1234 5678 9012 3456")).toBe(true); + }); + + test("should return false if the card number is not digit only", () => { + expect(creditCardValidator("1234-5678-abcd-3456")).toBe(false); + expect(creditCardValidator("1234 5678 9012 3456")).toBe(true); + }); + + test("should return false if the card number does not contain at least two different digits", () => { + expect(creditCardValidator("1111-1111-1111-1111")).toBe(false); + expect(creditCardValidator("1111 2222 2222 2222")).toBe(true); + }); + + test("should return false if the card number does not end with an even digit", () => { + expect(creditCardValidator("1234-5678-9012-3457")).toBe(false); + expect(creditCardValidator("1234 5678 9012 3456")).toBe(true); + }); + + test("should return false if the sum of all the digits is not greater than 16", () => { + expect(creditCardValidator("0000-0000-0000-0000")).toBe(false); + expect(creditCardValidator("1111 1111 1111 1111")).toBe(false); + expect(creditCardValidator("1234 5678 9012 3456")).toBe(true); + }); + + // test for less than 16 digits + test("should return false for a card number with less than 16 digits", () => { + expect(creditCardValidator("123456789012345")).toBe(false); + expect(creditCardValidator("1234-5678-9012-345")).toBe(false); + }); + + // test for more than 16 digits + test("should return false for a card number with more than 16 digits", () => { + expect(creditCardValidator("12345678901234567")).toBe(false); + expect(creditCardValidator("1234-5678-9012-34567")).toBe(false); + }); + + // test for only 16 digits without spaces or dashes + test("should return true for a card number with 16 digits without spaces or dashes", () => { + expect(creditCardValidator("1234567890123456")).toBe(true); + expect(creditCardValidator("0000000000000000")).toBe(false); + expect(creditCardValidator("1111111111111111")).toBe(false); + }); +}); diff --git a/Sprint-3/3-stretch/find.js b/Sprint-3/3-stretch/find.js index c7e79a2f2..3d3580073 100644 --- a/Sprint-3/3-stretch/find.js +++ b/Sprint-3/3-stretch/find.js @@ -20,6 +20,19 @@ console.log(find("code your future", "z")); // Pay particular attention to the following: // a) How the index variable updates during the call to find +// The index variable is set to 0 on line 2. +// When the function is called, the while loop on line 4 checks if index (0) is less than the length of the string (16). +// If the character is not found, the index will increment by 1 on line 8 +// Now, index is 1, and the while loop will check again, until the character is found or the index is no longer less than the length of the string. + // b) What is the if statement used to check +// The if statement on line 5 checks if the character at current index of the string is equal to the target character (char). +// If they are equal, the function returns the current index. + // c) Why is index++ being used? +// The index++ on line 8 is being used to update the index variable by incrementing it by 1. +// Given the character is not found at the current index, we need to move to the next index. + // d) What is the condition index < str.length used for? +// The condition index < str.length on line 4 is used to ensure that the while loop continues to execute as long as the index is less than the length of the string. +// More importantly, it prevents the while loop goes on forever into an infinite loop. diff --git a/Sprint-3/3-stretch/password-validator.js b/Sprint-3/3-stretch/password-validator.js index b55d527db..9707c30af 100644 --- a/Sprint-3/3-stretch/password-validator.js +++ b/Sprint-3/3-stretch/password-validator.js @@ -1,6 +1,30 @@ -function passwordValidator(password) { - return password.length < 5 ? false : true -} +function isValidPassword(password, previousPasswords) { + const lengthCondition = password.length >= 5; + console.log(`length condition: ${lengthCondition}`); + + const uppercaseCondition = /[A-Z]/.test(password); + console.log(`upper case condition: ${uppercaseCondition}`); + + const lowercaseCondition = /[a-z]/.test(password); + console.log(`lower case condition: ${lowercaseCondition}`); + + const numberCondition = /[0-9]/.test(password); + console.log(`number condition: ${numberCondition}`); + const symbolCondition = /[!#$%.*&]/.test(password); + console.log(`symbol condition: ${symbolCondition}`); + + const notInPreviousPasswords = !previousPasswords.includes(password); + console.log(`previous password condition: ${notInPreviousPasswords}`); + + return ( + lengthCondition && + uppercaseCondition && + lowercaseCondition && + numberCondition && + symbolCondition && + notInPreviousPasswords + ); +} -module.exports = passwordValidator; \ No newline at end of file +module.exports = isValidPassword; diff --git a/Sprint-3/3-stretch/password-validator.test.js b/Sprint-3/3-stretch/password-validator.test.js index 8fa3089d6..47adae6b2 100644 --- a/Sprint-3/3-stretch/password-validator.test.js +++ b/Sprint-3/3-stretch/password-validator.test.js @@ -15,12 +15,65 @@ To be valid, a password must: You must breakdown this problem in order to solve it. Find one test case first and get that working */ const isValidPassword = require("./password-validator"); -test("password has at least 5 characters", () => { - // Arrange - const password = "12345"; - // Act - const result = isValidPassword(password); - // Assert - expect(result).toEqual(true); -} -); \ No newline at end of file + +const previousPasswords = [ + "123Ab!", + "abcD1#", + "Password1!", + "Qwerty1*", + "Zxcvbnm2$", +]; + +describe("passwordValidator", () => { + const validPassword = "123Ab*"; + + test("returns true for passwords with at least 5 characters", () => { + expect(isValidPassword(validPassword, previousPasswords)).toBe(true); + }); + + test("return true for passwords with at least one uppercase letter", () => { + expect(isValidPassword(validPassword, previousPasswords)).toBe(true); + }); + + test("return true for passwords with at least one lowercase letter", () => { + expect(isValidPassword(validPassword, previousPasswords)).toBe(true); + }); + + test("return true for passwords with at least one number", () => { + expect(isValidPassword(validPassword, previousPasswords)).toBe(true); + }); + + test("return true for passwords with at least one non-alphanumeric symbol", () => { + expect(isValidPassword(validPassword, previousPasswords)).toBe(true); + }); + + test("return true for passwords that are not in the previous passwords array", () => { + expect(isValidPassword(validPassword, previousPasswords)).toBe(true); + }); + + // tests for false cases + + test("returns false for passwords with less than 5 characters", () => { + expect(isValidPassword("1234", previousPasswords)).toBe(false); + }); + + test("returns false for passwords without an uppercase letter", () => { + expect(isValidPassword("123ab*", previousPasswords)).toBe(false); + }); + + test("returns false for passwords without a lowercase letter", () => { + expect(isValidPassword("123AB*", previousPasswords)).toBe(false); + }); + + test("returns false for passwords without a number", () => { + expect(isValidPassword("abAB*", previousPasswords)).toBe(false); + }); + + test("returns false for passwords without a non-alphanumeric symbol", () => { + expect(isValidPassword("123Abc", previousPasswords)).toBe(false); + }); + + test("returns false for passwords that are in the previous passwords array", () => { + expect(isValidPassword("123Ab!", previousPasswords)).toBe(false); + }); +});