From 0b0b09762072012e42103e4c296268c2638572e2 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Tue, 10 Jan 2017 21:36:33 -0400 Subject: [PATCH] refactor(GUI): extract and test child writer CLI argument utilities (#1012) These utilities were extracted to `lib/shared/child-writer/cli.js`, and unit tests have been written for them. As a result of testing, `.getBooleanArgumentForm()` has been extended to support single letter options. Signed-off-by: Juan Cruz Viotti --- lib/shared/child-writer/cli.js | 99 ++++++++++++++++++++++ lib/shared/child-writer/index.js | 4 +- lib/shared/child-writer/utils.js | 69 --------------- tests/shared/child-writer/cli.spec.js | 116 ++++++++++++++++++++++++++ 4 files changed, 217 insertions(+), 71 deletions(-) create mode 100644 lib/shared/child-writer/cli.js create mode 100644 tests/shared/child-writer/cli.spec.js diff --git a/lib/shared/child-writer/cli.js b/lib/shared/child-writer/cli.js new file mode 100644 index 00000000..4fa237cc --- /dev/null +++ b/lib/shared/child-writer/cli.js @@ -0,0 +1,99 @@ +/* + * Copyright 2016 resin.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +const _ = require('lodash'); + +/** + * @summary Get the explicit boolean form of an argument + * @function + * @private + * + * @description + * We refer as "explicit boolean form of an argument" to a boolean + * argument in either normal or negated form. + * + * For example: `--check` and `--no-check`; + * + * @param {String} argumentName - argument name + * @param {Boolean} value - argument value + * @returns {String} argument + * + * @example + * console.log(cli.getBooleanArgumentForm('check', true)); + * > '--check' + * + * @example + * console.log(cli.getBooleanArgumentForm('check', false)); + * > '--no-check' + */ +exports.getBooleanArgumentForm = (argumentName, value) => { + const prefix = _.attempt(() => { + if (!value) { + return '--no-'; + } + + if (_.size(argumentName) === 1) { + return '-'; + } + + return '--'; + }); + + return prefix + argumentName; +}; + +/** + * @summary Get CLI writer arguments + * @function + * @public + * + * @param {Object} options - options + * @param {String} options.image - image + * @param {String} options.device - device + * @param {String} options.entryPoint - entry point + * @param {Boolean} [options.validateWriteOnSuccess] - validate write on success + * @param {Boolean} [options.unmountOnSuccess] - unmount on success + * @returns {String[]} arguments + * + * @example + * const argv = cli.getArguments({ + * image: 'path/to/rpi.img', + * device: '/dev/disk2' + * entryPoint: 'path/to/app.asar', + * validateWriteOnSuccess: true, + * unmountOnSuccess: true + * }); + */ +exports.getArguments = (options) => { + const argv = [ + options.entryPoint, + options.image, + '--drive', + options.device, + + // Explicitly set the boolen flag in positive + // or negative way in order to be on the safe + // side in case the Etcher CLI changes the + // default value of these options. + exports.getBooleanArgumentForm('unmount', options.unmountOnSuccess), + exports.getBooleanArgumentForm('check', options.validateWriteOnSuccess) + + ]; + + return argv; +}; diff --git a/lib/shared/child-writer/index.js b/lib/shared/child-writer/index.js index 0027e497..f4d63604 100644 --- a/lib/shared/child-writer/index.js +++ b/lib/shared/child-writer/index.js @@ -21,7 +21,7 @@ const _ = require('lodash'); const childProcess = require('child_process'); const ipc = require('node-ipc'); const rendererUtils = require('./renderer-utils'); -const utils = require('./utils'); +const cli = require('./cli'); const CONSTANTS = require('./constants'); const EXIT_CODES = require('../exit-codes'); const robot = require('../robot'); @@ -59,7 +59,7 @@ const robot = require('../robot'); exports.write = (image, drive, options) => { const emitter = new EventEmitter(); - const argv = utils.getCLIWriterArguments({ + const argv = cli.getArguments({ entryPoint: rendererUtils.getApplicationEntryPoint(), image: image, device: drive.device, diff --git a/lib/shared/child-writer/utils.js b/lib/shared/child-writer/utils.js index 8e09fa6f..8373b6dd 100644 --- a/lib/shared/child-writer/utils.js +++ b/lib/shared/child-writer/utils.js @@ -18,75 +18,6 @@ const _ = require('lodash'); -/** - * @summary Get the explicit boolean form of an argument - * @function - * @private - * - * @description - * We refer as "explicit boolean form of an argument" to a boolean - * argument in either normal or negated form. - * - * For example: `--check` and `--no-check`; - * - * @param {String} argumentName - argument name - * @param {Boolean} value - argument value - * @returns {String} argument - * - * @example - * console.log(utils.getBooleanArgumentForm('check', true)); - * > '--check' - * - * @example - * console.log(utils.getBooleanArgumentForm('check', false)); - * > '--no-check' - */ -exports.getBooleanArgumentForm = (argumentName, value) => { - const prefix = value ? '--' : '--no-'; - return prefix + argumentName; -}; - -/** - * @summary Get CLI writer arguments - * @function - * @public - * - * @param {Object} options - options - * @param {String} options.image - image - * @param {String} options.device - device - * @param {String} options.entryPoint - entry point - * @param {Boolean} [options.validateWriteOnSuccess] - validate write on success - * @param {Boolean} [options.unmountOnSuccess] - unmount on success - * @returns {String[]} arguments - * - * @example - * const argv = utils.getCLIWriterArguments({ - * image: 'path/to/rpi.img', - * device: '/dev/disk2' - * entryPoint: 'path/to/app.asar', - * validateWriteOnSuccess: true, - * unmountOnSuccess: true - * }); - */ -exports.getCLIWriterArguments = (options) => { - const argv = [ - options.entryPoint, - options.image, - '--drive', - options.device, - - // Explicitly set the boolen flag in positive - // or negative way in order to be on the safe - // side in case the Etcher CLI changes the - // default value of these options. - exports.getBooleanArgumentForm('unmount', options.unmountOnSuccess), - exports.getBooleanArgumentForm('check', options.validateWriteOnSuccess) - - ]; - - return argv; -}; - /** * @summary Split stringified object lines * @function diff --git a/tests/shared/child-writer/cli.spec.js b/tests/shared/child-writer/cli.spec.js new file mode 100644 index 00000000..a0a9d5e1 --- /dev/null +++ b/tests/shared/child-writer/cli.spec.js @@ -0,0 +1,116 @@ +/* + * Copyright 2016 resin.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +const m = require('mochainon'); +const cli = require('../../../lib/shared/child-writer/cli'); + +describe('Shared: ChildWriter CLI', function() { + + describe('.getBooleanArgumentForm()', function() { + + it('should prepend --no if the value is false and option is long', function() { + m.chai.expect(cli.getBooleanArgumentForm('foo', false)).to.equal('--no-foo'); + }); + + it('should prepend -- if the value is true and option is long', function() { + m.chai.expect(cli.getBooleanArgumentForm('foo', true)).to.equal('--foo'); + }); + + it('should prepend --no if the value is false and option is short', function() { + m.chai.expect(cli.getBooleanArgumentForm('x', false)).to.equal('--no-x'); + }); + + it('should prepend - if the value is true and option is short', function() { + m.chai.expect(cli.getBooleanArgumentForm('x', true)).to.equal('-x'); + }); + + }); + + describe('.getArguments()', function() { + + it('should return a list of arguments given validate = false, unmount = false', function() { + m.chai.expect(cli.getArguments({ + image: 'path/to/image.img', + device: '/dev/disk2', + entryPoint: 'path/to/app.asar', + validateWriteOnSuccess: false, + unmountOnSuccess: false + })).to.deep.equal([ + 'path/to/app.asar', + 'path/to/image.img', + '--drive', + '/dev/disk2', + '--no-unmount', + '--no-check' + ]); + }); + + it('should return a list of arguments given validate = false, unmount = true', function() { + m.chai.expect(cli.getArguments({ + image: 'path/to/image.img', + device: '/dev/disk2', + entryPoint: 'path/to/app.asar', + validateWriteOnSuccess: false, + unmountOnSuccess: true + })).to.deep.equal([ + 'path/to/app.asar', + 'path/to/image.img', + '--drive', + '/dev/disk2', + '--unmount', + '--no-check' + ]); + }); + + it('should return a list of arguments given validate = true, unmount = false', function() { + m.chai.expect(cli.getArguments({ + image: 'path/to/image.img', + device: '/dev/disk2', + entryPoint: 'path/to/app.asar', + validateWriteOnSuccess: true, + unmountOnSuccess: false + })).to.deep.equal([ + 'path/to/app.asar', + 'path/to/image.img', + '--drive', + '/dev/disk2', + '--no-unmount', + '--check' + ]); + }); + + it('should return a list of arguments given validate = true, unmount = true', function() { + m.chai.expect(cli.getArguments({ + image: 'path/to/image.img', + device: '/dev/disk2', + entryPoint: 'path/to/app.asar', + validateWriteOnSuccess: true, + unmountOnSuccess: true + })).to.deep.equal([ + 'path/to/app.asar', + 'path/to/image.img', + '--drive', + '/dev/disk2', + '--unmount', + '--check' + ]); + }); + + }); + +});