Skip to content
Closed
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
2 changes: 1 addition & 1 deletion Sprint-2/debug/address.js

Choose a reason for hiding this comment

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

Correct! One could consider whether a default value could be provided if a corresponding key does not exist.

Choose a reason for hiding this comment

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

nice !

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 ?? "unknown"}`); // Objects are accessed using dot notation or string keys. Example 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);
}
12 changes: 9 additions & 3 deletions Sprint-2/debug/recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ const recipe = {
ingredients: ["olive oil", "tomatoes", "salt", "pepper"],
};

console.log(`${recipe.title} serves ${recipe.serves}
ingredients:
${recipe}`);
console.log(`${recipe.title} serves ${recipe.serves}`);
console.log("ingredients:");

// Check if ingredients is an array
if (Array.isArray(recipe.ingredients)) {
console.log(recipe.ingredients.join("\n"));
} else {
console.log("No valid ingredient list available.");
}
7 changes: 6 additions & 1 deletion Sprint-2/implement/contains.js

Choose a reason for hiding this comment

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

This condition (invalid parameters (like array) → return false or throw an error) is not satisfied
e.g contains([1, 2, 3], "2")

Choose a reason for hiding this comment

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

ok. it works

Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
function contains() {}
function contains(object, propertyName) {
if (typeof object === "object" && object !== null && !Array.isArray(object)) {
return propertyName in object;
}
return false;
}

module.exports = contains;
25 changes: 22 additions & 3 deletions Sprint-2/implement/contains.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,39 @@ 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 if the object contains the property, false otherwise", () => {
const obj = { a: 1, b: 2 };

expect(contains(obj, "a")).toBe(true); // property exists
expect(contains(obj, "b")).toBe(true); // property exists
expect(contains(obj, "c")).toBe(false); // property does not exist
});

// Given an empty object
// When passed to contains
// Then it should return false
test.todo("contains on empty object returns false");
test("contains on empty object returns false", () => {
expect(contains({}, "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", () => {
expect(contains({ a: 1, b: 2 }, "a")).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 missing property", () => {
expect(contains({ a: 1, b: 2 }, "c")).toBe(false);
});
// Given invalid parameters like an array
// When passed to contains
// Then it should return false or throw an error
test("returns false for invalid inputs like arrays", () => {
expect(contains([], "a")).toBe(false);
expect(contains(null, "a")).toBe(false);
expect(contains(123, "a")).toBe(false);
expect(contains("hello", "a")).toBe(false);
});
9 changes: 8 additions & 1 deletion Sprint-2/implement/lookup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
function createLookup() {
function createLookup(pairs) {
// implementation here
const lookup = {};

for (const [country, currency] of pairs) {
lookup[country] = currency;
}

return lookup;
}

module.exports = createLookup;
14 changes: 13 additions & 1 deletion Sprint-2/implement/lookup.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
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 input = [
["US", "USD"],
["CA", "CAD"],
];

const expected = {
US: "USD",
CA: "CAD",
};

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

/*

Expand Down
47 changes: 43 additions & 4 deletions Sprint-2/implement/querystring.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,52 @@
function parseQueryString(queryString) {
const queryParams = {};
if (queryString.length === 0) {

// 1. Input Validation: Return empty object for non-string, null, or empty input.
if (typeof queryString !== "string" || !queryString) {
return queryParams;
}
const keyValuePairs = queryString.split("&");

// Remove leading '?' if it exists (e.g., if passed directly from window.location.search)
const cleanedString = queryString.startsWith("?")
? queryString.substring(1)
: queryString;

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

for (const pair of keyValuePairs) {
const [key, value] = pair.split("=");
queryParams[key] = value;
if (pair.length === 0) continue; // Skip empty pairs

const separatorIndex = pair.indexOf("=");
let key;
let value;

if (separatorIndex === -1) {
// Case 1: Key with no equals sign (e.g., "key")
key = pair;
value = "";
} else {
// Case 2: Key/value pair with or without extra '=' in value (e.g., "eq=a=b")
key = pair.substring(0, separatorIndex);
// Value is everything after the first '='
value = pair.substring(separatorIndex + 1);
}

// Decode the key and value
const decodedKey = decodeURIComponent(key);
const decodedValue = decodeURIComponent(value);

// Handle Duplicate Keys: If the key already exists, convert the value to an array.
if (queryParams.hasOwnProperty(decodedKey)) {
if (Array.isArray(queryParams[decodedKey])) {
queryParams[decodedKey].push(decodedValue);
} else {
// Convert existing value and new value to an array
queryParams[decodedKey] = [queryParams[decodedKey], decodedValue];
}
} else {
// Assign the value for the first time
queryParams[decodedKey] = decodedValue;
}
}

return queryParams;
Expand Down
29 changes: 27 additions & 2 deletions Sprint-2/implement/querystring.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,35 @@
// 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("handles URL encoding in keys and values", () => {
expect(parseQueryString("search=hello%20world&sort=d%26a")).toEqual({
search: "hello world",
sort: "d&a",
});
});
test("handles duplicate keys by creating an array of values", () => {
expect(parseQueryString("color=red&color=blue&size=m")).toEqual({
color: ["red", "blue"],
size: "m",
});
});
test("handles keys with empty or missing values", () => {
expect(parseQueryString("key1=&key2=value&key3&key4=")).toEqual({
key1: "",
key2: "value",
key3: "",
key4: "",
});
});
test("handles empty string, leading question mark, and malformed input", () => {
expect(parseQueryString("")).toEqual({});
expect(parseQueryString("?a=1")).toEqual({ a: "1" });
expect(parseQueryString("a=1&&b=2")).toEqual({ a: "1", b: "2" });
});
16 changes: 15 additions & 1 deletion Sprint-2/implement/tally.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
function tally() {}
function tally(list) {
// 1. Input Validation: Throw an error if the input is not a proper array.
if (!Array.isArray(list)) {
throw new Error("Input must be an array.");
}

// 2. Tally Frequencies using reduce()
return list.reduce((counts, item) => {
// If the item exists in the object, increment its count.
// Otherwise, initialize its count to 1.
counts[item] = (counts[item] || 0) + 1;

return counts;
}, {}); // Start with an empty object {}
}

module.exports = tally;
53 changes: 37 additions & 16 deletions Sprint-2/implement/tally.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,41 @@ const tally = require("./tally.js");
*/

// Acceptance criteria:
describe("tally", () => {
// 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("returns correct counts for mixed data types", () => {
const input = [1, "a", 2, true, 1, "a", 2, true];
const expectedOutput = { 1: 2, a: 2, 2: 2, true: 2 };
expect(tally(input)).toEqual(expectedOutput);
});
// Given an empty array
// When passed to tally
// Then it should return an empty object
test("tally on an empty array returns an empty object", () => {
expect(tally([])).toEqual({});
});
// Given an array with duplicate items
// When passed to tally
// Then it should return counts for each unique item
test("returns correct counts for an array with duplicates", () => {
const input = ["banana", "apple", "banana", "cherry", "apple", "banana"];
const expectedOutput = {
banana: 3,
apple: 2,
cherry: 1,
};
expect(tally(input)).toEqual(expectedOutput);
});
// Given an invalid input like a string
// When passed to tally
// Then it should throw an error

// Given a function called tally
// When passed an array of items
// Then it should return an object containing the count for each unique item

// 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");

// Given an array with duplicate items
// When passed to tally
// Then it should return counts for each unique item

// Given an invalid input like a string
// When passed to tally
// Then it should throw an error
test.each(["not an array", 123, null, undefined, { key: "value" }])(
"throws an error for invalid input type: %p",
(invalidInput) => {
expect(() => tally(invalidInput)).toThrow("Input must be an array.");
}
);
});
23 changes: 16 additions & 7 deletions Sprint-2/interpret/invert.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,30 @@
function invert(obj) {
const invertedObj = {};

// Checked for non-object input (optional, but robust)
if (typeof obj !== "object" || obj === null) {
return invertedObj;
}

for (const [key, value] of Object.entries(obj)) {
invertedObj.key = value;
// Used bracket notation to dynamically set the value as the new key,
// and assign the original key as the new value.
invertedObj[value] = key;
}

return invertedObj;
}

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

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

invert({ a: 1, b: 2 }); // returns: { key: 2 }
// 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?

Object.entries({ a: 1, b: 2 }) // returns: [["a", 1], ["b", 2]]
//Each entry is a [key, value] pair. Needed because we want to iterate over keys and values simultaneously in a for...of loop.
// d) Explain why the current return value is different from the target output

// Because you wrote invertedObj.key instead of using the dynamic key from the variable value. invertedObj.key creates a property literally named "key", not the value of the variable key.
// e) Fix the implementation of invert (and write tests to prove it's fixed!)
*/
Loading