hunk.code_window:       <span>Validate write on success</span>
       </label>
     </div>
     <div class="checkbox">
       <label>
         <input type="checkbox"
           tabindex="9"
  
hunk.labels: keep keep keep add keep keep keep keep
hunk.after_edit:   <div class="checkbox">
       <label>
         <input type="checkbox"
           tabindex="8"
           ng-model="settings.currentData.trim"
           ng-change="settings.toggle('trim')">
         <span>Trim ext{2,3,4} partitions before writing (raw images only)</span>
       </label>
     </div>
  
hunk.file_path: lib/gui/app/pages/settings/templates/settings.tpl.html
hunk.type: add
file: /*
   * Copyright 2016 resin.io
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *    http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  'use strict'
  
  const m = require('mochainon')
  const flashState = require('../../../lib/gui/app/models/flash-state')
  
  describe('Model: flashState', function () {
    beforeEach(function () {
      flashState.resetState()
    })
  
    describe('flashState', function () {
      describe('.resetState()', function () {
        it('should be able to reset the progress state', function () {
          flashState.setFlashingFlag()
          flashState.setProgressState({
            flashing: 2,
            verifying: 0,
            successful: 0,
            failed: 0,
            type: 'write',
            percentage: 50,
            eta: 15,
            speed: 100000000000,
            totalSpeed: 200000000000
          })
  
          flashState.resetState()
  
          m.chai.expect(flashState.getFlashState()).to.deep.equal({
            flashing: 0,
            verifying: 0,
            successful: 0,
            failed: 0,
            percentage: 0,
            speed: null,
            totalSpeed: null
          })
        })
  
        it('should be able to reset the progress state', function () {
          flashState.unsetFlashingFlag({
            cancelled: false,
            sourceChecksum: '1234'
          })
  
          flashState.resetState()
          m.chai.expect(flashState.getFlashResults()).to.deep.equal({})
        })
  
        it('should unset the flashing flag', function () {
          flashState.setFlashingFlag()
          flashState.resetState()
          m.chai.expect(flashState.isFlashing()).to.be.false
        })
  
        it('should unset the flash uuid', function () {
          flashState.setFlashingFlag()
          flashState.resetState()
          m.chai.expect(flashState.getFlashUuid()).to.be.undefined
        })
      })
  
      describe('.isFlashing()', function () {
        it('should return false by default', function () {
          m.chai.expect(flashState.isFlashing()).to.be.false
        })
  
        it('should return true if flashing', function () {
          flashState.setFlashingFlag()
          m.chai.expect(flashState.isFlashing()).to.be.true
        })
      })
  
      describe('.setProgressState()', function () {
        it('should not allow setting the state if flashing is false', function () {
          flashState.unsetFlashingFlag({
            cancelled: false,
            sourceChecksum: '1234'
          })
  
          m.chai.expect(function () {
            flashState.setProgressState({
              flashing: 2,
              verifying: 0,
              successful: 0,
              failed: 0,
              type: 'write',
              percentage: 50,
              eta: 15,
              speed: 100000000000,
              totalSpeed: 200000000000
            })
          }).to.throw('Can\'t set the flashing state when not flashing')
        })
  
        it('should not throw if percentage is 0', function () {
          flashState.setFlashingFlag()
          m.chai.expect(function () {
            flashState.setProgressState({
              flashing: 2,
              verifying: 0,
              successful: 0,
              failed: 0,
              type: 'write',
              percentage: 0,
              eta: 15,
              speed: 100000000000,
              totalSpeed: 200000000000
            })
          }).to.not.throw('Missing flash fields: percentage')
        })
  
        it('should throw if percentage is outside maximum bound', function () {
          flashState.setFlashingFlag()
          m.chai.expect(function () {
            flashState.setProgressState({
              flashing: 2,
              verifying: 0,
              successful: 0,
              failed: 0,
              type: 'write',
              percentage: 101,
              eta: 15,
              speed: 0,
              totalSpeed: 1
            })
          }).to.throw('Invalid state percentage: 101')
        })
  
        it('should throw if percentage is outside minimum bound', function () {
          flashState.setFlashingFlag()
          m.chai.expect(function () {
            flashState.setProgressState({
              flashing: 2,
              verifying: 0,
              successful: 0,
              failed: 0,
              type: 'write',
              percentage: -1,
              eta: 15,
              speed: 0,
              totalSpeed: 1
            })
          }).to.throw('Invalid state percentage: -1')
        })
  
        it('should not throw if eta is equal to zero', function () {
          flashState.setFlashingFlag()
          m.chai.expect(function () {
            flashState.setProgressState({
              flashing: 2,
              verifying: 0,
              successful: 0,
              failed: 0,
              type: 'write',
              percentage: 50,
              eta: 0,
              speed: 100000000000,
              totalSpeed: 200000000000
            })
          }).to.not.throw('Missing flash field eta')
        })
  
        it('should throw if eta is not a number', function () {
          flashState.setFlashingFlag()
          m.chai.expect(function () {
            flashState.setProgressState({
              flashing: 2,
              verifying: 0,
              successful: 0,
              failed: 0,
              type: 'write',
              percentage: 50,
              eta: '15',
              speed: 100000000000,
              totalSpeed: 200000000000
            })
          }).to.throw('Invalid state eta: 15')
        })
  
        it('should throw if speed is missing', function () {
          flashState.setFlashingFlag()
          m.chai.expect(function () {
            flashState.setProgressState({
              flashing: 2,
              verifying: 0,
              successful: 0,
              failed: 0,
              type: 'write',
              percentage: 50,
              eta: 15,
              totalSpeed: 1
            })
          }).to.throw('Missing flash fields: speed')
        })
  
        it('should not throw if speed is 0', function () {
          flashState.setFlashingFlag()
          m.chai.expect(function () {
            flashState.setProgressState({
              flashing: 2,
              verifying: 0,
              successful: 0,
              failed: 0,
              type: 'write',
              percentage: 50,
              eta: 15,
              speed: 0,
              totalSpeed: 1
            })
          }).to.not.throw('Missing flash fields: speed')
        })
  
        it('should throw if totalSpeed is missing', function () {
          flashState.setFlashingFlag()
          m.chai.expect(function () {
            flashState.setProgressState({
              flashing: 2,
              verifying: 0,
              successful: 0,
              failed: 0,
              type: 'write',
              percentage: 50,
              eta: 15,
              speed: 1
            })
          }).to.throw('Missing flash fields: totalSpeed')
        })
  
        it('should not throw if totalSpeed is 0', function () {
          flashState.setFlashingFlag()
          m.chai.expect(function () {
            flashState.setProgressState({
              flashing: 2,
              verifying: 0,
              successful: 0,
              failed: 0,
              type: 'write',
              percentage: 50,
              eta: 15,
              speed: 0,
              totalSpeed: 0
            })
          }).to.not.throw('Missing flash fields: totalSpeed')
        })
  
        it('should floor the percentage number', function () {
          flashState.setFlashingFlag()
          flashState.setProgressState({
            flashing: 2,
            verifying: 0,
            successful: 0,
            failed: 0,
            type: 'write',
            percentage: 50.253559459485,
            eta: 15,
            speed: 0,
            totalSpeed: 1
          })
  
          m.chai.expect(flashState.getFlashState().percentage).to.equal(50)
        })
  
        it('should error when any field is non-nil but not a finite number', function () {
          m.chai.expect(() => {
            flashState.setFlashingFlag()
            flashState.setProgressState({
              flashing: {},
              verifying: [],
              successful: true,
              failed: 'string',
              percentage: 0,
              eta: 0,
              speed: 0,
              totalSpeed: 0
            })
          }).to.throw('State quantity field(s) not finite number')
        })
  
        it('should not error when all quantity fields are zero', function () {
          m.chai.expect(() => {
            flashState.setFlashingFlag()
            flashState.setProgressState({
              flashing: 0,
              verifying: 0,
              successful: 0,
              failed: 0,
              percentage: 0,
              eta: 0,
              speed: 0,
              totalSpeed: 0
            })
          }).to.not.throw()
        })
      })
  
      describe('.getFlashResults()', function () {
        it('should get the flash results', function () {
          flashState.setFlashingFlag()
  
          const expectedResults = {
            cancelled: false,
            sourceChecksum: '1234'
          }
  
          flashState.unsetFlashingFlag(expectedResults)
          const results = flashState.getFlashResults()
          m.chai.expect(results).to.deep.equal(expectedResults)
        })
      })
  
      describe('.getFlashState()', function () {
        it('should initially return an empty state', function () {
          flashState.resetState()
          const currentFlashState = flashState.getFlashState()
          m.chai.expect(currentFlashState).to.deep.equal({
            flashing: 0,
            verifying: 0,
            successful: 0,
            failed: 0,
            percentage: 0,
            speed: null,
            totalSpeed: null
          })
        })
  
        it('should return the current flash state', function () {
          const state = {
            flashing: 1,
            verifying: 0,
            successful: 0,
            failed: 0,
            percentage: 50,
            eta: 15,
            speed: 0,
            totalSpeed: 0
          }
  
          flashState.setFlashingFlag()
          flashState.setProgressState(state)
          const currentFlashState = flashState.getFlashState()
          m.chai.expect(currentFlashState).to.deep.equal({
            flashing: 1,
            verifying: 0,
            successful: 0,
            failed: 0,
            percentage: 50,
            eta: 15,
            speed: 0,
            totalSpeed: 0
          })
        })
      })
  
      describe('.unsetFlashingFlag()', function () {
        it('should throw if no flashing results', function () {
          m.chai.expect(function () {
            flashState.unsetFlashingFlag()
          }).to.throw('Missing results')
        })
  
        it('should be able to set a string error code', function () {
          flashState.unsetFlashingFlag({
            cancelled: false,
            sourceChecksum: '1234',
            errorCode: 'EBUSY'
          })
  
          m.chai.expect(flashState.getLastFlashErrorCode()).to.equal('EBUSY')
        })
  
        it('should be able to set a number error code', function () {
          flashState.unsetFlashingFlag({
            cancelled: false,
            sourceChecksum: '1234',
            errorCode: 123
          })
  
          m.chai.expect(flashState.getLastFlashErrorCode()).to.equal(123)
        })
  
        it('should throw if errorCode is not a number not a string', function () {
          m.chai.expect(function () {
            flashState.unsetFlashingFlag({
              cancelled: false,
              sourceChecksum: '1234',
              errorCode: {
                name: 'EBUSY'
              }
            })
          }).to.throw('Invalid results errorCode: [object Object]')
        })
  
        it('should default cancelled to false', function () {
          flashState.unsetFlashingFlag({
            sourceChecksum: '1234'
          })
  
          const flashResults = flashState.getFlashResults()
  
          m.chai.expect(flashResults).to.deep.equal({
            cancelled: false,
            sourceChecksum: '1234'
          })
        })
  
        it('should throw if cancelled is not boolean', function () {
          m.chai.expect(function () {
            flashState.unsetFlashingFlag({
              cancelled: 'false',
              sourceChecksum: '1234'
            })
          }).to.throw('Invalid results cancelled: false')
        })
  
        it('should throw if cancelled is true and sourceChecksum exists', function () {
          m.chai.expect(function () {
            flashState.unsetFlashingFlag({
              cancelled: true,
              sourceChecksum: '1234'
            })
          }).to.throw('The sourceChecksum value can\'t exist if the flashing was cancelled')
        })
  
        it('should be able to set flashing to false', function () {
          flashState.unsetFlashingFlag({
            cancelled: false,
            sourceChecksum: '1234'
          })
  
          m.chai.expect(flashState.isFlashing()).to.be.false
        })
  
        it('should reset the flashing state', function () {
          flashState.setFlashingFlag()
  
          flashState.setProgressState({
            flashing: 2,
            verifying: 0,
            successful: 0,
            failed: 0,
            type: 'write',
            percentage: 50,
            eta: 15,
            speed: 100000000000,
            totalSpeed: 200000000000
          })
  
          m.chai.expect(flashState.getFlashState()).to.not.deep.equal({
            flashing: 2,
            verifying: 0,
            successful: 0,
            failed: 0,
            percentage: 0,
            speed: 0,
            totalSpeed: 0
          })
  
          flashState.unsetFlashingFlag({
            cancelled: false,
            sourceChecksum: '1234'
          })
  
          m.chai.expect(flashState.getFlashState()).to.deep.equal({
            flashing: 0,
            verifying: 0,
            successful: 0,
            failed: 0,
            percentage: 0,
            speed: null,
            totalSpeed: null
          })
        })
  
        it('should not reset the flash uuid', function () {
          flashState.setFlashingFlag()
          const uuidBeforeUnset = flashState.getFlashUuid()
  
          flashState.unsetFlashingFlag({
            sourceChecksum: '1234',
            cancelled: false
          })
  
          const uuidAfterUnset = flashState.getFlashUuid()
          m.chai.expect(uuidBeforeUnset).to.equal(uuidAfterUnset)
        })
      })
  
      describe('.setFlashingFlag()', function () {
        it('should be able to set flashing to true', function () {
          flashState.setFlashingFlag()
          m.chai.expect(flashState.isFlashing()).to.be.true
        })
  
        it('should reset the flash results', function () {
          const expectedResults = {
            cancelled: false,
            sourceChecksum: '1234'
          }
  
          flashState.unsetFlashingFlag(expectedResults)
          const results = flashState.getFlashResults()
          m.chai.expect(results).to.deep.equal(expectedResults)
          flashState.setFlashingFlag()
          m.chai.expect(flashState.getFlashResults()).to.deep.equal({})
        })
      })
  
      describe('.wasLastFlashCancelled()', function () {
        it('should return false given a pristine state', function () {
          flashState.resetState()
          m.chai.expect(flashState.wasLastFlashCancelled()).to.be.false
        })
  
        it('should return false if !cancelled', function () {
          flashState.unsetFlashingFlag({
            sourceChecksum: '1234',
            cancelled: false
          })
  
          m.chai.expect(flashState.wasLastFlashCancelled()).to.be.false
        })
  
        it('should return true if cancelled', function () {
          flashState.unsetFlashingFlag({
            cancelled: true
          })
  
          m.chai.expect(flashState.wasLastFlashCancelled()).to.be.true
        })
      })
  
      describe('.getLastFlashSourceChecksum()', function () {
        it('should return undefined given a pristine state', function () {
          flashState.resetState()
          m.chai.expect(flashState.getLastFlashSourceChecksum()).to.be.undefined
        })
  
        it('should return the last flash source checksum', function () {
          flashState.unsetFlashingFlag({
            sourceChecksum: '1234',
            cancelled: false
          })
  
          m.chai.expect(flashState.getLastFlashSourceChecksum()).to.equal('1234')
        })
  
        it('should return undefined if the last flash was cancelled', function () {
          flashState.unsetFlashingFlag({
            cancelled: true
          })
  
          m.chai.expect(flashState.getLastFlashSourceChecksum()).to.be.undefined
        })
      })
  
      describe('.getLastFlashErrorCode()', function () {
        it('should return undefined given a pristine state', function () {
          flashState.resetState()
          m.chai.expect(flashState.getLastFlashErrorCode()).to.be.undefined
        })
  
        it('should return the last flash error code', function () {
          flashState.unsetFlashingFlag({
            sourceChecksum: '1234',
            cancelled: false,
            errorCode: 'ENOSPC'
          })
  
          m.chai.expect(flashState.getLastFlashErrorCode()).to.equal('ENOSPC')
        })
  
        it('should return undefined if the last flash did not report an error code', function () {
          flashState.unsetFlashingFlag({
            sourceChecksum: '1234',
            cancelled: false
          })
  
          m.chai.expect(flashState.getLastFlashErrorCode()).to.be.undefined
        })
      })
  
      describe('.getFlashUuid()', function () {
        const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
  
        it('should be initially undefined', function () {
          m.chai.expect(flashState.getFlashUuid()).to.be.undefined
        })
  
        it('should be a valid uuid if the flashing flag is set', function () {
          flashState.setFlashingFlag()
          const uuid = flashState.getFlashUuid()
          m.chai.expect(UUID_REGEX.test(uuid)).to.be.true
        })
  
        it('should return different uuids every time the flashing flag is set', function () {
          flashState.setFlashingFlag()
          const uuid1 = flashState.getFlashUuid()
          flashState.unsetFlashingFlag({
            sourceChecksum: '1234',
            cancelled: false
          })
  
          flashState.setFlashingFlag()
          const uuid2 = flashState.getFlashUuid()
          flashState.unsetFlashingFlag({
            cancelled: true
          })
  
          flashState.setFlashingFlag()
          const uuid3 = flashState.getFlashUuid()
          flashState.unsetFlashingFlag({
            sourceChecksum: '1234',
            cancelled: false
          })
  
          m.chai.expect(UUID_REGEX.test(uuid1)).to.be.true
          m.chai.expect(UUID_REGEX.test(uuid2)).to.be.true
          m.chai.expect(UUID_REGEX.test(uuid3)).to.be.true
  
          m.chai.expect(uuid1).to.not.equal(uuid2)
          m.chai.expect(uuid2).to.not.equal(uuid3)
          m.chai.expect(uuid3).to.not.equal(uuid1)
        })
      })
    })
  })
  