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
4 changes: 2 additions & 2 deletions Sprint-2/debug/address.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
// Fix anything that isn't working

const address = {
houseNumber: 42,
houseNumber: "42",
street: "Imaginary Road",
city: "Manchester",
country: "England",
postcode: "XYZ 123",
};

console.log(`My house number is ${address[0]}`);
console.log(`My house number is ${address.houseNumber}`);
4 changes: 2 additions & 2 deletions Sprint-2/debug/author.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ const author = {
firstName: "Zadie",
lastName: "Smith",
occupation: "writer",
age: 40,
age: "40",
alive: true,
};

for (const value of author) {
for (const value of Object.values(author)) {
console.log(value);
}
10 changes: 5 additions & 5 deletions Sprint-2/debug/recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
// How can you fix it?

const recipe = {
title: "bruschetta",
title: "bruschetta",
serves: 2,
ingredients: ["olive oil", "tomatoes", "salt", "pepper"],
};

console.log(`${recipe.title} serves ${recipe.serves}
ingredients:
${recipe}`);
console.log(`${recipe.title} \nserves ${recipe.serves} \nIngredients:`);
for (const ingredient of recipe.ingredients) {
console.log(ingredient);
}
7 changes: 6 additions & 1 deletion Sprint-2/implement/contains.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
function contains() {}
function contains(obj, prop) {
if (obj !== null && typeof obj === 'object' && !Array.isArray(obj)) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
return false;
}

module.exports = contains;
22 changes: 21 additions & 1 deletion Sprint-2/implement/contains.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,40 @@ as the object doesn't contains a key of 'c'
// 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
test("returns true for existing property and false for non-existing property", () => {
const obj = { a: 1, b: 2};
expect(contains(obj, "a")).toBe(true);
expect(contains(obj, "c")).toBe(false);
});

// Given an empty object
// When passed to contains
// Then it should return false
test.todo("contains on empty object returns false");
test("returns false if contains empty object", () => {
const obj = {};
expect(contains(obj, "a")).toBe(false);
});

// Given an object with properties
// When passed to contains with an existing property name
// Then it should return true
test("returns true for existing property", () => {
const obj = { firstName: "Gina", lastName: "Rogers" };
expect(contains(obj, "firstName")).toBe(true);
});

// Given an object with properties
// When passed to contains with a non-existent property name
// Then it should return false
test("returns false for non-existing property", () => {
const obj = { firstName: "Gina", lastName: "Rogers" };
expect(contains(obj, "age")).toBe(false);
});

// Given invalid parameters like an array
// When passed to contains
// Then it should return false or throw an error
test("handles invalid parameters", () => {
const arr = [1, 2, 3];
expect(contains(arr, "0")).toBe(false);
});
18 changes: 16 additions & 2 deletions Sprint-2/implement/lookup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
function createLookup() {
// implementation here
function createLookup(pairs) {
// function accepts one parameter: pairs of country-currency code arrays
if (!Array.isArray(pairs)) {
return {}; // Return empty object if input is not an array
}

const lookup = {}; // Initialize empty lookup object, key-value pairs stored in this object
for (const pair of pairs) {
// Iterate over each pair in the input array
if (Array.isArray(pair) && pair.length >= 2) {
const [countryCode, currencyCode] = pair; // Destructuring first two elements of pair array and assigning them to country and currency
lookup[countryCode] = currencyCode; // Add country-currency pair to the lookup object - later entries overwrite earlier ones if duplicate country codes exist.
}
}
Comment on lines +8 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation is a bit off.

return lookup;
}


module.exports = createLookup;
17 changes: 15 additions & 2 deletions Sprint-2/implement/lookup.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
const createLookup = require("./lookup.js");

test.todo("creates a country currency code lookup for multiple codes");

test("creates a country currency code lookup for multiple codes", () => {
const countryCurrencyPairs = [
["US", "USD"],
["CA", "CAD"],
["GB", "GBP"],
];

const expectedLookup = {
US: "USD",
CA: "CAD",
GB: "GBP",
};

expect(createLookup(countryCurrencyPairs)).toEqual(expectedLookup);
});
/*

Create a lookup object of key value pairs from an array of code pairs
Expand Down
18 changes: 13 additions & 5 deletions Sprint-2/implement/querystring.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
function parseQueryString(queryString) {
const queryParams = {};
if (queryString.length === 0) {
return queryParams;
if (!queryString || queryString.length === 0) {
return queryParams; // Return empty object for empty query string
}
const keyValuePairs = queryString.split("&");
const keyValuePairs = queryString.split("&"); // Split by '&' to get individual key-value pairs

for (const pair of keyValuePairs) {
const [key, value] = pair.split("=");
queryParams[key] = value;
// Iterate over each key-value pair
if (!pair.includes("=")) {
// Handle missing equals sign
queryParams[pair] = undefined; // Assign undefined for keys without equals sign
continue; // Move to the next pair
}
const [key, ...rest] = pair.split("="); // array destructured into key and rest of array.
// Split by '=' to separate key and value.
const value = rest.join("="); // Join back any '=' in the value using rest operator
queryParams[key] = value; // Assign key-value pair to the result object
}
Comment on lines 8 to 19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that in real querystring, both key and value are percent-encoded or URL encoded in the URL. For example, the string "5%" will be encoded as "5%25". So to get the actual value of "5%25" (whether it is a key or value in the querystring), we would need to call a function to decode it.

May I suggest looking up any of these terms, and "How to decode URL encoded string in JS"?


return queryParams;
Expand Down
39 changes: 36 additions & 3 deletions Sprint-2/implement/querystring.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,43 @@
// 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",
expect(parseQueryString("equation=x=y+1")).toEqual({ equation: "x=y+1" });
});

test("parses empty string to empty object", () => {
expect(parseQueryString("")).toEqual({});
});

test("parses single key-value pair", () => {
expect(parseQueryString("name=Gina")).toEqual({ name: "Gina" });
});

test("parses multiple key-value pairs", () => {
expect(parseQueryString("name=Gina&age=23&city=Nottingham")).toEqual({
name: "Gina",
age: "23",
city: "Nottingham",
});
});

test("handles keys without values", () => {
expect(parseQueryString("name=&age=23")).toEqual({ name: "", age: "23" });
});

test("handles values without keys", () => {
expect(parseQueryString("=Gina&age=23")).toEqual({ "": "Gina", age: "23" });
});

test("handles missing equals sign", () => {
expect(parseQueryString("nameGina&age23")).toEqual({
nameGina: undefined,
age23: undefined,
});
});

test("handles repeated keys", () => {
expect(parseQueryString("name=Gina&name=Jane")).toEqual({ name: "Jane" });
});
17 changes: 16 additions & 1 deletion Sprint-2/implement/tally.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
function tally() {}
function tally(items) {
if (!Array.isArray(items)) {
throw new Error("Input must be an array");
}
const counts = {}; // empty object to store tally of key-value pairs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the following function call returns the value you expect?

tally(["toString", "toString"]);

Suggestion: Look up an approach to create an empty object with no inherited properties.

for (const item of items) {
// iterates through each element in the items array
if (counts[item]) {
// checks if the item already exists as a key in counts object
counts[item] += 1; // increments the count for that item by 1
} else {
counts[item] = 1; // initializes the count for that item to 1
}
}
return counts; // returns the final counts object
}

module.exports = tally;
20 changes: 19 additions & 1 deletion Sprint-2/implement/tally.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,34 @@ const tally = require("./tally.js");
// Given a function called tally
// When passed an array of items
// Then it should return an object containing the count for each unique item
test("tally counts frequency of each item in an array", () => {
const input = ["a", "a", "b", "c", "b", "a"];
const expectedOutput = { a: 3, b: 2, c: 1 };
expect(tally(input)).toEqual(expectedOutput);
});

// Given an empty array
// When passed to tally
// Then it should return an empty object
test.todo("tally on an empty array returns an empty object");
test("tally on an empty array returns an empty object", () => {
const input = [];
const expectedOutput = {};
expect(tally(input)).toEqual(expectedOutput);
});

// Given an array with duplicate items
// When passed to tally
// Then it should return counts for each unique item
test("tally counts each unique item in an array with duplicates", () => {
const input = ["x", "y", "x", "z", "y", "x"];
const expectedOutput = { x: 3, y: 2, z: 1 };
expect(tally(input)).toEqual(expectedOutput);
});

// Given an invalid input like a string
// When passed to tally
// Then it should throw an error
test("tally throws an error for invalid input", () => {
const input = "invalid input";
expect(() => tally(input)).toThrow("Input must be an array");
});
17 changes: 16 additions & 1 deletion Sprint-2/interpret/invert.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,38 @@
// E.g. invert({x : 10, y : 20}), target output: {"10": "x", "20": "y"}

function invert(obj) {
// Guard: only accept plain objects (not null, not arrays, not primitives)
if (obj === null || typeof obj !== 'object' || Array.isArray(obj)) {
return {};
}

const invertedObj = {};

for (const [key, value] of Object.entries(obj)) {
invertedObj.key = value;
// Ensure the value is used as a string key (object keys are strings)
invertedObj[String(value)] = key;
}

return invertedObj;
}

module.exports = invert;

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

// b) What is the current return value when invert is called with { a: 1, b: 2 }
// { '1': 'a', '2': 'b' }
Comment on lines +26 to +31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "current return value" in questions (a), (b), and (d) refers to the value returned by the original (unmodified) function.

The objects you described on line 28 and 31 are not the objects returned by the original function.
The explanation given on line 41 (answer to question (d)) is also not quite correct.


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

// c) What does Object.entries return? Why is it needed in this program?
// It returns an array of key-value pairs from the object.
// It is needed to iterate over each key-value pair in the input object.

// d) Explain why the current return value is different from the target output
// Numeric key values are converted to strings in the output object keys.

// e) Fix the implementation of invert (and write tests to prove it's fixed!)
// Invert function passes 4 edge case tests.
22 changes: 22 additions & 0 deletions Sprint-2/interpret/invert.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const invert = require('./invert');

describe('invert', () => {
test('inverts a single key', () => {
expect(invert({ a: 1 })).toEqual({ '1': 'a' });
});

test('inverts multiple keys', () => {
expect(invert({ a: 1, b: 2 })).toEqual({ '1': 'a', '2': 'b' });
});

test('duplicate values: last key wins', () => {
expect(invert({ a: 1, b: 1 })).toEqual({ '1': 'b' });
});

test('non-object inputs return empty object', () => {
expect(invert(null)).toEqual({});
expect(invert(undefined)).toEqual({});
expect(invert(123)).toEqual({});
expect(invert([1, 2, 3])).toEqual({});
});
});