Skip to content

Commit dfded06

Browse files
committed
feat: add geometry trapezoid
1 parent 9010481 commit dfded06

File tree

2 files changed

+234
-0
lines changed

2 files changed

+234
-0
lines changed

Geometry/Test/Trapezoid.test.js

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import Trapezoid from '../Trapezoid'
2+
3+
describe('Trapezoid', () => {
4+
describe('Constructor', () => {
5+
test('creates a trapezoid with valid dimensions', () => {
6+
const trapezoid = new Trapezoid(5, 10, 7)
7+
expect(trapezoid).toBeInstanceOf(Trapezoid)
8+
expect(trapezoid.base1).toBe(5)
9+
expect(trapezoid.base2).toBe(10)
10+
expect(trapezoid.height).toBe(7)
11+
expect(trapezoid.sides).toEqual([null, null])
12+
})
13+
14+
test('creates a trapezoid with all sides known', () => {
15+
const trapezoid = new Trapezoid(5, 10, 7, 3, 4)
16+
expect(trapezoid.sides).toEqual([3, 4])
17+
})
18+
19+
test('throws an error if any dimension is invalid', () => {
20+
expect(() => new Trapezoid(-5, 10, 7)).toThrow(
21+
'base1 must be a positive number.'
22+
)
23+
expect(() => new Trapezoid(5, -10, -7)).toThrow(
24+
'base2 must be a positive number.'
25+
)
26+
expect(() => new Trapezoid(5, NaN, 7)).toThrow(
27+
'base2 must be a positive number.'
28+
)
29+
expect(() => new Trapezoid(5, 10, -7)).toThrow(
30+
'height must be a positive number.'
31+
)
32+
})
33+
})
34+
35+
describe('Area Calculation', () => {
36+
test('calculates area correctly', () => {
37+
const trapezoid = new Trapezoid(5, 10, 7)
38+
expect(trapezoid.area()).toBe(52.5) // Area = ((5 + 10) / 2) * 7
39+
})
40+
})
41+
42+
describe('Perimeter Calculation', () => {
43+
test('calculates perimeter correctly when all sides are known', () => {
44+
const trapezoid = new Trapezoid(5, 10, 7, 3, 4)
45+
expect(trapezoid.perimeter()).toBe(22) // Perimeter = base1 + base2 + sideA + sideB
46+
})
47+
48+
test('throws an error if not all sides are known', () => {
49+
const trapezoid = new Trapezoid(5, 10, 7)
50+
expect(() => trapezoid.perimeter()).toThrow(
51+
'Cannot calculate perimeter: not all sides are known.'
52+
)
53+
})
54+
})
55+
56+
describe('Getters', () => {
57+
test('base1 getter returns correct value', () => {
58+
const trapezoid = new Trapezoid(5, 10, 7)
59+
expect(trapezoid.base1).toBe(5)
60+
})
61+
62+
test('base2 getter returns correct value', () => {
63+
const trapezoid = new Trapezoid(5, 10, 7)
64+
expect(trapezoid.base2).toBe(10)
65+
})
66+
67+
test('height getter returns correct value', () => {
68+
const trapezoid = new Trapezoid(5, 10, 7)
69+
expect(trapezoid.height).toBe(7)
70+
})
71+
72+
test('sides getter returns correct values', () => {
73+
const trapezoid = new Trapezoid(5, 10, 7, 3, 4)
74+
expect(trapezoid.sides).toEqual([3, 4])
75+
})
76+
})
77+
78+
describe('String Representation', () => {
79+
test('returns correct string representation when sides are unknown', () => {
80+
const trapezoid = new Trapezoid(5, 10, 7)
81+
expect(trapezoid.toString()).toBe(
82+
'Trapezoid: base1 = 5, base2 = 10, height = 7, sideA = unknown, sideB = unknown, area = 52.5, perimeter = unknown'
83+
)
84+
})
85+
86+
test('returns correct string representation when all sides are known', () => {
87+
const trapezoid = new Trapezoid(5, 10, 7, 3, 4)
88+
expect(trapezoid.toString()).toBe(
89+
'Trapezoid: base1 = 5, base2 = 10, height = 7, sideA = 3, sideB = 4, area = 52.5, perimeter = 22'
90+
)
91+
})
92+
})
93+
})

