From 73851711ddf9a802b8489a500bea8711eb47e23d Mon Sep 17 00:00:00 2001 From: Dagim-Daniel Date: Tue, 28 Jul 2026 17:24:29 +0100 Subject: [PATCH 1/2] sprint2 implement tasks are done --- Sprint-2/implement/contains.js | 15 ++++++++- Sprint-2/implement/contains.test.js | 44 +++++++++----------------- Sprint-2/implement/lookup.js | 15 ++++++++- Sprint-2/implement/lookup.test.js | 40 ++++------------------- Sprint-2/implement/querystring.js | 43 +++++++++++++++++++++++-- Sprint-2/implement/querystring.test.js | 12 +------ Sprint-2/implement/tally.js | 12 +++++-- Sprint-2/implement/tally.test.js | 12 +++++-- 8 files changed, 110 insertions(+), 83 deletions(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..70a33d487 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,16 @@ -function contains() {} +function contains(keyInput,valueInput) { + if (Array.isArray(keyInput) == true) { + return false; + } else { + for (const key in keyInput) { + if (key == valueInput) { + return true; + } + } + } + return false; +} + +} module.exports = contains; diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..b7180cf13 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -1,35 +1,21 @@ const contains = require("./contains.js"); -/* -Implement a function called contains that checks an object contains a -particular property +test("Give a contains with object and property and if the object contains the property returns true", () => { + expect(contains({ a: 1, b: 2 }, "b")).toEqual(true); +}); -E.g. contains({a: 1, b: 2}, 'a') // returns true -as the object contains a key of 'a' +test("Give a contains with empty object and when passed to contains it returns false", () => { + expect(contains({}, "y")).toEqual(false); +}); -E.g. contains({a: 1, b: 2}, 'c') // returns false -as the object doesn't contains a key of 'c' -*/ +test("Give a contains with object and property and if the object contains the property returns true", () => { + expect(contains({ a: 1, b: 2 }, "a")).toEqual(true); +}); -// Acceptance criteria: +test("Give a contains with object and property and if the property is non-existent returns false", () => { + expect(contains({ a: 1, b: 2 }, "z")).toEqual(false); +}); -// 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 - -// Given an empty object -// When passed to contains -// Then it should return false -test.todo("contains on empty object returns false"); - -// Given an object with properties -// When passed to contains with an existing property name -// Then it should return true - -// Given an object with properties -// When passed to contains with a non-existent property name -// Then it should return false - -// Given invalid parameters like an array -// When passed to contains -// Then it should return false or throw an error +test("Give invalid parameter in this case array when passed to contains it returns false", () => { + expect(contains(["a", 2, "b", 3, 2], 2)).toEqual(false); +}); diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..d32574051 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,18 @@ -function createLookup() { +function createLookup(countryCurrencyPairs) { // implementation here + pairs = {}; + for (const [country, currency] of countryCurrencyPairs) { + pairs[country] = currency; + } + return pairs; } +console.log( + createLookup([ + ["UK", "GBP"], + ["ET", "ETB"], + ["CA", "CAD"], + ["FR", "EUR"], + ]) +); module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..94871c13f 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,35 +1,9 @@ const createLookup = require("./lookup.js"); -test.todo("creates a country currency code lookup for multiple codes"); - -/* - -Create a lookup object of key value pairs from an array of code pairs - -Acceptance Criteria: - -Given - - An array of arrays representing country code and currency code pairs - e.g. [['US', 'USD'], ['CA', 'CAD']] - -When - - createLookup function is called with the country-currency array as an argument - -Then - - It should return an object where: - - The keys are the country codes - - The values are the corresponding currency codes - -Example -Given: [['US', 'USD'], ['CA', 'CAD']] - -When -createLookup(countryCurrencyPairs) is called - -Then -It should return: - { - 'US': 'USD', - 'CA': 'CAD' - } -*/ +test("creates a country currency code lookup for multiple codes", () => { + expect([ + ["US", "USD"], + ["CA", "CAD"], + ["UK", "GBP"], + ]).toEqual({ US: "USD", CA: "CAD", UK: "GBP" }); +}); diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..d8d01c4b7 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,16 +1,53 @@ function parseQueryString(queryString) { const queryParams = {}; - if (queryString.length === 0) { + if (!queryString) { return queryParams; } const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); - queryParams[key] = value; + // Skip completely empty segments from '&&' or trailing '&' + if (!pair) continue; + + // 2. Split on '=' separating key and value + const eqIndex = pair.indexOf("="); + let rawKey, rawValue; + + if (eqIndex === -1) { + // Key with no '=' (e.g. "key") + rawKey = pair; + rawValue = ""; + } else { + rawKey = pair.slice(0, eqIndex); + rawValue = pair.slice(eqIndex + 1); + } + + // 3. Replace '+' with ' ' first, then decode URL percent-encoded values + const key = decodeURIComponent(rawKey.replace(/\+/g, " ")); + const value = decodeURIComponent(rawValue.replace(/\+/g, " ")); + + // 4. Handle identical keys (stretch goal) + if (queryParams.hasOwnProperty(key)) { + if (Array.isArray(queryParams[key])) { + queryParams[key].push(value); + } else { + queryParams[key] = [queryParams[key], value]; + } + } else { + queryParams[key] = value; + } } return queryParams; } +console.log(parseQueryString("equation=a=b-2")); // "equation: a=b-2" +console.log(parseQueryString("key1=value&&key2=value2&")); // key1:"value1" key2:"value2" +console.log(parseQueryString("=value")); // "":value +console.log(parseQueryString("key=")); // key:"" +console.log(parseQueryString("=")); // {"":""} +console.log(parseQueryString("%24half=1%2F2")); //{$half: "1/2",} +console.log(parseQueryString("full+name=John+Doe")); //{"full name": "John Doe",} +console.log(parseQueryString()); + module.exports = parseQueryString; diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 328b8df61..a2f400262 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -3,7 +3,7 @@ // Below are some test cases the implementation doesn't handle well. // Fix the implementation for these tests, 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("should parse values containing '='", () => { expect(parseQueryString("equation=a=b-2")).toEqual({ @@ -36,13 +36,3 @@ test("should replace '+' by ' '", () => { "full name": "John Doe", }); }); - -// Stretch exercise: Handling query strings that contain identical keys - -// Delete this test if you are not working on this optional case -test("should store values of a key in an array when the key has 2 or more values", () => { - expect(parseQueryString("key=value1&key=value2&key=value3&foo=bar")).toEqual({ - key: ["value1", "value2", "value3"], - foo: "bar", - }); -}); diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..cb4bdb008 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,11 @@ -function tally() {} - +function tally(items) { + const result = {}; + for (const item of items) { + result[item] = (result[item] || 0) + 1; + } + return result; +} +console.log(tally(["a", "b", "a", "c"])); +console.log(tally([])); // {} +console.log(tally("never mind")); module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..8891ddf7e 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -19,16 +19,22 @@ 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("given an array of items returns an object containing the counter for each item", () => { + expect(["a", "a"]).toEqual({ a: 2 }); +}); // 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([]).toEqual({}); +}); // Given an array with duplicate items // When passed to tally // Then it should return counts for each unique item - +test("given an array of duplicated items returns an object containing the counter for each item", () => { + expect(["a", "a"]).toEqual({ a: 2 }); +}); // Given an invalid input like a string // When passed to tally // Then it should throw an error From e2f40298ad5a77d2e989173e583365aaac689d39 Mon Sep 17 00:00:00 2001 From: Dagim-Daniel Date: Tue, 28 Jul 2026 22:45:51 +0100 Subject: [PATCH 2/2] clearing tasks under implement section on sprint 2 --- Sprint-2/implement/contains.js | 6 ++---- Sprint-2/implement/lookup.js | 8 -------- Sprint-2/implement/lookup.test.js | 13 ++++++++++--- Sprint-2/implement/querystring.js | 9 --------- Sprint-2/implement/tally.js | 7 ++++--- Sprint-2/implement/tally.test.js | 3 +++ 6 files changed, 19 insertions(+), 27 deletions(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index 70a33d487..575136836 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,5 +1,5 @@ -function contains(keyInput,valueInput) { - if (Array.isArray(keyInput) == true) { +function contains(keyInput, valueInput) { + if (Array.isArray(keyInput) == true) { return false; } else { for (const key in keyInput) { @@ -11,6 +11,4 @@ function contains(keyInput,valueInput) { return false; } -} - module.exports = contains; diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index d32574051..08035feb3 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -6,13 +6,5 @@ function createLookup(countryCurrencyPairs) { } return pairs; } -console.log( - createLookup([ - ["UK", "GBP"], - ["ET", "ETB"], - ["CA", "CAD"], - ["FR", "EUR"], - ]) -); module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 94871c13f..d0bcef3fb 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,9 +1,16 @@ const createLookup = require("./lookup.js"); test("creates a country currency code lookup for multiple codes", () => { + expect([["UK", "GBP"]]).toEqual({ UK: "GBP" }); +}); +test("creates an empty country currency code returns empty lookup ", () => { + expect([]).toEqual({}); +}); + +test("for multiple country currency returns multiple lookup", () => { expect([ - ["US", "USD"], - ["CA", "CAD"], ["UK", "GBP"], - ]).toEqual({ US: "USD", CA: "CAD", UK: "GBP" }); + ["ET", "ETB"], + ["FR", "EUR"], + ]).toEqual({ UK: "GBP", ET: "ETB", FR: "EUR" }); }); diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index d8d01c4b7..4c68c2243 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -41,13 +41,4 @@ function parseQueryString(queryString) { return queryParams; } -console.log(parseQueryString("equation=a=b-2")); // "equation: a=b-2" -console.log(parseQueryString("key1=value&&key2=value2&")); // key1:"value1" key2:"value2" -console.log(parseQueryString("=value")); // "":value -console.log(parseQueryString("key=")); // key:"" -console.log(parseQueryString("=")); // {"":""} -console.log(parseQueryString("%24half=1%2F2")); //{$half: "1/2",} -console.log(parseQueryString("full+name=John+Doe")); //{"full name": "John Doe",} -console.log(parseQueryString()); - module.exports = parseQueryString; diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index cb4bdb008..f8c2dfcb8 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,11 +1,12 @@ function tally(items) { const result = {}; + if (!Array.isArray(items)) { + throw new Error("Invalid input!"); + } for (const item of items) { result[item] = (result[item] || 0) + 1; } return result; } -console.log(tally(["a", "b", "a", "c"])); -console.log(tally([])); // {} -console.log(tally("never mind")); + module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 8891ddf7e..9b489aa3a 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -38,3 +38,6 @@ test("given an array of duplicated items returns an object containing the counte // Given an invalid input like a string // When passed to tally // Then it should throw an error +test("tally on an empty array returns an empty object", () => { + expect(() => tally("string").toThrow("Invalid input!")); +});