diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index 901684fb..6965d929 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -108,7 +108,7 @@ be documented instead!
[lego-blocks]: https://github.com/sindresorhus/ama/issues/10#issuecomment-117766328
[etcher-image-write]: https://github.com/resin-io-modules/etcher-image-write
-[exit-codes]: https://github.com/resin-io/etcher/blob/master/lib/src/exit-codes.js
+[exit-codes]: https://github.com/resin-io/etcher/blob/master/lib/shared/exit-codes.js
[cli-dir]: https://github.com/resin-io/etcher/tree/master/lib/cli
[gui-dir]: https://github.com/resin-io/etcher/tree/master/lib/gui
[electron]: http://electron.atom.io
diff --git a/docs/CLI.md b/docs/CLI.md
index 43b74479..2f266661 100644
--- a/docs/CLI.md
+++ b/docs/CLI.md
@@ -71,7 +71,7 @@ Exit codes
----------
The Etcher CLI uses certain exit codes to signal the result of the operation.
-These are documented in [`lib/src/exit-codes.js`][exit-codes] and are also
+These are documented in [`lib/shared/exit-codes.js`][exit-codes] and are also
printed on the Etcher CLI help page.
-[exit-codes]: https://github.com/resin-io/etcher/blob/master/lib/src/exit-codes.js
+[exit-codes]: https://github.com/resin-io/etcher/blob/master/lib/shared/exit-codes.js
diff --git a/lib/cli/cli.js b/lib/cli/cli.js
index 72fa2155..da2c2cff 100644
--- a/lib/cli/cli.js
+++ b/lib/cli/cli.js
@@ -20,7 +20,7 @@ const _ = require('lodash');
const fs = require('fs');
const yargs = require('yargs');
const utils = require('./utils');
-const EXIT_CODES = require('../src/exit-codes');
+const EXIT_CODES = require('../shared/exit-codes');
const packageJSON = require('../../package.json');
/**
diff --git a/lib/cli/etcher.js b/lib/cli/etcher.js
index 2e5b6af1..127caa98 100644
--- a/lib/cli/etcher.js
+++ b/lib/cli/etcher.js
@@ -25,7 +25,7 @@ const drivelist = Bluebird.promisifyAll(require('drivelist'));
const writer = require('./writer');
const utils = require('./utils');
const options = require('./cli');
-const EXIT_CODES = require('../src/exit-codes');
+const EXIT_CODES = require('../shared/exit-codes');
isElevated().then((elevated) => {
if (!elevated) {
diff --git a/lib/gui/app.js b/lib/gui/app.js
index 59f29afc..e0cd15f2 100644
--- a/lib/gui/app.js
+++ b/lib/gui/app.js
@@ -24,7 +24,7 @@
var angular = require('angular');
const electron = require('electron');
-const EXIT_CODES = require('../src/exit-codes');
+const EXIT_CODES = require('../shared/exit-codes');
/* eslint-enable no-var */
diff --git a/lib/gui/components/drive-selector/controllers/drive-selector.js b/lib/gui/components/drive-selector/controllers/drive-selector.js
index 16e0812f..604f4fe4 100644
--- a/lib/gui/components/drive-selector/controllers/drive-selector.js
+++ b/lib/gui/components/drive-selector/controllers/drive-selector.js
@@ -18,7 +18,13 @@
const _ = require('lodash');
-module.exports = function($q, $uibModalInstance, DrivesModel, SelectionStateModel, WarningModalService) {
+module.exports = function(
+ $q,
+ $uibModalInstance,
+ DrivesModel,
+ SelectionStateModel,
+ WarningModalService,
+ DriveConstraintsModel) {
/**
* @summary The drive selector state
@@ -27,6 +33,13 @@ module.exports = function($q, $uibModalInstance, DrivesModel, SelectionStateMode
*/
this.state = SelectionStateModel;
+ /**
+ * @summary Static methods to check a drive's properties
+ * @property
+ * @type Object
+ */
+ this.constraints = DriveConstraintsModel;
+
/**
* @summary The drives model
* @property
@@ -55,11 +68,11 @@ module.exports = function($q, $uibModalInstance, DrivesModel, SelectionStateMode
* });
*/
const shouldChangeDriveSelectionState = (drive) => {
- if (!SelectionStateModel.isDriveValid(drive)) {
+ if (!DriveConstraintsModel.isDriveValid(drive, SelectionStateModel.getImage())) {
return $q.resolve(false);
}
- if (SelectionStateModel.isDriveSizeRecommended(drive)) {
+ if (DriveConstraintsModel.isDriveSizeRecommended(drive, SelectionStateModel.getImage())) {
return $q.resolve(true);
}
diff --git a/lib/gui/components/drive-selector/drive-selector.js b/lib/gui/components/drive-selector/drive-selector.js
index fe233181..14a7c3ad 100644
--- a/lib/gui/components/drive-selector/drive-selector.js
+++ b/lib/gui/components/drive-selector/drive-selector.js
@@ -27,6 +27,7 @@ const DriveSelector = angular.module(MODULE_NAME, [
require('../warning-modal/warning-modal'),
require('../../models/drives'),
require('../../models/selection-state'),
+ require('../../models/drive-constraints'),
require('../../utils/byte-size/byte-size')
]);
diff --git a/lib/gui/components/drive-selector/templates/drive-selector-modal.tpl.html b/lib/gui/components/drive-selector/templates/drive-selector-modal.tpl.html
index 33671fb5..bac07241 100644
--- a/lib/gui/components/drive-selector/templates/drive-selector-modal.tpl.html
+++ b/lib/gui/components/drive-selector/templates/drive-selector-modal.tpl.html
@@ -6,7 +6,7 @@
diff --git a/lib/gui/models/drive-constraints.js b/lib/gui/models/drive-constraints.js
new file mode 100644
index 00000000..13969cb9
--- /dev/null
+++ b/lib/gui/models/drive-constraints.js
@@ -0,0 +1,37 @@
+/*
+ * 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';
+
+/**
+ * @summary Expose a CLI/GUI shared utility object as an AngularJS service
+ * @module Etcher.Models.DriveConstraints
+ */
+
+const angular = require('angular');
+const MODULE_NAME = 'Etcher.Models.DriveConstraints';
+const DriveConstraintsModel = angular.module(MODULE_NAME, []);
+
+const DriveConstraints = require('../../shared/drive-constraints');
+
+// `DriveConstraintsModel.service` expects a constructor as the second argument, but we want
+// to expose an object. Calling `DriveConstraintsModel.factory` with a a function returning
+// the object is the right way to do it.
+DriveConstraintsModel.factory('DriveConstraintsModel', () => {
+ return DriveConstraints;
+});
+
+module.exports = MODULE_NAME;
diff --git a/lib/gui/models/selection-state.js b/lib/gui/models/selection-state.js
index 2cf38d22..04061eaf 100644
--- a/lib/gui/models/selection-state.js
+++ b/lib/gui/models/selection-state.js
@@ -47,149 +47,6 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
});
};
- /**
- * @summary Check if a drive is large enough for the selected image
- * @function
- * @public
- *
- * @description
- * For convenience, if there is no image selected, this function
- * returns true.
- *
- * Notice that if you select the drive before the image, the check
- * will not take place and it'll be the client's responsibility
- * to do so.
- *
- * @param {Object} drive - drive
- * @returns {Boolean} whether the drive is large enough
- *
- * @example
- * SelectionStateModel.setImage({
- * path: 'rpi.img',
- * size: 100000000
- * });
- *
- * if (SelectionStateModel.isDriveLargeEnough({
- * device: '/dev/disk2',
- * name: 'My Drive',
- * size: 123456789
- * })) {
- * console.log('We can flash the image to this drive!');
- * }
- */
- this.isDriveLargeEnough = (drive) => {
- return (this.getImageSize() || 0) <= drive.size;
- };
-
- /**
- * @summary Check if a drive meets the recommended drive size suggestion
- * @function
- * @public
- *
- * @description
- * For convenience, if there is no image selected, this function
- * returns true.
- *
- * @param {Object} drive - drive
- * @returns {Boolean} whether the drive size is recommended
- *
- * @example
- * SelectionStateModel.setImage({
- * path: 'rpi.img',
- * size: 100000000
- * recommendedDriveSize: 200000000
- * });
- *
- * if (SelectionStateModel.isDriveSizeRecommended({
- * device: '/dev/disk2',
- * name: 'My Drive',
- * size: 400000000
- * })) {
- * console.log('We meet the recommended drive size!');
- * }
- */
- this.isDriveSizeRecommended = (drive) => {
- return drive.size >= (this.getImageRecommendedDriveSize() || 0);
- };
-
- /**
- * @summary Check if a drive is locked
- * @function
- * @public
- *
- * @description
- * This usually points out a locked SD Card.
- *
- * @param {Object} drive - drive
- * @returns {Boolean} whether the drive is locked
- *
- * @example
- * if (SelectionStateModel.isDriveLocked({
- * device: '/dev/disk2',
- * name: 'My Drive',
- * size: 123456789,
- * protected: true
- * })) {
- * console.log('This drive is locked (e.g: write-protected)');
- * }
- */
- this.isDriveLocked = (drive) => {
- return _.get(drive, 'protected', false);
- };
-
- /**
- * @summary Check if a drive is valid
- * @function
- * @public
- *
- * @description
- * This function is a facade to:
- *
- * - `SelectionStateModel.isDriveLargeEnough()`
- * - `SelectionStateModel.isDriveLocked()`
- *
- * @param {Object} drive - drive
- * @returns {Boolean} whether the drive is valid
- *
- * @example
- * if (SelectionStateModel.isDriveValid({
- * device: '/dev/disk2',
- * name: 'My Drive',
- * size: 123456789,
- * protected: true
- * })) {
- * console.log('This drive is valid!');
- * }
- */
- this.isDriveValid = (drive) => {
- return _.every([
- this.isDriveLargeEnough(drive),
- !this.isDriveLocked(drive)
- ]);
- };
-
- /**
- * @summary Check if a drive is a system drive
- * @function
- * @public
- * @param {Object} drive - drive
- * @returns {Boolean} whether the drive is a system drive
- *
- * @example
- * if (SelectionStateModel.isSystemDrive({
- * device: '/dev/disk2',
- * name: 'My Drive',
- * size: 123456789,
- * protected: true,
- * system: true
- * })) {
- * console.log('This drive is a system drive!');
- * }
- */
- this.isSystemDrive = (drive) => {
- return Boolean(drive.system);
- };
-
/**
* @summary Toggle set drive
* @function
@@ -243,6 +100,20 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
});
};
+ /**
+ * @summary Get the selected image
+ * @function
+ * @public
+ *
+ * @returns {object}
+ *
+ * @example
+ * const image = SelectionStateModel.getImage();
+ */
+ this.getImage = () => {
+ return _.get(Store.getState().toJS(), 'selection.image');
+ };
+
/**
* @summary Get image path
* @function
@@ -370,7 +241,7 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
* }
*/
this.hasImage = () => {
- return Boolean(this.getImagePath() && this.getImageSize());
+ return Boolean(this.getImage());
};
/**
diff --git a/lib/gui/models/store.js b/lib/gui/models/store.js
index c963b739..d62598bc 100644
--- a/lib/gui/models/store.js
+++ b/lib/gui/models/store.js
@@ -20,6 +20,7 @@ const Immutable = require('immutable');
const _ = require('lodash');
const redux = require('redux');
const persistState = require('redux-localstorage');
+const constraints = require('../../shared/drive-constraints');
/**
* @summary Application default state
@@ -94,15 +95,13 @@ const storeReducer = (state, action) => {
const drive = _.first(action.data);
+ // Even if there's no image selectected, we need to call `isDriveValid`
+ // to check if the drive is locked, and `{}` works fine with it
+ const image = state.getIn([ 'selection', 'image' ], Immutable.fromJS({})).toJS();
+
if (_.every([
-
- // TODO: Reuse from SelectionStateModel.isDriveValid()
- state.getIn([ 'selection', 'image', 'size' ], 0) <= drive.size,
-
- // TODO: Reuse from SelectionStateModel.isDriveSizeRecommended()
- state.getIn([ 'selection', 'image', 'recommendedDriveSize' ], 0) <= drive.size,
-
- !drive.protected
+ constraints.isDriveValid(drive, image),
+ constraints.isDriveSizeRecommended(drive, image)
])) {
return storeReducer(newState, {
type: ACTIONS.SELECT_DRIVE,
@@ -225,8 +224,8 @@ const storeReducer = (state, action) => {
throw new Error('The drive is write-protected');
}
- // TODO: Reuse from SelectionStateModel.isDriveLargeEnough()
- if (state.getIn([ 'selection', 'image', 'size' ], 0) > selectedDrive.get('size')) {
+ const image = state.getIn([ 'selection', 'image' ]);
+ if (image && !constraints.isDriveLargeEnough(selectedDrive.toJS(), image.toJS())) {
throw new Error('The drive is not large enough');
}
@@ -268,9 +267,9 @@ const storeReducer = (state, action) => {
});
return _.attempt(() => {
- if (_.some([
- selectedDrive && selectedDrive.get('size', 0) < action.data.size,
- selectedDrive && selectedDrive.get('size', 0) < action.data.recommendedDriveSize
+ if (selectedDrive && !_.every([
+ constraints.isDriveLargeEnough(selectedDrive.toJS(), action.data),
+ constraints.isDriveSizeRecommended(selectedDrive.toJS(), action.data)
])) {
return storeReducer(state, {
type: ACTIONS.REMOVE_DRIVE
diff --git a/lib/gui/modules/image-writer.js b/lib/gui/modules/image-writer.js
index ee8ad98f..8edc2713 100644
--- a/lib/gui/modules/image-writer.js
+++ b/lib/gui/modules/image-writer.js
@@ -21,7 +21,7 @@
*/
const angular = require('angular');
-const childWriter = require('../../src/child-writer');
+const childWriter = require('../../shared/child-writer');
const MODULE_NAME = 'Etcher.Modules.ImageWriter';
const imageWriter = angular.module(MODULE_NAME, [
diff --git a/lib/src/child-writer/README.md b/lib/shared/child-writer/README.md
similarity index 100%
rename from lib/src/child-writer/README.md
rename to lib/shared/child-writer/README.md
diff --git a/lib/src/child-writer/constants.js b/lib/shared/child-writer/constants.js
similarity index 100%
rename from lib/src/child-writer/constants.js
rename to lib/shared/child-writer/constants.js
diff --git a/lib/src/child-writer/index.js b/lib/shared/child-writer/index.js
similarity index 100%
rename from lib/src/child-writer/index.js
rename to lib/shared/child-writer/index.js
diff --git a/lib/src/child-writer/renderer-utils.js b/lib/shared/child-writer/renderer-utils.js
similarity index 100%
rename from lib/src/child-writer/renderer-utils.js
rename to lib/shared/child-writer/renderer-utils.js
diff --git a/lib/src/child-writer/utils.js b/lib/shared/child-writer/utils.js
similarity index 100%
rename from lib/src/child-writer/utils.js
rename to lib/shared/child-writer/utils.js
diff --git a/lib/src/child-writer/writer-proxy.js b/lib/shared/child-writer/writer-proxy.js
similarity index 100%
rename from lib/src/child-writer/writer-proxy.js
rename to lib/shared/child-writer/writer-proxy.js
diff --git a/lib/shared/drive-constraints.js b/lib/shared/drive-constraints.js
new file mode 100644
index 00000000..1e75edb3
--- /dev/null
+++ b/lib/shared/drive-constraints.js
@@ -0,0 +1,149 @@
+/*
+ * 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';
+
+/**
+ * @summary Check if a drive is locked
+ * @function
+ * @public
+ *
+ * @description
+ * This usually points out a locked SD Card.
+ *
+ * @param {Object} drive - drive
+ * @returns {Boolean} whether the drive is locked
+ *
+ * @example
+ * if (constraints.isDriveLocked({
+ * device: '/dev/disk2',
+ * name: 'My Drive',
+ * size: 123456789,
+ * protected: true
+ * })) {
+ * console.log('This drive is locked (e.g: write-protected)');
+ * }
+ */
+exports.isDriveLocked = (drive) => {
+ return Boolean(drive.protected || false);
+};
+
+/**
+ * @summary Check if a drive is a system drive
+ * @function
+ * @public
+ * @param {Object} drive - drive
+ * @returns {Boolean} whether the drive is a system drive
+ *
+ * @example
+ * if (constraints.isSystemDrive({
+ * device: '/dev/disk2',
+ * name: 'My Drive',
+ * size: 123456789,
+ * protected: true,
+ * system: true
+ * })) {
+ * console.log('This drive is a system drive!');
+ * }
+ */
+exports.isSystemDrive = (drive) => {
+ return Boolean(drive.system || false);
+};
+
+/**
+ * @summary Check if a drive is large enough for an image
+ * @function
+ * @public
+ *
+ * @param {Object} drive - drive
+ * @param {Object} image - image
+ * @returns {Boolean} whether the drive is large enough
+ *
+ * @example
+ * if (constraints.isDriveLargeEnough({
+ * device: '/dev/disk2',
+ * name: 'My Drive',
+ * size: 1000000000
+ * }, {
+ * path: 'rpi.img',
+ * size: 1000000000
+ * })) {
+ * console.log('We can flash the image to this drive!');
+ * }
+ */
+exports.isDriveLargeEnough = (drive, image) => {
+ return drive.size >= (image.size || 0);
+};
+
+/**
+ * @summary Check if a drive is is valid, i.e. not locked and large enough for an image
+ * @function
+ * @public
+ *
+ * @param {Object} drive - drive
+ * @param {Object} image - image
+ * @returns {Boolean} whether the drive is valid
+ *
+ * @example
+ * if (constraints.isDriveValid({
+ * device: '/dev/disk2',
+ * name: 'My Drive',
+ * size: 1000000000,
+ * protected: false
+ * }, {
+ * path: 'rpi.img',
+ * size: 1000000000,
+ * recommendedDriveSize: 2000000000
+ * })) {
+ * console.log('This drive is valid!');
+ * }
+ */
+exports.isDriveValid = (drive, image) => {
+ return !this.isDriveLocked(drive) && this.isDriveLargeEnough(drive, image);
+};
+
+/**
+ * @summary Check if a drive meets the recommended drive size suggestion
+ * @function
+ * @public
+ *
+ * @description
+ * If the image doesn't have a recommended size, this function returns true.
+ *
+ * @param {Object} drive - drive
+ * @param {Object} image - image
+ * @returns {Boolean} whether the drive size is recommended
+ *
+ * @example
+ * const drive = {
+ * device: '/dev/disk2',
+ * name: 'My Drive',
+ * size: 4000000000
+ * };
+ *
+ * const image = {
+ * path: 'rpi.img',
+ * size: 2000000000
+ * recommendedDriveSize: 4000000000
+ * });
+ *
+ * if (constraints.isDriveSizeRecommended(drive, image)) {
+ * console.log('We meet the recommended drive size!');
+ * }
+ */
+exports.isDriveSizeRecommended = (drive, image) => {
+ return drive.size >= (image.recommendedDriveSize || 0);
+};
diff --git a/lib/src/exit-codes.js b/lib/shared/exit-codes.js
similarity index 100%
rename from lib/src/exit-codes.js
rename to lib/shared/exit-codes.js
diff --git a/package.json b/package.json
index 3b4f3aa9..e14e3855 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
"url": "git@github.com:resin-io/etcher.git"
},
"scripts": {
- "test": "npm run lint && electron-mocha --recursive --renderer tests/gui -R min && electron-mocha --recursive tests/cli -R min",
+ "test": "npm run lint && electron-mocha --recursive --renderer tests/gui -R min && electron-mocha --recursive tests/cli tests/shared -R min",
"sass": "node-sass ./lib/gui/scss/main.scss > build/css/main.css",
"jslint": "eslint lib tests scripts bin versionist.conf.js",
"scsslint": "scss-lint lib/gui/scss",
diff --git a/tests/gui/models/drive-constraints.spec.js b/tests/gui/models/drive-constraints.spec.js
new file mode 100644
index 00000000..9cf01d01
--- /dev/null
+++ b/tests/gui/models/drive-constraints.spec.js
@@ -0,0 +1,28 @@
+'use strict';
+
+const m = require('mochainon');
+const angular = require('angular');
+require('angular-mocks');
+
+describe('Browser: DriveConstraints', function() {
+
+ beforeEach(angular.mock.module(
+ require('../../../lib/gui/models/drive-constraints')
+ ));
+
+ describe('DriveConstraintsModel', function() {
+
+ let DriveConstraintsModel;
+
+ beforeEach(angular.mock.inject(function(_DriveConstraintsModel_) {
+ DriveConstraintsModel = _DriveConstraintsModel_;
+ }));
+
+ it('should be the `lib/shared/drive-constraints.js` object', function() {
+ const DriveConstraints = require('../../../lib/shared/drive-constraints');
+ m.chai.expect(Object.is(DriveConstraintsModel, DriveConstraints)).to.be.true;
+ });
+
+ });
+
+});
diff --git a/tests/gui/models/selection-state.spec.js b/tests/gui/models/selection-state.spec.js
index f96e42db..4a35113c 100644
--- a/tests/gui/models/selection-state.spec.js
+++ b/tests/gui/models/selection-state.spec.js
@@ -35,6 +35,10 @@ describe('Browser: SelectionState', function() {
m.chai.expect(drive).to.be.undefined;
});
+ it('getImage() should return undefined', function() {
+ m.chai.expect(SelectionStateModel.getImage()).to.be.undefined;
+ });
+
it('getImagePath() should return undefined', function() {
m.chai.expect(SelectionStateModel.getImagePath()).to.be.undefined;
});
@@ -75,95 +79,6 @@ describe('Browser: SelectionState', function() {
});
- describe('.isDriveLocked()', function() {
-
- it('should return true if the drive is protected', function() {
- const result = SelectionStateModel.isDriveLocked({
- device: '/dev/disk2',
- name: 'USB Drive',
- size: 999999999,
- protected: true
- });
-
- m.chai.expect(result).to.be.true;
- });
-
- it('should return false if the drive is not protected', function() {
- const result = SelectionStateModel.isDriveLocked({
- device: '/dev/disk2',
- name: 'USB Drive',
- size: 999999999,
- protected: false
- });
-
- m.chai.expect(result).to.be.false;
- });
-
- it('should return false if we don\'t know if the drive is protected', function() {
- const result = SelectionStateModel.isDriveLocked({
- device: '/dev/disk2',
- name: 'USB Drive',
- size: 999999999
- });
-
- m.chai.expect(result).to.be.false;
- });
-
- });
-
- describe('.isDriveValid()', function() {
-
- it('should return true if the drive is not locked', function() {
- const result = SelectionStateModel.isDriveValid({
- device: '/dev/disk2',
- name: 'USB Drive',
- size: 999999999,
- protected: false
- });
-
- m.chai.expect(result).to.be.true;
- });
-
- it('should return false if the drive is locked', function() {
- const result = SelectionStateModel.isDriveValid({
- device: '/dev/disk2',
- name: 'USB Drive',
- size: 999999999,
- protected: true
- });
-
- m.chai.expect(result).to.be.false;
- });
-
- });
-
- describe('.isSystemDrive()', function() {
-
- it('should return true if the drive is a system drive', function() {
- const result = SelectionStateModel.isSystemDrive({
- device: '/dev/disk2',
- name: 'USB Drive',
- size: 999999999,
- protected: true,
- system: true
- });
-
- m.chai.expect(result).to.be.true;
- });
-
- it('should return false if the drive is a removable drive', function() {
- const result = SelectionStateModel.isSystemDrive({
- device: '/dev/disk2',
- name: 'USB Drive',
- size: 999999999,
- protected: true,
- system: false
- });
-
- m.chai.expect(result).to.be.false;
- });
- });
-
describe('given a drive', function() {
beforeEach(function() {
@@ -302,7 +217,7 @@ describe('Browser: SelectionState', function() {
describe('given an image', function() {
beforeEach(function() {
- SelectionStateModel.setImage({
+ this.image = {
path: 'foo.img',
size: 999999999,
recommendedDriveSize: 1000000000,
@@ -310,129 +225,9 @@ describe('Browser: SelectionState', function() {
supportUrl: 'https://www.raspbian.org/forums/',
name: 'Raspbian',
logo: '
'
- });
- });
-
- describe('.isDriveLargeEnough()', function() {
-
- it('should return true if the drive size is greater than the image size', function() {
- const result = SelectionStateModel.isDriveLargeEnough({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 99999999999999,
- protected: false
- });
-
- m.chai.expect(result).to.be.true;
- });
-
- it('should return true if the drive size is equal to the image size', function() {
- const result = SelectionStateModel.isDriveLargeEnough({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 999999999,
- protected: false
- });
-
- m.chai.expect(result).to.be.true;
- });
-
- it('should return false if the drive size is less than the image size', function() {
- const result = SelectionStateModel.isDriveLargeEnough({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 999999998,
- protected: false
- });
-
- m.chai.expect(result).to.be.false;
- });
-
- });
-
- describe('.isDriveSizeRecommended()', function() {
-
- it('should return true if the drive size is greater than the recommended size', function() {
- const result = SelectionStateModel.isDriveSizeRecommended({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 1000000001,
- protected: false
- });
-
- m.chai.expect(result).to.be.true;
- });
-
- it('should return true if the drive size is equal to the recommended size', function() {
- const result = SelectionStateModel.isDriveSizeRecommended({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 1000000000,
- protected: false
- });
-
- m.chai.expect(result).to.be.true;
- });
-
- it('should return false if the drive size is less than the recommended size', function() {
- const result = SelectionStateModel.isDriveSizeRecommended({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 999999999,
- protected: false
- });
-
- m.chai.expect(result).to.be.false;
- });
-
- });
-
- describe('.isDriveValid()', function() {
-
- it('should return true if the drive is large enough and it is not locked', function() {
- const result = SelectionStateModel.isDriveValid({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 99999999999999,
- protected: false
- });
-
- m.chai.expect(result).to.be.true;
- });
-
- it('should return false if the drive is large enough but it is locked', function() {
- const result = SelectionStateModel.isDriveValid({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 99999999999999,
- protected: true
- });
-
- m.chai.expect(result).to.be.false;
- });
-
- it('should return false if the drive is not large enough and it is not locked', function() {
- const result = SelectionStateModel.isDriveValid({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 1,
- protected: false
- });
-
- m.chai.expect(result).to.be.false;
- });
-
- it('should return false if the drive is not large enough and it is locked', function() {
- const result = SelectionStateModel.isDriveValid({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 1,
- protected: true
- });
-
- m.chai.expect(result).to.be.false;
- });
+ };
+ SelectionStateModel.setImage(this.image);
});
describe('.setDrive()', function() {
@@ -454,6 +249,14 @@ describe('Browser: SelectionState', function() {
});
+ describe('.getImage()', function() {
+
+ it('should return the image', function() {
+ m.chai.expect(SelectionStateModel.getImage()).to.deep.equal(this.image);
+ });
+
+ });
+
describe('.getImagePath()', function() {
it('should return the image path', function() {
@@ -559,34 +362,6 @@ describe('Browser: SelectionState', function() {
describe('given no image', function() {
- describe('.isDriveLargeEnough()', function() {
-
- it('should return true', function() {
- const result = SelectionStateModel.isDriveLargeEnough({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 1
- });
-
- m.chai.expect(result).to.be.true;
- });
-
- });
-
- describe('.isDriveSizeRecommended()', function() {
-
- it('should return true', function() {
- const result = SelectionStateModel.isDriveSizeRecommended({
- device: '/dev/disk1',
- name: 'USB Drive',
- size: 1
- });
-
- m.chai.expect(result).to.be.true;
- });
-
- });
-
describe('.setImage()', function() {
it('should be able to set an image', function() {
diff --git a/tests/shared/drive-constraints.spec.js b/tests/shared/drive-constraints.spec.js
new file mode 100644
index 00000000..5ae50d26
--- /dev/null
+++ b/tests/shared/drive-constraints.spec.js
@@ -0,0 +1,242 @@
+'use strict';
+
+const m = require('mochainon');
+const constraints = require('../../lib/shared/drive-constraints');
+
+describe('Shared: DriveConstraints', function() {
+
+ describe('.isDriveLocked()', function() {
+
+ it('should return true if the drive is protected', function() {
+ const result = constraints.isDriveLocked({
+ device: '/dev/disk2',
+ name: 'USB Drive',
+ size: 999999999,
+ protected: true
+ });
+
+ m.chai.expect(result).to.be.true;
+ });
+
+ it('should return false if the drive is not protected', function() {
+ const result = constraints.isDriveLocked({
+ device: '/dev/disk2',
+ name: 'USB Drive',
+ size: 999999999,
+ protected: false
+ });
+
+ m.chai.expect(result).to.be.false;
+ });
+
+ it('should return false if we don\'t know if the drive is protected', function() {
+ const result = constraints.isDriveLocked({
+ device: '/dev/disk2',
+ name: 'USB Drive',
+ size: 999999999
+ });
+
+ m.chai.expect(result).to.be.false;
+ });
+
+ });
+
+ describe('.isSystemDrive()', function() {
+
+ it('should return true if the drive is a system drive', function() {
+ const result = constraints.isSystemDrive({
+ device: '/dev/disk2',
+ name: 'USB Drive',
+ size: 999999999,
+ protected: true,
+ system: true
+ });
+
+ m.chai.expect(result).to.be.true;
+ });
+
+ it('should default to `false` if the `system` property is `undefined`', function() {
+ const result = constraints.isSystemDrive({
+ device: '/dev/disk2',
+ name: 'USB Drive',
+ size: 999999999,
+ protected: true
+ });
+
+ m.chai.expect(result).to.be.false;
+ });
+
+ it('should return false if the drive is a removable drive', function() {
+ const result = constraints.isSystemDrive({
+ device: '/dev/disk2',
+ name: 'USB Drive',
+ size: 999999999,
+ protected: true,
+ system: false
+ });
+
+ m.chai.expect(result).to.be.false;
+ });
+
+ });
+
+ describe('.isDriveLargeEnough()', function() {
+
+ it('should return true if the drive size is greater than the image size', function() {
+ const result = constraints.isDriveLargeEnough({
+ device: '/dev/disk1',
+ name: 'USB Drive',
+ size: 1000000001,
+ protected: false
+ }, {
+ path: 'rpi.img',
+ size: 1000000000
+ });
+
+ m.chai.expect(result).to.be.true;
+ });
+
+ it('should return true if the drive size is equal to the image size', function() {
+ const result = constraints.isDriveLargeEnough({
+ device: '/dev/disk1',
+ name: 'USB Drive',
+ size: 1000000000,
+ protected: false
+ }, {
+ path: 'rpi.img',
+ size: 1000000000
+ });
+
+ m.chai.expect(result).to.be.true;
+ });
+
+ it('should return false if the drive size is less than the image size', function() {
+ const result = constraints.isDriveLargeEnough({
+ device: '/dev/disk1',
+ name: 'USB Drive',
+ size: 1000000000,
+ protected: false
+ }, {
+ path: 'rpi.img',
+ size: 1000000001
+ });
+
+ m.chai.expect(result).to.be.false;
+ });
+
+ });
+
+ describe('.isDriveSizeRecommended()', function() {
+
+ it('should return true if the drive size is greater than the recommended size ', function() {
+ const result = constraints.isDriveSizeRecommended({
+ device: '/dev/disk1',
+ name: 'USB Drive',
+ size: 2000000001,
+ protected: false
+ }, {
+ path: 'rpi.img',
+ size: 1000000000,
+ recommendedDriveSize: 2000000000
+ });
+
+ m.chai.expect(result).to.be.true;
+ });
+
+ it('should return true if the drive size is equal to recommended size', function() {
+ const result = constraints.isDriveSizeRecommended({
+ device: '/dev/disk1',
+ name: 'USB Drive',
+ size: 2000000000,
+ protected: false
+ }, {
+ path: 'rpi.img',
+ size: 1000000000,
+ recommendedDriveSize: 2000000000
+ });
+
+ m.chai.expect(result).to.be.true;
+ });
+
+ it('should return false if the drive size is less than the recommended size', function() {
+ const result = constraints.isDriveSizeRecommended({
+ device: '/dev/disk1',
+ name: 'USB Drive',
+ size: 2000000000,
+ protected: false
+ }, {
+ path: 'rpi.img',
+ size: 1000000000,
+ recommendedDriveSize: 2000000001
+ });
+
+ m.chai.expect(result).to.be.false;
+ });
+
+ it('should return true if the recommended drive size is undefined', function() {
+ const result = constraints.isDriveSizeRecommended({
+ device: '/dev/disk1',
+ name: 'USB Drive',
+ size: 2000000000,
+ protected: false
+ }, {
+ path: 'rpi.img',
+ size: 1000000000
+ });
+
+ m.chai.expect(result).to.be.true;
+ });
+
+ });
+
+ describe('.isDriveValid()', function() {
+
+ describe('given drive is large enough', function() {
+
+ beforeEach(function() {
+ this.drive = {
+ device: '/dev/disk2',
+ name: 'My Drive',
+ size: 4000000000
+ };
+ this.image = {
+ path: 'rpi.img',
+ size: 2000000000
+ };
+ });
+
+ it('should return true if drive is not locked', function() {
+ this.drive.protected = false;
+ m.chai.expect(constraints.isDriveValid(this.drive, this.image)).to.be.true;
+ });
+
+ it('should return false if drive is locked', function() {
+ this.drive.protected = true;
+ m.chai.expect(constraints.isDriveValid(this.drive, this.image)).to.be.false;
+ });
+
+ });
+
+ describe('given drive is not large enough', function() {
+
+ beforeEach(function() {
+ this.drive = {
+ device: '/dev/disk2',
+ name: 'My Drive',
+ size: 1000000000
+ };
+ this.image = {
+ path: 'rpi.img',
+ size: 2000000000
+ };
+ });
+
+ it('should return false', function() {
+ m.chai.expect(constraints.isDriveValid(this.drive, this.image)).to.be.false;
+ });
+
+ });
+
+ });
+
+});