Phase 5: Ausführung und Output implementieren und archivieren
This commit is contained in:
@@ -530,10 +530,14 @@ fn mouse_focus_is_modal_and_program_abort_is_not_editor_copy() {
|
||||
menu(&mut app, Command::Output);
|
||||
app.execution = Execution::Running;
|
||||
key(&mut app, K::Char('c'), M::CONTROL);
|
||||
assert_eq!(
|
||||
app.basic_events,
|
||||
vec![Event::Key(KeyEvent::new(K::Char('c'), M::CONTROL))]
|
||||
assert_eq!(app.execution, Execution::Paused);
|
||||
assert!(app.basic_events.is_empty());
|
||||
plain(&mut app, K::Char('x'));
|
||||
assert!(
|
||||
app.basic_events.is_empty(),
|
||||
"Tasten nach Break gehören nicht mehr BASIC"
|
||||
);
|
||||
app.execution = Execution::Running;
|
||||
let r = app.rect(app.active_window().unwrap());
|
||||
let mouse = MouseEvent {
|
||||
kind: MouseEventKind::Down(MouseButton::Right),
|
||||
@@ -542,7 +546,10 @@ fn mouse_focus_is_modal_and_program_abort_is_not_editor_copy() {
|
||||
modifiers: M::NONE,
|
||||
};
|
||||
app.handle(Event::Mouse(mouse));
|
||||
assert_eq!(app.basic_events.last(), Some(&Event::Mouse(mouse)));
|
||||
let mut local = mouse;
|
||||
local.column = 1;
|
||||
local.row = 1;
|
||||
assert_eq!(app.basic_events.last(), Some(&Event::Mouse(local)));
|
||||
app.execution = Execution::Idle;
|
||||
menu(&mut app, Command::RightMouse);
|
||||
plain(&mut app, K::Char(' '));
|
||||
|
||||
532
crates/tb-ide/tests/execution.rs
Normal file
532
crates/tb-ide/tests/execution.rs
Normal file
@@ -0,0 +1,532 @@
|
||||
use crossterm::event::{Event, KeyCode as K, KeyEvent, KeyModifiers as M};
|
||||
use std::{
|
||||
fs,
|
||||
path::PathBuf,
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
use tb_ide::{
|
||||
app::{App, DialogKind, Execution, Field, WindowKind},
|
||||
commands::Command,
|
||||
};
|
||||
use tb_runtime::{snapshot, value::Value};
|
||||
struct Temp(PathBuf);
|
||||
impl Temp {
|
||||
fn new() -> Self {
|
||||
static N: AtomicUsize = AtomicUsize::new(0);
|
||||
let p = std::env::temp_dir().join(format!(
|
||||
"tb-execution-{}-{}",
|
||||
std::process::id(),
|
||||
N.fetch_add(1, Ordering::Relaxed)
|
||||
));
|
||||
fs::create_dir_all(&p).unwrap();
|
||||
Self(p.canonicalize().unwrap())
|
||||
}
|
||||
fn app(&self, source: &str) -> App {
|
||||
let path = self.0.join("main.bas");
|
||||
fs::write(&path, source).unwrap();
|
||||
let mut app = App::new(&self.0, self.0.join("options"), (100, 30)).unwrap();
|
||||
app.load_initial_project(path).unwrap();
|
||||
app.options.syntax_checking = false;
|
||||
app
|
||||
}
|
||||
}
|
||||
impl Drop for Temp {
|
||||
fn drop(&mut self) {
|
||||
let _ = fs::remove_dir_all(&self.0);
|
||||
}
|
||||
}
|
||||
fn key(a: &mut App, k: K, m: M) {
|
||||
a.handle(Event::Key(KeyEvent::new(k, m)));
|
||||
}
|
||||
fn tick(a: &mut App) {
|
||||
for _ in 0..20 {
|
||||
a.tick_execution(0);
|
||||
}
|
||||
}
|
||||
fn output(a: &App) -> String {
|
||||
snapshot::text(a.session.screen())
|
||||
}
|
||||
fn edit_window(a: &mut App) {
|
||||
let id = a
|
||||
.windows
|
||||
.iter()
|
||||
.find(|w| matches!(w.kind, WindowKind::Code(_)))
|
||||
.unwrap()
|
||||
.id;
|
||||
a.execute(Command::FocusWindow(id));
|
||||
}
|
||||
#[test]
|
||||
fn f5_input_pause_copy_and_single_delivery_keep_the_same_vm() {
|
||||
let t = Temp::new();
|
||||
let mut a = t.app("LINE INPUT \"Name: \"; s$\nPRINT s$\nEND\n");
|
||||
key(&mut a, K::F(5), M::NONE);
|
||||
tick(&mut a);
|
||||
assert_eq!(a.execution, Execution::Waiting);
|
||||
key(&mut a, K::Char('a'), M::NONE);
|
||||
tick(&mut a);
|
||||
edit_window(&mut a);
|
||||
key(&mut a, K::Char('a'), M::CONTROL);
|
||||
key(&mut a, K::Char('c'), M::CONTROL);
|
||||
assert!(a.editor.clipboard.starts_with("LINE INPUT"));
|
||||
assert_eq!(a.execution, Execution::Waiting);
|
||||
key(&mut a, K::Pause, M::CONTROL);
|
||||
assert_eq!(a.execution, Execution::Paused);
|
||||
assert!(a.message.contains("main.bas"));
|
||||
key(&mut a, K::F(5), M::NONE);
|
||||
assert!(a.dialog.is_none());
|
||||
a.execute(Command::Output);
|
||||
key(&mut a, K::Char('b'), M::NONE);
|
||||
key(&mut a, K::Enter, M::NONE);
|
||||
tick(&mut a);
|
||||
assert_eq!(a.execution, Execution::Ended, "{}", a.message);
|
||||
assert_eq!(output(&a), "Name: ? ab\nab\n");
|
||||
assert!(!a.quit);
|
||||
assert!(a.session.vm.is_none());
|
||||
key(&mut a, K::F(5), M::SHIFT);
|
||||
tick(&mut a);
|
||||
key(&mut a, K::Char('c'), M::CONTROL);
|
||||
tick(&mut a);
|
||||
assert_eq!(a.execution, Execution::Paused);
|
||||
assert_eq!(output(&a), "Name: ? \n");
|
||||
}
|
||||
#[test]
|
||||
fn changed_paused_source_requires_explicit_old_revision_or_restart() {
|
||||
let t = Temp::new();
|
||||
let mut a = t.app("STOP\nPRINT \"old\"\nEND\n");
|
||||
a.execute(Command::Start);
|
||||
tick(&mut a);
|
||||
assert_eq!(a.execution, Execution::Paused);
|
||||
let id = a.project.members()[0];
|
||||
a.project
|
||||
.replace_text(
|
||||
id,
|
||||
0..a.project.document(id).unwrap().code().len(),
|
||||
"STOP\nPRINT \"new\"\nEND\n",
|
||||
)
|
||||
.unwrap();
|
||||
a.execute(Command::Continue);
|
||||
assert!(matches!(
|
||||
a.dialog.as_ref().unwrap().kind,
|
||||
DialogKind::ResumeRevision
|
||||
));
|
||||
a.dialog.as_mut().unwrap().fields[0] =
|
||||
Field::choice("Fortsetzen", vec!["restart".into(), "old".into()], 1);
|
||||
key(&mut a, K::Enter, M::NONE);
|
||||
assert!(a.session.old_revision);
|
||||
assert!(a
|
||||
.title(a.active_window().unwrap())
|
||||
.contains("ALTES KOMPILAT"));
|
||||
tick(&mut a);
|
||||
assert_eq!(output(&a), "old\n");
|
||||
a.execute(Command::Restart);
|
||||
tick(&mut a);
|
||||
a.project
|
||||
.replace_text(
|
||||
id,
|
||||
0..a.project.document(id).unwrap().code().len(),
|
||||
"' comment\nPRINT \"latest\"\nEND\n",
|
||||
)
|
||||
.unwrap();
|
||||
a.execute(Command::Continue);
|
||||
key(&mut a, K::Enter, M::NONE);
|
||||
tick(&mut a);
|
||||
assert_eq!(output(&a), "latest\n");
|
||||
assert!(!a.session.old_revision);
|
||||
a.project
|
||||
.replace_text(
|
||||
id,
|
||||
0..a.project.document(id).unwrap().code().len(),
|
||||
"PRINT (\n",
|
||||
)
|
||||
.unwrap();
|
||||
a.execute(Command::Start);
|
||||
assert_eq!(a.execution, Execution::Error);
|
||||
assert!(a.session.vm.is_none());
|
||||
}
|
||||
#[test]
|
||||
fn output_viewports_resize_and_end_preserve_buffer_and_basic_colors() {
|
||||
let t = Temp::new();
|
||||
let mut a = t.app("COLOR 4,1\nPRINT \"visible\"\nSTOP\nEND\n");
|
||||
a.execute(Command::Start);
|
||||
tick(&mut a);
|
||||
let original = output(&a);
|
||||
let size = (a.session.screen().cols(), a.session.screen().rows());
|
||||
let active = a.active;
|
||||
let w = a.windows.iter_mut().find(|w| w.id == active).unwrap();
|
||||
w.normal = ratatui::layout::Rect::new(3, 3, 30, 8);
|
||||
let mut terminal = ratatui::Terminal::new(ratatui::backend::TestBackend::new(100, 30)).unwrap();
|
||||
terminal.draw(|f| a.render(f)).unwrap();
|
||||
assert_eq!(terminal.backend().buffer()[(4, 4)].symbol(), "v");
|
||||
assert_eq!(
|
||||
terminal.backend().buffer()[(4, 4)].fg,
|
||||
tb_ui::screen::basic_color(4)
|
||||
);
|
||||
key(&mut a, K::F(4), M::NONE);
|
||||
terminal.draw(|f| a.render(f)).unwrap();
|
||||
assert_eq!(terminal.backend().buffer()[(0, 0)].symbol(), "v");
|
||||
assert_eq!((a.session.screen().cols(), a.session.screen().rows()), size);
|
||||
a.handle(Event::Resize(120, 40));
|
||||
assert_eq!(
|
||||
(a.session.screen().cols(), a.session.screen().rows()),
|
||||
(120, 40)
|
||||
);
|
||||
key(&mut a, K::F(4), M::NONE);
|
||||
a.execute(Command::Continue);
|
||||
tick(&mut a);
|
||||
assert_eq!(a.execution, Execution::Ended);
|
||||
assert_eq!(output(&a), original);
|
||||
}
|
||||
#[test]
|
||||
fn restart_command_run_targets_and_missing_target_preserve_documents() {
|
||||
let t = Temp::new();
|
||||
let mut a = t.app("PRINT COMMAND$\nn%=n%+1\nSTOP\nEND\n");
|
||||
a.execute(Command::CommandLine);
|
||||
a.dialog.as_mut().unwrap().fields[0] = Field::text("args", "one two");
|
||||
key(&mut a, K::Enter, M::NONE);
|
||||
for _ in 0..3 {
|
||||
a.execute(Command::Restart);
|
||||
tick(&mut a);
|
||||
assert_eq!(output(&a), "one two\n");
|
||||
assert!(matches!(
|
||||
a.session.vm.as_ref().unwrap().inspect("n"),
|
||||
Some(Value::Int(1))
|
||||
));
|
||||
}
|
||||
let id = a.project.members()[0];
|
||||
let path = a.project.document(id).unwrap().source_path().to_path_buf();
|
||||
fs::write(t.0.join("other.bas"), "PRINT \"foreign\"\nEND\n").unwrap();
|
||||
a.project
|
||||
.replace_text(
|
||||
id,
|
||||
0..a.project.document(id).unwrap().code().len(),
|
||||
"RUN \"OTHER\"\n",
|
||||
)
|
||||
.unwrap();
|
||||
a.execute(Command::Start);
|
||||
tick(&mut a);
|
||||
assert_eq!(output(&a), "foreign\n");
|
||||
assert_eq!(a.project.document(id).unwrap().source_path(), path);
|
||||
assert_eq!(a.project.document(id).unwrap().code(), "RUN \"OTHER\"\n");
|
||||
a.project
|
||||
.replace_text(
|
||||
id,
|
||||
0..a.project.document(id).unwrap().code().len(),
|
||||
"RUN \"missing\"\n",
|
||||
)
|
||||
.unwrap();
|
||||
a.execute(Command::Start);
|
||||
tick(&mut a);
|
||||
assert_eq!(a.execution, Execution::Error);
|
||||
assert!(a.message.contains("nicht gefunden"));
|
||||
assert_eq!(a.project.document(id).unwrap().code(), "RUN \"missing\"\n");
|
||||
assert!(!a.quit);
|
||||
a.project
|
||||
.replace_text(
|
||||
id,
|
||||
0..a.project.document(id).unwrap().code().len(),
|
||||
"10 PRINT \"skip\"\n20 STOP\n30 RUN 40\n40 PRINT \"target\"\n50 END\n",
|
||||
)
|
||||
.unwrap();
|
||||
a.execute(Command::Start);
|
||||
tick(&mut a);
|
||||
a.execute(Command::Continue);
|
||||
tick(&mut a);
|
||||
assert_eq!(output(&a), "target\n");
|
||||
}
|
||||
#[test]
|
||||
fn print_uses_utf8_protected_output_and_does_not_mutate_source() {
|
||||
let t = Temp::new();
|
||||
let mut a = t.app("PRINT \"Grüße\"\n");
|
||||
let id = a.project.members()[0];
|
||||
let WindowKind::Code(v) = a.active_window().unwrap().kind else {
|
||||
panic!()
|
||||
};
|
||||
a.project.view_mut(v).unwrap().anchor = Some(0);
|
||||
a.project.view_mut(v).unwrap().cursor = 5;
|
||||
a.execute(Command::Print);
|
||||
assert!(a.dialog.as_ref().unwrap().fields[0]
|
||||
.string()
|
||||
.ends_with("LPT1.TXT"));
|
||||
key(&mut a, K::Enter, M::NONE);
|
||||
assert_eq!(fs::read_to_string(t.0.join("LPT1.TXT")).unwrap(), "PRINT");
|
||||
a.execute(Command::Print);
|
||||
key(&mut a, K::Enter, M::NONE);
|
||||
assert!(!a.dialog.as_ref().unwrap().error.is_empty());
|
||||
a.dialog.as_mut().unwrap().fields[1] = Field::toggle("overwrite", true);
|
||||
a.dialog.as_mut().unwrap().fields[2] = Field::toggle("selection", false);
|
||||
key(&mut a, K::Enter, M::NONE);
|
||||
assert_eq!(
|
||||
fs::read_to_string(t.0.join("LPT1.TXT")).unwrap(),
|
||||
"PRINT \"Grüße\"\n"
|
||||
);
|
||||
a.execute(Command::Print);
|
||||
a.dialog.as_mut().unwrap().fields[0] =
|
||||
Field::text("path", t.0.join("main.bas").display().to_string());
|
||||
a.dialog.as_mut().unwrap().fields[1] = Field::toggle("overwrite", true);
|
||||
key(&mut a, K::Enter, M::NONE);
|
||||
assert!(!a.dialog.as_ref().unwrap().error.is_empty());
|
||||
assert_eq!(a.project.document(id).unwrap().code(), "PRINT \"Grüße\"\n");
|
||||
assert_eq!(
|
||||
fs::read_to_string(t.0.join("main.bas")).unwrap(),
|
||||
"PRINT \"Grüße\"\n"
|
||||
);
|
||||
key(&mut a, K::Esc, M::NONE);
|
||||
fs::write(t.0.join("blocked"), "existing destination parent").unwrap();
|
||||
a.execute(Command::Print);
|
||||
a.dialog.as_mut().unwrap().fields[0] =
|
||||
Field::text("path", t.0.join("blocked/print.txt").display().to_string());
|
||||
key(&mut a, K::Enter, M::NONE);
|
||||
assert!(!a.dialog.as_ref().unwrap().error.is_empty());
|
||||
assert_eq!(
|
||||
fs::read_to_string(t.0.join("blocked")).unwrap(),
|
||||
"existing destination parent"
|
||||
);
|
||||
assert_eq!(a.project.document(id).unwrap().code(), "PRINT \"Grüße\"\n");
|
||||
}
|
||||
#[test]
|
||||
fn shell_request_is_resumed_once_and_error_is_basic_error() {
|
||||
let t = Temp::new();
|
||||
let mut a = t.app("PRINT SHELL(\"exit 7\")\nEND\n");
|
||||
a.execute(Command::Start);
|
||||
tick(&mut a);
|
||||
assert_eq!(
|
||||
a.session.host.shell_request.take().as_deref(),
|
||||
Some("exit 7")
|
||||
);
|
||||
a.session.host.shell_result = Some(Ok(7));
|
||||
tick(&mut a);
|
||||
assert_eq!(output(&a), " 7 \n");
|
||||
assert!(a.session.host.shell_request.is_none());
|
||||
a.execute(Command::Start);
|
||||
tick(&mut a);
|
||||
a.session.host.shell_request = None;
|
||||
a.session.host.shell_result = Some(Err(tb_runtime::errors::RuntimeError(53)));
|
||||
tick(&mut a);
|
||||
assert_eq!(a.execution, Execution::Error);
|
||||
assert!(a.message.contains("53"));
|
||||
}
|
||||
#[test]
|
||||
fn startup_selection_matches_shared_cli_pipeline_and_legacy_mak() {
|
||||
use tb_vm::project_io::{new_execution, SourceLoader};
|
||||
let t = Temp::new();
|
||||
fs::write(t.0.join("a.bas"), "PRINT \"A\"\n").unwrap();
|
||||
fs::write(t.0.join("b.bas"), "PRINT \"B\"\n").unwrap();
|
||||
for (file, name) in [("one.frm", "One"), ("two.frm", "Two")] {
|
||||
fs::write(
|
||||
t.0.join(file),
|
||||
format!("VERSION 1.00\nBEGIN Form {name}\nEND\n"),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
for startup in [None, Some("b.bas"), Some("two.frm")] {
|
||||
fs::write(
|
||||
t.0.join("p.mak"),
|
||||
format!(
|
||||
"a.bas\nb.bas\none.frm\ntwo.frm\n{}",
|
||||
startup
|
||||
.map(|s| format!("' $STARTUP: \"{s}\"\n"))
|
||||
.unwrap_or_default()
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let mut a = App::new(&t.0, t.0.join("options"), (80, 25)).unwrap();
|
||||
a.load_initial_project(t.0.join("p.mak")).unwrap();
|
||||
a.session.command = "args".into();
|
||||
a.execute(Command::Start);
|
||||
let sources = SourceLoader::default().load(&t.0.join("p.mak")).unwrap();
|
||||
let module = sources.compile(&mut Default::default(), "CLI").unwrap();
|
||||
let module = tb_vm::bytecode::CompiledModule::from_tbc(&module.to_tbc()).unwrap();
|
||||
let mut cli = new_execution(module, "args", Some((80, 25)), None).unwrap();
|
||||
let ide = a.session.vm.as_ref().unwrap();
|
||||
assert_eq!(ide.rt.command, cli.rt.command);
|
||||
assert_eq!(ide.forms.active_form(), cli.forms.active_form());
|
||||
assert_eq!(ide.forms.has_visible_forms(), startup != Some("b.bas"));
|
||||
assert_eq!(
|
||||
sources.units[0].name.to_ascii_uppercase(),
|
||||
if startup == Some("two.frm") {
|
||||
"TWO"
|
||||
} else if startup == Some("b.bas") {
|
||||
"B"
|
||||
} else {
|
||||
"A"
|
||||
}
|
||||
);
|
||||
if startup == Some("b.bas") {
|
||||
tick(&mut a);
|
||||
assert_eq!(
|
||||
cli.run(&mut tb_runtime::host::CaptureHost::default()),
|
||||
tb_vm::interp::RunEvent::Ended
|
||||
);
|
||||
assert_eq!(output(&a), "B\nA\n");
|
||||
assert_eq!(output(&a), snapshot::text(&cli.rt.screen));
|
||||
}
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn ide_and_cli_run_wrapper_match_input_time_and_forms_script() {
|
||||
let t = Temp::new();
|
||||
let form="VERSION 1.00\nBEGIN Form Form1\n BEGIN Timer Timer1\n END\nEND\nTimer1.Interval=100\nTimer1.Enabled=-1\nSLEEP 10\nForm1.Hide\nCLS\nLINE INPUT s$\nPRINT s$; COMMAND$\nEND\nSUB Timer1_Timer\nTimer1.Enabled=0\nEND SUB\n";
|
||||
fs::write(t.0.join("form.frm"), form).unwrap();
|
||||
let mut a = App::new(&t.0, t.0.join("options"), (80, 25)).unwrap();
|
||||
a.load_initial_project(t.0.join("form.frm")).unwrap();
|
||||
a.session.command = "!".into();
|
||||
a.execute(Command::Start);
|
||||
a.tick_execution(0);
|
||||
assert_eq!(a.execution, Execution::Waiting);
|
||||
a.tick_execution(100);
|
||||
a.handle(Event::Paste("hello\n".into()));
|
||||
for _ in 0..20 {
|
||||
a.tick_execution(100);
|
||||
}
|
||||
assert_eq!(a.execution, Execution::Ended, "{}", a.message);
|
||||
// CLI wrapper gets the same scripted input at the same host deadline.
|
||||
struct ScriptHost {
|
||||
now: u64,
|
||||
events: std::collections::VecDeque<tb_runtime::host::Ereignis>,
|
||||
}
|
||||
impl tb_runtime::host::Host for ScriptHost {
|
||||
fn present(&mut self, _: &tb_runtime::screen::TextScreen) {}
|
||||
fn next_event(&mut self, _: bool) -> Option<tb_runtime::host::Ereignis> {
|
||||
self.events.pop_front()
|
||||
}
|
||||
fn jetzt_ms(&mut self) -> u64 {
|
||||
self.now
|
||||
}
|
||||
fn warten(&mut self, deadline: Option<u64>) -> Option<tb_runtime::host::Ereignis> {
|
||||
if let Some(d) = deadline {
|
||||
self.now = d;
|
||||
None
|
||||
} else {
|
||||
self.events.extend(
|
||||
"hello\r"
|
||||
.chars()
|
||||
.map(|c| tb_runtime::host::Ereignis::Taste(c.to_string(), 0)),
|
||||
);
|
||||
self.events.pop_front()
|
||||
}
|
||||
}
|
||||
}
|
||||
let module = tb_vm::project_io::load_program(&t.0.join("form.frm")).unwrap();
|
||||
let mut cli = tb_vm::project_io::new_execution(module, "!", Some((80, 25)), None).unwrap();
|
||||
assert_eq!(
|
||||
cli.run(&mut ScriptHost {
|
||||
now: 0,
|
||||
events: Default::default()
|
||||
}),
|
||||
tb_vm::interp::RunEvent::Ended
|
||||
);
|
||||
assert_eq!(output(&a), snapshot::text(&cli.rt.screen));
|
||||
assert_eq!(output(&a), "? hello\nhello!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn restart_drops_files_data_traps_and_queued_actions() {
|
||||
let t = Temp::new();
|
||||
let mut a=t.app(&format!("DATA 7\nSTOP\nREAD n%\nOPEN \"{}\" FOR OUTPUT AS #1\nON TIMER(1) GOSUB H\nTIMER ON\nSTOP\nEND\nH:\nRETURN\n",t.0.join("opened.txt").display()));
|
||||
a.execute(Command::Shell);
|
||||
assert!(a.session.file_shell);
|
||||
a.execute(Command::Start);
|
||||
tick(&mut a);
|
||||
assert!(!a.session.file_shell);
|
||||
assert!(a.session.host.shell_request.is_none());
|
||||
for _ in 0..3 {
|
||||
let vm = a.session.vm.as_ref().unwrap();
|
||||
assert!(!vm.rt.dateien.ist_offen(1));
|
||||
assert_eq!(vm.rt.traps.naechste_frist(), None);
|
||||
assert!(matches!(vm.inspect("n"), Some(Value::Int(0))));
|
||||
a.execute(Command::Continue);
|
||||
tick(&mut a);
|
||||
let vm = a.session.vm.as_ref().unwrap();
|
||||
assert!(vm.rt.dateien.ist_offen(1));
|
||||
assert!(vm.rt.traps.naechste_frist().is_some());
|
||||
assert!(matches!(vm.inspect("n"), Some(Value::Int(7))));
|
||||
a.session
|
||||
.host
|
||||
.events
|
||||
.push_back(tb_runtime::host::Ereignis::Taste("stale".into(), 0));
|
||||
a.execute(Command::Restart);
|
||||
tick(&mut a);
|
||||
assert!(a.session.host.events.is_empty());
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn named_run_of_current_target_uses_edited_sources() {
|
||||
let t = Temp::new();
|
||||
let mut a = t.app("PRINT \"disk\"\nEND\n");
|
||||
let id = a.project.members()[0];
|
||||
a.project
|
||||
.replace_text(
|
||||
id,
|
||||
0..a.project.document(id).unwrap().code().len(),
|
||||
"RUN \"MAIN.BAS\"\n",
|
||||
)
|
||||
.unwrap();
|
||||
a.execute(Command::Start);
|
||||
a.tick_execution(0);
|
||||
assert!(a.session.project_target);
|
||||
a.project
|
||||
.replace_text(
|
||||
id,
|
||||
0..a.project.document(id).unwrap().code().len(),
|
||||
"PRINT \"edited\"\nEND\n",
|
||||
)
|
||||
.unwrap();
|
||||
tick(&mut a);
|
||||
assert_eq!(output(&a), "edited\n");
|
||||
}
|
||||
#[test]
|
||||
fn explicit_end_and_system_end_visible_forms_but_natural_end_keeps_them_live() {
|
||||
let t = Temp::new();
|
||||
for ending in ["END", "SYSTEM", ""] {
|
||||
let path = t.0.join("form.frm");
|
||||
fs::write(
|
||||
&path,
|
||||
format!("VERSION 1.00\nBEGIN Form Form1\nEND\n{ending}\n"),
|
||||
)
|
||||
.unwrap();
|
||||
let mut a = App::new(&t.0, t.0.join("options"), (80, 25)).unwrap();
|
||||
a.load_initial_project(path).unwrap();
|
||||
a.execute(Command::Start);
|
||||
assert!(a.session.vm.as_ref().unwrap().forms.has_visible_forms());
|
||||
tick(&mut a);
|
||||
if ending.is_empty() {
|
||||
assert_eq!(a.execution, Execution::Waiting);
|
||||
key(&mut a, K::F(4), M::NONE);
|
||||
assert!(a.session.fullscreen);
|
||||
a.handle(Event::Resize(40, 10));
|
||||
key(&mut a, K::Pause, M::CONTROL);
|
||||
assert_eq!(a.execution, Execution::Paused);
|
||||
a.handle(Event::Resize(80, 25));
|
||||
key(&mut a, K::F(5), M::NONE);
|
||||
tick(&mut a);
|
||||
assert_eq!(a.execution, Execution::Waiting);
|
||||
assert!(a.session.vm.as_ref().unwrap().forms.has_visible_forms());
|
||||
} else {
|
||||
assert_eq!(a.execution, Execution::Ended);
|
||||
assert!(a.session.vm.is_none());
|
||||
}
|
||||
assert!(!a.quit);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn comment_only_source_change_also_requires_revision_choice() {
|
||||
let t = Temp::new();
|
||||
let mut a = t.app("STOP ' old\nPRINT 1\nEND\n");
|
||||
a.execute(Command::Start);
|
||||
tick(&mut a);
|
||||
let compiled = a.current_compilation().unwrap().to_tbc();
|
||||
let id = a.project.members()[0];
|
||||
a.project
|
||||
.replace_text(
|
||||
id,
|
||||
0..a.project.document(id).unwrap().code().len(),
|
||||
"STOP ' new\nPRINT 1\nEND\n",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(a.compile_current().unwrap().to_tbc(), compiled);
|
||||
a.execute(Command::Continue);
|
||||
assert!(matches!(
|
||||
a.dialog.as_ref().unwrap().kind,
|
||||
DialogKind::ResumeRevision
|
||||
));
|
||||
}
|
||||
Reference in New Issue
Block a user