Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion Sprint-3/2-practice-tdd/count.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,50 @@
/**
* countChar(stringOfCharacters, findCharacter)
*
* Count the number of times a single character appears in a string.
*
* Behaviour / contract:
* - The function is case-sensitive: 'a' ≠ 'A'.
* - `stringOfCharacters` may be `null` or `undefined`; in that case the function returns 0.
* - `findCharacter` is treated as a single character (a single Unicode code point).
* If you pass a longer string it will never match.
*
* Parameters:
* @param {string|null|undefined} stringOfCharacters - The string to search through.
* @param {string} findCharacter - The single character to count (should be length 1).
*
* Returns:
* @returns {number} The number of occurrences of `findCharacter` in `stringOfCharacters`.
*
* Throws:
* - Does not throw for `null`/`undefined` source; returns 0.
* - If you want stricter validation for types or for multi-character `findCharacter`,
* validate and throw in the implementation and update tests accordingly.
*
* Examples:
* // basic
* countChar('aaaaa', 'a'); // 5
* countChar('Hello', 'l'); // 2
*
* // empty/absent inputs
* countChar('', 'a'); // 0
* countChar(null, 'a'); // 0
*
* Notes:
* - Uses strict equality (===) so it matches exact code points.
* - For emoji or other characters outside the BMP this implementation (for..of)
* iterates code points, which handles many emoji correctly.
*/

function countChar(stringOfCharacters, findCharacter) {
return 5
if (stringOfCharacters == null) return 0;
let count = 0;
for (const char of stringOfCharacters) {
if (char === findCharacter) {
count++;
}
}
return count;
}

