From d110d210fce1a93ab9f60c0809a46274023f6867 Mon Sep 17 00:00:00 2001 From: Ammad Date: Wed, 22 Oct 2025 23:41:53 +0100 Subject: [PATCH 1/6] Complete count exercise --- Sprint-3/2-practice-tdd/count.js | 4 +++- Sprint-3/2-practice-tdd/count.test.js | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Sprint-3/2-practice-tdd/count.js b/Sprint-3/2-practice-tdd/count.js index 95b6ebb7d..924f72eb4 100644 --- a/Sprint-3/2-practice-tdd/count.js +++ b/Sprint-3/2-practice-tdd/count.js @@ -1,5 +1,7 @@ function countChar(stringOfCharacters, findCharacter) { - return 5 + return stringOfCharacters.split("").reduce((accumulator, character) => { + return accumulator + (character === findCharacter ? 1 : 0); + }, 0); } module.exports = countChar; diff --git a/Sprint-3/2-practice-tdd/count.test.js b/Sprint-3/2-practice-tdd/count.test.js index 42baf4b4b..9d012eaf5 100644 --- a/Sprint-3/2-practice-tdd/count.test.js +++ b/Sprint-3/2-practice-tdd/count.test.js @@ -22,3 +22,10 @@ test("should count multiple occurrences of a character", () => { // And a character char that does not exist within the case-sensitive str, // When the function is called with these inputs, // Then it should return 0, indicating that no occurrences of the char were found in the case-sensitive str. + +test("should count no occurences of z characters", () => { + const str = "aaaaa"; + const char = "z"; + const count = countChar(str, char); + expect(count).toEqual(0); +}); From 7536db77a606f96d68bdc503dc8a196f9368f4b8 Mon Sep 17 00:00:00 2001 From: Ammad Date: Sat, 25 Oct 2025 13:00:34 +0100 Subject: [PATCH 2/6] Completed get-ordinal-number exercise --- Sprint-3/2-practice-tdd/get-ordinal-number.js | 27 +++++++++- .../2-practice-tdd/get-ordinal-number.test.js | 52 ++++++++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/Sprint-3/2-practice-tdd/get-ordinal-number.js b/Sprint-3/2-practice-tdd/get-ordinal-number.js index f95d71db1..dd6ac16a2 100644 --- a/Sprint-3/2-practice-tdd/get-ordinal-number.js +++ b/Sprint-3/2-practice-tdd/get-ordinal-number.js @@ -1,5 +1,30 @@ function getOrdinalNumber(num) { - return "1st"; + if (isNaN(num)) { + return ""; + } + + const numberString = String(num); + const lastDigit = Number(numberString.slice(-1)); + const lastDigits = Number(numberString.slice(-2)); + let ordinal; + + console.log("lastDigits", lastDigits); + + if (num === 0) { + ordinal = ""; + } else if (lastDigits === 11) { + ordinal = "th"; + } else if (lastDigit === 1) { + ordinal = "st"; + } else if (lastDigit === 2) { + ordinal = "nd"; + } else if (lastDigit === 3) { + ordinal = "rd"; + } else { + ordinal = "th"; + } + + return `${num}${ordinal}`; } module.exports = getOrdinalNumber; diff --git a/Sprint-3/2-practice-tdd/get-ordinal-number.test.js b/Sprint-3/2-practice-tdd/get-ordinal-number.test.js index dfe4b6091..cc0c1a0fb 100644 --- a/Sprint-3/2-practice-tdd/get-ordinal-number.test.js +++ b/Sprint-3/2-practice-tdd/get-ordinal-number.test.js @@ -8,6 +8,54 @@ const getOrdinalNumber = require("./get-ordinal-number"); // When the number is 1, // Then the function should return "1st" -test("should return '1st' for 1", () => { - expect(getOrdinalNumber(1)).toEqual("1st"); +test("should return '@' for ", () => { + expect(getOrdinalNumber("@")).toEqual(""); +}); + +test("should return '0' for 0", () => { + expect(getOrdinalNumber(0)).toEqual("0"); +}); + +test("should return '11th' for 11", () => { + expect(getOrdinalNumber(11)).toEqual("11th"); +}); + +test("should return '-11th' for -11", () => { + expect(getOrdinalNumber(-11)).toEqual("-11th"); +}); + +test("should return `22nd` for 22", () => { + expect(getOrdinalNumber(22)).toEqual("22nd"); +}); + +test("should return `123rd` for 123", () => { + expect(getOrdinalNumber(123)).toEqual("123rd"); +}); + +test("should return '1234th' for 1234", () => { + expect(getOrdinalNumber(1234)).toEqual("1234th"); +}); + +test("should return '12345th' for 12345", () => { + expect(getOrdinalNumber(12345)).toEqual("12345th"); +}); + +test("should return '123456th' for 123456", () => { + expect(getOrdinalNumber(123456)).toEqual("123456th"); +}); + +test("should return '1234567th' for 1234567", () => { + expect(getOrdinalNumber(1234567)).toEqual("1234567th"); +}); + +test("should return '12345678th' for 12345678", () => { + expect(getOrdinalNumber(12345678)).toEqual("12345678th"); +}); + +test("should return '123456789th' for 123456789", () => { + expect(getOrdinalNumber(123456789)).toEqual("123456789th"); +}); + +test("should return '1234567890' for 1234567890th", () => { + expect(getOrdinalNumber(1234567890)).toEqual("1234567890th"); }); From fb189461629ebb596bc77996b9d52efc833655ce Mon Sep 17 00:00:00 2001 From: Ammad Date: Sat, 25 Oct 2025 15:30:10 +0100 Subject: [PATCH 3/6] Completed repeat exercise --- Sprint-3/2-practice-tdd/repeat.js | 14 ++++++++++++-- Sprint-3/2-practice-tdd/repeat.test.js | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Sprint-3/2-practice-tdd/repeat.js b/Sprint-3/2-practice-tdd/repeat.js index 00e60d7f3..5e097af7b 100644 --- a/Sprint-3/2-practice-tdd/repeat.js +++ b/Sprint-3/2-practice-tdd/repeat.js @@ -1,5 +1,15 @@ -function repeat() { - return "hellohellohello"; +function repeat(string, count) { + if (isNaN(count)) { + throw new Error("count is not a number"); + } else if (count < 0) { + throw new Error("negative numbers are not valid"); + } else if (count === 0) { + return ""; + } else if (count === 1) { + return string; + } else { + return string.repeat(count); + } } module.exports = repeat; diff --git a/Sprint-3/2-practice-tdd/repeat.test.js b/Sprint-3/2-practice-tdd/repeat.test.js index 34097b09c..81392f4e9 100644 --- a/Sprint-3/2-practice-tdd/repeat.test.js +++ b/Sprint-3/2-practice-tdd/repeat.test.js @@ -21,12 +21,35 @@ test("should repeat the string count times", () => { // When the repeat function is called with these inputs, // Then it should return the original str without repetition, ensuring that a count of 1 results in no repetition. +test("should repeat the string 1 times", () => { + const str = "Hello, World!"; + const count = 1; + const repeatedStr = repeat(str, count); + expect(repeatedStr).toEqual(str); +}); + // case: Handle Count of 0: // Given a target string str and a count equal to 0, // When the repeat function is called with these inputs, // Then it should return an empty string, ensuring that a count of 0 results in an empty output. +test("should return an empty string for 0 times", () => { + const str = "Bye, World!"; + const count = 0; + const repeatedStr = repeat(str, count); + expect(repeatedStr).toEqual(""); +}); + // case: Negative Count: // Given a target string str and a negative integer count, // When the repeat function is called with these inputs, // Then it should throw an error or return an appropriate error message, as negative counts are not valid. + +test("should throw an error for a negative number", () => { + expect(() => repeat("Ello!", -1)).toThrow("negative numbers are not valid"); +}); + +// case: count is not a number: +test("should throw an error when count is not a number", () => { + expect(() => repeat("Hello?", "@")).toThrow("count is not a number"); +}); From aac72a4339b9f6aa14a49807a0104eabc8bd2af4 Mon Sep 17 00:00:00 2001 From: Ammad Date: Mon, 27 Oct 2025 21:50:05 +0000 Subject: [PATCH 4/6] Completed password-validator exercise --- Sprint-3/3-stretch/password-validator.js | 16 ++++-- Sprint-3/3-stretch/password-validator.test.js | 54 +++++++++++++++---- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/Sprint-3/3-stretch/password-validator.js b/Sprint-3/3-stretch/password-validator.js index b55d527db..ac38b7bbb 100644 --- a/Sprint-3/3-stretch/password-validator.js +++ b/Sprint-3/3-stretch/password-validator.js @@ -1,6 +1,16 @@ +const previousPasswords = []; + function passwordValidator(password) { - return password.length < 5 ? false : true -} + if (previousPasswords.includes(password)) return false; + if (password.length < 5) return false; + if (!/[A-Z]/.test(password)) return false; + if (!/[a-z]/.test(password)) return false; + if (!/[0-9]/.test(password)) return false; + if (!/[!#$%.*&]/.test(password)) return false; + previousPasswords.push(password); + + return true; +} -module.exports = passwordValidator; \ No newline at end of file +module.exports = passwordValidator; diff --git a/Sprint-3/3-stretch/password-validator.test.js b/Sprint-3/3-stretch/password-validator.test.js index 8fa3089d6..9c94506e3 100644 --- a/Sprint-3/3-stretch/password-validator.test.js +++ b/Sprint-3/3-stretch/password-validator.test.js @@ -15,12 +15,48 @@ 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 + +test("invalid password (numbers only)", () => { + // Arrange + const password = "12345"; + // Act + const result = isValidPassword(password); + // Assert + expect(result).toEqual(false); +}); + +test("invalid password (lowercase letters only)", () => { + const password = "abcde"; + const result = isValidPassword(password); + expect(result).toEqual(false); +}); + +test("invalid password (uppercase letters only)", () => { + const password = "QWERTY"; + const result = isValidPassword(password); + expect(result).toEqual(false); +}); + +test("invalid password (non-alphanumeric symbols only)", () => { + const password = "!#$%.*&!"; + const result = isValidPassword(password); + expect(result).toEqual(false); +}); + +test("valid password", () => { + const password = "aB1!cD"; + const result = isValidPassword(password); + expect(result).toEqual(true); +}); + +test("duplicate password", () => { + const password = "aB1!cD"; + const result = isValidPassword(password); + expect(result).toEqual(false); +}); + +test("new valid password", () => { + const password = "zX1$2£€"; + const result = isValidPassword(password); + expect(result).toEqual(true); +}); From 4002e46a5fc8621b5ecca6fff74ab585001e0f2a Mon Sep 17 00:00:00 2001 From: Ammad Date: Tue, 28 Oct 2025 01:03:28 +0000 Subject: [PATCH 5/6] Completed credit-card-validator exercise --- Sprint-3/3-stretch/credit-card-validator.js | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Sprint-3/3-stretch/credit-card-validator.js diff --git a/Sprint-3/3-stretch/credit-card-validator.js b/Sprint-3/3-stretch/credit-card-validator.js new file mode 100644 index 000000000..b320d2243 --- /dev/null +++ b/Sprint-3/3-stretch/credit-card-validator.js @@ -0,0 +1,30 @@ +function creditCardValidator(cardNumber) { + // Check that the card number contains numbers only + if (isNaN(cardNumber)) return false; + + // Convert the card number to a string so we can check its digits easily + let cardNumberString = String(cardNumber); + + // Check that the card number has exactly 16 digits + if (cardNumberString.length != 16) return false; + + // Check that the last digit is even + if (cardNumberString[15] % 2 != 0) return false; + + // Calculate the sum of all digits + const sum = cardNumberString + .split("") + .reduce((sum, digit) => (sum += Number(digit)), 0); + + // If the sum of all digits is 16 or less, the card is invalid + if (sum <= 16) return false; + + // Use Set to filter out duplicate digits + let uniqueDigits = new Set(cardNumberString); + + // Make sure the card number isn’t made up of all the same digit + if (uniqueDigits.size < 2) return false; + + // If all conditions pass, the card number is valid + return true; +} From 5394a9ef8e139452782b9508532bde4619d4a302 Mon Sep 17 00:00:00 2001 From: Ammad Date: Mon, 3 Nov 2025 17:12:30 +0000 Subject: [PATCH 6/6] Address the issues from the pull request comments --- Sprint-3/2-practice-tdd/count.js | 18 ++++++++ Sprint-3/2-practice-tdd/count.test.js | 41 ++++++++++++++++++- Sprint-3/2-practice-tdd/get-ordinal-number.js | 4 +- .../2-practice-tdd/get-ordinal-number.test.js | 10 ++++- 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/Sprint-3/2-practice-tdd/count.js b/Sprint-3/2-practice-tdd/count.js index 924f72eb4..7bc01e201 100644 --- a/Sprint-3/2-practice-tdd/count.js +++ b/Sprint-3/2-practice-tdd/count.js @@ -1,4 +1,22 @@ function countChar(stringOfCharacters, findCharacter) { + if (typeof stringOfCharacters !== "string") { + throw new TypeError( + "The argument for parameter stringOfCharacters is not a String type" + ); + } + + if (typeof findCharacter !== "string") { + throw new TypeError( + "The argument for parameter findCharacter is not a String type" + ); + } + + if (findCharacter.length !== 1) { + throw new Error( + "Parameter findCharacter is must contain a single character" + ); + } + return stringOfCharacters.split("").reduce((accumulator, character) => { return accumulator + (character === findCharacter ? 1 : 0); }, 0); diff --git a/Sprint-3/2-practice-tdd/count.test.js b/Sprint-3/2-practice-tdd/count.test.js index 9d012eaf5..969283f3f 100644 --- a/Sprint-3/2-practice-tdd/count.test.js +++ b/Sprint-3/2-practice-tdd/count.test.js @@ -23,9 +23,48 @@ test("should count multiple occurrences of a character", () => { // When the function is called with these inputs, // Then it should return 0, indicating that no occurrences of the char were found in the case-sensitive str. -test("should count no occurences of z characters", () => { +test("should count no occurrences of z characters", () => { const str = "aaaaa"; const char = "z"; const count = countChar(str, char); expect(count).toEqual(0); }); + +test("should return 0 for an empty string and a non-empty character", () => { + const str = ""; + const char = "z"; + const count = countChar(str, char); + expect(count).toEqual(0); +}); + +test("should return 0 for an empty string and a whitespace character", () => { + const str = ""; + const char = " "; + const count = countChar(str, char); + expect(count).toEqual(0); +}); + +test("should return 0 when the string contains the character in a different case", () => { + const str = "aBcDeF"; + const char = "A"; + const count = countChar(str, char); + expect(count).toEqual(0); +}); + +test("throws error when the first argument is not a string", () => { + expect(() => countChar(1234, "1")).toThrow( + "The argument for parameter stringOfCharacters is not a String type" + ); +}); + +test("throws error when the second argument is not a string", () => { + expect(() => countChar("1234", 1)).toThrow( + "The argument for parameter findCharacter is not a String type" + ); +}); + +test("throws error when second argument is longer than one character", () => { + expect(() => countChar("1234", "12")).toThrow( + "Parameter findCharacter is must contain a single character" + ); +}); diff --git a/Sprint-3/2-practice-tdd/get-ordinal-number.js b/Sprint-3/2-practice-tdd/get-ordinal-number.js index dd6ac16a2..3d7ca87ba 100644 --- a/Sprint-3/2-practice-tdd/get-ordinal-number.js +++ b/Sprint-3/2-practice-tdd/get-ordinal-number.js @@ -8,11 +8,9 @@ function getOrdinalNumber(num) { const lastDigits = Number(numberString.slice(-2)); let ordinal; - console.log("lastDigits", lastDigits); - if (num === 0) { ordinal = ""; - } else if (lastDigits === 11) { + } else if ([11, 12, 13].includes(lastDigits)) { ordinal = "th"; } else if (lastDigit === 1) { ordinal = "st"; diff --git a/Sprint-3/2-practice-tdd/get-ordinal-number.test.js b/Sprint-3/2-practice-tdd/get-ordinal-number.test.js index cc0c1a0fb..ba657bcaf 100644 --- a/Sprint-3/2-practice-tdd/get-ordinal-number.test.js +++ b/Sprint-3/2-practice-tdd/get-ordinal-number.test.js @@ -8,7 +8,7 @@ const getOrdinalNumber = require("./get-ordinal-number"); // When the number is 1, // Then the function should return "1st" -test("should return '@' for ", () => { +test("should return an empty string for a non-numerical character", () => { expect(getOrdinalNumber("@")).toEqual(""); }); @@ -20,6 +20,14 @@ test("should return '11th' for 11", () => { expect(getOrdinalNumber(11)).toEqual("11th"); }); +test("should return '12th' for 12", () => { + expect(getOrdinalNumber(12)).toEqual("12th"); +}); + +test("should return '13th' for 13", () => { + expect(getOrdinalNumber(13)).toEqual("13th"); +}); + test("should return '-11th' for -11", () => { expect(getOrdinalNumber(-11)).toEqual("-11th"); });