progtest: Check inputs against known params

This aims to prevent needlessly wasted time debugging a non-working test
case, and to avoid writing incorrect test cases that happen to succeed even
though their inputs aren't properly defined.

For example, a common error is to use the name of a bucket field rather than
the name of the param that it maps to.

* progtest/src/TestRunner.js (_verifyKnownParams): New method.
  (_tryRun): Use it.
* progtest/test/TestRunnerTest.js: New test case.  Modify existing test
   cases to define used params.
* progtest/test/_stub/program.js (exports.rater.params): Declare used param.
master
Mike Gerwitz 2019-02-26 11:10:25 -05:00
parent 602a77443f
commit c062cc5a5c
3 changed files with 63 additions and 2 deletions

View File

@ -156,8 +156,8 @@ module.exports = Class( 'TestRunner',
/**
* Attempt test case, returning error on failure
*
* If an error is thrown (e.g. terminating classification), it will be
* returned in place of the results.
* If an error is thrown (e.g. terminating classification or unknown
* input), then it will be returned in place of the results.
*
* @param {Object} data input data
*
@ -168,6 +168,8 @@ module.exports = Class( 'TestRunner',
// no input map---#rate uses params directly
try
{
this._verifyKnownParams( data );
return this._program.rater( data ).vars;
}
catch( e )
@ -177,6 +179,33 @@ module.exports = Class( 'TestRunner',
},
/**
* Verify that all provided inputs match known params
*
* If a given input is not known for the rater for the current program,
* an Error will be thrown with a comma-delimited list of all unknown
* params.
*
* @param {Object} data input data
*
* @return {undefined}
*
* @throws Error when unknown input is found
*/
'private _verifyKnownParams'( data )
{
const params = this._program.rater.params || {};
const unknown = Object.keys( data )
.filter( param => params[ param ] === undefined );
if ( unknown.length > 0 )
{
throw Error( "Unknown params: " + unknown.join( ", " ) );
}
},
/**
* Recursively compare values (scalar, array)
*

View File

@ -41,6 +41,9 @@ describe( "TestRunner", () =>
}
};
// `a' is a known param
program.rater.params = { a: {} };
const test_cases = [
{
description: "first",
@ -118,6 +121,32 @@ describe( "TestRunner", () =>
} );
it( "fails on unknown params", () =>
{
// no params at all are defined
const program = { rater: () => ( { vars: {} } ) };
const bad_test = {
description: 'bad param',
data: {
unknown_param_1: 0,
unknown_param_2: 0,
},
expect: {},
};
return Sut( NullTestReporter(), program )
.runTests( [ bad_test ] )
.then( ( [ result ] ) =>
{
expect( result.failures[ 0 ].result )
.to.contain( 'unknown_param_1' );
expect( result.failures[ 0 ].result )
.to.contain( 'unknown_param_2' );
} );
} );
it( "invokes reporter before, during, and after test cases", done =>
{
let pre = false;

View File

@ -23,3 +23,6 @@ exports.rater = data =>
{
return { vars: { out: data.in } };
};
exports.rater.params = { in: {} };