From 80bfc316a9b2019f0c0c9db20550b54110cccba9 Mon Sep 17 00:00:00 2001 From: Nikita Ovchinnikov Date: Mon, 6 Apr 2020 00:42:17 +0300 Subject: [PATCH 1/5] Add lesson 2 with simple console calc --- README.md | 18 ++++++++++++ package-lock.json | 37 ++++++++++++++++++++++++ package.json | 9 ++++-- src/lesson2/engine.test.ts | 21 ++++++++++++++ src/lesson2/engine.ts | 48 +++++++++++++++++++++++++++++++ src/lesson2/helpers.ts | 1 + src/lesson2/index.ts | 29 +++++++++++++++++++ src/lesson2/mathOperators.test.ts | 25 ++++++++++++++++ src/lesson2/mathOperators.ts | 42 +++++++++++++++++++++++++++ src/lesson2/parser.test.ts | 21 ++++++++++++++ src/lesson2/parser.ts | 29 +++++++++++++++++++ src/lesson2/runner.test.ts | 29 +++++++++++++++++++ src/lesson2/runner.ts | 19 ++++++++++++ 13 files changed, 325 insertions(+), 3 deletions(-) create mode 100644 src/lesson2/engine.test.ts create mode 100644 src/lesson2/engine.ts create mode 100644 src/lesson2/helpers.ts create mode 100644 src/lesson2/index.ts create mode 100644 src/lesson2/mathOperators.test.ts create mode 100644 src/lesson2/mathOperators.ts create mode 100644 src/lesson2/parser.test.ts create mode 100644 src/lesson2/parser.ts create mode 100644 src/lesson2/runner.test.ts create mode 100644 src/lesson2/runner.ts diff --git a/README.md b/README.md index 4283f329..ce862cd5 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,21 @@ Basic configuration for the project on the master branch. What configurations yo * Eslint * Jest * Precommit hooks / husky + +## Lesson 2: +Math calculator with basic arithmetic operations without eval + +```npm run calc``` + +Then you can calc simple math operations + +Examples: + +``` +> 10 + 10 +Result: 20 +> 10 + 10 * 20 - 30 +Result: 180 +> 19 + -10 +Result: 9 +``` \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c6a6386b..8b7c6121 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2145,6 +2145,12 @@ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -4314,6 +4320,12 @@ "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", "dev": true }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, "diff-sequences": { "version": "25.2.1", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.1.tgz", @@ -8574,6 +8586,12 @@ } } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "makeerror": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", @@ -11761,6 +11779,19 @@ "punycode": "^2.1.0" } }, + "ts-node": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.8.2.tgz", + "integrity": "sha512-duVj6BpSpUpD/oM4MfhO98ozgkp3Gt9qIp3jGxwU2DFvl/3IRaEAvbLa8G60uS7C77457e/m5TMowjedeRxI1Q==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "3.1.1" + } + }, "tslib": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", @@ -13039,6 +13070,12 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/package.json b/package.json index 81b3d1bb..e9c23573 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,15 @@ "main": "index.js", "scripts": { "build": "npx webpack --mode production", + "calc": "npx ts-node src/lesson2", "lint": "npx eslint --ext .js,.jsx,.ts,.tsx --fix ./", - "test": "npx jest" + "test": "npx jest", + "check": "npm test && npm run lint" }, "husky": { "hooks": { - "pre-commit": "npm test && npm run lint", - "pre-push": "npm test && npm run lint" + "pre-commit": "npm run check", + "pre-push": "npm run check" } }, "repository": { @@ -40,6 +42,7 @@ "husky": "^4.2.3", "jest": "^25.2.4", "prettier": "^2.0.2", + "ts-node": "^8.8.2", "typescript": "^3.8.3", "webpack": "^4.42.1", "webpack-cli": "^3.3.11", diff --git a/src/lesson2/engine.test.ts b/src/lesson2/engine.test.ts new file mode 100644 index 00000000..2d49b359 --- /dev/null +++ b/src/lesson2/engine.test.ts @@ -0,0 +1,21 @@ +import { firstPrioritiesCalc, secondPrioritiesCalc } from "./engine"; + +test("firstPrioritiesCalc: [1, * 32]", () => { + expect(firstPrioritiesCalc([1, "*", 32])).toEqual([32]); +}); + +test("firstPrioritiesCalc: [32, / 32]", () => { + expect(firstPrioritiesCalc([32, "/", 32])).toEqual([1]); +}); + +test("firstPrioritiesCalc: [32, + 32]", () => { + expect(firstPrioritiesCalc([32, "+", 32])).toEqual([32, "+", 32]); +}); + +test("secondPrioritiesCalc: [32, + 32]", () => { + expect(secondPrioritiesCalc([32, "+", 32])).toEqual(64); +}); + +test("secondPrioritiesCalc: [32, - 32]", () => { + expect(secondPrioritiesCalc([32, "-", 32])).toEqual(0); +}); diff --git a/src/lesson2/engine.ts b/src/lesson2/engine.ts new file mode 100644 index 00000000..1f3623af --- /dev/null +++ b/src/lesson2/engine.ts @@ -0,0 +1,48 @@ +import { ParsedLineType } from "./parser"; +import { isNumber } from "./helpers"; +import { + mathOperators, + mathPriorities, + mathOperatorsPriorities, +} from "./mathOperators"; + +const { FIRST, SECOND } = mathPriorities; + +export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => { + let result: ParsedLineType = []; + + for (let key = 0; key < stack.length; key++) { + const prevItem = result[result.length - 2]; + const item = result[result.length - 1]; + const nextItem = stack[key]; + + if (!isNumber(String(item)) && mathOperatorsPriorities[item] === FIRST) { + result = [ + ...result.slice(0, -2), + mathOperators[item](Number(prevItem), Number(nextItem)), + ]; + } else { + result.push(nextItem); + } + } + + return result; +}; + +export const secondPrioritiesCalc = (stack: ParsedLineType): number => { + let result = 0; + for (let key = 0; key < stack.length; key++) { + if (key === 0) { + result = Number(stack[key]); + } + + const prevItem = result; + const item = stack[key - 1]; + const nextItem = stack[key]; + + if (!isNumber(String(item)) && mathOperatorsPriorities[item] === SECOND) { + result = mathOperators[item](Number(prevItem), Number(nextItem)); + } + } + return result; +}; diff --git a/src/lesson2/helpers.ts b/src/lesson2/helpers.ts new file mode 100644 index 00000000..b5a4b6ae --- /dev/null +++ b/src/lesson2/helpers.ts @@ -0,0 +1 @@ +export const isNumber = (item: string): boolean => !isNaN(Number(item)); diff --git a/src/lesson2/index.ts b/src/lesson2/index.ts new file mode 100644 index 00000000..1766cf85 --- /dev/null +++ b/src/lesson2/index.ts @@ -0,0 +1,29 @@ +import { createInterface } from "readline"; + +import { runner } from "./runner"; + +const rl = createInterface({ + input: process.stdin, + output: process.stdout, +}); + +const question = (): Promise => + new Promise((resolve) => { + rl.question("> ", (answer: string) => { + const result = runner(answer); + + if (result) { + console.log(`Result: ${result}`); + } + + resolve(); + }); + }); + +async function app(): Promise { + while (true) { + await question(); + } +} + +app(); diff --git a/src/lesson2/mathOperators.test.ts b/src/lesson2/mathOperators.test.ts new file mode 100644 index 00000000..e9b86a67 --- /dev/null +++ b/src/lesson2/mathOperators.test.ts @@ -0,0 +1,25 @@ +import { mul, div, add, minus } from "./mathOperators"; + +test("mul 1 * 2 to equal 2", () => { + expect(mul(1, 2)).toBe(2); +}); + +test("mul 2 * 2 to equal 4", () => { + expect(mul(2, 2)).toBe(4); +}); + +test("div 2 / 2 to equal 1", () => { + expect(div(2, 2)).toBe(1); +}); + +test("div 4 / 2 to equal 2", () => { + expect(div(4, 2)).toBe(2); +}); + +test("add 4 + 2 to equal 6", () => { + expect(add(4, 2)).toBe(6); +}); + +test("minus 4 - 2 to equal 2", () => { + expect(minus(4, 2)).toBe(2); +}); diff --git a/src/lesson2/mathOperators.ts b/src/lesson2/mathOperators.ts new file mode 100644 index 00000000..5b8d0dac --- /dev/null +++ b/src/lesson2/mathOperators.ts @@ -0,0 +1,42 @@ +export type ScalarOperationType = (first: number, second: number) => number; + +export const mul: ScalarOperationType = ( + first: number, + second: number +): number => first * second; + +export const div: ScalarOperationType = ( + first: number, + second: number +): number => first / second; + +export const add: ScalarOperationType = ( + first: number, + second: number +): number => first + second; + +export const minus: ScalarOperationType = ( + first: number, + second: number +): number => first - second; + +export const mathOperators: { [key: string]: ScalarOperationType } = { + "*": mul, + "/": div, + "+": add, + "-": minus, +}; + +export const mathPriorities: { [key: string]: number } = { + FIRST: 1, + SECOND: 2, +}; + +const { FIRST, SECOND } = mathPriorities; + +export const mathOperatorsPriorities: { [key: string]: number } = { + "*": FIRST, + "/": FIRST, + "+": SECOND, + "-": SECOND, +}; diff --git a/src/lesson2/parser.test.ts b/src/lesson2/parser.test.ts new file mode 100644 index 00000000..8788cc15 --- /dev/null +++ b/src/lesson2/parser.test.ts @@ -0,0 +1,21 @@ +import { parser } from "./parser"; + +test("parser: 1 + 32", () => { + expect(parser("1 + 32")).toEqual([1, "+", 32]); +}); + +test("parser: 11 + 3 * 22", () => { + expect(parser("11 + 3 * 22")).toEqual([11, "+", 3, "*", 22]); +}); + +test("parser: 1 + 32 - 2 + 2", () => { + expect(parser("1 + 32 - 2 + 2")).toEqual([1, "+", 32, "-", 2, "+", 2]); +}); + +test("parser: 1 + + 33 - 2", () => { + expect(() => parser("1 + + 33 - 2")).toThrow(TypeError("Unexpected string")); +}); + +test("parser: 1 ! 33 - 2", () => { + expect(() => parser("1 ! 33 - 2")).toThrow(TypeError("Unexpected string")); +}); diff --git a/src/lesson2/parser.ts b/src/lesson2/parser.ts new file mode 100644 index 00000000..62f793c6 --- /dev/null +++ b/src/lesson2/parser.ts @@ -0,0 +1,29 @@ +import { isNumber } from "./helpers"; +import { mathOperators } from "./mathOperators"; + +export type ParsedLineType = Array; + +export const parser = (line: string): ParsedLineType | null => { + const result = []; + const stack = line.split(" "); + + for (let key = 0; key < stack.length; key++) { + const prevItem = stack[key - 1]; + const item = stack[key]; + + const isValidNumberPush = !isNumber(prevItem) && isNumber(item); + const isValidOperatorPush = + isNumber(prevItem) && + !isNumber(item) && + mathOperators.hasOwnProperty(item); + + if (isValidNumberPush) { + result.push(Number(item)); + } else if (isValidOperatorPush) { + result.push(item); + } else { + throw new TypeError("Unexpected string"); + } + } + return result; +}; diff --git a/src/lesson2/runner.test.ts b/src/lesson2/runner.test.ts new file mode 100644 index 00000000..c2906b89 --- /dev/null +++ b/src/lesson2/runner.test.ts @@ -0,0 +1,29 @@ +import { runner } from "./runner"; + +test("runner: 1 * 32", () => { + expect(runner("1 * 32")).toEqual(32); +}); + +test("runner: 2 * 32", () => { + expect(runner("2 * 32")).toEqual(64); +}); + +test("runner: 2 * 2 * 3", () => { + expect(runner("2 * 2 * 3")).toEqual(12); +}); + +test("runner: 2 * 2 + 3", () => { + expect(runner("2 * 2 + 3")).toEqual(7); +}); + +test("runner: 2 + 2 * 3", () => { + expect(runner("2 + 2 * 3")).toEqual(8); +}); + +test("runner: 20 + 1 * 10 - 5 * 3", () => { + expect(runner("20 + 1 * 10 - 5 * 3")).toEqual(15); +}); + +test("runner: 20 - 10 * 10 / 5 - 3", () => { + expect(runner("20 - 10 * 10 / 5 - 3")).toEqual(-3); +}); diff --git a/src/lesson2/runner.ts b/src/lesson2/runner.ts new file mode 100644 index 00000000..920249fd --- /dev/null +++ b/src/lesson2/runner.ts @@ -0,0 +1,19 @@ +import { parser } from "./parser"; + +import { firstPrioritiesCalc, secondPrioritiesCalc } from "./engine"; + +export const runner = (line: string): number => { + const stack = parser(line); + + if (stack === null) { + throw new TypeError("Unexpected string"); + } + + const firstPrioritiesRes = firstPrioritiesCalc(stack); + + if (firstPrioritiesRes.length === 1) { + return Number(firstPrioritiesRes[0]); + } + + return secondPrioritiesCalc(firstPrioritiesRes); +}; From e619189cc576703424dc6fbc086d03e106a4adfa Mon Sep 17 00:00:00 2001 From: Nikita Ovchinnikov Date: Mon, 6 Apr 2020 01:02:25 +0300 Subject: [PATCH 2/5] FIx - reduce instead of for --- src/lesson2/engine.ts | 28 ++++++++-------------------- src/lesson2/parser.ts | 8 +++----- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/src/lesson2/engine.ts b/src/lesson2/engine.ts index 1f3623af..74b662cc 100644 --- a/src/lesson2/engine.ts +++ b/src/lesson2/engine.ts @@ -8,13 +8,10 @@ import { const { FIRST, SECOND } = mathPriorities; -export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => { - let result: ParsedLineType = []; - - for (let key = 0; key < stack.length; key++) { +export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => + stack.reduce((result, nextItem) => { const prevItem = result[result.length - 2]; const item = result[result.length - 1]; - const nextItem = stack[key]; if (!isNumber(String(item)) && mathOperatorsPriorities[item] === FIRST) { result = [ @@ -24,25 +21,16 @@ export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => { } else { result.push(nextItem); } - } - - return result; -}; - -export const secondPrioritiesCalc = (stack: ParsedLineType): number => { - let result = 0; - for (let key = 0; key < stack.length; key++) { - if (key === 0) { - result = Number(stack[key]); - } + return result; + }, []); +export const secondPrioritiesCalc = (stack: ParsedLineType): number => + stack.reduce((result, nextItem, key) => { const prevItem = result; const item = stack[key - 1]; - const nextItem = stack[key]; if (!isNumber(String(item)) && mathOperatorsPriorities[item] === SECOND) { result = mathOperators[item](Number(prevItem), Number(nextItem)); } - } - return result; -}; + return result; + }, Number(stack[0])); diff --git a/src/lesson2/parser.ts b/src/lesson2/parser.ts index 62f793c6..726a563f 100644 --- a/src/lesson2/parser.ts +++ b/src/lesson2/parser.ts @@ -4,12 +4,10 @@ import { mathOperators } from "./mathOperators"; export type ParsedLineType = Array; export const parser = (line: string): ParsedLineType | null => { - const result = []; const stack = line.split(" "); - for (let key = 0; key < stack.length; key++) { + return stack.reduce((result, item, key) => { const prevItem = stack[key - 1]; - const item = stack[key]; const isValidNumberPush = !isNumber(prevItem) && isNumber(item); const isValidOperatorPush = @@ -24,6 +22,6 @@ export const parser = (line: string): ParsedLineType | null => { } else { throw new TypeError("Unexpected string"); } - } - return result; + return result; + }, []); }; From e66933e33f00bf9f2be7fe2a0d8caeeb52bd0996 Mon Sep 17 00:00:00 2001 From: Nikita Ovchinnikov Date: Mon, 6 Apr 2020 09:55:29 +0300 Subject: [PATCH 3/5] Test coverage improve --- src/lesson2/engine.test.ts | 20 +++++++++++++++++++- src/lesson2/engine.ts | 7 +++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/lesson2/engine.test.ts b/src/lesson2/engine.test.ts index 2d49b359..69db95ef 100644 --- a/src/lesson2/engine.test.ts +++ b/src/lesson2/engine.test.ts @@ -4,14 +4,28 @@ test("firstPrioritiesCalc: [1, * 32]", () => { expect(firstPrioritiesCalc([1, "*", 32])).toEqual([32]); }); -test("firstPrioritiesCalc: [32, / 32]", () => { +test("firstPrioritiesCalc: [32, /, 32]", () => { expect(firstPrioritiesCalc([32, "/", 32])).toEqual([1]); }); +test("firstPrioritiesCalc: [32, /, 32, +, 10, *, 10]", () => { + expect(firstPrioritiesCalc([32, "/", 32, "+", 10, "*", 10])).toEqual([ + 1, + "+", + 100, + ]); +}); + test("firstPrioritiesCalc: [32, + 32]", () => { expect(firstPrioritiesCalc([32, "+", 32])).toEqual([32, "+", 32]); }); +test("secondPrioritiesCalc: [32, / 32]", () => { + expect(() => secondPrioritiesCalc([32, "/", 32])).toThrow( + TypeError("Unexpected stack!") + ); +}); + test("secondPrioritiesCalc: [32, + 32]", () => { expect(secondPrioritiesCalc([32, "+", 32])).toEqual(64); }); @@ -19,3 +33,7 @@ test("secondPrioritiesCalc: [32, + 32]", () => { test("secondPrioritiesCalc: [32, - 32]", () => { expect(secondPrioritiesCalc([32, "-", 32])).toEqual(0); }); + +test("secondPrioritiesCalc: [32, - 32, +, 10]", () => { + expect(secondPrioritiesCalc([32, "-", 32, "+", 10])).toEqual(10); +}); diff --git a/src/lesson2/engine.ts b/src/lesson2/engine.ts index 74b662cc..b69660cc 100644 --- a/src/lesson2/engine.ts +++ b/src/lesson2/engine.ts @@ -26,11 +26,14 @@ export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => export const secondPrioritiesCalc = (stack: ParsedLineType): number => stack.reduce((result, nextItem, key) => { - const prevItem = result; const item = stack[key - 1]; + if (mathOperatorsPriorities[item] === FIRST) { + throw new TypeError("Unexpected stack!"); + } + if (!isNumber(String(item)) && mathOperatorsPriorities[item] === SECOND) { - result = mathOperators[item](Number(prevItem), Number(nextItem)); + result = mathOperators[item](Number(result), Number(nextItem)); } return result; }, Number(stack[0])); From 219255f0049427070fdaeac61bd2f75e13d0622f Mon Sep 17 00:00:00 2001 From: Nikita Ovchinnikov Date: Mon, 6 Apr 2020 10:36:57 +0300 Subject: [PATCH 4/5] PR fixes --- src/lesson2/engine.test.ts | 80 +++++++++++++++++-------------- src/lesson2/engine.ts | 5 +- src/lesson2/mathOperators.test.ts | 36 +++++++------- src/lesson2/mathOperators.ts | 7 +-- src/lesson2/parser.test.ts | 32 ++++++++----- src/lesson2/parser.ts | 2 +- src/lesson2/runner.test.ts | 46 +++++++++++------- 7 files changed, 117 insertions(+), 91 deletions(-) diff --git a/src/lesson2/engine.test.ts b/src/lesson2/engine.test.ts index 69db95ef..291b5de3 100644 --- a/src/lesson2/engine.test.ts +++ b/src/lesson2/engine.test.ts @@ -1,39 +1,47 @@ import { firstPrioritiesCalc, secondPrioritiesCalc } from "./engine"; -test("firstPrioritiesCalc: [1, * 32]", () => { - expect(firstPrioritiesCalc([1, "*", 32])).toEqual([32]); -}); - -test("firstPrioritiesCalc: [32, /, 32]", () => { - expect(firstPrioritiesCalc([32, "/", 32])).toEqual([1]); -}); - -test("firstPrioritiesCalc: [32, /, 32, +, 10, *, 10]", () => { - expect(firstPrioritiesCalc([32, "/", 32, "+", 10, "*", 10])).toEqual([ - 1, - "+", - 100, - ]); -}); - -test("firstPrioritiesCalc: [32, + 32]", () => { - expect(firstPrioritiesCalc([32, "+", 32])).toEqual([32, "+", 32]); -}); - -test("secondPrioritiesCalc: [32, / 32]", () => { - expect(() => secondPrioritiesCalc([32, "/", 32])).toThrow( - TypeError("Unexpected stack!") - ); -}); - -test("secondPrioritiesCalc: [32, + 32]", () => { - expect(secondPrioritiesCalc([32, "+", 32])).toEqual(64); -}); - -test("secondPrioritiesCalc: [32, - 32]", () => { - expect(secondPrioritiesCalc([32, "-", 32])).toEqual(0); -}); - -test("secondPrioritiesCalc: [32, - 32, +, 10]", () => { - expect(secondPrioritiesCalc([32, "-", 32, "+", 10])).toEqual(10); +describe("firstPrioritiesCalc simple cases", () => { + it("firstPrioritiesCalc: [1, * 32]", () => { + expect(firstPrioritiesCalc([1, "*", 32])).toEqual([32]); + }); + + it("firstPrioritiesCalc: [32, /, 32]", () => { + expect(firstPrioritiesCalc([32, "/", 32])).toEqual([1]); + }); + + it("firstPrioritiesCalc: [32, + 32]", () => { + expect(firstPrioritiesCalc([32, "+", 32])).toEqual([32, "+", 32]); + }); +}); + +describe("firstPrioritiesCalc mixed with second priorities cases", () => { + it("firstPrioritiesCalc: [32, /, 32, +, 10, *, 10]", () => { + expect(firstPrioritiesCalc([32, "/", 32, "+", 10, "*", 10])).toEqual([ + 1, + "+", + 100, + ]); + }); +}); + +describe("secondPrioritiesCalc invalid cases", () => { + it("secondPrioritiesCalc: [32, / 32]", () => { + expect(() => secondPrioritiesCalc([32, "/", 32])).toThrow( + TypeError("Unexpected stack!") + ); + }); +}); + +describe("secondPrioritiesCalc simple cases", () => { + it("secondPrioritiesCalc: [32, + 32]", () => { + expect(secondPrioritiesCalc([32, "+", 32])).toEqual(64); + }); + + it("secondPrioritiesCalc: [32, - 32]", () => { + expect(secondPrioritiesCalc([32, "-", 32])).toEqual(0); + }); + + it("secondPrioritiesCalc: [32, - 32, +, 10]", () => { + expect(secondPrioritiesCalc([32, "-", 32, "+", 10])).toEqual(10); + }); }); diff --git a/src/lesson2/engine.ts b/src/lesson2/engine.ts index b69660cc..78aee1d7 100644 --- a/src/lesson2/engine.ts +++ b/src/lesson2/engine.ts @@ -6,7 +6,7 @@ import { mathOperatorsPriorities, } from "./mathOperators"; -const { FIRST, SECOND } = mathPriorities; +const [FIRST, SECOND] = mathPriorities; export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => stack.reduce((result, nextItem) => { @@ -14,6 +14,9 @@ export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => const item = result[result.length - 1]; if (!isNumber(String(item)) && mathOperatorsPriorities[item] === FIRST) { + if (!mathOperators[item]) { + throw new TypeError("Unexpected stack!"); + } result = [ ...result.slice(0, -2), mathOperators[item](Number(prevItem), Number(nextItem)), diff --git a/src/lesson2/mathOperators.test.ts b/src/lesson2/mathOperators.test.ts index e9b86a67..aad07e8d 100644 --- a/src/lesson2/mathOperators.test.ts +++ b/src/lesson2/mathOperators.test.ts @@ -1,25 +1,27 @@ import { mul, div, add, minus } from "./mathOperators"; -test("mul 1 * 2 to equal 2", () => { - expect(mul(1, 2)).toBe(2); -}); +describe("mathOperators test cases", () => { + it("mul 1 * 2 to equal 2", () => { + expect(mul(1, 2)).toBe(2); + }); -test("mul 2 * 2 to equal 4", () => { - expect(mul(2, 2)).toBe(4); -}); + it("mul 2 * 2 to equal 4", () => { + expect(mul(2, 2)).toBe(4); + }); -test("div 2 / 2 to equal 1", () => { - expect(div(2, 2)).toBe(1); -}); + it("div 2 / 2 to equal 1", () => { + expect(div(2, 2)).toBe(1); + }); -test("div 4 / 2 to equal 2", () => { - expect(div(4, 2)).toBe(2); -}); + it("div 4 / 2 to equal 2", () => { + expect(div(4, 2)).toBe(2); + }); -test("add 4 + 2 to equal 6", () => { - expect(add(4, 2)).toBe(6); -}); + it("add 4 + 2 to equal 6", () => { + expect(add(4, 2)).toBe(6); + }); -test("minus 4 - 2 to equal 2", () => { - expect(minus(4, 2)).toBe(2); + it("minus 4 - 2 to equal 2", () => { + expect(minus(4, 2)).toBe(2); + }); }); diff --git a/src/lesson2/mathOperators.ts b/src/lesson2/mathOperators.ts index 5b8d0dac..af8eb770 100644 --- a/src/lesson2/mathOperators.ts +++ b/src/lesson2/mathOperators.ts @@ -27,12 +27,9 @@ export const mathOperators: { [key: string]: ScalarOperationType } = { "-": minus, }; -export const mathPriorities: { [key: string]: number } = { - FIRST: 1, - SECOND: 2, -}; +export const mathPriorities: number[] = [1, 2]; -const { FIRST, SECOND } = mathPriorities; +const [FIRST, SECOND] = mathPriorities; export const mathOperatorsPriorities: { [key: string]: number } = { "*": FIRST, diff --git a/src/lesson2/parser.test.ts b/src/lesson2/parser.test.ts index 8788cc15..1ebfd133 100644 --- a/src/lesson2/parser.test.ts +++ b/src/lesson2/parser.test.ts @@ -1,21 +1,27 @@ import { parser } from "./parser"; -test("parser: 1 + 32", () => { - expect(parser("1 + 32")).toEqual([1, "+", 32]); -}); +describe("Parser correct cases", () => { + it("parser: 1 + 32", () => { + expect(parser("1 + 32")).toEqual([1, "+", 32]); + }); -test("parser: 11 + 3 * 22", () => { - expect(parser("11 + 3 * 22")).toEqual([11, "+", 3, "*", 22]); -}); + it("parser: 11 + 3 * 22", () => { + expect(parser("11 + 3 * 22")).toEqual([11, "+", 3, "*", 22]); + }); -test("parser: 1 + 32 - 2 + 2", () => { - expect(parser("1 + 32 - 2 + 2")).toEqual([1, "+", 32, "-", 2, "+", 2]); + it("parser: 1 + 32 - 2 + 2", () => { + expect(parser("1 + 32 - 2 + 2")).toEqual([1, "+", 32, "-", 2, "+", 2]); + }); }); -test("parser: 1 + + 33 - 2", () => { - expect(() => parser("1 + + 33 - 2")).toThrow(TypeError("Unexpected string")); -}); +describe("Parser invalid cases", () => { + it("parser: 1 + + 33 - 2", () => { + expect(() => parser("1 + + 33 - 2")).toThrow( + TypeError("Unexpected string") + ); + }); -test("parser: 1 ! 33 - 2", () => { - expect(() => parser("1 ! 33 - 2")).toThrow(TypeError("Unexpected string")); + it("parser: 1 ! 33 - 2", () => { + expect(() => parser("1 ! 33 - 2")).toThrow(TypeError("Unexpected string")); + }); }); diff --git a/src/lesson2/parser.ts b/src/lesson2/parser.ts index 726a563f..118ff662 100644 --- a/src/lesson2/parser.ts +++ b/src/lesson2/parser.ts @@ -1,7 +1,7 @@ import { isNumber } from "./helpers"; import { mathOperators } from "./mathOperators"; -export type ParsedLineType = Array; +export type ParsedLineType = (number | string)[]; export const parser = (line: string): ParsedLineType | null => { const stack = line.split(" "); diff --git a/src/lesson2/runner.test.ts b/src/lesson2/runner.test.ts index c2906b89..eadb9143 100644 --- a/src/lesson2/runner.test.ts +++ b/src/lesson2/runner.test.ts @@ -1,29 +1,39 @@ import { runner } from "./runner"; -test("runner: 1 * 32", () => { - expect(runner("1 * 32")).toEqual(32); -}); +describe("Runner simple cases", () => { + it("runner: 1 * 32", () => { + expect(runner("1 * 32")).toEqual(32); + }); -test("runner: 2 * 32", () => { - expect(runner("2 * 32")).toEqual(64); -}); + it("runner: 2 * 32", () => { + expect(runner("2 * 32")).toEqual(64); + }); -test("runner: 2 * 2 * 3", () => { - expect(runner("2 * 2 * 3")).toEqual(12); + it("runner: 2 + 32", () => { + expect(runner("2 + 32")).toEqual(34); + }); }); -test("runner: 2 * 2 + 3", () => { - expect(runner("2 * 2 + 3")).toEqual(7); -}); +describe("Runner tripled/mixed cases", () => { + it("runner: 2 * 2 * 3", () => { + expect(runner("2 * 2 * 3")).toEqual(12); + }); -test("runner: 2 + 2 * 3", () => { - expect(runner("2 + 2 * 3")).toEqual(8); -}); + it("runner: 2 * 2 + 3", () => { + expect(runner("2 * 2 + 3")).toEqual(7); + }); -test("runner: 20 + 1 * 10 - 5 * 3", () => { - expect(runner("20 + 1 * 10 - 5 * 3")).toEqual(15); + it("runner: 2 + 2 * 3", () => { + expect(runner("2 + 2 * 3")).toEqual(8); + }); }); -test("runner: 20 - 10 * 10 / 5 - 3", () => { - expect(runner("20 - 10 * 10 / 5 - 3")).toEqual(-3); +describe("Runner long cases", () => { + it("runner: 20 + 1 * 10 - 5 * 3", () => { + expect(runner("20 + 1 * 10 - 5 * 3")).toEqual(15); + }); + + it("runner: 20 - 10 * 10 / 5 - 3", () => { + expect(runner("20 - 10 * 10 / 5 - 3")).toEqual(-3); + }); }); From e82852c3efcf602c33afc97faa6ddd7a68919b47 Mon Sep 17 00:00:00 2001 From: Nikita Ovchinnikov Date: Mon, 6 Apr 2020 10:45:54 +0300 Subject: [PATCH 5/5] Test cases description fix --- src/lesson2/engine.test.ts | 16 ++++++++-------- src/lesson2/parser.test.ts | 10 +++++----- src/lesson2/runner.test.ts | 16 ++++++++-------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/lesson2/engine.test.ts b/src/lesson2/engine.test.ts index 291b5de3..eae1cc00 100644 --- a/src/lesson2/engine.test.ts +++ b/src/lesson2/engine.test.ts @@ -1,21 +1,21 @@ import { firstPrioritiesCalc, secondPrioritiesCalc } from "./engine"; describe("firstPrioritiesCalc simple cases", () => { - it("firstPrioritiesCalc: [1, * 32]", () => { + it("[1, * 32]", () => { expect(firstPrioritiesCalc([1, "*", 32])).toEqual([32]); }); - it("firstPrioritiesCalc: [32, /, 32]", () => { + it("[32, /, 32]", () => { expect(firstPrioritiesCalc([32, "/", 32])).toEqual([1]); }); - it("firstPrioritiesCalc: [32, + 32]", () => { + it("[32, + 32]", () => { expect(firstPrioritiesCalc([32, "+", 32])).toEqual([32, "+", 32]); }); }); describe("firstPrioritiesCalc mixed with second priorities cases", () => { - it("firstPrioritiesCalc: [32, /, 32, +, 10, *, 10]", () => { + it("[32, /, 32, +, 10, *, 10]", () => { expect(firstPrioritiesCalc([32, "/", 32, "+", 10, "*", 10])).toEqual([ 1, "+", @@ -25,7 +25,7 @@ describe("firstPrioritiesCalc mixed with second priorities cases", () => { }); describe("secondPrioritiesCalc invalid cases", () => { - it("secondPrioritiesCalc: [32, / 32]", () => { + it("[32, / 32]", () => { expect(() => secondPrioritiesCalc([32, "/", 32])).toThrow( TypeError("Unexpected stack!") ); @@ -33,15 +33,15 @@ describe("secondPrioritiesCalc invalid cases", () => { }); describe("secondPrioritiesCalc simple cases", () => { - it("secondPrioritiesCalc: [32, + 32]", () => { + it("[32, + 32]", () => { expect(secondPrioritiesCalc([32, "+", 32])).toEqual(64); }); - it("secondPrioritiesCalc: [32, - 32]", () => { + it("[32, - 32]", () => { expect(secondPrioritiesCalc([32, "-", 32])).toEqual(0); }); - it("secondPrioritiesCalc: [32, - 32, +, 10]", () => { + it("[32, - 32, +, 10]", () => { expect(secondPrioritiesCalc([32, "-", 32, "+", 10])).toEqual(10); }); }); diff --git a/src/lesson2/parser.test.ts b/src/lesson2/parser.test.ts index 1ebfd133..5593e312 100644 --- a/src/lesson2/parser.test.ts +++ b/src/lesson2/parser.test.ts @@ -1,27 +1,27 @@ import { parser } from "./parser"; describe("Parser correct cases", () => { - it("parser: 1 + 32", () => { + it("1 + 32", () => { expect(parser("1 + 32")).toEqual([1, "+", 32]); }); - it("parser: 11 + 3 * 22", () => { + it("11 + 3 * 22", () => { expect(parser("11 + 3 * 22")).toEqual([11, "+", 3, "*", 22]); }); - it("parser: 1 + 32 - 2 + 2", () => { + it("1 + 32 - 2 + 2", () => { expect(parser("1 + 32 - 2 + 2")).toEqual([1, "+", 32, "-", 2, "+", 2]); }); }); describe("Parser invalid cases", () => { - it("parser: 1 + + 33 - 2", () => { + it("1 + + 33 - 2", () => { expect(() => parser("1 + + 33 - 2")).toThrow( TypeError("Unexpected string") ); }); - it("parser: 1 ! 33 - 2", () => { + it("1 ! 33 - 2", () => { expect(() => parser("1 ! 33 - 2")).toThrow(TypeError("Unexpected string")); }); }); diff --git a/src/lesson2/runner.test.ts b/src/lesson2/runner.test.ts index eadb9143..1318dce3 100644 --- a/src/lesson2/runner.test.ts +++ b/src/lesson2/runner.test.ts @@ -1,39 +1,39 @@ import { runner } from "./runner"; describe("Runner simple cases", () => { - it("runner: 1 * 32", () => { + it("1 * 32", () => { expect(runner("1 * 32")).toEqual(32); }); - it("runner: 2 * 32", () => { + it("2 * 32", () => { expect(runner("2 * 32")).toEqual(64); }); - it("runner: 2 + 32", () => { + it("2 + 32", () => { expect(runner("2 + 32")).toEqual(34); }); }); describe("Runner tripled/mixed cases", () => { - it("runner: 2 * 2 * 3", () => { + it("2 * 2 * 3", () => { expect(runner("2 * 2 * 3")).toEqual(12); }); - it("runner: 2 * 2 + 3", () => { + it("2 * 2 + 3", () => { expect(runner("2 * 2 + 3")).toEqual(7); }); - it("runner: 2 + 2 * 3", () => { + it("2 + 2 * 3", () => { expect(runner("2 + 2 * 3")).toEqual(8); }); }); describe("Runner long cases", () => { - it("runner: 20 + 1 * 10 - 5 * 3", () => { + it("20 + 1 * 10 - 5 * 3", () => { expect(runner("20 + 1 * 10 - 5 * 3")).toEqual(15); }); - it("runner: 20 - 10 * 10 / 5 - 3", () => { + it("20 - 10 * 10 / 5 - 3", () => { expect(runner("20 - 10 * 10 / 5 - 3")).toEqual(-3); }); });