diff --git a/src/server/rater/DslRater.js b/src/server/rater/DslRater.js
index 490cd80..7c430bb 100644
--- a/src/server/rater/DslRater.js
+++ b/src/server/rater/DslRater.js
@@ -115,7 +115,8 @@ module.exports = Class( 'DslRater' )
{
try
{
- var single = rater( data );
+ var can_term = context.canTerm();
+ var single = rater( data, can_term );
// ensures that any previous eligibility errors are cleared out
single.ineligible = '';
diff --git a/src/server/rater/DslRaterContext.js b/src/server/rater/DslRaterContext.js
index 79dfaef..ebc5d88 100644
--- a/src/server/rater/DslRaterContext.js
+++ b/src/server/rater/DslRaterContext.js
@@ -37,13 +37,13 @@ module.exports = Class( 'DslRaterContext' )
* Hash of classes that will result in a global submit
* @type {Object}
*/
- 'private _globalSubmits': {},
+ 'private _global_submits': {},
/**
* Whether a particular global submit has been triggered
* @type {Object}
*/
- 'private _hasGsubmit': {},
+ 'private _has_g_submit': {},
/**
* Rater corestrictions
@@ -57,6 +57,12 @@ module.exports = Class( 'DslRaterContext' )
*/
'private _data': null,
+ /**
+ * Whether to immediately terminate on assertion failure
+ * @type {boolean}
+ */
+ 'private _can_term': true,
+
/**
* Result sets
* @type {Object}
@@ -67,18 +73,19 @@ module.exports = Class( 'DslRaterContext' )
* Number of available results
* @type {number}
*/
- 'private _availCount': 0,
+ 'private _avail_count': 0,
/**
* Total number of results
* @type {number}
*/
- 'private _totalCount': 0,
+ 'private _total_count': 0,
- __construct: function( data )
+ __construct: function( data, can_term )
{
- this._data = data;
+ this._data = data;
+ this._can_term = ( can_term == undefined ) ? true : !!can_term;
this.init();
},
@@ -90,6 +97,12 @@ module.exports = Class( 'DslRaterContext' )
},
+ 'public canTerm': function()
+ {
+ return this._can_term;
+ },
+
+
'virtual protected init': function()
{
// may be implemented by subtypes
@@ -118,8 +131,8 @@ module.exports = Class( 'DslRaterContext' )
*/
'public addResultSet': function( name, set )
{
- this._totalCount += set.getResultCount();
- this._availCount += set.getAvailableCount();
+ this._total_count += set.getResultCount();
+ this._avail_count += set.getAvailableCount();
this._checkGlobalSubmits( set );
@@ -146,11 +159,11 @@ module.exports = Class( 'DslRaterContext' )
return;
}
- for ( var cname in _self._globalSubmits )
+ for ( var cname in _self._global_submits )
{
if ( result.__classes[ cname ] )
{
- _self._hasGsubmit[ cname ] = true;
+ _self._has_g_submit[ cname ] = true;
}
}
} );
@@ -162,7 +175,7 @@ module.exports = Class( 'DslRaterContext' )
var i = submits.length;
while ( i-- )
{
- this._globalSubmits[ submits[ i ] ] = true;
+ this._global_submits[ submits[ i ] ] = true;
}
return this;
@@ -185,8 +198,8 @@ module.exports = Class( 'DslRaterContext' )
'public complete': function()
{
// allow context some time to manipulate the results mercilessly
- this._availCount = this.processCompleted(
- this._results, this._availCount
+ this._avail_count = this.processCompleted(
+ this._results, this._avail_count
);
this._processGlobalSubmits();
@@ -291,7 +304,7 @@ module.exports = Class( 'DslRaterContext' )
*/
'private _processGlobalSubmits': function()
{
- for ( var cname in this._hasGsubmit )
+ for ( var cname in this._has_g_submit )
{
this._results.forEach( function( set )
{
@@ -302,7 +315,7 @@ module.exports = Class( 'DslRaterContext' )
cname;
result._unavailable = '1';
- this._availCount--;
+ this._avail_count--;
} );
} );
}
@@ -340,7 +353,7 @@ module.exports = Class( 'DslRaterContext' )
} );
- ret.__prem_avail_count = [ this._availCount ];
+ ret.__prem_avail_count = [ this._avail_count ];
return ret;
}
diff --git a/test/server/rater/DslRaterContextTest.js b/test/server/rater/DslRaterContextTest.js
new file mode 100644
index 0000000..3481831
--- /dev/null
+++ b/test/server/rater/DslRaterContextTest.js
@@ -0,0 +1,66 @@
+/**
+ * Tests DslRaterContext
+ *
+ * Copyright (C) 2010-2019 R-T Specialty, LLC.
+ *
+ * This file is part of the Liza Data Collection Framework.
+ *
+ * liza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+'use strict';
+
+const root = require( '../../..' );
+const expect = require( 'chai' ).expect;
+
+const {
+ DslRaterContext: Sut,
+} = root.server.rater;
+
+describe( 'DslRaterContext', () =>
+{
+ describe( 'Defaults', () =>
+ {
+ it( `canTerm is true if not included`, () =>
+ {
+ const expected = true;
+ const data = { foo: 'bar' };
+ const sut = Sut( data );
+ const actual = sut.canTerm();
+
+ expect( actual ).to.equal( expected );
+ } );
+
+
+ it( `canTerm can be set to false`, () =>
+ {
+ const expected = false;
+ const data = { foo: 'bar' };
+ const sut = Sut( data, expected );
+ const actual = sut.canTerm();
+
+ expect( actual ).to.equal( expected );
+ } );
+
+
+ it( `data can be retrieved`, () =>
+ {
+ const expected = { foo: 'bar' };
+ const sut = Sut( expected );
+ const actual = sut.getSourceData();
+
+ expect( actual ).to.deep.equal( expected );
+ } );
+ } );
+} );
diff --git a/test/server/rater/DslRaterTest.js b/test/server/rater/DslRaterTest.js
new file mode 100644
index 0000000..6e83b00
--- /dev/null
+++ b/test/server/rater/DslRaterTest.js
@@ -0,0 +1,245 @@
+/**
+ * Tests DslRater
+ *
+ * Copyright (C) 2010-2019 R-T Specialty, LLC.
+ *
+ * This file is part of the Liza Data Collection Framework.
+ *
+ * liza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+'use strict';
+
+const root = require( '../../..' );
+const expect = require( 'chai' ).expect;
+const Class = require( 'easejs' ).Class;
+
+const {
+ DslRater: Sut,
+ DslRaterContext,
+} = root.server.rater;
+
+describe( 'DslRater', () =>
+{
+ describe( 'rate', () =>
+ {
+ it( `Calls context#rate`, () =>
+ {
+ let called = false;
+
+ const raters = [ getRaterStub(), getRaterStub() ];
+ const resultSet = getResultSetStub();
+ const override = {
+ 'override public rate': function( name, meta, rate, complete )
+ {
+ called = true
+ }
+ };
+
+ const context = getDslContext( override );
+ const sut = Sut( raters, resultSet );
+
+ sut.rate( context );
+
+ expect( called ).to.equal( true );
+ } );
+
+
+ it( `Throws exception on invalid context`, () =>
+ {
+ const raters = [ getRaterStub(), getRaterStub() ];
+ const resultSet = getResultSetStub();
+ const context = {};
+ const sut = Sut( raters, resultSet );
+
+ expect( () => { sut.rate( context ) } )
+ .to.throw( "Invalid DslRaterContext provided" );
+
+ } );
+
+
+ it( `Undefined rater calls context#complete`, () =>
+ {
+ let called = false;
+ let rateCalled = false;
+
+ const raters = [ undefined ];
+ const resultSet = getResultSetStub();
+ const override = {
+ 'override public rate': function( name, meta, rate, complete )
+ {
+ rateCalled = true
+ },
+
+ 'override public processCompleted': function( results, count )
+ {
+ called = true
+ }
+ };
+
+ const context = getDslContext( override );
+ const sut = Sut( raters, resultSet );
+
+ sut.rate( context );
+
+ expect( called ).to.equal( true );
+ expect( rateCalled ).to.equal( false );
+ } );
+
+
+ it( `Calls rater with canTerm from context`, () =>
+ {
+ let actual;
+
+ const expected = false;
+ const callback = ( data, canTerm ) =>
+ {
+ actual = canTerm;
+ called = true;
+ }
+
+ const raters = [ getRaterStub( callback ) ];
+ const resultSet = getResultSetStub();
+ const context = DslRaterContext( null, expected );
+ const sut = Sut( raters, resultSet );
+
+ sut.rate( context );
+
+ expect( actual ).to.equal( expected );
+ } );
+
+
+ it( `Submit or prohibit sets _unavailable flag`, () =>
+ {
+ let called = false;
+ let actual = {};
+
+ const expected = {
+ _unavailable: '1',
+ ineligible: '',
+ submit: 'true',
+ __classes: {
+ 'submit': true,
+ 'submit-foo': true,
+ },
+ };
+ const raterCb = ( _, __ ) => {};
+ const resultCb = ( name, set ) =>
+ {
+ actual = name;
+ called = true;
+ };
+ const classes = {
+ 'submit-foo': true,
+ submit: true,
+ };
+ const raters = [ getRaterStub( raterCb, classes ) ];
+ const resultSet = getResultSetStub( resultCb );
+ const context = DslRaterContext( null, expected );
+ const sut = Sut( raters, resultSet );
+
+ sut.rate( context );
+
+ expect( called ).to.equal( true );
+ expect( actual ).to.deep.equal( expected );
+ } );
+ } );
+
+
+ it( `_unavailable flag defaults to false`, () =>
+ {
+ let called = false;
+ let actual = {};
+
+ const expected = {
+ _unavailable: '0',
+ ineligible: '',
+ submit: '',
+ __classes: {
+ 'foo': true,
+ 'submit': false,
+ },
+ };
+ const raterCb = ( _, __ ) => {};
+ const resultCb = ( name, set ) =>
+ {
+ actual = name;
+ called = true;
+ };
+ const classes = {
+ 'foo': true,
+ submit: false,
+ };
+ const raters = [ getRaterStub( raterCb, classes ) ];
+ const resultSet = getResultSetStub( resultCb );
+ const context = DslRaterContext( null, expected );
+ const sut = Sut( raters, resultSet );
+
+ sut.rate( context );
+
+ expect( called ).to.equal( true );
+ expect( actual ).to.deep.equal( expected );
+ } );
+
+
+ function getRaterStub( callback = ( _, __ ) => {}, classes = [] )
+ {
+ let raterStub = ( function()
+ {
+ var raterStub = function( data, canTerm )
+ {
+ callback( data, canTerm );
+
+ return {
+ __classes: classes
+ };
+ }
+
+ raterStub.supplier = 'bar';
+ raterStub.rater = {
+ meta: 'foo',
+ classify: {
+ desc: classes
+ },
+ };
+
+ return raterStub;
+ } )();
+
+ return raterStub;
+ }
+
+
+ function getResultSetStub( callback = ( _, __ ) => {} )
+ {
+ return ( str ) => {
+ return {
+ addResult( name, set ){
+ callback( name, set );
+ }
+ }
+ };
+ }
+
+
+ function getDslContext( override, data, canTerm )
+ {
+ const ContextCtr = Class( 'DummyDslRaterContext' ).extend(
+ DslRaterContext,
+ override
+ );
+
+ return ContextCtr( data, canTerm );
+ }
+} );