mirror of
https://github.com/actions/runner.git
synced 2026-01-24 13:31:26 +08:00
simplify
This commit is contained in:
@@ -1,687 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GitHub.Runner.Worker.Dap.StepCommands;
|
||||
using Xunit;
|
||||
|
||||
namespace GitHub.Runner.Common.Tests.Worker.Dap.StepCommands
|
||||
{
|
||||
/// <summary>
|
||||
/// Unit tests for StepCommandParser JSON API functionality.
|
||||
/// Tests the parsing of JSON commands for browser extension integration.
|
||||
/// </summary>
|
||||
public sealed class StepCommandParserJsonL0 : IDisposable
|
||||
{
|
||||
private TestHostContext _hc;
|
||||
private StepCommandParser _parser;
|
||||
|
||||
public StepCommandParserJsonL0()
|
||||
{
|
||||
_hc = new TestHostContext(this);
|
||||
_parser = new StepCommandParser();
|
||||
_parser.Initialize(_hc);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_hc?.Dispose();
|
||||
}
|
||||
|
||||
#region IsStepCommand Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void IsStepCommand_DetectsJsonFormat()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
Assert.True(_parser.IsStepCommand("{\"cmd\":\"step.list\"}"));
|
||||
Assert.True(_parser.IsStepCommand("{\"cmd\": \"step.add\", \"type\": \"run\"}"));
|
||||
Assert.True(_parser.IsStepCommand(" { \"cmd\" : \"step.export\" } "));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void IsStepCommand_RejectsInvalidJson()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
Assert.False(_parser.IsStepCommand("{\"cmd\":\"other.command\"}"));
|
||||
Assert.False(_parser.IsStepCommand("{\"action\":\"step.list\"}"));
|
||||
Assert.False(_parser.IsStepCommand("{\"type\":\"step\"}"));
|
||||
Assert.False(_parser.IsStepCommand("{}"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void IsStepCommand_HandlesBothFormats()
|
||||
{
|
||||
// REPL format
|
||||
Assert.True(_parser.IsStepCommand("!step list"));
|
||||
Assert.True(_parser.IsStepCommand("!STEP ADD run \"test\""));
|
||||
|
||||
// JSON format
|
||||
Assert.True(_parser.IsStepCommand("{\"cmd\":\"step.list\"}"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON List Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_ListCommand_Basic()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.list\"}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<ListCommand>(command);
|
||||
var listCmd = (ListCommand)command;
|
||||
Assert.False(listCmd.Verbose);
|
||||
Assert.True(listCmd.WasJsonInput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_ListCommand_WithVerbose()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.list\",\"verbose\":true}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var listCmd = Assert.IsType<ListCommand>(command);
|
||||
Assert.True(listCmd.Verbose);
|
||||
Assert.True(listCmd.WasJsonInput);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON Add Run Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_AddRunCommand_Basic()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.add\",\"type\":\"run\",\"script\":\"npm test\"}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(command);
|
||||
Assert.Equal("npm test", addCmd.Script);
|
||||
Assert.True(addCmd.WasJsonInput);
|
||||
Assert.Equal(PositionType.Last, addCmd.Position.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_AddRunCommand_AllOptions()
|
||||
{
|
||||
// Arrange
|
||||
var json = @"{
|
||||
""cmd"": ""step.add"",
|
||||
""type"": ""run"",
|
||||
""script"": ""npm run build"",
|
||||
""name"": ""Build App"",
|
||||
""shell"": ""bash"",
|
||||
""workingDirectory"": ""./src"",
|
||||
""if"": ""success()"",
|
||||
""env"": {""NODE_ENV"": ""production"", ""CI"": ""true""},
|
||||
""continueOnError"": true,
|
||||
""timeout"": 30,
|
||||
""position"": {""after"": 3}
|
||||
}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(command);
|
||||
Assert.Equal("npm run build", addCmd.Script);
|
||||
Assert.Equal("Build App", addCmd.Name);
|
||||
Assert.Equal("bash", addCmd.Shell);
|
||||
Assert.Equal("./src", addCmd.WorkingDirectory);
|
||||
Assert.Equal("success()", addCmd.Condition);
|
||||
Assert.NotNull(addCmd.Env);
|
||||
Assert.Equal("production", addCmd.Env["NODE_ENV"]);
|
||||
Assert.Equal("true", addCmd.Env["CI"]);
|
||||
Assert.True(addCmd.ContinueOnError);
|
||||
Assert.Equal(30, addCmd.Timeout);
|
||||
Assert.Equal(PositionType.After, addCmd.Position.Type);
|
||||
Assert.Equal(3, addCmd.Position.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_AddRunCommand_MissingScript_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.add\",\"type\":\"run\"}";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(json));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
Assert.Contains("script", ex.Message.ToLower());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON Add Uses Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_AddUsesCommand_Basic()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.add\",\"type\":\"uses\",\"action\":\"actions/checkout@v4\"}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddUsesCommand>(command);
|
||||
Assert.Equal("actions/checkout@v4", addCmd.Action);
|
||||
Assert.True(addCmd.WasJsonInput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_AddUsesCommand_AllOptions()
|
||||
{
|
||||
// Arrange
|
||||
var json = @"{
|
||||
""cmd"": ""step.add"",
|
||||
""type"": ""uses"",
|
||||
""action"": ""actions/setup-node@v4"",
|
||||
""name"": ""Setup Node.js"",
|
||||
""with"": {""node-version"": ""20"", ""cache"": ""npm""},
|
||||
""env"": {""NODE_OPTIONS"": ""--max-old-space-size=4096""},
|
||||
""if"": ""always()"",
|
||||
""continueOnError"": false,
|
||||
""timeout"": 10,
|
||||
""position"": {""at"": 2}
|
||||
}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddUsesCommand>(command);
|
||||
Assert.Equal("actions/setup-node@v4", addCmd.Action);
|
||||
Assert.Equal("Setup Node.js", addCmd.Name);
|
||||
Assert.NotNull(addCmd.With);
|
||||
Assert.Equal("20", addCmd.With["node-version"]);
|
||||
Assert.Equal("npm", addCmd.With["cache"]);
|
||||
Assert.NotNull(addCmd.Env);
|
||||
Assert.Equal("--max-old-space-size=4096", addCmd.Env["NODE_OPTIONS"]);
|
||||
Assert.Equal("always()", addCmd.Condition);
|
||||
Assert.False(addCmd.ContinueOnError);
|
||||
Assert.Equal(10, addCmd.Timeout);
|
||||
Assert.Equal(PositionType.At, addCmd.Position.Type);
|
||||
Assert.Equal(2, addCmd.Position.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_AddUsesCommand_MissingAction_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.add\",\"type\":\"uses\"}";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(json));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
Assert.Contains("action", ex.Message.ToLower());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_AddCommand_InvalidType_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.add\",\"type\":\"invalid\",\"script\":\"echo test\"}";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(json));
|
||||
Assert.Equal(StepCommandErrors.InvalidType, ex.ErrorCode);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON Edit Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_EditCommand_Basic()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.edit\",\"index\":3,\"name\":\"New Name\"}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var editCmd = Assert.IsType<EditCommand>(command);
|
||||
Assert.Equal(3, editCmd.Index);
|
||||
Assert.Equal("New Name", editCmd.Name);
|
||||
Assert.True(editCmd.WasJsonInput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_EditCommand_AllOptions()
|
||||
{
|
||||
// Arrange
|
||||
var json = @"{
|
||||
""cmd"": ""step.edit"",
|
||||
""index"": 4,
|
||||
""name"": ""Updated Step"",
|
||||
""script"": ""npm run test:ci"",
|
||||
""shell"": ""pwsh"",
|
||||
""workingDirectory"": ""./tests"",
|
||||
""if"": ""failure()"",
|
||||
""with"": {""key1"": ""value1""},
|
||||
""env"": {""DEBUG"": ""true""},
|
||||
""removeWith"": [""oldKey""],
|
||||
""removeEnv"": [""OBSOLETE""],
|
||||
""continueOnError"": true,
|
||||
""timeout"": 15
|
||||
}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var editCmd = Assert.IsType<EditCommand>(command);
|
||||
Assert.Equal(4, editCmd.Index);
|
||||
Assert.Equal("Updated Step", editCmd.Name);
|
||||
Assert.Equal("npm run test:ci", editCmd.Script);
|
||||
Assert.Equal("pwsh", editCmd.Shell);
|
||||
Assert.Equal("./tests", editCmd.WorkingDirectory);
|
||||
Assert.Equal("failure()", editCmd.Condition);
|
||||
Assert.NotNull(editCmd.With);
|
||||
Assert.Equal("value1", editCmd.With["key1"]);
|
||||
Assert.NotNull(editCmd.Env);
|
||||
Assert.Equal("true", editCmd.Env["DEBUG"]);
|
||||
Assert.NotNull(editCmd.RemoveWith);
|
||||
Assert.Contains("oldKey", editCmd.RemoveWith);
|
||||
Assert.NotNull(editCmd.RemoveEnv);
|
||||
Assert.Contains("OBSOLETE", editCmd.RemoveEnv);
|
||||
Assert.True(editCmd.ContinueOnError);
|
||||
Assert.Equal(15, editCmd.Timeout);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_EditCommand_MissingIndex_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.edit\",\"name\":\"New Name\"}";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(json));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
Assert.Contains("index", ex.Message.ToLower());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON Remove Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_RemoveCommand()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.remove\",\"index\":5}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var removeCmd = Assert.IsType<RemoveCommand>(command);
|
||||
Assert.Equal(5, removeCmd.Index);
|
||||
Assert.True(removeCmd.WasJsonInput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_RemoveCommand_MissingIndex_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.remove\"}";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(json));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
Assert.Contains("index", ex.Message.ToLower());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON Move Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_MoveCommand_After()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.move\",\"from\":5,\"position\":{\"after\":2}}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var moveCmd = Assert.IsType<MoveCommand>(command);
|
||||
Assert.Equal(5, moveCmd.FromIndex);
|
||||
Assert.Equal(PositionType.After, moveCmd.Position.Type);
|
||||
Assert.Equal(2, moveCmd.Position.Index);
|
||||
Assert.True(moveCmd.WasJsonInput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_MoveCommand_Before()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.move\",\"from\":3,\"position\":{\"before\":5}}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var moveCmd = Assert.IsType<MoveCommand>(command);
|
||||
Assert.Equal(3, moveCmd.FromIndex);
|
||||
Assert.Equal(PositionType.Before, moveCmd.Position.Type);
|
||||
Assert.Equal(5, moveCmd.Position.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_MoveCommand_First()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.move\",\"from\":5,\"position\":{\"first\":true}}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var moveCmd = Assert.IsType<MoveCommand>(command);
|
||||
Assert.Equal(PositionType.First, moveCmd.Position.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_MoveCommand_Last()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.move\",\"from\":2,\"position\":{\"last\":true}}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var moveCmd = Assert.IsType<MoveCommand>(command);
|
||||
Assert.Equal(PositionType.Last, moveCmd.Position.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_MoveCommand_At()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.move\",\"from\":5,\"position\":{\"at\":3}}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var moveCmd = Assert.IsType<MoveCommand>(command);
|
||||
Assert.Equal(PositionType.At, moveCmd.Position.Type);
|
||||
Assert.Equal(3, moveCmd.Position.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_MoveCommand_MissingFrom_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.move\",\"position\":{\"after\":2}}";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(json));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
Assert.Contains("from", ex.Message.ToLower());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_MoveCommand_MissingPosition_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.move\",\"from\":5}";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(json));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
Assert.Contains("position", ex.Message.ToLower());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON Export Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_ExportCommand_Default()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.export\"}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var exportCmd = Assert.IsType<ExportCommand>(command);
|
||||
Assert.False(exportCmd.ChangesOnly);
|
||||
Assert.False(exportCmd.WithComments);
|
||||
Assert.True(exportCmd.WasJsonInput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_ExportCommand_WithOptions()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.export\",\"changesOnly\":true,\"withComments\":true}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var exportCmd = Assert.IsType<ExportCommand>(command);
|
||||
Assert.True(exportCmd.ChangesOnly);
|
||||
Assert.True(exportCmd.WithComments);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON Error Handling Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_InvalidJson_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{invalid json}";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(json));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
Assert.Contains("Invalid JSON", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_MissingCmd_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"action\":\"list\"}";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(json));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
Assert.Contains("cmd", ex.Message.ToLower());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_UnknownCommand_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.unknown\"}";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(json));
|
||||
Assert.Equal(StepCommandErrors.InvalidCommand, ex.ErrorCode);
|
||||
Assert.Contains("unknown", ex.Message.ToLower());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_EmptyJson_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{}";
|
||||
|
||||
// Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(json));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Position Parsing Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_PositionDefaults_ToLast()
|
||||
{
|
||||
// Arrange - position is optional for add commands
|
||||
var json = "{\"cmd\":\"step.add\",\"type\":\"run\",\"script\":\"test\"}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(command);
|
||||
Assert.Equal(PositionType.Last, addCmd.Position.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_NullPosition_DefaultsToLast()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.add\",\"type\":\"run\",\"script\":\"test\",\"position\":null}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(command);
|
||||
Assert.Equal(PositionType.Last, addCmd.Position.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ParseJson_EmptyPosition_DefaultsToLast()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.add\",\"type\":\"run\",\"script\":\"test\",\"position\":{}}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(command);
|
||||
Assert.Equal(PositionType.Last, addCmd.Position.Type);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region WasJsonInput Flag Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_JsonInput_SetsWasJsonInputTrue()
|
||||
{
|
||||
// Arrange
|
||||
var json = "{\"cmd\":\"step.list\"}";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(json);
|
||||
|
||||
// Assert
|
||||
Assert.True(command.WasJsonInput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_ReplInput_SetsWasJsonInputFalse()
|
||||
{
|
||||
// Arrange
|
||||
var repl = "!step list";
|
||||
|
||||
// Act
|
||||
var command = _parser.Parse(repl);
|
||||
|
||||
// Assert
|
||||
Assert.False(command.WasJsonInput);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
726
src/Test/L0/Worker/Dap/StepCommands/StepCommandParserL0.cs
Normal file
726
src/Test/L0/Worker/Dap/StepCommands/StepCommandParserL0.cs
Normal file
@@ -0,0 +1,726 @@
|
||||
using System;
|
||||
using GitHub.Runner.Worker.Dap.StepCommands;
|
||||
using Xunit;
|
||||
|
||||
namespace GitHub.Runner.Common.Tests.Worker.Dap.StepCommands
|
||||
{
|
||||
/// <summary>
|
||||
/// Unit tests for StepCommandParser.
|
||||
/// Tests parsing of "steps" commands with the --output flag.
|
||||
/// </summary>
|
||||
public sealed class StepCommandParserL0 : IDisposable
|
||||
{
|
||||
private TestHostContext _hc;
|
||||
private StepCommandParser _parser;
|
||||
|
||||
public StepCommandParserL0()
|
||||
{
|
||||
_hc = new TestHostContext(this);
|
||||
_parser = new StepCommandParser();
|
||||
_parser.Initialize(_hc);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_hc?.Dispose();
|
||||
}
|
||||
|
||||
#region IsStepCommand Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void IsStepCommand_DetectsStepsPrefix()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
Assert.True(_parser.IsStepCommand("steps list"));
|
||||
Assert.True(_parser.IsStepCommand("steps add run \"test\""));
|
||||
Assert.True(_parser.IsStepCommand("STEPS LIST")); // case insensitive
|
||||
Assert.True(_parser.IsStepCommand(" steps list ")); // whitespace
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void IsStepCommand_RejectsInvalid()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
Assert.False(_parser.IsStepCommand("step list")); // missing 's'
|
||||
Assert.False(_parser.IsStepCommand("!step list")); // old format
|
||||
Assert.False(_parser.IsStepCommand("stepslist")); // no space
|
||||
Assert.False(_parser.IsStepCommand(""));
|
||||
Assert.False(_parser.IsStepCommand(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void IsStepCommand_AllowsStepsAlone()
|
||||
{
|
||||
// "steps" alone should be detected (even if parsing will fail for lack of subcommand)
|
||||
Assert.True(_parser.IsStepCommand("steps"));
|
||||
Assert.True(_parser.IsStepCommand(" steps "));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Output Format Flag Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_ListCommand_WithOutputJson()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps list --output json") as ListCommand;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(cmd);
|
||||
Assert.Equal(OutputFormat.Json, cmd.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_ListCommand_WithOutputText()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps list --output text") as ListCommand;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(cmd);
|
||||
Assert.Equal(OutputFormat.Text, cmd.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_ListCommand_DefaultOutputIsText()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps list") as ListCommand;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(cmd);
|
||||
Assert.Equal(OutputFormat.Text, cmd.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddCommand_WithOutputFlag()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps add run \"echo test\" --output json") as AddRunCommand;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(cmd);
|
||||
Assert.Equal(OutputFormat.Json, cmd.Output);
|
||||
Assert.Equal("echo test", cmd.Script);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_OutputFlag_ShortForm()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps list -o json") as ListCommand;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(cmd);
|
||||
Assert.Equal(OutputFormat.Json, cmd.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_OutputFlag_EqualsForm()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps list --output=json") as ListCommand;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(cmd);
|
||||
Assert.Equal(OutputFormat.Json, cmd.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_OutputFlag_TextEqualsForm()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps list --output=text") as ListCommand;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(cmd);
|
||||
Assert.Equal(OutputFormat.Text, cmd.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_EditCommand_WithOutputJson()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps edit 3 --name \"New Name\" --output json") as EditCommand;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(cmd);
|
||||
Assert.Equal(OutputFormat.Json, cmd.Output);
|
||||
Assert.Equal(3, cmd.Index);
|
||||
Assert.Equal("New Name", cmd.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_RemoveCommand_WithOutputJson()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps remove 5 --output json") as RemoveCommand;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(cmd);
|
||||
Assert.Equal(OutputFormat.Json, cmd.Output);
|
||||
Assert.Equal(5, cmd.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_MoveCommand_WithOutputJson()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps move 3 --after 5 --output json") as MoveCommand;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(cmd);
|
||||
Assert.Equal(OutputFormat.Json, cmd.Output);
|
||||
Assert.Equal(3, cmd.FromIndex);
|
||||
Assert.Equal(PositionType.After, cmd.Position.Type);
|
||||
Assert.Equal(5, cmd.Position.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_ExportCommand_WithOutputJson()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps export --output json") as ExportCommand;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(cmd);
|
||||
Assert.Equal(OutputFormat.Json, cmd.Output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region List Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_ListCommand_Basic()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps list");
|
||||
|
||||
// Assert
|
||||
var listCmd = Assert.IsType<ListCommand>(cmd);
|
||||
Assert.False(listCmd.Verbose);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_ListCommand_WithVerbose()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps list --verbose");
|
||||
|
||||
// Assert
|
||||
var listCmd = Assert.IsType<ListCommand>(cmd);
|
||||
Assert.True(listCmd.Verbose);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_ListCommand_WithVerboseShort()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps list -v");
|
||||
|
||||
// Assert
|
||||
var listCmd = Assert.IsType<ListCommand>(cmd);
|
||||
Assert.True(listCmd.Verbose);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Add Run Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddRunCommand_Basic()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps add run \"npm test\"");
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(cmd);
|
||||
Assert.Equal("npm test", addCmd.Script);
|
||||
Assert.Equal(PositionType.Last, addCmd.Position.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddRunCommand_AllOptions()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps add run \"npm run build\" --name \"Build App\" --shell bash --after 3");
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(cmd);
|
||||
Assert.Equal("npm run build", addCmd.Script);
|
||||
Assert.Equal("Build App", addCmd.Name);
|
||||
Assert.Equal("bash", addCmd.Shell);
|
||||
Assert.Equal(PositionType.After, addCmd.Position.Type);
|
||||
Assert.Equal(3, addCmd.Position.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddRunCommand_WithEnv()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps add run \"npm test\" --env NODE_ENV=test --env CI=true");
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(cmd);
|
||||
Assert.NotNull(addCmd.Env);
|
||||
Assert.Equal("test", addCmd.Env["NODE_ENV"]);
|
||||
Assert.Equal("true", addCmd.Env["CI"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddRunCommand_WithContinueOnError()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps add run \"npm test\" --continue-on-error");
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(cmd);
|
||||
Assert.True(addCmd.ContinueOnError);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddRunCommand_WithTimeout()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps add run \"npm test\" --timeout 30");
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(cmd);
|
||||
Assert.Equal(30, addCmd.Timeout);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddRunCommand_PositionFirst()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps add run \"echo first\" --first");
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(cmd);
|
||||
Assert.Equal(PositionType.First, addCmd.Position.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddRunCommand_PositionAt()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps add run \"echo at\" --at 5");
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(cmd);
|
||||
Assert.Equal(PositionType.At, addCmd.Position.Type);
|
||||
Assert.Equal(5, addCmd.Position.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddRunCommand_PositionBefore()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps add run \"echo before\" --before 3");
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddRunCommand>(cmd);
|
||||
Assert.Equal(PositionType.Before, addCmd.Position.Type);
|
||||
Assert.Equal(3, addCmd.Position.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddRunCommand_MissingScript_Throws()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse("steps add run"));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Add Uses Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddUsesCommand_Basic()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps add uses actions/checkout@v4");
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddUsesCommand>(cmd);
|
||||
Assert.Equal("actions/checkout@v4", addCmd.Action);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddUsesCommand_AllOptions()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps add uses actions/setup-node@v4 --name \"Setup Node\" --with node-version=20 --with cache=npm");
|
||||
|
||||
// Assert
|
||||
var addCmd = Assert.IsType<AddUsesCommand>(cmd);
|
||||
Assert.Equal("actions/setup-node@v4", addCmd.Action);
|
||||
Assert.Equal("Setup Node", addCmd.Name);
|
||||
Assert.NotNull(addCmd.With);
|
||||
Assert.Equal("20", addCmd.With["node-version"]);
|
||||
Assert.Equal("npm", addCmd.With["cache"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddUsesCommand_MissingAction_Throws()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse("steps add uses"));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_AddCommand_InvalidType_Throws()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse("steps add invalid \"test\""));
|
||||
Assert.Equal(StepCommandErrors.InvalidType, ex.ErrorCode);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Edit Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_EditCommand_Basic()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps edit 3 --name \"New Name\"");
|
||||
|
||||
// Assert
|
||||
var editCmd = Assert.IsType<EditCommand>(cmd);
|
||||
Assert.Equal(3, editCmd.Index);
|
||||
Assert.Equal("New Name", editCmd.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_EditCommand_AllOptions()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps edit 4 --name \"Updated\" --script \"npm test\" --shell pwsh --if \"failure()\"");
|
||||
|
||||
// Assert
|
||||
var editCmd = Assert.IsType<EditCommand>(cmd);
|
||||
Assert.Equal(4, editCmd.Index);
|
||||
Assert.Equal("Updated", editCmd.Name);
|
||||
Assert.Equal("npm test", editCmd.Script);
|
||||
Assert.Equal("pwsh", editCmd.Shell);
|
||||
Assert.Equal("failure()", editCmd.Condition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_EditCommand_MissingIndex_Throws()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse("steps edit --name \"Test\""));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_EditCommand_InvalidIndex_Throws()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse("steps edit abc --name \"Test\""));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Remove Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_RemoveCommand()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps remove 5");
|
||||
|
||||
// Assert
|
||||
var removeCmd = Assert.IsType<RemoveCommand>(cmd);
|
||||
Assert.Equal(5, removeCmd.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_RemoveCommand_MissingIndex_Throws()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse("steps remove"));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Move Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_MoveCommand_After()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps move 5 --after 2");
|
||||
|
||||
// Assert
|
||||
var moveCmd = Assert.IsType<MoveCommand>(cmd);
|
||||
Assert.Equal(5, moveCmd.FromIndex);
|
||||
Assert.Equal(PositionType.After, moveCmd.Position.Type);
|
||||
Assert.Equal(2, moveCmd.Position.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_MoveCommand_Before()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps move 3 --before 5");
|
||||
|
||||
// Assert
|
||||
var moveCmd = Assert.IsType<MoveCommand>(cmd);
|
||||
Assert.Equal(3, moveCmd.FromIndex);
|
||||
Assert.Equal(PositionType.Before, moveCmd.Position.Type);
|
||||
Assert.Equal(5, moveCmd.Position.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_MoveCommand_First()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps move 5 --first");
|
||||
|
||||
// Assert
|
||||
var moveCmd = Assert.IsType<MoveCommand>(cmd);
|
||||
Assert.Equal(PositionType.First, moveCmd.Position.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_MoveCommand_Last()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps move 2 --last");
|
||||
|
||||
// Assert
|
||||
var moveCmd = Assert.IsType<MoveCommand>(cmd);
|
||||
Assert.Equal(PositionType.Last, moveCmd.Position.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_MoveCommand_To()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps move 5 --to 3");
|
||||
|
||||
// Assert
|
||||
var moveCmd = Assert.IsType<MoveCommand>(cmd);
|
||||
Assert.Equal(PositionType.At, moveCmd.Position.Type);
|
||||
Assert.Equal(3, moveCmd.Position.Index);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_MoveCommand_MissingFrom_Throws()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse("steps move --after 2"));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_MoveCommand_MissingPosition_Throws()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse("steps move 5"));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Export Command Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_ExportCommand_Default()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps export");
|
||||
|
||||
// Assert
|
||||
var exportCmd = Assert.IsType<ExportCommand>(cmd);
|
||||
Assert.False(exportCmd.ChangesOnly);
|
||||
Assert.False(exportCmd.WithComments);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_ExportCommand_WithOptions()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cmd = _parser.Parse("steps export --changes-only --with-comments");
|
||||
|
||||
// Assert
|
||||
var exportCmd = Assert.IsType<ExportCommand>(cmd);
|
||||
Assert.True(exportCmd.ChangesOnly);
|
||||
Assert.True(exportCmd.WithComments);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Error Handling Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_InvalidFormat_Throws()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse("step list"));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
Assert.Contains("steps", ex.Message.ToLower());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_UnknownCommand_Throws()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse("steps unknown"));
|
||||
Assert.Equal(StepCommandErrors.InvalidCommand, ex.ErrorCode);
|
||||
Assert.Contains("unknown", ex.Message.ToLower());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_Empty_Throws()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse(""));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_StepsAlone_Throws()
|
||||
{
|
||||
// "steps" without a subcommand should throw
|
||||
var ex = Assert.Throws<StepCommandException>(() => _parser.Parse("steps"));
|
||||
Assert.Equal(StepCommandErrors.ParseError, ex.ErrorCode);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Case Insensitivity Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_CaseInsensitive_StepsKeyword()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
Assert.IsType<ListCommand>(_parser.Parse("STEPS list"));
|
||||
Assert.IsType<ListCommand>(_parser.Parse("Steps list"));
|
||||
Assert.IsType<ListCommand>(_parser.Parse("sTePs list"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void Parse_CaseInsensitive_Subcommand()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
Assert.IsType<ListCommand>(_parser.Parse("steps LIST"));
|
||||
Assert.IsType<ListCommand>(_parser.Parse("steps List"));
|
||||
Assert.IsType<AddRunCommand>(_parser.Parse("steps ADD run \"test\""));
|
||||
Assert.IsType<EditCommand>(_parser.Parse("steps EDIT 1"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user