diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..3abde7b56 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -1,5 +1,5 @@ // Predict and explain first... - +// this code will give an error because the address is not an array and we should use dot notation to access houseNumber. // This code should log out the houseNumber from the address object // but it isn't working... // Fix anything that isn't working @@ -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}`); \ No newline at end of file diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..51aec4d8d 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -1,5 +1,5 @@ // Predict and explain first... - +// this code will give an error because the for...of is generally used to iterate over iterable objects like arrays or strings. thus, we should use for...in loop to iterate over the properties of an object. // This program attempts to log out all the property values in the object. // But it isn't working. Explain why first and then fix the problem @@ -11,6 +11,6 @@ const author = { alive: true, }; -for (const value of author) { - console.log(value); -} +for (const value in author) { + console.log(`${value}: ${author[value]}`); +}; \ No newline at end of file diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..6819c8244 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -1,5 +1,5 @@ // Predict and explain first... - +// This code will not log out the ingredients correctly.we should access the ingredients array specifically. // This program should log out the title, how many it serves and the ingredients. // Each ingredient should be logged on a new line // How can you fix it? @@ -10,6 +10,10 @@ const recipe = { ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; -console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); +console.log(`${recipe.title} +serves ${recipe.serves} +ingredients:`); + +recipe.ingredients.forEach(ingredient => { + console.log(ingredient); +}); \ No newline at end of file diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..db7e15c1b 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,8 @@ -function contains() {} +function contains(input, propertyName) { + if (input && typeof input === 'object' && !Array.isArray(input)) { + return input.hasOwnProperty(propertyName); + } + return false; +}; -module.exports = contains; +module.exports = contains; \ No newline at end of file diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..90478d58f 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -16,20 +16,52 @@ 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("given a contains function ,returns true for existing property, false otherwise", () => { + const input = {a: 1, b: 2}; + const propertyName = 'a'; + const currentOutput = contains(input, propertyName); + const targetOutput = true; + expect(currentOutput).toBe(targetOutput); +}); // Given an empty object // When passed to contains // Then it should return false -test.todo("contains on empty object returns false"); - +test("given an empty object, contains returns false",()=>{ + const input = {}; + const propertyName = 'anyProp'; + const currentOutput = contains(input,propertyName); + const targetOutput = false; + expect(currentOutput).toBe(targetOutput); +}); // Given an object with properties // When passed to contains with an existing property name // Then it should return true +test("given an object with properties, returns true for existing property",()=>{ + const input = {x:10,y:20,z:30}; + const propertyName = 'y'; + const currentOutput = contains(input,propertyName); + const targetOutput = true; + expect(currentOutput).toBe(targetOutput); +}); // Given an object with properties // When passed to contains with a non-existent property name // Then it should return false +test("given an object with properties, returns false for non-existing property",()=>{ + const input = {x:10,y:20,z:30}; + const propertyName = 'a'; + const currentOutput = contains(input,propertyName); + const targetOutput = false; + expect(currentOutput).toBe(targetOutput); +}); // Given invalid parameters like an array // When passed to contains // Then it should return false or throw an error +test("given invalid parameters like an array, contains returns false",()=>{ + const input = [1,2,3]; + const propertyName = '0'; + const currentOutput = contains(input,propertyName); + const targetOutput = false; + expect(currentOutput).toBe(targetOutput); +}); \ No newline at end of file diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..3d78d9059 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,9 @@ -function createLookup() { - // implementation here +function createLookup(pairs) { + const lookup = {}; + for (const [countryCode, currencyCode] of pairs) { + lookup[countryCode] = currencyCode; + } + return lookup; } -module.exports = createLookup; +module.exports = createLookup; \ No newline at end of file diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..b83e152a1 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,6 +1,15 @@ 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'], ['GB', 'GBP']]; + const currentOutput = createLookup(input); + const targetOutput = { + 'US': 'USD', + 'CA': 'CAD', + 'GB': 'GBP' + }; + expect(currentOutput).toEqual(targetOutput); +}); /* @@ -32,4 +41,4 @@ It should return: 'US': 'USD', 'CA': 'CAD' } -*/ +*/ \ No newline at end of file diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..51de262ed 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,12 +1,33 @@ function parseQueryString(queryString) { const queryParams = {}; - if (queryString.length === 0) { + + 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 firstEq = pair.indexOf("="); + + let key; + let value; + + if (firstEq === -1) { + // No "=" found → key with empty value + key = decodeURIComponent(pair); + value = ""; + } else { + key = decodeURIComponent(pair.slice(0, firstEq)); + value = decodeURIComponent(pair.slice(firstEq + 1)); + } + queryParams[key] = value; } @@ -14,3 +35,4 @@ function parseQueryString(queryString) { } module.exports = parseQueryString; +console.log(parseQueryString("?text=Hello%20World&amount=5%25")); \ No newline at end of file diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 3e218b789..8fce8228b 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -6,7 +6,21 @@ 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 multiple key=value pairs", () => { + expect(parseQueryString("a=1&b=2")).toEqual({ a: "1", b: "2" }); +}); + +test("parses empty querystring", () => { + expect(parseQueryString("")).toEqual({}); +}); + +test("parses key with no '=' (a)", () => { + expect(parseQueryString("a")).toEqual({ a: "" }); +}); + +test("last value wins for duplicate keys", () => { + expect(parseQueryString("a=1&a=2")).toEqual({ a: "2" }); +}); \ No newline at end of file diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..934ca410b 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,22 @@ -function tally() {} +function tally(items) { + if (!Array.isArray(items)) { + throw new TypeError('Input must be an array'); + } + + const tallyResult = Object.create(null); + + for (const item of items) { + if (tallyResult[item] === undefined) { + tallyResult[item] = 1; + } else { + tallyResult[item]++; + } + } + + return tallyResult; +} module.exports = tally; + +console.log("Test : tally with 'toString':"); +console.log(tally(["toString", "toString"])); \ No newline at end of file diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..64391033d 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("tally returns counts for each unique item", () => { + const input = ['a', 'a', 'b', 'c']; + const expectedOutput = { a: 2, b: 1, 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 correctly", () => { + const input = ['a', 'b', 'a', 'c', 'b', 'a']; + const expectedOutput = { a: 3, b: 2, c: 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 non-array input", () => { + const input = "not an array"; + expect(() => tally(input)).toThrow(TypeError); +}); \ No newline at end of file diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..7db085cdf 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -6,24 +6,69 @@ // E.g. invert({x : 10, y : 20}), target output: {"10": "x", "20": "y"} +//function invert(obj) { +// const invertedObj = {}; + + // for (const [key, value] of Object.entries(obj)) { + // invertedObj.key = value; + // } + + // return invertedObj; +//} + +// 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? +// Object.entries returns an array of a given object's own enumerable string-keyed property [key, value] pairs. It is needed in this program to iterate over each key-value pair in the object so that we can swap them when creating 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 line (invertedObj.key = value;), the property name 'key' is being used literally instead of using the variable (key). This means that every iteration of the loop is overwriting the same property 'key' in the inverted object, resulting in only the last value being stored. + +// e) Fix the implementation of invert (and write tests to prove it's fixed!) + +// Fixed implementation: + + function invert(obj) { const invertedObj = {}; for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; + invertedObj[value] = key; } return invertedObj; } +module.exports = invert; -// a) What is the current return value when invert is called with { a : 1 } -// b) What is the current return value when invert is called with { a: 1, b: 2 } +// Test cases: -// c) What is the target return value when invert is called with {a : 1, b: 2} +const invert = require('./invert'); -// c) What does Object.entries return? Why is it needed in this program? +// single key: -// d) Explain why the current return value is different from the target output +test('invert single key-value pair', () => { + expect(invert({ a: 1 })).toEqual({ "1": "a" }); +}); -// e) Fix the implementation of invert (and write tests to prove it's fixed!) +// multiple keys: + +test('invert multiple key-value pairs', () => { + expect(invert({ a: 1, b: 2 })).toEqual({ "1": "a", "2": "b" }); +}); + +// Empty object: + +test('invert empty object', () => { + expect(invert({})).toEqual({}); +}); + +// Non-string values: + +test('invert with non-string values', () => { + expect(invert({ x: 10, y: 20 })).toEqual({ "10": "x", "20": "y" }); +}); \ No newline at end of file