Skip to content

WESTMIDLANDS|MAY-2025|SARA TAHIR|Sprint 2/coursework #565

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
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
5 changes: 4 additions & 1 deletion Sprint-2/debug/address.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ const address = {
postcode: "XYZ 123",
};

console.log(`My house number is ${address[0]}`);
console.log(`My house number is ${address.houseNumber}`);
//It will not work because we cannot access a keys value from an object through index position.
//Fixed the code by using dot notation with the variable and the key.
// The current code is correctly giving us the output for the housenumber.
11 changes: 8 additions & 3 deletions Sprint-2/debug/author.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ const author = {
age: 40,
alive: true,
};

for (const value of author) {
console.log(value);
function readvalues(){
for (const key in author) {
console.log(key + ':' +author[key]);
}
}
readvalues();
/* My first prediction was that it wont work and we will need a for of loop to iterate over every key in object.
That prediction failed because a for of loop doesn't work here. we need a for in loop or we can also use a built in js method
called object.keys(), for my better understanding I will use a for in loop here.*/
15 changes: 12 additions & 3 deletions Sprint-2/debug/recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ const recipe = {
ingredients: ["olive oil", "tomatoes", "salt", "pepper"],
};

console.log(`${recipe.title} serves ${recipe.serves}
ingredients:
${recipe}`);
console.log(`${recipe.title} serves ${recipe.serves}\ningredients:`); // add a line break
recipe.ingredients.forEach((ingredient) => { //iterate over ear ingredient in ingredients.
console.log(ingredient);
})
/* This will log the whole object recipe rather than each ingredient on a different line.
We need to access each item of ingredients from the array seperately.Iterate over them.
we could also use
console.log(`${recipe.title} serves ${recipe.serves}\ningredients:`);

for (let i = 0; i < recipe.ingredients.length; i++) {
console.log(recipe.ingredients[i]);
}*/
15 changes: 14 additions & 1 deletion Sprint-2/implement/contains.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
function contains() {}
function contains(object, propertyName) {
// Check if the input is a real object (not null or an array)
const isObject =
typeof object === "object" && object !== null && !Array.isArray(object);

// If it's not a valid object or property name is missing, return false
if (!isObject || typeof propertyName !== "string") {
return false;
}

// Return true if the object has the property directly (not inherited)
return object.hasOwnProperty(propertyName);
}


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 @@ -20,16 +20,35 @@ as the object doesn't contains a key of 'c'
// 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",function(){
const input = {}
const result = contains(input,"name")
expect(result).toBe(false)
});


// Given an object with properties
// When passed to contains with an existing property name
// Then it should return true

test("returns true when object contains the property 'name'",function(){
const input ={firstName: "Sara",lastName: "Tahir",}
const result= contains(input, "firstName")
expect(result).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 when object doesn't contain the property 'name'",function(){
const input ={firstName: "Sara",lastName: "Tahir",}
const result= contains(input, "address")
expect(result).toBe(false)
})
// Given invalid parameters like an array
// When passed to contains
// Then it should return false or throw an error
test("returns false when an array is passed instead of an object", function () {
const input = ["address"];
const result = contains(input, "address");
expect(result).toBe(false);
});
26 changes: 23 additions & 3 deletions Sprint-2/implement/lookup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
function createLookup() {
// implementation here
function createLookup(pairs) {
const lookup = {};
for (let i = 0; i < pairs.length; i++) {
const [country, currency] = pairs[i];
lookup[country] = currency;
}
return lookup;
}

module.exports = createLookup;

/*const pair = [['US','USD'],['CA','CAD']]

Choose a reason for hiding this comment

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

This isn't a major problem here, but remember in a more complex git project not to commit lots of comments of unused code like this.

Copy link
Author

Choose a reason for hiding this comment

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

Noted, I will make sure I dont make it a practice.

const firstpair = pair[0]
let country1 = firstpair[0]
let currency1 = firstpair[1]
console.log("First country:", country1); // US
console.log("First currency:", currency1);

const secondPair= pair[1]
let country2 = secondPair[0]
let currency2 = secondPair[1]
console.log("Second country:", country2); // CA
console.log("Second currency:", currency2);
}
*/
7 changes: 6 additions & 1 deletion Sprint-2/implement/lookup.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
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'],['PAK','PKR']];
const expected = { 'US': 'USD', 'CA': 'CAD','PAK':'PKR' };
const result = createLookup(input);
expect(result).toEqual(expected);
});

/*

Expand Down
43 changes: 38 additions & 5 deletions Sprint-2/implement/querystring.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,49 @@

function parseQueryString(queryString) {
const queryParams = {};
if (queryString.length === 0) {
return queryParams;


if (queryString.startsWith("?")) { // Remove "?" if present at start
queryString = queryString.substring(1);
}

/*if (queryString.length === 0) {
return queryParams;
}*/

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

