feat(mosstank): add VTank-style automation PoC
This commit is contained in:
parent
f6fe0f2a4f
commit
4e6e9bc9d9
212 changed files with 49462 additions and 416 deletions
|
|
@ -8,6 +8,56 @@ namespace AcDream.Core.Tests.Plugins;
|
|||
|
||||
public sealed class PluginSessionTests
|
||||
{
|
||||
[Fact]
|
||||
public void ScopedHostPrefixesStorageWithAuthenticatedManifestId()
|
||||
{
|
||||
var storage = new MemoryStorage();
|
||||
using var alpha = new ScopedPluginHost(
|
||||
new StubHost(storage),
|
||||
"acdream.alpha",
|
||||
"Alpha");
|
||||
using var beta = new ScopedPluginHost(
|
||||
new StubHost(storage),
|
||||
"acdream.beta",
|
||||
"Beta");
|
||||
|
||||
alpha.Storage.WriteText("profile.json", "alpha");
|
||||
beta.Storage.WriteText("profile.json", "beta");
|
||||
alpha.Storage.WriteText("imports/route.nav", "nav");
|
||||
|
||||
Assert.Equal("alpha", storage.Text[Path.Combine(
|
||||
"acdream.alpha", "profile.json")]);
|
||||
Assert.Equal("beta", storage.Text[Path.Combine(
|
||||
"acdream.beta", "profile.json")]);
|
||||
Assert.Equal(["imports/route.nav"], alpha.Storage.List("imports"));
|
||||
Assert.Empty(beta.Storage.List("imports"));
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
alpha.Storage.WriteText("../escape.json", "bad"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScopedHostNamespacesAndUnregistersLootClassifierOnDispose()
|
||||
{
|
||||
var global = new PluginLootClassifierRegistry();
|
||||
var scope = new ScopedPluginHost(
|
||||
new StubHost(lootClassifiers: global),
|
||||
"acdream.looter",
|
||||
"Looter");
|
||||
|
||||
scope.LootClassifiers.Register(
|
||||
"main",
|
||||
"My loot rules",
|
||||
new KeepClassifier());
|
||||
|
||||
PluginLootClassifierInfo registered = Assert.Single(global.Available);
|
||||
Assert.Equal("acdream.looter/main", registered.Id);
|
||||
Assert.Equal("My loot rules", registered.DisplayName);
|
||||
|
||||
scope.Dispose();
|
||||
|
||||
Assert.Empty(global.Available);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AbsentAllowListLoadsEveryDiscoveredPlugin()
|
||||
{
|
||||
|
|
@ -282,6 +332,11 @@ public sealed class PluginSessionTests
|
|||
|
||||
private static string FixturePluginPath()
|
||||
{
|
||||
string fileName = "AcDream.Core.Tests.Fixtures.HelloPlugin.dll";
|
||||
string colocated = Path.Combine(AppContext.BaseDirectory, fileName);
|
||||
if (File.Exists(colocated))
|
||||
return colocated;
|
||||
|
||||
string configuration = new DirectoryInfo(AppContext.BaseDirectory)
|
||||
.Parent!.Name;
|
||||
string root = FindRepoRoot(AppContext.BaseDirectory);
|
||||
|
|
@ -292,7 +347,7 @@ public sealed class PluginSessionTests
|
|||
"bin",
|
||||
configuration,
|
||||
"net10.0",
|
||||
"AcDream.Core.Tests.Fixtures.HelloPlugin.dll");
|
||||
fileName);
|
||||
}
|
||||
|
||||
private static string FindRepoRoot(string start)
|
||||
|
|
@ -307,7 +362,9 @@ public sealed class PluginSessionTests
|
|||
?? throw new InvalidOperationException("Repository root not found.");
|
||||
}
|
||||
|
||||
private sealed class StubHost : IPluginHost
|
||||
private sealed class StubHost(
|
||||
IPluginStorage? storage = null,
|
||||
IPluginLootClassifierRegistry? lootClassifiers = null) : IPluginHost
|
||||
{
|
||||
public bool HasUi => false;
|
||||
public IPluginLogger Log { get; } = new StubLogger();
|
||||
|
|
@ -316,6 +373,34 @@ public sealed class PluginSessionTests
|
|||
public ISelectionService Selection { get; } = new SelectionState();
|
||||
public IUiRegistry Ui => NoOpUiRegistry.Instance;
|
||||
public IAutomationSurface Automation => NoOpAutomationSurface.Instance;
|
||||
public IPluginStorage Storage { get; } =
|
||||
storage ?? NoOpPluginStorage.Instance;
|
||||
public IPluginLootClassifierRegistry LootClassifiers { get; } =
|
||||
lootClassifiers ?? NoOpPluginLootClassifierRegistry.Instance;
|
||||
}
|
||||
|
||||
private sealed class KeepClassifier : IPluginLootClassifier
|
||||
{
|
||||
public PluginLootClassification Classify(
|
||||
in PluginLootClassificationContext context) => new(
|
||||
true,
|
||||
PluginLootAction.Keep);
|
||||
}
|
||||
|
||||
private sealed class MemoryStorage : IPluginStorage
|
||||
{
|
||||
public Dictionary<string, string> Text { get; } =
|
||||
new(StringComparer.Ordinal);
|
||||
public bool IsAvailable => true;
|
||||
public string? ReadText(string key) =>
|
||||
Text.TryGetValue(key, out string? value) ? value : null;
|
||||
public IReadOnlyList<string> List(string prefix) => Text.Keys
|
||||
.Where(key => key.StartsWith(prefix + Path.DirectorySeparatorChar,
|
||||
StringComparison.Ordinal))
|
||||
.OrderBy(static key => key, StringComparer.Ordinal)
|
||||
.ToArray();
|
||||
public void WriteText(string key, string content) => Text[key] = content;
|
||||
public bool Delete(string key) => Text.Remove(key);
|
||||
}
|
||||
|
||||
private sealed class StubLogger : IPluginLogger
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue