diff --git a/lib/cli/writer.js b/lib/cli/writer.js index eca53cfd..b5d9bd5b 100644 --- a/lib/cli/writer.js +++ b/lib/cli/writer.js @@ -69,9 +69,7 @@ exports.writeImage = (imagePath, drive, options, onProgress) => { return fs.openAsync(drive.raw, 'rs+'); }).then((driveFileDescriptor) => { return imageStream.getFromFilePath(imagePath).then((image) => { - if (!image.size.final.estimation && !constraints.isDriveLargeEnough(drive, { - size: image.size.final.value - })) { + if (!constraints.isDriveLargeEnough(drive, image)) { throw errors.createUserError( 'The image you selected is too big for this drive', 'Please connect a bigger drive and try again' diff --git a/lib/gui/models/selection-state.js b/lib/gui/models/selection-state.js index 583aad86..3c856f1f 100644 --- a/lib/gui/models/selection-state.js +++ b/lib/gui/models/selection-state.js @@ -146,7 +146,9 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) { return _.get(Store.getState().toJS(), [ 'selection', 'image', - 'size' + 'size', + 'final', + 'value' ]); }; diff --git a/lib/gui/models/store.js b/lib/gui/models/store.js index 3c5756fa..5b6c0028 100644 --- a/lib/gui/models/store.js +++ b/lib/gui/models/store.js @@ -287,10 +287,24 @@ const storeReducer = (state = DEFAULT_STATE, action) => { throw errors.createError('Missing image size'); } - if (!_.isNumber(action.data.size)) { + if (!_.isPlainObject(action.data.size)) { throw errors.createError(`Invalid image size: ${action.data.size}`); } + const MINIMUM_IMAGE_SIZE = 0; + + if (!_.isInteger(action.data.size.original) || action.data.size.original < MINIMUM_IMAGE_SIZE) { + throw errors.createError(`Invalid original image size: ${action.data.size.original}`); + } + + if (!_.isInteger(action.data.size.final.value) || action.data.size.final.value < MINIMUM_IMAGE_SIZE) { + throw errors.createError(`Invalid final image size: ${action.data.size.final.value}`); + } + + if (!_.isBoolean(action.data.size.final.estimation)) { + throw errors.createError(`Invalid final image size estimation flag: ${action.data.size.final.estimation}`); + } + if (action.data.url && !_.isString(action.data.url)) { throw errors.createError(`Invalid image url: ${action.data.url}`); } diff --git a/lib/gui/os/dialog/services/dialog.js b/lib/gui/os/dialog/services/dialog.js index 013f0901..3d3fae64 100644 --- a/lib/gui/os/dialog/services/dialog.js +++ b/lib/gui/os/dialog/services/dialog.js @@ -18,7 +18,6 @@ const _ = require('lodash'); const electron = require('electron'); -const imageStream = require('../../../../image-stream'); const errors = require('../../../../shared/errors'); module.exports = function($q, SupportedFormatsModel) { @@ -47,7 +46,7 @@ module.exports = function($q, SupportedFormatsModel) { * }); */ this.selectImage = () => { - return $q((resolve, reject) => { + return $q((resolve) => { electron.remote.dialog.showOpenDialog(currentWindow, { // This variable is set when running in GNU/Linux from @@ -73,17 +72,8 @@ module.exports = function($q, SupportedFormatsModel) { // `_.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). - const imagePath = _.first(files); + return resolve(_.first(files)); - if (!imagePath) { - return resolve(); - } - - return imageStream.getImageMetadata(imagePath).then((metadata) => { - metadata.path = imagePath; - metadata.size = metadata.size.final.value; - return resolve(metadata); - }).catch(reject); }); }); }; diff --git a/lib/gui/os/dropzone/directives/dropzone.js b/lib/gui/os/dropzone/directives/dropzone.js index fa1a531c..d744c1a9 100644 --- a/lib/gui/os/dropzone/directives/dropzone.js +++ b/lib/gui/os/dropzone/directives/dropzone.js @@ -17,7 +17,6 @@ 'use strict'; const _ = require('lodash'); -const fs = require('fs'); /** * @summary Dropzone directive @@ -60,10 +59,7 @@ module.exports = ($timeout) => { // Pass the filename as a named // parameter called `$file` - $file: { - path: filename, - size: fs.statSync(filename).size - } + $file: filename }); }); diff --git a/lib/gui/pages/main/controllers/image-selection.js b/lib/gui/pages/main/controllers/image-selection.js index 553de563..2611d1d2 100644 --- a/lib/gui/pages/main/controllers/image-selection.js +++ b/lib/gui/pages/main/controllers/image-selection.js @@ -21,6 +21,7 @@ const Bluebird = require('bluebird'); const path = require('path'); const messages = require('../../../../shared/messages'); const errors = require('../../../../shared/errors'); +const imageStream = require('../../../../image-stream'); module.exports = function( SupportedFormatsModel, @@ -107,6 +108,22 @@ module.exports = function( }).catch(ErrorService.reportException); }; + /** + * @summary Select an image by path + * @function + * @public + * + * @param {String} imagePath - image path + * + * @example + * ImageSelectionController.selectImageByPath('path/to/image.img'); + */ + this.selectImageByPath = (imagePath) => { + imageStream.getImageMetadata(imagePath) + .then(this.selectImage) + .catch(ErrorService.reportException); + }; + /** * @summary Open image selector * @function @@ -118,16 +135,16 @@ module.exports = function( this.openImageSelector = () => { AnalyticsService.logEvent('Open image selector'); - OSDialogService.selectImage().then((image) => { + OSDialogService.selectImage().then((imagePath) => { // Avoid analytics and selection state changes // if no file was resolved from the dialog. - if (!image) { + if (!imagePath) { AnalyticsService.logEvent('Image selector closed'); return; } - this.selectImage(image); + this.selectImageByPath(imagePath); }).catch(ErrorService.reportException); }; diff --git a/lib/gui/pages/main/templates/main.tpl.html b/lib/gui/pages/main/templates/main.tpl.html index abba9f69..cec6880f 100644 --- a/lib/gui/pages/main/templates/main.tpl.html +++ b/lib/gui/pages/main/templates/main.tpl.html @@ -1,6 +1,6 @@
-
+
{ }).then((results) => { results.metadata.stream = results.imageStream; results.metadata.transform = new PassThroughStream(); + results.metadata.path = archive; results.metadata.size = { original: imageEntry.size, diff --git a/lib/image-stream/handlers.js b/lib/image-stream/handlers.js index 5e3ee73a..d46673fb 100644 --- a/lib/image-stream/handlers.js +++ b/lib/image-stream/handlers.js @@ -48,6 +48,7 @@ module.exports = { */ 'application/x-bzip2': (file, options) => { return Bluebird.props({ + path: file, stream: fs.createReadStream(file), size: { original: options.size, @@ -76,6 +77,7 @@ module.exports = { 'application/gzip': (file, options) => { return gzip.getUncompressedSize(file).then((uncompressedSize) => { return Bluebird.props({ + path: file, stream: fs.createReadStream(file), size: { original: options.size, @@ -109,6 +111,7 @@ module.exports = { }); }).then((metadata) => { return { + path: file, stream: fs.createReadStream(file), size: { original: options.size, @@ -151,6 +154,7 @@ module.exports = { */ 'application/octet-stream': (file, options) => { return Bluebird.props({ + path: file, stream: fs.createReadStream(file), size: { original: options.size, diff --git a/lib/shared/drive-constraints.js b/lib/shared/drive-constraints.js index 1e5e0647..585ac506 100644 --- a/lib/shared/drive-constraints.js +++ b/lib/shared/drive-constraints.js @@ -142,7 +142,31 @@ exports.isSourceDrive = (drive, image) => { * } */ exports.isDriveLargeEnough = (drive, image) => { - return _.get(drive, [ 'size' ], UNKNOWN_SIZE) >= _.get(image, [ 'size' ], UNKNOWN_SIZE); + const driveSize = _.get(drive, [ 'size' ], UNKNOWN_SIZE); + + if (_.get(image, [ 'size', 'final', 'estimation' ])) { + + // If the drive size is smaller than the original image size, and + // the final image size is just an estimation, then we stop right + // here, based on the assumption that the final size will never + // be less than the original size. + if (driveSize < _.get(image, [ 'size', 'original' ], UNKNOWN_SIZE)) { + return false; + } + + // If the final image size is just an estimation then consider it + // large enough. In the worst case, the user gets an error saying + // the drive has ran out of space, instead of prohibiting the flash + // at all, when the estimation may be wrong. + return true; + + } + + return driveSize >= _.get(image, [ + 'size', + 'final', + 'value' + ], UNKNOWN_SIZE); }; /** diff --git a/tests/gui/models/drives.spec.js b/tests/gui/models/drives.spec.js index 8c7008db..5fb4d7e4 100644 --- a/tests/gui/models/drives.spec.js +++ b/tests/gui/models/drives.spec.js @@ -118,7 +118,13 @@ describe('Browser: DrivesModel', function() { SelectionStateModel.removeDrive(); SelectionStateModel.setImage({ path: this.imagePath, - size: 999999999, + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + }, recommendedDriveSize: 2000000000 }); }); diff --git a/tests/gui/models/selection-state.spec.js b/tests/gui/models/selection-state.spec.js index 15c18b89..1a7d1a7b 100644 --- a/tests/gui/models/selection-state.spec.js +++ b/tests/gui/models/selection-state.spec.js @@ -221,7 +221,13 @@ describe('Browser: SelectionState', function() { beforeEach(function() { this.image = { path: 'foo.img', - size: 999999999, + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + }, recommendedDriveSize: 1000000000, url: 'https://www.raspbian.org', supportUrl: 'https://www.raspbian.org/forums/', @@ -336,7 +342,13 @@ describe('Browser: SelectionState', function() { it('should override the image', function() { SelectionStateModel.setImage({ path: 'bar.img', - size: 999999999 + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } }); const imagePath = SelectionStateModel.getImagePath(); @@ -369,7 +381,13 @@ describe('Browser: SelectionState', function() { it('should be able to set an image', function() { SelectionStateModel.setImage({ path: 'foo.img', - size: 999999999 + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } }); const imagePath = SelectionStateModel.getImagePath(); @@ -381,7 +399,13 @@ describe('Browser: SelectionState', function() { it('should throw if no path', function() { m.chai.expect(function() { SelectionStateModel.setImage({ - size: 999999999 + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } }); }).to.throw('Missing image path'); }); @@ -390,7 +414,13 @@ describe('Browser: SelectionState', function() { m.chai.expect(function() { SelectionStateModel.setImage({ path: 123, - size: 999999999 + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } }); }).to.throw('Invalid image path: 123'); }); @@ -403,40 +433,163 @@ describe('Browser: SelectionState', function() { }).to.throw('Missing image size'); }); - it('should throw if size is not a number', function() { + it('should throw if size is not a plain object', function() { m.chai.expect(function() { SelectionStateModel.setImage({ path: 'foo.img', - size: '999999999' + size: 999999999 }); }).to.throw('Invalid image size: 999999999'); }); - it('should throw if url is defined but its not a string', function() { + it('should throw if the original size is not a number', function() { m.chai.expect(function() { SelectionStateModel.setImage({ path: 'foo.img', - size: 999999999, + size: { + original: '999999999', + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid original image size: 999999999'); + }); + + it('should throw if the original size is a float number', function() { + m.chai.expect(function() { + SelectionStateModel.setImage({ + path: 'foo.img', + size: { + original: 999999999.999, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid original image size: 999999999.999'); + }); + + it('should throw if the original size is negative', function() { + m.chai.expect(function() { + SelectionStateModel.setImage({ + path: 'foo.img', + size: { + original: -1, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid original image size: -1'); + }); + + it('should throw if the final size is not a number', function() { + m.chai.expect(function() { + SelectionStateModel.setImage({ + path: 'foo.img', + size: { + original: 999999999, + final: { + estimation: false, + value: '999999999' + } + } + }); + }).to.throw('Invalid final image size: 999999999'); + }); + + it('should throw if the final size is a float number', function() { + m.chai.expect(function() { + SelectionStateModel.setImage({ + path: 'foo.img', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999.999 + } + } + }); + }).to.throw('Invalid final image size: 999999999.999'); + }); + + it('should throw if the final size is negative', function() { + m.chai.expect(function() { + SelectionStateModel.setImage({ + path: 'foo.img', + size: { + original: 999999999, + final: { + estimation: false, + value: -1 + } + } + }); + }).to.throw('Invalid final image size: -1'); + }); + + it('should throw if the final size estimation flag is not a boolean', function() { + m.chai.expect(function() { + SelectionStateModel.setImage({ + path: 'foo.img', + size: { + original: 999999999, + final: { + estimation: 'false', + value: 999999999 + } + } + }); + }).to.throw('Invalid final image size estimation flag: false'); + }); + + it('should throw if url is defined but it\'s not a string', function() { + m.chai.expect(function() { + SelectionStateModel.setImage({ + path: 'foo.img', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + }, url: 1234 }); }).to.throw('Invalid image url: 1234'); }); - it('should throw if name is defined but its not a string', function() { + it('should throw if name is defined but it\'s not a string', function() { m.chai.expect(function() { SelectionStateModel.setImage({ path: 'foo.img', - size: 999999999, + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + }, name: 1234 }); }).to.throw('Invalid image name: 1234'); }); - it('should throw if logo is defined but its not a string', function() { + it('should throw if logo is defined but it\'s not a string', function() { m.chai.expect(function() { SelectionStateModel.setImage({ path: 'foo.img', - size: 999999999, + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + }, logo: 1234 }); }).to.throw('Invalid image logo: 1234'); @@ -457,7 +610,13 @@ describe('Browser: SelectionState', function() { SelectionStateModel.setImage({ path: 'foo.img', - size: 9999999999 + size: { + original: 9999999999, + final: { + estimation: false, + value: 9999999999 + } + } }); m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; @@ -479,7 +638,13 @@ describe('Browser: SelectionState', function() { SelectionStateModel.setImage({ path: 'foo.img', - size: 999999999, + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + }, recommendedDriveSize: 1500000000 }); @@ -515,7 +680,13 @@ describe('Browser: SelectionState', function() { SelectionStateModel.setImage({ path: imagePath, - size: 999999999 + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } }); m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; @@ -542,7 +713,13 @@ describe('Browser: SelectionState', function() { SelectionStateModel.setImage({ path: 'foo.img', - size: 999999999 + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } }); }); diff --git a/tests/gui/os/dropzone.spec.js b/tests/gui/os/dropzone.spec.js index 8ac02996..6cff270e 100644 --- a/tests/gui/os/dropzone.spec.js +++ b/tests/gui/os/dropzone.spec.js @@ -17,7 +17,6 @@ 'use strict'; const m = require('mochainon'); -const fs = require('fs'); const angular = require('angular'); require('angular-mocks'); @@ -40,20 +39,11 @@ describe('Browser: OSDropzone', function() { })); it('should pass the file back to the callback as $file', function(done) { - const statStub = m.sinon.stub(fs, 'statSync'); $rootScope.onDropZone = function(file) { - statStub.restore(); - m.chai.expect(file).to.deep.equal({ - path: '/foo/bar', - size: 999999999 - }); + m.chai.expect(file).to.deep.equal('/foo/bar'); done(); }; - statStub.returns({ - size: 999999999 - }); - const element = $compile('
Drop a file here
')($rootScope); $rootScope.$digest(); @@ -73,17 +63,11 @@ describe('Browser: OSDropzone', function() { }); it('should pass undefined to the callback if not passing $file', function(done) { - const statStub = m.sinon.stub(fs, 'statSync'); $rootScope.onDropZone = function(file) { - statStub.restore(); m.chai.expect(file).to.be.undefined; done(); }; - statStub.returns({ - size: 999999999 - }); - const element = $compile('
Drop a file here
')($rootScope); $rootScope.$digest(); diff --git a/tests/gui/pages/main.spec.js b/tests/gui/pages/main.spec.js index 88a6ded8..3e9a28a8 100644 --- a/tests/gui/pages/main.spec.js +++ b/tests/gui/pages/main.spec.js @@ -43,7 +43,13 @@ describe('Browser: MainPage', function() { SelectionStateModel.setImage({ path: 'rpi.img', - size: 99999 + size: { + original: 99999, + final: { + estimation: false, + value: 99999 + } + } }); m.chai.expect(controller.shouldDriveStepBeDisabled()).to.be.false; @@ -71,7 +77,13 @@ describe('Browser: MainPage', function() { SelectionStateModel.clear(); SelectionStateModel.setImage({ path: 'rpi.img', - size: 99999 + size: { + original: 99999, + final: { + estimation: false, + value: 99999 + } + } }); m.chai.expect(controller.shouldFlashStepBeDisabled()).to.be.true; @@ -118,7 +130,13 @@ describe('Browser: MainPage', function() { SelectionStateModel.setImage({ path: 'rpi.img', - size: 99999 + size: { + original: 99999, + final: { + estimation: false, + value: 99999 + } + } }); m.chai.expect(controller.shouldFlashStepBeDisabled()).to.be.false; @@ -159,7 +177,13 @@ describe('Browser: MainPage', function() { SelectionStateModel.setImage({ path: path.join(__dirname, 'foo', 'bar.img'), - size: 999999999 + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } }); m.chai.expect(controller.getImageBasename()).to.equal('bar.img'); diff --git a/tests/image-stream/bz2.spec.js b/tests/image-stream/bz2.spec.js index 6c7af238..6cd8a948 100644 --- a/tests/image-stream/bz2.spec.js +++ b/tests/image-stream/bz2.spec.js @@ -47,6 +47,7 @@ describe('ImageStream: BZ2', function() { imageStream.getImageMetadata(image).then((metadata) => { m.chai.expect(metadata).to.deep.equal({ + path: image, size: { original: expectedSize, final: { diff --git a/tests/image-stream/gz.spec.js b/tests/image-stream/gz.spec.js index 08cf10c1..cad48ae9 100644 --- a/tests/image-stream/gz.spec.js +++ b/tests/image-stream/gz.spec.js @@ -48,6 +48,7 @@ describe('ImageStream: GZ', function() { imageStream.getImageMetadata(image).then((metadata) => { m.chai.expect(metadata).to.deep.equal({ + path: image, size: { original: compressedSize, final: { diff --git a/tests/image-stream/img.spec.js b/tests/image-stream/img.spec.js index 16e16552..9fb01b1b 100644 --- a/tests/image-stream/img.spec.js +++ b/tests/image-stream/img.spec.js @@ -46,6 +46,7 @@ describe('ImageStream: IMG', function() { imageStream.getImageMetadata(image).then((metadata) => { m.chai.expect(metadata).to.deep.equal({ + path: image, size: { original: expectedSize, final: { diff --git a/tests/image-stream/xz.spec.js b/tests/image-stream/xz.spec.js index cffb11ab..06b90198 100644 --- a/tests/image-stream/xz.spec.js +++ b/tests/image-stream/xz.spec.js @@ -48,6 +48,7 @@ describe('ImageStream: XZ', function() { imageStream.getImageMetadata(image).then((metadata) => { m.chai.expect(metadata).to.deep.equal({ + path: image, size: { original: compressedSize, final: { diff --git a/tests/image-stream/zip.spec.js b/tests/image-stream/zip.spec.js index 81be1e07..c0bd95be 100644 --- a/tests/image-stream/zip.spec.js +++ b/tests/image-stream/zip.spec.js @@ -71,6 +71,7 @@ describe('ImageStream: ZIP', function() { imageStream.getImageMetadata(image).then((metadata) => { m.chai.expect(metadata).to.deep.equal({ + path: image, size: { original: expectedSize, final: { diff --git a/tests/shared/drive-constraints.spec.js b/tests/shared/drive-constraints.spec.js index 8f6bc15c..9d4bbc56 100644 --- a/tests/shared/drive-constraints.spec.js +++ b/tests/shared/drive-constraints.spec.js @@ -303,52 +303,219 @@ describe('Shared: DriveConstraints', function() { 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({ + beforeEach(function() { + this.drive = { 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 + describe('given the final image size estimation flag is false', function() { + + describe('given the original size is less than the drive size', function() { + + beforeEach(function() { + this.image = { + path: path.join(__dirname, 'rpi.img'), + size: { + original: this.drive.size - 1, + final: { + estimation: false + } + } + }; + }); + + it('should return true if the final size is less than the drive size', function() { + this.image.size.final.value = this.drive.size - 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + it('should return true if the final size is equal to the drive size', function() { + this.image.size.final.value = this.drive.size; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + it('should return false if the final size is greater than the drive size', function() { + this.image.size.final.value = this.drive.size + 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false; + }); + + }); + + describe('given the original size is equal to the drive size', function() { + + beforeEach(function() { + this.image = { + path: path.join(__dirname, 'rpi.img'), + size: { + original: this.drive.size, + final: { + estimation: false + } + } + }; + }); + + it('should return true if the final size is less than the drive size', function() { + this.image.size.final.value = this.drive.size - 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + it('should return true if the final size is equal to the drive size', function() { + this.image.size.final.value = this.drive.size; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + it('should return false if the final size is greater than the drive size', function() { + this.image.size.final.value = this.drive.size + 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false; + }); + + }); + + describe('given the original size is greater than the drive size', function() { + + beforeEach(function() { + this.image = { + path: path.join(__dirname, 'rpi.img'), + size: { + original: this.drive.size + 1, + final: { + estimation: false + } + } + }; + }); + + it('should return true if the final size is less than the drive size', function() { + this.image.size.final.value = this.drive.size - 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + it('should return true if the final size is equal to the drive size', function() { + this.image.size.final.value = this.drive.size; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + it('should return false if the final size is greater than the drive size', function() { + this.image.size.final.value = this.drive.size + 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false; + }); + + }); + + }); + + describe('given the final image size estimation flag is true', function() { + + describe('given the original size is less than the drive size', function() { + + beforeEach(function() { + this.image = { + path: path.join(__dirname, 'rpi.img'), + size: { + original: this.drive.size - 1, + final: { + estimation: true + } + } + }; + }); + + it('should return true if the final size is less than the drive size', function() { + this.image.size.final.value = this.drive.size - 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + it('should return true if the final size is equal to the drive size', function() { + this.image.size.final.value = this.drive.size; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + it('should return true if the final size is greater than the drive size', function() { + this.image.size.final.value = this.drive.size + 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + }); + + describe('given the original size is equal to the drive size', function() { + + beforeEach(function() { + this.image = { + path: path.join(__dirname, 'rpi.img'), + size: { + original: this.drive.size, + final: { + estimation: true + } + } + }; + }); + + it('should return true if the final size is less than the drive size', function() { + this.image.size.final.value = this.drive.size - 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + it('should return true if the final size is equal to the drive size', function() { + this.image.size.final.value = this.drive.size; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + it('should return true if the final size is greater than the drive size', function() { + this.image.size.final.value = this.drive.size + 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true; + }); + + }); + + describe('given the original size is greater than the drive size', function() { + + beforeEach(function() { + this.image = { + path: path.join(__dirname, 'rpi.img'), + size: { + original: this.drive.size + 1, + final: { + estimation: true + } + } + }; + }); + + it('should return false if the final size is less than the drive size', function() { + this.image.size.final.value = this.drive.size - 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false; + }); + + it('should return false if the final size is equal to the drive size', function() { + this.image.size.final.value = this.drive.size; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false; + }); + + it('should return false if the final size is greater than the drive size', function() { + this.image.size.final.value = this.drive.size + 1; + m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false; + }); + }); - m.chai.expect(result).to.be.false; }); it('should return false if the drive is undefined', function() { const result = constraints.isDriveLargeEnough(undefined, { - path: 'rpi.img', - size: 1000000000 + path: path.join(__dirname, 'rpi.img'), + size: { + original: 1000000000, + final: { + estimation: false, + value: 1000000000 + } + } }); m.chai.expect(result).to.be.false; @@ -381,7 +548,7 @@ describe('Shared: DriveConstraints', function() { size: 2000000001, protected: false }, { - path: 'rpi.img', + path: path.join(__dirname, 'rpi.img'), size: 1000000000, recommendedDriveSize: 2000000000 }); @@ -396,7 +563,7 @@ describe('Shared: DriveConstraints', function() { size: 2000000000, protected: false }, { - path: 'rpi.img', + path: path.join(__dirname, 'rpi.img'), size: 1000000000, recommendedDriveSize: 2000000000 }); @@ -411,7 +578,7 @@ describe('Shared: DriveConstraints', function() { size: 2000000000, protected: false }, { - path: 'rpi.img', + path: path.join(__dirname, 'rpi.img'), size: 1000000000, recommendedDriveSize: 2000000001 }); @@ -426,7 +593,7 @@ describe('Shared: DriveConstraints', function() { size: 2000000000, protected: false }, { - path: 'rpi.img', + path: path.join(__dirname, 'rpi.img'), size: 1000000000 }); @@ -435,7 +602,7 @@ describe('Shared: DriveConstraints', function() { it('should return false if the drive is undefined', function() { const result = constraints.isDriveSizeRecommended(undefined, { - path: 'rpi.img', + path: path.join(__dirname, 'rpi.img'), size: 1000000000, recommendedDriveSize: 1000000000 }); @@ -491,28 +658,52 @@ describe('Shared: DriveConstraints', function() { it('should return false if the drive is not large enough and is a source drive', function() { m.chai.expect(constraints.isDriveValid(this.drive, { path: path.join(this.mountpoint, 'rpi.img'), - size: 5000000000 + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } + } })).to.be.false; }); it('should return false if the drive is not large enough and is not a source drive', function() { m.chai.expect(constraints.isDriveValid(this.drive, { path: path.resolve(this.mountpoint, '../bar/rpi.img'), - size: 5000000000 + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } + } })).to.be.false; }); it('should return false if the drive is large enough and is a source drive', function() { m.chai.expect(constraints.isDriveValid(this.drive, { path: path.join(this.mountpoint, 'rpi.img'), - size: 2000000000 + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } })).to.be.false; }); it('should return false if the drive is large enough and is not a source drive', function() { m.chai.expect(constraints.isDriveValid(this.drive, { path: path.resolve(this.mountpoint, '../bar/rpi.img'), - size: 2000000000 + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } })).to.be.false; }); @@ -527,28 +718,52 @@ describe('Shared: DriveConstraints', function() { it('should return false if the drive is not large enough and is a source drive', function() { m.chai.expect(constraints.isDriveValid(this.drive, { path: path.join(this.mountpoint, 'rpi.img'), - size: 5000000000 + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } + } })).to.be.false; }); it('should return false if the drive is not large enough and is not a source drive', function() { m.chai.expect(constraints.isDriveValid(this.drive, { path: path.resolve(this.mountpoint, '../bar/rpi.img'), - size: 5000000000 + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } + } })).to.be.false; }); it('should return false if the drive is large enough and is a source drive', function() { m.chai.expect(constraints.isDriveValid(this.drive, { path: path.join(this.mountpoint, 'rpi.img'), - size: 2000000000 + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } })).to.be.false; }); it('should return true if the drive is large enough and is not a source drive', function() { m.chai.expect(constraints.isDriveValid(this.drive, { path: path.resolve(this.mountpoint, '../bar/rpi.img'), - size: 2000000000 + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } })).to.be.true; });