Skip to content
Open

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Good coverage of test cases (except angle 90 tested two times ^^" ).

Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,35 @@ import test from "node:test";

import { getAngleType } from "../implement/1-get-angle-type.js";

// TODO: Write tests to cover all cases, including boundary and invalid cases.
// Example: Identify Right Angles
test("Classifies right angle", () => {
assert.equal(getAngleType(90), "Right angle");
});

test("Classifies acute angles", () => {
assert.equal(getAngleType(45), "Acute angle");
assert.equal(getAngleType(1), "Acute angle"); // just inside
assert.equal(getAngleType(89), "Acute angle"); // just before 90
});

test("Classifies obtuse angles", () => {
assert.equal(getAngleType(140), "Obtuse angle");
assert.equal(getAngleType(91), "Obtuse angle"); // just after 90
assert.equal(getAngleType(179), "Obtuse angle"); // just before 180
});

test("Classifies straight angle", () => {
assert.equal(getAngleType(180), "Straight angle");
});

test("Classifies reflex angles", () => {
assert.equal(getAngleType(250), "Reflex angle");
assert.equal(getAngleType(181), "Reflex angle"); // just after 180
assert.equal(getAngleType(359), "Reflex angle"); // just before 360
});

test("Classifies right angles", () => {
const right = getAngleType(90);
assert.equal(right, "Right angle");
test("Classifies invalid angles", () => {
assert.equal(getAngleType(-1), "Invalid angle");
assert.equal(getAngleType(0), "Invalid angle"); // edge
assert.equal(getAngleType(360), "Invalid angle"); // edge
assert.equal(getAngleType(400), "Invalid angle");
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,26 @@ import test from "node:test";

import { isProperFraction } from "../implement/2-is-proper-fraction.js";

// TODO: Write tests to cover all cases.
// What combinations of numerators and denominators should you test?
test("Improper fraction (numerator > denominator)", () => {
assert.equal(isProperFraction(3, 2), false);
});

test("Zero cases", () => {
assert.equal(isProperFraction(0, 1), false);
assert.equal(isProperFraction(1, 0), false);
assert.equal(isProperFraction(0, 0), false);
});

test("Equal numerator and denominator", () => {
assert.equal(isProperFraction(1, 1), false);
});

test("Negative cases", () => {
assert.equal(isProperFraction(-2, 1), false);
assert.equal(isProperFraction(1, -2), false);
assert.equal(isProperFraction(-1, -2), true);
});

test("Basic proper fraction", () => {
// Example: 1/2 is a proper fraction
assert.equal(isProperFraction(1, 2), true);
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,63 @@ import test from "node:test";

import { getCardValue } from "../implement/3-get-card-value.js";

// TODO: Write tests to cover all outcomes, including throwing errors for invalid cards.

test("Valid single-digit card", () => {
assert.equal(getCardValue("9♠"), 9);
});

test("Arbitrary non-card string", () => {
assert.throws(() => getCardValue("invalid"), /Expected a number followed by a suit, but got "invalid"/, "Expected clear error");
assert.throws(
() => getCardValue("invalid"),
/Expected a number followed by a suit, but got "invalid"/,
"Expected clear error"
);
});

test("Ace returns 11", () => {
assert.equal(getCardValue("A♠"), 11);
assert.equal(getCardValue("A♥"), 11);
});

test("Face cards return 10", () => {
assert.equal(getCardValue("J♠"), 10);
assert.equal(getCardValue("Q♥"), 10);
assert.equal(getCardValue("K♦"), 10);
});

test("Number cards return their value", () => {
assert.equal(getCardValue("2♣"), 2);
assert.equal(getCardValue("5♥"), 5);
assert.equal(getCardValue("7♠"), 7);
assert.equal(getCardValue("10♦"), 10);
});

// TODO: What other invalid card cases can you think of?
test("Invalid cards throw an error", () => {
assert.throws(
() => getCardValue("A"),
/Expected a number followed by a suit, but got "A"/
);
assert.throws(
() => getCardValue("♠"),
/Expected a number followed by a suit, but got "♠"/
);
assert.throws(
() => getCardValue("11♠"),
/Expected a number followed by a suit, but got "11♠"/
);
assert.throws(
() => getCardValue("1♠"),
/Expected a number followed by a suit, but got "1♠"/
);
assert.throws(
() => getCardValue("hello"),
/Expected a number followed by a suit, but got "hello"/
);
assert.throws(
() => getCardValue(""),
/Expected a number followed by a suit, but got ""/
);
assert.throws(
() => getCardValue("A♠♠"),
/Expected a number followed by a suit, but got "A♠♠"/
);
});
35 changes: 16 additions & 19 deletions implement-and-rewrite-tests/implement/1-get-angle-type.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
// Implement a function getAngleType
//
// Don't forget to write tests in implement-tests-with-node-test.
//
// When given an angle in degrees, it should return a string indicating the type of angle:
// - "Acute angle" for angles greater than 0° and less than 90°
// - "Right angle" for exactly 90°
// - "Obtuse angle" for angles greater than 90° and less than 180°
// - "Straight angle" for exactly 180°
// - "Reflex angle" for angles greater than 180° and less than 360°
// - "Invalid angle" for angles outside the valid range.

// Assumption: The parameter is a valid number. (You do not need to handle non-numeric inputs.)

// Acceptance criteria:
// After you have implemented the function, write tests to cover all the cases, and
// execute the code to ensure all tests pass.

export function getAngleType(angle) {
// TODO: Implement this function
if (angle <= 0 || angle >= 360) {
return "Invalid angle";
}
if (angle < 90) {
return "Acute angle";
}
if (angle === 90) {
return "Right angle";
}
if (angle < 180) {
return "Obtuse angle";
}
if (angle === 180) {
return "Straight angle";
}
return "Reflex angle";
}
18 changes: 2 additions & 16 deletions implement-and-rewrite-tests/implement/2-is-proper-fraction.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
// Implement a function isProperFraction,
//
// Don't forget to write tests in implement-tests-with-node-test.
//
// When given two numbers, a numerator and a denominator, it should return true if
// the given numbers form a proper fraction, and false otherwise.

// Assumption: The parameters are valid numbers (not NaN or Infinity).

// Note: If you are unfamiliar with proper fractions, please look up its mathematical definition.

// Acceptance criteria:
// After you have implemented the function, write tests to cover all the cases, and
// execute the code to ensure all tests pass.

export function isProperFraction(numerator, denominator) {
// TODO: Implement this function
const value = numerator / denominator;
return value > 0 && value < 1;
}
Comment on lines 1 to 4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I know there are two different mathematical definitions regarding negative proper fraction. For those test cases, I would treat them as correct no matter it returns true or false. I only highlight those test cases consistently defined across both mathematical definitions. Based on the test cases changes, you may need to change this implementation as well. Thank you.

53 changes: 28 additions & 25 deletions implement-and-rewrite-tests/implement/3-get-card-value.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
// This problem involves playing cards: https://en.wikipedia.org/wiki/Standard_52-card_deck

// Don't forget to write tests in implement-tests-with-node-test.

// Implement a function getCardValue, when given a string representing a playing card,
// should return the numerical value of the card.

// A valid card string will contain a rank followed by the suit.
// The rank can be one of the following strings:
// "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"
// The suit can be one of the following emojis:
// "♠", "♥", "♦", "♣"
// For example: "A♠", "2♥", "10♥", "J♣", "Q♦", "K♦".

// When the card is an ace ("A"), the function should return 11.
// When the card is a face card ("J", "Q", "K"), the function should return 10.
// When the card is a number card ("2" to "10"), the function should return its numeric value.

// When the card string is invalid (not following the above format), the function should
// throw an error.
export function getCardValue(card) {
const suit = card.slice(-1);
const rank = card.slice(0, -1);
const validSuits = "♠♥♦♣";
const validRanks = [
"A",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"J",
"Q",
"K",
];

// Acceptance criteria:
// After you have implemented the function, write tests to cover all the cases, and
// execute the code to ensure all tests pass.
if (!validSuits.includes(suit)) {
throw new Error(`Expected a number followed by a suit, but got "${card}"`);
}
if (!validRanks.includes(rank)) {
throw new Error(`Expected a number followed by a suit, but got "${card}"`);
}

export function getCardValue(card) {
// TODO: Implement this function
if (rank === "A") return 11;
if (rank === "J" || rank === "Q" || rank === "K") return 10;
return Number(rank);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Excellent.

Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
import { getAngleType } from "../implement/1-get-angle-type.js";

// TODO: Write tests in Jest syntax to cover all cases/outcomes,
// including boundary and invalid cases.

// Case 1: Acute angles
test(`should return "Acute angle" when (0 < angle < 90)`, () => {
// Test various acute angles, including boundary cases
expect(getAngleType(1)).toEqual("Acute angle");
expect(getAngleType(45)).toEqual("Acute angle");
expect(getAngleType(89)).toEqual("Acute angle");
});

// Case 2: Right angle
// Case 3: Obtuse angles
// Case 4: Straight angle
// Case 5: Reflex angles
// Case 6: Invalid angles
test(`should return "Right angle" when angle === 90`, () => {
expect(getAngleType(90)).toEqual("Right angle");
});

test(`should return "Obtuse angle" when (90 < angle < 180)`, () => {
expect(getAngleType(91)).toEqual("Obtuse angle");
expect(getAngleType(135)).toEqual("Obtuse angle");
expect(getAngleType(179)).toEqual("Obtuse angle");
});

test(`should return "Straight angle" when angle === 180`, () => {
expect(getAngleType(180)).toEqual("Straight angle");
});

test(`should return "Reflex angle" when (180 < angle < 360)`, () => {
expect(getAngleType(181)).toEqual("Reflex angle");
expect(getAngleType(270)).toEqual("Reflex angle");
expect(getAngleType(359)).toEqual("Reflex angle");
});

test(`should return "Invalid angle" for angles outside the valid range`, () => {
expect(getAngleType(0)).toEqual("Invalid angle");
expect(getAngleType(-45)).toEqual("Invalid angle");
expect(getAngleType(360)).toEqual("Invalid angle");
expect(getAngleType(400)).toEqual("Invalid angle");
});
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
import { isProperFraction } from "../implement/2-is-proper-fraction.js";

// TODO: Write tests in Jest syntax to cover all combinations of positives, negatives, zeros, and other categories.

// Special case: numerator is zero
test(`should return false when denominator is zero`, () => {
expect(isProperFraction(1, 0)).toEqual(false);
});

test("Basic proper fraction", () => {
expect(isProperFraction(1, 2)).toEqual(true);
expect(isProperFraction(2, 1)).toEqual(false);
expect(isProperFraction(-2, 1)).toEqual(false);
expect(isProperFraction(1, -2)).toEqual(false);
});

test("Improper fraction (numerator > denominator)", () => {
expect(isProperFraction(3, 2)).toEqual(false);
});

test("Zero cases", () => {
expect(isProperFraction(0, 1)).toEqual(false);
expect(isProperFraction(1, 0)).toEqual(false);
expect(isProperFraction(0, 0)).toEqual(false);
});

test("Equal numerator and denominator", () => {
expect(isProperFraction(1, 1)).toEqual(false);
});

test("Negative cases", () => {
expect(isProperFraction(-2, 1)).toEqual(false);
expect(isProperFraction(1, -2)).toEqual(false);
expect(isProperFraction(-1, -2)).toEqual(true);
});
Original file line number Diff line number Diff line change
@@ -1,18 +1,40 @@
import { getCardValue } from "../implement/3-get-card-value.js";

// TODO: Write tests in Jest syntax to cover all possible outcomes.

// Case 1: Ace (A)
test(`Should return 11 when given an ace card`, () => {
expect(getCardValue("A♠")).toEqual(11);
expect(getCardValue("A♥")).toEqual(11);
});

// Suggestion: Group the remaining test data into these categories:
// Number Cards (2-10)
// Face Cards (J, Q, K)
// Invalid Cards
test(`Should return the number for number cards`, () => {
expect(getCardValue("2♣")).toEqual(2);
expect(getCardValue("5♥")).toEqual(5);
expect(getCardValue("7♠")).toEqual(7);
expect(getCardValue("10♦")).toEqual(10);
});

// To learn how to test whether a function throws an error as expected in Jest,
// please refer to the Jest documentation:
// https://jestjs.io/docs/expect#tothrowerror
test(`Should return 10 for face cards`, () => {
expect(getCardValue("J♠")).toEqual(10);
expect(getCardValue("Q♥")).toEqual(10);
expect(getCardValue("K♦")).toEqual(10);
});

test(`Should throw for invalid cards`, () => {
expect(() => getCardValue("A")).toThrow(
/Expected a number followed by a suit, but got "A"/
);
expect(() => getCardValue("♠")).toThrow(
/Expected a number followed by a suit, but got "♠"/
);
expect(() => getCardValue("11♠")).toThrow(
/Expected a number followed by a suit, but got "11♠"/
);
expect(() => getCardValue("hello")).toThrow(
/Expected a number followed by a suit, but got "hello"/
);
expect(() => getCardValue("")).toThrow(
/Expected a number followed by a suit, but got ""/
);
expect(() => getCardValue("A♠♠")).toThrow(
/Expected a number followed by a suit, but got "A♠♠"/
);
});
Loading