mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-21 18:26:32 +00:00
Prevent selection of drives that are not large enough (#408)
* Make .selectImage() dialog return an object with a `path` property This allows to return more than one value for the selected image, like image size and other metadata for example. Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com> * Return image size from .selectImage() dialog This property will be useful to perform some sanity checks, like ensuring the selected drive is large enough to contain the image. Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com> * Store both the image path and the image size in the selection model In order to simplify accessing such properties in an encapsulated manner, `SelectionStateModel.getImage()` was replaced with the following functions: - `SelectionStateModel.getImagePath()`. - `SelectionStateModel.getImageSize()`. Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com> * Increase SelectionStateModel setter validation The model not providing any kind of validation was the source of some bugs I encountered while implementing the previous commits that would not have happened otherwise. Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com> * Prevent selection of drives that are not large enough - The drive selector modal was modified such that drives that are not large enough are crossed out, and the user is not able to click them. - In the case of drive auto-selection, not large enough drives won't attempt to get autoselected. This commit introduces: - The `SelectionStateModel.isDriveLargeEnough()` function. Fixes: https://github.com/resin-io/etcher/issues/344 Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This commit is contained in:
parent
c31ccdbdbe
commit
bf37ee72df
@ -6252,6 +6252,25 @@ button.btn:focus, button.progress-button:focus {
|
||||
.alert-ribbon--open {
|
||||
top: 0; }
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
.list-group-item[disabled] {
|
||||
text-decoration: line-through;
|
||||
cursor: not-allowed; }
|
||||
|
||||
/*
|
||||
* Copyright 2016 Resin.io
|
||||
*
|
||||
|
@ -160,10 +160,14 @@ app.controller('AppController', function(
|
||||
// `angular.equals` is used instead of `_.isEqual` to
|
||||
// cope with `$$hashKey`.
|
||||
if (!angular.equals(self.selection.getDrive(), drive)) {
|
||||
AnalyticsService.logEvent('Auto-select drive', {
|
||||
device: drive.device
|
||||
});
|
||||
self.selectDrive(drive);
|
||||
|
||||
if (self.selection.isDriveLargeEnough(drive)) {
|
||||
self.selectDrive(drive);
|
||||
|
||||
AnalyticsService.logEvent('Auto-select drive', {
|
||||
device: drive.device
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -181,9 +185,7 @@ app.controller('AppController', function(
|
||||
|
||||
this.selectImage = function(image) {
|
||||
self.selection.setImage(image);
|
||||
AnalyticsService.logEvent('Select image', {
|
||||
image: image
|
||||
});
|
||||
AnalyticsService.logEvent('Select image', image);
|
||||
};
|
||||
|
||||
this.openImageSelector = function() {
|
||||
|
@ -6,12 +6,15 @@
|
||||
<div class="modal-body">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item" ng-repeat="drive in modal.scanner.drives"
|
||||
ng-click="modal.state.toggleSetDrive(drive)">
|
||||
ng-disabled="!modal.state.isDriveLargeEnough(drive)"
|
||||
ng-click="modal.state.isDriveLargeEnough(drive) && modal.state.toggleSetDrive(drive)">
|
||||
<div>
|
||||
<h4 class="list-group-item-heading">{{ drive.description }} - {{ drive.size | gigabyte | number:1 }} GB</h4>
|
||||
<p class="list-group-item-text">{{ drive.name }}</p>
|
||||
</div>
|
||||
<span class="tick tick--success" ng-disabled="!modal.state.isCurrentDrive(drive)"></span>
|
||||
<span class="tick tick--success"
|
||||
ng-show="modal.state.isDriveLargeEnough(drive)"
|
||||
ng-disabled="!modal.state.isCurrentDrive(drive)"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -42,15 +42,88 @@ SelectionStateModel.service('SelectionStateModel', function() {
|
||||
*
|
||||
* @param {Object} drive - drive
|
||||
*
|
||||
* @throws Will throw if drive lacks `.device`.
|
||||
* @throws Will throw if `drive.device` is not a string.
|
||||
* @throws Will throw if drive lacks `.name`.
|
||||
* @throws Will throw if `drive.name` is not a string.
|
||||
* @throws Will throw if drive lacks `.size`.
|
||||
* @throws Will throw if `drive.size` is not a number.
|
||||
* @throws Will throw if there is an image and the drive is not large enough.
|
||||
*
|
||||
* @example
|
||||
* SelectionStateModel.setDrive({
|
||||
* device: '/dev/disk2'
|
||||
* device: '/dev/disk2',
|
||||
* name: 'USB drive',
|
||||
* size: 999999999
|
||||
* });
|
||||
*/
|
||||
this.setDrive = function(drive) {
|
||||
|
||||
if (!drive.device) {
|
||||
throw new Error('Missing drive device');
|
||||
}
|
||||
|
||||
if (!_.isString(drive.device)) {
|
||||
throw new Error(`Invalid drive device: ${drive.device}`);
|
||||
}
|
||||
|
||||
if (!drive.name) {
|
||||
throw new Error('Missing drive name');
|
||||
}
|
||||
|
||||
if (!_.isString(drive.name)) {
|
||||
throw new Error(`Invalid drive name: ${drive.name}`);
|
||||
}
|
||||
|
||||
if (!drive.size) {
|
||||
throw new Error('Missing drive size');
|
||||
}
|
||||
|
||||
if (!_.isNumber(drive.size)) {
|
||||
throw new Error(`Invalid drive size: ${drive.size}`);
|
||||
}
|
||||
|
||||
if (!self.isDriveLargeEnough(drive)) {
|
||||
throw new Error('The drive is not large enough');
|
||||
}
|
||||
|
||||
selection.drive = drive;
|
||||
};
|
||||
|
||||
/**
|
||||
* @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 = function(drive) {
|
||||
return (self.getImageSize() || 0) <= drive.size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Toggle set drive
|
||||
* @function
|
||||
@ -76,12 +149,36 @@ SelectionStateModel.service('SelectionStateModel', function() {
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {String} image - image
|
||||
* @param {Object} image - image
|
||||
*
|
||||
* @throws Will throw if image lacks `.path`.
|
||||
* @throws Will throw if `image.path` is not a string.
|
||||
* @throws Will throw if image lacks `.size`.
|
||||
* @throws Will throw if `image.size` is not a number.
|
||||
*
|
||||
* @example
|
||||
* SelectionStateModel.setImage('foo.img');
|
||||
* SelectionStateModel.setImage({
|
||||
* path: 'foo.img'
|
||||
* });
|
||||
*/
|
||||
this.setImage = function(image) {
|
||||
|
||||
if (!image.path) {
|
||||
throw new Error('Missing image path');
|
||||
}
|
||||
|
||||
if (!_.isString(image.path)) {
|
||||
throw new Error(`Invalid image path: ${image.path}`);
|
||||
}
|
||||
|
||||
if (!image.size) {
|
||||
throw new Error('Missing image size');
|
||||
}
|
||||
|
||||
if (!_.isNumber(image.size)) {
|
||||
throw new Error(`Invalid image size: ${image.size}`);
|
||||
}
|
||||
|
||||
selection.image = image;
|
||||
};
|
||||
|
||||
@ -104,17 +201,31 @@ SelectionStateModel.service('SelectionStateModel', function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Get image
|
||||
* @summary Get image path
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @returns {String} image
|
||||
* @returns {String} image path
|
||||
*
|
||||
* @example
|
||||
* const image = SelectionStateModel.getImage();
|
||||
* const imagePath = SelectionStateModel.getImagePath();
|
||||
*/
|
||||
this.getImage = function() {
|
||||
return selection.image;
|
||||
this.getImagePath = function() {
|
||||
return _.get(selection.image, 'path');
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Get image size
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @returns {Number} image size
|
||||
*
|
||||
* @example
|
||||
* const imageSize = SelectionStateModel.getImageSize();
|
||||
*/
|
||||
this.getImageSize = function() {
|
||||
return _.get(selection.image, 'size');
|
||||
};
|
||||
|
||||
/**
|
||||
@ -146,7 +257,7 @@ SelectionStateModel.service('SelectionStateModel', function() {
|
||||
* }
|
||||
*/
|
||||
this.hasImage = function() {
|
||||
return Boolean(self.getImage());
|
||||
return Boolean(self.getImagePath() && self.getImageSize());
|
||||
};
|
||||
|
||||
/**
|
||||
@ -157,7 +268,7 @@ SelectionStateModel.service('SelectionStateModel', function() {
|
||||
* @example
|
||||
* SelectionStateModel.removeDrive();
|
||||
*/
|
||||
this.removeDrive = _.partial(self.setDrive, undefined);
|
||||
this.removeDrive = _.partial(_.unset, selection, 'drive');
|
||||
|
||||
/**
|
||||
* @summary Remove image
|
||||
@ -167,7 +278,7 @@ SelectionStateModel.service('SelectionStateModel', function() {
|
||||
* @example
|
||||
* SelectionStateModel.removeImage();
|
||||
*/
|
||||
this.removeImage = _.partial(self.setImage, undefined);
|
||||
this.removeImage = _.partial(_.unset, selection, 'image');
|
||||
|
||||
/**
|
||||
* @summary Clear selections
|
||||
|
@ -17,6 +17,7 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const fs = require('fs');
|
||||
const electron = require('electron');
|
||||
const imageStream = require('etcher-image-stream');
|
||||
|
||||
@ -30,16 +31,16 @@ module.exports = function($q) {
|
||||
* @description
|
||||
* Notice that by image, we mean *.img/*.iso/*.zip/etc files.
|
||||
*
|
||||
* @fulfil {String} - selected image
|
||||
* @fulfil {Object} - selected image
|
||||
* @returns {Promise};
|
||||
*
|
||||
* @example
|
||||
* OSDialogService.selectImage().then(function(image) {
|
||||
* console.log('The selected image is', image);
|
||||
* console.log('The selected image is', image.path);
|
||||
* });
|
||||
*/
|
||||
this.selectImage = function() {
|
||||
return $q(function(resolve) {
|
||||
return $q(function(resolve, reject) {
|
||||
electron.remote.dialog.showOpenDialog({
|
||||
properties: [
|
||||
'openFile'
|
||||
@ -55,8 +56,23 @@ module.exports = function($q) {
|
||||
// `_.first` is smart enough to not throw and return `undefined`
|
||||
// if we pass it an `undefined` value (e.g: when the selection
|
||||
// dialog was cancelled).
|
||||
return resolve(_.first(files));
|
||||
const imagePath = _.first(files);
|
||||
|
||||
if (!imagePath) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
fs.stat(imagePath, function(error, stats) {
|
||||
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
return resolve({
|
||||
path: imagePath,
|
||||
size: stats.size
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -11,7 +11,7 @@
|
||||
<p class="step-footer">.img, .iso, or <span class="step-footer-underline" uib-tooltip=".zip, .xz">compressed images</span></p>
|
||||
</div>
|
||||
<div ng-show="app.selection.hasImage()">
|
||||
<div ng-bind="app.selection.getImage() | basename"></div>
|
||||
<div ng-bind="app.selection.getImagePath() | basename"></div>
|
||||
|
||||
<button class="btn btn-link step-footer"
|
||||
ng-click="app.reselectImage()"
|
||||
@ -74,7 +74,7 @@
|
||||
striped="{{ app.writer.state.type == 'check' }}"
|
||||
ng-attr-active="{{ app.writer.isFlashing() }}"
|
||||
ng-show="app.success"
|
||||
ng-click="app.flash(app.selection.getImage(), app.selection.getDrive())"
|
||||
ng-click="app.flash(app.selection.getImagePath(), app.selection.getDrive())"
|
||||
ng-disabled="!app.selection.hasImage() || !app.selection.hasDrive()">
|
||||
<span ng-show="app.writer.state.progress == 100 && app.writer.isFlashing()">Finishing...</span>
|
||||
<span ng-show="app.writer.state.progress == 0 && !app.writer.isFlashing()">Flash!</span>
|
||||
|
20
lib/gui/scss/components/_list-group.scss
Normal file
20
lib/gui/scss/components/_list-group.scss
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.list-group-item[disabled] {
|
||||
text-decoration: line-through;
|
||||
cursor: not-allowed;
|
||||
}
|
@ -43,6 +43,7 @@ $alert-padding: 13px;
|
||||
@import "./components/tick";
|
||||
@import "./components/modal";
|
||||
@import "./components/alert-ribbon";
|
||||
@import "./components/list-group";
|
||||
@import "../components/update-notifier/styles/update-notifier";
|
||||
@import "../components/progress-button/styles/progress-button";
|
||||
@import "../components/svg-icon/styles/svg-icon";
|
||||
|
@ -29,9 +29,12 @@ describe('Browser: SelectionState', function() {
|
||||
m.chai.expect(drive).to.be.undefined;
|
||||
});
|
||||
|
||||
it('getImage() should return undefined', function() {
|
||||
const image = SelectionStateModel.getImage();
|
||||
m.chai.expect(image).to.be.undefined;
|
||||
it('getImagePath() should return undefined', function() {
|
||||
m.chai.expect(SelectionStateModel.getImagePath()).to.be.undefined;
|
||||
});
|
||||
|
||||
it('getImageSize() should return undefined', function() {
|
||||
m.chai.expect(SelectionStateModel.getImageSize()).to.be.undefined;
|
||||
});
|
||||
|
||||
it('hasDrive() should return false', function() {
|
||||
@ -46,34 +49,25 @@ describe('Browser: SelectionState', function() {
|
||||
|
||||
});
|
||||
|
||||
describe('given an empty object drive', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
SelectionStateModel.setDrive({});
|
||||
});
|
||||
|
||||
describe('.getDrive()', function() {
|
||||
|
||||
it('should return undefined', function() {
|
||||
const drive = SelectionStateModel.getDrive();
|
||||
m.chai.expect(drive).to.be.undefined;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('given a drive', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
SelectionStateModel.setDrive('/dev/disk2');
|
||||
SelectionStateModel.setDrive({
|
||||
device: '/dev/disk2',
|
||||
name: 'USB Drive',
|
||||
size: 999999999
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getDrive()', function() {
|
||||
|
||||
it('should return the drive', function() {
|
||||
const drive = SelectionStateModel.getDrive();
|
||||
m.chai.expect(drive).to.equal('/dev/disk2');
|
||||
m.chai.expect(drive).to.deep.equal({
|
||||
device: '/dev/disk2',
|
||||
name: 'USB Drive',
|
||||
size: 999999999
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@ -90,9 +84,18 @@ describe('Browser: SelectionState', function() {
|
||||
describe('.setDrive()', function() {
|
||||
|
||||
it('should override the drive', function() {
|
||||
SelectionStateModel.setDrive('/dev/disk5');
|
||||
SelectionStateModel.setDrive({
|
||||
device: '/dev/disk5',
|
||||
name: 'USB Drive',
|
||||
size: 999999999
|
||||
});
|
||||
|
||||
const drive = SelectionStateModel.getDrive();
|
||||
m.chai.expect(drive).to.equal('/dev/disk5');
|
||||
m.chai.expect(drive).to.deep.equal({
|
||||
device: '/dev/disk5',
|
||||
name: 'USB Drive',
|
||||
size: 999999999
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@ -114,9 +117,75 @@ describe('Browser: SelectionState', function() {
|
||||
describe('.setDrive()', function() {
|
||||
|
||||
it('should be able to set a drive', function() {
|
||||
SelectionStateModel.setDrive('/dev/disk5');
|
||||
SelectionStateModel.setDrive({
|
||||
device: '/dev/disk5',
|
||||
name: 'USB Drive',
|
||||
size: 999999999
|
||||
});
|
||||
|
||||
const drive = SelectionStateModel.getDrive();
|
||||
m.chai.expect(drive).to.equal('/dev/disk5');
|
||||
m.chai.expect(drive).to.deep.equal({
|
||||
device: '/dev/disk5',
|
||||
name: 'USB Drive',
|
||||
size: 999999999
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw if no device', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setDrive({
|
||||
name: 'USB Drive',
|
||||
size: 999999999
|
||||
});
|
||||
}).to.throw('Missing drive device');
|
||||
});
|
||||
|
||||
it('should throw if device is not a string', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setDrive({
|
||||
device: 123,
|
||||
name: 'USB Drive',
|
||||
size: 999999999
|
||||
});
|
||||
}).to.throw('Invalid drive device: 123');
|
||||
});
|
||||
|
||||
it('should throw if no name', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setDrive({
|
||||
device: '/dev/disk2',
|
||||
size: 999999999
|
||||
});
|
||||
}).to.throw('Missing drive name');
|
||||
});
|
||||
|
||||
it('should throw if name is not a string', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setDrive({
|
||||
device: '/dev/disk2',
|
||||
name: 123,
|
||||
size: 999999999
|
||||
});
|
||||
}).to.throw('Invalid drive name: 123');
|
||||
});
|
||||
|
||||
it('should throw if no size', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setDrive({
|
||||
device: '/dev/disk2',
|
||||
name: 'USB Drive'
|
||||
});
|
||||
}).to.throw('Missing drive size');
|
||||
});
|
||||
|
||||
it('should throw if size is not a number', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setDrive({
|
||||
device: '/dev/disk2',
|
||||
name: 'USB Drive',
|
||||
size: '999999999'
|
||||
});
|
||||
}).to.throw('Invalid drive size: 999999999');
|
||||
});
|
||||
|
||||
});
|
||||
@ -126,14 +195,74 @@ describe('Browser: SelectionState', function() {
|
||||
describe('given an image', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
SelectionStateModel.setImage('foo.img');
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: 999999999
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getImage()', function() {
|
||||
describe('.isDriveLargeEnough()', function() {
|
||||
|
||||
it('should return the image', function() {
|
||||
const image = SelectionStateModel.getImage();
|
||||
m.chai.expect(image).to.equal('foo.img');
|
||||
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
|
||||
});
|
||||
|
||||
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
|
||||
});
|
||||
|
||||
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
|
||||
});
|
||||
|
||||
m.chai.expect(result).to.be.false;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('.setDrive()', function() {
|
||||
|
||||
it('should throw if drive is no large enough', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setDrive({
|
||||
device: '/dev/disk1',
|
||||
name: 'USB Drive',
|
||||
size: 999999998
|
||||
});
|
||||
}).to.throw('The drive is not large enough');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('.getImagePath()', function() {
|
||||
|
||||
it('should return the image path', function() {
|
||||
const imagePath = SelectionStateModel.getImagePath();
|
||||
m.chai.expect(imagePath).to.equal('foo.img');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('.getImageSize()', function() {
|
||||
|
||||
it('should return the image size', function() {
|
||||
const imageSize = SelectionStateModel.getImageSize();
|
||||
m.chai.expect(imageSize).to.equal(999999999);
|
||||
});
|
||||
|
||||
});
|
||||
@ -150,9 +279,15 @@ describe('Browser: SelectionState', function() {
|
||||
describe('.setImage()', function() {
|
||||
|
||||
it('should override the image', function() {
|
||||
SelectionStateModel.setImage('bar.img');
|
||||
const image = SelectionStateModel.getImage();
|
||||
m.chai.expect(image).to.equal('bar.img');
|
||||
SelectionStateModel.setImage({
|
||||
path: 'bar.img',
|
||||
size: 999999999
|
||||
});
|
||||
|
||||
const imagePath = SelectionStateModel.getImagePath();
|
||||
m.chai.expect(imagePath).to.equal('bar.img');
|
||||
const imageSize = SelectionStateModel.getImageSize();
|
||||
m.chai.expect(imageSize).to.equal(999999999);
|
||||
});
|
||||
|
||||
});
|
||||
@ -161,8 +296,11 @@ describe('Browser: SelectionState', function() {
|
||||
|
||||
it('should clear the image', function() {
|
||||
SelectionStateModel.removeImage();
|
||||
const image = SelectionStateModel.getImage();
|
||||
m.chai.expect(image).to.be.undefined;
|
||||
|
||||
const imagePath = SelectionStateModel.getImagePath();
|
||||
m.chai.expect(imagePath).to.be.undefined;
|
||||
const imageSize = SelectionStateModel.getImageSize();
|
||||
m.chai.expect(imageSize).to.be.undefined;
|
||||
});
|
||||
|
||||
});
|
||||
@ -171,12 +309,66 @@ 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('.setImage()', function() {
|
||||
|
||||
it('should be able to set an image', function() {
|
||||
SelectionStateModel.setImage('foo.img');
|
||||
const image = SelectionStateModel.getImage();
|
||||
m.chai.expect(image).to.equal('foo.img');
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: 999999999
|
||||
});
|
||||
|
||||
const imagePath = SelectionStateModel.getImagePath();
|
||||
m.chai.expect(imagePath).to.equal('foo.img');
|
||||
const imageSize = SelectionStateModel.getImageSize();
|
||||
m.chai.expect(imageSize).to.equal(999999999);
|
||||
});
|
||||
|
||||
it('should throw if no path', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
size: 999999999
|
||||
});
|
||||
}).to.throw('Missing image path');
|
||||
});
|
||||
|
||||
it('should throw if path is not a string', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 123,
|
||||
size: 999999999
|
||||
});
|
||||
}).to.throw('Invalid image path: 123');
|
||||
});
|
||||
|
||||
it('should throw if no size', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img'
|
||||
});
|
||||
}).to.throw('Missing image size');
|
||||
});
|
||||
|
||||
it('should throw if size is not a number', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: '999999999'
|
||||
});
|
||||
}).to.throw('Invalid image size: 999999999');
|
||||
});
|
||||
|
||||
});
|
||||
@ -186,8 +378,16 @@ describe('Browser: SelectionState', function() {
|
||||
describe('given a drive', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
SelectionStateModel.setDrive('/dev/disk2');
|
||||
SelectionStateModel.setImage('foo.img');
|
||||
SelectionStateModel.setDrive({
|
||||
device: '/dev/disk1',
|
||||
name: 'USB Drive',
|
||||
size: 999999999
|
||||
});
|
||||
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: 999999999
|
||||
});
|
||||
});
|
||||
|
||||
describe('.clear()', function() {
|
||||
@ -217,9 +417,14 @@ describe('Browser: SelectionState', function() {
|
||||
m.chai.expect(drive).to.be.undefined;
|
||||
});
|
||||
|
||||
it('getImage() should return the image', function() {
|
||||
const image = SelectionStateModel.getImage();
|
||||
m.chai.expect(image).to.equal('foo.img');
|
||||
it('getImagePath() should return the image path', function() {
|
||||
const imagePath = SelectionStateModel.getImagePath();
|
||||
m.chai.expect(imagePath).to.equal('foo.img');
|
||||
});
|
||||
|
||||
it('getImageSize() should return the image size', function() {
|
||||
const imageSize = SelectionStateModel.getImageSize();
|
||||
m.chai.expect(imageSize).to.equal(999999999);
|
||||
});
|
||||
|
||||
it('hasDrive() should return false', function() {
|
||||
@ -244,7 +449,7 @@ describe('Browser: SelectionState', function() {
|
||||
SelectionStateModel.setDrive({
|
||||
device: '/dev/sdb',
|
||||
description: 'DataTraveler 2.0',
|
||||
size: '7.3G',
|
||||
size: 999999999,
|
||||
mountpoint: '/media/UNTITLED',
|
||||
name: '/dev/sdb',
|
||||
system: false
|
||||
@ -263,7 +468,7 @@ describe('Browser: SelectionState', function() {
|
||||
m.chai.expect(SelectionStateModel.isCurrentDrive({
|
||||
device: '/dev/sdb',
|
||||
description: 'DataTraveler 2.0',
|
||||
size: '7.3G',
|
||||
size: 999999999,
|
||||
mountpoint: '/media/UNTITLED',
|
||||
name: '/dev/sdb',
|
||||
system: false
|
||||
@ -274,7 +479,7 @@ describe('Browser: SelectionState', function() {
|
||||
m.chai.expect(SelectionStateModel.isCurrentDrive({
|
||||
device: '/dev/sdb',
|
||||
description: 'DataTraveler 2.0',
|
||||
size: '7.3G',
|
||||
size: 999999999,
|
||||
mountpoint: '/media/UNTITLED',
|
||||
name: '/dev/sdb',
|
||||
system: false,
|
||||
@ -286,7 +491,7 @@ describe('Browser: SelectionState', function() {
|
||||
m.chai.expect(SelectionStateModel.isCurrentDrive({
|
||||
device: '/dev/sdc',
|
||||
description: 'DataTraveler 2.0',
|
||||
size: '7.3G',
|
||||
size: 999999999,
|
||||
mountpoint: '/media/UNTITLED',
|
||||
name: '/dev/sdb',
|
||||
system: false
|
||||
@ -297,7 +502,7 @@ describe('Browser: SelectionState', function() {
|
||||
m.chai.expect(SelectionStateModel.isCurrentDrive({
|
||||
device: '/dev/sdb',
|
||||
description: 'DataTraveler 3.0',
|
||||
size: '7.3G',
|
||||
size: 999999999,
|
||||
mountpoint: '/media/UNTITLED',
|
||||
name: '/dev/sdb',
|
||||
system: false
|
||||
@ -325,7 +530,7 @@ describe('Browser: SelectionState', function() {
|
||||
m.chai.expect(SelectionStateModel.isCurrentDrive({
|
||||
device: '/dev/sdb',
|
||||
description: 'DataTraveler 2.0',
|
||||
size: '7.3G',
|
||||
size: 999999999,
|
||||
mountpoint: '/media/UNTITLED',
|
||||
name: '/dev/sdb',
|
||||
system: false
|
||||
@ -345,7 +550,7 @@ describe('Browser: SelectionState', function() {
|
||||
this.drive = {
|
||||
device: '/dev/sdb',
|
||||
description: 'DataTraveler 2.0',
|
||||
size: '7.3G',
|
||||
size: 999999999,
|
||||
mountpoint: '/media/UNTITLED',
|
||||
name: '/dev/sdb',
|
||||
system: false
|
||||
@ -364,7 +569,7 @@ describe('Browser: SelectionState', function() {
|
||||
const drive = {
|
||||
device: '/dev/disk2',
|
||||
name: 'USB Drive',
|
||||
size: '16GB'
|
||||
size: 999999999
|
||||
};
|
||||
|
||||
m.chai.expect(SelectionStateModel.getDrive()).to.deep.equal(this.drive);
|
||||
@ -385,7 +590,7 @@ describe('Browser: SelectionState', function() {
|
||||
const drive = {
|
||||
device: '/dev/disk2',
|
||||
name: 'USB Drive',
|
||||
size: '16GB'
|
||||
size: 999999999
|
||||
};
|
||||
|
||||
m.chai.expect(SelectionStateModel.hasDrive()).to.be.false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user