module.exports = countChar;
19 changes: 19 additions & 0 deletions Sprint-3/2-practice-tdd/count.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,22 @@ test("should count multiple occurrences of a character", () => {
// 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.
test("return 0 when the character is not found", () => {
const str = "hello world";
const char = "x";
const count = countChar(str, char);
expect(count).toEqual(0);
});

test("handles empty source string", () => {
const str = "";
const char = "a";
const count = countChar(str, char);
expect(count).toEqual(0);
});

test("handles null or undefined source string", () => {
const char = "a";
expect(countChar(null, char)).toEqual(0);
expect(countChar(undefined, char)).toEqual(0);
});
22 changes: 21 additions & 1 deletion Sprint-3/2-practice-tdd/get-ordinal-number.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
function getOrdinalNumber(num) {
return "1st";
// Validate input: must be a number (not a string, null or undefined) and not NaN
if (typeof num !== "number" || Number.isNaN(num)) {
throw new TypeError("Input must be a number");
}

const abs = Math.abs(num);
const lastTwoDigits = abs % 100;
if (lastTwoDigits >= 11 && lastTwoDigits <= 13) {
return `${num}th`;
}
const lastDigit = lastTwoDigits % 10;
if (lastDigit === 1) {
return `${num}st`;
}
if (lastDigit === 2) {
return `${num}nd`;
}
if (lastDigit === 3) {
return `${num}rd`;
}
return `${num}th`;
}

module.exports = getOrdinalNumber;
61 changes: 57 additions & 4 deletions Sprint-3/2-practice-tdd/get-ordinal-number.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,61 @@ const getOrdinalNumber = require("./get-ordinal-number");
// 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");
test("should append 'st' for numbers ending with 1, excluding 11", () => {
expect(getOrdinalNumber(1)).toBe("1st");
expect(getOrdinalNumber(21)).toBe("21st");
expect(getOrdinalNumber(101)).toBe("101st");
expect(getOrdinalNumber(131)).toBe("131st");
});

test("should append 'nd' for numbers ending with 2, excluding 12", () => {
expect(getOrdinalNumber(2)).toBe("2nd");
expect(getOrdinalNumber(22)).toBe("22nd");
expect(getOrdinalNumber(132)).toBe("132nd");
});

test("should append 'rd' for numbers ending with 3, excluding 13", () => {
expect(getOrdinalNumber(3)).toBe("3rd");
expect(getOrdinalNumber(23)).toBe("23rd");
expect(getOrdinalNumber(133)).toBe("133rd");
});

test("should append 'th' for numbers ending with 11, 12, or 13", () => {
expect(getOrdinalNumber(11)).toBe("11th");
expect(getOrdinalNumber(12)).toBe("12th");
expect(getOrdinalNumber(13)).toBe("13th");
expect(getOrdinalNumber(111)).toBe("111th");
expect(getOrdinalNumber(112)).toBe("112th");
expect(getOrdinalNumber(113)).toBe("113th");
});

test("should append 'th' for numbers ending with 4-9 or 0", () => {
expect(getOrdinalNumber(4)).toBe("4th");
expect(getOrdinalNumber(5)).toBe("5th");
expect(getOrdinalNumber(6)).toBe("6th");
expect(getOrdinalNumber(7)).toBe("7th");
expect(getOrdinalNumber(8)).toBe("8th");
expect(getOrdinalNumber(9)).toBe("9th");
expect(getOrdinalNumber(0)).toBe("0th");
});

test("non-integer and negative numbers should be handled correctly", () => {
expect(getOrdinalNumber(1.5)).toBe("1.5th");
expect(getOrdinalNumber(-2.3)).toBe("-2.3th");
expect(getOrdinalNumber(-11)).toBe("-11th");
});

test("invalid input should throw an error", () => {
expect(() => getOrdinalNumber("string")).toThrow("Input must be a number");
expect(() => getOrdinalNumber(null)).toThrow("Input must be a number");
expect(() => getOrdinalNumber(undefined)).toThrow("Input must be a number");
});

test("NaN input should throw an error", () => {
expect(() => getOrdinalNumber(NaN)).toThrow("Input must be a number");
});

test("Infinity input should be handled correctly", () => {
expect(getOrdinalNumber(Infinity)).toBe("Infinityth");
expect(getOrdinalNumber(-Infinity)).toBe("-Infinityth");
});
17 changes: 13 additions & 4 deletions Sprint-3/2-practice-tdd/repeat-str.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
function repeatStr() {
// Your implementation of this function must *not* call String.prototype.repeat (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat).
// The goal is to re-implement that function, not to use it.
return "hellohellohello";
function repeatStr(str, count) {
if (typeof str !== "string") {
throw new TypeError("First argument must be a string");
}
if (!Number.isInteger(count) || count < 0) {
throw new TypeError("Count must be a non-negative integer");
}

let result = "";
for (let i = 0; i < count; i++) {
result += str;
}
return result;
}

module.exports = repeatStr;
88 changes: 87 additions & 1 deletion Sprint-3/2-practice-tdd/repeat-str.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,99 @@ test("should repeat the string count times", () => {
// 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.

test("should return the original string when count is 1", () => {
const str = "world";
const count = 1;
const repeatedStr = repeatStr(str, count);
expect(repeatedStr).toEqual("world");
});
// 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.
test("should return an empty string when count is 0", () => {
const str = "test";
const count = 0;
const repeatedStr = repeatStr(str, count);
expect(repeatedStr).toEqual("");
});

// 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.
test("should throw an error for negative count", () => {
const str = "error";
const count = -2;
expect(() => repeatStr(str, count)).toThrow(
"Count must be a non-negative integer"
);
});

test("should throw an error for non-integer count", () => {
const str = "error";
const count = 2.5;
expect(() => repeatStr(str, count)).toThrow(
"Count must be a non-negative integer"
);
});

test("should throw an error for non-string input", () => {
const str = 123;
const count = 3;
expect(() => repeatStr(str, count)).toThrow(
"First argument must be a string"
);
});

test("should throw an error for null or undefined input", () => {
const count = 3;
expect(() => repeatStr(null, count)).toThrow(
"First argument must be a string"
);
expect(() => repeatStr(undefined, count)).toThrow(
"First argument must be a string"
);
});

test("handle empty string input", () => {
const str = "";
const count = 5;
const repeatedStr = repeatStr(str, count);
expect(repeatedStr).toEqual("");
});

test("handle large count input", () => {
const str = "a";
const count = 1000;
const repeatedStr = repeatStr(str, count);
expect(repeatedStr).toEqual("a".repeat(count));
});

test("handle special characters in string", () => {
const str = "!@#";
const count = 4;
const repeatedStr = repeatStr(str, count);
expect(repeatedStr).toEqual("!@#!@#!@#!@#");
});

test("handle whitespace in string", () => {
const str = " ";
const count = 3;
const repeatedStr = repeatStr(str, count);
expect(repeatedStr).toEqual(" ");
});

test("repeats unicode characters correctly", () => {
const str = "😊";
const count = 5;
const repeatedStr = repeatStr(str, count);
expect(repeatedStr).toEqual("😊😊😊😊😊");
});

test("handles empty string", () => {
const str = "";
const count = 5;
const repeatedStr = repeatStr(str, count);
expect(repeatedStr).toEqual("");
});
Loading