diff --git a/.gitignore b/.gitignore index 3d3f1a253..8fe47d869 100644 --- a/.gitignore +++ b/.gitignore @@ -66,4 +66,6 @@ typings/ out/ -newmanResponses.json \ No newline at end of file +newmanResponses.json + +dummyFile* \ No newline at end of file diff --git a/codegens/arduino/.gitignore b/codegens/arduino/.gitignore new file mode 100644 index 000000000..f92058a8b --- /dev/null +++ b/codegens/arduino/.gitignore @@ -0,0 +1,66 @@ +.DS_Store +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Prevent IDE stuff +.idea +.vscode +*.sublime-* + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +.coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +out/ \ No newline at end of file diff --git a/codegens/arduino/.npmignore b/codegens/arduino/.npmignore new file mode 100644 index 000000000..79ad2ba5f --- /dev/null +++ b/codegens/arduino/.npmignore @@ -0,0 +1,76 @@ +### NPM Specific: Disregard recursive project files +### =============================================== +/.editorconfig +/.gitmodules +/test + +### Borrowed from .gitignore +### ======================== + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Prevent IDE stuff +.idea +.vscode +*.sublime-* + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +.coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +snippet.swift + +out/ diff --git a/codegens/arduino/README.md b/codegens/arduino/README.md new file mode 100644 index 000000000..8a9ec02f5 --- /dev/null +++ b/codegens/arduino/README.md @@ -0,0 +1,66 @@ +# codegen-arduino + +> Converts Postman-SDK Request into code snippet for [Arduino](https://www.arduino.cc/en/Guide/Introduction) code. + +#### Prerequisites +To run Code-Gen, ensure that you have NodeJS >= v8. A copy of the NodeJS installable can be downloaded from + +## Using the Module +The module will expose an object which will have property `convert` which is the function for converting the Postman-SDK request to HTTP spec and `getOptions` function which returns an array of supported options. + +### convert function +Convert function takes three parameters + +* `request` - Postman-SDK Request Object + +* `options` - options is an object which has following properties + * `trimRequestBody` - Trim request body fields + +* `callback` - callback function with first parameter as error and second parameter as string for code snippet + + +##### Example: +```js +var request = new sdk.Request('www.example.com'), //using postman sdk to create request + options = {}; +convert(request, options, function(error, snippet) { + if (error) { + console.error(error); + return; + } + console.log(snippet) +}); +``` +### getOptions function + +This function returns a list of options supported by this codegen. + +#### Example +```js +var options = getOptions(); + +console.log(options); +// output +// [ +// { +// name: 'Trim request body fields', +// id: 'trimRequestBody', +// type: 'boolean', +// default: false, +// description: "Remove white space and additional lines that may affect the server's response" +// }, +// { +// name: 'WiFi Library', +// id: 'arduinoWifiLibrary', +// type: 'string', +// default: 'WiFiNINA', +// description: 'The Wifi library your Arduino is using, supported values are WiFiNINA|WiFi101|WiFi' +// } +// ] +``` +### Guidelines for using generated snippet + +* Since Postman-SDK Request object doesn't provide complete path of the file, it needs to be manually inserted in case of uploading a file. + +* This module doesn't support cookies. + diff --git a/codegens/arduino/index.js b/codegens/arduino/index.js new file mode 100644 index 000000000..ede037fc0 --- /dev/null +++ b/codegens/arduino/index.js @@ -0,0 +1,6 @@ +let converter = require('./lib/converter'); + +module.exports = { + getOptions: converter.getOptions, + convert: converter.convert +}; diff --git a/codegens/arduino/lib/converter.js b/codegens/arduino/lib/converter.js new file mode 100644 index 000000000..6558e301a --- /dev/null +++ b/codegens/arduino/lib/converter.js @@ -0,0 +1,100 @@ +const utils = require('./util'), + httpCodegen = require('./../../http/index'); + +/** + * Used in order to get additional options for generation of C# code snippet (i.e. Include Boilerplate code) + * + * @module getOptions + * + * @returns {Array} Additional options specific to generation of http code snippet + */ +function getOptions () { + return [{ + name: 'Trim request body fields', + id: 'trimRequestBody', + type: 'boolean', + default: false, + description: 'Remove white space and additional lines that may affect the server\'s response' + }, + { + name: 'WiFi Library', + id: 'arduinoWifiLibrary', + type: 'string', + default: 'WiFiNINA', + description: 'The Wifi library your Arduino is using, supported values are WiFiNINA|WiFi101|WiFi' + }]; +} + +/** + * Converts a Postman SDK request to HTTP message + * + * @param {Object} request - Postman SDK request + * @param {Object} options - Options for converter + * @param {Boolean} options.trimRequestBody - determines whether to trim the body or not + * @param {String} options.arduinoWifiLibrary - determines the wifi library used. Default: WiFiNINA + * @param {Function} callback callback + * @returns {Function} returns the snippet with the callback function. + */ +function convert (request, options, callback) { + httpCodegen.convert(request, options, (error, httpSnippet) => { + const clientSnippet = utils.getClientHttpSnippet(httpSnippet), + port = utils.getPort(request), + host = utils.getHost(request); + + let wifiLibrary = 'WiFiNINA', + arduinoSnippet = ''; + if (['WiFi', 'WiFi101'].includes(options.wifiLibrary)) { + wifiLibrary = options.wifiLibrary; + } + + arduinoSnippet += '#include \n'; + arduinoSnippet += `#include <${wifiLibrary}.h>\n`; + arduinoSnippet += '\n'; + arduinoSnippet += 'char ssid[] = "myNetwork"; // your network SSID (name)\n'; + arduinoSnippet += 'char pass[] = "myPassword"; // your network password\n'; + arduinoSnippet += '\n'; + arduinoSnippet += 'int status = WL_IDLE_STATUS;\n'; + arduinoSnippet += `char server[] = "${host}";\n`; + arduinoSnippet += '\n'; + arduinoSnippet += 'WiFiClient client;\n'; + arduinoSnippet += '\n'; + arduinoSnippet += 'void setup() {\n'; + arduinoSnippet += ' Serial.begin(9600);\n'; + arduinoSnippet += ' Serial.println("Attempting to connect to WPA network...");\n'; + arduinoSnippet += ' Serial.print("SSID: ");\n'; + arduinoSnippet += ' Serial.println(ssid);\n'; + arduinoSnippet += '\n'; + arduinoSnippet += ' status = WiFi.begin(ssid, pass);\n'; + arduinoSnippet += ' if ( status != WL_CONNECTED) {\n'; + arduinoSnippet += ' Serial.println("Couldn\'t get a wifi connection");\n'; + arduinoSnippet += ' while(true);\n'; + arduinoSnippet += ' }\n'; + arduinoSnippet += ' else {\n'; + arduinoSnippet += ' Serial.println("Connected to wifi");\n'; + arduinoSnippet += ' Serial.println("\nStarting connection...");\n'; + arduinoSnippet += ` if (client.connect(server, ${port})) {\n`; + arduinoSnippet += ' Serial.println("connected");\n'; + arduinoSnippet += clientSnippet; + arduinoSnippet += ' }\n'; + arduinoSnippet += ' }\n'; + arduinoSnippet += '}\n'; + arduinoSnippet += '\n'; + arduinoSnippet += 'void loop() {\n'; + arduinoSnippet += ' printResponse();\n'; + arduinoSnippet += '}\n'; + arduinoSnippet += '\n'; + arduinoSnippet += 'void printResponse() {\n'; + arduinoSnippet += ' while (client.available()) {\n'; + arduinoSnippet += ' char c = client.read();\n'; + arduinoSnippet += ' Serial.write(c);\n'; + arduinoSnippet += ' }\n'; + arduinoSnippet += '}\n'; + + return callback(error, arduinoSnippet); + }); +} + +module.exports = { + getOptions: getOptions, + convert: convert +}; diff --git a/codegens/arduino/lib/lodash.js b/codegens/arduino/lib/lodash.js new file mode 100644 index 000000000..55ea6666d --- /dev/null +++ b/codegens/arduino/lib/lodash.js @@ -0,0 +1,456 @@ +/* istanbul ignore next */ +module.exports = { + + /** + * Checks if `value` is an empty object, array or string. + * + * Objects are considered empty if they have no own enumerable string keyed + * properties. + * + * Values such as strings, arrays are considered empty if they have a `length` of `0`. + * + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * isEmpty(null) + * // => true + * + * isEmpty(true) + * // => true + * + * isEmpty(1) + * // => true + * + * isEmpty([1, 2, 3]) + * // => false + * + * isEmpty('abc') + * // => false + * + * isEmpty({ 'a': 1 }) + * // => false + */ + isEmpty: function (value) { + // eslint-disable-next-line lodash/prefer-is-nil + if (value === null || value === undefined) { + return true; + } + if (Array.isArray(value) || typeof value === 'string' || typeof value.splice === 'function') { + return !value.length; + } + + for (const key in value) { + if (Object.prototype.hasOwnProperty.call(value, key)) { + return false; + } + } + + return true; + }, + + /** + * Checks if `value` is `undefined`. + * + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * isUndefined(void 0) + * // => true + * + * isUndefined(null) + * // => false + */ + isUndefined: function (value) { + return value === undefined; + }, + + /** + * Checks if `func` is classified as a `Function` object. + * + * @param {*} func The value to check. + * @returns {boolean} Returns `true` if `func` is a function, else `false`. + * @example + * + * isFunction(self.isEmpty) + * // => true + * + * isFunction(/abc/) + * // => false + */ + isFunction: function (func) { + return typeof func === 'function'; + }, + + /** + * Converts the first character of `string` to upper case and the remaining + * to lower case. + * + * @param {string} [string=''] The string to capitalize. + * @returns {string} Returns the capitalized string. + * @example + * + * capitalize('FRED') + * // => 'Fred' + * + * capitalize('john') + * // => 'John' + */ + + capitalize: function (string) { + return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); + }, + + /** + * Reduces `array` to a value which is the accumulated result of running + * each element in `array` thru `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not given, the first element of `array` is used as the initial + * value. The iteratee is invoked with four arguments: + * (accumulator, value, index|key, array). + * + * @param {Array} array The Array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @example + * + * reduce([1, 2], (sum, n) => sum + n, 0) + * // => 3 + * + */ + reduce: function (array, iteratee, accumulator) { + return array.reduce(iteratee, accumulator); + }, + + /** + * Iterates over elements of `array`, returning an array of all elements + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index, array). + * + * @param {Array} array The array to iterate over. + * @param {Function|object} predicate The function/object invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @example + * + * const users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ] + * + * filter(users, ({ active }) => active) + * // => object for ['barney'] + */ + filter: function (array, predicate) { + if (typeof predicate === 'function') { + return array.filter(predicate); + } + var key = Object.keys(predicate), + val = predicate[key], + res = []; + array.forEach(function (item) { + if (item[key] && item[key] === val) { + res.push(item); + } + }); + return res; + }, + + /** + * The opposite of `filter` this method returns the elements of `array` + * that `predicate` does **not** return truthy for. + * + * @param {Array} array collection to iterate over. + * @param {String} predicate The String that needs to have truthy value, invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @example + * + * const users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ] + * + * reject(users, 'active') + * // => object for ['fred'] + */ + reject: function (array, predicate) { + var res = []; + array.forEach((object) => { + if (!object[predicate]) { + res.push(object); + } + }); + return res; + }, + + /** + * Creates an array of values by running each element of `array` thru `iteratee`. + * The iteratee is invoked with three arguments: (value, index, array). + * + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + * @example + * + * function square(n) { + * return n * n + * } + * + * map([4, 8], square) + * // => [16, 64] + */ + map: function (array, iteratee) { + return array.map(iteratee); + }, + + /** + * Iterates over elements of `collection` and invokes `iteratee` for each element. + * The iteratee is invoked with three arguments: (value, index|key, collection). + * + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @example + * + * forEach([1, 2], value => console.log(value)) + * // => Logs `1` then `2`. + * + * forEach({ 'a': 1, 'b': 2 }, (value, key) => console.log(key)) + * // => Logs 'a' then 'b' + */ + + forEach: function (collection, iteratee) { + if (collection === null) { + return null; + } + + if (Array.isArray(collection)) { + return collection.forEach(iteratee); + } + const iterable = Object(collection), + props = Object.keys(collection); + var index = -1, + key, i; + + for (i = 0; i < props.length; i++) { + key = props[++index]; + iteratee(iterable[key], key, iterable); + } + return collection; + }, + + /** + * Checks if `value` is in `collection`. If `collection` is a string, it's + * checked for a substring of `value`, otherwise it checks if the `value` is present + * as a key in a `collection` object. + * + * @param {Array|Object|string} collection The collection to inspect. + * @param {*} value The value to search for. + * @returns {boolean} Returns `true` if `value` is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes({ 'a': 1, 'b': 2 }, 1); + * // => true + * + * _.includes('abcd', 'bc'); + * // => true + */ + includes: function (collection, value) { + if (Array.isArray(collection) || typeof collection === 'string') { + return collection.includes(value); + } + for (var key in collection) { + if (collection.hasOwnProperty(key)) { + if (collection[key] === value) { + return true; + } + } + } + return false; + }, + + /** + * Gets the size of `collection` by returning its length for array and strings. + * For objects it returns the number of enumerable string keyed + * properties. + * + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the collection size. + * @example + * + * size([1, 2, 3]) + * // => 3 + * + * size({ 'a': 1, 'b': 2 }) + * // => 2 + * + * size('pebbles') + * // => 7 + */ + size: function (collection) { + // eslint-disable-next-line lodash/prefer-is-nil + if (collection === null || collection === undefined) { + return 0; + } + if (Array.isArray(collection) || typeof collection === 'string') { + return collection.length; + } + + return Object.keys(collection).length; + }, + + /** + * Converts all elements in `array` into a string separated by `separator`. + * + * @param {Array} array The array to convert. + * @param {string} [separator=','] The element separator. + * @returns {string} Returns the joined string. + * @example + * + * _.join(['a', 'b', 'c'], '~'); + * // => 'a~b~c' + */ + join: function (array, separator) { + if (array === null) { + return ''; + } + return array.join(separator); + }, + + /** + * Removes trailing whitespace or specified characters from `string`. + * + * @param {string} [string=''] The string to trim. + * @param {string} [chars=whitespace] The characters to trim. + * @returns {string} Returns the trimmed string. + * @example + * + * trimEnd(' abc ') + * // => ' abc' + * + * trimEnd('-_-abc-_-', '_-') + * // => '-_-abc' + */ + trimEnd: function (string, chars) { + if (!string) { + return ''; + } + if (string && !chars) { + return string.replace(/\s*$/, ''); + } + chars += '$'; + return string.replace(new RegExp(chars, 'g'), ''); + }, + + /** + * Returns the index of the first + * element `predicate` returns truthy for. + * + * @param {Array} array The array to inspect. + * @param {Object} predicate The exact object to be searched for in the array. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.findIndex(users, { 'user': 'fred', 'active': false }); + * // => 1 + * + * _.findIndex(users, {'active' : false}); + * // => 0 + * + */ + findIndex: function (array, predicate) { + var length = array === null ? 0 : array.length, + index = -1, + keys = Object.keys(predicate), + found, i; + if (!length) { + return -1; + } + for (i = 0; i < array.length; i++) { + found = true; + // eslint-disable-next-line no-loop-func + keys.forEach((key) => { + if (!(array[i][key] && array[i][key] === predicate[key])) { + found = false; + } + }); + if (found) { + index = i; + break; + } + } + return index; + }, + + /** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @param {Object} object The object to query. + * @param {string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * const object = { a: {b : 'c'} } + * + * + * get(object, 'a.b.c', 'default') + * // => 'default' + * + * get(object, 'a.b', 'default') + * // => 'c' + */ + get: function (object, path, defaultValue) { + if (object === null) { + return undefined; + } + var arr = path.split('.'), + res = object, + i; + for (i = 0; i < arr.length; i++) { + res = res[arr[i]]; + if (res === undefined) { + return defaultValue; + } + } + return res; + }, + + /** + * Checks if `predicate` returns truthy for **all** elements of `array`. + * Iteration is stopped once `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * every([true, 1, null, 'yes'], Boolean) + * // => false + */ + every: function (array, predicate) { + var index = -1, + length = array === null ? 0 : array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; + } + +}; diff --git a/codegens/arduino/lib/util.js b/codegens/arduino/lib/util.js new file mode 100644 index 000000000..e66e334f4 --- /dev/null +++ b/codegens/arduino/lib/util.js @@ -0,0 +1,58 @@ +const _ = require('./lodash'); + +/** + * Get the client code snippet + * + * @param {String} httpSnippet - snippet of http messages + * @returns {String} returns the snippet. + */ +function getClientHttpSnippet (httpSnippet) { + let snippet = ''; + httpSnippet.split(/\n/).forEach((line) => { + snippet += ` client.println("${line}");\n`; + }); + return snippet; +} + +/** + * Get the host value from a request object + * + * @param {Object} request - Postman SDK request + * @returns {String} returns the host value. + */ +function getHost (request) { + if (typeof request.url === 'string' || request.url instanceof String) { + const url = new URL(request.url); + return url.hostname; + } + + return _.join(request.url.host, '.'); +} + +/** + * Get the target port of the request + * + * @param {Object} request - Postman SDK request + * @returns {String} returns the port value. + */ +function getPort (request) { + if (typeof request.url === 'string' || request.url instanceof String) { + const url = new URL(request.url); + if (url.port === '') { + return url.protocol === 'https:' ? '443' : '80'; + } + return url.port; + } + + if (request.url.port) { + return request.url.port; + } + + return request.url.protocol === 'https' ? '443' : '80'; +} + +module.exports = { + getClientHttpSnippet: getClientHttpSnippet, + getHost: getHost, + getPort: getPort +}; diff --git a/codegens/arduino/npm/test-lint.js b/codegens/arduino/npm/test-lint.js new file mode 100644 index 000000000..b113b8bfd --- /dev/null +++ b/codegens/arduino/npm/test-lint.js @@ -0,0 +1,58 @@ +#!/usr/bin/env node +var shell = require('shelljs'), + chalk = require('chalk'), + async = require('async'), + ESLintCLIEngine = require('eslint').CLIEngine, + + /** + * The list of source code files / directories to be linted. + * + * @type {Array} + */ + LINT_SOURCE_DIRS = [ + './lib', + './bin', + './test', + './examples/*.js', + './npm/*.js', + './index.js' + ]; + +module.exports = function (exit) { + // banner line + console.info(chalk.yellow.bold('\nLinting files using eslint...')); + + async.waterfall([ + + /** + * Instantiates an ESLint CLI engine and runs it in the scope defined within LINT_SOURCE_DIRS. + * + * @param {Function} next - The callback function whose invocation marks the end of the lint test run. + * @returns {*} + */ + function (next) { + next(null, (new ESLintCLIEngine()).executeOnFiles(LINT_SOURCE_DIRS)); + }, + + /** + * Processes a test report from the Lint test runner, and displays meaningful results. + * + * @param {Object} report - The overall test report for the current lint test. + * @param {Object} report.results - The set of test results for the current lint run. + * @param {Function} next - The callback whose invocation marks the completion of the post run tasks. + * @returns {*} + */ + function (report, next) { + var errorReport = ESLintCLIEngine.getErrorResults(report.results); + // log the result to CLI + console.info(ESLintCLIEngine.getFormatter()(report.results)); + // log the success of the parser if it has no errors + (errorReport && !errorReport.length) && console.info(chalk.green('eslint ok!')); + // ensure that the exit code is non zero in case there was an error + next(Number(errorReport && errorReport.length) || 0); + } + ], exit); +}; + +// ensure we run this script exports if this is a direct stdin.tty run +!module.parent && module.exports(shell.exit); diff --git a/codegens/arduino/npm/test-unit.js b/codegens/arduino/npm/test-unit.js new file mode 100644 index 000000000..31d2371ad --- /dev/null +++ b/codegens/arduino/npm/test-unit.js @@ -0,0 +1,60 @@ +#!/usr/bin/env node +/* eslint-env node, es6 */ +// --------------------------------------------------------------------------------------------------------------------- +// This script is intended to execute all unit tests. +// --------------------------------------------------------------------------------------------------------------------- + +var shell = require('shelljs'), + + // set directories and files for test and coverage report + path = require('path'), + + NYC = require('nyc'), + chalk = require('chalk'), + recursive = require('recursive-readdir'), + + COV_REPORT_PATH = '.coverage', + SPEC_SOURCE_DIR = path.join(__dirname, '..', 'test', 'unit'); + +module.exports = function (exit) { + // banner line + console.info(chalk.yellow.bold('Running unit tests using mocha on node...')); + + shell.test('-d', COV_REPORT_PATH) && shell.rm('-rf', COV_REPORT_PATH); + shell.mkdir('-p', COV_REPORT_PATH); + + var Mocha = require('mocha'), + nyc = new NYC({ + reportDir: COV_REPORT_PATH, + tempDirectory: COV_REPORT_PATH, + reporter: ['text', 'lcov', 'text-summary'], + include: ['**/*.js'], + exclude: ['config', 'test'], + hookRunInContext: true, + hookRunInThisContext: true + }); + + nyc.wrap(); + // add all spec files to mocha + recursive(SPEC_SOURCE_DIR, function (err, files) { + if (err) { console.error(err); return exit(1); } + + var mocha = new Mocha({ timeout: 1000 * 60 }); + + files.filter(function (file) { // extract all test files + return (file.substr(-8) === '.test.js'); + }).forEach(mocha.addFile.bind(mocha)); + + return mocha.run(function (runError) { + runError && console.error(runError.stack || runError); + + nyc.reset(); + nyc.writeCoverageFile(); + nyc.report(); + exit(runError ? 1 : 0); + }); + }); +}; + +// ensure we run this script exports if this is a direct stdin.tty run +!module.parent && module.exports(shell.exit); diff --git a/codegens/arduino/npm/test.js b/codegens/arduino/npm/test.js new file mode 100644 index 000000000..1109945ea --- /dev/null +++ b/codegens/arduino/npm/test.js @@ -0,0 +1,14 @@ +#!/usr/bin/env node +var chalk = require('chalk'), + exit = require('shelljs').exit, + prettyms = require('pretty-ms'), + startedAt = Date.now(), + name = require('../package.json').name; +require('async').series([ + require('./test-unit'), + require('./test-lint') +], function (code) { + // eslint-disable-next-line max-len + console.info(chalk[code ? 'red' : 'green'](`\n${name}: duration ${prettyms(Date.now() - startedAt)}\n${name}: ${code ? 'not ok' : 'ok'}!`)); + exit(code && (typeof code === 'number' ? code : 1) || 0); +}); diff --git a/codegens/arduino/package.json b/codegens/arduino/package.json new file mode 100644 index 000000000..c455a900b --- /dev/null +++ b/codegens/arduino/package.json @@ -0,0 +1,33 @@ +{ + "name": "@postman/codegen-arduino", + "version": "0.1.1", + "description": "Generates Arduino code from a Postman request", + "main": "index.js", + "com_postman_plugin": { + "type": "code_generator", + "lang": "arduino", + "variant": "WiFi", + "syntax_mode": "text" + }, + "repository": { + "type": "git", + "url": "" + }, + "keywords": [ + "codegen", + "arduino" + ], + "author": "Postman Labs ", + "license": "Apache-2.0", + "homepage": "https://github.com/postmanlabs/code-generators/tree/master/codegens/arduino", + "dependencies": {}, + "scripts": { + "test": "node npm/test.js", + "test-lint": "node npm/test-lint.js", + "test-unit": "node npm/test-unit.js" + }, + "devDependencies": {}, + "engines": { + "node": ">=8" + } +} diff --git a/codegens/arduino/test/unit/converter.test.js b/codegens/arduino/test/unit/converter.test.js new file mode 100644 index 000000000..d26ed9ed8 --- /dev/null +++ b/codegens/arduino/test/unit/converter.test.js @@ -0,0 +1,44 @@ +let { convert, getOptions } = require('../../index'), + { expect } = require('chai'), + Request = require('postman-collection').Request; + +describe('convert()', () => { + it.only('should generate an output', () => { + + const request = new Request({ + description: 'This is a sample POST request', + url: 'https://echo.getpostman.com/post', + method: 'POST', + header: [ + { + key: 'Content-Type', + value: 'application/json' + } + ], + body: { + mode: 'urlencoded', + urlencoded: [ + { + key: 'my-body-variable', + value: 'Something Awesome!' + } + ] + } + }); + + convert(request, {}, function (error, snippet) { + if (error) { + expect.fail('error object should be falsy'); + } + expect(snippet).to.be.a('string'); + }); + }); +}); + +describe('getOptions()', () => { + it('should return an empty array', () => { + const options = getOptions(); + expect(options).to.be.an('array'); + expect(options.length).to.equal(2); + }); +}); diff --git a/codegens/arduino/test/unit/util.test.js b/codegens/arduino/test/unit/util.test.js new file mode 100644 index 000000000..874dddf05 --- /dev/null +++ b/codegens/arduino/test/unit/util.test.js @@ -0,0 +1,56 @@ +const { getClientHttpSnippet, getHost, getPort } = require('../../lib/util'), + { expect } = require('chai'); + +describe('getClientHttpSnippet()', () => { + it('should generate a correct output', () => { + expectedSnippet = ''; + expectedSnippet += ' client.println("line1");\n'; + expectedSnippet += ' client.println("line2");\n'; + expectedSnippet += ' client.println("line3");\n'; + expectedSnippet += ' client.println("line4withescapednewline\\n");\n'; + expectedSnippet += ' client.println("");\n'; + expectedSnippet += ' client.println("");\n'; + expectedSnippet += ' client.println("");\n'; + + snippet = getClientHttpSnippet('line1\nline2\nline3\nline4withescapednewline\\n\n\n\n'); + + expect(snippet).to.equal(expectedSnippet); + }); +}); + +describe('getHost()', () => { + const testCases = [ + { url: 'http://example.com', expected_host: 'example.com' }, + { url: 'https://example.com/watch?v=ClkQA2Lb_iE', expected_host: 'example.com' }, + { url: 'http://192.168.100.0:1234', expected_host: '192.168.100.0' }, + { url: { host: ['example', 'com'] }, expected_host: 'example.com' }, + { url: { host: ['subdomain', 'example', 'com'] }, expected_host: 'subdomain.example.com' } + ]; + + testCases.forEach(function (testCase) { + it(`correctly gets the host of ${testCase.url}`, function () { + expect(getHost({ url: testCase.url })).to.equal(testCase.expected_host); + }); + }); +}); + +describe('getPort()', () => { + const testCases = [ + { url: 'http://example.com', expected_port: '80' }, + { url: 'https://example.com', expected_port: '443' }, + { url: 'http://example.com:8080', expected_port: '8080' }, + { url: 'https://example.com:8080', expected_port: '8080' }, + { url: 'http://192.168.100.0:1234', expected_port: '1234' }, + { url: 'http://192.168.100.0', expected_port: '80' }, + { url: { protocol: 'https', port: '23' }, expected_port: '23' }, + { url: { protocol: 'http' }, expected_port: 80 }, + { url: { protocol: 'https' }, expected_port: '443' } + ]; + + testCases.forEach(function (testCase) { + it(`correctly gets the port of ${testCase.url}`, function () { + expect(getPort({ url: testCase.url })).to.equal(testCase.expected_port); + }); + }); +}); + diff --git a/test/codegen/structure.test.js b/test/codegen/structure.test.js index aaaa3e1ae..4ddfe3da3 100644 --- a/test/codegen/structure.test.js +++ b/test/codegen/structure.test.js @@ -83,7 +83,8 @@ const expectedOptions = { 'lineContinuationCharacter', 'protocol', 'useMimeType', - 'ES6_enabled' + 'ES6_enabled', + 'arduinoWifiLibrary' ], CODEGEN_ABS_PATH = `./codegens/${codegen}`; describe('Code-gen repository ' + codegen, function () {