d2cc071517
ScriptContext.CancellationToken is backed by an AsyncLocal that ScriptEvaluator.RunAsync scopes around the compiled delegate, so it is exactly the token ScriptRunGuard cancels on timeout. A polling script can now end its own abandoned run and free the slot. AsyncLocal rather than a field because the scripted-alarm engine reuses one context per alarm: an orphan keeps seeing its own cancelled token. The scoping entry point is internal (IVT to Core.Scripting) so a script cannot replace its own token. Editor parity: ScriptAnalysisService dot-completion now walks the receiver's base chain (instance members only, stopping before System.Object). Before this, a member declared only on ScriptContext compiled and published but never completed. DiagnoseTests pins the member as allow-listed; CompletionTests pins the completion. Refs #731 #734 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
31 lines
1.2 KiB
C#
31 lines
1.2 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.AdminUI.ScriptAnalysis;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.ScriptAnalysis;
|
|
|
|
public sealed class CompletionTests
|
|
{
|
|
private static readonly ScriptAnalysisService Svc = new();
|
|
private static async Task<IReadOnlyList<CompletionItem>> Complete(string code, int line, int col)
|
|
=> (await Svc.CompleteAsync(new CompletionsRequest(code, line, col))).Items;
|
|
|
|
[Fact] public async Task Dot_after_ctx_offers_context_members()
|
|
{
|
|
// caret immediately after "ctx." — column is 1-based; "ctx." is 4 chars so col 5 is just past the dot.
|
|
var labels = (await Complete("ctx.", 1, 5)).Select(i => i.Label).ToList();
|
|
labels.ShouldContain("GetTag");
|
|
labels.ShouldContain("SetVirtualTag");
|
|
labels.ShouldContain("Now");
|
|
labels.ShouldContain("Logger");
|
|
labels.ShouldContain("CancellationToken");
|
|
}
|
|
|
|
[Fact] public async Task Scope_completion_includes_the_ctx_local()
|
|
{
|
|
// a partial identifier on its own line; scope completion should surface the `ctx` local.
|
|
var labels = (await Complete("var x = c", 1, 10)).Select(i => i.Label).ToList();
|
|
labels.ShouldContain("ctx");
|
|
}
|
|
}
|