Files
chapter-organizer/Tests/Validation/Rules/StudentAssignmentRulesTests.cs
poprhythm 45edcf5e5f Refactor event assignment structure and introduce new models for assignment parameters and requirements
This commit removes the obsolete EventAssignment class from Core.Entities and introduces new models in Core.Models, including AssignmentParameters, AssignmentRequirement, PartialTeam, and StudentEventStatistics. The changes enhance the organization of assignment-related data and improve the overall structure of the codebase. Additionally, several files have been updated to include references to the new Core.Models namespace, ensuring consistency across the application.
2026-01-10 18:36:52 -05:00

442 lines
13 KiB
C#

using Core.Entities;
using Core.Models;
using Core.Validation;
using Core.Validation.Rules.StudentAssignmentRules;
using Tests.Builders;
namespace Tests.Validation.Rules;
[TestFixture]
public class StudentAssignmentRulesTests
{
private Student _testStudent;
[SetUp]
public void SetUp()
{
BuilderExtensions.ResetAllBuilders();
_testStudent = StudentBuilder.Default().WithName("Test", "Student").Build();
}
#region TooFewEventsRule Tests
[Test]
public void TooFewEventsRule_AboveMinimum_ReturnsNull()
{
// Arrange
var config = new ValidationConfiguration { MinRecommendedEvents = 2 };
var rule = new TooFewEventsRule();
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = new List<EventDefinition>
{
EventDefinitionBuilder.Individual("Flight").Build(),
EventDefinitionBuilder.Individual("Coding").Build(),
EventDefinitionBuilder.Individual("Speech").Build()
}
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Null);
}
[Test]
public void TooFewEventsRule_BelowMinimum_ReturnsWarning()
{
// Arrange
var config = new ValidationConfiguration
{
MinRecommendedEvents = 3,
MinCriticalEvents = 1,
EventCountSeverity = ValidationSeverity.Warning
};
var rule = new TooFewEventsRule();
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = new List<EventDefinition>
{
EventDefinitionBuilder.Individual("Flight").Build()
}
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Not.Null);
Assert.That(warning!.Code, Is.EqualTo("TOO_FEW_EVENTS"));
Assert.That(warning.Message, Does.Contain("1 events"));
Assert.That(warning.Message, Does.Contain("min recommended: 3"));
Assert.That(warning.Severity, Is.EqualTo(ValidationSeverity.Warning));
}
[Test]
public void TooFewEventsRule_BelowCritical_EscalatesToError()
{
// Arrange
var config = new ValidationConfiguration
{
MinRecommendedEvents = 3,
MinCriticalEvents = 2,
EventCountSeverity = ValidationSeverity.Warning
};
var rule = new TooFewEventsRule();
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = new List<EventDefinition>
{
EventDefinitionBuilder.Individual("Flight").Build()
}
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Not.Null);
Assert.That(warning!.Severity, Is.EqualTo(ValidationSeverity.Error),
"Should escalate to Error when below critical threshold");
}
#endregion
#region TooManyEventsRule Tests
[Test]
public void TooManyEventsRule_BelowMaximum_ReturnsNull()
{
// Arrange
var config = new ValidationConfiguration { MaxRecommendedEvents = 4 };
var rule = new TooManyEventsRule();
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = new List<EventDefinition>
{
EventDefinitionBuilder.Individual("Event1").Build(),
EventDefinitionBuilder.Individual("Event2").Build(),
EventDefinitionBuilder.Individual("Event3").Build()
}
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Null);
}
[Test]
public void TooManyEventsRule_AboveMaximum_ReturnsWarning()
{
// Arrange
var config = new ValidationConfiguration
{
MaxRecommendedEvents = 3,
MaxCriticalEvents = 6,
EventCountSeverity = ValidationSeverity.Warning
};
var rule = new TooManyEventsRule();
var events = new List<EventDefinition>();
for (int i = 0; i < 5; i++)
{
events.Add(EventDefinitionBuilder.Individual($"Event{i}").Build());
}
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = events
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Not.Null);
Assert.That(warning!.Code, Is.EqualTo("TOO_MANY_EVENTS"));
Assert.That(warning.Message, Does.Contain("5 events"));
Assert.That(warning.Message, Does.Contain("max recommended: 3"));
Assert.That(warning.Severity, Is.EqualTo(ValidationSeverity.Warning));
}
[Test]
public void TooManyEventsRule_AboveCritical_EscalatesToError()
{
// Arrange
var config = new ValidationConfiguration
{
MaxRecommendedEvents = 4,
MaxCriticalEvents = 6,
EventCountSeverity = ValidationSeverity.Warning
};
var rule = new TooManyEventsRule();
var events = new List<EventDefinition>();
for (int i = 0; i < 7; i++)
{
events.Add(EventDefinitionBuilder.Individual($"Event{i}").Build());
}
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = events
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Not.Null);
Assert.That(warning!.Severity, Is.EqualTo(ValidationSeverity.Error),
"Should escalate to Error when above critical threshold");
}
[Test]
public void TooManyEventsRule_ContainsMetadata()
{
// Arrange
var config = new ValidationConfiguration
{
MaxRecommendedEvents = 2,
MaxCriticalEvents = 5
};
var rule = new TooManyEventsRule();
var events = new List<EventDefinition>();
for (int i = 0; i < 4; i++)
{
events.Add(EventDefinitionBuilder.Individual($"Event{i}").Build());
}
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = events
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Not.Null);
Assert.That(warning!.Metadata, Contains.Key("MaxRecommended"));
Assert.That(warning.Metadata, Contains.Key("MaxCritical"));
Assert.That(warning.Metadata["MaxRecommended"], Is.EqualTo(2));
Assert.That(warning.Metadata["MaxCritical"], Is.EqualTo(5));
}
#endregion
#region NoRegionalEventAssignmentRule Tests
[Test]
public void NoRegionalEventAssignmentRule_HasRegionalEvent_ReturnsNull()
{
// Arrange
var config = new ValidationConfiguration { RequireRegionalEvent = true };
var rule = new NoRegionalEventAssignmentRule();
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = new List<EventDefinition>
{
EventDefinitionBuilder.Individual("Flight").AsRegionalEvent().Build()
}
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Null);
}
[Test]
public void NoRegionalEventAssignmentRule_LacksRegionalEvent_ReturnsWarning()
{
// Arrange
var config = new ValidationConfiguration
{
RequireRegionalEvent = true,
NoRegionalEventSeverity = ValidationSeverity.Warning
};
var rule = new NoRegionalEventAssignmentRule();
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = new List<EventDefinition>
{
EventDefinitionBuilder.Individual("Coding").Build()
}
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Not.Null);
Assert.That(warning!.Code, Is.EqualTo("NO_REGIONAL_EVENT_ASSIGNED"));
Assert.That(warning.Context, Is.EqualTo(ValidationContext.StudentAssignment));
}
#endregion
#region NoOnSiteActivityAssignmentRule Tests
[Test]
public void NoOnSiteActivityAssignmentRule_HasOnSiteActivity_ReturnsNull()
{
// Arrange
var config = new ValidationConfiguration { RequireOnSiteActivity = true };
var rule = new NoOnSiteActivityAssignmentRule();
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = new List<EventDefinition>
{
EventDefinitionBuilder.Individual("Speech").AsOnSite().Build()
}
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Null);
}
[Test]
public void NoOnSiteActivityAssignmentRule_LacksOnSiteActivity_ReturnsWarning()
{
// Arrange
var config = new ValidationConfiguration
{
RequireOnSiteActivity = true,
NoOnSiteActivitySeverity = ValidationSeverity.Error
};
var rule = new NoOnSiteActivityAssignmentRule();
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = new List<EventDefinition>
{
EventDefinitionBuilder.Individual("Flight").Build()
}
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Not.Null);
Assert.That(warning!.Code, Is.EqualTo("NO_ONSITE_ACTIVITY_ASSIGNED"));
Assert.That(warning.Severity, Is.EqualTo(ValidationSeverity.Error));
}
#endregion
#region TooManyRegionalEventsAssignmentRule Tests
[Test]
public void TooManyRegionalEventsAssignmentRule_WithinLimit_ReturnsNull()
{
// Arrange
var config = new ValidationConfiguration { MaxRegionalEvents = 3 };
var rule = new TooManyRegionalEventsAssignmentRule();
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = new List<EventDefinition>
{
EventDefinitionBuilder.Individual("Flight").AsRegionalEvent().Build(),
EventDefinitionBuilder.Individual("Coding").AsRegionalEvent().Build()
}
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Null);
}
[Test]
public void TooManyRegionalEventsAssignmentRule_ExceedsLimit_ReturnsWarning()
{
// Arrange
var config = new ValidationConfiguration
{
MaxRegionalEvents = 2,
TooManyRegionalEventsSeverity = ValidationSeverity.Warning
};
var rule = new TooManyRegionalEventsAssignmentRule();
var stats = new StudentEventStatistics
{
Student = _testStudent,
Events = new List<EventDefinition>
{
EventDefinitionBuilder.Individual("Flight").AsRegionalEvent().Build(),
EventDefinitionBuilder.Individual("Coding").AsRegionalEvent().Build(),
EventDefinitionBuilder.Individual("Essays").AsRegionalEvent().Build()
}
};
// Act
var warning = rule.Validate(stats, config);
// Assert
Assert.That(warning, Is.Not.Null);
Assert.That(warning!.Code, Is.EqualTo("TOO_MANY_REGIONAL_EVENTS"));
Assert.That(warning.Message, Does.Contain("3 regional events"));
}
#endregion
#region AppliesTo Tests
[Test]
public void AssignmentRules_ApplyToCorrectContexts()
{
// Arrange
var rules = new IValidationRule<StudentEventStatistics>[]
{
new TooFewEventsRule(),
new TooManyEventsRule(),
new NoRegionalEventAssignmentRule(),
new NoOnSiteActivityAssignmentRule(),
new TooManyRegionalEventsAssignmentRule()
};
// Act & Assert - all assignment rules should apply to these contexts
foreach (var rule in rules)
{
Assert.That(rule.AppliesTo(ValidationContext.StudentAssignment), Is.True,
$"{rule.GetType().Name} should apply to StudentAssignment");
Assert.That(rule.AppliesTo(ValidationContext.StudentRegistration), Is.True,
$"{rule.GetType().Name} should apply to StudentRegistration");
Assert.That(rule.AppliesTo(ValidationContext.StudentRanking), Is.False,
$"{rule.GetType().Name} should not apply to StudentRanking");
Assert.That(rule.AppliesTo(ValidationContext.Team), Is.False,
$"{rule.GetType().Name} should not apply to Team");
}
}
#endregion
}