Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3423b3d
Fix the code in the log on how to get dictionary value
jamesishimwe Apr 10, 2026
8ea5df9
Fix the code for iterating dictionary
jamesishimwe Apr 10, 2026
1030df2
Fix the code to get ingredients from recipe to recipe.ingredient
jamesishimwe Apr 10, 2026
b056074
Implement the function contains
jamesishimwe Apr 10, 2026
dd0f4aa
Write tests for contains function
jamesishimwe Apr 10, 2026
3926858
Implement function createLookUp
jamesishimwe Apr 11, 2026
cb7f840
Add test for undefined array
jamesishimwe Apr 11, 2026
126e361
Write tests for lookup function
jamesishimwe Apr 11, 2026
35fb86c
Fix the code for queryString
jamesishimwe May 1, 2026
baf9e28
Remove ? from the query string
jamesishimwe May 1, 2026
c2cc321
Add code to skip empty segments
jamesishimwe May 1, 2026
8688782
Add simple key value pair
jamesishimwe May 1, 2026
4fc5819
Add test to check if it strips leading question marks
jamesishimwe May 1, 2026
bde632c
Add test for null,empty and undefined
jamesishimwe May 1, 2026
feb056f
Add test for URL Encoded Content
jamesishimwe May 1, 2026
51e10b8
Add test for redudant and duplicate ampersands
jamesishimwe May 1, 2026
6a31914
Add test for empty and missing values
jamesishimwe May 1, 2026
02c49e6
Fix code to pass the decodess url encoded strings and complex charact…
jamesishimwe May 1, 2026
f370fe3
Add test for empty array
jamesishimwe May 1, 2026
fa3b442
Add code for the empty array
jamesishimwe May 1, 2026
4176d24
Add code for throwing error if not array
jamesishimwe May 1, 2026
e0f7967
Add test for not array
jamesishimwe May 1, 2026
85dab09
Add code for counting duplicates
jamesishimwe May 1, 2026
b046080
Add test for duplicate array
jamesishimwe May 1, 2026
29cfb09
Fix the code and answer the questions
jamesishimwe May 1, 2026
20d5acc
Create test file for invert
jamesishimwe May 1, 2026
6cc9c37
Create test for the invert function
jamesishimwe May 1, 2026
24b56be
Format the code
jamesishimwe May 1, 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
2 changes: 1 addition & 1 deletion Sprint-2/debug/address.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ const address = {
postcode: "XYZ 123",
};

console.log(`My house number is ${address[0]}`);
console.log(`My house number is ${address.houseNumber}`);
2 changes: 1 addition & 1 deletion Sprint-2/debug/author.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ const author = {
alive: true,
};

