Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
3d7370b
Implementation for median
bytesandroses Feb 22, 2026
fdbd966
Test for empty array
bytesandroses Feb 22, 2026
a28e904
Test for array without duplicates
bytesandroses Feb 22, 2026
06339fc
Implement dedupe
bytesandroses Feb 22, 2026
4426ed9
Testing for dedupe
bytesandroses Feb 25, 2026
4b1ac0d
Refactor test
bytesandroses Feb 25, 2026
b6c0807
Testing for max
bytesandroses Feb 25, 2026
aa0f82d
Fix: correct case 2 input to array with single number, not just a sin…
bytesandroses Feb 25, 2026
cc952dd
Implement findMax
bytesandroses Feb 25, 2026
8596f7f
Readability: remove unused code
bytesandroses Feb 25, 2026
ebbad7e
Fix: reduce number of decimal places returned for sum
bytesandroses Feb 25, 2026
0940103
Refactor to use for of loop
bytesandroses Feb 25, 2026
1c72bab
Debug: address.js
bytesandroses Mar 3, 2026
88d95b1
Debug author
bytesandroses Mar 3, 2026
c0f7bb1
Fix: correct for loop
bytesandroses Mar 7, 2026
cb55db5
Fix: correct for loop
bytesandroses Mar 7, 2026
81f9946
Fix: print property instead of entire object
bytesandroses Mar 7, 2026
1c5c121
Test: Case 1 -- prop exists in object
bytesandroses Mar 8, 2026
b22a517
Fix: correct passing obj and prop into test
bytesandroses Mar 8, 2026
7689546
Test: Case 2 for when property not present in object
bytesandroses Mar 8, 2026
ceebce1
Test: Case 3 for empty object
bytesandroses Mar 8, 2026
b688460
Test: Case 3 for empty object
bytesandroses Mar 8, 2026
fdc221d
Test: Case 4 for invalid objects
bytesandroses Mar 8, 2026
c68b85c
Implement contains.js
bytesandroses Mar 8, 2026
49e36bb
Refactor with describe
bytesandroses Mar 8, 2026
7ad5748
Test: add test for Case 2
bytesandroses Mar 17, 2026
34d7c95
Refactor: remove unnecessary try/catch
bytesandroses Mar 17, 2026
47113d8
Refactor for readability
bytesandroses Mar 27, 2026
8aefebd
Fix: reorder validation checks to prevent weird results
bytesandroses Mar 27, 2026
ff9eac0
Refactor: remove unnecessary try/catch wrapping
bytesandroses Mar 27, 2026
2743b71
Ensure prototype properties aren't incorrectly returned as true
bytesandroses Mar 28, 2026
672d459
Fix: ensure prototype properties don't return true
bytesandroses Mar 28, 2026
e6cde3f
Check for nulls and arrays
bytesandroses Mar 28, 2026
c837ff1
Refactor
bytesandroses Mar 28, 2026
273dc37
Test: empty object input
bytesandroses Mar 28, 2026
eb1dee9
Test: array without duplicates
bytesandroses Mar 28, 2026
340015c
Implementation of tally function
bytesandroses Mar 28, 2026
420bc1f
Fix: correct tally variable with counts
bytesandroses Mar 28, 2026
8919eac
Test: array with duplicates
bytesandroses Mar 28, 2026
8d56810
Refactor: remove unnecessary debugging code
bytesandroses Mar 28, 2026
bf09c40
Test: invalid non array inputs
bytesandroses Mar 28, 2026
7e6ad11
Fix: split key-value pair on only first occurence of '='
bytesandroses Mar 28, 2026
21df2c2
Refactor: test for additional cases
bytesandroses Mar 28, 2026
50e80fd
Test: strings with multiple key-value pairs
bytesandroses Mar 28, 2026
a9a06c3
Validate input is string
bytesandroses Mar 28, 2026
774cce1
Ensure that '=' with spaces are processed correctly
bytesandroses Mar 28, 2026
9873f85
Fix: iterate over tests correctly
bytesandroses Mar 28, 2026
cd4b7b5
Fix: ensure input is stripped of spaces
bytesandroses Mar 28, 2026
0c144f3
Ensure both key and value are provided
bytesandroses Mar 28, 2026
a62b0eb
Ensure that neither the key nor value is made up entirely of whitespace
bytesandroses Mar 28, 2026
35e98cc
Fix: correct implementation and test
bytesandroses Mar 28, 2026
a2eb57f
Revert to main for files outside Sprint 2
bytesandroses Mar 28, 2026
2921a9e
Merge branch 'main' into coursework/Sprint-2
bytesandroses Mar 28, 2026
7c8f06d
Implement findMax function in max.js
bytesandroses Mar 28, 2026
a005979
Implement findMax function in max.js
bytesandroses Mar 28, 2026
e5aee85
Add sum function definition in sum.js
bytesandroses Mar 28, 2026
b212457
Fix formatting in sum.test.js
bytesandroses Mar 28, 2026
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
11 changes: 5 additions & 6 deletions Sprint-2/debug/address.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
// Predict and explain first...

