diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..36d2f865d 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -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}`); diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..8e8bcd053 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -11,6 +11,7 @@ const author = { alive: true, }; -for (const value of author) { +for (const value of Object.values(author)) { console.log(value); } +// The problem is that the code is trying to log out the values of the object using a for...of loop, but it is not using the correct syntax to access the values. The Object.values() method returns an array of the object's values, so we need to use a for...of loop to iterate over that array and log each value. \ No newline at end of file diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..db1d2afc3 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -9,7 +9,14 @@ const recipe = { serves: 2, ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; +/* Replacing the for loop with Array.prototype.join() to log the ingredients in a single line, separated by new lines. +console.log(`${recipe.title} serves ${recipe.serves}`); +for (const ingredient of recipe.ingredients) { + console.log(ingredient); +} +*/ +console.log(`${recipe.title} serves ${recipe.serves}`); +console.log (recipe.ingredients.join("\n")); -console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); + +// The problem is that the code is trying to log out the ingredients using a for...of loop, but it is not using the correct syntax to access the ingredients. The recipe.ingredients is an array, so we need to use a for...of loop to iterate over that array and log each ingredient. \ No newline at end of file diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..282c8ec76 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,10 @@ -function contains() {} +function contains(obj, prop) { + return ( + !!obj && // confirm that obj is not null or undefined. If undefined or null, return false. + typeof obj === "object" && // confirm that obj is an object. If not an object, return false. + !Array.isArray(obj) && // confirm that obj is not an array. If an array, return false. + Object.hasOwnProperty.call(obj, prop)// check if the object has the property. If it does, return true; otherwise, return false. + ); +} module.exports = contains; diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..b1466695b 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -16,20 +16,48 @@ 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("contains returns true for existing property", () => { + const obj = { a: 1, b: 2 }; + expect(contains(obj, "a")).toBe(true); + expect(contains(obj, "b")).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("contains on empty object returns false", () => { + const emptyObj = {}; + expect(contains(emptyObj, "a")).toBe(false); + expect(contains(emptyObj, "b")).toBe(false); +}); // Given an object with properties // When passed to contains with an existing property name // Then it should return true +test("contains returns true for existing property", () => { + const obj2 = { x: 10, y: 20 }; + expect(contains(obj2, "x")).toBe(true); + expect(contains(obj2, "y")).toBe(true); + expect(contains(obj2, "z")).toBe(false); +}); // Given an object with properties // When passed to contains with a non-existent property name // Then it should return false +test("contains returns false for non-existent property", () => { + const obj3 = { name: "Alice", age: 30 }; + expect(contains(obj3, "name")).toBe(true); + expect(contains(obj3, "age")).toBe(true); + expect(contains(obj3, "gender")).toBe(false); +}); // Given invalid parameters like an array // When passed to contains // Then it should return false or throw an error +test("contains returns false for invalid input types", () => { + const arr = [1, 2, 3]; + expect(contains(arr, "0")).toBe(false); // Arrays do not have properties like objects, so it should return false + expect(contains(null, "a")).toBe(false); // null is not an object, so it should return false + expect(contains(undefined, "a")).toBe(false); // undefined is not an object, so it should return false +}); \ No newline at end of file diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..33366fb60 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,23 @@ -function createLookup() { - // implementation here +function createLookup(pairs) { + if (!Array.isArray(pairs)) { + // check if the input is an array. If not, throw an error. + throw new Error("Input must be an array of pairs"); + } + + const lookup = {}; // create an empty object to store key-value pairs + + for (const pair of pairs) { + // iterate through each pair in the input array + if (!Array.isArray(pair) || pair.length !== 2) { + // check if the current pair is an array of length 2. If not, throw an error. + throw new Error("Each pair must be an array of two elements"); + } + + const key = pair[0]; // extract the first element of the pair as the key + const value = pair[1]; // extract the second element of the pair as the value + lookup[key] = value; // add the key-value pair to the lookup object + } + return lookup; } module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..6daf10981 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,13 +1,22 @@ 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");// /* - +Note this test script just tests the happy path of the function. Create a lookup object of key value pairs from an array of code pairs - +const countryCurrencyPairs = [['US', 'USD'], ['CA', 'CAD']]; Acceptance Criteria: +*/ +const countryCurrencyPairs = [['US', 'USD'], ['CA', 'CAD']]; +test("createLookup returns an object with country codes as keys and currency codes as values", () => { + const lookup = createLookup(countryCurrencyPairs); + expect(lookup).toEqual({ + 'US': 'USD', + 'CA': 'CAD' + }); +}); +/* Given - An array of arrays representing country code and currency code pairs e.g. [['US', 'USD'], ['CA', 'CAD']] @@ -32,4 +41,33 @@ It should return: 'US': 'USD', 'CA': 'CAD' } -*/ + +These are tests for empty and multiple pairs to test edge cases. + */ + +test("createLookup handles empty input array", () => { + const emptyPairs = []; + const lookup = createLookup(emptyPairs); + expect(lookup).toEqual({}); +}); + +test("createLookup handles multiple pairs", () => { + const morePairs = [['US', 'USD'], ['CA', 'CAD'], ['GB', 'GBP']]; + const lookup = createLookup(morePairs); + expect(lookup).toEqual({ + 'US': 'USD', + 'CA': 'CAD', + 'GB': 'GBP' + }); +}); + +// these test check unexpected input types to ensure the function can handle them gracefully. +test("createLookup handles non-array input", () => { + expect(() => createLookup("not an array")).toThrow(); +}); + +test("createLookup handles array with non-array elements", () => { + const invalidPairs = [['US', 'USD'], 'invalid pair']; + expect(() => createLookup(invalidPairs)).toThrow(); +}); + diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..d26ce5902 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,13 +1,15 @@ function parseQueryString(queryString) { - const queryParams = {}; - if (queryString.length === 0) { + const queryParams = {}; // Initialize an empty object to store the key-value pairs + if (queryString.length === 0) {// If the input query string is empty, return the empty object return queryParams; } - const keyValuePairs = queryString.split("&"); + const keyValuePairs = queryString.split("&");// Split the query string into an array of key-value pairs using '&' as the delimiter - for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); - queryParams[key] = value; + for (const pair of keyValuePairs) {// Iterate through each key-value pair in the array + const separatorIndex = pair.indexOf("=");// Find the index of the '=' character in the current pair + const key = separatorIndex === -1 ? pair : pair.slice(0, separatorIndex);// Extract the key from the pair. If there is no '=', the entire pair is the key; otherwise, it's the substring before '=' + const value = separatorIndex === -1 ? "" : pair.slice(separatorIndex + 1);// Extract the value from the pair. If there is no '=', the value is an empty string; otherwise, it's the substring after '=' + queryParams[key] = value;// Add the key and value to the queryParams object } return queryParams; diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 3e218b789..124cce002 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -5,8 +5,35 @@ const parseQueryString = require("./querystring.js") -test("parses querystring values containing =", () => { - expect(parseQueryString("equation=x=y+1")).toEqual({ - "equation": "x=y+1", +test("given a query string with one pair of query params, returns them in object form", function () { + const input = "fruit=banana"; + const currentOutput = parseQueryString(input); + const targetOutput = { fruit: "banana" }; + + expect(currentOutput).toEqual(targetOutput); +}); + +test("parses querystring with multiple key-value pairs", () => { + expect(parseQueryString("equation1=x=y+1&equation2=z=w+1")).toEqual({ + "equation1": "x=y+1", + "equation2": "z=w+1" + }); +}); + + +test("parses querystring with keys but no values", () => { + expect(parseQueryString("equation1&equation2")).toEqual({ + "equation1": "", + "equation2": "" }); }); + +test ("parse querystring with empty string", () => { + expect(parseQueryString("")).toEqual({}); + const input="" +const currentOutput=parseQueryString(input) +const targetOutput={} +expect(currentOutput).toEqual(targetOutput) + +}); + diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..800d362e9 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,12 @@ -function tally() {} +function tally(items) { + if (!Array.isArray(items)) { + throw new TypeError("Input must be an array"); + } + + return items.reduce((counts, item) => { + counts[item] = (counts[item] ?? 0) + 1; + return counts; + }, Object.create(null)); +} module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..5295ec3e8 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -20,15 +20,63 @@ 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("tally on a single-item array returns count for one count", () => { + const input = ["a"]; + const result = tally(input); + const expected = { a: 1 }; + expect(result).toEqual(expected); +}); + +test("tally on an array with duplicate items returns count for each unique item", () => { + const input = ["a", "a", "a"]; + const result = tally(input); + const expected = { a: 3 }; + expect(result).toEqual(expected); +}); + +test("tally on an array with multiple items returns count for each unique item", () => { + const input = ["a", "a", "b", "c"]; + const result = tally(input); + const expected = { a: 2, b: 1, c: 1 }; + expect(result).toEqual(expected); +}); + // 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.todo("tally on an empty array returns an empty object"); + +test("tally on an empty array returns an empty object", () => { + const input = []; + const result = tally(input); + const expected = {}; + expect(result).toEqual(expected); +}); // Given an array with duplicate items // When passed to tally // Then it should return counts for each unique item +test("tally on an array with duplicate items returns count for each unique item", () => { + const input = ["a", "a", "a", "b", "b", "c"]; + const result = tally(input); + const expected = { a: 3, b: 2, c: 1 }; + expect(result).toEqual(expected); +}); + // Given an invalid input like a string // When passed to tally // Then it should throw an error + +test("tally on a non-array input throws an error", () => { + const input = "not an array"; + expect(() => tally(input)).toThrow(TypeError); +}); + +test("tally counts keys like toString correctly", () => { + const input = ["toString", "toString"]; + const result = tally(input); + const expected = Object.create(null); + expected.toString = 2; + expect(result).toEqual(expected); +}); diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..ec4ecda49 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -10,20 +10,37 @@ function invert(obj) { const invertedObj = {}; for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; + invertedObj[value] = key; } return invertedObj; } // a) What is the current return value when invert is called with { a : 1 } +const currentReturnValue = invert({ a: 1 }); +console.log(currentReturnValue); // Output: { key: 1 } // b) What is the current return value when invert is called with { a: 1, b: 2 } +const currentReturnValue2 = invert({ a: 1, b: 2 }); +console.log(currentReturnValue2); // Output: { key: 2 } // c) What is the target return value when invert is called with {a : 1, b: 2} +const currentReturnValue3 = invert({ a: 1, b: 2 }); +console.log(currentReturnValue3); // Output: { "1": "a", "2": "b" } // c) What does Object.entries return? Why is it needed in this program? +// Object.entries returns an array of a given object's [key, value] pairs. It is needed in this program to iterate over the key-value pairs of the input object so that we can swap them and create the inverted object. // d) Explain why the current return value is different from the target output +// The current return value is different from the target output because in the current implementation, we are assigning the value to a property named "key" in the inverted object, instead of using the actual key from the original object. This results in only the last key-value pair being stored in the inverted object, and it does not correctly swap the keys and values as intended. // e) Fix the implementation of invert (and write tests to prove it's fixed!) +// Here's the corrected implementation of the invert function: + +//function invert(obj) { + //const invertedObj = {}; + //for (const [key, value] of Object.entries(obj)) { + //invertedObj[value] = key; + //} + //return invertedObj; +//}