diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..0a63bf437 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -12,4 +12,8 @@ const address = { postcode: "XYZ 123", }; -console.log(`My house number is ${address[0]}`); +/*console.log(`My house number is ${address[0]}`);*/ + +console.log(`My house number is ${address.houseNumber}`); + + diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..ddd731645 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -11,6 +11,11 @@ const author = { alive: true, }; -for (const value of author) { +/*for (const value of author) { + console.log(value); +}*/ + +for (const value of Object.values(author)) { console.log(value); } + diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..6f64e73dd 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -12,4 +12,5 @@ const recipe = { console.log(`${recipe.title} serves ${recipe.serves} ingredients: -${recipe}`); +/*${recipe}`);*/ //incomplete instructions, To show data inside we need to add more properties +${recipe.ingredients.join(", ")}`); diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..b45ce2bed 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,8 @@ -function contains() {} +function contains(obj, property) { + if (obj === null || typeof obj !== "object" || Array.isArray(obj)) { + return false; + } + return Object.hasOwn(obj, property); +} module.exports = contains; diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..cea8af07b 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -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 when object contains the property", () => { + expect(contains({ a: 1, b: 2 }, "a")).toBe(true); + expect(contains({ name: "Alice", age: 25 }, "age")).toBe(true); + expect(contains({ g: "p", m: 1 }, "t")).toBe(false); +}); // 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, c: 3 }, "c")).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-existent property", () => { + expect(contains({ a: 1, b: 2 }, "z")).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 parameters", () => { + expect(contains([], "a")).toBe(false); + expect(contains(null, "a")).toBe(false); + expect(contains(undefined, "a")).toBe(false); + expect(contains(42, "a")).toBe(false); + expect(contains("notAnObject", "a")).toBe(false); +}); diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..bec9555db 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,9 @@ -function createLookup() { - // implementation here +function createLookup(pairs) { + if (!Array.isArray(pairs)) { + throw new Error("Input must be an array of pairs"); + } + + return Object.fromEntries(pairs); } module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..332f7dce5 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,6 +1,6 @@ const createLookup = require("./lookup.js"); -test.todo("creates a country currency code lookup for multiple codes"); +//test.todo("creates a country currency code lookup for multiple codes"); /* @@ -33,3 +33,26 @@ It should return: 'CA': 'CAD' } */ + +test("creates a country currency code lookup for multiple codes", () => { + const pairs = [ + ["US", "USD"], + ["CA", "CAD"], + ]; + + const expected = { + US: "USD", + CA: "CAD", + }; + + expect(createLookup(pairs)).toEqual(expected); +}); + +test("returns an empty object for an empty array", () => { + expect(createLookup([])).toEqual({}); +}); + +test("throws an error for invalid input", () => { + expect(() => createLookup(null)).toThrow(Error); + expect(() => createLookup("not an array")).toThrow(Error); +}); diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..e28c03121 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,16 +1,31 @@ -function parseQueryString(queryString) { - const queryParams = {}; - if (queryString.length === 0) { - return queryParams; - } - const keyValuePairs = queryString.split("&"); - - for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); - queryParams[key] = value; - } - - return queryParams; +function parseQueryString(query) { + const result = {}; + if (!query) return result; + + if (query.startsWith("?")) query = query.slice(1); + if (!query) return result; + + query.split("&").forEach(pair => { + if (!pair) return; + + const [key, value = ""] = pair.split("="); + const k = key.replace(/\+/g, " "); + const v = value.replace(/\+/g, " "); + + if (result[k]) { + result[k] = [].concat(result[k], v); + } else { + result[k] = v; + } + }); + + return result; +} + +module.exports = parseQueryString; + + + return result; } module.exports = parseQueryString; diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 3e218b789..32ea8cd78 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -10,3 +10,23 @@ test("parses querystring values containing =", () => { "equation": "x=y+1", }); }); + +test("parses multiple key-value pairs", () => { + expect(parseQueryString("a=1&b=2")).toEqual({ a: "1", b: "2" }); +}); + +test("handles empty query string", () => { + expect(parseQueryString("")).toEqual({}); +}); + +test("handles values with multiple =", () => { + expect(parseQueryString("formula=a=b=c=d")).toEqual({ formula: "a=b=c=d" }); +}); + +test("handles keys with no value", () => { + expect(parseQueryString("flag")).toEqual({ flag: "" }); +}); + +test("handles multiple & with some empty pairs", () => { + expect(parseQueryString("a=1&&b=2&c")).toEqual({ a: "1", b: "2", c: "" }); +}); diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..a8259b828 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,9 @@ -function tally() {} +function tally(arr) { + const result = {}; + for (const item of arr) { + result[item] = (result[item] || 0) + 1; + } + return result; +} module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..bf662820d 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -20,15 +20,35 @@ const tally = require("./tally.js"); // When passed an array of items // Then it should return an object containing the count for each unique item +test("returns an object with counts for each unique item", () => { + expect(tally(["a", "a", "b", "c"])).toEqual({ a: 2, b: 1, c: 1 }); + expect(tally(["cow", "goat", "cow", "fox"])).toEqual({ + cow: 2,goat: 1,fox: 1, + }); +}); + // 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", () => { + expect(tally([])).toEqual({}); +}); // Given an array with duplicate items // When passed to tally // Then it should return counts for each unique item +test("tally returns counts for each unique item", () => { + expect(tally(["a", "a", "b", "c"])).toEqual({ a: 2, b: 1, c: 1 }); + expect(tally(["x", "x", "x"])).toEqual({ x: 3 }); +}); + // Given an invalid input like a string // When passed to tally // Then it should throw an error + +test("throws an error for invalid input", () => { + expect(() => tally("not an array")).toThrow("Input must be an array"); + expect(() => tally(123)).toThrow("Input must be an array"); +}); diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..a425c8a44 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -10,20 +10,30 @@ function invert(obj) { const invertedObj = {}; for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; + invertedObj[value] = key; } return invertedObj; } +module.exports = invert; + +const invert = require("./invert.js"); + // 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} +{ "1": "a", "2": "b" } // c) What does Object.entries return? Why is it needed in this program? - +returns an array of [key, value] pairs // d) Explain why the current return value is different from the target output // e) Fix the implementation of invert (and write tests to prove it's fixed!) +console.log(invert({ a: 1, b: 2 }));