test(configmanager): expand unit test coverage to 451 tests

Add comprehensive tests for services (ConnectionTestService, RuntimeConfigValidation),
ViewModels (PipelineEditor, dialogs, transformers), and Avalonia headless UI tests
for views and forms.
This commit is contained in:
Joseph Doherty
2026-01-27 07:24:55 -05:00
parent 227a749cdf
commit 937eb66ac8
14 changed files with 4053 additions and 62 deletions
@@ -0,0 +1,241 @@
using JdeScoping.ConfigManager.Services;
using JdeScoping.ConfigManager.ViewModels.Dialogs;
namespace JdeScoping.ConfigManager.Tests.ViewModels.Dialogs;
public class DiffPreviewDialogViewModelTests
{
[Fact]
public void Constructor_WithEmptyDiff_InitializesCorrectly()
{
// Arrange
var diff = new DiffResult
{
HasChanges = false,
Lines = [],
Insertions = 0,
Deletions = 0
};
// Act
var sut = new DiffPreviewDialogViewModel(diff);
// Assert
sut.Lines.Count.ShouldBe(0);
sut.HasChanges.ShouldBeFalse();
sut.Insertions.ShouldBe(0);
sut.Deletions.ShouldBe(0);
sut.Result.ShouldBeFalse();
}
[Fact]
public void Constructor_WithChanges_PopulatesLines()
{
// Arrange
var diff = new DiffResult
{
HasChanges = true,
Lines =
[
new DiffLine { OldLineNumber = 1, NewLineNumber = 1, Text = "unchanged line", Type = DiffLineType.Unchanged },
new DiffLine { OldLineNumber = 2, NewLineNumber = null, Text = "removed line", Type = DiffLineType.Removed },
new DiffLine { OldLineNumber = null, NewLineNumber = 2, Text = "added line", Type = DiffLineType.Added }
],
Insertions = 1,
Deletions = 1
};
// Act
var sut = new DiffPreviewDialogViewModel(diff);
// Assert
sut.Lines.Count.ShouldBe(3);
sut.HasChanges.ShouldBeTrue();
sut.Insertions.ShouldBe(1);
sut.Deletions.ShouldBe(1);
}
[Fact]
public void SaveCommand_SetsResultTrue_AndInvokesRequestClose()
{
// Arrange
var diff = CreateEmptyDiff();
var sut = new DiffPreviewDialogViewModel(diff);
var closeInvoked = false;
sut.RequestClose = () => closeInvoked = true;
// Act
sut.SaveCommand.Execute(null);
// Assert
sut.Result.ShouldBeTrue();
closeInvoked.ShouldBeTrue();
}
[Fact]
public void CancelCommand_SetsResultFalse_AndInvokesRequestClose()
{
// Arrange
var diff = CreateEmptyDiff();
var sut = new DiffPreviewDialogViewModel(diff);
var closeInvoked = false;
sut.RequestClose = () => closeInvoked = true;
// Act
sut.CancelCommand.Execute(null);
// Assert
sut.Result.ShouldBeFalse();
closeInvoked.ShouldBeTrue();
}
[Fact]
public void SaveCommand_DoesNotThrow_WhenRequestCloseIsNull()
{
// Arrange
var diff = CreateEmptyDiff();
var sut = new DiffPreviewDialogViewModel(diff);
sut.RequestClose = null;
// Act & Assert - Should not throw
Should.NotThrow(() => sut.SaveCommand.Execute(null));
sut.Result.ShouldBeTrue();
}
[Fact]
public void CancelCommand_DoesNotThrow_WhenRequestCloseIsNull()
{
// Arrange
var diff = CreateEmptyDiff();
var sut = new DiffPreviewDialogViewModel(diff);
sut.RequestClose = null;
// Act & Assert - Should not throw
Should.NotThrow(() => sut.CancelCommand.Execute(null));
sut.Result.ShouldBeFalse();
}
[Fact]
public void Constructor_ThrowsOnNullDiff()
{
// Act & Assert
Should.Throw<ArgumentNullException>(() => new DiffPreviewDialogViewModel(null!));
}
[Fact]
public void Result_InitialValue_IsFalse()
{
// Arrange
var diff = CreateEmptyDiff();
// Act
var sut = new DiffPreviewDialogViewModel(diff);
// Assert
sut.Result.ShouldBeFalse();
}
private static DiffResult CreateEmptyDiff()
{
return new DiffResult
{
HasChanges = false,
Lines = [],
Insertions = 0,
Deletions = 0
};
}
}
public class DiffLineViewModelTests
{
[Fact]
public void Constructor_UnchangedLine_SetsPropertiesCorrectly()
{
// Arrange
var line = new DiffLine
{
OldLineNumber = 5,
NewLineNumber = 5,
Text = "unchanged content",
Type = DiffLineType.Unchanged
};
// Act
var sut = new DiffLineViewModel(line);
// Assert
sut.OldLineNumber.ShouldBe("5");
sut.NewLineNumber.ShouldBe("5");
sut.Text.ShouldBe("unchanged content");
sut.Type.ShouldBe(DiffLineType.Unchanged);
sut.Background.ShouldBe("Transparent");
sut.BorderColor.ShouldBe("Transparent");
}
[Fact]
public void Constructor_AddedLine_SetsGreenStyling()
{
// Arrange
var line = new DiffLine
{
OldLineNumber = null,
NewLineNumber = 10,
Text = "new line",
Type = DiffLineType.Added
};
// Act
var sut = new DiffLineViewModel(line);
// Assert
sut.OldLineNumber.ShouldBe("");
sut.NewLineNumber.ShouldBe("10");
sut.Type.ShouldBe(DiffLineType.Added);
sut.Background.ShouldBe("#1A3DD68C");
sut.BorderColor.ShouldBe("#3DD68C");
}
[Fact]
public void Constructor_RemovedLine_SetsRedStyling()
{
// Arrange
var line = new DiffLine
{
OldLineNumber = 7,
NewLineNumber = null,
Text = "deleted line",
Type = DiffLineType.Removed
};
// Act
var sut = new DiffLineViewModel(line);
// Assert
sut.OldLineNumber.ShouldBe("7");
sut.NewLineNumber.ShouldBe("");
sut.Type.ShouldBe(DiffLineType.Removed);
sut.Background.ShouldBe("#1AFF6B6B");
sut.BorderColor.ShouldBe("#FF6B6B");
}
[Fact]
public void Constructor_NullLineNumbers_ReturnsEmptyStrings()
{
// Arrange
var line = new DiffLine
{
OldLineNumber = null,
NewLineNumber = null,
Text = "text",
Type = DiffLineType.Unchanged
};
// Act
var sut = new DiffLineViewModel(line);
// Assert
sut.OldLineNumber.ShouldBe("");
sut.NewLineNumber.ShouldBe("");
}
}
@@ -0,0 +1,193 @@
using JdeScoping.ConfigManager.Services;
using JdeScoping.ConfigManager.ViewModels.Dialogs;
namespace JdeScoping.ConfigManager.Tests.ViewModels.Dialogs;
public class ValidationResultsDialogViewModelTests
{
[Fact]
public void Constructor_WithEmptyResults_HasNoItems()
{
// Arrange
var appSettingsResult = new ValidationResult();
var pipelinesResult = new ValidationResult();
// Act
var sut = new ValidationResultsDialogViewModel(appSettingsResult, pipelinesResult);
// Assert
sut.Items.Count.ShouldBe(0);
sut.ErrorCount.ShouldBe(0);
sut.WarningCount.ShouldBe(0);
sut.IsValid.ShouldBeTrue();
}
[Fact]
public void Constructor_WithErrors_PopulatesItemsCorrectly()
{
// Arrange
var appSettingsResult = new ValidationResult();
appSettingsResult.AddError("Missing connection string");
appSettingsResult.AddError("Invalid timeout value");
var pipelinesResult = new ValidationResult();
// Act
var sut = new ValidationResultsDialogViewModel(appSettingsResult, pipelinesResult);
// Assert
sut.Items.Count.ShouldBe(2);
sut.ErrorCount.ShouldBe(2);
sut.WarningCount.ShouldBe(0);
sut.IsValid.ShouldBeFalse();
}
[Fact]
public void Constructor_WithWarnings_PopulatesItemsCorrectly()
{
// Arrange
var appSettingsResult = new ValidationResult();
appSettingsResult.AddWarning("Deprecated setting used");
var pipelinesResult = new ValidationResult();
pipelinesResult.AddWarning("Pipeline has no transformers");
// Act
var sut = new ValidationResultsDialogViewModel(appSettingsResult, pipelinesResult);
// Assert
sut.Items.Count.ShouldBe(2);
sut.ErrorCount.ShouldBe(0);
sut.WarningCount.ShouldBe(2);
sut.IsValid.ShouldBeFalse(); // Both errors and warnings make it invalid
}
[Fact]
public void Constructor_WithMixedResults_PopulatesAllItems()
{
// Arrange
var appSettingsResult = new ValidationResult();
appSettingsResult.AddError("Error in appsettings");
appSettingsResult.AddWarning("Warning in appsettings");
var pipelinesResult = new ValidationResult();
pipelinesResult.AddError("Error in pipelines");
pipelinesResult.AddWarning("Warning in pipelines");
// Act
var sut = new ValidationResultsDialogViewModel(appSettingsResult, pipelinesResult);
// Assert
sut.Items.Count.ShouldBe(4);
sut.ErrorCount.ShouldBe(2);
sut.WarningCount.ShouldBe(2);
sut.IsValid.ShouldBeFalse();
}
[Fact]
public void Constructor_SetsCorrectSourceOnItems()
{
// Arrange
var appSettingsResult = new ValidationResult();
appSettingsResult.AddError("App error");
var pipelinesResult = new ValidationResult();
pipelinesResult.AddError("Pipeline error");
// Act
var sut = new ValidationResultsDialogViewModel(appSettingsResult, pipelinesResult);
// Assert
sut.Items.ShouldContain(i => i.Source == "appsettings.json" && i.Message == "App error");
sut.Items.ShouldContain(i => i.Source == "pipelines.json" && i.Message == "Pipeline error");
}
[Fact]
public void CloseCommand_InvokesRequestClose()
{
// Arrange
var appSettingsResult = new ValidationResult();
var pipelinesResult = new ValidationResult();
var sut = new ValidationResultsDialogViewModel(appSettingsResult, pipelinesResult);
var closeInvoked = false;
sut.RequestClose = () => closeInvoked = true;
// Act
sut.CloseCommand.Execute(null);
// Assert
closeInvoked.ShouldBeTrue();
}
[Fact]
public void CloseCommand_DoesNotThrow_WhenRequestCloseIsNull()
{
// Arrange
var appSettingsResult = new ValidationResult();
var pipelinesResult = new ValidationResult();
var sut = new ValidationResultsDialogViewModel(appSettingsResult, pipelinesResult);
sut.RequestClose = null;
// Act & Assert - Should not throw
Should.NotThrow(() => sut.CloseCommand.Execute(null));
}
[Fact]
public void Constructor_ThrowsOnNullAppSettingsResult()
{
// Arrange
var pipelinesResult = new ValidationResult();
// Act & Assert
Should.Throw<ArgumentNullException>(() =>
new ValidationResultsDialogViewModel(null!, pipelinesResult));
}
[Fact]
public void Constructor_ThrowsOnNullPipelinesResult()
{
// Arrange
var appSettingsResult = new ValidationResult();
// Act & Assert
Should.Throw<ArgumentNullException>(() =>
new ValidationResultsDialogViewModel(appSettingsResult, null!));
}
}
public class ValidationItemViewModelTests
{
[Fact]
public void Constructor_SetsPropertiesCorrectly()
{
// Act
var sut = new ValidationItemViewModel("Test message", "test.json", ValidationItemType.Error);
// Assert
sut.Message.ShouldBe("Test message");
sut.Source.ShouldBe("test.json");
sut.Type.ShouldBe(ValidationItemType.Error);
}
[Fact]
public void Constructor_ErrorType_SetsErrorStyling()
{
// Act
var sut = new ValidationItemViewModel("Error", "test.json", ValidationItemType.Error);
// Assert
sut.Icon.ShouldBe("\u2717"); // X mark
sut.IconColor.ShouldBe("#FF6B6B");
sut.Background.ShouldBe("#1AFF6B6B");
sut.BorderColor.ShouldBe("#FF6B6B");
}
[Fact]
public void Constructor_WarningType_SetsWarningStyling()
{
// Act
var sut = new ValidationItemViewModel("Warning", "test.json", ValidationItemType.Warning);
// Assert
sut.Icon.ShouldBe("\u26A0"); // Warning sign
sut.IconColor.ShouldBe("#FFB84D");
sut.Background.ShouldBe("#1AFFB84D");
sut.BorderColor.ShouldBe("#FFB84D");
}
}