From 7e2150cf0be171400b8aa3dd6def37f5a476f5b4 Mon Sep 17 00:00:00 2001 From: System Date: Sat, 18 Feb 2017 19:14:10 +0000 Subject: [PATCH] Initial commit from Gomix. --- .bashrc | 111 ++++++++++++++++++++++++++++ .gitconfig | 2 + .hyperdev-assets | 5 ++ .profile | 17 +++++ README.md | 11 ++- assertion-analyser.js | 131 ++++++++++++++++++++++++++++++++++ controllers/convertHandler.js | 52 ++++++++++++++ package.json | 36 ++++++++++ public/style.css | 0 routes/api.js | 30 ++++++++ routes/fcctesting.js | 103 ++++++++++++++++++++++++++ server.js | 57 +++++++++++++++ test-runner.js | 106 +++++++++++++++++++++++++++ tests/1_unit-tests.js | 127 ++++++++++++++++++++++++++++++++ tests/2_functional-tests.js | 60 ++++++++++++++++ views/index.html | 75 +++++++++++++++++++ 16 files changed, 921 insertions(+), 2 deletions(-) create mode 100644 .bashrc create mode 100644 .gitconfig create mode 100644 .hyperdev-assets create mode 100644 .profile create mode 100644 assertion-analyser.js create mode 100644 controllers/convertHandler.js create mode 100644 package.json create mode 100644 public/style.css create mode 100644 routes/api.js create mode 100644 routes/fcctesting.js create mode 100644 server.js create mode 100644 test-runner.js create mode 100644 tests/1_unit-tests.js create mode 100644 tests/2_functional-tests.js create mode 100644 views/index.html diff --git a/.bashrc b/.bashrc new file mode 100644 index 00000000..d4d528c7 --- /dev/null +++ b/.bashrc @@ -0,0 +1,111 @@ +# ~/.bashrc: executed by bash(1) for non-login shells. +# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) +# for examples + +# If not running interactively, don't do anything +case $- in + *i*) ;; + *) return;; +esac + +# don't put duplicate lines or lines starting with space in the history. +# See bash(1) for more options +HISTCONTROL=ignoreboth + +# append to the history file, don't overwrite it +shopt -s histappend + +# for setting history length see HISTSIZE and HISTFILESIZE in bash(1) +HISTSIZE=1000 +HISTFILESIZE=2000 + +# check the window size after each command and, if necessary, +# update the values of LINES and COLUMNS. +shopt -s checkwinsize + +# If set, the pattern "**" used in a pathname expansion context will +# match all files and zero or more directories and subdirectories. +#shopt -s globstar + +# make less more friendly for non-text input files, see lesspipe(1) +[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" + +# set variable identifying the chroot you work in (used in the prompt below) +if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) +fi + +# set a fancy prompt (non-color, unless we know we "want" color) +case "$TERM" in + xterm-color|*-256color) color_prompt=yes;; +esac + +# uncomment for a colored prompt, if the terminal has the capability; turned +# off by default to not distract the user: the focus in a terminal window +# should be on the output of commands, not on the prompt +#force_color_prompt=yes + +if [ -n "$force_color_prompt" ]; then + if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then + # We have color support; assume it's compliant with Ecma-48 + # (ISO/IEC-6429). (Lack of such support is extremely rare, and such + # a case would tend to support setf rather than setaf.) + color_prompt=yes + else + color_prompt= + fi +fi +if [ "$color_prompt" = yes ]; then + PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@${PROJECT_NAME}\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' +else + PS1='${debian_chroot:+($debian_chroot)}\u@${PROJECT_NAME}:\w\$ ' +fi +unset color_prompt force_color_prompt +# If this is an xterm set the title to user@host:dir +case "$TERM" in +xterm*|rxvt*) + PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" + ;; +*) + ;; +esac +# enable color support of ls and also add handy aliases +if [ -x /usr/bin/dircolors ]; then + test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" + alias ls='ls --color=auto' + #alias dir='dir --color=auto' + #alias vdir='vdir --color=auto' + alias grep='grep --color=auto' + alias fgrep='fgrep --color=auto' + alias egrep='egrep --color=auto' +fi +# colored GCC warnings and errors +#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' +# some more ls aliases +alias ll='ls -alF' +alias la='ls -A' +alias l='ls -CF' +# Add an "alert" alias for long running commands. Use like so: +# sleep 10; alert +alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s +/[;&|]\s*alert$//'\'')"' +# Alias definitions. +# You may want to put all your additions into a separate file like +# ~/.bash_aliases, instead of adding them here directly. +# See /usr/share/doc/bash-doc/examples in the bash-doc package. +if [ -f ~/.bash_aliases ]; then + . ~/.bash_aliases +fi +# enable programmable completion features (you don't need to enable +# this, if it's already enabled in /etc/bash.bashrc and /etc/profile +# sources /etc/bash.bashrc). +if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi +fi + +export NVM_DIR="/home/nvm/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 00000000..07b56d1f --- /dev/null +++ b/.gitconfig @@ -0,0 +1,2 @@ +[core] + excludesfile = /etc/.gitignore-global diff --git a/.hyperdev-assets b/.hyperdev-assets new file mode 100644 index 00000000..4d4c4f57 --- /dev/null +++ b/.hyperdev-assets @@ -0,0 +1,5 @@ +{"name":"drag-in-files.svg","date":"2016-10-22T16:17:49.954Z","url":"https://cdn.hyperdev.com/drag-in-files.svg","type":"image/svg","size":7646,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/drag-in-files.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(102, 153, 205)","uuid":"adSBq97hhhpFNUna"} +{"name":"click-me.svg","date":"2016-10-23T16:17:49.954Z","url":"https://cdn.hyperdev.com/click-me.svg","type":"image/svg","size":7116,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/click-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(243, 185, 186)","uuid":"adSBq97hhhpFNUnb"} +{"name":"paste-me.svg","date":"2016-10-24T16:17:49.954Z","url":"https://cdn.hyperdev.com/paste-me.svg","type":"image/svg","size":7242,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/paste-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(42, 179, 185)","uuid":"adSBq97hhhpFNUnc"} +{"name":"Screen Shot 2016-12-16 at 1.35.56 AM.png","date":"2016-12-16T06:36:32.934Z","url":"https://cdn.gomix.com/d7932c52-287f-4dae-b175-631fef453000%2FScreen%20Shot%202016-12-16%20at%201.35.56%20AM.png","type":"image/png","size":18223,"imageWidth":499,"imageHeight":80,"thumbnail":"https://cdn.gomix.com/d7932c52-287f-4dae-b175-631fef453000%2Fthumbnails%2FScreen%20Shot%202016-12-16%20at%201.35.56%20AM.png","thumbnailWidth":330,"thumbnailHeight":53,"dominantColor":"rgb(236,236,236)","uuid":"IHJDL7lzupnoDep4"} +{"uuid":"IHJDL7lzupnoDep4","deleted":true} diff --git a/.profile b/.profile new file mode 100644 index 00000000..bb9ebbb3 --- /dev/null +++ b/.profile @@ -0,0 +1,17 @@ +# ~/.profile: executed by the command interpreter for login shells. +# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login +# exists. +# see /usr/share/doc/bash/examples/startup-files for examples. +# the files are located in the bash-doc package. +# the default umask is set in /etc/profile; for setting the umask +# for ssh logins, install and configure the libpam-umask package. +#umask 022 +# if running bash +if [ -n "$BASH_VERSION" ]; then + # include .bashrc if it exists + if [ -f "$HOME/.bashrc" ]; then + . "$HOME/.bashrc" + fi +fi +# set PATH so it includes user's private bin directories +PATH="$HOME/bin:$HOME/.local/bin:$HOME/node_modules/.bin:$PATH" diff --git a/README.md b/README.md index 999edd11..5eed063d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ -# boilerplate-project-metricimpconverter -A boilerplate for a freeCodeCamp project. +**FreeCodeCamp**- Information Security and Quality Assurance +------ + +1) SET NODE_ENV to `test` without quotes +2) Most logic will need done in `controllers/convertHandler.js` but do complete `routes/api.js` +3) You will add any security features to `server.js` +4) You will create all of the functional/unit tests in `tests/2_functional-tests.js` and `tests/1_unit-tests.js` + + diff --git a/assertion-analyser.js b/assertion-analyser.js new file mode 100644 index 00000000..dd5682bd --- /dev/null +++ b/assertion-analyser.js @@ -0,0 +1,131 @@ +/* +* +* +* +* +* +* +* +* +* +* +* +* DO NOT EDIT THIS FILE +* For FCC testing purposes! +* +* +* +* +* +* +* +* +* +* +* +*/ + +function objParser(str, init) { + // finds objects, arrays, strings, and function arguments + // between parens, because they may contain ',' + var openSym = ['[', '{', '"', "'", '(']; + var closeSym = [']', '}', '"', "'", ')']; + var type; + for(var i = (init || 0); i < str.length; i++ ) { + type = openSym.indexOf(str[i]); + if( type !== -1) break; + } + if (type === -1) return null; + var open = openSym[type]; + var close = closeSym[type]; + var count = 1; + for(var k = i+1; k < str.length; k++) { + if(open === '"' || open === "'") { + if(str[k] === close) count--; + if(str[k] === '\\') k++; + } else { + if(str[k] === open) count++; + if(str[k] === close) count--; + } + if(count === 0) break; + } + if(count !== 0) return null; + var obj = str.slice(i, k+1); + return { + start : i, + end: k, + obj: obj + }; +} + +function replacer(str) { + // replace objects with a symbol ( __#n) + var obj; + var cnt = 0; + var data = []; + while(obj = objParser(str)) { + data[cnt] = obj.obj; + str = str.substring(0, obj.start) + '__#' + cnt++ + str.substring(obj.end+1) + } + return { + str : str, + dictionary : data + } +} + +function splitter(str) { + // split on commas, then restore the objects + var strObj = replacer(str); + var args = strObj.str.split(','); + args = args.map(function(a){ + var m = a.match(/__#(\d+)/); + while (m) { + a = a.replace(/__#(\d+)/, strObj.dictionary[m[1]]); + m = a.match(/__#(\d+)/); + } + return a.trim(); + }) + return args; +} + +function assertionAnalyser(body) { + + // already filtered in the test runner + // // remove comments + // body = body.replace(/\/\/.*\n|\/\*.*\*\//g, ''); + // // get test function body + // body = body.match(/\{\s*([\s\S]*)\}\s*$/)[1]; + + if(!body) return "invalid assertion"; + // replace assertions bodies, so that they cannot + // contain the word 'assertion' + + var body = body.match(/(?:browser\s*\.\s*)?assert\s*\.\s*\w*\([\s\S]*\)/)[0]; + var s = replacer(body); + // split on 'assertion' + var splittedAssertions = s.str.split('assert'); + var assertions = splittedAssertions.slice(1); + // match the METHODS + + var assertionBodies = []; + var methods = assertions.map(function(a, i){ + var m = a.match(/^\s*\.\s*(\w+)__#(\d+)/); + assertionBodies.push(parseInt(m[2])); + var pre = splittedAssertions[i].match(/browser\s*\.\s*/) ? 'browser.' : ''; + return pre + m[1]; + }); + if(methods.some(function(m){ return !m })) return "invalid assertion"; + // remove parens from the assertions bodies + var bodies = assertionBodies.map(function(b){ + return s.dictionary[b].slice(1,-1).trim(); + }); + assertions = methods.map(function(m, i) { + return { + method: m, + args: splitter(bodies[i]) //replace objects, split on ',' ,then restore objects + } + }) + return assertions; +} + +module.exports = assertionAnalyser; diff --git a/controllers/convertHandler.js b/controllers/convertHandler.js new file mode 100644 index 00000000..490ad192 --- /dev/null +++ b/controllers/convertHandler.js @@ -0,0 +1,52 @@ +/* +* +* +* Complete the handler logic below +* +* +*/ + +function ConvertHandler() { + + this.getNum = function(input) { + var result; + + return result; + }; + + this.getUnit = function(input) { + var result; + + return result; + }; + + this.getReturnUnit = function(initUnit) { + var result; + + return result; + }; + + this.spellOutUnit = function(unit) { + var result; + + return result; + }; + + this.convert = function(initNum, initUnit) { + const galToL = 3.78541; + const lbsToKg = 0.453592; + const miToKm = 1.60934; + var result; + + return result; + }; + + this.getString = function(initNum, initUnit, returnNum, returnUnit) { + var result; + + return result; + }; + +} + +module.exports = ConvertHandler; diff --git a/package.json b/package.json new file mode 100644 index 00000000..c6c1cf8b --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "//1": "describes your app and its dependencies", + "//2": "https://docs.npmjs.com/files/package.json", + "//3": "updating this file will download and update your packages", + "name": "my-hyperdev-app", + "version": "0.0.1", + "description": "What am I about?", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "express": "^4.14.0", + "cors": "^2.8.1", + "body-parser": "^1.15.2", + "chai": "^3.5.0", + "mongodb": "^2.2.16", + "chai-http": "^3.0.0", + "mocha": "^3.2.0", + "zombie": "^5.0.5", + "helmet": "^3.1.0" + }, + "engines": { + "node": "4.4.3" + }, + "repository": { + "type": "git", + "url": "https://hyperdev.com/#!/project/welcome-project" + }, + "keywords": [ + "node", + "hyperdev", + "express" + ], + "license": "MIT" +} \ No newline at end of file diff --git a/public/style.css b/public/style.css new file mode 100644 index 00000000..e69de29b diff --git a/routes/api.js b/routes/api.js new file mode 100644 index 00000000..efa968d1 --- /dev/null +++ b/routes/api.js @@ -0,0 +1,30 @@ +/* +* +* +* Complete the API routing below +* +* +*/ + +'use strict'; + +var expect = require('chai').expect; +var ConvertHandler = require('../controllers/convertHandler.js'); + +module.exports = function (app) { + + var convertHandler = new ConvertHandler(); + + app.route('/api/convert') + .get(function (req, res){ + var input = req.query.input; + var initNum = convertHandler.getNum(input); + var initUnit = convertHandler.getUnit(input); + var returnNum = convertHandler.convert(initNum, initUnit); + var returnUnit = convertHandler.getReturnUnit(initUnit); + var toString = convertHandler.getString(initNum, initUnit, returnNum, returnUnit); + + //res.json + }); + +}; diff --git a/routes/fcctesting.js b/routes/fcctesting.js new file mode 100644 index 00000000..f1af2775 --- /dev/null +++ b/routes/fcctesting.js @@ -0,0 +1,103 @@ +/* +* +* +* +* +* +* +* +* +* +* +* +* DO NOT EDIT THIS FILE +* For FCC testing purposes! +* +* +* +* +* +* +* +* +* +* +* +*/ + +'use strict'; + +var cors = require('cors'); +var fs = require('fs'); +var runner = require('../test-runner'); + +module.exports = function (app) { + + app.route('/_api/server.js') + .get(function(req, res, next) { + console.log('requested'); + fs.readFile(__dirname + '/server.js', function(err, data) { + if(err) return next(err); + res.send(data.toString()); + }); + }); + app.route('/_api/routes/api.js') + .get(function(req, res, next) { + console.log('requested'); + fs.readFile(__dirname + '/routes/api.js', function(err, data) { + if(err) return next(err); + res.type('txt').send(data.toString()); + }); + }); + app.route('/_api/controllers/convertHandler.js') + .get(function(req, res, next) { + console.log('requested'); + fs.readFile(__dirname + '/controllers/convertHandler.js', function(err, data) { + if(err) return next(err); + res.type('txt').send(data.toString()); + }); + }); + + var error; + app.get('/_api/get-tests', cors(), function(req, res, next){ + console.log(error); + if(!error && process.env.NODE_ENV === 'test') return next(); + res.json({status: 'unavailable'}); + }, + function(req, res, next){ + if(!runner.report) return next(); + res.json(testFilter(runner.report, req.query.type, req.query.n)); + }, + function(req, res){ + runner.on('done', function(report){ + process.nextTick(() => res.json(testFilter(runner.report, req.query.type, req.query.n))); + }); + }); + app.get('/_api/app-info', function(req, res) { + var hs = Object.keys(res._headers) + .filter(h => !h.match(/^access-control-\w+/)); + var hObj = {}; + hs.forEach(h => {hObj[h] = res._headers[h]}); + delete res._headers['strict-transport-security']; + res.json({headers: hObj}); + }); + +}; + +function testFilter(tests, type, n) { + var out; + switch (type) { + case 'unit' : + out = tests.filter(t => t.context.match('Unit Tests')); + break; + case 'functional': + out = tests.filter(t => t.context.match('Functional Tests') && !t.title.match('#example')); + break; + default: + out = tests; + } + if(n !== undefined) { + return out[n] || out; + } + return out; +} \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 00000000..a731619f --- /dev/null +++ b/server.js @@ -0,0 +1,57 @@ +'use strict'; + +var express = require('express'); +var bodyParser = require('body-parser'); +var expect = require('chai').expect; +var cors = require('cors'); + +var apiRoutes = require('./routes/api.js'); +var fccTestingRoutes = require('./routes/fcctesting.js'); +var runner = require('./test-runner'); + +var app = express(); + +app.use('/public', express.static(process.cwd() + '/public')); + +app.use(cors({origin: '*'})); //For FCC testing purposes only + +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +//Index page (static HTML) +app.route('/') + .get(function (req, res) { + res.sendFile(process.cwd() + '/views/index.html'); + }); + +//For FCC testing purposes +fccTestingRoutes(app); + +//Routing for API +apiRoutes(app); + +//404 Not Found Middleware +app.use(function(req, res, next) { + res.status(404) + .type('text') + .send('Not Found'); +}); + +//Start our server and tests! +app.listen(process.env.PORT || 3000, function () { + console.log("Listening on port " + process.env.PORT); + if(process.env.NODE_ENV==='test') { + console.log('Running Tests...'); + setTimeout(function () { + try { + runner.run(); + } catch(e) { + var error = e; + console.log('Tests are not valid:'); + console.log(error); + } + }, 1500); + } +}); + +module.exports = app; //for testing diff --git a/test-runner.js b/test-runner.js new file mode 100644 index 00000000..06cfad53 --- /dev/null +++ b/test-runner.js @@ -0,0 +1,106 @@ +/* +* +* +* +* +* +* +* +* +* +* +* +* DO NOT EDIT THIS FILE +* For FCC testing purposes! +* +* +* +* +* +* +* +* +* +* +* +*/ + +var analyser = require('./assertion-analyser'); +var EventEmitter = require('events').EventEmitter; + +var Mocha = require('mocha'), + fs = require('fs'), + path = require('path'); + +var mocha = new Mocha(); +var testDir = './tests' + + +// Add each .js file to the mocha instance +fs.readdirSync(testDir).filter(function(file){ + // Only keep the .js files + return file.substr(-3) === '.js'; + +}).forEach(function(file){ + mocha.addFile( + path.join(testDir, file) + ); +}); + +var emitter = new EventEmitter(); +emitter.run = function() { + + var tests = []; + var context = ""; + var separator = ' -> '; + // Run the tests. + try { + var runner = mocha.ui('tdd').run() + .on('test end', function(test) { + // remove comments + var body = test.body.replace(/\/\/.*\n|\/\*.*\*\//g, ''); + // collapse spaces + body = body.replace(/\s+/g,' '); + var obj = { + title: test.title, + context: context.slice(0, -separator.length), + state: test.state, + // body: body, + assertions: analyser(body) + }; + tests.push(obj); + }) + .on('end', function() { + emitter.report = tests; + emitter.emit('done', tests) + }) + .on('suite', function(s) { + context += (s.title + separator); + + }) + .on('suite end', function(s) { + context = context.slice(0, -(s.title.length + separator.length)) + }) + } catch(e) { + throw(e); + } +}; + +module.exports = emitter; + +/* + * Mocha.runner Events: + * can be used to build a better custom report + * + * - `start` execution started + * - `end` execution complete + * - `suite` (suite) test suite execution started + * - `suite end` (suite) all tests (and sub-suites) have finished + * - `test` (test) test execution started + * - `test end` (test) test completed + * - `hook` (hook) hook execution started + * - `hook end` (hook) hook complete + * - `pass` (test) test passed + * - `fail` (test, err) test failed + * - `pending` (test) test pending + */ \ No newline at end of file diff --git a/tests/1_unit-tests.js b/tests/1_unit-tests.js new file mode 100644 index 00000000..7f348a09 --- /dev/null +++ b/tests/1_unit-tests.js @@ -0,0 +1,127 @@ +/* +* +* +* FILL IN EACH UNIT TEST BELOW COMPLETELY +* -----[Keep the tests in the same order!]---- +* (if additional are added, keep them at the very end!) +*/ + +var chai = require('chai'); +var assert = chai.assert; +var ConvertHandler = require('../controllers/convertHandler.js'); + +var convertHandler = new ConvertHandler(); + +suite('Unit Tests', function(){ + + suite('Function convertHandler.getNum(input)', function() { + + test('Whole number input', function(done) { + var input = '32L'; + assert.equal(convertHandler.getNum(input),32); + done(); + }); + + test('Decimal Input', function(done) { + + //done(); + }); + + test('Fractional Input', function(done) { + + //done(); + }); + + test('Fractional Input w/ Decimal', function(done) { + + //done(); + }); + + test('Invalid Input (double fraction)', function(done) { + + //done(); + }); + + test('No Numerical Input', function(done) { + + //done(); + }); + + }); + + suite('Function convertHandler.getUnit(input)', function() { + + test('For Each Valid Unit Inputs', function(done) { + var input = ['gal','l','mi','km','lbs','kg','GAL','L','MI','KM','LBS','KG']; + input.forEach(function(ele) { + //assert + }); + done(); + }); + + test('Unknown Unit Input', function(done) { + + //done(); + }); + + }); + + suite('Function convertHandler.getReturnUnit(initUnit)', function() { + + test('For Each Valid Unit Inputs', function(done) { + var input = ['gal','l','mi','km','lbs','kg']; + var expect = ['l','gal','km','mi','kg','lbs']; + input.forEach(function(ele, i) { + assert.equal(convertHandler.getReturnUnit(ele), expect[i]); + }); + done(); + }); + + }); + + suite('Function convertHandler.spellOutUnit(unit)', function() { + + test('For Each Valid Unit Inputs', function(done) { + //see above example for hint + done(); + }); + + }); + + suite('Function convertHandler.convert(num, unit)', function() { + + test('Gal to L', function(done) { + var input = [5, 'gal']; + var expected = 18.9271; + assert.approximately(convertHandler.convert(input[0],input[1]),expected,0.1); //0.1 tolerance + done(); + }); + + test('L to Gal', function(done) { + + //done(); + }); + + test('Mi to Km', function(done) { + + //done(); + }); + + test('Km to Mi', function(done) { + + //done(); + }); + + test('Lbs to Kg', function(done) { + + //done(); + }); + + test('Kg to Lbs', function(done) { + + //done(); + }); + + }); + +}); \ No newline at end of file diff --git a/tests/2_functional-tests.js b/tests/2_functional-tests.js new file mode 100644 index 00000000..e893a611 --- /dev/null +++ b/tests/2_functional-tests.js @@ -0,0 +1,60 @@ +/* +* +* +* FILL IN EACH FUNCTIONAL TEST BELOW COMPLETELY +* -----[Keep the tests in the same order!]----- +* (if additional are added, keep them at the very end!) +*/ + +var chaiHttp = require('chai-http'); +var chai = require('chai'); +var assert = chai.assert; +var server = require('../server'); + +chai.use(chaiHttp); + +suite('Functional Tests', function() { + + suite('Routing Tests', function() { + + suite('GET /api/convert => conversion object', function() { + + test('Convert 10L (valid input)', function(done) { + chai.request(server) + .get('/api/convert') + .query({input: '10L'}) + .end(function(err, res){ + assert.equal(res.status, 200); + assert.equal(res.body.initNum, 10); + assert.equal(res.body.initUnit, 'L'); + assert.approximately(res.body.returnNum, 2.64172, 0.1); + assert.equal(res.body.returnUnit, 'gal'); + done(); + }); + }); + + test('Convert 32g (invalid input unit)', function(done) { + + //done(); + }); + + test('Convert 3/7.2/4kg (invalid number)', function(done) { + + //done(); + }); + + test('Convert 3/7.2/4kilomegagram (invalid number and unit)', function(done) { + + //done(); + }); + + test('Convert kg (no number)', function(done) { + + //done(); + }); + + }); + + }); + +}); diff --git a/views/index.html b/views/index.html new file mode 100644 index 00000000..ae29d0e8 --- /dev/null +++ b/views/index.html @@ -0,0 +1,75 @@ + + + + Welcome to HyperDev! + + + + + + + + +
+

