using Core.Calculation; using Core.Entities; using Core.Models; using Tests.Builders; using Tests.Fixtures; using EventAssignment = Core.Calculation.EventAssignment; namespace Tests.Calculation; [TestFixture] public class EventAssignmentTests { [SetUp] public void SetUp() { BuilderExtensions.ResetAllBuilders(); } [Test] public async Task SolutionTest() { // Create custom test data with sufficient rankings for EventAssignment // Need enough events and rankings to satisfy the default parameters: // - 2-4 events per student // - 6-8 effort points per student // - At least 1 regional event // - At least 1 on-site activity var flight = EventDefinitionBuilder.Individual("Flight").AsRegionalEvent().Build(); var coding = EventDefinitionBuilder.Individual("Coding").AsRegionalEvent().Build(); var speech = EventDefinitionBuilder.Individual("Prepared Speech").AsOnSite().Build(); var photo = EventDefinitionBuilder.Individual("Digital Photography").Build(); var essays = EventDefinitionBuilder.Individual("Essays on Technology").Build(); var robotics = EventDefinitionBuilder.Team("Robotics", 2, 5).AsRegionalEvent().AsOnSite().Build(); var biotech = EventDefinitionBuilder.Team("Biotechnology", 2, 6).AsRegionalEvent().Build(); var webDesign = EventDefinitionBuilder.Team("Website Design", 3, 6).Build(); var videoGame = EventDefinitionBuilder.Team("Video Game Design", 2, 6).Build(); var engineering = EventDefinitionBuilder.Team("Engineering Design", 3, 6).AsOnSite().Build(); var events = new[] { flight, coding, speech, photo, essays, robotics, biotech, webDesign, videoGame, engineering }; // Create students with diverse rankings (each ranks 7-8 events) var alice = StudentBuilder.Default() .WithName("Alice", "A").WithGrade(9) .WithRanking(flight, 1).WithRanking(robotics, 2).WithRanking(biotech, 3) .WithRanking(speech, 4).WithRanking(webDesign, 5).WithRanking(coding, 6) .WithRanking(videoGame, 7) .Build(); var bob = StudentBuilder.Default() .WithName("Bob", "B").WithGrade(10) .WithRanking(coding, 1).WithRanking(engineering, 2).WithRanking(robotics, 3) .WithRanking(speech, 4).WithRanking(biotech, 5).WithRanking(photo, 6) .WithRanking(videoGame, 7) .Build(); var carol = StudentBuilder.Default() .WithName("Carol", "C").WithGrade(11) .WithRanking(photo, 1).WithRanking(webDesign, 2).WithRanking(engineering, 3) .WithRanking(speech, 4).WithRanking(biotech, 5).WithRanking(flight, 6) .WithRanking(coding, 7) .Build(); var david = StudentBuilder.Default() .WithName("David", "D").WithGrade(9) .WithRanking(essays, 1).WithRanking(robotics, 2).WithRanking(videoGame, 3) .WithRanking(engineering, 4).WithRanking(speech, 5).WithRanking(coding, 6) .WithRanking(biotech, 7) .Build(); var eve = StudentBuilder.Default() .WithName("Eve", "E").WithGrade(10) .WithRanking(flight, 1).WithRanking(webDesign, 2).WithRanking(engineering, 3) .WithRanking(robotics, 4).WithRanking(photo, 5).WithRanking(coding, 6) .WithRanking(speech, 7) .Build(); var frank = StudentBuilder.Default() .WithName("Frank", "F").WithGrade(11) .WithRanking(coding, 1).WithRanking(biotech, 2).WithRanking(videoGame, 3) .WithRanking(speech, 4).WithRanking(webDesign, 5).WithRanking(flight, 6) .WithRanking(robotics, 7) .Build(); var students = new[] { alice, bob, carol, david, eve, frank }; // Use relaxed parameters for test var parameters = new AssignmentParameters( effortLowerBound: 4, effortUpperBound: 7, eventsLowerBound: 2, eventsUpperBound: 4, requireRegional: false, // Relax for test simplicity requireOnSite: false // Relax for test simplicity ); var eventAssignment = new EventAssignment(events, students, parameters); var solution = await eventAssignment.Solve(); // Verify solution Assert.That(solution.Teams, Is.Not.Null); Assert.That(solution.Status, Is.EqualTo("Optimal").Or.EqualTo("Feasible"), $"Solution should be Optimal or Feasible, but was {solution.Status}"); // Print solution summary for verification Console.WriteLine($"Solution Status: {solution.Status}"); Console.WriteLine($"Teams Created: {solution.Teams.Length}"); Console.WriteLine($"Students Assigned: {solution.Teams.SelectMany(t => t.Students).Distinct().Count()}"); // Verify each team has valid structure foreach (var team in solution.Teams) { Assert.That(team.Event, Is.Not.Null, $"Team should have an event"); Assert.That(team.Students, Is.Not.Empty, $"Team for {team.Event.Name} should have students"); } } [Test] public async Task SolutionTest_WithMinimalData() { // Test with minimal custom data to verify basic functionality var flight = EventDefinitionBuilder.Individual("Flight").Build(); var coding = EventDefinitionBuilder.Individual("Coding").Build(); var robotics = EventDefinitionBuilder.Team("Robotics", 2, 5).AsRegionalEvent().Build(); var biotech = EventDefinitionBuilder.Team("Biotechnology", 2, 6).AsRegionalEvent().Build(); var events = new[] { flight, coding, robotics, biotech }; var alice = StudentBuilder.Default() .WithName("Alice", "A") .WithGrade(9) .WithRanking(flight, 1) .WithRanking(robotics, 2) .WithRanking(biotech, 3) .Build(); var bob = StudentBuilder.Default() .WithName("Bob", "B") .WithGrade(10) .WithRanking(coding, 1) .WithRanking(robotics, 2) .WithRanking(biotech, 3) .Build(); var carol = StudentBuilder.Default() .WithName("Carol", "C") .WithGrade(11) .WithRanking(flight, 2) .WithRanking(biotech, 1) .WithRanking(robotics, 3) .Build(); var students = new[] { alice, bob, carol }; // Run the event assignment algorithm with minimal data var parameters = new AssignmentParameters( effortLowerBound: 2, effortUpperBound: 4, eventsLowerBound: 2, eventsUpperBound: 3, requireRegional: false, requireOnSite: false ); var eventAssignment = new EventAssignment(events, students, parameters); var solution = await eventAssignment.Solve(); // Verify solution Assert.That(solution.Status, Is.EqualTo("Optimal").Or.EqualTo("Feasible")); Assert.That(solution.Teams, Is.Not.Empty, "Should create some teams"); Console.WriteLine($"Minimal Test - Status: {solution.Status}"); Console.WriteLine($"Teams: {solution.Teams.Length}"); } }