Initial commit

This commit is contained in:
2026-07-03 16:37:12 +07:00
commit 63b8c1ea8b
1931 changed files with 640587 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using RobotNet10.Script;
using RobotNet10.ScriptEngine.HubContexts;
using RobotNet10.ScriptEngine.Models;
using RobotNet10.ScriptEngine.Shared;
namespace RobotNet10.ScriptEngine.Test.Helpers;
public static class TestHelpers
{
public static Mock<IScriptEngineResource> CreateMockScriptResource()
{
var mock = new Mock<IScriptEngineResource>();
mock.Setup(x => x.GetTaskGlobals()).Returns(new Dictionary<string, object?>());
mock.Setup(x => x.GetMissionGlobals(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).Returns(new Dictionary<string, object?>());
mock.Setup(x => x.AppGlobalType).Returns(typeof(object));
mock.Setup(x => x.UsingNamespaces).Returns(System.Collections.Immutable.ImmutableArray<string>.Empty);
mock.Setup(x => x.Modules).Returns(System.Collections.Immutable.ImmutableArray<string>.Empty);
return mock;
}
public static Mock<ILogger<ScriptEngineGlobals>> CreateMockLogger()
{
return new Mock<ILogger<ScriptEngineGlobals>>();
}
public static Mock<IServiceScopeFactory> CreateMockScopeFactory(IServiceProvider serviceProvider)
{
var mockScope = new Mock<IServiceScope>();
mockScope.Setup(x => x.ServiceProvider).Returns(serviceProvider);
var mockScopeFactory = new Mock<IServiceScopeFactory>();
mockScopeFactory.Setup(x => x.CreateScope()).Returns(mockScope.Object);
return mockScopeFactory;
}
public static Mock<ConsoleHubContext> CreateMockConsoleHubContext()
{
return new Mock<ConsoleHubContext>(Mock.Of<Microsoft.AspNetCore.SignalR.IHubContext<RobotNet10.ScriptEngine.Hubs.ConsoleHub>>());
}
public static IConfiguration CreateMockConfiguration()
{
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>())
.Build();
return configuration;
}
public static Mock<Microsoft.AspNetCore.SignalR.IHubContext<RobotNet10.ScriptEngine.Hubs.ScriptManagerHub>> CreateMockHubContext()
{
return new Mock<Microsoft.AspNetCore.SignalR.IHubContext<RobotNet10.ScriptEngine.Hubs.ScriptManagerHub>>();
}
public static Mock<RobotNet10.Script.ILogger> CreateMockScriptLogger()
{
return new Mock<RobotNet10.Script.ILogger>();
}
public static ScriptGlobals CreateTestScriptGlobals(RobotNet10.Script.ILogger logger, IServiceScopeFactory scopeFactory)
{
var scriptEngineGlobals = new ScriptEngineGlobals(logger, scopeFactory);
var robotNetDict = new Dictionary<string, object?>
{
["get_Logger"] = new Func<RobotNet10.Script.ILogger>(() => logger)
};
var appApisDict = new Dictionary<string, object?>();
var globalVariablesDict = new Dictionary<string, object?>();
var missionParametersDict = new Dictionary<string, object?>();
return new ScriptGlobals(robotNetDict, appApisDict, globalVariablesDict, missionParametersDict);
}
}

View File

