From 3149a983a2202977a2ac337edc88fa5c700c8a48 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 07:03:12 +0000 Subject: [PATCH 1/2] Initial plan From dfd220c029a525e83faab0a0e2b5923ad0afc167 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 07:06:40 +0000 Subject: [PATCH 2/2] Add factorial utility, API endpoint, and tests Co-authored-by: kavyashri-as <213833080+kavyashri-as@users.noreply.github.com> --- factorial.js | 24 +++++++++ index.js | 15 ++++++ tests/factorial.test.js | 112 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 factorial.js create mode 100644 tests/factorial.test.js diff --git a/factorial.js b/factorial.js new file mode 100644 index 0000000..796931d --- /dev/null +++ b/factorial.js @@ -0,0 +1,24 @@ +const MAX_FACTORIAL_INPUT = 18; // factorial(18) is within JavaScript's safe integer range + +/** + * Computes the factorial of a non-negative integer. + * Supports inputs from 0 to 18 (factorial values within Number.MAX_SAFE_INTEGER). + * @param {number} n - A non-negative integer (0–18) + * @returns {number} The factorial of n + */ +function factorial(n) { + if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) { + throw new Error('Input must be a non-negative integer'); + } + if (n > MAX_FACTORIAL_INPUT) { + throw new Error(`Input must not exceed ${MAX_FACTORIAL_INPUT} to ensure precise integer results`); + } + if (n === 0 || n === 1) return 1; + let result = 1; + for (let i = 2; i <= n; i++) { + result *= i; + } + return result; +} + +module.exports = { factorial }; diff --git a/index.js b/index.js index b2c6a6a..d9b2f99 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ const express = require('express'); const bodyParser = require('body-parser'); const db = require('./database'); +const { factorial } = require('./factorial'); const app = express(); @@ -258,6 +259,20 @@ app.delete('/api/tasks/:id', (req, res) => { }); }); +// Factorial Route +app.get('/api/factorial/:n', (req, res) => { + const n = parseInt(req.params.n, 10); + if (isNaN(n) || n < 0 || String(n) !== req.params.n) { + return res.status(400).json({ error: 'Input must be a non-negative integer' }); + } + try { + const result = factorial(n); + res.json({ n, result }); + } catch (err) { + res.status(400).json({ error: err.message }); + } +}); + // Error handling middleware app.use((err, req, res, next) => { console.error('Unhandled error:', err); diff --git a/tests/factorial.test.js b/tests/factorial.test.js new file mode 100644 index 0000000..e1bf7cd --- /dev/null +++ b/tests/factorial.test.js @@ -0,0 +1,112 @@ +const request = require('supertest'); +const express = require('express'); +const bodyParser = require('body-parser'); +const { factorial } = require('../factorial'); + +// Build a minimal app for testing the factorial route +const app = express(); +app.use(bodyParser.json()); + +app.get('/api/factorial/:n', (req, res) => { + const n = parseInt(req.params.n, 10); + if (isNaN(n) || n < 0 || String(n) !== req.params.n) { + return res.status(400).json({ error: 'Input must be a non-negative integer' }); + } + try { + const result = factorial(n); + res.json({ n, result }); + } catch (err) { + res.status(400).json({ error: err.message }); + } +}); + +describe('Factorial utility', () => { + test('factorial(0) should return 1', () => { + expect(factorial(0)).toBe(1); + }); + + test('factorial(1) should return 1', () => { + expect(factorial(1)).toBe(1); + }); + + test('factorial(5) should return 120', () => { + expect(factorial(5)).toBe(120); + }); + + test('factorial(10) should return 3628800', () => { + expect(factorial(10)).toBe(3628800); + }); + + test('should throw for negative numbers', () => { + expect(() => factorial(-1)).toThrow('Input must be a non-negative integer'); + }); + + test('should throw for non-integer input', () => { + expect(() => factorial(3.5)).toThrow('Input must be a non-negative integer'); + }); + + test('should throw for non-number input', () => { + expect(() => factorial('abc')).toThrow('Input must be a non-negative integer'); + }); + + test('should throw for input exceeding maximum safe value', () => { + expect(() => factorial(19)).toThrow('Input must not exceed 18'); + }); +}); + +describe('GET /api/factorial/:n', () => { + test('should return factorial of 0', (done) => { + request(app) + .get('/api/factorial/0') + .expect(200) + .end((err, res) => { + if (err) return done(err); + expect(res.body).toEqual({ n: 0, result: 1 }); + done(); + }); + }); + + test('should return factorial of 5', (done) => { + request(app) + .get('/api/factorial/5') + .expect(200) + .end((err, res) => { + if (err) return done(err); + expect(res.body).toEqual({ n: 5, result: 120 }); + done(); + }); + }); + + test('should return factorial of 10', (done) => { + request(app) + .get('/api/factorial/10') + .expect(200) + .end((err, res) => { + if (err) return done(err); + expect(res.body).toEqual({ n: 10, result: 3628800 }); + done(); + }); + }); + + test('should return 400 for negative number', (done) => { + request(app) + .get('/api/factorial/-1') + .expect(400) + .end((err, res) => { + if (err) return done(err); + expect(res.body.error).toBeDefined(); + done(); + }); + }); + + test('should return 400 for non-integer input', (done) => { + request(app) + .get('/api/factorial/abc') + .expect(400) + .end((err, res) => { + if (err) return done(err); + expect(res.body.error).toBeDefined(); + done(); + }); + }); +});