Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/validate/DataValidator.js14
-rw-r--r--src/validate/ValidStateMonitor.js61
-rw-r--r--test/validate/DataValidatorTest.js11
-rw-r--r--test/validate/ValidStateMonitorTest.js50
4 files changed, 102 insertions, 34 deletions
diff --git a/src/validate/DataValidator.js b/src/validate/DataValidator.js
index 4651fcb..12e663f 100644
--- a/src/validate/DataValidator.js
+++ b/src/validate/DataValidator.js
@@ -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;
},
diff --git a/src/validate/ValidStateMonitor.js b/src/validate/ValidStateMonitor.js
index afe8545..a25a79a 100644
--- a/src/validate/ValidStateMonitor.js
+++ b/src/validate/ValidStateMonitor.js
@@ -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 )
{
- let fixed = {};
-
- for ( let name in this._failures )
- {
- const failure = this._failures[ name ];
+ const failures = this._failures;
- 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 );
- }
- }
- }
+ let fixed = {};
- // clear _before_ emitting the fixes (listeners might trigger
- // additional failures, for example, or call `#hasFailures`)
- this._failures = {};
+ const isRequestedIndex = ( fields )
+ ? field => ( fields[ field.getName() ] || [] ).indexOf(
+ field.getIndex()
+ ) !== -1
+ : () => true;
+
+ 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 );
diff --git a/test/validate/DataValidatorTest.js b/test/validate/DataValidatorTest.js
index 8ff4af9..b31a93e 100644
--- a/test/validate/DataValidatorTest.js
+++ b/test/validate/DataValidatorTest.js
@@ -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();
diff --git a/test/validate/ValidStateMonitorTest.js b/test/validate/ValidStateMonitorTest.js
index 5c44cb4..b57ff07 100644
--- a/test/validate/ValidStateMonitorTest.js
+++ b/test/validate/ValidStateMonitorTest.js
@@ -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 );
+ } );
} );
} );