311 lines
10 KiB
C#
311 lines
10 KiB
C#
using Core.Entities;
|
|
using Core.Validation;
|
|
using Core.Validation.Rules.TeamRules;
|
|
using Tests.Builders;
|
|
|
|
namespace Tests.Validation.Rules;
|
|
|
|
[TestFixture]
|
|
public class TeamRulesTests
|
|
{
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
BuilderExtensions.ResetAllBuilders();
|
|
}
|
|
|
|
#region MissingCaptainRule Tests
|
|
|
|
[Test]
|
|
public void MissingCaptainRule_TeamHasCaptain_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var config = new ValidationConfiguration { RequireTeamCaptain = true };
|
|
var rule = new MissingCaptainRule();
|
|
|
|
var robotics = EventDefinitionBuilder.Team("Robotics", 2, 4).Build();
|
|
var captain = StudentBuilder.Default().WithName("Alice", "A").Build();
|
|
var member = StudentBuilder.Default().WithName("Bob", "B").Build();
|
|
|
|
var team = TeamBuilder.Default()
|
|
.ForEvent(robotics)
|
|
.WithStudent(captain, isCaptain: true)
|
|
.WithStudent(member)
|
|
.Build();
|
|
|
|
// Act
|
|
var warning = rule.Validate(team, config);
|
|
|
|
// Assert
|
|
Assert.That(warning, Is.Null);
|
|
}
|
|
|
|
[Test]
|
|
public void MissingCaptainRule_TeamLacksCaptain_ReturnsWarning()
|
|
{
|
|
// Arrange
|
|
var config = new ValidationConfiguration
|
|
{
|
|
RequireTeamCaptain = true,
|
|
MissingCaptainSeverity = ValidationSeverity.Warning
|
|
};
|
|
var rule = new MissingCaptainRule();
|
|
|
|
var robotics = EventDefinitionBuilder.Team("Robotics", 2, 4).Build();
|
|
var team = TeamBuilder.Default()
|
|
.ForEvent(robotics)
|
|
.WithStudent(StudentBuilder.Default().WithName("Alice", "A").Build())
|
|
.WithStudent(StudentBuilder.Default().WithName("Bob", "B").Build())
|
|
.Build();
|
|
|
|
// Act
|
|
var warning = rule.Validate(team, config);
|
|
|
|
// Assert
|
|
Assert.That(warning, Is.Not.Null);
|
|
Assert.That(warning!.Code, Is.EqualTo("MISSING_CAPTAIN"));
|
|
Assert.That(warning.Message, Does.Contain("no captain assigned"));
|
|
Assert.That(warning.Severity, Is.EqualTo(ValidationSeverity.Warning));
|
|
Assert.That(warning.IconIdentifier, Is.EqualTo("Captain"));
|
|
}
|
|
|
|
[Test]
|
|
public void MissingCaptainRule_RequirementDisabled_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var config = new ValidationConfiguration { RequireTeamCaptain = false };
|
|
var rule = new MissingCaptainRule();
|
|
|
|
var robotics = EventDefinitionBuilder.Team("Robotics", 2, 4).Build();
|
|
var team = TeamBuilder.Default()
|
|
.ForEvent(robotics)
|
|
.WithStudent(StudentBuilder.Default().Build())
|
|
.Build();
|
|
|
|
// Act
|
|
var warning = rule.Validate(team, config);
|
|
|
|
// Assert
|
|
Assert.That(warning, Is.Null);
|
|
}
|
|
|
|
[Test]
|
|
public void MissingCaptainRule_IndividualEvent_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var config = new ValidationConfiguration { RequireTeamCaptain = true };
|
|
var rule = new MissingCaptainRule();
|
|
|
|
var flight = EventDefinitionBuilder.Individual("Flight").Build();
|
|
var team = TeamBuilder.Default()
|
|
.ForEvent(flight)
|
|
.WithStudent(StudentBuilder.Default().Build())
|
|
.Build();
|
|
|
|
// Act
|
|
var warning = rule.Validate(team, config);
|
|
|
|
// Assert
|
|
Assert.That(warning, Is.Null, "Individual events should not require a captain");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TeamSizeTooSmallRule Tests
|
|
|
|
[Test]
|
|
public void TeamSizeTooSmallRule_MeetsMinimum_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var config = new ValidationConfiguration { TeamSizeSeverity = ValidationSeverity.Warning };
|
|
var rule = new TeamSizeTooSmallRule();
|
|
|
|
var robotics = EventDefinitionBuilder.Team("Robotics", 2, 4).Build();
|
|
var team = TeamBuilder.Default()
|
|
.ForEvent(robotics)
|
|
.WithStudent(StudentBuilder.Default().WithName("Alice", "A").Build())
|
|
.WithStudent(StudentBuilder.Default().WithName("Bob", "B").Build())
|
|
.Build();
|
|
|
|
// Act
|
|
var warning = rule.Validate(team, config);
|
|
|
|
// Assert
|
|
Assert.That(warning, Is.Null);
|
|
}
|
|
|
|
[Test]
|
|
public void TeamSizeTooSmallRule_BelowMinimum_ReturnsWarning()
|
|
{
|
|
// Arrange
|
|
var config = new ValidationConfiguration { TeamSizeSeverity = ValidationSeverity.Error };
|
|
var rule = new TeamSizeTooSmallRule();
|
|
|
|
var robotics = EventDefinitionBuilder.Team("Robotics", 3, 5).Build();
|
|
var team = TeamBuilder.Default()
|
|
.ForEvent(robotics)
|
|
.WithStudent(StudentBuilder.Default().WithName("Alice", "A").Build())
|
|
.Build();
|
|
|
|
// Act
|
|
var warning = rule.Validate(team, config);
|
|
|
|
// Assert
|
|
Assert.That(warning, Is.Not.Null);
|
|
Assert.That(warning!.Code, Is.EqualTo("TEAM_SIZE_TOO_SMALL"));
|
|
Assert.That(warning.Message, Does.Contain("1 members"));
|
|
Assert.That(warning.Message, Does.Contain("min: 3"));
|
|
Assert.That(warning.Severity, Is.EqualTo(ValidationSeverity.Error));
|
|
}
|
|
|
|
[Test]
|
|
public void TeamSizeTooSmallRule_IndividualEvent_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var config = new ValidationConfiguration { TeamSizeSeverity = ValidationSeverity.Warning };
|
|
var rule = new TeamSizeTooSmallRule();
|
|
|
|
var flight = EventDefinitionBuilder.Individual("Flight").Build();
|
|
var team = TeamBuilder.Default()
|
|
.ForEvent(flight)
|
|
.WithStudent(StudentBuilder.Default().Build())
|
|
.Build();
|
|
|
|
// Act
|
|
var warning = rule.Validate(team, config);
|
|
|
|
// Assert
|
|
Assert.That(warning, Is.Null);
|
|
}
|
|
|
|
[Test]
|
|
public void TeamSizeTooSmallRule_ContainsMetadata()
|
|
{
|
|
// Arrange
|
|
var config = new ValidationConfiguration { TeamSizeSeverity = ValidationSeverity.Warning };
|
|
var rule = new TeamSizeTooSmallRule();
|
|
|
|
var robotics = EventDefinitionBuilder.Team("Robotics", 4, 6).Build();
|
|
var team = TeamBuilder.Default()
|
|
.ForEvent(robotics)
|
|
.WithStudent(StudentBuilder.Default().Build())
|
|
.WithStudent(StudentBuilder.Default().Build())
|
|
.Build();
|
|
|
|
// Act
|
|
var warning = rule.Validate(team, config);
|
|
|
|
// Assert
|
|
Assert.That(warning, Is.Not.Null);
|
|
Assert.That(warning!.Metadata, Contains.Key("EventName"));
|
|
Assert.That(warning.Metadata, Contains.Key("ActualSize"));
|
|
Assert.That(warning.Metadata, Contains.Key("MinSize"));
|
|
Assert.That(warning.Metadata["ActualSize"], Is.EqualTo(2));
|
|
Assert.That(warning.Metadata["MinSize"], Is.EqualTo(4));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TeamSizeTooLargeRule Tests
|
|
|
|
[Test]
|
|
public void TeamSizeTooLargeRule_MeetsMaximum_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var config = new ValidationConfiguration { TeamSizeSeverity = ValidationSeverity.Warning };
|
|
var rule = new TeamSizeTooLargeRule();
|
|
|
|
var robotics = EventDefinitionBuilder.Team("Robotics", 2, 4).Build();
|
|
var team = TeamBuilder.Default()
|
|
.ForEvent(robotics)
|
|
.WithStudent(StudentBuilder.Default().WithName("Alice", "A").Build())
|
|
.WithStudent(StudentBuilder.Default().WithName("Bob", "B").Build())
|
|
.WithStudent(StudentBuilder.Default().WithName("Carol", "C").Build())
|
|
.Build();
|
|
|
|
// Act
|
|
var warning = rule.Validate(team, config);
|
|
|
|
// Assert
|
|
Assert.That(warning, Is.Null);
|
|
}
|
|
|
|
[Test]
|
|
public void TeamSizeTooLargeRule_ExceedsMaximum_ReturnsWarning()
|
|
{
|
|
// Arrange
|
|
var config = new ValidationConfiguration { TeamSizeSeverity = ValidationSeverity.Warning };
|
|
var rule = new TeamSizeTooLargeRule();
|
|
|
|
var robotics = EventDefinitionBuilder.Team("Robotics", 2, 3).Build();
|
|
var team = TeamBuilder.Default()
|
|
.ForEvent(robotics)
|
|
.WithStudent(StudentBuilder.Default().WithName("Alice", "A").Build())
|
|
.WithStudent(StudentBuilder.Default().WithName("Bob", "B").Build())
|
|
.WithStudent(StudentBuilder.Default().WithName("Carol", "C").Build())
|
|
.WithStudent(StudentBuilder.Default().WithName("David", "D").Build())
|
|
.WithStudent(StudentBuilder.Default().WithName("Eve", "E").Build())
|
|
.Build();
|
|
|
|
// Act
|
|
var warning = rule.Validate(team, config);
|
|
|
|
// Assert
|
|
Assert.That(warning, Is.Not.Null);
|
|
Assert.That(warning!.Code, Is.EqualTo("TEAM_SIZE_TOO_LARGE"));
|
|
Assert.That(warning.Message, Does.Contain("5 members"));
|
|
Assert.That(warning.Message, Does.Contain("max: 3"));
|
|
}
|
|
|
|
[Test]
|
|
public void TeamSizeTooLargeRule_IndividualEvent_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var config = new ValidationConfiguration { TeamSizeSeverity = ValidationSeverity.Warning };
|
|
var rule = new TeamSizeTooLargeRule();
|
|
|
|
var flight = EventDefinitionBuilder.Individual("Flight").Build();
|
|
var team = TeamBuilder.Default()
|
|
.ForEvent(flight)
|
|
.WithStudent(StudentBuilder.Default().Build())
|
|
.Build();
|
|
|
|
// Act
|
|
var warning = rule.Validate(team, config);
|
|
|
|
// Assert
|
|
Assert.That(warning, Is.Null);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AppliesTo Tests
|
|
|
|
[Test]
|
|
public void TeamRules_ApplyToCorrectContexts()
|
|
{
|
|
// Arrange
|
|
var rules = new IValidationRule<Team>[]
|
|
{
|
|
new MissingCaptainRule(),
|
|
new TeamSizeTooSmallRule(),
|
|
new TeamSizeTooLargeRule()
|
|
};
|
|
|
|
// Act & Assert - all team rules should apply to Team context only
|
|
foreach (var rule in rules)
|
|
{
|
|
Assert.That(rule.AppliesTo(ValidationContext.Team), Is.True,
|
|
$"{rule.GetType().Name} should apply to Team");
|
|
Assert.That(rule.AppliesTo(ValidationContext.StudentRanking), Is.False,
|
|
$"{rule.GetType().Name} should not apply to StudentRanking");
|
|
Assert.That(rule.AppliesTo(ValidationContext.StudentAssignment), Is.False,
|
|
$"{rule.GetType().Name} should not apply to StudentAssignment");
|
|
Assert.That(rule.AppliesTo(ValidationContext.StudentRegistration), Is.False,
|
|
$"{rule.GetType().Name} should not apply to StudentRegistration");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|