for (const value of author) {
for (const value of Object.values(author)) {
console.log(value);
}
2 changes: 1 addition & 1 deletion Sprint-2/debug/recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ const recipe = {

console.log(`${recipe.title} serves ${recipe.serves}
ingredients:
${recipe}`);
${recipe.ingredients}`);
6 changes: 5 additions & 1 deletion Sprint-2/implement/contains.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
function contains() {}
function contains(Obj, key) {
if (Obj === null || typeof Obj !== "object" || Array.isArray(Obj))
return false;
return Object.prototype.hasOwnProperty.call(Obj, key);
}

module.exports = contains;
16 changes: 16 additions & 0 deletions Sprint-2/implement/contains.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,19 @@ test.todo("contains on empty object returns false");
// Given invalid parameters like an array
// When passed to contains
// Then it should return false or throw an error

test("contains on empty object returns false", () => {
expect(contains({}, "a")).toEqual(false);
});

test("returns true when property exists", () => {
expect(contains({ a: 1, b: 2 }, "a")).toEqual(true);
});

test("returns false when property does not exist", () => {
expect(contains({ a: 1, b: 2 }, "c")).toEqual(false);
});

test("returns false for invalid input like array", () => {
expect(contains([1, 2, 3], "0")).toEqual(false);
});
7 changes: 5 additions & 2 deletions Sprint-2/implement/lookup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
function createLookup() {
// implementation here
function createLookup(countryCurrencyPairs) {
if (!Array.isArray(countryCurrencyPairs)) {
return {};
}
return Object.fromEntries(countryCurrencyPairs);
}

module.exports = createLookup;
37 changes: 37 additions & 0 deletions Sprint-2/implement/lookup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,40 @@ It should return:
'CA': 'CAD'
}
*/

test("returns empty object for empty array", () => {
expect(createLookup([])).toEqual({});
});

test("creates lookup from country-currency pairs", () => {
expect(
createLookup([
["US", "USD"],
["CA", "CAD"],
])
).toEqual({
US: "USD",
CA: "CAD",
});
});

test("handles single pair", () => {
expect(createLookup([["JP", "JPY"]])).toEqual({
JP: "JPY",
});
});

test("overwrites duplicate country codes (last one wins)", () => {
expect(
createLookup([
["US", "USD"],
["US", "USN"],
])
).toEqual({
US: "USN",
});
});

test("handles invalid input (non-array)", () => {
expect(createLookup(null)).toEqual({});
});
15 changes: 12 additions & 3 deletions Sprint-2/implement/querystring.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
function parseQueryString(queryString) {
const queryParams = {};
if (queryString.length === 0) {
return queryParams;

if (!queryString) return queryParams;

if (queryString.startsWith("?")) {
queryString = queryString.slice(1);
}

const keyValuePairs = queryString.split("&");

for (const pair of keyValuePairs) {
const [key, value] = pair.split("=");
if (!pair) continue;

const [rawKey, ...rawValue] = pair.split("=");
const key = decodeURIComponent(rawKey);
const value = decodeURIComponent(rawValue.join("="));

queryParams[key] = value;
}

Expand Down
63 changes: 61 additions & 2 deletions Sprint-2/implement/querystring.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,69 @@
// Below is one test case for an edge case the implementation doesn't handle well.
// Fix the implementation for this test, and try to think of as many other edge cases as possible - write tests and fix those too.

const parseQueryString = require("./querystring.js")
const parseQueryString = require("./querystring.js");

test("parses querystring values containing =", () => {
expect(parseQueryString("equation=x=y+1")).toEqual({
"equation": "x=y+1",
equation: "x=y+1",
});
});
test("parses simple key-value pairs", () => {
expect(parseQueryString("name=alice&age=25")).toEqual({
name: "alice",
age: "25",
});
});
test("strips leading question marks", () => {
expect(parseQueryString("?user=bob&status=active")).toEqual({
user: "bob",
status: "active",
});
});
test("returns empty object for empty string", () => {
expect(parseQueryString("")).toEqual({});
});

test("returns empty object for null or undefined", () => {
expect(parseQueryString(null)).toEqual({});
expect(parseQueryString(undefined)).toEqual({});
});
test("decodes URL encoded keys and values", () => {
expect(parseQueryString("search=coding%20tutorials&city=New%20York")).toEqual(
{
search: "coding tutorials",
city: "New York",
}
);
});

test("decodes complex characters and emojis", () => {
expect(parseQueryString("item=%F0%9F%8D%95&price=%2410")).toEqual({
item: "🍕",
price: "$10",
});
});
test("ignores empty segments from double ampersands", () => {
expect(parseQueryString("a=1&&b=2")).toEqual({
a: "1",
b: "2",
});
});

test("ignores trailing ampersands", () => {
expect(parseQueryString("a=1&b=2&")).toEqual({
a: "1",
b: "2",
});
});
test("handles keys with empty values", () => {
expect(parseQueryString("key=")).toEqual({
key: "",
});
});

test("handles keys without an equals sign", () => {
expect(parseQueryString("flag")).toEqual({
flag: "",
});
});
10 changes: 9 additions & 1 deletion Sprint-2/implement/tally.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
function tally() {}
function tally(array) {
const tally = {};
if (!Array.isArray(array)) throw new TypeError("Expected an array");
if (array.length === 0) return tally;
for (const item of array) {
tally[item] = (tally[item] || 0) + 1;
}
return tally;
}

module.exports = tally;
23 changes: 23 additions & 0 deletions Sprint-2/implement/tally.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ const tally = require("./tally.js");
// When passed to tally
// Then it should return an empty object
test.todo("tally on an empty array returns an empty object");
test("Empty array of items", () => {
expect(tally([])).toEqual({});
});

// Given an array with duplicate items
// When passed to tally
Expand All @@ -32,3 +35,23 @@ test.todo("tally on an empty array returns an empty object");
// Given an invalid input like a string
// When passed to tally
// Then it should throw an error

test("Invalid input", () => {
expect(() => tally("not an array")).toThrow(TypeError);
});
test("Test duplicate array", () => {
const duplicatesArray = [
"apple",
"banana",
"apple",
"orange",
"banana",
"apple",
];
const result = tally(duplicatesArray);
expect(result).toEqual({
apple: 3,
banana: 2,
orange: 1,
});
});
22 changes: 21 additions & 1 deletion Sprint-2/interpret/invert.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Then it should swap the keys and values in the object

// E.g. invert({x : 10, y : 20}), target output: {"10": "x", "20": "y"}

/*
function invert(obj) {
const invertedObj = {};

Expand All @@ -17,13 +17,33 @@ function invert(obj) {
}

// a) What is the current return value when invert is called with { a : 1 }
//{ key: 1 }

// b) What is the current return value when invert is called with { a: 1, b: 2 }
//{ key: 2 }

// c) What is the target return value when invert is called with {a : 1, b: 2}
//The target return value is { "1": "a", "2": "b" }.

// c) What does Object.entries return? Why is it needed in this program?
//It returns An array of the object's own property [key, value] pairs.
// It allows the for...of loop to easily access both the key and the value at the same time during each iteration.

// d) Explain why the current return value is different from the target output
//Using invertedObj.key creates a literal property named "key" on the object.
// To use the value inside the key variable, you must use bracket notation: invertedObj[key].
//The function is setting the original value to the key.
// To actually "invert" the object, it needs to swap them: invertedObj[value] = key;.

// e) Fix the implementation of invert (and write tests to prove it's fixed!)
*/
function invert(obj) {
const invertedObj = {};

for (const [key, value] of Object.entries(obj)) {
invertedObj[value] = key;
}

return invertedObj;
}
module.exports = invert;
24 changes: 24 additions & 0 deletions Sprint-2/interpret/invert.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const invert = require("./invert.js");
test("inverts a single key-value pair", () => {
const input = { a: 1 };
expect(invert(input)).toEqual({ 1: "a" });
});
test("inverts multiple key-value pairs", () => {
const input = { a: 1, b: 2, c: 3 };
const expected = { 1: "a", 2: "b", 3: "c" };

expect(invert(input)).toEqual(expected);
});
test("returns empty object for empty input", () => {
expect(invert({})).toEqual({});
});
test("overwrites keys when duplicate values exist", () => {
const input = { a: 1, b: 1 };
expect(invert(input)).toEqual({ 1: "b" });
});
test("turns boolean and null values into string keys", () => {
const input = { a: true, b: null };
const expected = { true: "a", null: "b" };

expect(invert(input)).toEqual(expected);
});