mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 07:13:46 +00:00
Merge pull request #6471 from dotCooCoo/fix/plugin-no-call-after-failure
Plug-ins: no command call is made after a run's failed call
This commit is contained in:
@@ -121,8 +121,9 @@ pub const CALL_COMMAND_FAILED: i32 = -8;
|
||||
pub const CALL_LIMIT: i32 = -9;
|
||||
/// What `vc_call_result` returns: no call has a result yet.
|
||||
pub const CALL_NO_RESULT: i32 = -10;
|
||||
/// What `vc_call` returns: nothing can be called now (while the module is being loaded, or in a
|
||||
/// run that isn't a filter's run on a document). In a run, this fails it too.
|
||||
/// What `vc_call` returns: nothing can be called now (while the module is being loaded, in a run
|
||||
/// that isn't a filter's run on a document, or after a call in the run failed). In a run, this
|
||||
/// fails it too.
|
||||
pub const CALL_NO_CONTEXT: i32 = -11;
|
||||
|
||||
/// Most `vc_call` calls one run makes.
|
||||
@@ -429,9 +430,14 @@ impl Run {
|
||||
|
||||
/// `vc_call`: checks the call to the command at `id` with the arguments at `args` in `memory`
|
||||
/// and leaves it in [`Run::pending`] for the host to make, or → the code for why it can't be
|
||||
/// made, which fails the run. The size of the arguments is checked before they are read.
|
||||
/// made, which fails the run. The size of the arguments is checked before they are read. After
|
||||
/// the run's first failed call, every call returns [`CALL_NO_CONTEXT`] and none is made.
|
||||
fn call_request(&mut self, memory: &[u8], id: (usize, usize), args: (usize, usize)) -> std::result::Result<(), i32> {
|
||||
self.call_result = None;
|
||||
// No call is made after the run's first failed call.
|
||||
if self.call_failure.is_some() {
|
||||
return Err(CALL_NO_CONTEXT);
|
||||
}
|
||||
if self.allowed.is_none() {
|
||||
let why = "vc_call: no command can be called here (while the module loads, or in a run that can't make calls)";
|
||||
return Err(self.fail(CALL_NO_CONTEXT, Error::Abi(why.into())));
|
||||
|
||||
@@ -138,6 +138,25 @@ fn a_failed_command_fails_the_run_with_its_reason() {
|
||||
assert_eq!(out, Err(Error::Failed("vc_call `select.all`: nothing is selected".into())));
|
||||
}
|
||||
|
||||
/// After the run's first failed call, a plug-in that goes on calling gets [`CALL_NO_CONTEXT`] for
|
||||
/// each call and the host makes none of them; the run fails with the first call's reason.
|
||||
#[test]
|
||||
fn no_call_is_made_after_a_failed_one() {
|
||||
let rest = [select_all(), select_all(), select_all()].map(|c| expect(&c, CALL_NO_CONTEXT)).concat();
|
||||
let p = calling("test.call.after.failed", &format!("{}{rest}", expect(&select_all(), CALL_COMMAND_FAILED)));
|
||||
let (out, seen) = run_with(&p, |_| Err(CallFailure { code: CALL_COMMAND_FAILED, why: "nothing is selected".into() }));
|
||||
assert_eq!(out, Err(Error::Failed("vc_call `select.all`: nothing is selected".into())));
|
||||
assert_eq!(seen.len(), 1);
|
||||
// Also after a call the host refused without making it.
|
||||
let p = calling(
|
||||
"test.call.after.refused",
|
||||
&format!("{}{}", expect(&call("0x2010", "13", "0", "0"), CALL_NOT_ALLOWED), expect(&select_all(), CALL_NO_CONTEXT)),
|
||||
);
|
||||
let (out, seen) = run_with(&p, |_| Ok(Value::Null));
|
||||
assert!(out.unwrap_err().to_string().contains("vc_call `object.delete`: the manifest's `commandAllowlist` doesn't list it"));
|
||||
assert!(seen.is_empty());
|
||||
}
|
||||
|
||||
/// A result larger than [`MAX_CALL_DATA`] fails the run, and so do more than [`MAX_CALLS`] calls.
|
||||
#[test]
|
||||
fn results_and_calls_are_capped() {
|
||||
|
||||
+1
-1
@@ -407,7 +407,7 @@ arguments as a JSON object, the params the command takes from any request:
|
||||
`-3` when the arguments are not a JSON object, `-4` when `commandAllowlist` doesn't list the id, `-5` when no command
|
||||
has the id, `-6` when a plug-in may not call the command, `-7` when the command can't run now (nothing is selected),
|
||||
`-8` when the command ran and failed, `-9` when a limit below is passed, and `-11` when nothing can be called (from
|
||||
the module's start function, or in a run that isn't a filter's run on a document).
|
||||
the module's start function, in a run that isn't a filter's run on a document, or after a call in the run failed).
|
||||
|
||||
- Every code also fails the run, whatever the plug-in does next, and the error names the call and why it failed. The run's calls and its output are one undo step, named after the plug-in or its command. A run that fails,
|
||||
traps, runs out of budget or is canceled leaves every document, its selection and its history as they were.
|
||||
|
||||
Reference in New Issue
Block a user