// This code should log out the houseNumber from the address object
// but it isn't working...
// Fix anything that isn't working

const address = {
houseNumber: 42,
street: "Imaginary Road",
Expand All @@ -12,4 +6,9 @@ const address = {
postcode: "XYZ 123",
};

/* Prediction */
// This will throw an error. This is because unlike lists, key values are selected using a '.'
console.log(`My house number is ${address[0]}`);

/* Fix */
console.log(`My house number is ${address.houseNumber}`);
29 changes: 22 additions & 7 deletions Sprint-2/debug/author.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
// Predict and explain first...

// This program attempts to log out all the property values in the object.
// But it isn't working. Explain why first and then fix the problem

/* ======== Initial Script ======= */
const author = {
firstName: "Zadie",
lastName: "Smith",
Expand All @@ -11,6 +7,25 @@ const author = {
alive: true,
};

for (const value of author) {
console.log(value);
try {
for (const value of author) {
console.log(value);
}
} catch (error) {
console.error("Error:", error.message);
}

/* ============== Prediction ============== */
// It will print out only the name of the keys (i.e. firstName, lastName,
// occupation, age, and alive), but not their actual values.

/* ============== Actual Result ============== */
// Error: author is not iterable.
// This error occurs because the for...of loop can only be used with
// iterable objects like arrays, strings, etc. Since 'author' is an object,
// it is not iterable. To fix this, we can use a for...in loop instead.

/* ============== Corrected Script ============== */
for (const key in author) {
console.log(author[key]);
}
16 changes: 16 additions & 0 deletions Sprint-2/debug/recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// Each ingredient should be logged on a new line
// How can you fix it?

/* ============== Initial Script ============== */
const recipe = {
title: "bruschetta",
serves: 2,
Expand All @@ -13,3 +14,18 @@ const recipe = {
console.log(`${recipe.title} serves ${recipe.serves}
ingredients:
${recipe}`);

/* ============== Prediction ============== */
// It will throw an error when trying to print the ingredients.
// This is because the entire recipe object was called instead of
// just its ingredients property. JavaScript cannot print an object,
// hence the error is thrown.

/// ============== Actual Result ============== */
// It tunrs out that JavaScript does not throw an error when
// trying to print an object. Instead, it prints out [object Object].

/* ============== Corrected Script ============== */
console.log(`${recipe.title} serves ${recipe.serves}
ingredients:
- ${recipe.ingredients.join("\n - ")}`);
10 changes: 9 additions & 1 deletion Sprint-2/implement/contains.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
function contains() {}
function contains(object, property) {
if (typeof object !== "object" || object === null || Array.isArray(object)) {
throw new TypeError(
"First argument must be an object in the form { key: value }"
);
}

return object.hasOwnProperty(property);
}

module.exports = contains;
85 changes: 60 additions & 25 deletions Sprint-2/implement/contains.test.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,70 @@
const contains = require("./contains.js");

/*
Implement a function called contains that checks an object contains a
particular property
describe("contains", () => {
// Case 1: Should return true if the property exists in object.
test("should return true when object contains passed property name", () => {
const objsWithValidProps = [
[{ a: 1, b: 2 }, "b"],
[{ name: "John", age: 30 }, "name"],
[{ nested: { key: "value" } }, "nested"],
[{ id: 123, status: "active", language: "JavaScript" }, "status"],
[{ data: [], items: null }, "data"],
];

E.g. contains({a: 1, b: 2}, 'a') // returns true
as the object contains a key of 'a'
objsWithValidProps.forEach(([obj, prop]) => {
expect(contains(obj, prop)).toEqual(true);
});
});

E.g. contains({a: 1, b: 2}, 'c') // returns false
as the object doesn't contains a key of 'c'
*/
// Case 2: Should return false if the object does not contain the given property.
test("should return false when object does not contain passed property name", () => {
const objsWithoutProps = [
[{ a: 1, b: 2 }, "c"],
[{ name: "John", age: 30 }, "email"],
[{ nested: { key: "value" } }, "nonexistent"],
[{ id: 123, status: "active", language: "JavaScript" }, "description"],
[{ data: [], items: null }, "nonexistent"],
];

// Acceptance criteria:
objsWithoutProps.forEach(([obj, prop]) => {
expect(contains(obj, prop)).toEqual(false);
});
});

// Given a contains function
// When passed an object and a property name
// Then it should return true if the object contains the property, false otherwise
// Case 3: Should return false if the object is empty.
test("should return false when object is empty", () => {
expect(contains({}, "anyProperty")).toEqual(false);
});

// Given an empty object
// When passed to contains
// Then it should return false
test.todo("contains on empty object returns false");
// Case 4: Should return false for properties that only exist in the prototype chain
test("should return false for properties in prototype chain", () => {
const objsWithProtoProps = [
[{ a: 1 }, "toString"],
[{ name: "John", age: 30 }, "hasOwnProperty"],
[{ nested: { key: "value" } }, "isPrototypeOf"],
];

// Given an object with properties
// When passed to contains with an existing property name
// Then it should return true
objsWithProtoProps.forEach(([obj, prop]) => {
expect(contains(obj, prop)).toEqual(false);
});
});

// Given an object with properties
// When passed to contains with a non-existent property name
// Then it should return false
// Case 5: Should throw an error if a non-object is passed
test("should throw error when non-object is passed", () => {
const nonObjects = [
null,
undefined,
42,
"The Curse",
true,
Infinity,
["string"],
];

// Given invalid parameters like an array
// When passed to contains
// Then it should return false or throw an error
nonObjects.forEach((nonObj) => {
expect(() => contains(nonObj, "prop")).toThrow(
"First argument must be an object in the form { key: value }"
);
});
});
});
34 changes: 32 additions & 2 deletions Sprint-2/implement/lookup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
function createLookup() {
// implementation here
function createLookup(countryCurrencyPairs) {
let countryCurrencyObj = {};

for (const countryCurrencyPair of countryCurrencyPairs) {
if (!Array.isArray(countryCurrencyPair)) {
throw new Error("Country-currency pairs must be in array format");
}

if (countryCurrencyPair.length !== 2) {
throw new Error(
"Country-currency pairs must contain exactly two elements: country and currency"
);
}

let [country, currency] = countryCurrencyPair;

if (typeof country !== "string" || typeof currency !== "string") {
throw new Error("Country-currency pairs must be in string format");
}

if (country.trim() === "" || currency.trim() === "") {
throw new Error("Country and currency codes cannot be empty");
}

if (countryCurrencyObj[country]) {
throw new Error(`Duplicate country code found: ${country}`);
}

countryCurrencyObj[country] = currency;
}

return countryCurrencyObj;
}

module.exports = createLookup;
125 changes: 101 additions & 24 deletions Sprint-2/implement/lookup.test.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,112 @@
const createLookup = require("./lookup.js");

test.todo("creates a country currency code lookup for multiple codes");
describe("createLookup", () => {
// Case 1: Returns an empty object if no country-currency pairs are provided
test("returns an empty object if no country-currency pairs are provided", () => {
const countryCurrencyPairs = [];
const currencyObj = createLookup(countryCurrencyPairs);

/*
expect(currencyObj).toEqual({});
});

Create a lookup object of key value pairs from an array of code pairs
// Case 2: Returns country currency code lookup for a single country-currency pair
test("creates a country currency code lookup for a single code pair", () => {
const countryCurrencyPairs = [["US", "USD"]];
const currencyObj = createLookup(countryCurrencyPairs);

Acceptance Criteria:
expect(currencyObj).toEqual({
US: "USD",
});
});

Given
- An array of arrays representing country code and currency code pairs
e.g. [['US', 'USD'], ['CA', 'CAD']]
// Case 3: Returns country currency codes lookup for multiple country-currency pairs
test("creates a country currency code lookup for multiple codes", () => {
const countryCurrencyPairs = [
["US", "USD"],
["CA", "CAD"],
["GB", "GBP"],
["ZA", "ZAR"],
["NG", "NGN"],
];

When
- createLookup function is called with the country-currency array as an argument
const inputCurrencyPairObj = createLookup(countryCurrencyPairs);
const outputCurrencyPairObj = {
US: "USD",
CA: "CAD",
GB: "GBP",
ZA: "ZAR",
NG: "NGN",
};

Then
- It should return an object where:
- The keys are the country codes
- The values are the corresponding currency codes
expect(inputCurrencyPairObj).toEqual(outputCurrencyPairObj);
});

Example
Given: [['US', 'USD'], ['CA', 'CAD']]
// Case 4: Throws an error if a country-currency pair is not an array
test("throws an error if a country-currency pair is not an array", () => {
const countryCurrencyPairs = [
["US", "USD"],
["CA", "CAD"],
"GB-GBP",
["ZA", "ZAR"],
["NG", "NGN"],
];

When
createLookup(countryCurrencyPairs) is called
expect(() => createLookup(countryCurrencyPairs)).toThrow(
"Country-currency pairs must be in array format"
);
});

Then
It should return:
{
'US': 'USD',
'CA': 'CAD'
}
*/
// Case 5: Throws an error if a country-currency pair is missing a country or currency
test("throws an error if a country-currency pair is missing a country or currency", () => {
const countryCurrencyPairs = [
["US", ""],
["", "CAD"],
[" ", "GBP"],
];

for (const currencyPair of countryCurrencyPairs) {
expect(() => createLookup([currencyPair])).toThrow(
"Country and currency codes cannot be empty"
);
}
});

// Case 6: Throws an error if a country-currency pair contains more than two elements
test("throws an error if a country-currency pair contains more than two elements", () => {
const countryCurrencyPairs = [["GB", "GBP", "ZAR"]];

expect(() => createLookup(countryCurrencyPairs)).toThrow(
"Country-currency pairs must contain exactly two elements: country and currency"
);
});

// Case 7: Throws and error if a country-currency pair is duplicated
test("throws an error if a country-currency pair is duplicated", () => {
const countryCurrencyPairs = [
["US", "USD"],
["CA", "CAD"],
["US", "USD"],
];

expect(() => createLookup(countryCurrencyPairs)).toThrow(
"Duplicate country code found: US"
);
});

// Case 8: Throws an error if non-string values are used as country or currency codes
test("throws an error if non-string values are used as country or currency codes", () => {
const countryCurrencyPairs = [
[{ name: "United States" }, "USD"],
["CA", Infinity],
["GB", 1.21],
[undefined, "ZAR"],
["NG", null],
];

for (const currencyPair of countryCurrencyPairs) {
expect(() => createLookup([currencyPair])).toThrow(
"Country-currency pairs must be in string format"
);
}
});
});
Loading
Loading