From e092272bd4bafd2a78774071a185c38c586aef30 Mon Sep 17 00:00:00 2001 From: Pauline Srifi Date: Thu, 18 Apr 2024 09:43:42 +0200 Subject: [PATCH] debut TP2 --- package.json | 4 +- src/exercises/TP2/fibo/index.test.ts | 57 +++++++++ src/exercises/TP2/fibo/index.ts | 5 + src/exercises/TP2/fizzbuzz/index.test.ts | 64 ++++++++++ src/exercises/TP2/fizzbuzz/index.ts | 7 ++ src/exercises/Template/index.test.ts | 32 ----- src/exercises/Template/index.ts | 3 - .../addStringOfNumbers/index.test.ts | 70 +++++++++++ src/exercises/addStringOfNumbers/index.ts | 21 ++++ .../convertToLowercase/index.test.ts | 19 +++ src/exercises/convertToLowercase/index.ts | 3 + src/exercises/isBeforeNow/index.test.ts | 37 ++++++ src/exercises/isBeforeNow/index.ts | 3 + src/exercises/mockMathPow/index.test.ts | 18 +++ src/exercises/mockMathPow/index.ts | 3 + .../mockStringUppercase/index.test.ts | 18 +++ src/exercises/mockStringUppercase/index.ts | 3 + src/exercises/multiplyArrays/index.test.ts | 47 ++++++++ src/exercises/multiplyArrays/index.ts | 16 +++ src/exercises/multiplyArrays2/index.test.ts | 44 +++++++ src/exercises/multiplyArrays2/index.ts | 10 ++ src/exercises/removeDuplicates/index.test.ts | 14 +++ src/exercises/removeDuplicates/index.ts | 3 + src/exercises/removeDuplicates2/index.test.ts | 14 +++ src/exercises/removeDuplicates2/index.ts | 3 + src/exercises/testAnException/index.test.ts | 14 +++ src/exercises/testAnException/index.ts | 3 + src/exercises/validation/age/index.test.ts | 37 ++++++ src/exercises/validation/age/index.ts | 18 +++ src/exercises/validation/number/index.test.ts | 109 ++++++++++++++++++ src/exercises/validation/number/index.ts | 34 ++++++ 31 files changed, 696 insertions(+), 37 deletions(-) create mode 100644 src/exercises/TP2/fibo/index.test.ts create mode 100644 src/exercises/TP2/fibo/index.ts create mode 100644 src/exercises/TP2/fizzbuzz/index.test.ts create mode 100644 src/exercises/TP2/fizzbuzz/index.ts delete mode 100644 src/exercises/Template/index.test.ts delete mode 100644 src/exercises/Template/index.ts create mode 100644 src/exercises/addStringOfNumbers/index.test.ts create mode 100644 src/exercises/addStringOfNumbers/index.ts create mode 100644 src/exercises/convertToLowercase/index.test.ts create mode 100644 src/exercises/convertToLowercase/index.ts create mode 100644 src/exercises/isBeforeNow/index.test.ts create mode 100644 src/exercises/isBeforeNow/index.ts create mode 100644 src/exercises/mockMathPow/index.test.ts create mode 100644 src/exercises/mockMathPow/index.ts create mode 100644 src/exercises/mockStringUppercase/index.test.ts create mode 100644 src/exercises/mockStringUppercase/index.ts create mode 100644 src/exercises/multiplyArrays/index.test.ts create mode 100644 src/exercises/multiplyArrays/index.ts create mode 100644 src/exercises/multiplyArrays2/index.test.ts create mode 100644 src/exercises/multiplyArrays2/index.ts create mode 100644 src/exercises/removeDuplicates/index.test.ts create mode 100644 src/exercises/removeDuplicates/index.ts create mode 100644 src/exercises/removeDuplicates2/index.test.ts create mode 100644 src/exercises/removeDuplicates2/index.ts create mode 100644 src/exercises/testAnException/index.test.ts create mode 100644 src/exercises/testAnException/index.ts create mode 100644 src/exercises/validation/age/index.test.ts create mode 100644 src/exercises/validation/age/index.ts create mode 100644 src/exercises/validation/number/index.test.ts create mode 100644 src/exercises/validation/number/index.ts diff --git a/package.json b/package.json index 2162d1a..711bd0c 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ }, "dependencies": { "nodemon": "^3.1.0", - "reflect-metadata": "^0.2.1", + "reflect-metadata": "^0.2.2", "ts-node": "^10.9.2", "tsyringe": "^4.8.0" } -} \ No newline at end of file +} diff --git a/src/exercises/TP2/fibo/index.test.ts b/src/exercises/TP2/fibo/index.test.ts new file mode 100644 index 0000000..681e329 --- /dev/null +++ b/src/exercises/TP2/fibo/index.test.ts @@ -0,0 +1,57 @@ +import { fibo } from "./index"; + +describe("fibo", () => { + it("should return 0 when given 0", () => { + // arrange + const input = 0; + const expected = 0; + + // act + const result = fibo(input); + + // assert + expect(result).toBe(expected); + }); + + it("should return 1 when given 1", () => { + // arrange + const input = 1; + const expected = 1; + + // act + const result = fibo(input); + + // assert + expect(result).toBe(expected); + }); + + it.each([ + { + input: 2, + expected: 1, + }, + { + input: 3, + expected: 2, + }, + { + input: 4, + expected: 3, + }, + { + input: 5, + expected: 5, + }, + { + input: 6, + expected: 8, + }, + ])("should return fibo(n) when given n", ({ input, expected }) => { + // arrange + // act + const result = fibo(input); + + // assert + expect(result).toBe(expected); + }); +}); diff --git a/src/exercises/TP2/fibo/index.ts b/src/exercises/TP2/fibo/index.ts new file mode 100644 index 0000000..e92d3fd --- /dev/null +++ b/src/exercises/TP2/fibo/index.ts @@ -0,0 +1,5 @@ +export function fibo(n: number): number { + if (n <= 1) return n; + + return fibo(n - 2) + fibo(n - 1); +} diff --git a/src/exercises/TP2/fizzbuzz/index.test.ts b/src/exercises/TP2/fizzbuzz/index.test.ts new file mode 100644 index 0000000..cf6e3a9 --- /dev/null +++ b/src/exercises/TP2/fizzbuzz/index.test.ts @@ -0,0 +1,64 @@ +import { fizzBuzz } from "./index"; + +describe("fizzBuzz", () => { + it.each([ + { + input: 1, + expected: "1", + }, + { + input: 2, + expected: "2", + }, + { + input: 4, + expected: "4", + }, + ])( + "should return the number as string when given a non multiple of 3, 5 or 15", + ({ input, expected }) => { + // arrange + // act + const result = fizzBuzz(input); + + // assert + expect(result).toBe(expected); + } + ); + + it.each([3, 6, 9])( + "should return 'Fizz' when given a multiple of 3", + (input) => { + // arrange + // act + const result = fizzBuzz(input); + + // assert + expect(result).toBe("Fizz"); + } + ); + + it.each([5, 10, 20])( + 'should return "Buzz" when given a multiple of 5', + (input) => { + // arrange + // act + const result = fizzBuzz(input); + + // assert + expect(result).toBe("Buzz"); + } + ); + + it.each([15, 30, 45])( + 'should return "FizzBuzz" when given a multiple of 15', + (input) => { + // arrange + // act + const result = fizzBuzz(input); + + // assert + expect(result).toBe("FizzBuzz"); + } + ); +}); diff --git a/src/exercises/TP2/fizzbuzz/index.ts b/src/exercises/TP2/fizzbuzz/index.ts new file mode 100644 index 0000000..cc9329d --- /dev/null +++ b/src/exercises/TP2/fizzbuzz/index.ts @@ -0,0 +1,7 @@ +export function fizzBuzz(input: number): string { + if (input % 15 === 0) return "FizzBuzz"; + if (input % 5 === 0) return "Buzz"; + if (input % 3 === 0) return "Fizz"; + + return input.toString(); +} diff --git a/src/exercises/Template/index.test.ts b/src/exercises/Template/index.test.ts deleted file mode 100644 index 0b2f38e..0000000 --- a/src/exercises/Template/index.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { divide } from "./index"; - -describe("Test divide", () => { - it.each([ - { foo: "", bar: "", expected: "" }, - ])( - "should $foo $bar", - ({ foo, bar, expected }) => { - // act - // const result = function (foo, bar); - const result = 0; - // assert - expect(result).toEqual(expected); - console.log(`Test with foo = ${foo}, bar = ${bar}, expected = ${expected}, result = ${result}`); - } - ); - - /* - * - * If exception test - * - * */ - it("should throw an exception when dividing by zero", () => { - // arrange - const foo = ""; - const bar = ""; - // act & assert - ///TODO - // expect(() => function (foo, bar).toThrow("E"); - console.log(foo + bar); - }); -}); \ No newline at end of file diff --git a/src/exercises/Template/index.ts b/src/exercises/Template/index.ts deleted file mode 100644 index 667f905..0000000 --- a/src/exercises/Template/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function name(foo : number) : number { - return foo + 1; -} diff --git a/src/exercises/addStringOfNumbers/index.test.ts b/src/exercises/addStringOfNumbers/index.test.ts new file mode 100644 index 0000000..2fcda00 --- /dev/null +++ b/src/exercises/addStringOfNumbers/index.test.ts @@ -0,0 +1,70 @@ +import { addStringOfNumbers } from "./index"; + +describe("addStringOfNumbers", () => { + it("should return 0 when given an empty string", () => { + // arrange + const input = ""; + const expected = 0; + + // act + const result = addStringOfNumbers(input); + + // assert + expect(result).toBe(expected); + }); + + it.each([ + { input: "12", expected: 12 }, + { input: "1.5", expected: 1.5 }, + { input: "-2", expected: -2 }, + { input: "-2.333", expected: -2.333 }, + ])( + "should return n when given the string representation of n", + ({ input, expected }) => { + // arrange + // act + const result = addStringOfNumbers(input); + + // assert + expect(result).toBe(expected); + } + ); + + it.each(["--4", "1-23", "3..5"])( + "should throw an error when given a string that is not a number", + (input) => { + // arrange + // act + const act = () => addStringOfNumbers(input); + + // assert + expect(act).toThrow("Not valid number"); + } + ); + + it.each([ + { input: "2,3", expected: 5 }, + { input: "-2.5,4", expected: 1.5 }, + ])( + "should add two comma separated numbers in a string", + ({ input, expected }) => { + // arrange + // act + const result = addStringOfNumbers(input); + + // assert + expect(result).toBe(expected); + } + ); + + it("should throw an error when given a string with wrong separator", () => { + // arrange + const input = "-2.5;3"; + + // act + const act = () => addStringOfNumbers(input); + + // assert + expect(act).toThrow("Invalid characters"); + }); +}); diff --git a/src/exercises/addStringOfNumbers/index.ts b/src/exercises/addStringOfNumbers/index.ts new file mode 100644 index 0000000..c69230c --- /dev/null +++ b/src/exercises/addStringOfNumbers/index.ts @@ -0,0 +1,21 @@ +export function addStringOfNumbers(input: string) { + if (input === "") return 0; + + // Regex to catch any character that is not a digit, comma, dot or minus sign + const isContainingBadCharacters = /[^-,.\d]/.test(input); + if (isContainingBadCharacters) throw new Error("Invalid characters"); + + if (!input.includes(",")) { + const num = Number(input); + if (isNaN(num)) throw new Error("Not valid number"); + return num; + } + + const arr = input.split(","); + return arr.reduce((acc, str) => { + const num = Number(str); + if (isNaN(num)) throw new Error("Not valid numbers"); + + return acc + num; + }, 0); +} diff --git a/src/exercises/convertToLowercase/index.test.ts b/src/exercises/convertToLowercase/index.test.ts new file mode 100644 index 0000000..a727dd2 --- /dev/null +++ b/src/exercises/convertToLowercase/index.test.ts @@ -0,0 +1,19 @@ +import { convertToLowercase } from "./index"; + +describe("convertToLowercase", () => { + it.each([ + { input: "ToTO", expected: "toto" }, + { input: "ToTo", expected: "toto" }, + { input: "TOTo", expected: "toto" }, + ])( + "should return the input in lowercase when all letters are uppercases", + ({ input, expected }) => { + // Arrange + // Act + const result = convertToLowercase(input); + + // Assert + expect(result).toStrictEqual(expected); + } + ); +}); diff --git a/src/exercises/convertToLowercase/index.ts b/src/exercises/convertToLowercase/index.ts new file mode 100644 index 0000000..1f626cb --- /dev/null +++ b/src/exercises/convertToLowercase/index.ts @@ -0,0 +1,3 @@ +export function convertToLowercase(input: string): string { + return input.toLowerCase(); +} diff --git a/src/exercises/isBeforeNow/index.test.ts b/src/exercises/isBeforeNow/index.test.ts new file mode 100644 index 0000000..af0f4d0 --- /dev/null +++ b/src/exercises/isBeforeNow/index.test.ts @@ -0,0 +1,37 @@ +import { isBeforeNow } from "./index"; + +const dateBefore = new Date("2022-01-01T00:00:00.000Z"); +const dateNow = new Date("2023-01-01T00:00:00.000Z"); +const dateAfter = new Date("2024-01-01T00:00:00.000Z"); + +describe("isBeforeNow", () => { + beforeEach(() => { + jest.useFakeTimers({ + now: dateNow, + }); + + // or + + // jest.spyOn(Date, "now").mockReturnValue(dateNow.getTime()); + }); + + afterEach(() => { + jest.useRealTimers(); + + // or + + // jest.restoreAllMocks(); + }); + + it("returns true if the date is before now", () => { + expect(isBeforeNow(dateBefore)).toBe(true); + }); + + it("returns false if the date is now", () => { + expect(isBeforeNow(dateNow)).toBe(false); + }); + + it("returns false if the date is after now", () => { + expect(isBeforeNow(dateAfter)).toBe(false); + }); +}); diff --git a/src/exercises/isBeforeNow/index.ts b/src/exercises/isBeforeNow/index.ts new file mode 100644 index 0000000..5215b87 --- /dev/null +++ b/src/exercises/isBeforeNow/index.ts @@ -0,0 +1,3 @@ +export function isBeforeNow(date: Date): boolean { + return date.getTime() < Date.now(); +} diff --git a/src/exercises/mockMathPow/index.test.ts b/src/exercises/mockMathPow/index.test.ts new file mode 100644 index 0000000..69228d4 --- /dev/null +++ b/src/exercises/mockMathPow/index.test.ts @@ -0,0 +1,18 @@ +import { square } from "./index"; + +describe("square", () => { + it("returns the number pow 2", () => { + // Arrange + const num = 3; + Math.pow = jest.fn(); //.mockReturnValue(2); + + // Act + square(num); + + // Assert + expect(Math.pow).toHaveBeenCalledTimes(1); + expect(Math.pow).toHaveBeenCalledWith(3, 2); + + // expect(square(num)).toBe(2); + }); +}); diff --git a/src/exercises/mockMathPow/index.ts b/src/exercises/mockMathPow/index.ts new file mode 100644 index 0000000..966aed7 --- /dev/null +++ b/src/exercises/mockMathPow/index.ts @@ -0,0 +1,3 @@ +export function square(value: number): number { + return Math.pow(value, 2); +} diff --git a/src/exercises/mockStringUppercase/index.test.ts b/src/exercises/mockStringUppercase/index.test.ts new file mode 100644 index 0000000..a39dfde --- /dev/null +++ b/src/exercises/mockStringUppercase/index.test.ts @@ -0,0 +1,18 @@ +import { toUpperCase } from "./index"; + +describe("toUpperCase", () => { + it("returns the string in uppercase", () => { + // Arrange + const input = "hello"; + String.prototype.toUpperCase = jest.fn(); //.mockReturnValue("BLABLA"); + + // Act + toUpperCase(input); + + // Assert + expect(input.toUpperCase).toHaveBeenCalledTimes(1); + expect(input.toUpperCase).toHaveBeenCalledWith(); + + // expect(toUpperCase(input)).toBe("BLABLA"); + }); +}); diff --git a/src/exercises/mockStringUppercase/index.ts b/src/exercises/mockStringUppercase/index.ts new file mode 100644 index 0000000..2c981f9 --- /dev/null +++ b/src/exercises/mockStringUppercase/index.ts @@ -0,0 +1,3 @@ +export function toUpperCase(value: string): string { + return value.toUpperCase(); +} diff --git a/src/exercises/multiplyArrays/index.test.ts b/src/exercises/multiplyArrays/index.test.ts new file mode 100644 index 0000000..0d4ba3c --- /dev/null +++ b/src/exercises/multiplyArrays/index.test.ts @@ -0,0 +1,47 @@ +import { multiplyArrays } from "./index"; + +describe("multiplyArrays", () => { + it.each([ + { + arr1: [1, 2, 3], + arr2: [4, 5, 6], + expected: [4, 10, 18], + }, + { + arr1: [3, 2, 3], + arr2: [4, 5, 3], + expected: [12, 10, 9], + }, + ])("should multiply all numbers of 2 arrays", ({ arr1, arr2, expected }) => { + // Arrange + // Act + const result = multiplyArrays(arr1, arr2); + + // Assert + expect(result).toStrictEqual(expected); + }); + + it("should throw when one array is empty", () => { + // Arrange + const arr1 = [1, 2, 3]; + const arr2: number[] = []; + + // Act + const act = () => multiplyArrays(arr1, arr2); + + // Assert + expect(act).toThrow("Arrays must have at least one element"); + }); + + it("should throw when arrays length is different", () => { + // Arrange + const arr1 = [1, 2, 3]; + const arr2 = [4, 5]; + + // Act + const act = () => multiplyArrays(arr1, arr2); + + // Assert + expect(act).toThrow("Arrays must have the same length"); + }); +}); diff --git a/src/exercises/multiplyArrays/index.ts b/src/exercises/multiplyArrays/index.ts new file mode 100644 index 0000000..9d79c0e --- /dev/null +++ b/src/exercises/multiplyArrays/index.ts @@ -0,0 +1,16 @@ +export function multiplyArrays(a: number[], b: number[]): number[] { + if (a.length === 0 || b.length === 0) { + throw new Error("Arrays must have at least one element"); + } + + if (a.length !== b.length) { + throw new Error("Arrays must have the same length"); + } + + const output: number[] = new Array(a.length); + for (let i = 0; i < output.length; i++) { + output[i] = a[i] * b[i]; + } + + return output; +} diff --git a/src/exercises/multiplyArrays2/index.test.ts b/src/exercises/multiplyArrays2/index.test.ts new file mode 100644 index 0000000..24f1c82 --- /dev/null +++ b/src/exercises/multiplyArrays2/index.test.ts @@ -0,0 +1,44 @@ +import { multiplyArrays } from "./index"; + +describe("multiplyArrays", () => { + it.each([ + { arr1: [1, 2, 3], arr2: [4, 5, 6], expected: [4, 10, 18] }, + { arr1: [-1, -2, -3], arr2: [4, -5, 6], expected: [-4, 10, -18] }, + { + arr1: [-1.1, -2.1, -3.1], + arr2: [4, -5, 6], + expected: [-4.4, 10.5, -18.6], + }, + ])("should multiply two arrays", ({ arr1, arr2, expected }) => { + // arrange + // act + const result = multiplyArrays(arr1, arr2); + + // assert + expect(result).toStrictEqual(expected); + }); + + it("should throw an error if arrays are not the same length", () => { + // arrange + const arr1 = [1, 2, 3]; + const arr2 = [4, 5]; + + // act + const act = () => multiplyArrays(arr1, arr2); + + // assert + expect(act).toThrow("Arrays must be the same length"); + }); + + it("should throw an error if arrays are empty", () => { + // arrange + const arr1: number[] = []; + const arr2: number[] = []; + + // act + const act = () => multiplyArrays(arr1, arr2); + + // assert + expect(act).toThrow("Arrays must not be empty"); + }); +}); diff --git a/src/exercises/multiplyArrays2/index.ts b/src/exercises/multiplyArrays2/index.ts new file mode 100644 index 0000000..38d134d --- /dev/null +++ b/src/exercises/multiplyArrays2/index.ts @@ -0,0 +1,10 @@ +export function multiplyArrays(arr1: number[], arr2: number[]): number[] { + const isSameLength = arr1.length === arr2.length; + + if (!isSameLength) throw new Error("Arrays must be the same length"); + + const isOneEmpty = arr1.length === 0 || arr2.length === 0; + if (isOneEmpty) throw new Error("Arrays must not be empty"); + + return arr1.map((num, index) => num * arr2[index]); +} diff --git a/src/exercises/removeDuplicates/index.test.ts b/src/exercises/removeDuplicates/index.test.ts new file mode 100644 index 0000000..e11d234 --- /dev/null +++ b/src/exercises/removeDuplicates/index.test.ts @@ -0,0 +1,14 @@ +import { removeDuplicates } from "./index"; + +describe("removeDuplicates", () => { + it("should multiply all numbers of 2 arrays", () => { + // Arrange + const arr = [1, 2, 2, 2, 3, 3, 4]; + + // Act + const result = removeDuplicates(arr); + + // Assert + expect(result).toStrictEqual([1, 2, 3, 4]); + }); +}); diff --git a/src/exercises/removeDuplicates/index.ts b/src/exercises/removeDuplicates/index.ts new file mode 100644 index 0000000..f76ad20 --- /dev/null +++ b/src/exercises/removeDuplicates/index.ts @@ -0,0 +1,3 @@ +export function removeDuplicates(a: number[]): number[] { + return Array.from(new Set(a)); +} diff --git a/src/exercises/removeDuplicates2/index.test.ts b/src/exercises/removeDuplicates2/index.test.ts new file mode 100644 index 0000000..3a89c18 --- /dev/null +++ b/src/exercises/removeDuplicates2/index.test.ts @@ -0,0 +1,14 @@ +import { removeDuplicates } from "./index"; + +describe("removeDuplicates", () => { + it("should remove duplicates from an array", () => { + // arrange + const arr = [1, 2, 2, 3, 4, 4, 5]; + + // act + const result = removeDuplicates(arr); + + // assert + expect(result).toStrictEqual([1, 2, 3, 4, 5]); + }); +}); diff --git a/src/exercises/removeDuplicates2/index.ts b/src/exercises/removeDuplicates2/index.ts new file mode 100644 index 0000000..0afc5bb --- /dev/null +++ b/src/exercises/removeDuplicates2/index.ts @@ -0,0 +1,3 @@ +export function removeDuplicates(arr: number[]): number[] { + return Array.from(new Set(arr)); +} diff --git a/src/exercises/testAnException/index.test.ts b/src/exercises/testAnException/index.test.ts new file mode 100644 index 0000000..60247a7 --- /dev/null +++ b/src/exercises/testAnException/index.test.ts @@ -0,0 +1,14 @@ +import { throwAnException } from "./index"; + +describe("testAnException", () => { + it("should throw an exception", () => { + // Arrange + // Act + const act = () => { + throwAnException(); + }; + + // Assert + expect(act).toThrow("I am an exception"); + }); +}); diff --git a/src/exercises/testAnException/index.ts b/src/exercises/testAnException/index.ts new file mode 100644 index 0000000..fe6789e --- /dev/null +++ b/src/exercises/testAnException/index.ts @@ -0,0 +1,3 @@ +export function throwAnException(): void { + throw new Error("I am an exception"); +} diff --git a/src/exercises/validation/age/index.test.ts b/src/exercises/validation/age/index.test.ts new file mode 100644 index 0000000..dcba489 --- /dev/null +++ b/src/exercises/validation/age/index.test.ts @@ -0,0 +1,37 @@ +import "reflect-metadata"; +import { container } from "tsyringe"; +import { AgeValidation } from "./index"; + +describe("AgeValidation", () => { + const ageValidation = container.resolve(AgeValidation); + + describe("validateAge", () => { + it.each([ + { input: "1", expected: 1 }, + { input: "18", expected: 18 }, + { input: "100", expected: 100 }, + ])( + "should return a number when given a string if represents a valid age", + ({ input, expected }) => { + // arrange + // act + const result = ageValidation.validateAge(input); + + // assert + expect(result).toBe(expected); + } + ); + + it.each([{ input: "-2", expected: "Input must be a valid age" }])( + "should throw an error if input does not represent a valid age", + ({ input, expected }) => { + // arrange + // act + const act = () => ageValidation.validateAge(input); + + // assert + expect(act).toThrow(expected); + } + ); + }); +}); diff --git a/src/exercises/validation/age/index.ts b/src/exercises/validation/age/index.ts new file mode 100644 index 0000000..fb282ed --- /dev/null +++ b/src/exercises/validation/age/index.ts @@ -0,0 +1,18 @@ +import { singleton } from "tsyringe"; +import { NumberValidation } from "../number"; + +@singleton() +export class AgeValidation { + public constructor(private numberValidation: NumberValidation) {} + + public validateAge(input: string) { + try { + let number: number = this.numberValidation.validateInteger(input); + number = this.numberValidation.validatePositive(input); + + return number; + } catch (error) { + throw new Error("Input must be a valid age"); + } + } +} diff --git a/src/exercises/validation/number/index.test.ts b/src/exercises/validation/number/index.test.ts new file mode 100644 index 0000000..e319d7c --- /dev/null +++ b/src/exercises/validation/number/index.test.ts @@ -0,0 +1,109 @@ +import "reflect-metadata" +import { container } from "tsyringe"; +import { NumberValidation } from "./index"; + +describe("NumberValidation", () => { + const numberValidation = container.resolve(NumberValidation); + + describe("validateNumber", () => { + it.each([ + { input: "0", expected: 0 }, + { input: "1", expected: 1 }, + { input: "-1", expected: -1 }, + { input: "1.67", expected: 1.67 }, + { input: "-1.67", expected: -1.67 }, + { input: "-1e7", expected: -1e7 }, + ])( + "should return a number when given a string if valid", + ({ input, expected }) => { + // arrange + // act + const result = numberValidation.validateNumber(input); + + // assert + expect(result).toBe(expected); + } + ); + + it("should throw an error if input is not a number", () => { + // arrange + const input = "a"; + + // act + const act = () => numberValidation.validateNumber(input); + + // assert + expect(act).toThrow("Input must be a number"); + }); + }); + + describe("validateInteger", () => { + it.each([ + { input: "0", expected: 0 }, + { input: "1", expected: 1 }, + { input: "-1", expected: -1 }, + { input: "1e3", expected: 1e3 }, + ])( + "should return an integer when given a string if valid", + ({ input, expected }) => { + // arrange + // act + const result = numberValidation.validateInteger(input); + + // assert + expect(result).toBe(expected); + } + ); + + it.each([ + { input: "1.67", expected: "Input must be an integer" }, + { input: "-1.67", expected: "Input must be an integer" }, + { input: "1e-3", expected: "Input must be an integer" }, + ])( + "should throw an error if input is not an integer", + ({ input, expected }) => { + // arrange + // act + const act = () => numberValidation.validateInteger(input); + + // assert + expect(act).toThrow(expected); + } + ); + }); + + describe("validatePositive", () => { + it.each([ + { input: "0", expected: 0 }, + { input: "1", expected: 1 }, + { input: "1.67", expected: 1.67 }, + { input: "1e3", expected: 1e3 }, + ])( + "should return a positive number when given a string if valid", + ({ input, expected }) => { + // arrange + // act + const result = numberValidation.validatePositive(input); + + // assert + expect(result).toBe(expected); + } + ); + + it.each([ + { input: "-1", expected: "Input must be positive" }, + { input: "-1.67", expected: "Input must be positive" }, + { input: "-1e3", expected: "Input must be positive" }, + ])( + "should throw an error if input is not positive", + ({ input, expected }) => { + // arrange + // act + const act = () => numberValidation.validatePositive(input); + + // assert + expect(act).toThrow(expected); + } + ); + }); +}); diff --git a/src/exercises/validation/number/index.ts b/src/exercises/validation/number/index.ts new file mode 100644 index 0000000..dce6fbc --- /dev/null +++ b/src/exercises/validation/number/index.ts @@ -0,0 +1,34 @@ +import { singleton } from "tsyringe"; + +@singleton() +export class NumberValidation { + public validateNumber(input: string): number { + const number = Number(input); + + if (isNaN(number)) { + throw new Error("Input must be a number"); + } + + return number; + } + + public validateInteger(input: string): number { + const number = this.validateNumber(input); + + if (!Number.isInteger(number)) { + throw new Error("Input must be an integer"); + } + + return number; + } + + public validatePositive(input: string): number { + const number = this.validateNumber(input); + + if (number < 0) { + throw new Error("Input must be positive"); + } + + return number; + } +}