1
0
Fork 0

DataValidator, ValidStateMonitor: Add #clearFailures argument

This allows clearing only the specified failures.

* src/validate/ValidStateMonitor.js
  (clearFailures): Add `fields' argument.  Make method more concise.
  (_fixFailure): Handle clearing `_failures' record.

* src/validate/DataValidator.js
  (clearFailures): Add `fields' argument.

* test/validate/ValidStateMonitorTest.js: Add test.
* test/validate/DataValidatorTest.js: Add test.
master
Mike Gerwitz 2017-02-03 16:50:40 -05:00
parent e7700e8b69
commit ed21707920
4 changed files with 101 additions and 33 deletions

View File

@ -159,13 +159,21 @@ module.exports = Class( 'DataValidator',
/**
* Clear all recorded failures
* Clear specified failures, or otherwise all recorded failures
*
* `fields` must be a key-value map with the field name as the key and
* an array of indexes as the value. Any field in `fields` that has no
* failure is ignored.
*
* See `ValidStateMonitor#clearFailures` for more information.
*
* @param {Object} fields key-value names of fields/indexes to clear
*
* @return {DataValidator} self
*/
'public clearFailures'()
'public clearFailures'( failures )
{
this._field_monitor.clearFailures();
this._field_monitor.clearFailures( failures );
return this;
},

View File

@ -263,7 +263,6 @@ module.exports = Class( 'ValidStateMonitor' )
// looks like it has been resolved
this._fixFailure( fixed, name, fail_i, result );
delete past_fail[ fail_i ];
return true;
} );
} ) ).then( fixes => fixes.some( fix => fix === true ) );
@ -328,48 +327,58 @@ module.exports = Class( 'ValidStateMonitor' )
'private _fixFailure'( fixed, name, index, value )
{
( fixed[ name ] = fixed[ name ] || [] )[ index ] = value;
// caller is expected to have ensured that this exists
delete this._failures[ name ][ index ];
return fixed;
},
/**
* Clear all recorded failures
* Clear specified failures, or otherwise all recorded failures
*
* For each recorded failure, a `fix` even is emitted. All failure
* records are then cleared.
* `fields` must be a key-value map with the field name as the key and
* an array of indexes as the value. Any field in `fields` that has no
* failure is ignored.
*
* For each specified failure, a `fix` event is emitted. If no failures
* are specified by `fields`, all recorded failures are marked as
* fixed. If a field in `fields` is not known, it is ignored.
*
* Normally the resulting fix object contains the values that triggered
* the fix. Instead, each fixed index will contain `undefined`.
* the fix. Instead, each fixed index will contain `null`.
*
* This process is synchronous, and only a single `fix` event is emitted
* after all failures have been cleared.
*
* @param {Object} fields key-value names of fields/indexes to clear
*
* @return {ValidStateMonitor} self
*/
'public clearFailures'()
'public clearFailures'( fields )
{
const failures = this._failures;
let fixed = {};
for ( let name in this._failures )
{
const failure = this._failures[ name ];
const isRequestedIndex = ( fields )
? field => ( fields[ field.getName() ] || [] ).indexOf(
field.getIndex()
) !== -1
: () => true;
for ( let cause_i in failure )
{
const cause = failure[ cause_i ];
for ( let cause_i in cause )
{
let fail_i = cause.getField().getIndex();
this._fixFailure( fixed, name, fail_i, undefined );
}
}
}
// clear _before_ emitting the fixes (listeners might trigger
// additional failures, for example, or call `#hasFailures`)
this._failures = {};
Object.keys( failures )
.reduce(
( all_fields, name ) => all_fields.concat(
failures[ name ].map( cause => cause.getField() )
),
[]
)
.filter( isRequestedIndex )
.forEach( field => this._fixFailure(
fixed, field.getName(), field.getIndex(), null
) );
this.emit( 'fix', fixed );

View File

@ -217,7 +217,7 @@ describe( 'DataValidator', () =>
describe( '#clearFailures', () =>
{
it( 'marks all failures as fixed', () =>
it( 'proxies to validator', () =>
{
const bvalidator = createMockBucketValidator();
const vmonitor = ValidStateMonitor();
@ -229,9 +229,14 @@ describe( 'DataValidator', () =>
bvalidator, vmonitor, dep_factory, createStubStore()
);
mock_vmonitor.expects( 'clearFailures' ).once();
const failures = [ 'foo', 'bar' ];
expect( sut.clearFailures() )
mock_vmonitor
.expects( 'clearFailures' )
.once()
.withExactArgs( failures );
expect( sut.clearFailures( failures ) )
.to.equal( sut );
mock_vmonitor.verify();

View File

@ -596,7 +596,7 @@ describe( 'ValidStateMonitor', function()
describe( '#clearFailures', () =>
{
it( 'clears all failures', () =>
it( 'clears all failures when provided no arguments', () =>
{
return new Promise( ( accept, reject ) =>
{
@ -608,7 +608,7 @@ describe( 'ValidStateMonitor', function()
.on( 'fix', fixed =>
{
expect( fixed )
.to.deep.equal( { foo: [ undefined ] } );
.to.deep.equal( { foo: [ null ] } );
expect( sut.hasFailures() ).to.be.false;
@ -620,6 +620,52 @@ describe( 'ValidStateMonitor', function()
.catch( e => reject( e ) );
} );
} );
it( 'clears only provided failures when provided array argument', () =>
{
return new Promise( ( accept, reject ) =>
{
mkstore( {} ).then( empty =>
{
const sut = Sut();
return sut
.on( 'fix', fixed =>
{
debugger;
// `bar' not cleared
expect( fixed )
.to.deep.equal( {
foo: [ null ],
baz: [ , null ],
} );
// still has `bar'
expect( sut.hasFailures() ).to.be.true;
accept( true );
} )
.update( empty, {
foo: mkfail( 'foo', [ 'bar1', 'bar2' ] ),
bar: mkfail( 'bar', [ 'baz' ] ),
baz: mkfail( 'baz', [ 'quux', 'quuux' ] ),
} )
.then( sut => sut.clearFailures( {
foo: [ 0 ],
baz: [ 1 ],
} ) );
} )
.catch( e => reject( e ) );
} );
} );
it( 'does not error on non-existent failure', () =>
{
expect( () => Sut().clearFailures( [ 'foo', 'baz' ] ) )
.to.not.throw( Error );
} );
} );
} );