for (const pair of keyValuePairs) {
const [key, value] = pair.split("=");
queryParams[key] = value;
if (!pair) continue; // Skip empty strings from && or trailing &,

const idx = pair.indexOf("=");

let rawKey, rawValue;

if (idx === -1) {
rawKey = pair;
rawValue = "";
} else {
rawKey = pair.slice(0, idx);// starts at zero, stop just before the index of =
rawValue = pair.slice(idx + 1);
}

// Decode without replacing '+' with space
const key = decodeURIComponent(rawKey);
const value = decodeURIComponent(rawValue);

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;
}

module.exports = parseQueryString;
39 changes: 39 additions & 0 deletions Sprint-2/implement/querystring.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,42 @@ test("parses querystring values containing =", () => {
"equation": "x=y+1",
});
});
test("parses empty query string", () => {
expect(parseQueryString("")).toEqual({});
});

test("ignores leading question mark", () => {
expect(parseQueryString("?name=Sara")).toEqual({ name: "Sara" });
});

test("parses multiple key-value pairs", () => {
expect(parseQueryString("name=Sara&age=30")).toEqual({
name: "Sara",
age: "30"
})
});

test("handles missing value", () => {
expect(parseQueryString("name=")).toEqual({ name: "" });
});

test("handles missing key", () => {
expect(parseQueryString("=value")).toEqual({ "": "value" });
});

test("handles key without =", () => {
expect(parseQueryString("flag")).toEqual({ flag: "" });
});

test("handles duplicate keys", () => {
expect(parseQueryString("id=1&id=2")).toEqual({ id: ["1", "2"] });
});
test("decodes URL-encoded characters", () => {
expect(parseQueryString("name=Sara%20Tahir&city=Nottingham%20City")).toEqual({
name: "Sara Tahir",
city: "Nottingham City"
});
});
test("handles empty key and value", () => {
expect(parseQueryString("=")).toEqual({ "": "" });
});
20 changes: 19 additions & 1 deletion Sprint-2/implement/tally.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
function tally() {}
function tally(items) {
if (!Array.isArray(items)) {
throw new Error("Input should be an array");
}

const result = {};

for (const item of items) {
if (result[item]) {
result[item]++;
} else {
result[item] = 1;
}
}

return result;
}
module.exports = tally;
//takes and array of items
//item are keys
// how many times that item is repeated in the array- count of that item(key) is the value of each key
38 changes: 31 additions & 7 deletions Sprint-2/implement/tally.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,45 @@ const tally = require("./tally.js");
* tally(['a', 'a', 'b', 'c']), target output: { a : 2, b: 1, c: 1 }
*/

// Acceptance criteria:

// 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");
test("tally on an empty array returns an empty object", () => {
expect(tally([])).toEqual({});
});

// Given an array with one item
// When passed to tally
// Then it should return an object with count 1 for that item
test("tally on an array with one item returns correct count", () => {
expect(tally(['a'])).toEqual({ a: 1 });
});

// 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 correct counts", () => {
expect(tally(['a', 'a', 'a'])).toEqual({ a: 3 });
expect(tally(['a', 'a', 'b', 'c'])).toEqual({ a: 2, b: 1, c: 1 });
});

// Given an invalid input like a string
// When passed to tally
// Then it should throw an error
test("tally throws an error on invalid input like a string", () => {
expect(() => tally("invalid input")).toThrow();
});

// Given an invalid input like a number
// When passed to tally
// Then it should throw an error
test("tally throws an error on invalid input like a number", () => {
expect(() => tally(123)).toThrow();
});

// Given an invalid input like null
// When passed to tally
// Then it should throw an error
test("tally throws an error on invalid input like null", () => {
expect(() => tally(null)).toThrow();
});
21 changes: 19 additions & 2 deletions Sprint-2/interpret/invert.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
let object = {a:1,b:2}
console.log((invert)(object))

module.exports= invert
// a) What is the current return value when invert is called with { a : 1 }
// Current return value is {key: 1}, I was expecting {"1":"a"}

// b) What is the current return value when invert is called with { a: 1, b: 2 }
//// Current return value is {key: 2}, I was expecting {"1":"a", "2":"b"}

// 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 is creating an array of key-value pairs.

// d) Explain why the current return value is different from the target output
/*The target output swaps the keys and values. But in the current function,
the line invertedObj.key = value creates a property named "key" literally,
instead of using the variable key from the key-value pair.
This means it doesn’t use the actual key from the object, so the output is wrong.
To swap keys and values properly, we need to use bracket notation (invertedObj[value] = key)
so that the value of the variable value is used as the property name.

*/




// e) Fix the implementation of invert (and write tests to prove it's fixed!)
17 changes: 17 additions & 0 deletions Sprint-2/interpret/invert.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const invert = require("./invert");

test("given an object of key-value, it should return inverted value-key", () => {
expect(invert({ a: 1, b: 2 })).toEqual({ "1": "a", "2": "b" });
});

test("given an object of single key-value, it should return single value-key", () => {
expect(invert({ a: 1 })).toEqual({ "1": "a" });
});

test("given an empty input it should return an empty object", () => {
expect(invert({})).toEqual({});
});

test("invert values that are strings", () => {
expect(invert({ a: "1", b: "pink" })).toEqual({ "1": "a", "pink": "b" });
});
Loading