diff --git a/modules/ecs6-class/line.js b/modules/ecs6-class/line.js index 76a7359..c5107ac 100644 --- a/modules/ecs6-class/line.js +++ b/modules/ecs6-class/line.js @@ -2,35 +2,72 @@ const Point = require("./point"); class Line { constructor({ point1 = new Point(), point2 = new Point(), n = undefined, slope = undefined }) { + if (!(point1 instanceof Point) || !(point2 instanceof Point)) { + throw new Error('InvalidPointError: point1 and point2 must be instances of Point'); + } + if (typeof(n)!=="number"&&n!=undefined) { + throw new Error('InvalidError: n must be a number'); + } + if (typeof(slope)!=="number"&&slope!=undefined) { + throw new Error('InvalidError: slope must be a number'); + } this.point1 = point1; this.point2 = point2; this.slope = slope; this.n = n; } - calculateSlope() { + calculateSlope () { + if (this.point1.x === this.point2.x) { + throw new Error('UndefinedSlopeError: Slope is undefined for vertical lines'); + } this.slope = (this.point1.y - this.point2.y) / (this.point1.x - this.point2.x) } - calculateNOfLineFunction() { + calculateNOfLineFunction = () => { + if (this.slope === undefined) { + this.calculateSlope(); + } this.n = this.point1.y - this.slope * this.point1.x } getPointOnXAsis() { + + if (this.slope === undefined || this.n === undefined) { + this.calculateNOfLineFunction(); + } return this.getPointByY(0) } getPointOnYAsis() { + if (this.slope === undefined || this.n === undefined) { + this.calculateNOfLineFunction(); + } return this.getPointByX(0) } getPointByX(x) { + if (typeof x !== 'number') { + throw new Error('InvalidInputError: x must be a number'); + } + if (this.slope === undefined || this.n === undefined) { + this.calculateNOfLineFunction(); + } let y = this.slope * x + this.n return new Point({ x, y }) } getPointByY(y) { + if (typeof y !== 'number') { + throw new Error('InvalidInputError: y must be a number'); + } + if (this.slope === undefined || this.n === undefined) { + this.calculateNOfLineFunction(); + } + if (this.slope === 0) { + throw new Error('InvalidSlopeError: Slope cannot be zero for calculating X by Y'); + } let x = (y - this.n) / this.slope; return new Point({ x, y }) } diff --git a/modules/ecs6-class/point.js b/modules/ecs6-class/point.js index e81b4a4..c4e8f9a 100644 --- a/modules/ecs6-class/point.js +++ b/modules/ecs6-class/point.js @@ -1,12 +1,21 @@ class Point { - constructor({x=0, y=0}={}) { + constructor({ x = 0, y = 0 } = {}) { + if (typeof x !== 'number' || typeof y !== 'number') { + throw new Error('InvalidPointError: values must be numbers'); + } this.x = x; this.y = y; } moveVertical(value) { + if (typeof value !== 'number') { + throw new Error('InvalidValueError: Value must be a number'); + } this.y += value; } moveHorizontal(value) { + if (typeof value !== 'number') { + throw new Error('InvalidValueError: Value must be a number'); + } this.x += value; } } diff --git a/modules/geometry-calculation.js b/modules/geometry-calculation.js index 6e11643..b2da165 100644 --- a/modules/geometry-calculation.js +++ b/modules/geometry-calculation.js @@ -1,19 +1,41 @@ const Line = require('./ecs6-class/line') - +const Point = require('../modules/ecs6-class/point'); const calculateDistance = (point1, point2) => { + if (!point1 || !point2 || typeof point1.x !== 'number' || typeof point1.y !== 'number' || typeof point2.x !== 'number' || typeof point2.y !== 'number') { + throw new Error('Invalid input points'); + } let distanceX = (point2.x - point1.x) ** 2; - let distanceY = (point2.y - point2.y) ** 2; + let distanceY = (point2.y - point1.y) ** 2; const distance = Math.sqrt(distanceX + distanceY); return distance; } -const calculateJunctionPoint = (line1, line2) => { +const calculateJunctionPoint = (line1, line2) => { + + if (!(line1 instanceof Line)) { + throw new Error('Invalid input line1'); + } + if (!(line2 instanceof Line) ) { + throw new Error('Invalid input line2'); + } + if(line1.slope==undefined){ + line1.calculateSlope(); + } + if(line2.slope==undefined){ + line2.calculateSlope(); + } if (line1.slope === line2.slope) { + if(line1.n===undefined){ + line1.calculateNOfLineFunction(); + } + if(line2.n===undefined){ + line2.calculateNOfLineFunction(); + } if (line1.n === line2.n) { - return true + return true; } else { - return false + return false; } } else { @@ -24,8 +46,17 @@ const calculateJunctionPoint = (line1, line2) => { } const isPointOnLine = (line, point) => { + if (!(line instanceof Line) ) { + throw new Error('Invalid input line '); + } + if ( !(point instanceof Point) || typeof point.x !== 'number' || typeof point.y !== 'number') { + throw new Error('Invalid input point'); + } const proxyLine = new Line({ point1: line.point1, point2: point }) - proxyLine.calculateSlope() + proxyLine.calculateSlope(); + if(line.slope==undefined){ + line.calculateSlope(); + } if (line.slope === proxyLine.slope) { proxyLine.calculateNOfLineFunction() if (line.n === proxyLine.n) { diff --git a/package.json b/package.json index 56bf17b..e1048b4 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "practice unit tests in javascript", "main": "index.js", "scripts": { - "test": "jest" + "test": "jest", + "coverage": "jest --coverage" }, "dependencies": { "jest": "^29.7.0" diff --git a/tests/ecs6-class/line.test.js b/tests/ecs6-class/line.test.js new file mode 100644 index 0000000..45fa90d --- /dev/null +++ b/tests/ecs6-class/line.test.js @@ -0,0 +1,188 @@ +const Line = require('../../modules/ecs6-class/line'); +const Point = require('../../modules/ecs6-class/point'); + +describe('Line class', () => { + test('should create a line with default points and undefined slope and n', () => { + const line = new Line({}); + expect(line.point1).toBeInstanceOf(Point); + expect(line.point2).toBeInstanceOf(Point); + expect(line.slope).toBeUndefined(); + expect(line.n).toBeUndefined(); + }); + test('should create a line with selected values and undefined slope and n', () => { + const point1=new Point({x:5,y:3}); + const point2=new Point({x:4,y:6}); + const line = new Line({point1:point1,point2:point2}); + expect(line.point1).toEqual(point1); + expect(line.point2).toEqual(point2); + expect(line.slope).toBeUndefined(); + expect(line.n).toBeUndefined(); + }); + test('should create a line with selected values', () => { + const point1=new Point({x:5,y:3}); + const point2=new Point({x:4,y:6}); + const line = new Line({point1:point1,point2:point2,n:5,slope:3}); + expect(line.point1).toEqual(point1); + expect(line.point2).toEqual(point2); + expect(line.slope).toEqual(3); + expect(line.n).toEqual(5); + }); + + test('should throw an error for invalid point1 or point2', () => { + expect(() => new Line({ point1: {}, point2: new Point() })).toThrow('InvalidPointError: point1 and point2 must be instances of Point'); + expect(() => new Line({ point1: new Point(), point2: {} })).toThrow('InvalidPointError: point1 and point2 must be instances of Point'); + }); + + test('should throw an error for invalid n ', () => { + expect(() => new Line({ point1: new Point(), point2: new Point() ,n:'n',slope:5})).toThrow('InvalidError: n must be a number'); + expect(() => new Line({ point1: new Point(), point2: new Point() ,n:{},slope:5})).toThrow('InvalidError: n must be a number'); + expect(() => new Line({ point1: new Point(), point2: new Point() ,n:[],slope:5})).toThrow('InvalidError: n must be a number'); + expect(() => new Line({ point1: new Point(), point2: new Point() ,n:true,slope:5})).toThrow('InvalidError: n must be a number'); + }); + test('should throw an error for invalid slope ', () => { + expect(() => new Line({ point1: new Point(), point2: new Point() ,n:5,slope:{}})).toThrow('InvalidError: slope must be a number'); + expect(() => new Line({ point1: new Point(), point2: new Point() ,n:5,slope:'5'})).toThrow('InvalidError: slope must be a number'); + expect(() => new Line({ point1: new Point(), point2: new Point() ,n:5,slope:[]})).toThrow('InvalidError: slope must be a number'); + expect(() => new Line({ point1: new Point(), point2: new Point() ,n:5,slope:true})).toThrow('InvalidError: slope must be a number'); + }); + describe('calculateSlope', () => { + test('should calculate the slope of the line', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const line = new Line({ point1, point2 }); + line.calculateSlope(); + expect(line.slope).toBe(1); + }); + + test('should throw an error for undefined slope (vertical line)', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 0, y: 4 }); + const line = new Line({ point1, point2 }); + expect(() => line.calculateSlope()).toThrow('UndefinedSlopeError: Slope is undefined for vertical lines'); + }); + }) + + describe('calculateNOfLineFunction', () => { + test('should calculate the n of the line function', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const line = new Line({ point1, point2 }); + line.calculateNOfLineFunction(); + expect(line.n).toBe(0); + }); + test('should throw an error for undefined slope (vertical line)', () => { + const point1 = new Point({ x: 4, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const line = new Line({ point1, point2 }); + expect(() => line.calculateNOfLineFunction()).toThrow('UndefinedSlopeError: Slope is undefined for vertical lines'); + }); + }); + describe('getPointOnXAsis', () => { + test('should get point on X axis', () => { + const point1 = new Point({ x: 0, y: 1 }); + const point2 = new Point({ x: 1, y: 0 }); + const line = new Line({ point1, point2 }); + const pointOnXAxis = line.getPointOnXAsis(); + expect(pointOnXAxis.x).toBe(1); + expect(pointOnXAxis.y).toBe(0); + }); + + + test('should handle horizontal lines correctly by throwing an error', () => { + const point1 = new Point({ x: 1, y: 0 }); + const point2 = new Point({ x: 3, y: 0 }); + + const line = new Line({ + point1: point1, + point2: point2, + slope: 0, + n: 0 + }); + + expect(() => line.getPointOnXAsis()).toThrow('InvalidSlopeError: Slope cannot be zero for calculating X by Y'); + }); + test('should throw an error for undefined slope (vertical line)', () => { + const point1 = new Point({ x: 4, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const line = new Line({ point1, point2 }); + expect(() => line.getPointOnXAsis()).toThrow('UndefinedSlopeError: Slope is undefined for vertical lines'); + }); + }) + describe('getPointOnYAsis',()=>{ + test('should get point on Y axis', () => { + const point1 = new Point({ x: 1, y: 0 }); + const point2 = new Point({ x: 2, y: 1 }); + const line = new Line({ point1, point2 }); + const pointOnYAxis = line.getPointOnYAsis(); + expect(pointOnYAxis.x).toBe(0); + expect(pointOnYAxis.y).toBe(-1); + }); + + test('should return the Y-intercept for horizontal lines', () => { + const point1 = new Point({ x: 1, y: 5 }); + const point2 = new Point({ x: 3, y: 5 }); + const line = new Line({ point1: point1, point2: point2, slope: 0, n: 5 }); + const expectedPoint = new Point({ x: 0, y: 5 }); + const result = line.getPointOnYAsis(); + + expect(result).toEqual(expectedPoint); + }); + test('should throw an error for undefined slope (vertical line)', () => { + const point1 = new Point({ x: 4, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const line = new Line({ point1, point2 }); + expect(() => line.getPointOnYAsis()).toThrow('UndefinedSlopeError: Slope is undefined for vertical lines'); + }); + }) + +describe('getPointByX',()=>{ + test('should get point by X', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const line = new Line({ point1, point2 }); + const point = line.getPointByX(2); + expect(point.x).toBe(2); + expect(point.y).toBe(2); + }); + test('should throw an error for invalid x input in getPointByX', () => { + const line = new Line({}); + expect(() => line.getPointByX('a')).toThrow('InvalidInputError: x must be a number'); + expect(() => line.getPointByX()).toThrow('InvalidInputError: x must be a number'); + expect(() => line.getPointByX({})).toThrow('InvalidInputError: x must be a number'); + expect(() => line.getPointByX([])).toThrow('InvalidInputError: x must be a number'); + }); +}) +describe('getPointByY',()=>{ + test('should get point by Y', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const line = new Line({ point1, point2 }); + const point = line.getPointByY(2); + expect(point.x).toBe(2); + expect(point.y).toBe(2); + }); + test('should throw an error for invalid slope (slope is zero) in getPointByY', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 4, y: 0 }); + const line = new Line({ point1, point2 }); + expect(() => line.getPointByY(2)).toThrow('InvalidSlopeError: Slope cannot be zero for calculating X by Y'); + }); + + test('should throw an error for invalid y input in getPointByY', () => { + const line = new Line({}); + expect(() => line.getPointByY('a')).toThrow('InvalidInputError: y must be a number'); + expect(() => line.getPointByY()).toThrow('InvalidInputError: y must be a number'); + expect(() => line.getPointByY({})).toThrow('InvalidInputError: y must be a number'); + expect(() => line.getPointByY([])).toThrow('InvalidInputError: y must be a number'); + }); +}) + + + + + + + + + +}); diff --git a/tests/ecs6-class/point.test.js b/tests/ecs6-class/point.test.js new file mode 100644 index 0000000..756acf3 --- /dev/null +++ b/tests/ecs6-class/point.test.js @@ -0,0 +1,51 @@ +const Point = require('../../modules/ecs6-class/point'); + +describe('Point class', () => { + test('should create a point with default values (0, 0)', () => { + const point = new Point(); + expect(point.x).toBe(0); + expect(point.y).toBe(0); + }); + + test('should create a point with given values', () => { + const point = new Point({ x: 3, y: 4 }); + expect(point.x).toBe(3); + expect(point.y).toBe(4); + }); + + test('should throw an error for invalid initial values', () => { + expect(() => new Point({ x: 'a', y: 4 })).toThrow('InvalidPointError: values must be numbers'); + expect(() => new Point({ x: 3, y: 'b' })).toThrow('InvalidPointError: values must be numbers'); + expect(() => new Point({ x: 'a', y: 'b' })).toThrow('InvalidPointError: values must be numbers'); + }); + describe('moveVertical',()=>{ + test('should move vertically', () => { + const point = new Point({ x: 0, y: 0 }); + point.moveVertical(5); + expect(point.y).toBe(5); + }); + + test('should throw an error for invalid vertical move value', () => { + const point = new Point({ x: 0, y: 0 }); + expect(() => point.moveVertical('a')).toThrow('InvalidValueError: Value must be a numbe'); + expect(() => point.moveVertical({})).toThrow('InvalidValueError: Value must be a number'); + expect(() => point.moveVertical()).toThrow('InvalidValueError: Value must be a number'); + expect(() => point.moveVertical([])).toThrow('InvalidValueError: Value must be a number'); + }); + }) + describe('moveHorizontal',()=>{ + test('should move horizontally', () => { + const point = new Point({ x: 0, y: 0 }); + point.moveHorizontal(5); + expect(point.x).toBe(5); + }); + test('should throw an error for invalid horizontal move value', () => { + const point = new Point({ x: 0, y: 0 }); + expect(() => point.moveHorizontal('a')).toThrow('InvalidValueError: Value must be a numbe'); + expect(() => point.moveHorizontal({})).toThrow('InvalidValueError: Value must be a number'); + expect(() => point.moveHorizontal()).toThrow('InvalidValueError: Value must be a number'); + expect(() => point.moveHorizontal([])).toThrow('InvalidValueError: Value must be a number'); + }); + }); + +}); diff --git a/tests/geometry_calculation.test.js b/tests/geometry_calculation.test.js new file mode 100644 index 0000000..fdac395 --- /dev/null +++ b/tests/geometry_calculation.test.js @@ -0,0 +1,131 @@ +const { calculateDistance, calculateJunctionPoint, isPointOnLine } = require('../modules/geometry-calculation'); +const Line = require('../modules/ecs6-class/line'); +const Point = require('../modules/ecs6-class/point'); + +describe('calculateDistance', () => { + test('should calculate the correct distance between two points', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 3, y: 4 }); + const distance = calculateDistance(point1, point2); + expect(distance).toBe(5); + }); + test('should throw an error for invalid input points', () => { + expect(() => calculateDistance(null, { x: 3, y: 4 })).toThrow('Invalid input points'); + expect(() => calculateDistance({ x: 0, y: 0 }, null)).toThrow('Invalid input points'); + expect(() => calculateDistance({ x: 'a', y: 0 }, { x: 3, y: 4 })).toThrow('Invalid input points'); + }); +}); + +describe('calculateJunctionPoint', () => { + test('should return true if lines are the same', () => { + const line1 = new Line({ slope: 1, n: 0 }); + const line2 = new Line({ slope: 1, n: 0 }); + const result = calculateJunctionPoint(line1, line2); + expect(result).toBe(true); + }); + test('should calculate slope and return false if lines are parallel but not the same', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 3, y: 4 }); + const line1 = new Line({point1:point1,point2:point2,slope:undefined,n:2}); + const line2 = new Line({point1:point1,point2:point2,slope:undefined,n:3}); + const result = calculateJunctionPoint(line1, line2); + expect(result).toBe(false); + }); + test('should calculate n and return true if lines are the same', () => { + const line1 = new Line({ slope: 1, n: undefined }); + const line2 = new Line({ slope: 1, n: undefined }); + const result = calculateJunctionPoint(line1, line2); + expect(result).toBe(true); + }); + test('should return false if lines are parallel but not the same', () => { + const line1 = new Line({ slope: 1, n: 0 }); + const line2 = new Line({ slope: 1, n: 1 }); + const result = calculateJunctionPoint(line1, line2); + expect(result).toBe(false); + }); + + test('should return the junction point if lines intersect', () => { + const line1 = new Line({slope:1,n:2}); + const line2 = new Line({slope:-1,n:3}); + const expectedJunctionPoint = { x: 0.5, y: 2.5 }; + line1.getPointByX = jest.fn().mockImplementation((x) => { + return { x, y: line1.slope * x + line1.n }; + }); + const result = calculateJunctionPoint(line1, line2); + expect(line1.getPointByX).toHaveBeenCalledWith(0.5); + expect(result).toEqual(expectedJunctionPoint); + }); + + test('should throw an error for invalid input line1', () => { + expect(() => calculateJunctionPoint(null, new Line({ slope: 1, n: 0 }))).toThrow('Invalid input line1'); + expect(() => calculateJunctionPoint(null,new Line({ slope: 1, n: 0 }))).toThrow('Invalid input line1'); + expect(() => calculateJunctionPoint({}, new Line({ slope: 1, n: 0 }))).toThrow('Invalid input line1'); + + + }); + test('should throw an error for invalid input line2', () => { + + expect(() => calculateJunctionPoint( new Line({ slope: 1, n: 0 }),null)).toThrow('Invalid input line2'); + expect(() => calculateJunctionPoint(new Line({ slope: 1, n: 0 }), null)).toThrow('Invalid input line2'); + expect(() => calculateJunctionPoint( new Line({ slope: 1, n: 0 }),null)).toThrow('Invalid input line2'); + + }); + +}); + +describe('isPointOnLine', () => { + test('should return true if the point is on the line', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const line = new Line({ point1: point1, point2: point2,slope:1,n:0} ); + const point = new Point({ x: 2, y: 2 }); + const result = isPointOnLine(line, point); + expect(result).toBe(true); + }); + test('should return false if the point is not on the line', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const line = new Line({ point1: point1, point2: point2 ,slope:1,n:0}); + const point = new Point({ x: 2, y: 3 }); + const result = isPointOnLine(line, point); + expect(result).toBe(false); + }); + + test('should calculate slope and return false if the point is not on the line', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const line = new Line({ point1: point1, point2: point2 }); + const point = new Point({ x: 2, y: 3 }); + const result = isPointOnLine(line, point); + expect(result).toBe(false); + }); + test('should return false if the point is not on the line', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const line = new Line({ point1: point1, point2: point2 ,slope:1,n:0}); + const point = new Point({ x: 2, y: 3 }); + + const result = isPointOnLine(line, point); + expect(result).toBe(false); + }); + test('should throw an error for invalid input line ', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const point = new Point({ x: 2, y: 3 }); + const line = new Line({ point1:point1, point2: point2 }); + expect(() => isPointOnLine(null, point)).toThrow('Invalid input line'); + expect(() => calculateJunctionPoint(new Line({ slope: 1, n: 0 }))).toThrow('Invalid input line2'); + expect(() => calculateJunctionPoint(new Line({ slope: 1, n: 0 }))).toThrow('Invalid input line2'); + }); + test('should throw an error for invalid input point', () => { + const point1 = new Point({ x: 0, y: 0 }); + const point2 = new Point({ x: 4, y: 4 }); + const point = new Point({ x: 2, y: 3 }); + const line = new Line({ point1:point1, point2: point2 }); + expect(() => isPointOnLine(line, null)).toThrow('Invalid input point'); + expect(() => isPointOnLine(line,{ x: 'a', y: 2 })).toThrow('Invalid input point'); + expect(() => isPointOnLine(line,new Point({ x: 'a', y: 2 }))).toThrow('InvalidPointError: values must be numbers'); + }); + + +});