Geometry/Trapezoid.js

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/**
2+
* This class represents a Trapezoid and provides methods to calculate its area and perimeter.
3+
* @see {@link https://en.wikipedia.org/wiki/Trapezoid|Trapezoid}
4+
* @class
5+
*/
6+
export default class Trapezoid {
7+
/** @private */
8+
#base1
9+
10+
/** @private */
11+
#base2
12+
13+
/** @private */
14+
#height
15+
16+
/** @private */
17+
#sideA
18+
19+
/** @private */
20+
#sideB
21+
22+
/**
23+
* Creates a trapezoid instance.
24+
* @constructor
25+
* @param {number} base1 - The length of the first base.
26+
* @param {number} base2 - The length of the second base.
27+
* @param {number} height - The height of the trapezoid.
28+
* @param {number} [sideA] - The length of side A (optional).
29+
* @param {number} [sideB] - The length of side B (optional).
30+
* @throws {Error} Will throw an error if any dimension is invalid.
31+
*/
32+
constructor(base1, base2, height, sideA = null, sideB = null) {
33+
this.#validateDimension(base1, 'base1')
34+
this.#validateDimension(base2, 'base2')
35+
this.#validateDimension(height, 'height')
36+
37+
this.#base1 = base1
38+
this.#base2 = base2
39+
this.#height = height
40+
this.#sideA = sideA
41+
this.#sideB = sideB
42+
}
43+
44+
/**
45+
* Validates that a dimension is a positive number.
46+
* @private
47+
* @param {number} value - The value to validate.
48+
* @param {string} name - The name of the dimension (for error reporting).
49+
* @throws {Error} Will throw an error if the value is not a positive number.
50+
*/
51+
#validateDimension(value, name) {
52+
if (typeof value !== 'number' || isNaN(value) || value <= 0) {
53+
throw new Error(`${name} must be a positive number.`)
54+
}
55+
}
56+
57+
/**
58+
* Calculates the area of the trapezoid.
59+
* @public
60+
* @returns {number} The area of the trapezoid.
61+
*/
62+
area() {
63+
return ((this.#base1 + this.#base2) / 2) * this.#height
64+
}
65+
66+
/**
67+
* Calculates the perimeter of the trapezoid.
68+
* @public
69+
* @returns {number} The perimeter of the trapezoid.
70+
* @throws {Error} Will throw an error if not all sides are known.
71+
*/
72+
perimeter() {
73+
if (this.#sideA === null || this.#sideB === null) {
74+
throw new Error('Cannot calculate perimeter: not all sides are known.')
75+
}
76+
return this.#base1 + this.#base2 + this.#sideA + this.#sideB
77+
}
78+
79+
/**
80+
* Returns a string representation of the trapezoid.
81+
* @public
82+
* @returns {string} A string describing the trapezoid's dimensions and area/perimeter.
83+
*/
84+
toString() {
85+
const areaValue = this.area()
86+
let perimeterValue
87+
88+
// Check if all sides are known for perimeter calculation
89+
if (this.#sideA === null || this.#sideB === null) {
90+
perimeterValue = 'unknown'
91+
} else {
92+
perimeterValue = this.perimeter()
93+
}
94+
95+
return (
96+
`Trapezoid: base1 = ${this.#base1}, base2 = ${this.#base2}, height = ${
97+
this.#height
98+
}, ` +
99+
`sideA = ${this.#sideA ?? 'unknown'}, sideB = ${
100+
this.#sideB ?? 'unknown'
101+
}, ` +
102+
`area = ${areaValue}, perimeter = ${perimeterValue}`
103+
)
104+
}
105+
106+
/**
107+
* Gets the first base of the trapezoid.
108+
* @public
109+
* @returns {number} The first base of the trapezoid.
110+
*/
111+
get base1() {
112+
return this.#base1
113+
}
114+
115+
/**
116+
* Gets the second base of the trapezoid.
117+
* @public
118+
* @returns {number} The second base of the trapezoid.
119+
*/
120+
get base2() {
121+
return this.#base2
122+
}
123+
124+
/**
125+
* Gets the height of the trapezoid.
126+
* @public
127+
* @returns {number} The height of the trapezoid.
128+
*/
129+
get height() {
130+
return this.#height
131+
}
132+
133+
/**
134+
* Gets the lengths of sides A and B of the trapezoid.
135+
* @public
136+
* @returns {Array<number|null>} An array containing lengths of side A and side B or null for unknown sides.
137+
*/
138+
get sides() {
139+
return [this.#sideA, this.#sideB]
140+
}
141+
}

0 commit comments

Comments
 (0)