Compare commits
11 Commits
97522013f3
...
main
Author | SHA1 | Date | |
---|---|---|---|
5ca2e7a358 | |||
4df48587df | |||
5573b6d6a5 | |||
e092272bd4 | |||
a17920df41 | |||
eb3de77bd9 | |||
08351ec94f | |||
1ab49d8b08 | |||
98edde4a8f | |||
e61ce661f5 | |||
b47e3608b5 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -5,3 +5,7 @@ package-lock.json
|
||||
.idea/inspectionProfiles/
|
||||
|
||||
.idea/
|
||||
|
||||
.vscode/
|
||||
|
||||
coverage/
|
||||
|
43
.vscode/launch.json
vendored
43
.vscode/launch.json
vendored
@ -1,43 +0,0 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Start app",
|
||||
"request": "launch",
|
||||
"runtimeArgs": ["run-script", "start"],
|
||||
"runtimeExecutable": "npm",
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"type": "node",
|
||||
"sourceMaps": true,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "Debug app",
|
||||
"request": "launch",
|
||||
"runtimeArgs": ["run-script", "dev", "debug"],
|
||||
"runtimeExecutable": "npm",
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"type": "node",
|
||||
"sourceMaps": true,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Jest All",
|
||||
"program": "${workspaceFolder}/node_modules/.bin/jest",
|
||||
"args": ["--runInBand"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Jest Current File",
|
||||
"program": "${workspaceFolder}/node_modules/.bin/jest",
|
||||
"args": ["${fileBasenameNoExtension}", "--config", "jest.config.js"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
}
|
||||
]
|
||||
}
|
@ -1 +1,2 @@
|
||||
# unit-test-template-typescript
|
||||
# Méthodologies de tests et tests unitaires
|
||||
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
21
src/exercises/DoubleToUnique/index.test.ts
Normal file
21
src/exercises/DoubleToUnique/index.test.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import {removeDuplicates} from "./index";
|
||||
|
||||
describe("Test removeDuplicates", () => {
|
||||
it.each([
|
||||
{ arr: [3, 2, 4, 3, 5, 2], expected: [3, 2, 4, 5] },
|
||||
{ arr: [1, 1, 1, 1, 1], expected: [1] },
|
||||
{ arr: [1, 2, 3, 4, 5], expected: [1, 2, 3, 4, 5] }
|
||||
])(
|
||||
"should remove duplicates from array",
|
||||
({ arr, expected }) => {
|
||||
const result = removeDuplicates(arr);
|
||||
expect(result).toEqual(expected);
|
||||
console.log(`Test with array = ${arr}, expected = ${expected}, result = ${result}`);
|
||||
}
|
||||
);
|
||||
|
||||
it("should throw an exception when the array is empty", () => {
|
||||
const emptyArray: number[] = [];
|
||||
expect(() => removeDuplicates(emptyArray)).toThrowError("Le tableau est vide.");
|
||||
});
|
||||
});
|
13
src/exercises/DoubleToUnique/index.ts
Normal file
13
src/exercises/DoubleToUnique/index.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export function removeDuplicates(arr: number[]): number[] {
|
||||
if (arr.length === 0) {
|
||||
throw new Error("Le tableau est vide.");
|
||||
}
|
||||
|
||||
const uniqueArray: number[] = [];
|
||||
arr.forEach((num) => {
|
||||
if (!uniqueArray.includes(num)) {
|
||||
uniqueArray.push(num);
|
||||
}
|
||||
});
|
||||
return uniqueArray;
|
||||
}
|
29
src/exercises/TP1/AgeValidation/index.test.ts
Normal file
29
src/exercises/TP1/AgeValidation/index.test.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { AgeValidation } from "./index";
|
||||
|
||||
describe("Test AgeValidation", () => {
|
||||
const ageValidator = new AgeValidation();
|
||||
|
||||
it.each([
|
||||
{ input: "30", expected: 30 },
|
||||
{ input: "25", expected: 25 },
|
||||
{ input: "50", expected: 50 },
|
||||
])(
|
||||
"should validate age %s correctly",
|
||||
({ input, expected }) => {
|
||||
const result = ageValidator.validateAge(input);
|
||||
expect(result).toEqual(expected);
|
||||
console.log(`Test with input = ${input}, expected = ${expected}, result = ${result}`);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ input: "17", expectedErrorMsg: "L'âge doit être compris entre 18 et 130 ans" },
|
||||
{ input: "131", expectedErrorMsg: "L'âge doit être compris entre 18 et 130 ans" },
|
||||
{ input: "abc", expectedErrorMsg: "L'âge doit représenter un nombre entier positif" },
|
||||
])(
|
||||
"should throw a validation exception for invalid age %s",
|
||||
({ input, expectedErrorMsg }) => {
|
||||
expect(() => ageValidator.validateAdult(input)).toThrowError(expectedErrorMsg);
|
||||
}
|
||||
);
|
||||
});
|
40
src/exercises/TP1/AgeValidation/index.ts
Normal file
40
src/exercises/TP1/AgeValidation/index.ts
Normal file
@ -0,0 +1,40 @@
|
||||
export class AgeValidation {
|
||||
validateAge(input: string): number {
|
||||
try {
|
||||
const age = this.validateNumber(input);
|
||||
if (!Number.isInteger(age) || age < 0) {
|
||||
throw new ValidationException("L'âge doit représenter un nombre entier positif");
|
||||
}
|
||||
return age;
|
||||
} catch (error) {
|
||||
if (error instanceof ValidationException) {
|
||||
throw new ValidationException("L'âge doit représenter un nombre entier positif");
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
validateAdult(input: string): number {
|
||||
const age = this.validateAge(input);
|
||||
if (age < 18 || age > 130) {
|
||||
throw new ValidationException("L'âge doit être compris entre 18 et 130 ans");
|
||||
}
|
||||
return age;
|
||||
}
|
||||
|
||||
private validateNumber(input: string): number {
|
||||
const num = parseFloat(input);
|
||||
if (isNaN(num)) {
|
||||
throw new ValidationException('La valeur doit représenter un nombre');
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
export class ValidationException extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'ValidationException';
|
||||
}
|
||||
}
|
57
src/exercises/TP1/NumberValidation/index.test.ts
Normal file
57
src/exercises/TP1/NumberValidation/index.test.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { NumberValidation } from "./index";
|
||||
|
||||
describe("Test NumberValidation", () => {
|
||||
const numberValidator = new NumberValidation();
|
||||
|
||||
it.each([
|
||||
{ input: "123", expected: 123 },
|
||||
{ input: "123.45", expected: 123.45 },
|
||||
{ input: "-123", expected: -123 }
|
||||
])(
|
||||
"should validate number %s correctly",
|
||||
({ input, expected }) => {
|
||||
const result = numberValidator.validateNumber(input);
|
||||
expect(result).toEqual(expected);
|
||||
console.log(`Test with input = ${input}, expected = ${expected}, result = ${result}`);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ input: "123", expected: 123 },
|
||||
{ input: "-123", expected: -123 }
|
||||
])(
|
||||
"should validate integer %s correctly",
|
||||
({ input, expected }) => {
|
||||
const result = numberValidator.validateInteger(input);
|
||||
expect(result).toEqual(expected);
|
||||
console.log(`Test with input = ${input}, expected = ${expected}, result = ${result}`);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ input: "123", expected: 123 },
|
||||
{ input: "123.45", expected: 123.45 }
|
||||
])(
|
||||
"should validate positive number %s correctly",
|
||||
({ input, expected }) => {
|
||||
const result = numberValidator.validatePositive(input);
|
||||
expect(result).toEqual(expected);
|
||||
console.log(`Test with input = ${input}, expected = ${expected}, result = ${result}`);
|
||||
}
|
||||
);
|
||||
|
||||
it("should throw a validation exception when input is not a number", () => {
|
||||
const input = "abc";
|
||||
expect(() => numberValidator.validateNumber(input)).toThrowError("La valeur doit représenter un nombre");
|
||||
});
|
||||
|
||||
it("should throw a validation exception when input is not an integer", () => {
|
||||
const input = "123.45";
|
||||
expect(() => numberValidator.validateInteger(input)).toThrowError("La valeur doit représenter un nombre entier");
|
||||
});
|
||||
|
||||
it("should throw a validation exception when input is not a positive number", () => {
|
||||
const input = "-123";
|
||||
expect(() => numberValidator.validatePositive(input)).toThrowError("La valeur doit représenter un nombre positif");
|
||||
});
|
||||
});
|
32
src/exercises/TP1/NumberValidation/index.ts
Normal file
32
src/exercises/TP1/NumberValidation/index.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export class ValidationException extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'ValidationException';
|
||||
}
|
||||
}
|
||||
|
||||
export class NumberValidation {
|
||||
validateNumber(input: string): number {
|
||||
const num = parseFloat(input);
|
||||
if (isNaN(num)) {
|
||||
throw new ValidationException('La valeur doit représenter un nombre');
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
validateInteger(input: string): number {
|
||||
const num = this.validateNumber(input);
|
||||
if (!Number.isInteger(num)) {
|
||||
throw new ValidationException('La valeur doit représenter un nombre entier');
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
validatePositive(input: string): number {
|
||||
const num = this.validateNumber(input);
|
||||
if (num <= 0) {
|
||||
throw new ValidationException('La valeur doit représenter un nombre positif');
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
35
src/exercises/TP1/PhoneValidation/index.test.ts
Normal file
35
src/exercises/TP1/PhoneValidation/index.test.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { PhoneValidation } from "./index";
|
||||
|
||||
describe("Test PhoneValidation", () => {
|
||||
const phoneValidator = new PhoneValidation();
|
||||
|
||||
it.each([
|
||||
{ input: "0612345678", expected: "0612345678" },
|
||||
{ input: "07.12.34.56.78", expected: "07.12.34.56.78" },
|
||||
{ input: "04 12 34 56 78", expected: "04 12 34 56 78" },
|
||||
{ input: "08/12/34/56/78", expected: "08/12/34/56/78" }
|
||||
])(
|
||||
"should validate phone %s correctly",
|
||||
({ input, expected }) => {
|
||||
const result = phoneValidator.validatePhone(input);
|
||||
expect(result).toEqual(expected);
|
||||
console.log(`Test with input = ${input}, expected = ${expected}, result = ${result}`);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ input: "", expectedErrorMsg: "Le numéro ne peut pas être vide" },
|
||||
{ input: "123", expectedErrorMsg: "Le numéro doit contenir exactement 10 chiffres" },
|
||||
{ input: "061234567", expectedErrorMsg: "Le numéro doit contenir exactement 10 chiffres" },
|
||||
{ input: "0912345678", expectedErrorMsg: "Le numéro doit commencer par 04, 06, 07 ou 08" },
|
||||
{ input: "06.123.45.6.78", expectedErrorMsg: "Le numéro doit être composé de 5 paires de deux chiffres séparés par des points, des espaces ou des slashs" },
|
||||
{ input: "06/12/34/56", expectedErrorMsg: "Le numéro doit contenir exactement 10 chiffres" },
|
||||
{ input: "0312345678", expectedErrorMsg: "Le numéro doit commencer par 04, 06, 07 ou 08" },
|
||||
{ input: "05.12.34.56.78", expectedErrorMsg: "Le numéro doit commencer par 04, 06, 07 ou 08" }
|
||||
])(
|
||||
"should throw a validation exception for invalid phone %s",
|
||||
({ input, expectedErrorMsg }) => {
|
||||
expect(() => phoneValidator.validatePhone(input)).toThrowError(expectedErrorMsg);
|
||||
}
|
||||
);
|
||||
});
|
45
src/exercises/TP1/PhoneValidation/index.ts
Normal file
45
src/exercises/TP1/PhoneValidation/index.ts
Normal file
@ -0,0 +1,45 @@
|
||||
export class PhoneValidation {
|
||||
validatePhone(input: string): string {
|
||||
if (input.length === 0) {
|
||||
throw new ValidationException("Le numéro ne peut pas être vide");
|
||||
}
|
||||
|
||||
// digit checker
|
||||
const digitsOnly = input.replace(/[ ./]/g, '');
|
||||
if (!/^\d{10}$/.test(digitsOnly)) {
|
||||
throw new ValidationException("Le numéro doit contenir exactement 10 chiffres");
|
||||
}
|
||||
|
||||
// check number
|
||||
if (!/^(04|06|07|08)/.test(digitsOnly)) {
|
||||
throw new ValidationException("Le numéro doit commencer par 04, 06, 07 ou 08");
|
||||
}
|
||||
|
||||
// separator is '.' or '/' or ' ' and identiques
|
||||
const separators = input.match(/[ ./]/g);
|
||||
if (separators) {
|
||||
if (separators.length !== 4) {
|
||||
throw new ValidationException("Le numéro doit comporter 5 paires de chiffres séparés par des points, des espaces ou des slashs, mais pas en même temps");
|
||||
}
|
||||
|
||||
const separator = separators[0];
|
||||
if (!/^[ .\/]$/.test(separator)) {
|
||||
throw new ValidationException("Les séparateurs acceptés sont seulement des points, des espaces ou des slashs");
|
||||
}
|
||||
|
||||
const parts = input.split(separator);
|
||||
if (parts.length !== 5 || parts.some(part => part.length !== 2 || !/^\d{2}$/.test(part))) {
|
||||
throw new ValidationException("Le numéro doit être composé de 5 paires de deux chiffres séparés par des points, des espaces ou des slashs");
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
export class ValidationException extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'ValidationException';
|
||||
}
|
||||
}
|
57
src/exercises/TP2/fibo/index.test.ts
Normal file
57
src/exercises/TP2/fibo/index.test.ts
Normal file
@ -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);
|
||||
});
|
||||
});
|
5
src/exercises/TP2/fibo/index.ts
Normal file
5
src/exercises/TP2/fibo/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export function fibo(n: number): number {
|
||||
if (n <= 1) return n;
|
||||
|
||||
return fibo(n - 2) + fibo(n - 1);
|
||||
}
|
64
src/exercises/TP2/fizzbuzz/index.test.ts
Normal file
64
src/exercises/TP2/fizzbuzz/index.test.ts
Normal file
@ -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");
|
||||
}
|
||||
);
|
||||
});
|
7
src/exercises/TP2/fizzbuzz/index.ts
Normal file
7
src/exercises/TP2/fizzbuzz/index.ts
Normal file
@ -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();
|
||||
}
|
@ -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);
|
||||
});
|
||||
});
|
@ -1,10 +0,0 @@
|
||||
async function start() {
|
||||
console.log("Application starts...");
|
||||
|
||||
console.log("Application ends...");
|
||||
}
|
||||
|
||||
start();
|
||||
export function name(foo : number) : number {
|
||||
return foo + 1;
|
||||
}
|
115
src/exercises/addStringOfNumbers/index.test.ts
Normal file
115
src/exercises/addStringOfNumbers/index.test.ts
Normal file
@ -0,0 +1,115 @@
|
||||
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 },
|
||||
{ input: "1,2,5,9", expected: 17 },
|
||||
{ input: "1,-3.2,3.7,2", expected: 3.5 },
|
||||
])(
|
||||
"should add any quantity of comma separated numbers in a string",
|
||||
({ input, expected }) => {
|
||||
// arrange
|
||||
// act
|
||||
const result = addStringOfNumbers(input);
|
||||
|
||||
// assert
|
||||
expect(result).toBe(expected);
|
||||
}
|
||||
);
|
||||
|
||||
it("should throw when given a string with wrong separator", () => {
|
||||
// arrange
|
||||
const input = "-2.5;3";
|
||||
|
||||
// act
|
||||
const act = () => addStringOfNumbers(input);
|
||||
|
||||
// assert
|
||||
expect(act).toThrow("Invalid characters");
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ input: "//;\n1;2", expected: 3 },
|
||||
{ input: "//:\n-2.5:4", expected: 1.5 },
|
||||
{ input: "//;\n1;2;5;9", expected: 17 },
|
||||
])(
|
||||
"should add any quantity of numbers separated by a custom character in a string",
|
||||
({ input, expected }) => {
|
||||
// arrange
|
||||
// act
|
||||
const result = addStringOfNumbers(input);
|
||||
|
||||
// assert
|
||||
expect(result).toBe(expected);
|
||||
}
|
||||
);
|
||||
|
||||
it.each(["//.\n1.2", "//-\n-2.5-4"])(
|
||||
"should throw when the custom separator is not valid",
|
||||
(input) => {
|
||||
// arrange
|
||||
// act
|
||||
const act = () => addStringOfNumbers(input);
|
||||
|
||||
// assert
|
||||
expect(act).toThrow("Invalid custom separator");
|
||||
}
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ input: "//;;;\n1;;;2", expected: 3 },
|
||||
{ input: "//::\n-2.5::4", expected: 1.5 },
|
||||
])(
|
||||
"should add any quantity of numbers separated by a custom character in a string",
|
||||
({ input, expected }) => {
|
||||
// arrange
|
||||
// act
|
||||
const result = addStringOfNumbers(input);
|
||||
|
||||
// assert
|
||||
expect(result).toBe(expected);
|
||||
}
|
||||
);
|
||||
});
|
41
src/exercises/addStringOfNumbers/index.ts
Normal file
41
src/exercises/addStringOfNumbers/index.ts
Normal file
@ -0,0 +1,41 @@
|
||||
const defaultSeparator = ",";
|
||||
|
||||
export function addStringOfNumbers(input: string) {
|
||||
if (input === "") return 0;
|
||||
|
||||
const customSeparatorMatches = input.match(/^\/\/(.+)\n/);
|
||||
const customSeparator = customSeparatorMatches
|
||||
? customSeparatorMatches[1]
|
||||
: null;
|
||||
|
||||
const separator = customSeparator || defaultSeparator;
|
||||
const isContainingBadSeparator = /[-.]/.test(separator);
|
||||
if (isContainingBadSeparator) throw new Error("Invalid custom separator");
|
||||
|
||||
const isSeparatorMadeWithSameCharacters = !separator
|
||||
.split("")
|
||||
.some((char) => char !== separator[0]);
|
||||
if (!isSeparatorMadeWithSameCharacters)
|
||||
throw new Error("Invalid custom separator");
|
||||
|
||||
// Regex to catch any character that is not a digit, dot, minus sign or separator
|
||||
const badCharactersRegex = new RegExp(`[^-.\\d${separator}]`);
|
||||
|
||||
const focusedExpression = customSeparator ? input.split("\n")[1] : input;
|
||||
const isContainingBadCharacters = badCharactersRegex.test(focusedExpression);
|
||||
if (isContainingBadCharacters) throw new Error("Invalid characters");
|
||||
|
||||
if (!focusedExpression.includes(separator)) {
|
||||
const num = Number(focusedExpression);
|
||||
if (isNaN(num)) throw new Error("Not valid number");
|
||||
return num;
|
||||
}
|
||||
|
||||
const arr = focusedExpression.split(separator);
|
||||
return arr.reduce((acc, str) => {
|
||||
const num = Number(str);
|
||||
if (isNaN(num)) throw new Error("Not valid numbers");
|
||||
|
||||
return acc + num;
|
||||
}, 0);
|
||||
}
|
19
src/exercises/convertToLowercase/index.test.ts
Normal file
19
src/exercises/convertToLowercase/index.test.ts
Normal file
@ -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);
|
||||
}
|
||||
);
|
||||
});
|
3
src/exercises/convertToLowercase/index.ts
Normal file
3
src/exercises/convertToLowercase/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function convertToLowercase(input: string): string {
|
||||
return input.toLowerCase();
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { divide } from "./index";
|
||||
|
||||
describe("Test divide", () => {
|
||||
describe("Test hexToDecimal", () => {
|
||||
it.each([
|
||||
{ a: 2, b: 1, expected: 2 },
|
||||
{ a: 10, b: 2, expected: 5 },
|
||||
|
37
src/exercises/isBeforeNow/index.test.ts
Normal file
37
src/exercises/isBeforeNow/index.test.ts
Normal file
@ -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);
|
||||
});
|
||||
});
|
3
src/exercises/isBeforeNow/index.ts
Normal file
3
src/exercises/isBeforeNow/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function isBeforeNow(date: Date): boolean {
|
||||
return date.getTime() < Date.now();
|
||||
}
|
18
src/exercises/mockMathPow/index.test.ts
Normal file
18
src/exercises/mockMathPow/index.test.ts
Normal file
@ -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);
|
||||
});
|
||||
});
|
3
src/exercises/mockMathPow/index.ts
Normal file
3
src/exercises/mockMathPow/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function square(value: number): number {
|
||||
return Math.pow(value, 2);
|
||||
}
|
18
src/exercises/mockStringUppercase/index.test.ts
Normal file
18
src/exercises/mockStringUppercase/index.test.ts
Normal file
@ -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");
|
||||
});
|
||||
});
|
3
src/exercises/mockStringUppercase/index.ts
Normal file
3
src/exercises/mockStringUppercase/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function toUpperCase(value: string): string {
|
||||
return value.toUpperCase();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import {multiply} from "./index";
|
||||
import { multiply, multiplyArrays } from "./index";
|
||||
|
||||
describe("Test multiply", () => {
|
||||
it.each([
|
||||
@ -19,3 +19,16 @@ describe("Test multiply", () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('multiplyArrays', () => {
|
||||
test('multiplie les éléments de deux tableaux de même taille', () => {
|
||||
expect(multiplyArrays([3, 5, 2], [4, 3, 1])).toEqual([12, 15, 2]);
|
||||
});
|
||||
|
||||
test('lève une exception si les tableaux ne sont pas de même taille', () => {
|
||||
expect(() => multiplyArrays([1, 2, 3], [4, 5])).toThrowError('Les tableaux ne sont pas de même taille.');
|
||||
});
|
||||
|
||||
test('lève une exception si les tableaux sont vides', () => {
|
||||
expect(() => multiplyArrays([], [])).toThrowError('Les tableaux sont vides.');
|
||||
});
|
||||
});
|
@ -1,11 +1,22 @@
|
||||
async function start() {
|
||||
console.log("Application starts...");
|
||||
|
||||
console.log("Application ends...");
|
||||
}
|
||||
|
||||
start();
|
||||
|
||||
export function multiply (a : number, b : number) : number {
|
||||
return a*b;
|
||||
}
|
||||
|
||||
export function multiplyArrays(arr1: number[], arr2: number[]): number[] {
|
||||
// Vérifier si les tableaux sont vides
|
||||
if (arr1.length === 0 || arr2.length === 0) {
|
||||
throw new Error("Les tableaux sont vides.");
|
||||
}
|
||||
|
||||
// Vérifier si les tableaux ont la même taille
|
||||
if (arr1.length !== arr2.length) {
|
||||
throw new Error("Les tableaux ne sont pas de même taille.");
|
||||
}
|
||||
|
||||
// Multiplier les éléments des tableaux
|
||||
const result: number[] = [];
|
||||
for (let i = 0; i < arr1.length; i++) {
|
||||
result.push(arr1[i] * arr2[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
47
src/exercises/multiplyArrays/index.test.ts
Normal file
47
src/exercises/multiplyArrays/index.test.ts
Normal file
@ -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");
|
||||
});
|
||||
});
|
16
src/exercises/multiplyArrays/index.ts
Normal file
16
src/exercises/multiplyArrays/index.ts
Normal file
@ -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;
|
||||
}
|
44
src/exercises/multiplyArrays2/index.test.ts
Normal file
44
src/exercises/multiplyArrays2/index.test.ts
Normal file
@ -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");
|
||||
});
|
||||
});
|
10
src/exercises/multiplyArrays2/index.ts
Normal file
10
src/exercises/multiplyArrays2/index.ts
Normal file
@ -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]);
|
||||
}
|
14
src/exercises/removeDuplicates/index.test.ts
Normal file
14
src/exercises/removeDuplicates/index.test.ts
Normal file
@ -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]);
|
||||
});
|
||||
});
|
3
src/exercises/removeDuplicates/index.ts
Normal file
3
src/exercises/removeDuplicates/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function removeDuplicates(a: number[]): number[] {
|
||||
return Array.from(new Set(a));
|
||||
}
|
14
src/exercises/removeDuplicates2/index.test.ts
Normal file
14
src/exercises/removeDuplicates2/index.test.ts
Normal file
@ -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]);
|
||||
});
|
||||
});
|
3
src/exercises/removeDuplicates2/index.ts
Normal file
3
src/exercises/removeDuplicates2/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function removeDuplicates(arr: number[]): number[] {
|
||||
return Array.from(new Set(arr));
|
||||
}
|
14
src/exercises/testAnException/index.test.ts
Normal file
14
src/exercises/testAnException/index.test.ts
Normal file
@ -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");
|
||||
});
|
||||
});
|
3
src/exercises/testAnException/index.ts
Normal file
3
src/exercises/testAnException/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function throwAnException(): void {
|
||||
throw new Error("I am an exception");
|
||||
}
|
37
src/exercises/validation/age/index.test.ts
Normal file
37
src/exercises/validation/age/index.test.ts
Normal file
@ -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);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
18
src/exercises/validation/age/index.ts
Normal file
18
src/exercises/validation/age/index.ts
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
109
src/exercises/validation/number/index.test.ts
Normal file
109
src/exercises/validation/number/index.test.ts
Normal file
@ -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);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
34
src/exercises/validation/number/index.ts
Normal file
34
src/exercises/validation/number/index.ts
Normal file
@ -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;
|
||||
}
|
||||
}
|
31
src/note/HexColorToDecimal/index.test.ts
Normal file
31
src/note/HexColorToDecimal/index.test.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import {hexToRgb} from "./index"
|
||||
|
||||
describe("hexToRgb", () => {
|
||||
it.each([
|
||||
{ hex: '#BD3F0A', expected: 'rgb(189,63,10)' },
|
||||
{ hex: '#A3BF7E', expected: 'rgb(163,191,126)' },
|
||||
])(
|
||||
"should convert $hex to $expected",
|
||||
({ hex, expected }: { hex: string, expected: string }) => {
|
||||
// act
|
||||
const result = hexToRgb(hex);
|
||||
// assert
|
||||
expect(result).toEqual(expected);
|
||||
console.log(`Test with hex = ${hex}, expected = ${expected}, result = ${result}`);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ hex: '', expectedErrorMsg: "Couleur hexadécimale invalide, ne doit pas être vide" },
|
||||
{ hex: 'BD3F0A', expectedErrorMsg: "Couleur hexadécimale invalide, doit commencer par #" },
|
||||
{ hex: '#', expectedErrorMsg: "Couleur hexadécimale invalide, doit contenir 6 caractères" },
|
||||
{ hex: '#12345', expectedErrorMsg: "Couleur hexadécimale invalide, doit contenir 6 caractères" },
|
||||
{ hex: '#GHIJKL', expectedErrorMsg: "Couleur hexadécimale invalide, caractères invalides" },
|
||||
])(
|
||||
"should throw an error for invalid hex $hex",
|
||||
({ hex, expectedErrorMsg }: { hex: string, expectedErrorMsg: string }) => {
|
||||
// assert
|
||||
expect(() => hexToRgb(hex)).toThrow(expectedErrorMsg);
|
||||
}
|
||||
);
|
||||
});
|
28
src/note/HexColorToDecimal/index.ts
Normal file
28
src/note/HexColorToDecimal/index.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import {parse} from "../hexToDecimal"
|
||||
|
||||
export function hexToRgb(hex: string): string {
|
||||
if (hex === "") {
|
||||
throw new Error("Couleur hexadécimale invalide, ne doit pas être vide");
|
||||
}
|
||||
|
||||
if (!hex.startsWith("#")) {
|
||||
throw new Error("Couleur hexadécimale invalide, doit commencer par #");
|
||||
}
|
||||
|
||||
hex = hex.slice(1);
|
||||
|
||||
if (hex.length !== 6) {
|
||||
throw new Error("Couleur hexadécimale invalide, doit contenir 6 caractères");
|
||||
}
|
||||
|
||||
if (!/^[0-9A-F]{6}$/.test(hex.toUpperCase())) {
|
||||
throw new Error("Couleur hexadécimale invalide, caractères invalides");
|
||||
}
|
||||
|
||||
const r: number = parse(hex.slice(0, 2));
|
||||
const g: number = parse(hex.slice(2, 4));
|
||||
const b: number = parse(hex.slice(4, 6));
|
||||
|
||||
|
||||
return `rgb(${r},${g},${b})`;
|
||||
}
|
35
src/note/hexToDecimal/index.test.ts
Normal file
35
src/note/hexToDecimal/index.test.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import {parse} from "./index"
|
||||
|
||||
describe("parse", () => {
|
||||
it.each([
|
||||
{a: 'CE', expected: 206},
|
||||
{a: '9B', expected: 155},
|
||||
{a: 'E6', expected: 230},
|
||||
{a: '25', expected: 37},
|
||||
])(
|
||||
"should return conversion of $a hex value to decimal value",
|
||||
({a, expected}: { a: string, expected: number }) => {
|
||||
// act
|
||||
const result = parse(a);
|
||||
// assert
|
||||
expect(result).toEqual(expected);
|
||||
console.log(`Test with a = ${a}, expected = ${expected}, result = ${result}`);
|
||||
}
|
||||
);
|
||||
|
||||
it("should throw an error for empty string", () => {
|
||||
expect(() => parse("")).toThrow("Teinte hexadécimale invalide, teinte vide");
|
||||
});
|
||||
|
||||
it("should throw an error for invalid length", () => {
|
||||
expect(() => parse("B")).toThrow("Teinte hexadécimale invalide, la teinte doit contenir 2 caractères");
|
||||
expect(() => parse("2BC")).toThrow("Teinte hexadécimale invalide, la teinte doit contenir 2 caractères");
|
||||
});
|
||||
|
||||
it("should throw an error for invalid characters", () => {
|
||||
expect(() => parse("-G")).toThrow("Teinte hexadécimale invalide, caractère non valide");
|
||||
expect(() => parse("1.")).toThrow("Teinte hexadécimale invalide, caractère non valide");
|
||||
expect(() => parse("G0")).toThrow("Teinte hexadécimale invalide, caractère non valide");
|
||||
expect(() => parse("0G")).toThrow("Teinte hexadécimale invalide, caractère non valide");
|
||||
});
|
||||
});
|
22
src/note/hexToDecimal/index.ts
Normal file
22
src/note/hexToDecimal/index.ts
Normal file
@ -0,0 +1,22 @@
|
||||
export function parse(a: string): number {
|
||||
const alphabet: string = "0123456789ABCDEF";
|
||||
|
||||
if (a === "") {
|
||||
throw new Error("Teinte hexadécimale invalide, teinte vide");
|
||||
}
|
||||
|
||||
if (a.length !== 2) {
|
||||
throw new Error("Teinte hexadécimale invalide, la teinte doit contenir 2 caractères");
|
||||
}
|
||||
|
||||
const hexToDecimal = (char: string): number => {
|
||||
const value = alphabet.indexOf(char.toUpperCase());
|
||||
if (value == -1) {
|
||||
throw new Error(" Teinte hexadécimale invalide, caractère non valide");
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
return hexToDecimal(a[0]) * 16 + hexToDecimal(a[1]);
|
||||
}
|
Reference in New Issue
Block a user