Laufzeit-Eingabe und Zonenzustand korrigieren und Change archivieren
This commit is contained in:
@@ -1516,3 +1516,203 @@ fn klassischer_timer_trap_ruht_solange_das_menu_offen_ist() {
|
||||
assert_eq!(vm.run(&mut host), RunEvent::Ended);
|
||||
assert!(matches!(vm.inspect("n"), Some(Value::Int(1))));
|
||||
}
|
||||
|
||||
// ---- Laufzeit-Eingabe und Systemstatus ------------------------------------
|
||||
|
||||
#[test]
|
||||
fn input_datei_bewahrt_felder_und_unterscheidet_leer_von_fehlend() {
|
||||
let tmp = TempVerzeichnis::neu("input_felder");
|
||||
let p = tmp.pfad("daten.txt");
|
||||
assert_eq!(out(&format!(
|
||||
"OPEN \"{p}\" FOR OUTPUT AS #1\nWRITE #1, \"a\", \"b\"\nWRITE #1, \"a,b\", 5\nWRITE #1, CHR$(34) + \"ä\" + CHR$(34), \"\"\nCLOSE #1\nOPEN \"{p}\" FOR INPUT AS #1\nINPUT #1, a$\nINPUT #1, b$, c$, n%, d$, e$\nPRINT a$; b$; c$; n%; d$; LEN(e$); EOF(1)\nCLOSE"
|
||||
)), "aba,b 5 \"ä\" 0 -1 \n");
|
||||
for (data, expected) in [("\"a\"\n", 62), ("a", 62), ("", 62), ("\"a", 62)] {
|
||||
std::fs::write(&p, data).unwrap();
|
||||
assert_eq!(
|
||||
err_code(&format!("OPEN \"{p}\" FOR INPUT AS #1\nINPUT #1, a$, b$")),
|
||||
expected
|
||||
);
|
||||
}
|
||||
std::fs::write(&p, "a,\r\n\r\n\"b\n,c\"\r\n").unwrap();
|
||||
assert_eq!(out(&format!("OPEN \"{p}\" FOR INPUT AS #1\nINPUT #1, a$, b$, c$, d$\nPRINT a$; LEN(b$); LEN(c$); LEN(d$); EOF(1)")), "a 0 0 4 -1 \n");
|
||||
std::fs::write(&p, "a,").unwrap();
|
||||
assert_eq!(out(&format!("OPEN \"{p}\" FOR INPUT AS #1\nINPUT #1, a$\nPRINT EOF(1);\nINPUT #1, b$\nPRINT LEN(b$); EOF(1)")), " 0 0 -1 \n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn input_datei_alle_lesearten_teilen_utf8_cursor_und_seek() {
|
||||
let tmp = TempVerzeichnis::neu("input_cursor");
|
||||
let p = tmp.pfad("daten.txt");
|
||||
std::fs::write(&p, "ä😀,rest\r\n\"a,b\",Ende\r\nZ").unwrap();
|
||||
assert_eq!(out(&format!(
|
||||
"OPEN \"{p}\" FOR INPUT AS #1\nPRINT INPUT$(1, #1); INPUT$(1, #1); SEEK(1)\nLINE INPUT #1, s$\nPRINT s$\nINPUT #1, s$\nPRINT s$; INPUT$(2, #1)\nLINE INPUT #1, s$\nPRINT s$\nPRINT INPUT$(1, #1); EOF(1); LEN(INPUT$(0, #1))\nSEEK #1, 1\nINPUT #1, s$\nPRINT s$; SEEK(1)\nCLOSE"
|
||||
)), "ä😀 7 \n,rest\na,bEn\nde\nZ-1 0 \nä😀 8 \n");
|
||||
for mode in ["INPUT", "BINARY"] {
|
||||
std::fs::write(&p, "ä😀x").unwrap();
|
||||
assert_eq!(
|
||||
out(&format!(
|
||||
"OPEN \"{p}\" FOR {mode} AS #1\nPRINT INPUT$(2, #1); INPUT$(1, #1); EOF(1)"
|
||||
)),
|
||||
"ä😀x-1 \n"
|
||||
);
|
||||
assert_eq!(
|
||||
err_code(&format!(
|
||||
"OPEN \"{p}\" FOR {mode} AS #1\ns$ = INPUT$(4, #1)"
|
||||
)),
|
||||
62
|
||||
);
|
||||
for bad in [&[0xc3][..], &[0xff], &[0xe0, 0x80, 0x80], &[0xf0, 0x9f]] {
|
||||
std::fs::write(&p, bad).unwrap();
|
||||
assert_eq!(
|
||||
err_code(&format!(
|
||||
"OPEN \"{p}\" FOR {mode} AS #1\ns$ = INPUT$(1, #1)"
|
||||
)),
|
||||
57
|
||||
);
|
||||
}
|
||||
}
|
||||
for input in ["INPUT #1, s$", "LINE INPUT #1, s$"] {
|
||||
assert_eq!(
|
||||
err_code(&format!("OPEN \"{p}\" FOR INPUT AS #1\n{input}")),
|
||||
57
|
||||
);
|
||||
}
|
||||
for mode in ["OUTPUT", "APPEND", "RANDOM"] {
|
||||
assert_eq!(
|
||||
err_code(&format!(
|
||||
"OPEN \"{p}\" FOR {mode} AS #1\ns$ = INPUT$(1, #1)"
|
||||
)),
|
||||
54
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn input_s_teilt_sondertasten_und_bewahrt_rest_fuer_inkey() {
|
||||
use tb_runtime::host::Ereignis;
|
||||
for second in ["INPUT$(1)", "INKEY$"] {
|
||||
let src = format!("a$ = INPUT$(1)\nb$ = {second}\nc$ = INPUT$(2)\nPRINT LEN(a$); ASC(a$); LEN(b$); ASC(b$); c$; LEN(INKEY$)");
|
||||
let mut vm = Vm::new(tb_vm::compile_source("T", &src).unwrap());
|
||||
let mut host = CaptureHost::default();
|
||||
for text in ["\0;", "ä", "😀"] {
|
||||
host.ereignis(Ereignis::Taste(text.into(), 0));
|
||||
}
|
||||
assert_eq!(vm.run(&mut host), RunEvent::Ended);
|
||||
assert_eq!(
|
||||
tb_runtime::snapshot::text(&vm.rt.screen),
|
||||
" 1 0 1 59 ä😀 0 \n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alle_mk_cv_paare_verlangen_exakte_bytezeichenbreite() {
|
||||
for (mk, cv, n, breite) in [
|
||||
("MKI$", "CVI", "-123", 2),
|
||||
("MKL$", "CVL", "123456", 4),
|
||||
("MKS$", "CVS", "1.5", 4),
|
||||
("MKD$", "CVD", "-12.25", 8),
|
||||
("MKC$", "CVC", "12.3456@", 8),
|
||||
] {
|
||||
assert_eq!(out(&format!("PRINT {cv}({mk}({n})) = {n}")), "-1 \n");
|
||||
for arg in [
|
||||
format!("LEFT$({mk}({n}), {})", breite - 1),
|
||||
format!("{mk}({n}) + CHR$(0)"),
|
||||
format!("STRING$({breite}, \"😀\")"),
|
||||
] {
|
||||
assert_eq!(err_code(&format!("PRINT {cv}({arg})")), 5, "{cv}({arg})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn datei_und_elternpfadfehler_sind_am_sprachzugang_unterscheidbar() {
|
||||
let tmp = TempVerzeichnis::neu("pfadfehler");
|
||||
let leaf = tmp.pfad("fehlt.txt");
|
||||
let parent = tmp.pfad("fehlt/datei.txt");
|
||||
let source = tmp.pfad("quelle.txt");
|
||||
std::fs::write(&source, "erhalten").unwrap();
|
||||
for (path, code) in [(&leaf, 53), (&parent, 76)] {
|
||||
for stmt in [
|
||||
format!("OPEN \"{path}\" FOR INPUT AS #1"),
|
||||
format!("KILL \"{path}\""),
|
||||
format!("NAME \"{path}\" AS \"{source}\""),
|
||||
] {
|
||||
assert_eq!(err_code(&stmt), code, "{stmt}");
|
||||
}
|
||||
}
|
||||
for stmt in [
|
||||
format!("MKDIR \"{parent}\""),
|
||||
format!("NAME \"{source}\" AS \"{parent}\""),
|
||||
format!("CHDIR \"{parent}\""),
|
||||
format!("RMDIR \"{parent}\""),
|
||||
format!("PRINT DIR$(\"{parent}\")"),
|
||||
] {
|
||||
assert_eq!(err_code(&stmt), 76, "{stmt}");
|
||||
}
|
||||
for mode in ["OUTPUT", "APPEND", "BINARY", "RANDOM"] {
|
||||
assert_eq!(err_code(&format!("OPEN \"{parent}\" FOR {mode} AS #1")), 76);
|
||||
}
|
||||
assert_eq!(std::fs::read_to_string(&source).unwrap(), "erhalten");
|
||||
let sub = tmp.pfad("unter");
|
||||
let a = format!("{sub}\\a.txt");
|
||||
let b = format!("{sub}/b.txt");
|
||||
assert_eq!(out(&format!("MKDIR \"{sub}\"\nOPEN \"{a}\" FOR OUTPUT AS #1\nWRITE #1, \"ok\"\nCLOSE\nNAME \"{a}\" AS \"{b}\"\nPRINT DIR$(\"{sub}/*.txt\"); LEN(DIR$(\"\"))\nOPEN \"{b}\" FOR INPUT AS #1\nINPUT #1, s$\nPRINT s$\nCLOSE\nKILL \"{b}\"\nRMDIR \"{sub}\"")), "b.txt 0 \nok\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timezoneknown_hat_integer_signatur_und_zeigt_aktuellen_status() {
|
||||
for (zone, expected) in [(Zeitzone::Fest(0), "-1 \n"), (Zeitzone::Unbekannt, " 0 \n")] {
|
||||
assert_eq!(out_mit_zone("PRINT TIMEZONEKNOWN", zone), expected);
|
||||
}
|
||||
let diagnostics = tb_vm::compile_source("T", "PRINT TIMEZONEKNOWN(1)").unwrap_err();
|
||||
assert!(
|
||||
diagnostics
|
||||
.iter()
|
||||
.any(|d| d.message.contains("TIMEZONEKNOWN")),
|
||||
"{diagnostics:?}"
|
||||
);
|
||||
let mut vm = Vm::new(
|
||||
tb_vm::compile_source(
|
||||
"T",
|
||||
"x = TIMEZONEKNOWN\nSTOP\ny = TIMEZONEKNOWN\nSTOP\nz = TIMEZONEKNOWN\nEND",
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
let mut host = CaptureHost::default();
|
||||
vm.rt.zonen_ermittler = |_| Some(7200);
|
||||
assert!(matches!(vm.run(&mut host), RunEvent::Stopped { .. }));
|
||||
assert!(matches!(vm.inspect("x"), Some(Value::Sng(-1.0))));
|
||||
vm.rt.zonen_ermittler = |_| None;
|
||||
assert!(matches!(vm.run(&mut host), RunEvent::Stopped { .. }));
|
||||
assert!(matches!(vm.inspect("y"), Some(Value::Sng(0.0))));
|
||||
vm.rt.zonen_ermittler = |_| Some(0);
|
||||
assert_eq!(vm.run(&mut host), RunEvent::Ended);
|
||||
assert!(matches!(vm.inspect("z"), Some(Value::Sng(-1.0))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unicode_puffergrenzen_und_binaere_records_bleiben_getrennt() {
|
||||
let tmp = TempVerzeichnis::neu("input_puffer");
|
||||
let p = tmp.pfad("daten.txt");
|
||||
for n in [8190, 8191, 8192] {
|
||||
std::fs::write(&p, format!("{}ä😀\r\nZ", "x".repeat(n))).unwrap();
|
||||
assert_eq!(out(&format!("OPEN \"{p}\" FOR INPUT AS #1\na$ = INPUT$({n}, #1)\nPRINT INPUT$(2, #1)\nLINE INPUT #1, b$\nINPUT #1, c$\nPRINT LEN(b$); c$; EOF(1)")), "ä😀\n 0 Z-1 \n");
|
||||
}
|
||||
let mut bytes = "ä😀".as_bytes().to_vec();
|
||||
bytes.extend_from_slice(&513i16.to_le_bytes());
|
||||
bytes.push(b'Z');
|
||||
std::fs::write(&p, bytes).unwrap();
|
||||
assert_eq!(out(&format!("OPEN \"{p}\" FOR BINARY AS #1\nPRINT INPUT$(2, #1);\nGET #1, , n%\nPRINT n%; INPUT$(1, #1); EOF(1)\nSEEK #1, 7\nn% = 1027\nPUT #1, , n%\nSEEK #1, 7\nGET #1, , n%\nPRINT n%; INPUT$(1, #1)")), "ä😀 513 Z-1 \n 1027 Z\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sondertastenrest_wird_nicht_erneut_getrappt() {
|
||||
use tb_runtime::host::Ereignis;
|
||||
let src = "ON KEY(1) GOSUB H\nKEY(1) STOP\na$ = INPUT$(1)\nKEY(1) ON\nb$ = INPUT$(1)\nDOEVENTS\nPRINT ASC(a$); ASC(b$); n%\nEND\nH:\nn% = n% + 1\nRETURN";
|
||||
let mut vm = Vm::new(tb_vm::compile_source("T", src).unwrap());
|
||||
let mut host = CaptureHost::default();
|
||||
host.ereignis(Ereignis::Taste("\0;".into(), 0));
|
||||
assert_eq!(vm.run(&mut host), RunEvent::Ended);
|
||||
assert_eq!(tb_runtime::snapshot::text(&vm.rt.screen), " 0 59 1 \n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user