+ ISQA_2 - Metric/Imp Converter +

+
+
+

User Stories

+
    +
  1. I will help prevent the client from trying to guess(sniff) the MIME type.
  2. +
  3. I will prevent cross-site scripting (XSS) attacks.
  4. +
  5. I can GET /api/convert with a single parameter containing an accepted number and unit and have it converted.
  6. +
  7. Hint: Split the input by looking for the index of the first character.
  8. +
  9. I can convert 'gal' to 'L' and vice versa. (1 gal to 3.78541 L)
  10. +
  11. I can convert 'lbs' to 'kg' and vice versa. (1 lbs to 0.453592 kg)
  12. +
  13. I can convert 'mi' to 'km' and vice versa. (1 mi to 1.60934 km)
  14. +
  15. If my unit of measurement is invalid, returned will be 'invalid unit'.
  16. +
  17. If my number is invalid, returned with will 'invalid number'.
  18. +
  19. If both are invalid, return will be 'invalid number and unit'.
  20. +
  21. I can use fractions, decimals or both in my parameter(ie. 5, 1/2, 2.5/6), but if nothing is provided it will default to 1.
  22. +
  23. My return will consist of the initNum, initUnit, returnNum, returnUnit, and string spelling out units in format {initNum} {initial_Units} converts to {returnNum} {return_Units} with the result rounded to 5 decimals.
  24. +
  25. All 16 unit tests are complete and passing.
  26. +
  27. All 5 functional tests are complete and passing.
  28. +
+

Example usage:

+ /api/convert?input=4gal
+ /api/convert?input=1/2km
+ /api/convert?input=5.4/3lbs
+ /api/convert?input=kg
+

Example return:

+ {initNum: 3.1, initUnit: 'mi', returnNum: 5.0000008, returnUnit: 'km', string: '3.1 miles converts to 5.00002 kilometers'} +
+
+
+

Front-End:

+
+ + +
+

+ +
+
+ + + + +