2015-05-04 18:56:16 +00:00
//: Mu scenarios. This will get long, but these are the tests we want to
//: support in this layer.
2015-04-20 17:14:56 +00:00
2016-09-29 02:48:56 +00:00
//: We avoid raw numeric locations in Mu -- except in scenarios, where they're
//: handy to check the values of specific variables
2015-05-02 22:52:22 +00:00
: ( scenarios run_mu_scenario )
: ( scenario scenario_block )
scenario foo [
run [
2016-09-17 17:28:25 +00:00
1 : num < - copy 13
2015-05-02 22:52:22 +00:00
]
memory - should - contain [
1 < - 13
]
]
# checks are inside scenario
2015-04-20 17:14:56 +00:00
2015-05-02 22:52:22 +00:00
: ( scenario scenario_multiple_blocks )
2015-04-20 17:14:56 +00:00
scenario foo [
run [
2016-09-17 17:28:25 +00:00
1 : num < - copy 13
2015-05-02 22:52:22 +00:00
]
memory - should - contain [
1 < - 13
]
run [
2016-09-17 17:28:25 +00:00
2 : num < - copy 13
2015-04-20 17:14:56 +00:00
]
2015-05-02 22:52:22 +00:00
memory - should - contain [
1 < - 13
2 < - 13
2015-04-20 17:14:56 +00:00
]
]
2016-07-11 04:47:24 +00:00
# checks are inside scenario
2015-04-20 17:14:56 +00:00
2015-05-02 22:52:22 +00:00
: ( scenario scenario_check_memory_and_trace )
2015-04-20 17:19:35 +00:00
scenario foo [
run [
2016-09-17 17:28:25 +00:00
1 : num < - copy 13
2015-08-13 23:53:32 +00:00
trace 1 , [ a ] , [ a b c ]
2015-04-20 17:19:35 +00:00
]
2015-05-02 22:52:22 +00:00
memory - should - contain [
1 < - 13
]
trace - should - contain [
a : a b c
]
trace - should - not - contain [
a : x y z
2015-04-20 17:19:35 +00:00
]
]
2016-07-11 04:47:24 +00:00
# checks are inside scenario
2015-04-20 17:19:35 +00:00
2015-05-04 18:56:16 +00:00
//:: Core data structure
: ( before " End Types " )
struct scenario {
string name ;
string to_run ;
2016-11-16 07:14:30 +00:00
void clear ( ) {
name . clear ( ) ;
to_run . clear ( ) ;
}
2015-05-04 18:56:16 +00:00
} ;
: ( before " End Globals " )
2016-12-28 02:35:27 +00:00
vector < scenario > Scenarios , Scenarios_snapshot ;
set < string > Scenario_names , Scenario_names_snapshot ;
: ( before " End save_snapshots " )
Scenarios_snapshot = Scenarios ;
Scenario_names_snapshot = Scenario_names ;
: ( before " End restore_snapshots " )
Scenarios = Scenarios_snapshot ;
Scenario_names = Scenario_names_snapshot ;
2015-05-04 18:56:16 +00:00
//:: Parse the 'scenario' form.
//: Simply store the text of the scenario.
: ( before " End Command Handlers " )
else if ( command = = " scenario " ) {
2016-11-16 07:14:30 +00:00
scenario result = parse_scenario ( in ) ;
if ( ! result . name . empty ( ) )
Scenarios . push_back ( result ) ;
2015-04-06 19:02:38 +00:00
}
2016-09-27 21:48:37 +00:00
else if ( command = = " pending-scenario " ) {
// for temporary use only
parse_scenario ( in ) ; // discard
}
2015-04-06 19:02:38 +00:00
2015-05-04 18:56:16 +00:00
: ( code )
2015-04-06 19:02:38 +00:00
scenario parse_scenario ( istream & in ) {
2015-05-02 22:52:22 +00:00
scenario result ;
result . name = next_word ( in ) ;
2016-12-28 02:35:27 +00:00
if ( contains_key ( Scenario_names , result . name ) )
raise < < " duplicate scenario name: ' " < < result . name < < " ' \n " < < end ( ) ;
Scenario_names . insert ( result . name ) ;
2016-10-21 08:08:09 +00:00
if ( result . name . empty ( ) ) {
assert ( ! has_data ( in ) ) ;
raise < < " incomplete scenario at end of file \n " < < end ( ) ;
return result ;
}
2015-05-28 18:28:15 +00:00
skip_whitespace_and_comments ( in ) ;
2016-05-05 15:13:45 +00:00
if ( in . peek ( ) ! = ' [ ' ) {
2016-05-21 05:09:06 +00:00
raise < < " Expected '[' after scenario ' " < < result . name < < " ' \n " < < end ( ) ;
2016-05-05 15:13:45 +00:00
exit ( 0 ) ;
}
2015-05-28 18:28:15 +00:00
// scenarios are take special 'code' strings so we need to ignore brackets
// inside comments
2015-06-14 23:24:37 +00:00
result . to_run = slurp_quoted ( in ) ;
// delete [] delimiters
2016-11-16 07:14:30 +00:00
if ( ! starts_with ( result . to_run , " [ " ) ) {
raise < < " scenario " < < result . name < < " should start with '[' \n " < < end ( ) ;
result . clear ( ) ;
return result ;
}
2015-06-14 23:24:37 +00:00
result . to_run . erase ( 0 , 1 ) ;
2016-11-16 07:14:30 +00:00
if ( result . to_run . at ( SIZE ( result . to_run ) - 1 ) ! = ' ] ' ) {
raise < < " scenario " < < result . name < < " has an unbalanced '[' \n " < < end ( ) ;
result . clear ( ) ;
return result ;
}
2015-06-14 23:24:37 +00:00
result . to_run . erase ( SIZE ( result . to_run ) - 1 ) ;
2015-05-02 22:52:22 +00:00
return result ;
2015-04-08 07:47:04 +00:00
}
2015-05-28 18:28:15 +00:00
: ( scenario read_scenario_with_bracket_in_comment )
scenario foo [
# ']' in comment
2016-09-17 17:28:25 +00:00
1 : num < - copy 0
2015-05-28 18:28:15 +00:00
]
2016-03-21 09:25:52 +00:00
+ run : { 1 : " number " } < - copy { 0 : " literal " }
2015-05-28 18:28:15 +00:00
: ( scenario read_scenario_with_bracket_in_comment_in_nested_string )
scenario foo [
2016-09-17 07:06:04 +00:00
1 : text < - new [ # not a comment ]
2015-05-28 18:28:15 +00:00
]
2016-04-24 18:54:30 +00:00
+ run : { 1 : ( " address " " array " " character " ) } < - new { " # not a comment " : " literal-string " }
2015-05-28 18:28:15 +00:00
2016-12-28 02:35:27 +00:00
: ( scenarios run )
: ( scenario duplicate_scenarios )
% Hide_errors = true ;
scenario foo [
1 : num < - copy 0
]
scenario foo [
2 : num < - copy 0
]
+ error : duplicate scenario name : ' foo '
2016-10-22 23:56:07 +00:00
//:: Run scenarios when we run './mu test'.
2015-05-04 18:56:16 +00:00
//: Treat the text of the scenario as a regular series of instructions.
2016-01-21 02:52:34 +00:00
: ( before " End Globals " )
2016-08-12 22:49:27 +00:00
int Num_core_mu_scenarios = 0 ;
2016-01-21 02:52:34 +00:00
: ( after " Check For .mu Files " )
2016-08-12 22:49:27 +00:00
Num_core_mu_scenarios = SIZE ( Scenarios ) ;
2015-05-04 18:56:16 +00:00
: ( before " End Tests " )
2016-02-25 16:24:14 +00:00
Hide_missing_default_space_errors = false ;
2016-10-25 19:35:03 +00:00
if ( Num_core_mu_scenarios > 0 ) {
2016-08-14 00:12:31 +00:00
time ( & t ) ;
2016-08-14 00:17:24 +00:00
cerr < < " Mu tests: " < < ctime ( & t ) ;
2016-10-20 05:10:35 +00:00
for ( int i = 0 ; i < Num_core_mu_scenarios ; + + i ) {
2016-08-14 12:45:30 +00:00
//? cerr << '\n' << i << ": " << Scenarios.at(i).name;
2016-08-14 00:12:31 +00:00
run_mu_scenario ( Scenarios . at ( i ) ) ;
if ( Passed ) cerr < < " . " ;
2017-07-09 20:55:32 +00:00
else + + num_failures ;
2016-08-14 00:12:31 +00:00
}
cerr < < " \n " ;
2015-05-04 18:56:16 +00:00
}
2016-08-12 22:49:27 +00:00
run_app_scenarios :
if ( Num_core_mu_scenarios ! = SIZE ( Scenarios ) ) {
time ( & t ) ;
cerr < < " App tests: " < < ctime ( & t ) ;
2016-10-20 05:10:35 +00:00
for ( int i = Num_core_mu_scenarios ; i < SIZE ( Scenarios ) ; + + i ) {
2016-08-14 12:45:30 +00:00
//? cerr << '\n' << i << ": " << Scenarios.at(i).name;
2016-08-12 22:49:27 +00:00
run_mu_scenario ( Scenarios . at ( i ) ) ;
if ( Passed ) cerr < < " . " ;
2017-07-09 20:55:32 +00:00
else + + num_failures ;
2016-08-12 22:49:27 +00:00
}
2016-08-14 00:17:24 +00:00
cerr < < " \n " ;
2016-08-12 22:49:27 +00:00
}
2015-05-04 18:56:16 +00:00
2016-08-12 22:53:48 +00:00
//: For faster debugging, support running tests for just the Mu app(s) we are
//: loading.
: ( before " End Globals " )
bool Test_only_app = false ;
: ( before " End Commandline Options(*arg) " )
else if ( is_equal ( * arg , " --test-only-app " ) ) {
Test_only_app = true ;
}
2016-07-23 06:36:19 +00:00
: ( after " End Test Run Initialization " )
2016-08-12 22:49:27 +00:00
if ( Test_only_app & & Num_core_mu_scenarios < SIZE ( Scenarios ) ) {
goto run_app_scenarios ;
2016-07-23 06:36:19 +00:00
}
2015-05-12 16:20:19 +00:00
//: Convenience: run a single named scenario.
2015-07-10 17:25:44 +00:00
: ( after " Test Runs " )
2016-10-20 05:10:35 +00:00
for ( int i = 0 ; i < SIZE ( Scenarios ) ; + + i ) {
2015-07-10 17:25:44 +00:00
if ( Scenarios . at ( i ) . name = = argv [ argc - 1 ] ) {
run_mu_scenario ( Scenarios . at ( i ) ) ;
if ( Passed ) cerr < < " . \n " ;
return 0 ;
2015-05-12 16:20:19 +00:00
}
}
2015-05-04 22:06:46 +00:00
: ( before " End Globals " )
2016-08-29 01:12:03 +00:00
// this isn't a constant, just a global of type const*
2015-05-04 22:06:46 +00:00
const scenario * Current_scenario = NULL ;
2015-05-04 18:56:16 +00:00
: ( code )
2015-05-02 22:52:22 +00:00
void run_mu_scenario ( const scenario & s ) {
2015-05-04 22:06:46 +00:00
Current_scenario = & s ;
2015-05-04 17:31:52 +00:00
bool not_already_inside_test = ! Trace_stream ;
2015-08-29 06:21:48 +00:00
//? cerr << s.name << '\n';
2015-05-04 17:31:52 +00:00
if ( not_already_inside_test ) {
Trace_stream = new trace_stream ;
2017-07-09 21:25:48 +00:00
reset ( ) ;
2015-05-04 17:31:52 +00:00
}
2016-01-28 03:59:29 +00:00
vector < recipe_ordinal > tmp = load ( " recipe scenario_ " + s . name + " [ " + s . to_run + " ] " ) ;
2016-05-27 16:50:39 +00:00
mark_autogenerated ( tmp . at ( 0 ) ) ;
2015-06-28 06:13:57 +00:00
bind_special_scenario_names ( tmp . at ( 0 ) ) ;
transform_all ( ) ;
2016-11-16 06:30:52 +00:00
if ( ! trace_contains_errors ( ) )
run ( tmp . front ( ) ) ;
2016-10-21 03:17:21 +00:00
// End Mu Test Teardown
2016-11-16 05:55:56 +00:00
if ( ! Hide_errors & & trace_contains_errors ( ) & & ! Scenario_testing_scenario )
2016-02-25 15:31:20 +00:00
Passed = false ;
2015-05-19 01:51:48 +00:00
if ( not_already_inside_test & & Trace_stream ) {
2018-07-26 05:25:12 +00:00
if ( Save_trace ) Trace_stream - > save ( ) ;
2015-05-02 22:52:22 +00:00
delete Trace_stream ;
Trace_stream = NULL ;
}
2015-05-04 22:06:46 +00:00
Current_scenario = NULL ;
2015-04-08 07:47:04 +00:00
}
2016-12-12 18:01:12 +00:00
//: Permit numeric locations to be accessed in scenarios.
: ( before " End check_default_space Special-cases " )
// user code should never create recipes with underscores in their names
2017-06-15 17:45:03 +00:00
if ( starts_with ( caller . name , " scenario_ " ) ) return ; // skip Mu scenarios which will use raw memory locations
if ( starts_with ( caller . name , " run_ " ) ) return ; // skip calls to 'run', which should be in scenarios and will also use raw memory locations
: ( before " End maybe(recipe_name) Special-cases " )
if ( starts_with ( recipe_name , " scenario_ " ) )
return recipe_name . substr ( strlen ( " scenario_ " ) ) + " : " ;
2016-12-12 18:01:12 +00:00
2016-05-27 16:50:39 +00:00
//: Some variables for fake resources always get special /raw addresses in scenarios.
2016-12-12 18:31:57 +00:00
: ( code )
2016-05-27 16:50:39 +00:00
// Should contain everything passed by is_special_name but failed by is_disqualified.
2016-10-22 23:10:23 +00:00
void bind_special_scenario_names ( const recipe_ordinal r ) {
2016-05-27 16:50:39 +00:00
// Special Scenario Variable Names(r)
// End Special Scenario Variable Names(r)
}
2016-08-25 17:11:04 +00:00
: ( before " Done Placing Ingredient(ingredient, inst, caller) " )
maybe_make_raw ( ingredient , caller ) ;
: ( before " Done Placing Product(product, inst, caller) " )
maybe_make_raw ( product , caller ) ;
2016-05-27 16:50:39 +00:00
: ( code )
void maybe_make_raw ( reagent & r , const recipe & caller ) {
if ( ! is_special_name ( r . name ) ) return ;
if ( starts_with ( caller . name , " scenario_ " ) )
r . properties . push_back ( pair < string , string_tree * > ( " raw " , NULL ) ) ;
// End maybe_make_raw
}
//: Test.
2016-11-07 17:10:48 +00:00
: ( before " End is_special_name Special-cases " )
2016-05-27 16:50:39 +00:00
if ( s = = " __maybe_make_raw_test__ " ) return true ;
: ( before " End Special Scenario Variable Names(r) " )
//: ugly: we only need this for this one test, but need to define it for all time
Name [ r ] [ " __maybe_make_raw_test__ " ] = Reserved_for_tests - 1 ;
: ( code )
void test_maybe_make_raw ( ) {
// check that scenarios can use local-scope and special variables together
vector < recipe_ordinal > tmp = load (
" def scenario_foo [ \n "
" local-scope \n "
2016-09-17 17:28:25 +00:00
" __maybe_make_raw_test__:num <- copy 34 \n "
2016-05-27 16:50:39 +00:00
" ] \n " ) ;
mark_autogenerated ( tmp . at ( 0 ) ) ;
bind_special_scenario_names ( tmp . at ( 0 ) ) ;
transform_all ( ) ;
run ( tmp . at ( 0 ) ) ;
2016-11-16 05:55:56 +00:00
CHECK_TRACE_DOESNT_CONTAIN_ERRORS ( ) ;
2016-05-27 16:50:39 +00:00
}
2015-07-25 07:20:35 +00:00
//: Watch out for redefinitions of scenario routines. We should never ever be
//: doing that, regardless of anything else.
2016-02-25 19:29:42 +00:00
: ( scenario forbid_redefining_scenario_even_if_forced )
2016-02-25 15:58:09 +00:00
% Hide_errors = true ;
2016-02-25 19:29:42 +00:00
% Disable_redefine_checks = true ;
2016-03-08 09:30:14 +00:00
def scenario - foo [
2016-09-17 17:28:25 +00:00
1 : num < - copy 34
2015-07-25 07:20:35 +00:00
]
2016-03-08 09:30:14 +00:00
def scenario - foo [
2016-09-17 17:28:25 +00:00
1 : num < - copy 35
2015-07-25 07:20:35 +00:00
]
2016-02-25 15:58:09 +00:00
+ error : redefining recipe scenario - foo
2015-07-25 07:20:35 +00:00
2016-11-16 07:14:30 +00:00
: ( scenario scenario_containing_parse_error )
% Hide_errors = true ;
scenario foo [
memory - should - contain [
1 < - 0
# missing ']'
]
# no crash
2016-11-16 06:30:52 +00:00
: ( scenario scenario_containing_transform_error )
% Hide_errors = true ;
def main [
local - scope
add x , 1
]
# no crash
2016-02-25 19:29:42 +00:00
: ( after " bool should_check_for_redefine(const string& recipe_name) " )
2015-08-24 21:19:52 +00:00
if ( recipe_name . find ( " scenario- " ) = = 0 ) return true ;
2015-07-25 07:20:35 +00:00
2015-05-04 18:56:16 +00:00
//:: The special instructions we want to support inside scenarios.
2016-10-22 23:56:07 +00:00
//: These are easy to support in an interpreter, but will require more work
//: when we eventually build a compiler.
2015-05-04 18:56:16 +00:00
2016-09-29 02:48:56 +00:00
//: 'run' is a purely lexical convenience to separate the code actually being
2017-07-09 21:25:48 +00:00
//: tested from any setup
2015-05-04 18:56:16 +00:00
: ( scenario run )
2016-03-08 09:30:14 +00:00
def main [
2015-05-04 18:56:16 +00:00
run [
2016-09-17 17:28:25 +00:00
1 : num < - copy 13
2015-05-04 18:56:16 +00:00
]
]
+ mem : storing 13 in location 1
2016-09-29 02:48:56 +00:00
: ( before " End Rewrite Instruction(curr, recipe result) " )
if ( curr . name = = " run " ) {
// Just inline all instructions inside the run block in the containing
// recipe. 'run' is basically a comment; pretend it doesn't exist.
istringstream in2 ( " [ \n " + curr . ingredients . at ( 0 ) . name + " \n ] \n " ) ;
slurp_body ( in2 , result ) ;
curr . clear ( ) ;
2015-10-02 00:30:14 +00:00
}
2015-06-28 06:13:57 +00:00
2015-05-04 18:56:16 +00:00
: ( scenario run_multiple )
2016-03-08 09:30:14 +00:00
def main [
2015-05-04 18:56:16 +00:00
run [
2016-09-17 17:28:25 +00:00
1 : num < - copy 13
2015-05-04 18:56:16 +00:00
]
run [
2016-09-17 17:28:25 +00:00
2 : num < - copy 13
2015-05-04 18:56:16 +00:00
]
]
+ mem : storing 13 in location 1
+ mem : storing 13 in location 2
2015-10-07 05:15:45 +00:00
//: 'memory-should-contain' raises errors if specific locations aren't as expected
2017-06-15 18:10:15 +00:00
//: Also includes some special support for checking Mu texts.
2015-05-04 18:56:16 +00:00
2015-07-08 18:43:59 +00:00
: ( before " End Globals " )
bool Scenario_testing_scenario = false ;
2017-07-09 21:34:17 +00:00
: ( before " End Reset " )
2015-07-08 18:43:59 +00:00
Scenario_testing_scenario = false ;
2015-05-04 18:56:16 +00:00
: ( scenario memory_check )
2015-07-08 18:43:59 +00:00
% Scenario_testing_scenario = true ;
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def main [
2015-05-04 18:56:16 +00:00
memory - should - contain [
1 < - 13
]
]
+ run : checking location 1
2017-06-15 17:45:03 +00:00
+ error : F - main : expected location ' 1 ' to contain 13 but saw 0
2015-05-04 18:56:16 +00:00
: ( before " End Primitive Recipe Declarations " )
MEMORY_SHOULD_CONTAIN ,
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " memory-should-contain " , MEMORY_SHOULD_CONTAIN ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
case MEMORY_SHOULD_CONTAIN : {
break ;
}
2015-05-04 18:56:16 +00:00
: ( before " End Primitive Recipe Implementations " )
case MEMORY_SHOULD_CONTAIN : {
2015-05-28 01:32:07 +00:00
if ( ! Passed ) break ;
2015-05-07 22:06:53 +00:00
check_memory ( current_instruction ( ) . ingredients . at ( 0 ) . name ) ;
2015-05-04 18:56:16 +00:00
break ;
}
: ( code )
void check_memory ( const string & s ) {
istringstream in ( s ) ;
in > > std : : noskipws ;
2016-03-14 03:26:47 +00:00
set < int > locations_checked ;
2015-05-04 18:56:16 +00:00
while ( true ) {
skip_whitespace_and_comments ( in ) ;
2015-11-17 09:21:00 +00:00
if ( ! has_data ( in ) ) break ;
2015-05-04 18:56:16 +00:00
string lhs = next_word ( in ) ;
2016-10-21 08:08:09 +00:00
if ( lhs . empty ( ) ) {
assert ( ! has_data ( in ) ) ;
2017-06-15 17:45:03 +00:00
raise < < maybe ( current_recipe_name ( ) ) < < " incomplete 'memory-should-contain' block at end of file (0) \n " < < end ( ) ;
2016-10-21 08:08:09 +00:00
return ;
}
2015-05-17 04:24:21 +00:00
if ( ! is_integer ( lhs ) ) {
2015-05-04 18:56:16 +00:00
check_type ( lhs , in ) ;
continue ;
}
2016-03-14 03:26:47 +00:00
int address = to_integer ( lhs ) ;
2015-05-04 18:56:16 +00:00
skip_whitespace_and_comments ( in ) ;
string _assign ; in > > _assign ; assert ( _assign = = " <- " ) ;
skip_whitespace_and_comments ( in ) ;
2016-02-25 05:04:11 +00:00
string rhs = next_word ( in ) ;
2016-10-21 08:08:09 +00:00
if ( rhs . empty ( ) ) {
assert ( ! has_data ( in ) ) ;
2017-06-15 17:45:03 +00:00
raise < < maybe ( current_recipe_name ( ) ) < < " incomplete 'memory-should-contain' block at end of file (1) \n " < < end ( ) ;
2016-10-21 08:08:09 +00:00
return ;
}
2016-02-25 05:04:11 +00:00
if ( ! is_integer ( rhs ) & & ! is_noninteger ( rhs ) ) {
2017-06-15 17:45:03 +00:00
if ( ! Hide_errors ) cerr < < ' \n ' ;
raise < < " F - " < < maybe ( current_recipe_name ( ) ) < < " location ' " < < address < < " ' can't contain non-number " < < rhs < < ' \n ' < < end ( ) ;
2016-07-22 20:11:40 +00:00
if ( ! Scenario_testing_scenario ) Passed = false ;
2016-02-25 05:04:11 +00:00
return ;
}
double value = to_double ( rhs ) ;
2015-11-06 21:22:16 +00:00
if ( contains_key ( locations_checked , address ) )
2017-06-15 17:45:03 +00:00
raise < < maybe ( current_recipe_name ( ) ) < < " duplicate expectation for location ' " < < address < < " ' \n " < < end ( ) ;
2017-11-03 08:50:46 +00:00
trace ( " run " ) < < " checking location " < < address < < end ( ) ;
2015-11-06 19:06:58 +00:00
if ( get_or_insert ( Memory , address ) ! = value ) {
2017-06-15 17:45:03 +00:00
if ( ! Hide_errors ) cerr < < ' \n ' ;
raise < < " F - " < < maybe ( current_recipe_name ( ) ) < < " expected location ' " < < address < < " ' to contain " < < no_scientific ( value ) < < " but saw " < < no_scientific ( get_or_insert ( Memory , address ) ) < < ' \n ' < < end ( ) ;
2016-07-22 20:11:40 +00:00
if ( ! Scenario_testing_scenario ) Passed = false ;
2015-05-04 22:06:46 +00:00
return ;
}
2015-05-04 18:56:16 +00:00
locations_checked . insert ( address ) ;
}
}
void check_type ( const string & lhs , istream & in ) {
reagent x ( lhs ) ;
2016-11-11 05:39:02 +00:00
if ( is_mu_array ( x . type ) & & is_mu_character ( array_element ( x . type ) ) ) {
2015-05-17 04:24:21 +00:00
x . set_value ( to_integer ( x . name ) ) ;
2015-05-04 18:56:16 +00:00
skip_whitespace_and_comments ( in ) ;
string _assign = next_word ( in ) ;
2016-10-21 08:08:09 +00:00
if ( _assign . empty ( ) ) {
assert ( ! has_data ( in ) ) ;
2017-06-15 17:45:03 +00:00
raise < < maybe ( current_recipe_name ( ) ) < < " incomplete 'memory-should-contain' block at end of file (2) \n " < < end ( ) ;
2016-10-21 08:08:09 +00:00
return ;
}
2015-05-04 18:56:16 +00:00
assert ( _assign = = " <- " ) ;
skip_whitespace_and_comments ( in ) ;
string literal = next_word ( in ) ;
2016-10-21 08:08:09 +00:00
if ( literal . empty ( ) ) {
assert ( ! has_data ( in ) ) ;
2017-06-15 17:45:03 +00:00
raise < < maybe ( current_recipe_name ( ) ) < < " incomplete 'memory-should-contain' block at end of file (3) \n " < < end ( ) ;
2016-10-21 08:08:09 +00:00
return ;
}
2016-03-14 03:26:47 +00:00
int address = x . value ;
2015-05-04 18:56:16 +00:00
// exclude quoting brackets
2017-06-15 17:53:32 +00:00
if ( * literal . begin ( ) ! = ' [ ' ) {
raise < < maybe ( current_recipe_name ( ) ) < < " array:character types inside 'memory-should-contain' can only be compared with text literals surrounded by [], not ' " < < literal < < " ' \n " < < end ( ) ;
return ;
}
literal . erase ( literal . begin ( ) ) ;
2015-05-07 22:49:40 +00:00
assert ( * - - literal . end ( ) = = ' ] ' ) ; literal . erase ( - - literal . end ( ) ) ;
2017-06-15 18:10:15 +00:00
check_mu_text ( address , literal ) ;
2015-05-04 18:56:16 +00:00
return ;
}
2016-11-07 17:10:48 +00:00
// End Scenario Type Special-cases
2016-05-21 05:09:06 +00:00
raise < < " don't know how to check memory for ' " < < lhs < < " ' \n " < < end ( ) ;
2015-05-04 18:56:16 +00:00
}
2017-06-15 18:10:15 +00:00
void check_mu_text ( int start , const string & literal ) {
2017-11-03 08:50:46 +00:00
trace ( " run " ) < < " checking text length at " < < start < < end ( ) ;
2017-06-15 18:10:15 +00:00
int array_length = static_cast < int > ( get_or_insert ( Memory , start ) ) ;
if ( array_length ! = SIZE ( literal ) ) {
2017-06-15 17:45:03 +00:00
if ( ! Hide_errors ) cerr < < ' \n ' ;
2017-06-15 18:10:15 +00:00
raise < < " F - " < < maybe ( current_recipe_name ( ) ) < < " expected location ' " < < start < < " ' to contain length " < < SIZE ( literal ) < < " of text [ " < < literal < < " ] but saw " < < array_length < < " (for text [ " < < read_mu_characters ( start + /*skip length*/ 1 , array_length ) < < " ]) \n " < < end ( ) ;
2016-07-22 20:11:40 +00:00
if ( ! Scenario_testing_scenario ) Passed = false ;
2015-05-23 19:30:58 +00:00
return ;
}
2017-06-15 18:10:15 +00:00
int curr = start + 1 ; // now skip length
2016-10-20 05:10:35 +00:00
for ( int i = 0 ; i < SIZE ( literal ) ; + + i ) {
2017-11-03 08:50:46 +00:00
trace ( " run " ) < < " checking location " < < curr + i < < end ( ) ;
2017-06-15 18:10:15 +00:00
if ( get_or_insert ( Memory , curr + i ) ! = literal . at ( i ) ) {
2017-06-15 17:45:03 +00:00
if ( ! Hide_errors ) cerr < < ' \n ' ;
2017-06-15 18:10:15 +00:00
raise < < " F - " < < maybe ( current_recipe_name ( ) ) < < " expected location " < < ( curr + i ) < < " to contain " < < literal . at ( i ) < < " but saw " < < no_scientific ( get_or_insert ( Memory , curr + i ) ) < < ' \n ' < < end ( ) ;
2016-07-22 20:11:40 +00:00
if ( ! Scenario_testing_scenario ) Passed = false ;
2015-05-23 19:30:58 +00:00
return ;
}
2015-05-04 18:56:16 +00:00
}
}
: ( scenario memory_check_multiple )
2015-07-08 18:43:59 +00:00
% Scenario_testing_scenario = true ;
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def main [
2015-05-04 18:56:16 +00:00
memory - should - contain [
1 < - 0
1 < - 0
]
]
2017-06-15 17:45:03 +00:00
+ error : main : duplicate expectation for location ' 1 '
2015-05-04 18:56:16 +00:00
2017-06-15 18:10:15 +00:00
: ( scenario memory_check_mu_text_length )
2015-07-08 18:43:59 +00:00
% Scenario_testing_scenario = true ;
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def main [
2016-09-17 17:28:25 +00:00
1 : num < - copy 3
2 : num < - copy 97 # ' a '
3 : num < - copy 98 # ' b '
4 : num < - copy 99 # ' c '
2015-05-04 18:56:16 +00:00
memory - should - contain [
2015-11-21 17:26:30 +00:00
1 : array : character < - [ ab ]
2015-05-04 18:56:16 +00:00
]
]
2017-06-15 18:10:15 +00:00
+ error : F - main : expected location ' 1 ' to contain length 2 of text [ ab ] but saw 3 ( for text [ abc ] )
2015-05-04 18:56:16 +00:00
2017-06-15 18:10:15 +00:00
: ( scenario memory_check_mu_text )
2016-03-08 09:30:14 +00:00
def main [
2016-09-17 17:28:25 +00:00
1 : num < - copy 3
2 : num < - copy 97 # ' a '
3 : num < - copy 98 # ' b '
4 : num < - copy 99 # ' c '
2015-05-04 18:56:16 +00:00
memory - should - contain [
2015-11-21 17:26:30 +00:00
1 : array : character < - [ abc ]
2015-05-04 18:56:16 +00:00
]
]
2017-06-15 18:10:15 +00:00
+ run : checking text length at 1
2015-05-04 18:56:16 +00:00
+ run : checking location 2
+ run : checking location 3
+ run : checking location 4
2016-02-25 05:04:11 +00:00
: ( scenario memory_invalid_string_check )
% Scenario_testing_scenario = true ;
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def main [
2016-02-25 05:04:11 +00:00
memory - should - contain [
1 < - [ abc ]
]
]
2017-06-15 17:45:03 +00:00
+ error : F - main : location ' 1 ' can ' t contain non - number [ abc ]
2016-02-25 05:04:11 +00:00
2017-06-15 17:53:32 +00:00
: ( scenario memory_invalid_string_check2 )
% Hide_errors = true ;
def main [
1 : num < - copy 3
2 : num < - copy 97 # ' a '
3 : num < - copy 98 # ' b '
4 : num < - copy 99 # ' c '
memory - should - contain [
1 : array : character < - 0
]
]
+ error : main : array : character types inside ' memory - should - contain ' can only be compared with text literals surrounded by [ ] , not ' 0 '
2016-02-25 05:04:11 +00:00
: ( scenario memory_check_with_comment )
% Scenario_testing_scenario = true ;
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def main [
2016-02-25 05:04:11 +00:00
memory - should - contain [
1 < - 34 # comment
]
]
- error : location 1 can ' t contain non - number 34 # comment
2016-02-26 06:08:27 +00:00
# but there'll be an error signalled by memory-should-contain
2016-02-25 05:04:11 +00:00
2015-05-04 18:56:16 +00:00
//: 'trace-should-contain' is like the '+' lines in our scenarios so far
// Like runs of contiguous '+' lines, order is important. The trace checks
// that the lines are present *and* in the specified sequence. (There can be
// other lines in between.)
2015-10-07 05:15:45 +00:00
: ( scenario trace_check_fails )
2015-07-08 18:43:59 +00:00
% Scenario_testing_scenario = true ;
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def main [
2015-05-04 18:56:16 +00:00
trace - should - contain [
a : b
a : d
]
]
2017-06-15 17:45:03 +00:00
+ error : F - main : missing [ b ] in trace with label ' a '
2015-05-04 18:56:16 +00:00
: ( before " End Primitive Recipe Declarations " )
TRACE_SHOULD_CONTAIN ,
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " trace-should-contain " , TRACE_SHOULD_CONTAIN ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
case TRACE_SHOULD_CONTAIN : {
break ;
}
2015-05-04 18:56:16 +00:00
: ( before " End Primitive Recipe Implementations " )
case TRACE_SHOULD_CONTAIN : {
2015-05-28 01:32:07 +00:00
if ( ! Passed ) break ;
2015-05-07 22:06:53 +00:00
check_trace ( current_instruction ( ) . ingredients . at ( 0 ) . name ) ;
2015-05-04 18:56:16 +00:00
break ;
}
: ( code )
2015-10-07 05:15:45 +00:00
// simplified version of check_trace_contents() that emits errors rather
2015-05-04 18:56:16 +00:00
// than just printing to stderr
2015-11-29 09:00:30 +00:00
void check_trace ( const string & expected ) {
2015-05-04 18:56:16 +00:00
Trace_stream - > newline ( ) ;
2015-05-22 01:10:17 +00:00
vector < trace_line > expected_lines = parse_trace ( expected ) ;
2015-11-29 09:00:30 +00:00
if ( expected_lines . empty ( ) ) return ;
2016-03-14 03:26:47 +00:00
int curr_expected_line = 0 ;
2016-10-20 05:10:35 +00:00
for ( vector < trace_line > : : iterator p = Trace_stream - > past_lines . begin ( ) ; p ! = Trace_stream - > past_lines . end ( ) ; + + p ) {
2015-05-22 01:10:17 +00:00
if ( expected_lines . at ( curr_expected_line ) . label ! = p - > label ) continue ;
if ( expected_lines . at ( curr_expected_line ) . contents ! = trim ( p - > contents ) ) continue ;
2015-05-04 18:56:16 +00:00
// match
+ + curr_expected_line ;
2015-11-29 09:00:30 +00:00
if ( curr_expected_line = = SIZE ( expected_lines ) ) return ;
2015-05-04 18:56:16 +00:00
}
2017-06-15 17:45:03 +00:00
if ( ! Hide_errors ) cerr < < ' \n ' ;
raise < < " F - " < < maybe ( current_recipe_name ( ) ) < < " missing [ " < < expected_lines . at ( curr_expected_line ) . contents < < " ] "
< < " in trace with label ' " < < expected_lines . at ( curr_expected_line ) . label < < " ' \n " < < end ( ) ;
2016-07-20 17:08:42 +00:00
if ( ! Hide_errors )
DUMP ( expected_lines . at ( curr_expected_line ) . label ) ;
2016-10-21 03:19:29 +00:00
if ( ! Scenario_testing_scenario ) Passed = false ;
2015-04-21 05:20:39 +00:00
}
2015-05-22 01:10:17 +00:00
vector < trace_line > parse_trace ( const string & expected ) {
2015-05-04 18:56:16 +00:00
vector < string > buf = split ( expected , " \n " ) ;
2015-05-22 01:10:17 +00:00
vector < trace_line > result ;
2016-10-20 05:10:35 +00:00
for ( int i = 0 ; i < SIZE ( buf ) ; + + i ) {
2015-05-07 22:06:53 +00:00
buf . at ( i ) = trim ( buf . at ( i ) ) ;
if ( buf . at ( i ) . empty ( ) ) continue ;
2016-03-14 03:26:47 +00:00
int delim = buf . at ( i ) . find ( " : " ) ;
2016-09-27 21:45:51 +00:00
if ( delim = = - 1 ) {
2017-06-15 17:45:03 +00:00
raise < < maybe ( current_recipe_name ( ) ) < < " lines in 'trace-should-contain' should be of the form <label>: <contents>. Both parts are required. \n " < < end ( ) ;
2016-09-27 21:45:51 +00:00
result . clear ( ) ;
return result ;
}
2015-05-22 01:10:17 +00:00
result . push_back ( trace_line ( trim ( buf . at ( i ) . substr ( 0 , delim ) ) , trim ( buf . at ( i ) . substr ( delim + 2 ) ) ) ) ;
2015-05-04 18:56:16 +00:00
}
return result ;
}
2015-10-07 05:15:45 +00:00
: ( scenario trace_check_fails_in_nonfirst_line )
2015-07-08 18:43:59 +00:00
% Scenario_testing_scenario = true ;
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def main [
2015-05-04 18:56:16 +00:00
run [
2015-08-13 23:53:32 +00:00
trace 1 , [ a ] , [ b ]
2015-05-04 18:56:16 +00:00
]
trace - should - contain [
a : b
a : d
]
]
2017-06-15 17:45:03 +00:00
+ error : F - main : missing [ d ] in trace with label ' a '
2015-05-04 18:56:16 +00:00
: ( scenario trace_check_passes_silently )
2015-07-08 18:43:59 +00:00
% Scenario_testing_scenario = true ;
2016-03-08 09:30:14 +00:00
def main [
2015-05-04 18:56:16 +00:00
run [
2015-08-13 23:53:32 +00:00
trace 1 , [ a ] , [ b ]
2015-05-04 18:56:16 +00:00
]
trace - should - contain [
a : b
]
]
2016-07-20 20:06:28 +00:00
- error : missing [ b ] in trace with label ' a '
2015-10-07 05:15:45 +00:00
$ error : 0
2015-05-04 18:56:16 +00:00
//: 'trace-should-not-contain' is like the '-' lines in our scenarios so far
//: Each trace line is separately checked for absense. Order is *not*
//: important, so you can't say things like "B should not exist after A."
2015-10-07 05:15:45 +00:00
: ( scenario trace_negative_check_fails )
2015-07-08 18:43:59 +00:00
% Scenario_testing_scenario = true ;
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def main [
2015-05-04 18:56:16 +00:00
run [
2015-08-13 23:53:32 +00:00
trace 1 , [ a ] , [ b ]
2015-05-04 18:56:16 +00:00
]
trace - should - not - contain [
a : b
]
]
2017-06-15 17:45:03 +00:00
+ error : F - main : unexpected [ b ] in trace with label ' a '
2015-05-04 18:56:16 +00:00
: ( before " End Primitive Recipe Declarations " )
TRACE_SHOULD_NOT_CONTAIN ,
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " trace-should-not-contain " , TRACE_SHOULD_NOT_CONTAIN ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
case TRACE_SHOULD_NOT_CONTAIN : {
break ;
}
2015-05-04 18:56:16 +00:00
: ( before " End Primitive Recipe Implementations " )
case TRACE_SHOULD_NOT_CONTAIN : {
2015-05-28 01:32:07 +00:00
if ( ! Passed ) break ;
2015-05-07 22:06:53 +00:00
check_trace_missing ( current_instruction ( ) . ingredients . at ( 0 ) . name ) ;
2015-05-04 18:56:16 +00:00
break ;
}
: ( code )
2015-10-07 05:15:45 +00:00
// simplified version of check_trace_contents() that emits errors rather
2015-05-04 18:56:16 +00:00
// than just printing to stderr
bool check_trace_missing ( const string & in ) {
Trace_stream - > newline ( ) ;
2015-05-22 01:10:17 +00:00
vector < trace_line > lines = parse_trace ( in ) ;
2016-10-20 05:10:35 +00:00
for ( int i = 0 ; i < SIZE ( lines ) ; + + i ) {
2015-05-22 01:10:17 +00:00
if ( trace_count ( lines . at ( i ) . label , lines . at ( i ) . contents ) ! = 0 ) {
2017-06-15 17:45:03 +00:00
raise < < " F - " < < maybe ( current_recipe_name ( ) ) < < " unexpected [ " < < lines . at ( i ) . contents < < " ] in trace with label ' " < < lines . at ( i ) . label < < " ' \n " < < end ( ) ;
2016-10-21 03:19:29 +00:00
if ( ! Scenario_testing_scenario ) Passed = false ;
2015-05-04 18:56:16 +00:00
return false ;
}
}
return true ;
}
: ( scenario trace_negative_check_passes_silently )
2015-07-08 18:43:59 +00:00
% Scenario_testing_scenario = true ;
2016-03-08 09:30:14 +00:00
def main [
2015-05-04 18:56:16 +00:00
trace - should - not - contain [
a : b
]
]
2016-07-20 20:06:28 +00:00
- error : unexpected [ b ] in trace with label ' a '
2015-10-07 05:15:45 +00:00
$ error : 0
2015-05-04 18:56:16 +00:00
2015-10-07 05:15:45 +00:00
: ( scenario trace_negative_check_fails_on_any_unexpected_line )
2015-07-08 18:43:59 +00:00
% Scenario_testing_scenario = true ;
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def main [
2015-05-04 18:56:16 +00:00
run [
2015-08-13 23:53:32 +00:00
trace 1 , [ a ] , [ d ]
2015-05-04 18:56:16 +00:00
]
trace - should - not - contain [
a : b
a : d
]
]
2017-06-15 17:45:03 +00:00
+ error : F - main : unexpected [ d ] in trace with label ' a '
2015-05-04 18:56:16 +00:00
2015-08-14 02:03:17 +00:00
: ( scenario trace_count_check )
2016-03-08 09:30:14 +00:00
def main [
2015-08-14 02:03:17 +00:00
run [
trace 1 , [ a ] , [ foo ]
]
check - trace - count - for - label 1 , [ a ]
]
2016-07-11 04:47:24 +00:00
# checks are inside scenario
2015-08-14 02:03:17 +00:00
: ( before " End Primitive Recipe Declarations " )
CHECK_TRACE_COUNT_FOR_LABEL ,
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " check-trace-count-for-label " , CHECK_TRACE_COUNT_FOR_LABEL ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
2015-08-14 02:03:17 +00:00
case CHECK_TRACE_COUNT_FOR_LABEL : {
2015-10-02 00:30:14 +00:00
if ( SIZE ( inst . ingredients ) ! = 2 ) {
2017-05-26 23:43:18 +00:00
raise < < maybe ( get ( Recipe , r ) . name ) < < " 'check-trace-count-for-label' requires exactly two ingredients, but got ' " < < to_original_string ( inst ) < < " ' \n " < < end ( ) ;
2015-08-14 02:03:17 +00:00
break ;
}
2015-10-07 05:15:45 +00:00
if ( ! is_mu_number ( inst . ingredients . at ( 0 ) ) ) {
2016-05-21 05:09:06 +00:00
raise < < maybe ( get ( Recipe , r ) . name ) < < " first ingredient of 'check-trace-count-for-label' should be a number (count), but got ' " < < inst . ingredients . at ( 0 ) . original_string < < " ' \n " < < end ( ) ;
2015-08-14 02:03:17 +00:00
break ;
}
2016-09-17 06:52:15 +00:00
if ( ! is_literal_text ( inst . ingredients . at ( 1 ) ) ) {
2016-05-21 05:09:06 +00:00
raise < < maybe ( get ( Recipe , r ) . name ) < < " second ingredient of 'check-trace-count-for-label' should be a literal string (label), but got ' " < < inst . ingredients . at ( 1 ) . original_string < < " ' \n " < < end ( ) ;
2015-08-14 02:03:17 +00:00
break ;
}
2015-10-02 00:30:14 +00:00
break ;
}
: ( before " End Primitive Recipe Implementations " )
case CHECK_TRACE_COUNT_FOR_LABEL : {
if ( ! Passed ) break ;
2016-03-14 03:26:47 +00:00
int expected_count = ingredients . at ( 0 ) . at ( 0 ) ;
2015-08-14 02:03:17 +00:00
string label = current_instruction ( ) . ingredients . at ( 1 ) . name ;
2016-03-14 03:26:47 +00:00
int count = trace_count ( label ) ;
2015-08-14 02:03:17 +00:00
if ( count ! = expected_count ) {
2017-06-15 17:45:03 +00:00
if ( ! Hide_errors ) cerr < < ' \n ' ;
raise < < " F - " < < maybe ( current_recipe_name ( ) ) < < " expected " < < expected_count < < " lines in trace with label ' " < < label < < " ' in trace \n " < < end ( ) ;
2017-06-16 00:11:08 +00:00
if ( ! Hide_errors ) DUMP ( label ) ;
2016-07-22 21:13:25 +00:00
if ( ! Scenario_testing_scenario ) Passed = false ;
2015-08-14 02:03:17 +00:00
}
break ;
}
2017-06-09 22:54:26 +00:00
: ( before " End Primitive Recipe Declarations " )
CHECK_TRACE_COUNT_FOR_LABEL_GREATER_THAN ,
: ( before " End Primitive Recipe Numbers " )
put ( Recipe_ordinal , " check-trace-count-for-label-greater-than " , CHECK_TRACE_COUNT_FOR_LABEL_GREATER_THAN ) ;
: ( before " End Primitive Recipe Checks " )
case CHECK_TRACE_COUNT_FOR_LABEL_GREATER_THAN : {
if ( SIZE ( inst . ingredients ) ! = 2 ) {
raise < < maybe ( get ( Recipe , r ) . name ) < < " 'check-trace-count-for-label' requires exactly two ingredients, but got ' " < < to_original_string ( inst ) < < " ' \n " < < end ( ) ;
break ;
}
if ( ! is_mu_number ( inst . ingredients . at ( 0 ) ) ) {
raise < < maybe ( get ( Recipe , r ) . name ) < < " first ingredient of 'check-trace-count-for-label' should be a number (count), but got ' " < < inst . ingredients . at ( 0 ) . original_string < < " ' \n " < < end ( ) ;
break ;
}
if ( ! is_literal_text ( inst . ingredients . at ( 1 ) ) ) {
raise < < maybe ( get ( Recipe , r ) . name ) < < " second ingredient of 'check-trace-count-for-label' should be a literal string (label), but got ' " < < inst . ingredients . at ( 1 ) . original_string < < " ' \n " < < end ( ) ;
break ;
}
break ;
}
: ( before " End Primitive Recipe Implementations " )
case CHECK_TRACE_COUNT_FOR_LABEL_GREATER_THAN : {
if ( ! Passed ) break ;
int expected_count = ingredients . at ( 0 ) . at ( 0 ) ;
string label = current_instruction ( ) . ingredients . at ( 1 ) . name ;
int count = trace_count ( label ) ;
if ( count < = expected_count ) {
2017-06-15 17:45:03 +00:00
if ( ! Hide_errors ) cerr < < ' \n ' ;
raise < < maybe ( current_recipe_name ( ) ) < < " expected more than " < < expected_count < < " lines in trace with label ' " < < label < < " ' in trace \n " < < end ( ) ;
if ( ! Hide_errors ) {
cerr < < " trace contents: \n " ;
2017-06-09 22:54:26 +00:00
DUMP ( label ) ;
}
if ( ! Scenario_testing_scenario ) Passed = false ;
}
break ;
}
: ( before " End Primitive Recipe Declarations " )
CHECK_TRACE_COUNT_FOR_LABEL_LESSER_THAN ,
: ( before " End Primitive Recipe Numbers " )
put ( Recipe_ordinal , " check-trace-count-for-label-lesser-than " , CHECK_TRACE_COUNT_FOR_LABEL_LESSER_THAN ) ;
: ( before " End Primitive Recipe Checks " )
case CHECK_TRACE_COUNT_FOR_LABEL_LESSER_THAN : {
if ( SIZE ( inst . ingredients ) ! = 2 ) {
raise < < maybe ( get ( Recipe , r ) . name ) < < " 'check-trace-count-for-label' requires exactly two ingredients, but got ' " < < to_original_string ( inst ) < < " ' \n " < < end ( ) ;
break ;
}
if ( ! is_mu_number ( inst . ingredients . at ( 0 ) ) ) {
raise < < maybe ( get ( Recipe , r ) . name ) < < " first ingredient of 'check-trace-count-for-label' should be a number (count), but got ' " < < inst . ingredients . at ( 0 ) . original_string < < " ' \n " < < end ( ) ;
break ;
}
if ( ! is_literal_text ( inst . ingredients . at ( 1 ) ) ) {
raise < < maybe ( get ( Recipe , r ) . name ) < < " second ingredient of 'check-trace-count-for-label' should be a literal string (label), but got ' " < < inst . ingredients . at ( 1 ) . original_string < < " ' \n " < < end ( ) ;
break ;
}
break ;
}
: ( before " End Primitive Recipe Implementations " )
case CHECK_TRACE_COUNT_FOR_LABEL_LESSER_THAN : {
if ( ! Passed ) break ;
int expected_count = ingredients . at ( 0 ) . at ( 0 ) ;
string label = current_instruction ( ) . ingredients . at ( 1 ) . name ;
int count = trace_count ( label ) ;
if ( count > = expected_count ) {
2017-06-15 17:45:03 +00:00
if ( ! Hide_errors ) cerr < < ' \n ' ;
raise < < " F - " < < maybe ( current_recipe_name ( ) ) < < " expected less than " < < expected_count < < " lines in trace with label ' " < < label < < " ' in trace \n " < < end ( ) ;
if ( ! Hide_errors ) {
cerr < < " trace contents: \n " ;
2017-06-09 22:54:26 +00:00
DUMP ( label ) ;
}
if ( ! Scenario_testing_scenario ) Passed = false ;
}
break ;
}
2015-08-14 02:03:17 +00:00
: ( scenario trace_count_check_2 )
% Scenario_testing_scenario = true ;
2015-10-07 05:15:45 +00:00
% Hide_errors = true ;
2016-03-08 09:30:14 +00:00
def main [
2015-08-14 02:03:17 +00:00
run [
trace 1 , [ a ] , [ foo ]
]
check - trace - count - for - label 2 , [ a ]
]
2017-06-15 17:45:03 +00:00
+ error : F - main : expected 2 lines in trace with label ' a ' in trace
2015-08-14 02:03:17 +00:00
2015-07-28 22:22:58 +00:00
//: Minor detail: ignore 'system' calls in scenarios, since anything we do
2016-10-22 23:56:07 +00:00
//: with them is by definition impossible to test through Mu.
2015-07-28 22:22:58 +00:00
: ( after " case _SYSTEM: " )
if ( Current_scenario ) break ;
2017-11-04 01:01:59 +00:00
//:: Warn if people use '_' manually in recipe names. They're reserved for internal use.
2016-05-27 16:50:39 +00:00
: ( scenario recipe_name_with_underscore )
% Hide_errors = true ;
def foo_bar [
]
+ error : foo_bar : don ' t create recipes with ' _ ' in the name
: ( before " End recipe Fields " )
bool is_autogenerated ;
: ( before " End recipe Constructor " )
is_autogenerated = false ;
: ( code )
void mark_autogenerated ( recipe_ordinal r ) {
get ( Recipe , r ) . is_autogenerated = true ;
}
: ( after " void transform_all() " )
2016-10-20 05:10:35 +00:00
for ( map < recipe_ordinal , recipe > : : iterator p = Recipe . begin ( ) ; p ! = Recipe . end ( ) ; + + p ) {
2016-05-27 16:50:39 +00:00
const recipe & r = p - > second ;
if ( r . name . find ( ' _ ' ) = = string : : npos ) continue ;
if ( r . is_autogenerated ) continue ; // created by previous call to transform_all()
raise < < r . name < < " : don't create recipes with '_' in the name \n " < < end ( ) ;
}
2015-04-22 20:29:02 +00:00
//:: Helpers
2015-05-02 22:52:22 +00:00
: ( code )
2015-05-04 18:56:16 +00:00
// just for the scenarios running scenarios in C++ layers
void run_mu_scenario ( const string & form ) {
2016-12-28 02:35:27 +00:00
Scenario_names . clear ( ) ;
2015-05-04 18:56:16 +00:00
istringstream in ( form ) ;
in > > std : : noskipws ;
2015-05-27 18:27:50 +00:00
skip_whitespace_and_comments ( in ) ;
2015-05-04 18:56:16 +00:00
string _scenario = next_word ( in ) ;
2016-10-21 08:08:09 +00:00
if ( _scenario . empty ( ) ) {
assert ( ! has_data ( in ) ) ;
raise < < " no scenario in string passed into run_mu_scenario() \n " < < end ( ) ;
return ;
}
2015-05-04 18:56:16 +00:00
assert ( _scenario = = " scenario " ) ;
scenario s = parse_scenario ( in ) ;
run_mu_scenario ( s ) ;
}