diff --git a/api/controller.js b/api/controller.js index 949731c..5def039 100644 --- a/api/controller.js +++ b/api/controller.js @@ -1,7 +1,7 @@ 'use strict'; -exports.calculate = function(req, res) { - req.app.use(function(err, _req, res, next) { +exports.calculate = function (req, res) { + req.app.use(function (err, _req, res, next) { if (res.headersSent) { return next(err); } @@ -10,12 +10,14 @@ exports.calculate = function(req, res) { res.json({ error: err.message }); }); - // TODO: Add operator var operations = { - 'add': function(a, b) { return Number(a) + Number(b) }, - 'subtract': function(a, b) { return a - b }, - 'multiply': function(a, b) { return a * b }, - 'divide': function(a, b) { return a / b }, + 'add': function (a, b) { return Number(a) + Number(b) }, + 'subtract': function (a, b) { return a - b }, + 'multiply': function (a, b) { return a * b }, + 'divide': function (a, b) { return a / b }, + 'power': function (a, b) { return Math.pow(a, b) }, + 'toBinary': function (a) { return parseInt(a).toString(2) }, + 'toDecimal': function (a) { return parseInt(a, 2).toString() } }; if (!req.query.operation) { @@ -28,17 +30,26 @@ exports.calculate = function(req, res) { throw new Error("Invalid operation: " + req.query.operation); } + // Validate operand1 for all operations if (!req.query.operand1 || - !req.query.operand1.match(/^(-)?[0-9\.]+(e(-)?[0-9]+)?$/) || - req.query.operand1.replace(/[-0-9e]/g, '').length > 1) { + !req.query.operand1.match(/^(-)?[0-9\.]+(e(-)?[0-9]+)?$/) || + req.query.operand1.replace(/[-0-9e]/g, '').length > 1) { throw new Error("Invalid operand1: " + req.query.operand1); } - if (!req.query.operand2 || + // Only validate operand2 for operations that need it + if (!['toBinary', 'toDecimal'].includes(req.query.operation)) { + if (!req.query.operand2 || !req.query.operand2.match(/^(-)?[0-9\.]+(e(-)?[0-9]+)?$/) || req.query.operand2.replace(/[-0-9e]/g, '').length > 1) { - throw new Error("Invalid operand2: " + req.query.operand2); + throw new Error("Invalid operand2: " + req.query.operand2); + } } - res.json({ result: operation(req.query.operand1, req.query.operand2) }); + // Call operation with appropriate number of arguments + const result = ['toBinary', 'toDecimal'].includes(req.query.operation) + ? operation(req.query.operand1) + : operation(req.query.operand1, req.query.operand2); + + res.json({ result: result }); }; diff --git a/public/client.js b/public/client.js index 1c60f86..4aed2a1 100644 --- a/public/client.js +++ b/public/client.js @@ -17,21 +17,30 @@ var operand2 = 0; var operation = null; function calculate(operand1, operand2, operation) { - var uri = location.origin + "/arithmetic"; + var uri = location.origin + "/arithmetic?operation="; // TODO: Add operator switch (operation) { case '+': - uri += "?operation=add"; + uri += "add"; break; case '-': - uri += "?operation=subtract"; + uri += "subtract"; break; case '*': - uri += "?operation=multiply"; + uri += "multiply"; break; case '/': - uri += "?operation=divide"; + uri += "divide"; + break; + case '^': + uri += "power"; + break; + case 'bin': + uri += "toBinary"; + break; + case 'dec': + uri += "toDecimal"; break; default: setError(); @@ -39,7 +48,10 @@ function calculate(operand1, operand2, operation) { } uri += "&operand1=" + encodeURIComponent(operand1); - uri += "&operand2=" + encodeURIComponent(operand2); + // Only add operand2 for non-conversion operations + if (!['bin', 'dec'].includes(operation)) { + uri += "&operand2=" + encodeURIComponent(operand2); + } setLoading(true); @@ -111,9 +123,16 @@ function signPressed() { } function operationPressed(op) { - operand1 = getValue(); - operation = op; - state = states.operator; + if (op === 'bin' || op === 'dec') { + // For binary conversion, immediately calculate with current value + operand1 = getValue(); + calculate(operand1, null, op); + state = states.complete; + } else { + operand1 = getValue(); + operation = op; + state = states.operator; + } } function equalPressed() { diff --git a/public/index.html b/public/index.html index 400c454..1fec505 100644 --- a/public/index.html +++ b/public/index.html @@ -1,8 +1,11 @@ Calculator - - + + @@ -11,7 +14,7 @@
0
- +
@@ -23,7 +26,9 @@ - + @@ -41,6 +46,12 @@ + + + + + +
diff --git a/test/arithmetic.test.js b/test/arithmetic.test.js index deded48..5db2284 100644 --- a/test/arithmetic.test.js +++ b/test/arithmetic.test.js @@ -93,15 +93,12 @@ describe('Arithmetic', function () { }); }); -// TODO: Challenge #1 - - - describe('Multiplication', function () { - it('multiplies two positive integers', function (done) { - request.get('/arithmetic?operation=multiply&operand1=21&operand2=2') + describe('Subtraction', function () { + it('subtracts two positive integers', function (done) { + request.get('/arithmetic?operation=subtract&operand1=42&operand2=21') .expect(200) .end(function (err, res) { - expect(res.body).to.eql({ result: 42 }); + expect(res.body).to.eql({ result: 21 }); done(); }); }); @@ -147,6 +144,37 @@ describe('Arithmetic', function () { }); }); + describe('Power', function () { + it('raises a positive integer to a positive integer exponent', function (done) { + request.get('/arithmetic?operation=power&operand1=2&operand2=3') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: 8 }); + done(); + }); + }) + }); + + describe('Binary Conversion', function () { + it('converts decimal to binary', function (done) { + request.get('/arithmetic?operation=toBinary&operand1=42') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: "101010" }); + done(); + }); + }); + + it('converts binary to decimal', function (done) { + request.get('/arithmetic?operation=toDecimal&operand1=101010') + .expect(200) + .end(function (err, res) { + expect(res.body).to.eql({ result: "42" }); + done(); + }); + }); + }); + describe('Division', function () { it('divides a positive integer by an integer factor ', function (done) { request.get('/arithmetic?operation=divide&operand1=42&operand2=2')