use super::*;
use crate::testing::ebcdic;
use std::cell::RefCell;
use std::rc::Rc;
const SUBPROGRAM: &str = " IDENTIFICATION DIVISION.
PROGRAM-ID. SUB.
DATA DIVISION.
LINKAGE SECTION.
01 QTY PIC 9(5).
01 NAME PIC X(8).
01 MISSING PIC X(4).
PROCEDURE DIVISION USING QTY NAME MISSING.
DISPLAY 'NAME ' NAME
IF ADDRESS OF MISSING = NULL
DISPLAY 'OMITTED'
END-IF
ADD 1 TO QTY
DISPLAY 'QTY ' QTY
EXIT PROGRAM.
DISPLAY 'AFTER EXIT'.
";
fn arguments(qty: &str) -> Vec<Option<Vec<u8>>> {
vec![Some(ebcdic(qty)), Some(ebcdic("ALICE ")), None]
}
#[test]
fn a_subprogram_reads_its_arguments_as_its_using_items_and_exit_program_returns() {
for (executor, name) in [(Executor::Interpreter, "interpreter"), (Executor::Vm, "vm")] {
let o = Harness::source(SUBPROGRAM).arguments(arguments("00041")).run(executor);
assert!(o.ending.is_ok(), "{:?} {}", o.ending, o.err);
assert_eq!(o.out, "NAME ALICE \nOMITTED\nQTY 00042\n", "{name}");
}
}
#[test]
fn an_argument_that_breaks_its_picture_ends_the_subprogram_where_it_is_used() {
for (executor, name) in [(Executor::Interpreter, "interpreter"), (Executor::Vm, "vm")] {
let o = Harness::source(SUBPROGRAM).arguments(arguments("AB*DE")).run(executor);
let abend = o.ending.expect_err("a non-numeric QTY is a data exception at the ADD");
assert_eq!(abend.code.as_str(), "S0C7", "{name}");
assert_eq!(o.out, "NAME ALICE \nOMITTED\n", "{name}");
}
}
#[test]
fn every_argument_is_input_to_the_run() {
let mut programs = syntax::parse_all_with(SUBPROGRAM, &syntax::copy::Libraries::default()).unwrap_or_else(|e| panic!("{e}"));
let compiled = compile(programs.remove(0), &[]).unwrap_or_else(|e| panic!("{e:?}"));
let seen = Rc::new(RefCell::new(Vec::new()));
let recorder = seen.clone();
let observer: unit::Observer<'_> = Box::new(move |e| {
if let unit::Event::Sink { operand, input, .. } = e {
recorder.borrow_mut().push((operand.to_owned(), input));
}
});
let library = unit::Library { programs, trace_input: true, ..Default::default() };
let (mut out, mut err) = (Vec::new(), Vec::new());
let ended = compiled.execute_with_arguments(library, files::Dds::default(), None, unit::Clock::Fixed(0, 0), None, &mut out, &mut err, Some(observer), &arguments("00041"));
assert!(ended.is_ok(), "{ended:?} {}", String::from_utf8_lossy(&err));
let seen = seen.borrow();
let input_of = |text: &str| seen.iter().find(|(operand, _)| operand.contains(text)).unwrap_or_else(|| panic!("no sink shows {text}: {seen:?}")).1;
assert_eq!(input_of("ALICE"), Some(true));
assert_eq!(input_of("00042"), Some(true));
assert_eq!(input_of("OMITTED"), Some(false));
}