diff --git a/Sprint-3/2-practice-tdd/count.js b/Sprint-3/2-practice-tdd/count.js index 95b6ebb7d..bc13deb4c 100644 --- a/Sprint-3/2-practice-tdd/count.js +++ b/Sprint-3/2-practice-tdd/count.js @@ -1,5 +1,30 @@ function countChar(stringOfCharacters, findCharacter) { - return 5 + if ( + typeof stringOfCharacters != "string" || + typeof findCharacter != "string" + ) { + throw new Error("Please enter a valid string"); + } + + if (findCharacter.length != 1) { + throw new Error( + "Please enter a single character for findCharacter, e.g. 't" + ); + } + + if (stringOfCharacters.length === 0) { + throw new Error( + "Please enter a non-empty string, e.g. 'A series of unfortunate events'" + ); + } + + let charCount = 0; + let lowerCaseChar = findCharacter.toLowerCase(); + for (char of stringOfCharacters.toLowerCase()) { + if (lowerCaseChar === char) charCount++; + } + + return charCount; } module.exports = countChar; diff --git a/Sprint-3/2-practice-tdd/count.test.js b/Sprint-3/2-practice-tdd/count.test.js index 179ea0ddf..a912eca6f 100644 --- a/Sprint-3/2-practice-tdd/count.test.js +++ b/Sprint-3/2-practice-tdd/count.test.js @@ -1,24 +1,64 @@ -// implement a function countChar that counts the number of times a character occurs in a string const countChar = require("./count"); -// Given a string `str` and a single character `char` to search for, -// When the countChar function is called with these inputs, -// Then it should: - -// Scenario: Multiple Occurrences -// Given the input string `str`, -// And a character `char` that occurs one or more times in `str` (e.g., 'a' in 'aaaaa'), -// When the function is called with these inputs, -// Then it should correctly count occurrences of `char`. - -test("should count multiple occurrences of a character", () => { - const str = "aaaaa"; - const char = "a"; - const count = countChar(str, char); - expect(count).toEqual(5); + +// Scenario 1: Multiple Occurrences +test("Should count multiple occurrences of a character", () => { + const multipleOccurrences = [ + { a: "aaaaa", b: "a", c: 5 }, + { a: "sea saw", b: "s", c: 2 }, + { a: "Arrested Development", b: "d", c: 2 }, + { a: "* Star * TV *", b: "*", c: 3 }, + ]; + + for (const { a, b, c } of multipleOccurrences) { + expect(countChar(a, b)).toEqual(c); + } +}); + +// Scenario 2: Single Occurrence +test("Should count single occurrence of a character", () => { + const singleOccurrences = [ + { a: "a", b: "a" }, + { a: "Star Light", b: "i" }, + { a: "!@#$%^&*()", b: "#" }, + { a: "Why fly?", b: " " }, + ]; + + for (const { a, b } of singleOccurrences) { + expect(countChar(a, b)).toEqual(1); + } }); -// Scenario: No Occurrences -// Given the input string `str`, -// And a character `char` that does not exist within `str`. -// When the function is called with these inputs, -// Then it should return 0, indicating that no occurrences of `char` were found. +// Scenario 3: No Occurrence +test("Should return 0 for no occurrence of a character", () => { + const noOccurrences = [ + { a: "The Rookie", b: "S" }, + { a: "Angela Bassett", b: "r" }, + { a: "Santa Clarita Diet", b: "*" }, + { a: "Better Off Ted", b: "9" }, + ]; + + for (const { a, b } of noOccurrences) { + expect(countChar(a, b)).toEqual(0); + } +}); + +// Scenario 4: Invalid Entries +test("Should throw an error when given an invalid input", () => { + const invalidEntries = [ + { a: "Courage, the Cowardly Dog", b: "dog" }, + { a: "Sheep in the Big City", b: 1 }, + { a: -205, b: "a" }, + { a: -205, b: 55.5 }, + { a: true, b: "f" }, + { a: undefined, b: "f" }, + { a: null, b: true }, + { a: false, b: true }, + { a: [false], b: {} }, + ]; + + for (const { a, b } of invalidEntries) { + expect(() => { + countChar(a, b); + }).toThrow(); + } +}); diff --git a/Sprint-3/2-practice-tdd/get-ordinal-number.js b/Sprint-3/2-practice-tdd/get-ordinal-number.js index f95d71db1..97dd54a77 100644 --- a/Sprint-3/2-practice-tdd/get-ordinal-number.js +++ b/Sprint-3/2-practice-tdd/get-ordinal-number.js @@ -1,5 +1,27 @@ function getOrdinalNumber(num) { - return "1st"; + if (typeof num != "number" || !Number.isInteger(num)) { + throw new Error("Please enter an integer"); + } + + const positiveNumber = Math.abs(num); + + let suffix; + + switch (true) { + case positiveNumber % 10 === 1 && positiveNumber % 100 !== 11: + suffix = "st"; + break; + case positiveNumber % 10 === 2 && positiveNumber % 100 !== 12: + suffix = "nd"; + break; + case positiveNumber % 10 === 3 && positiveNumber % 100 !== 13: + suffix = "rd"; + break; + default: + suffix = "th"; + } + + return `${num}${suffix}`; } 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 adfa58560..1c71924b9 100644 --- a/Sprint-3/2-practice-tdd/get-ordinal-number.test.js +++ b/Sprint-3/2-practice-tdd/get-ordinal-number.test.js @@ -1,20 +1,123 @@ const getOrdinalNumber = require("./get-ordinal-number"); -// In this week's prep, we started implementing getOrdinalNumber. -// Continue testing and implementing getOrdinalNumber for additional cases. -// Write your tests using Jest — remember to run your tests often for continual feedback. +// Case 1: Numbers ending with 1 (but not in 11) +test("should append 'st' for numbers ending with 1, except those ending with 11", () => { + const numbers = [1, 21, 131]; + + for (const number of numbers) { + expect(getOrdinalNumber(number)).toEqual(`${number}st`); + } +}); -// To ensure thorough testing, we need broad scenarios that cover all possible cases. -// Listing individual values, however, can quickly lead to an unmanageable number of test cases. -// Instead of writing tests for individual numbers, consider grouping all possible input values -// into meaningful categories. Then, select representative samples from each category to test. -// This approach improves coverage and makes our tests easier to maintain. +// Case 2: Numbers ending with 11 +test("should append 'th' for numbers ending with 11", () => { + const numbers = [11, 111, 700011]; -// Case 1: Numbers ending with 1 (but not 11) -// When the number ends with 1, except those ending with 11, -// Then the function should return a string by appending "st" to the number. -test("should append 'st' for numbers ending with 1, except those ending with 11", () => { - expect(getOrdinalNumber(1)).toEqual("1st"); - expect(getOrdinalNumber(21)).toEqual("21st"); - expect(getOrdinalNumber(131)).toEqual("131st"); + for (const number of numbers) { + expect(getOrdinalNumber(number)).toEqual(`${number}th`); + } +}); + +// Case 3: Numbers ending with 2 (but not in 12) +test("should append 'nd' for numbers ending in 2", () => { + const numbers = [2, 22, 32, 502]; + + for (const number of numbers) { + expect(getOrdinalNumber(number)).toEqual(`${number}nd`); + } +}); + +// Case 4: Numbers ending with 12 +test("should append 'th' for numbers ending in 12", () => { + const numbers = [12, 212, 312, 5012]; + + for (const number of numbers) { + expect(getOrdinalNumber(number)).toEqual(`${number}th`); + } +}); + +// Case 5: Numbers ending in 3 (but not in 13) +test("should append 'rd' for numbers ending in 3 (but not 13)", () => { + const numbers = [3, 23, 33, 1063]; + + for (const number of numbers) { + expect(getOrdinalNumber(number)).toEqual(`${number}rd`); + } +}); + +// Case 6: Numbers ending in 13 +test("should append 'th' for numbers ending in 13", () => { + const numbers = [13, 113, 613, 713]; + + for (const number of numbers) { + expect(getOrdinalNumber(number)).toEqual(`${number}th`); + } +}); + +// Case 7: Numbers ending in 4-10 +test("should append 'th' for numbers ending in 4-10", () => { + const lastDigits = [4, 5, 6, 7, 8, 9, 10]; + const bases = [0, 10, 50, 90, 100]; + + for (const lastDigit of lastDigits) { + for (const base of bases) { + const finalNumber = base + lastDigit; + expect(getOrdinalNumber(finalNumber)).toEqual(`${finalNumber}th`); + } + } +}); + +// Case 8: Negative numbers +test("should return ordinal number for negative integer input", () => { + const ordinals = [ + { a: -2, b: "-2nd" }, + { a: -1, b: "-1st" }, + { a: -3, b: "-3rd" }, + { a: -4, b: "-4th" }, + { a: -11, b: "-11th" }, + { a: -12, b: "-12th" }, + { a: -13, b: "-13th" }, + ]; + + for (const { a, b } of ordinals) { + expect(getOrdinalNumber(a)).toEqual(b); + } +}); + +// Case 9: Decimal representations of integers +test("should return ordinal number for integer in decimal form", () => { + const ordinals = [ + { a: 1.0, b: "1st" }, + { a: 2.0, b: "2nd" }, + { a: 3.0, b: "3rd" }, + { a: 4.0, b: "4th" }, + { a: -11.0, b: "-11th" }, + { a: -12.0, b: "-12th" }, + { a: -13.0, b: "-13th" }, + ]; + + for (const { a, b } of ordinals) { + expect(getOrdinalNumber(a)).toEqual(b); + } +}); + +// Case 10: Invalid entries +test("should throw error for invalid inputs", () => { + const invalidEntries = [ + "one", + "", + [1], + null, + undefined, + 9.5, + 8.00001, + {}, + true, + ]; + + for (const entry of invalidEntries) { + expect(() => { + getOrdinalNumber(entry); + }).toThrow(); + } }); diff --git a/Sprint-3/2-practice-tdd/repeat-str.js b/Sprint-3/2-practice-tdd/repeat-str.js index 3838c7b00..e0ac371d0 100644 --- a/Sprint-3/2-practice-tdd/repeat-str.js +++ b/Sprint-3/2-practice-tdd/repeat-str.js @@ -1,5 +1,13 @@ -function repeatStr() { - return "hellohellohello"; +function repeatStr(str, count) { + if (typeof str !== "string") + throw new Error("Please use a string i.e. 'Hello World'"); + + if (!Number.isInteger(count)) + throw new Error("Please set count to an integer"); + + if (count < 0) throw new Error("Please use a count of 0 or greater"); + + return str.repeat(count); } module.exports = repeatStr; diff --git a/Sprint-3/2-practice-tdd/repeat-str.test.js b/Sprint-3/2-practice-tdd/repeat-str.test.js index a3fc1196c..89c87bedd 100644 --- a/Sprint-3/2-practice-tdd/repeat-str.test.js +++ b/Sprint-3/2-practice-tdd/repeat-str.test.js @@ -1,32 +1,78 @@ -// Implement a function repeatStr const repeatStr = require("./repeat-str"); -// Given a target string `str` and a positive integer `count`, -// When the repeatStr function is called with these inputs, -// Then it should: - -// Case: handle multiple repetitions: -// Given a target string `str` and a positive integer `count` greater than 1, -// When the repeatStr function is called with these inputs, -// Then it should return a string that contains the original `str` repeated `count` times. +// Case 1: handle count of 1 test("should repeat the string count times", () => { - const str = "hello"; - const count = 3; - const repeatedStr = repeatStr(str, count); - expect(repeatedStr).toEqual("hellohellohello"); + const repeats = [ + { a: "hello", b: 1, c: "hello" }, + { a: "Silo", b: 1, c: "Silo" }, + { a: "Ugly Betty", b: 1, c: "Ugly Betty" }, + { a: "ByteOil", b: 1, c: "ByteOil" }, + ]; + + for (const { a, b, c } of repeats) { + expect(repeatStr(a, b)).toEqual(c); + } +}); + +// Case 2: handle count greater than 1 +test("should return the original string repeated", () => { + const repeats = [ + { a: "hello", b: 3, c: "hellohellohello" }, + { a: "CYF ", b: 5, c: "CYF CYF CYF CYF CYF " }, + { + a: "My Year of Meat", + b: 2, + c: "My Year of MeatMy Year of Meat", + }, + { a: "Y2K", b: 10, c: "Y2KY2KY2KY2KY2KY2KY2KY2KY2KY2K" }, + ]; + + for (const { a, b, c } of repeats) { + expect(repeatStr(a, b)).toEqual(c); + } }); -// Case: handle count of 1: -// Given a target string `str` and a `count` equal to 1, -// When the repeatStr function is called with these inputs, -// Then it should return the original `str` without repetition. +// Case 3: Handle count of 0 +test("should return an empty string when count is 0", () => { + const repeats = [ + { a: "The Office", b: 0, c: "" }, + { a: "Angela Martin", b: 0, c: "" }, + { a: "Michael Scott", b: 0, c: "" }, + { a: "Kevin Malone", b: 0, c: "" }, + ]; -// Case: Handle count of 0: -// Given a target string `str` and a `count` equal to 0, -// When the repeatStr function is called with these inputs, -// Then it should return an empty string. + for (const { a, b, c } of repeats) { + expect(repeatStr(a, b)).toEqual(c); + } +}); -// Case: Handle negative count: -// Given a target string `str` and a negative integer `count`, -// When the repeatStr function is called with these inputs, -// Then it should throw an error, as negative counts are not valid. +// Case 4: Handle negative count +test("should return an empty string when count is negative", () => { + const repeats = [ + { a: "Osuofia in London", b: -1 }, + { a: "Nkem Owoh", b: -5 }, + { a: "Mara Derwent", b: -10 }, + { a: "Cynthia Okereke", b: -100 }, + ]; + + for (const { a, b } of repeats) { + expect(() => repeatStr(a, b)).toThrow(); + } +}); + +// Case 5: Handle non-string input +test("should throw an error when input is not a string", () => { + const repeats = [ + { a: 123, b: 3 }, + { a: "123", b: "3" }, + { a: "true", b: true }, + { a: null, b: 1 }, + { a: "undefined", b: undefined }, + { a: {}, b: 4 }, + { a: [], b: 0 }, + ]; + + for (const { a, b } of repeats) { + expect(() => repeatStr(a, b)).toThrow(); + } +});