@@ -0,0 +1,177 @@
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using RobotNet10.Script;
using RobotNet10.ScriptEngine;
using RobotNet10.ScriptEngine.Data;
using RobotNet10.ScriptEngine.HubContexts;
using RobotNet10.ScriptEngine.Models;
using RobotNet10.ScriptEngine.Shared;
using RobotNet10.ScriptEngine.Test.Helpers;
using RobotNet10.Shared;
namespace RobotNet10.ScriptEngine.Test;
[TestFixture]
public class MissionManagerTests
{
private MissionManager _missionManager = null!;
private VariableManager _variableManager = null!;
private Mock<IScriptEngineResource> _mockResource = null!;
private Mock<IServiceScopeFactory> _mockScopeFactory = null!;
private IServiceProvider _serviceProvider = null!;
[SetUp]
public void SetUp()
{
_variableManager = new VariableManager();
_mockResource = TestHelpers.CreateMockScriptResource();
var mockLogger = TestHelpers.CreateMockLogger();
var mockConsoleHubContext = TestHelpers.CreateMockConsoleHubContext();
var configuration = TestHelpers.CreateMockConfiguration();
// Setup service provider with DbContext
var services = new ServiceCollection();
services.AddDbContext<ScriptEngineDbContext>(options =>
options.UseInMemoryDatabase($"TestDb_{Guid.NewGuid()}"));
_serviceProvider = services.BuildServiceProvider();
_mockScopeFactory = TestHelpers.CreateMockScopeFactory(_serviceProvider);
_missionManager = new MissionManager(
_mockScopeFactory.Object,
_variableManager,
_mockResource.Object,
mockLogger.Object,
mockConsoleHubContext.Object,
configuration);
}
[TearDown]
public void TearDown()
{
_missionManager?.Dispose();
(_serviceProvider as IDisposable)?.Dispose();
}
[Test]
public void Load_WithValidMissions_ShouldLoadSuccessfully()
{
// Arrange
var script = CSharpScript.Create<IAsyncEnumerable<MissionStatus>>(
"yield return new MissionStatus(100, \"Success\");",
Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var missionModels = new[]
{
new ScriptMissionModel("Mission1", new List<ScriptMissionParameterModel>(), "code", 100, false, false, runner),
new ScriptMissionModel("Mission2", new List<ScriptMissionParameterModel>(), "code", 200, false, false, runner)
};
// Act
var result = _missionManager.Load(missionModels);
// Assert
Assert.That(result.IsSuccess, Is.True);
Assert.That(_missionManager.MissionModels.Count, Is.EqualTo(2));
Assert.That(_missionManager.MissionModels.ContainsKey("Mission1"), Is.True);
Assert.That(_missionManager.MissionModels.ContainsKey("Mission2"), Is.True);
}
[Test]
public void Load_WithNullMissions_ShouldThrowArgumentNullException()
{
// Act & Assert
Assert.Throws<ArgumentNullException>(() => _missionManager.Load(null!));
}
[Test]
public void CreateMission_WithValidMission_ShouldReturnMissionId()
{
// Arrange
var script = CSharpScript.Create<IAsyncEnumerable<MissionStatus>>(
"yield return new MissionStatus(100, \"Success\");",
Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var missionModels = new[]
{
new ScriptMissionModel("Mission1", new List<ScriptMissionParameterModel>(), "code", 100, false, false, runner)
};
_missionManager.Load(missionModels);
_missionManager.Start();
// Act
var result = _missionManager.CreateMission("Mission1", new Dictionary<string, object?>());
// Assert
Assert.That(result.IsSuccess, Is.True);
Assert.That(result.Data, Is.Not.EqualTo(Guid.Empty));
}
[Test]
public void CreateMission_WithNonExistentMission_ShouldFail()
{
// Arrange
_missionManager.Start();
// Act
var result = _missionManager.CreateMission("NonExistent", new Dictionary<string, object?>());
// Assert
Assert.That(result.IsSuccess, Is.False);
}
[Test]
public void GetScriptMissions_ShouldReturnAllMissionModels()
{
// Arrange
var script = CSharpScript.Create<IAsyncEnumerable<MissionStatus>>(
"yield return new MissionStatus(100, \"Success\");",
Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var missionModels = new[]
{
new ScriptMissionModel("Mission1", new List<ScriptMissionParameterModel>(), "code", 100, false, false, runner),
new ScriptMissionModel("Mission2", new List<ScriptMissionParameterModel>(), "code", 200, false, false, runner)
};
_missionManager.Load(missionModels);
// Act
var result = _missionManager.GetScriptMissions();
// Assert
Assert.That(result.Length, Is.EqualTo(2));
Assert.That(result.Any(m => m.Name == "Mission1"), Is.True);
Assert.That(result.Any(m => m.Name == "Mission2"), Is.True);
}
[Test]
public void Reset_ShouldClearAllMissions()
{
// Arrange
var script = CSharpScript.Create<IAsyncEnumerable<MissionStatus>>(
"yield return new MissionStatus(100, \"Success\");",
Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var missionModels = new[]
{
new ScriptMissionModel("Mission1", new List<ScriptMissionParameterModel>(), "code", 100, false, false, runner)
};
_missionManager.Load(missionModels);
Assert.That(_missionManager.MissionModels.Count, Is.EqualTo(1));
// Act
var result = _missionManager.Reset();
// Assert
Assert.That(result.IsSuccess, Is.True);
Assert.That(_missionManager.MissionModels.Count, Is.EqualTo(0));
}
}

View File

@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="NUnit" Version="4.5.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.11.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Commons\RobotNet10.ScriptEngine\RobotNet10.ScriptEngine.csproj" />
<ProjectReference Include="..\..\Commons\RobotNet10.Script\RobotNet10.Script.csproj" />
<ProjectReference Include="..\..\Shared\RobotNet10.ScriptEngine.Shared\RobotNet10.ScriptEngine.Shared.csproj" />
<ProjectReference Include="..\..\Shared\RobotNet10.Shared\RobotNet10.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="NUnit.Framework" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,175 @@
using Moq;
using RobotNet10.ScriptEngine.Helpers;
using RobotNet10.ScriptEngine.Models;
using RobotNet10.ScriptEngine.Shared;
using RobotNet10.ScriptEngine.Test.Helpers;
namespace RobotNet10.ScriptEngine.Test;
[TestFixture]
public class ScriptBuilderTests
{
private ScriptBuilder _scriptBuilder = null!;
private Mock<IScriptEngineResource> _mockResource = null!;
[SetUp]
public void SetUp()
{
_mockResource = TestHelpers.CreateMockScriptResource();
_scriptBuilder = new ScriptBuilder(_mockResource.Object, "dlls");
}
[Test]
public void Build_WithValidScript_ShouldExtractVariables()
{
// Arrange
var script = @"
using RobotNet10.Script;
public class DummyClass
{
[Variable]
public int TestInt = 42;
[Variable]
public string TestString = ""Hello"";
}
";
// Act
_scriptBuilder.Build(script, out var variables, out var tasks, out var missions);
// Assert
Assert.That(variables, Is.Not.Null);
Assert.That(variables.Count(), Is.EqualTo(2));
Assert.That(variables.Any(v => v.Name == "TestInt"), Is.True);
Assert.That(variables.Any(v => v.Name == "TestString"), Is.True);
}
[Test]
public void Build_WithValidScript_ShouldExtractTasks()
{
// Arrange
var script = @"
using RobotNet10.Script;
using System.Threading.Tasks;
public class DummyClass
{
[Task(1000, true)]
public async Task TestTask()
{
await Task.Delay(100);
}
}
";
// Act
_scriptBuilder.Build(script, out var variables, out var tasks, out var missions);
// Assert
Assert.That(tasks, Is.Not.Null);
Assert.That(tasks.Count(), Is.EqualTo(1));
Assert.That(tasks.First().Name, Is.EqualTo("TestTask"));
Assert.That(tasks.First().Interval, Is.EqualTo(1000));
Assert.That(tasks.First().AutoStart, Is.True);
}
[Test]
public void Build_WithValidScript_ShouldExtractMissions()
{
// Arrange
var script = @"
using RobotNet10.Script;
using System.Collections.Generic;
using System.Threading;
public class DummyClass
{
[Mission]
public async IAsyncEnumerable<MissionStatus> TestMission(CancellationToken ct)
{
yield return MissionStatus.Running;
yield return MissionStatus.Success;
}
}
";
// Act
_scriptBuilder.Build(script, out var variables, out var tasks, out var missions);
// Assert
Assert.That(missions, Is.Not.Null);
Assert.That(missions.Count(), Is.EqualTo(1));
Assert.That(missions.First().Name, Is.EqualTo("TestMission"));
}
[Test]
public void Build_WithInvalidScript_ShouldThrowScriptCompilationException()
{
// Arrange
var script = @"
public class DummyClass
{
invalid syntax here
}
";
// Act & Assert
Assert.Throws<ScriptCompilationException>(() =>
_scriptBuilder.Build(script, out _, out _, out _));
}
[Test]
public void Build_WithEmptyScript_ShouldReturnEmptyCollections()
{
// Arrange
var script = @"
public class DummyClass
{
}
";
// Act
_scriptBuilder.Build(script, out var variables, out var tasks, out var missions);
// Assert
Assert.That(variables.Count(), Is.EqualTo(0));
Assert.That(tasks.Count(), Is.EqualTo(0));
Assert.That(missions.Count(), Is.EqualTo(0));
}
[Test]
public void Build_WithMultipleTasks_ShouldExtractAll()
{
// Arrange
var script = @"
using RobotNet10.Script;
using System.Threading.Tasks;
public class DummyClass
{
[Task(1000, true)]
public async Task Task1()
{
await Task.Delay(100);
}
[Task(2000, false)]
public async Task Task2()
{
await Task.Delay(100);
}
}
";
// Act
_scriptBuilder.Build(script, out var variables, out var tasks, out var missions);
// Assert
Assert.That(tasks.Count(), Is.EqualTo(2));
Assert.That(tasks.Any(t => t.Name == "Task1"), Is.True);
Assert.That(tasks.Any(t => t.Name == "Task2"), Is.True);
}
}

View File

@@ -0,0 +1,223 @@
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using RobotNet10.Script;
using RobotNet10.ScriptEngine;
using RobotNet10.ScriptEngine.HubContexts;
using RobotNet10.ScriptEngine.Models;
using RobotNet10.ScriptEngine.Shared;
using RobotNet10.ScriptEngine.Test.Helpers;
using RobotNet10.Shared;
namespace RobotNet10.ScriptEngine.Test;
[TestFixture]
public class ScriptEngineGlobalsTests
{
private Mock<ILogger> _mockLogger = null!;
private Mock<IServiceScopeFactory> _mockScopeFactory = null!;
private Mock<IServiceProvider> _mockServiceProvider = null!;
private Mock<IServiceScope> _mockScope = null!;
private ScriptEngineGlobals _scriptEngineGlobals = null!;
private VariableManager _variableManager = null!;
private TaskManager _taskManager = null!;
private MissionManager _missionManager = null!;
[SetUp]
public void SetUp()
{
_mockLogger = TestHelpers.CreateMockScriptLogger();
_mockServiceProvider = new Mock<IServiceProvider>();
_mockScope = new Mock<IServiceScope>();
_mockScope.Setup(x => x.ServiceProvider).Returns(_mockServiceProvider.Object);
_mockScopeFactory = new Mock<IServiceScopeFactory>();
_mockScopeFactory.Setup(x => x.CreateScope()).Returns(_mockScope.Object);
var mockScriptResource = TestHelpers.CreateMockScriptResource();
var mockConsoleHubContext = TestHelpers.CreateMockConsoleHubContext();
var mockLoggerGlobals = TestHelpers.CreateMockLogger();
var configuration = TestHelpers.CreateMockConfiguration();
_variableManager = new VariableManager();
_taskManager = new TaskManager(
_variableManager,
mockScriptResource.Object,
mockLoggerGlobals.Object,
_mockScopeFactory.Object,
mockConsoleHubContext.Object,
configuration);
_missionManager = new MissionManager(
_mockScopeFactory.Object,
_variableManager,
mockScriptResource.Object,
mockLoggerGlobals.Object,
mockConsoleHubContext.Object,
configuration);
_mockServiceProvider.Setup(x => x.GetRequiredService<MissionManager>()).Returns(_missionManager);
_mockServiceProvider.Setup(x => x.GetRequiredService<TaskManager>()).Returns(_taskManager);
_scriptEngineGlobals = new ScriptEngineGlobals(_mockLogger.Object, _mockScopeFactory.Object);
}
[Test]
public void Logger_ShouldReturnProvidedLogger()
{
// Act
var logger = _scriptEngineGlobals.Logger;
// Assert
Assert.That(logger, Is.EqualTo(_mockLogger.Object));
}
[Test]
public void CreateMission_WithValidMission_ShouldReturnMissionId()
{
// Arrange
var script = CSharpScript.Create<IAsyncEnumerable<MissionStatus>>(
"yield return new MissionStatus(100, \"Success\");",
ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var missionModel = new ScriptMissionModel(
"TestMission",
new List<ScriptMissionParameterModel>(),
"code",
100,
false,
false,
runner);
_missionManager.Load([missionModel]);
_missionManager.Start();
// Act
var missionId = _scriptEngineGlobals.CreateMission("TestMission");
// Assert
Assert.That(missionId, Is.Not.EqualTo(Guid.Empty));
}
[Test]
public void CreateMission_WithNonExistentMission_ShouldThrowInvalidOperationException()
{
// Act & Assert
Assert.Throws<InvalidOperationException>(() =>
_scriptEngineGlobals.CreateMission("NonExistentMission"));
}
[Test]
public void CancelMission_WithExistingMission_ShouldReturnTrue()
{
// Arrange
var script = CSharpScript.Create<IAsyncEnumerable<MissionStatus>>(
"yield return new MissionStatus(100, \"Success\");",
ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var missionModel = new ScriptMissionModel(
"TestMission",
new List<ScriptMissionParameterModel>(),
"code",
100,
false,
false,
runner);
_missionManager.Load([missionModel]);
_missionManager.Start();
var missionId = _missionManager.CreateMission("TestMission", Array.Empty<object>()).Data;
// Act
var result = _scriptEngineGlobals.CancelMission(missionId, "Test reason");
// Assert
Assert.That(result, Is.True);
}
[Test]
public void CancelMission_WithNonExistentMission_ShouldReturnFalse()
{
// Act
var result = _scriptEngineGlobals.CancelMission(Guid.NewGuid(), "Test reason");
// Assert
Assert.That(result, Is.False);
}
[Test]
public void EnableTask_WithExistingTask_ShouldSucceed()
{
// Arrange
var script = CSharpScript.Create(
"await Task.Delay(10);",
ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var taskModel = new ScriptTaskModel(
"TestTask",
1000,
false,
"code",
runner);
_taskManager.Load([taskModel]);
_taskManager.Start();
// Act & Assert
Assert.DoesNotThrow(() => _scriptEngineGlobals.EnableTask("TestTask"));
}
[Test]
public void EnableTask_WithNonExistentTask_ShouldThrowInvalidOperationException()
{
// Act & Assert
Assert.Throws<InvalidOperationException>(() =>
_scriptEngineGlobals.EnableTask("NonExistentTask"));
}
[Test]
public void DisableTask_WithExistingTask_ShouldSucceed()
{
// Arrange
var script = CSharpScript.Create(
"await Task.Delay(10);",
ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var taskModel = new ScriptTaskModel(
"TestTask",
1000,
false,
"code",
runner);
_taskManager.Load([taskModel]);
_taskManager.Start();
_taskManager.EnableTask("TestTask");
// Act & Assert
Assert.DoesNotThrow(() => _scriptEngineGlobals.DisableTask("TestTask"));
}
[Test]
public void DisableTask_WithNonExistentTask_ShouldThrowInvalidOperationException()
{
// Act & Assert
Assert.Throws<InvalidOperationException>(() =>
_scriptEngineGlobals.DisableTask("NonExistentTask"));
}
[TearDown]
public void TearDown()
{
_taskManager?.Dispose();
_missionManager?.Dispose();
}
}

View File

@@ -0,0 +1,230 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using RobotNet10.ScriptEngine;
using RobotNet10.ScriptEngine.Enums;
using RobotNet10.ScriptEngine.Helpers;
using RobotNet10.ScriptEngine.Hubs;
using RobotNet10.ScriptEngine.Models;
using RobotNet10.ScriptEngine.Shared;
using RobotNet10.ScriptEngine.Test.Helpers;
using RobotNet10.Shared;
namespace RobotNet10.ScriptEngine.Test;
[TestFixture]
public class ScriptEngineTests
{
private ScriptEngine _scriptEngine = null!;
private Mock<IScriptEngineResource> _mockResource = null!;
private FileManager _fileManager = null!;
private VariableManager _variableManager = null!;
private TaskManager _taskManager = null!;
private MissionManager _missionManager = null!;
private Mock<ILogger<ScriptEngine>> _mockLogger = null!;
private Mock<IConfiguration> _mockConfiguration = null!;
private Mock<IHubContext<ScriptManagerHub>> _mockHubContext = null!;
private string _testScriptPath = null!;
[SetUp]
public void SetUp()
{
_testScriptPath = Path.Combine(Path.GetTempPath(), "ScriptEngineTest", Guid.NewGuid().ToString());
Directory.CreateDirectory(_testScriptPath);
_mockResource = TestHelpers.CreateMockScriptResource();
_mockLogger = new Mock<ILogger<ScriptEngine>>();
_mockConfiguration = new Mock<IConfiguration>();
_mockHubContext = TestHelpers.CreateMockHubContext();
var mockConsoleHubContext = TestHelpers.CreateMockConsoleHubContext();
var mockLoggerGlobals = TestHelpers.CreateMockLogger();
var configuration = TestHelpers.CreateMockConfiguration();
var mockScopeFactory = Mock.Of<IServiceScopeFactory>();
_variableManager = new VariableManager();
_fileManager = new FileManager();
_fileManager.RootPath = _testScriptPath;
_taskManager = new TaskManager(
_variableManager,
_mockResource.Object,
mockLoggerGlobals.Object,
mockScopeFactory,
mockConsoleHubContext.Object,
configuration);
_missionManager = new MissionManager(
mockScopeFactory,
_variableManager,
_mockResource.Object,
mockLoggerGlobals.Object,
mockConsoleHubContext.Object,
configuration);
_scriptEngine = new ScriptEngine(
_mockResource.Object,
_mockConfiguration.Object,
_fileManager,
_variableManager,
_taskManager,
_missionManager,
_mockLogger.Object,
_mockHubContext.Object,
mockConsoleHubContext.Object);
}
[TearDown]
public void TearDown()
{
_scriptEngine?.Dispose();
_taskManager?.Dispose();
_missionManager?.Dispose();
if (Directory.Exists(_testScriptPath))
{
Directory.Delete(_testScriptPath, true);
}
}
[Test]
public void Constructor_ShouldInitializeToIdleState()
{
// Assert
Assert.That(_scriptEngine.State, Is.EqualTo(ScriptEngineState.Idle));
}
[Test]
public void Build_WithValidScript_ShouldTransitionToReady()
{
// Arrange
var scriptFile = Path.Combine(_testScriptPath, "test.cs");
File.WriteAllText(scriptFile, @"
using RobotNet10.Script;
public class DummyClass
{
[Variable]
public int TestVar = 42;
}
");
// Act
var result = _scriptEngine.Build();
// Assert
Assert.That(result.IsSuccess, Is.True);
// Wait a bit for async build to complete
Thread.Sleep(500);
Assert.That(_scriptEngine.State, Is.EqualTo(ScriptEngineState.Ready).Or.EqualTo(ScriptEngineState.Building));
}
[Test]
public void Build_WithInvalidScript_ShouldTransitionToBuildError()
{
// Arrange
var scriptFile = Path.Combine(_testScriptPath, "test.cs");
File.WriteAllText(scriptFile, "invalid syntax here");
// Act
var result = _scriptEngine.Build();
// Assert
Assert.That(result.IsSuccess, Is.True); // Build initiation succeeds
// Wait a bit for async build to complete
Thread.Sleep(500);
Assert.That(_scriptEngine.State, Is.EqualTo(ScriptEngineState.BuildError).Or.EqualTo(ScriptEngineState.Building));
}
[Test]
public void Build_WhenNotIdle_ShouldFail()
{
// Arrange
var scriptFile = Path.Combine(_testScriptPath, "test.cs");
File.WriteAllText(scriptFile, "public class DummyClass { }");
_scriptEngine.Build();
Thread.Sleep(500); // Wait for build to complete
_scriptEngine.Start();
Thread.Sleep(500); // Wait for start to complete
// Act
var result = _scriptEngine.Build();
// Assert
Assert.That(result.IsSuccess, Is.False);
}
[Test]
public void Start_WhenReady_ShouldTransitionToRunning()
{
// Arrange
var scriptFile = Path.Combine(_testScriptPath, "test.cs");
File.WriteAllText(scriptFile, "public class DummyClass { }");
_scriptEngine.Build();
Thread.Sleep(1000); // Wait for build to complete
// Act
var result = _scriptEngine.Start();
// Assert
Assert.That(result.IsSuccess, Is.True);
Thread.Sleep(500);
Assert.That(_scriptEngine.State, Is.EqualTo(ScriptEngineState.Running).Or.EqualTo(ScriptEngineState.Starting));
}
[Test]
public void Start_WhenNotReady_ShouldFail()
{
// Act
var result = _scriptEngine.Start();
// Assert
Assert.That(result.IsSuccess, Is.False);
}
[Test]
public void Stop_WhenRunning_ShouldTransitionToReady()
{
// Arrange
var scriptFile = Path.Combine(_testScriptPath, "test.cs");
File.WriteAllText(scriptFile, "public class DummyClass { }");
_scriptEngine.Build();
Thread.Sleep(1000);
_scriptEngine.Start();
Thread.Sleep(1000);
// Act
var result = _scriptEngine.Stop();
// Assert
Assert.That(result.IsSuccess, Is.True);
Thread.Sleep(2000); // Wait for stop to complete
Assert.That(_scriptEngine.State, Is.EqualTo(ScriptEngineState.Ready).Or.EqualTo(ScriptEngineState.Stopping));
}
[Test]
public void Reset_ShouldTransitionToIdle()
{
// Arrange
var scriptFile = Path.Combine(_testScriptPath, "test.cs");
File.WriteAllText(scriptFile, "public class DummyClass { }");
_scriptEngine.Build();
Thread.Sleep(1000);
// Act
var result = _scriptEngine.Reset();
// Assert
Assert.That(result.IsSuccess, Is.True);
Thread.Sleep(500);
Assert.That(_scriptEngine.State, Is.EqualTo(ScriptEngineState.Idle).Or.EqualTo(ScriptEngineState.Resetting));
}
[Test]
public void Dispose_ShouldCleanupResources()
{
// Act & Assert
Assert.DoesNotThrow(() => _scriptEngine.Dispose());
}
}

View File

@@ -0,0 +1,210 @@
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using RobotNet10.ScriptEngine;
using RobotNet10.ScriptEngine.HubContexts;
using RobotNet10.ScriptEngine.Models;
using RobotNet10.ScriptEngine.Shared;
using RobotNet10.ScriptEngine.Test.Helpers;
using RobotNet10.Shared;
namespace RobotNet10.ScriptEngine.Test;
[TestFixture]
public class TaskManagerTests
{
private TaskManager _taskManager = null!;
private VariableManager _variableManager = null!;
private Mock<IScriptEngineResource> _mockResource = null!;
[SetUp]
public void SetUp()
{
_variableManager = new VariableManager();
_mockResource = TestHelpers.CreateMockScriptResource();
var mockLogger = TestHelpers.CreateMockLogger();
var mockScopeFactory = Mock.Of<IServiceScopeFactory>();
var mockConsoleHubContext = TestHelpers.CreateMockConsoleHubContext();
var configuration = TestHelpers.CreateMockConfiguration();
_taskManager = new TaskManager(
_variableManager,
_mockResource.Object,
mockLogger.Object,
mockScopeFactory,
mockConsoleHubContext.Object,
configuration);
}
[TearDown]
public void TearDown()
{
_taskManager?.Dispose();
}
[Test]
public void Load_WithValidTasks_ShouldLoadSuccessfully()
{
// Arrange
var script = CSharpScript.Create(
"await Task.Delay(10);",
Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var taskModels = new[]
{
new ScriptTaskModel("Task1", 1000, false, "code", runner),
new ScriptTaskModel("Task2", 2000, true, "code", runner)
};
// Act
var result = _taskManager.Load(taskModels);
// Assert
Assert.That(result.IsSuccess, Is.True);
Assert.That(_taskManager.Tasks.Count, Is.EqualTo(2));
Assert.That(_taskManager.Tasks.ContainsKey("Task1"), Is.True);
Assert.That(_taskManager.Tasks.ContainsKey("Task2"), Is.True);
}
[Test]
public void Load_WithNullTasks_ShouldThrowArgumentNullException()
{
// Act & Assert
Assert.Throws<ArgumentNullException>(() => _taskManager.Load(null!));
}
[Test]
public void Start_ShouldTransitionToRunning()
{
// Arrange
var script = CSharpScript.Create(
"await Task.Delay(10);",
Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var taskModels = new[] { new ScriptTaskModel("Task1", 1000, false, "code", runner) };
_taskManager.Load(taskModels);
// Act
var result = _taskManager.Start();
// Assert
Assert.That(result.IsSuccess, Is.True);
Thread.Sleep(500);
Assert.That(_taskManager.State, Is.EqualTo(TaskManagerState.Running));
}
[Test]
public void Stop_ShouldTransitionToIdle()
{
// Arrange
var script = CSharpScript.Create(
"await Task.Delay(10);",
Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var taskModels = new[] { new ScriptTaskModel("Task1", 1000, false, "code", runner) };
_taskManager.Load(taskModels);
_taskManager.Start();
Thread.Sleep(500);
// Act
var result = _taskManager.Stop();
// Assert
Assert.That(result.IsSuccess, Is.True);
Thread.Sleep(2000);
Assert.That(_taskManager.State, Is.EqualTo(TaskManagerState.Idle));
}
[Test]
public void EnableTask_WithExistingTask_ShouldSucceed()
{
// Arrange
var script = CSharpScript.Create(
"await Task.Delay(10);",
Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var taskModels = new[] { new ScriptTaskModel("Task1", 1000, false, "code", runner) };
_taskManager.Load(taskModels);
_taskManager.Start();
// Act
var result = _taskManager.EnableTask("Task1");
// Assert
Assert.That(result.IsSuccess, Is.True);
}
[Test]
public void DisableTask_WithExistingTask_ShouldSucceed()
{
// Arrange
var script = CSharpScript.Create(
"await Task.Delay(10);",
Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var taskModels = new[] { new ScriptTaskModel("Task1", 1000, false, "code", runner) };
_taskManager.Load(taskModels);
_taskManager.Start();
_taskManager.EnableTask("Task1");
// Act
var result = _taskManager.DisableTask("Task1");
// Assert
Assert.That(result.IsSuccess, Is.True);
}
[Test]
public void GetScriptTasks_ShouldReturnAllTasks()
{
// Arrange
var script = CSharpScript.Create(
"await Task.Delay(10);",
Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var taskModels = new[]
{
new ScriptTaskModel("Task1", 1000, false, "code", runner),
new ScriptTaskModel("Task2", 2000, false, "code", runner)
};
_taskManager.Load(taskModels);
// Act
var result = _taskManager.GetScriptTasks();
// Assert
Assert.That(result.Length, Is.EqualTo(2));
Assert.That(result.Any(t => t.Name == "Task1"), Is.True);
Assert.That(result.Any(t => t.Name == "Task2"), Is.True);
}
[Test]
public void Reset_ShouldClearAllTasks()
{
// Arrange
var script = CSharpScript.Create(
"await Task.Delay(10);",
Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default,
typeof(ScriptGlobals));
var runner = script.CreateDelegate();
var taskModels = new[] { new ScriptTaskModel("Task1", 1000, false, "code", runner) };
_taskManager.Load(taskModels);
Assert.That(_taskManager.Tasks.Count, Is.EqualTo(1));
// Act
var result = _taskManager.Reset();
// Assert
Assert.That(result.IsSuccess, Is.True);
Assert.That(_taskManager.Tasks.Count, Is.EqualTo(0));
}
}

View File

@@ -0,0 +1,180 @@
using RobotNet10.ScriptEngine;
using RobotNet10.ScriptEngine.Models;
using RobotNet10.ScriptEngine.Shared;
namespace RobotNet10.ScriptEngine.Test;
[TestFixture]
public class VariableManagerTests
{
private VariableManager _variableManager = null!;
[SetUp]
public void SetUp()
{
_variableManager = new VariableManager();
}
[Test]
public void Load_WithValidVariables_ShouldLoadSuccessfully()
{
// Arrange
var variables = new[]
{
new ScriptVariableModel("TestInt", typeof(int), 42, true, true),
new ScriptVariableModel("TestString", typeof(string), "Hello", true, false)
};
// Act
_variableManager.Load(variables);
// Assert
Assert.That(_variableManager.HasVariable("TestInt"), Is.True);
Assert.That(_variableManager.HasVariable("TestString"), Is.True);
Assert.That(_variableManager.GetVariable<int>("TestInt"), Is.EqualTo(42));
Assert.That(_variableManager.GetVariable<string>("TestString"), Is.EqualTo("Hello"));
}
[Test]
public void Load_WithNullVariables_ShouldThrowArgumentNullException()
{
// Act & Assert
Assert.Throws<ArgumentNullException>(() => _variableManager.Load(null!));
}
[Test]
public void GetVariable_WithExistingVariable_ShouldReturnValue()
{
// Arrange
var variables = new[]
{
new ScriptVariableModel("TestInt", typeof(int), 100, true, true)
};
_variableManager.Load(variables);
// Act
var value = _variableManager.GetVariable<int>("TestInt");
// Assert
Assert.That(value, Is.EqualTo(100));
}
[Test]
public void GetVariable_WithNonExistingVariable_ShouldReturnNull()
{
// Act
var value = _variableManager.GetVariable("NonExisting");
// Assert
Assert.That(value, Is.Null);
}
[Test]
public void SetVariable_WithPublicWriteVariable_ShouldSetSuccessfully()
{
// Arrange
var variables = new[]
{
new ScriptVariableModel("TestInt", typeof(int), 0, true, true)
};
_variableManager.Load(variables);
// Act
var result = _variableManager.SetVariable("TestInt", 50);
// Assert
Assert.That(result, Is.True);
Assert.That(_variableManager.GetVariable<int>("TestInt"), Is.EqualTo(50));
}
[Test]
public void SetVariable_WithNonPublicWriteVariable_ShouldFail()
{
// Arrange
var variables = new[]
{
new ScriptVariableModel("TestInt", typeof(int), 0, true, false)
};
_variableManager.Load(variables);
// Act
var result = _variableManager.SetVariable("TestInt", 50);
// Assert
Assert.That(result, Is.False);
Assert.That(_variableManager.GetVariable<int>("TestInt"), Is.EqualTo(0));
}
[Test]
public void SetValue_WithStringValue_ShouldConvertAndSet()
{
// Arrange
var variables = new[]
{
new ScriptVariableModel("TestInt", typeof(int), 0, true, true)
};
_variableManager.Load(variables);
// Act
var result = _variableManager.SetValue("TestInt", "123");
// Assert
Assert.That(result.IsSuccess, Is.True);
Assert.That(_variableManager.GetVariable<int>("TestInt"), Is.EqualTo(123));
}
[Test]
public void SetValue_WithNonWritableVariable_ShouldFail()
{
// Arrange
var variables = new[]
{
new ScriptVariableModel("TestInt", typeof(int), 0, true, false)
};
_variableManager.Load(variables);
// Act
var result = _variableManager.SetValue("TestInt", "123");
// Assert
Assert.That(result.IsSuccess, Is.False);
}
[Test]
public void GetVariables_ShouldReturnPublicReadableVariables()
{
// Arrange
var variables = new[]
{
new ScriptVariableModel("PublicVar", typeof(int), 1, true, true),
new ScriptVariableModel("PrivateVar", typeof(int), 2, false, false)
};
_variableManager.Load(variables);
// Act
var result = _variableManager.GetVariables().ToArray();
// Assert
Assert.That(result.Length, Is.EqualTo(1));
Assert.That(result[0].Name, Is.EqualTo("PublicVar"));
}
[Test]
public void Reset_ShouldClearAllVariables()
{
// Arrange
var variables = new[]
{
new ScriptVariableModel("TestInt", typeof(int), 42, true, true)
};
_variableManager.Load(variables);
Assert.That(_variableManager.HasVariable("TestInt"), Is.True);
// Act
_variableManager.Reset();
// Assert
Assert.That(_variableManager.HasVariable("TestInt"), Is.False);
}
}