diff --git a/Tests/Builders/AssignmentRequirementBuilder.cs b/Tests/Builders/AssignmentRequirementBuilder.cs
new file mode 100644
index 0000000..7fcc873
--- /dev/null
+++ b/Tests/Builders/AssignmentRequirementBuilder.cs
@@ -0,0 +1,69 @@
+using Core.Entities;
+
+namespace Tests.Builders;
+
+///
+/// Fluent builder for creating AssignmentRequirement test entities.
+///
+public class AssignmentRequirementBuilder
+{
+ private EventDefinition? _eventDefinition = null;
+ private Student? _student = null;
+ private Requirement _requirement = Requirement.Include;
+
+ public AssignmentRequirementBuilder ForEvent(EventDefinition eventDef)
+ {
+ _eventDefinition = eventDef;
+ return this;
+ }
+
+ public AssignmentRequirementBuilder ForStudent(Student student)
+ {
+ _student = student;
+ return this;
+ }
+
+ public AssignmentRequirementBuilder AsInclude()
+ {
+ _requirement = Requirement.Include;
+ return this;
+ }
+
+ public AssignmentRequirementBuilder AsExclude()
+ {
+ _requirement = Requirement.Exclude;
+ return this;
+ }
+
+ public AssignmentRequirementBuilder WithRequirement(Requirement requirement)
+ {
+ _requirement = requirement;
+ return this;
+ }
+
+ public AssignmentRequirement Build()
+ {
+ if (_eventDefinition == null)
+ throw new InvalidOperationException("AssignmentRequirement must have an event. Call ForEvent() before Build().");
+
+ if (_student == null)
+ throw new InvalidOperationException("AssignmentRequirement must have a student. Call ForStudent() before Build().");
+
+ return new AssignmentRequirement(_eventDefinition, _student, _requirement);
+ }
+
+ // Static factory methods
+ public static AssignmentRequirementBuilder Default() => new AssignmentRequirementBuilder();
+
+ public static AssignmentRequirementBuilder Include(EventDefinition eventDef, Student student) =>
+ new AssignmentRequirementBuilder()
+ .ForEvent(eventDef)
+ .ForStudent(student)
+ .AsInclude();
+
+ public static AssignmentRequirementBuilder Exclude(EventDefinition eventDef, Student student) =>
+ new AssignmentRequirementBuilder()
+ .ForEvent(eventDef)
+ .ForStudent(student)
+ .AsExclude();
+}
diff --git a/Tests/Builders/BuilderExtensions.cs b/Tests/Builders/BuilderExtensions.cs
new file mode 100644
index 0000000..c7c8493
--- /dev/null
+++ b/Tests/Builders/BuilderExtensions.cs
@@ -0,0 +1,80 @@
+using Core.Entities;
+
+namespace Tests.Builders;
+
+///
+/// Helper utilities for working with test data builders.
+///
+public static class BuilderExtensions
+{
+ ///
+ /// Resets all builder ID counters to 1.
+ /// Call this in test SetUp to ensure test isolation.
+ ///
+ public static void ResetAllBuilders()
+ {
+ EventDefinitionBuilder.ResetIdCounter();
+ StudentBuilder.ResetIdCounter();
+ TeamBuilder.ResetIdCounter();
+ }
+
+ ///
+ /// Creates a student with event rankings for multiple events.
+ ///
+ /// The student builder
+ /// Dictionary of events to their ranks (1-10)
+ /// The builder for method chaining
+ public static StudentBuilder WithRankings(this StudentBuilder builder, Dictionary rankedEvents)
+ {
+ foreach (var (eventDef, rank) in rankedEvents)
+ {
+ builder.WithRanking(eventDef, rank);
+ }
+ return builder;
+ }
+
+ ///
+ /// Creates a team with a captain as the first student.
+ ///
+ /// The team builder
+ /// Students to add (first one becomes captain)
+ /// The builder for method chaining
+ public static TeamBuilder WithStudentsAndCaptain(this TeamBuilder builder, params Student[] students)
+ {
+ if (students.Length == 0)
+ return builder;
+
+ builder.WithStudents(students);
+ builder.WithCaptain(students[0]);
+ return builder;
+ }
+
+ ///
+ /// Creates multiple event definitions at once.
+ ///
+ /// Event names
+ /// Array of individual event definitions
+ public static EventDefinition[] CreateIndividualEvents(params string[] names)
+ {
+ return names.Select(name => EventDefinitionBuilder.Individual(name).Build()).ToArray();
+ }
+
+ ///
+ /// Creates multiple students at once with sequential names.
+ ///
+ /// Number of students to create
+ /// Base first name (will be suffixed with numbers)
+ /// Base last name
+ /// Array of students
+ public static Student[] CreateStudents(int count, string baseFirstName = "Student", string baseLastName = "Test")
+ {
+ var students = new Student[count];
+ for (int i = 0; i < count; i++)
+ {
+ students[i] = StudentBuilder.Default()
+ .WithName($"{baseFirstName}{i + 1}", baseLastName)
+ .Build();
+ }
+ return students;
+ }
+}
diff --git a/Tests/Builders/EventDefinitionBuilder.cs b/Tests/Builders/EventDefinitionBuilder.cs
new file mode 100644
index 0000000..342dfbc
--- /dev/null
+++ b/Tests/Builders/EventDefinitionBuilder.cs
@@ -0,0 +1,178 @@
+using Core.Entities;
+
+namespace Tests.Builders;
+
+///
+/// Fluent builder for creating EventDefinition test entities.
+///
+public class EventDefinitionBuilder
+{
+ private static int _idCounter = 1;
+
+ private int _id = _idCounter++;
+ private string _name = "Test Event";
+ private string _shortName = "Test";
+ private EventFormat _format = EventFormat.Individual;
+ private int _minTeamSize = 1;
+ private int _maxTeamSize = 1;
+ private string? _semifinalistActivity = null;
+ private bool _onSiteActivity = false;
+ private int _regionalCount = 0;
+ private int _stateCount = 2;
+ private bool _presubmission = false;
+ private string _eligibility = "All students";
+ private string? _theme = null;
+ private string? _description = null;
+ private int? _levelOfEffort = null;
+ private string? _documentation = null;
+ private string? _notes = null;
+
+ public EventDefinitionBuilder WithName(string name)
+ {
+ _name = name;
+ if (_shortName == "Test") _shortName = name; // Auto-sync short name
+ return this;
+ }
+
+ public EventDefinitionBuilder WithShortName(string shortName)
+ {
+ _shortName = shortName;
+ return this;
+ }
+
+ public EventDefinitionBuilder AsTeamEvent(int minSize, int maxSize)
+ {
+ _format = EventFormat.Team;
+ _minTeamSize = minSize;
+ _maxTeamSize = maxSize;
+ return this;
+ }
+
+ public EventDefinitionBuilder AsIndividualEvent()
+ {
+ _format = EventFormat.Individual;
+ _minTeamSize = 1;
+ _maxTeamSize = 1;
+ return this;
+ }
+
+ public EventDefinitionBuilder WithInterview()
+ {
+ _semifinalistActivity = "Interview";
+ return this;
+ }
+
+ public EventDefinitionBuilder WithPresentation()
+ {
+ _semifinalistActivity = "Presentation";
+ return this;
+ }
+
+ public EventDefinitionBuilder WithSemifinalistActivity(string activity)
+ {
+ _semifinalistActivity = activity;
+ return this;
+ }
+
+ public EventDefinitionBuilder AsOnSite()
+ {
+ _onSiteActivity = true;
+ return this;
+ }
+
+ public EventDefinitionBuilder AsRegionalEvent(int count = 3)
+ {
+ _regionalCount = count;
+ return this;
+ }
+
+ public EventDefinitionBuilder WithStateCount(int count)
+ {
+ _stateCount = count;
+ return this;
+ }
+
+ public EventDefinitionBuilder WithPresubmission()
+ {
+ _presubmission = true;
+ return this;
+ }
+
+ public EventDefinitionBuilder WithEligibility(string eligibility)
+ {
+ _eligibility = eligibility;
+ return this;
+ }
+
+ public EventDefinitionBuilder WithTheme(string theme)
+ {
+ _theme = theme;
+ return this;
+ }
+
+ public EventDefinitionBuilder WithDescription(string description)
+ {
+ _description = description;
+ return this;
+ }
+
+ public EventDefinitionBuilder WithLevelOfEffort(int level)
+ {
+ _levelOfEffort = level;
+ return this;
+ }
+
+ public EventDefinitionBuilder WithDocumentation(string documentation)
+ {
+ _documentation = documentation;
+ return this;
+ }
+
+ public EventDefinitionBuilder WithNotes(string notes)
+ {
+ _notes = notes;
+ return this;
+ }
+
+ public EventDefinition Build()
+ {
+ return new EventDefinition
+ {
+ Id = _id,
+ Name = _name,
+ ShortName = _shortName,
+ EventFormat = _format,
+ MinTeamSize = _minTeamSize,
+ MaxTeamSize = _maxTeamSize,
+ SemifinalistActivity = _semifinalistActivity,
+ OnSiteActivity = _onSiteActivity,
+ ChapterEligibilityCountRegionals = _regionalCount,
+ ChapterEligibilityCountState = _stateCount,
+ Presubmission = _presubmission,
+ Eligibility = _eligibility,
+ Theme = _theme,
+ Description = _description,
+ LevelOfEffort = _levelOfEffort,
+ Documentation = _documentation,
+ Notes = _notes
+ };
+ }
+
+ // Static factory methods
+ public static EventDefinitionBuilder Default() => new EventDefinitionBuilder();
+
+ public static EventDefinitionBuilder Individual(string name) =>
+ new EventDefinitionBuilder()
+ .WithName(name)
+ .AsIndividualEvent();
+
+ public static EventDefinitionBuilder Team(string name, int minSize, int maxSize) =>
+ new EventDefinitionBuilder()
+ .WithName(name)
+ .AsTeamEvent(minSize, maxSize);
+
+ ///
+ /// Reset the ID counter for test isolation. Call this in test SetUp.
+ ///
+ public static void ResetIdCounter() => _idCounter = 1;
+}
diff --git a/Tests/Builders/StudentBuilder.cs b/Tests/Builders/StudentBuilder.cs
new file mode 100644
index 0000000..fca2292
--- /dev/null
+++ b/Tests/Builders/StudentBuilder.cs
@@ -0,0 +1,166 @@
+using Core.Entities;
+
+namespace Tests.Builders;
+
+///
+/// Fluent builder for creating Student test entities.
+///
+public class StudentBuilder
+{
+ private static int _idCounter = 1;
+
+ private int _id = _idCounter++;
+ private string _firstName = "Test";
+ private string _lastName = "Student";
+ private int _grade = 9;
+ private string? _email = null;
+ private string? _phoneNumber = null;
+ private int _tsaYear = 1;
+ private string? _stateId = null;
+ private string? _regionalId = null;
+ private string? _nationalId = null;
+ private OfficerRole? _officerRole = null;
+ private List<(EventDefinition eventDef, int rank)> _rankings = new();
+
+ public StudentBuilder WithName(string firstName, string lastName)
+ {
+ _firstName = firstName;
+ _lastName = lastName;
+ return this;
+ }
+
+ public StudentBuilder WithFirstName(string firstName)
+ {
+ _firstName = firstName;
+ return this;
+ }
+
+ public StudentBuilder WithLastName(string lastName)
+ {
+ _lastName = lastName;
+ return this;
+ }
+
+ public StudentBuilder WithGrade(int grade)
+ {
+ _grade = grade;
+ return this;
+ }
+
+ public StudentBuilder WithEmail(string email)
+ {
+ _email = email;
+ return this;
+ }
+
+ public StudentBuilder WithPhone(string phoneNumber)
+ {
+ _phoneNumber = phoneNumber;
+ return this;
+ }
+
+ public StudentBuilder WithTsaYear(int year)
+ {
+ _tsaYear = year;
+ return this;
+ }
+
+ public StudentBuilder WithStateId(string stateId)
+ {
+ _stateId = stateId;
+ return this;
+ }
+
+ public StudentBuilder WithRegionalId(string regionalId)
+ {
+ _regionalId = regionalId;
+ return this;
+ }
+
+ public StudentBuilder WithNationalId(string nationalId)
+ {
+ _nationalId = nationalId;
+ return this;
+ }
+
+ public StudentBuilder AsOfficer(OfficerRole role)
+ {
+ _officerRole = role;
+ return this;
+ }
+
+ public StudentBuilder AsPresident()
+ {
+ _officerRole = OfficerRole.President;
+ return this;
+ }
+
+ public StudentBuilder AsVicePresident()
+ {
+ _officerRole = OfficerRole.VicePresident;
+ return this;
+ }
+
+ public StudentBuilder AsSecretary()
+ {
+ _officerRole = OfficerRole.Secretary;
+ return this;
+ }
+
+ public StudentBuilder AsTreasurer()
+ {
+ _officerRole = OfficerRole.Treasurer;
+ return this;
+ }
+
+ public StudentBuilder WithRanking(EventDefinition eventDef, int rank)
+ {
+ _rankings.Add((eventDef, rank));
+ return this;
+ }
+
+ public Student Build()
+ {
+ var student = new Student
+ {
+ Id = _id,
+ FirstName = _firstName,
+ LastName = _lastName,
+ Grade = _grade,
+ Email = _email,
+ PhoneNumber = _phoneNumber,
+ TsaYear = _tsaYear,
+ StateId = _stateId,
+ RegionalId = _regionalId,
+ NationalId = _nationalId,
+ OfficerRole = _officerRole,
+ Teams = new List() // Initialize Teams collection
+ };
+
+ // Set up event rankings if any were specified
+ foreach (var (eventDef, rank) in _rankings)
+ {
+ var ranking = new StudentEventRanking
+ {
+ Student = student,
+ EventDefinition = eventDef,
+ Rank = rank
+ };
+ student.EventRankings.Add(ranking);
+ }
+
+ return student;
+ }
+
+ // Static factory methods
+ public static StudentBuilder Default() => new StudentBuilder();
+
+ public static StudentBuilder Create(string firstName, string lastName) =>
+ new StudentBuilder()
+ .WithName(firstName, lastName);
+
+ ///
+ /// Reset the ID counter for test isolation. Call this in test SetUp.
+ ///
+ public static void ResetIdCounter() => _idCounter = 1;
+}
diff --git a/Tests/Builders/StudentEventRankingBuilder.cs b/Tests/Builders/StudentEventRankingBuilder.cs
new file mode 100644
index 0000000..79e96d7
--- /dev/null
+++ b/Tests/Builders/StudentEventRankingBuilder.cs
@@ -0,0 +1,65 @@
+using Core.Entities;
+
+namespace Tests.Builders;
+
+///
+/// Fluent builder for creating StudentEventRanking test entities.
+///
+public class StudentEventRankingBuilder
+{
+ private Student? _student = null;
+ private EventDefinition? _eventDefinition = null;
+ private int _rank = 1;
+
+ public StudentEventRankingBuilder ForStudent(Student student)
+ {
+ _student = student;
+ return this;
+ }
+
+ public StudentEventRankingBuilder ForEvent(EventDefinition eventDef)
+ {
+ _eventDefinition = eventDef;
+ return this;
+ }
+
+ public StudentEventRankingBuilder WithRank(int rank)
+ {
+ if (rank < 1 || rank > StudentEventRanking.MaxRank)
+ throw new ArgumentOutOfRangeException(nameof(rank),
+ $"Rank must be between 1 and {StudentEventRanking.MaxRank}");
+
+ _rank = rank;
+ return this;
+ }
+
+ public StudentEventRanking Build()
+ {
+ if (_student == null)
+ throw new InvalidOperationException("StudentEventRanking must have a student. Call ForStudent() before Build().");
+
+ if (_eventDefinition == null)
+ throw new InvalidOperationException("StudentEventRanking must have an event. Call ForEvent() before Build().");
+
+ var ranking = new StudentEventRanking
+ {
+ Student = _student,
+ EventDefinition = _eventDefinition,
+ Rank = _rank
+ };
+
+ // Set up bidirectional relationship: add to student's EventRankings if not already there
+ if (!_student.EventRankings.Any(er => er.EventDefinition == _eventDefinition))
+ {
+ _student.EventRankings.Add(ranking);
+ }
+
+ return ranking;
+ }
+
+ // Static factory methods
+ public static StudentEventRankingBuilder Default() => new StudentEventRankingBuilder();
+
+ public static StudentEventRankingBuilder Create(Student student, EventDefinition eventDef) =>
+ new StudentEventRankingBuilder().ForStudent(student).ForEvent(eventDef);
+}
diff --git a/Tests/Builders/TeamBuilder.cs b/Tests/Builders/TeamBuilder.cs
new file mode 100644
index 0000000..d28f1bd
--- /dev/null
+++ b/Tests/Builders/TeamBuilder.cs
@@ -0,0 +1,100 @@
+using Core.Entities;
+
+namespace Tests.Builders;
+
+///
+/// Fluent builder for creating Team test entities.
+///
+public class TeamBuilder
+{
+ private static int _idCounter = 1;
+
+ private int _id = _idCounter++;
+ private EventDefinition? _event = null;
+ private List _students = new();
+ private Student? _captain = null;
+ private string? _identifier = null;
+
+ public TeamBuilder ForEvent(EventDefinition eventDef)
+ {
+ _event = eventDef;
+ return this;
+ }
+
+ public TeamBuilder WithStudent(Student student)
+ {
+ if (!_students.Contains(student))
+ _students.Add(student);
+ return this;
+ }
+
+ public TeamBuilder WithStudents(params Student[] students)
+ {
+ foreach (var student in students)
+ {
+ if (!_students.Contains(student))
+ _students.Add(student);
+ }
+ return this;
+ }
+
+ public TeamBuilder WithStudents(IEnumerable students)
+ {
+ foreach (var student in students)
+ {
+ if (!_students.Contains(student))
+ _students.Add(student);
+ }
+ return this;
+ }
+
+ public TeamBuilder WithCaptain(Student captain)
+ {
+ _captain = captain;
+ // Ensure captain is in the students list
+ if (!_students.Contains(captain))
+ _students.Add(captain);
+ return this;
+ }
+
+ public TeamBuilder WithIdentifier(string identifier)
+ {
+ _identifier = identifier;
+ return this;
+ }
+
+ public Team Build()
+ {
+ if (_event == null)
+ throw new InvalidOperationException("Team must have an event. Call ForEvent() before Build().");
+
+ var team = new Team
+ {
+ Id = _id,
+ Event = _event,
+ Students = _students.ToList(),
+ Captain = _captain,
+ Identifier = _identifier
+ };
+
+ // Set up bidirectional relationship: add team to each student's Teams collection
+ foreach (var student in _students)
+ {
+ if (!student.Teams.Contains(team))
+ student.Teams.Add(team);
+ }
+
+ return team;
+ }
+
+ // Static factory methods
+ public static TeamBuilder Default() => new TeamBuilder();
+
+ public static TeamBuilder Create(EventDefinition eventDef) =>
+ new TeamBuilder().ForEvent(eventDef);
+
+ ///
+ /// Reset the ID counter for test isolation. Call this in test SetUp.
+ ///
+ public static void ResetIdCounter() => _idCounter = 1;
+}
diff --git a/Tests/Calculation/DataProcessingTests.cs b/Tests/Calculation/DataProcessingTests.cs
index e99c6f5..8b584cb 100644
--- a/Tests/Calculation/DataProcessingTests.cs
+++ b/Tests/Calculation/DataProcessingTests.cs
@@ -1,19 +1,58 @@
using Core.Calculation;
-using Tests.Parsers;
+using Core.Entities;
+using Tests.Builders;
+using Tests.Fixtures;
namespace Tests.Calculation;
+
[TestFixture]
public class DataProcessingTests
{
+ [SetUp]
+ public void SetUp()
+ {
+ BuilderExtensions.ResetAllBuilders();
+ }
[Test]
public void GetEventStudentRankingsTest()
{
- var events = TestEntityHandler.GetEvents();
- var students = TestEntityHandler.GetStudents(events);
- var rankings = TestEntityHandler.GetStudentEventRankings(students, events);
+ // Create test data with explicit rankings
+ var flight = EventDefinitionBuilder.Individual("Flight").Build();
+ var coding = EventDefinitionBuilder.Individual("Coding").Build();
+ var robotics = EventDefinitionBuilder.Team("Robotics", 2, 5).Build();
- foreach (var ranking in rankings)
+ var alice = StudentBuilder.Default()
+ .WithName("Alice", "Anderson")
+ .WithGrade(9)
+ .WithRanking(flight, rank: 1)
+ .WithRanking(coding, rank: 2)
+ .WithRanking(robotics, rank: 3)
+ .Build();
+
+ var bob = StudentBuilder.Default()
+ .WithName("Bob", "Brown")
+ .WithGrade(10)
+ .WithRanking(coding, rank: 1)
+ .WithRanking(flight, rank: 3)
+ .Build();
+
+ // Verify rankings are accessible
+ Assert.That(alice.EventRankings, Has.Count.EqualTo(3));
+ Assert.That(bob.EventRankings, Has.Count.EqualTo(2));
+
+ // Verify rankings are correctly associated
+ var aliceFlightRanking = alice.EventRankings.First(r => r.EventDefinition == flight);
+ Assert.That(aliceFlightRanking.Rank, Is.EqualTo(1));
+ Assert.That(aliceFlightRanking.Student, Is.EqualTo(alice));
+
+ // Print rankings for verification (matching original test output)
+ var allRankings = new[] { alice, bob }
+ .SelectMany(s => s.EventRankings)
+ .OrderBy(r => r.EventDefinition.Name)
+ .ThenBy(r => r.Student.FirstName);
+
+ foreach (var ranking in allRankings)
{
Console.WriteLine(ranking.EventDefinition.Name);
Console.WriteLine($"{ranking.Student.FirstName}: {ranking.Rank}");
diff --git a/Tests/Calculation/EventAssignmentTests.cs b/Tests/Calculation/EventAssignmentTests.cs
index 4551b40..f1bdf4e 100644
--- a/Tests/Calculation/EventAssignmentTests.cs
+++ b/Tests/Calculation/EventAssignmentTests.cs
@@ -1,24 +1,175 @@
using Core.Calculation;
using Core.Entities;
-using Core.Parsers;
-using Tests.Parsers;
+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 void SolutionTest()
+ public async Task SolutionTest()
{
- var events = TestEntityHandler.GetEvents();
- var students = TestEntityHandler.GetStudents(events);
+ // 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 eventAssignment = new EventAssignment(events, students, new AssignmentParameters());
- var solution = eventAssignment.Solve().Result;
+ 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 teamWriter = new TeamWriter(solution.Teams, @"c:\temp\teams.csv");
- //teamWriter.Write();
+ 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}");
}
}
\ No newline at end of file
diff --git a/Tests/Calculation/TeamSchedulerTest.cs b/Tests/Calculation/TeamSchedulerTest.cs
index 8c598aa..bfd43c4 100644
--- a/Tests/Calculation/TeamSchedulerTest.cs
+++ b/Tests/Calculation/TeamSchedulerTest.cs
@@ -1,12 +1,19 @@
using Core.Calculation;
using Core.Entities;
-using Tests.Parsers;
+using Tests.Builders;
+using Tests.Fixtures;
namespace Tests.Calculation;
[TestFixture]
public class TeamSchedulerTest
{
+ [SetUp]
+ public void SetUp()
+ {
+ BuilderExtensions.ResetAllBuilders();
+ }
+
[Test]
public void Prototype_Test()
{
@@ -17,40 +24,57 @@ public class TeamSchedulerTest
[Test]
public void SolutionTest()
{
- var events = TestEntityHandler.GetEvents();
- var students = TestEntityHandler.GetStudents(events);
-
- var allTeams = TestEntityHandler.GetTeams(events, students);
- var teams = allTeams;
+ // Create test data with regional team events for TeamScheduler
+ var robotics = EventDefinitionBuilder.Team("Robotics", 2, 5).AsRegionalEvent().Build();
+ var biotech = EventDefinitionBuilder.Team("Biotechnology", 2, 6).AsRegionalEvent().Build();
+ var webDesign = EventDefinitionBuilder.Team("Website Design", 3, 6).AsRegionalEvent().Build();
+ var videoGame = EventDefinitionBuilder.Team("Video Game Design", 2, 6).AsRegionalEvent().Build();
+ var engineering = EventDefinitionBuilder.Team("Engineering Design", 3, 6).AsRegionalEvent().Build();
+ var cybersecurity = EventDefinitionBuilder.Team("Cybersecurity", 2, 6).AsRegionalEvent().Build();
- teams =
- (from e in events
- from t in teams
- where t.Event == e
- //&& t.Students.Count > 1
- && (e.EventFormat == EventFormat.Team && e.RegionalEvent)
- select t).ToArray();
- teams =
- teams.Where(t => !t.Event.Name.Contains("Tech Bowl")).ToArray();
+ var events = new[] { robotics, biotech, webDesign, videoGame, engineering, cybersecurity };
- //var eventAssignment = new EventAssignment(events, students);
- //var teams = eventAssignment.Solve();
+ // Create students
+ var alice = StudentBuilder.Default().WithName("Alice", "A").WithGrade(9).WithTsaYear(1).Build();
+ var bob = StudentBuilder.Default().WithName("Bob", "B").WithGrade(10).WithTsaYear(2).Build();
+ var carol = StudentBuilder.Default().WithName("Carol", "C").WithGrade(11).WithTsaYear(3).Build();
+ var david = StudentBuilder.Default().WithName("David", "D").WithGrade(9).WithTsaYear(1).Build();
+ var eve = StudentBuilder.Default().WithName("Eve", "E").WithGrade(10).WithTsaYear(2).Build();
+ var frank = StudentBuilder.Default().WithName("Frank", "F").WithGrade(11).WithTsaYear(3).Build();
+ var grace = StudentBuilder.Default().WithName("Grace", "G").WithGrade(9).WithTsaYear(1).Build();
+ var henry = StudentBuilder.Default().WithName("Henry", "H").WithGrade(10).WithTsaYear(2).Build();
- TeamSchedulerSolution solution;
- if (true)
+ var students = new[] { alice, bob, carol, david, eve, frank, grace, henry };
+
+ // Create teams with student assignments
+ var allTeams = new[]
{
- var teamScheduler = new TeamScheduler(teams, 3, students);
- solution = teamScheduler.Solve();
- }
- else
- {
- var teamScheduler = new TeamScheduler_DecisionTree(teams, 3);
- solution = teamScheduler.Solve();
- }
+ TeamBuilder.Default().ForEvent(robotics).WithStudentsAndCaptain(alice, bob, carol).WithIdentifier("Robotics A").Build(),
+ TeamBuilder.Default().ForEvent(biotech).WithStudentsAndCaptain(david, eve, frank).WithIdentifier("Biotech A").Build(),
+ TeamBuilder.Default().ForEvent(webDesign).WithStudentsAndCaptain(grace, henry, alice).WithIdentifier("WebDesign A").Build(),
+ TeamBuilder.Default().ForEvent(videoGame).WithStudentsAndCaptain(bob, david).WithIdentifier("VideoGame A").Build(),
+ TeamBuilder.Default().ForEvent(engineering).WithStudentsAndCaptain(carol, eve, frank).WithIdentifier("Engineering A").Build(),
+ TeamBuilder.Default().ForEvent(cybersecurity).WithStudentsAndCaptain(grace, henry).WithIdentifier("Cybersecurity A").Build()
+ };
- //solution = new UnassignedStudentScheduler(allTeams, solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.BiggestGroup);
- //solution = new UnassignedStudentScheduler(allTeams, solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.IndividualEvents);
+ // Filter to only regional team events (matching original test logic)
+ var teams = allTeams
+ .Where(t => t.Event.EventFormat == EventFormat.Team && t.Event.RegionalEvent)
+ .ToArray();
+ // Verify we have teams to schedule
+ Assert.That(teams, Is.Not.Empty, "Should have teams to schedule");
+
+ // Run TeamScheduler with 3 time slots
+ var teamScheduler = new TeamScheduler(teams, 3, students);
+ var solution = teamScheduler.Solve();
+
+ // Verify solution
+ Assert.That(solution, Is.Not.Null);
+ Assert.That(solution.TimeSlots, Is.Not.Null);
+ Assert.That(solution.TimeSlots.Length, Is.EqualTo(3), "Should have 3 time slots");
+
+ // Print solution (matching original test output format)
var i = 1;
foreach (var slot in solution.TimeSlots)
{
@@ -73,17 +97,10 @@ public class TeamSchedulerTest
}
var unassigned = UnassignedStudentScheduler.UnassignedStudents(students, slot.Teams).ToList();
-
+
if (unassigned.Any())
Console.WriteLine("\tunassigned");
Console.WriteLine($"\t\t{string.Join(", ", unassigned.Select(s => s.FirstName))}");
}
-
- //var allScheduledTeams = timeSlots.SelectMany(list => list).GroupBy(t => t.Name).SelectMany(g => g).Distinct();
- //foreach (var allScheduledTeam in allScheduledTeams.OrderBy(a => a.Name))
- //{
- // Console.WriteLine($"{allScheduledTeam.Name}");
- // Console.WriteLine($"\t{string.Join(", ", allScheduledTeam.Students.Select(s => s.FirstName))}");
- //}
}
}
\ No newline at end of file
diff --git a/Tests/Fixtures/TestDataFixtures.cs b/Tests/Fixtures/TestDataFixtures.cs
new file mode 100644
index 0000000..5e59270
--- /dev/null
+++ b/Tests/Fixtures/TestDataFixtures.cs
@@ -0,0 +1,287 @@
+using Core.Entities;
+using Tests.Builders;
+
+namespace Tests.Fixtures;
+
+///
+/// Pre-configured test data fixtures for different testing scenarios.
+///
+public static class TestDataFixtures
+{
+ ///
+ /// Small dataset for simple unit tests (5 events, 6 students, minimal teams).
+ ///
+ public static class Small
+ {
+ ///
+ /// Returns a small set of test data: 5 events, 6 students, and 3 teams.
+ /// Suitable for simple unit tests that don't require realistic volume.
+ ///
+ public static (EventDefinition[] Events, Student[] Students, Team[] Teams) Full()
+ {
+ BuilderExtensions.ResetAllBuilders();
+
+ var events = new[]
+ {
+ EventDefinitionBuilder.Individual("Flight").Build(),
+ EventDefinitionBuilder.Individual("Coding").Build(),
+ EventDefinitionBuilder.Team("Biotechnology", 2, 6).WithInterview().Build(),
+ EventDefinitionBuilder.Team("Robotics", 2, 5).AsOnSite().Build(),
+ EventDefinitionBuilder.Individual("Essays on Technology").Build()
+ };
+
+ var students = new[]
+ {
+ StudentBuilder.Default().WithName("Alice", "Anderson").WithGrade(9).Build(),
+ StudentBuilder.Default().WithName("Bob", "Brown").WithGrade(10).Build(),
+ StudentBuilder.Default().WithName("Carol", "Clark").WithGrade(11).Build(),
+ StudentBuilder.Default().WithName("David", "Davis").WithGrade(9).Build(),
+ StudentBuilder.Default().WithName("Eve", "Evans").WithGrade(10).Build(),
+ StudentBuilder.Default().WithName("Frank", "Foster").WithGrade(11).Build()
+ };
+
+ var teams = new[]
+ {
+ TeamBuilder.Default().ForEvent(events[2]) // Biotechnology
+ .WithStudentsAndCaptain(students[0], students[1])
+ .Build(),
+ TeamBuilder.Default().ForEvent(events[3]) // Robotics
+ .WithStudentsAndCaptain(students[2], students[3], students[4])
+ .Build(),
+ TeamBuilder.Default().ForEvent(events[0]) // Flight (individual)
+ .WithStudent(students[5])
+ .Build()
+ };
+
+ return (events, students, teams);
+ }
+
+ ///
+ /// Returns just events from the small fixture.
+ ///
+ public static EventDefinition[] Events()
+ {
+ BuilderExtensions.ResetAllBuilders();
+ return Full().Events;
+ }
+
+ ///
+ /// Returns just students from the small fixture.
+ ///
+ public static Student[] Students()
+ {
+ BuilderExtensions.ResetAllBuilders();
+ return Full().Students;
+ }
+ }
+
+ ///
+ /// Large dataset for algorithm tests requiring realistic volume (25 events, 18 students, 15+ teams).
+ ///
+ public static class Large
+ {
+ ///
+ /// Returns a realistic large set of test data: 25 events, 18 students, and 15+ teams.
+ /// Includes real TSA event names and realistic team configurations.
+ /// Suitable for testing algorithms like EventAssignment and TeamScheduler.
+ ///
+ public static (EventDefinition[] Events, Student[] Students, Team[] Teams) Full()
+ {
+ BuilderExtensions.ResetAllBuilders();
+
+ // Real TSA events with realistic configurations
+ var events = new[]
+ {
+ // Individual events (some are regional)
+ EventDefinitionBuilder.Individual("Architectural Design").WithStateCount(3).AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Individual("Biotechnology Design").WithInterview().AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Individual("Coding").WithStateCount(3).Build(),
+ EventDefinitionBuilder.Individual("Digital Photography").AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Individual("Essays on Technology").Build(),
+ EventDefinitionBuilder.Individual("Extemporaneous Speech").AsOnSite().Build(),
+ EventDefinitionBuilder.Individual("Flight").WithStateCount(3).AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Individual("Prepared Speech").AsOnSite().Build(),
+ EventDefinitionBuilder.Individual("Scientific Visualization").Build(),
+ EventDefinitionBuilder.Individual("System Control Technology").Build(),
+
+ // Team events (2-6 members, many are regional)
+ EventDefinitionBuilder.Team("Animatronics", 2, 6).WithInterview().AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Team("Chapter Team", 6, 6).WithPresentation().Build(),
+ EventDefinitionBuilder.Team("Cybersecurity", 2, 6).AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Team("Debate", 2, 2).AsOnSite().Build(),
+ EventDefinitionBuilder.Team("Dragster", 1, 3).AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Team("Engineering Design", 3, 6).WithInterview().AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Team("Fashion Design", 2, 6).WithInterview().AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Team("Forensic Technology", 2, 6).Build(),
+ EventDefinitionBuilder.Team("Future Technology Teacher", 2, 6).WithPresentation().AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Team("Junior Solar Sprint", 2, 3).AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Team("Music Production", 2, 6).WithInterview().AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Team("On Demand Video", 2, 6).Build(),
+ EventDefinitionBuilder.Team("Promotional Marketing", 1, 6).WithPresentation().Build(),
+ EventDefinitionBuilder.Team("Software Development", 2, 6).WithInterview().AsRegionalEvent().Build(),
+ EventDefinitionBuilder.Team("Video Game Design", 2, 6).WithInterview().AsRegionalEvent().Build()
+ };
+
+ // 18 students with varied grades and rankings
+ var students = new[]
+ {
+ StudentBuilder.Default().WithName("Alice", "Anderson").WithGrade(9).WithTsaYear(1).Build(),
+ StudentBuilder.Default().WithName("Bob", "Brown").WithGrade(10).WithTsaYear(2).Build(),
+ StudentBuilder.Default().WithName("Carol", "Clark").WithGrade(11).WithTsaYear(3).Build(),
+ StudentBuilder.Default().WithName("David", "Davis").WithGrade(9).WithTsaYear(1).Build(),
+ StudentBuilder.Default().WithName("Eve", "Evans").WithGrade(10).WithTsaYear(2).Build(),
+ StudentBuilder.Default().WithName("Frank", "Foster").WithGrade(11).WithTsaYear(3).Build(),
+ StudentBuilder.Default().WithName("Grace", "Garcia").WithGrade(9).WithTsaYear(1).Build(),
+ StudentBuilder.Default().WithName("Henry", "Harris").WithGrade(10).WithTsaYear(2).Build(),
+ StudentBuilder.Default().WithName("Ivy", "Irwin").WithGrade(11).WithTsaYear(3).Build(),
+ StudentBuilder.Default().WithName("Jack", "Johnson").WithGrade(9).WithTsaYear(1).Build(),
+ StudentBuilder.Default().WithName("Kelly", "King").WithGrade(10).WithTsaYear(2).Build(),
+ StudentBuilder.Default().WithName("Leo", "Lopez").WithGrade(11).WithTsaYear(3).Build(),
+ StudentBuilder.Default().WithName("Maria", "Martinez").WithGrade(9).WithTsaYear(1).Build(),
+ StudentBuilder.Default().WithName("Noah", "Nelson").WithGrade(10).WithTsaYear(2).Build(),
+ StudentBuilder.Default().WithName("Olivia", "O'Brien").WithGrade(11).WithTsaYear(3).Build(),
+ StudentBuilder.Default().WithName("Paul", "Patel").WithGrade(9).WithTsaYear(1).Build(),
+ StudentBuilder.Default().WithName("Quinn", "Quinn").WithGrade(10).WithTsaYear(2).Build(),
+ StudentBuilder.Default().WithName("Rachel", "Robinson").WithGrade(11).WithTsaYear(3).Build()
+ };
+
+ // Add event rankings for students (realistic preferences)
+ AddRankingsToStudent(students[0], events, new[] { 0, 2, 6, 10, 12 }); // Individual + teams
+ AddRankingsToStudent(students[1], events, new[] { 1, 3, 11, 13, 16 });
+ AddRankingsToStudent(students[2], events, new[] { 4, 5, 14, 17, 20 });
+ AddRankingsToStudent(students[3], events, new[] { 6, 7, 15, 18, 21 });
+ AddRankingsToStudent(students[4], events, new[] { 8, 9, 16, 19, 22 });
+ AddRankingsToStudent(students[5], events, new[] { 0, 2, 12, 20, 23 });
+ AddRankingsToStudent(students[6], events, new[] { 1, 3, 10, 13, 24 });
+ AddRankingsToStudent(students[7], events, new[] { 4, 5, 11, 14, 15 });
+ AddRankingsToStudent(students[8], events, new[] { 6, 7, 16, 17, 18 });
+ AddRankingsToStudent(students[9], events, new[] { 8, 9, 19, 21, 22 });
+ AddRankingsToStudent(students[10], events, new[] { 0, 10, 12, 14, 23 });
+ AddRankingsToStudent(students[11], events, new[] { 1, 11, 13, 15, 24 });
+ AddRankingsToStudent(students[12], events, new[] { 2, 12, 16, 18, 20 });
+ AddRankingsToStudent(students[13], events, new[] { 3, 13, 17, 19, 21 });
+ AddRankingsToStudent(students[14], events, new[] { 4, 14, 18, 20, 22 });
+ AddRankingsToStudent(students[15], events, new[] { 5, 15, 19, 21, 23 });
+ AddRankingsToStudent(students[16], events, new[] { 6, 16, 20, 22, 24 });
+ AddRankingsToStudent(students[17], events, new[] { 7, 10, 11, 12, 13 });
+
+ // Create representative teams (some will be created by algorithm tests)
+ var teams = new[]
+ {
+ TeamBuilder.Default().ForEvent(events[10]) // Animatronics
+ .WithStudentsAndCaptain(students[0], students[1], students[2])
+ .WithIdentifier("Team A")
+ .Build(),
+ TeamBuilder.Default().ForEvent(events[11]) // Chapter Team
+ .WithStudentsAndCaptain(students[3], students[4], students[5], students[6], students[7], students[8])
+ .WithIdentifier("Chapter")
+ .Build(),
+ TeamBuilder.Default().ForEvent(events[12]) // Cybersecurity
+ .WithStudentsAndCaptain(students[9], students[10])
+ .WithIdentifier("Team C")
+ .Build(),
+ TeamBuilder.Default().ForEvent(events[13]) // Debate
+ .WithStudentsAndCaptain(students[11], students[12])
+ .WithIdentifier("Team D")
+ .Build(),
+ TeamBuilder.Default().ForEvent(events[16]) // Fashion Design
+ .WithStudentsAndCaptain(students[13], students[14], students[15])
+ .WithIdentifier("Team F")
+ .Build(),
+ TeamBuilder.Default().ForEvent(events[24]) // Video Game Design
+ .WithStudentsAndCaptain(students[16], students[17])
+ .WithIdentifier("Team V")
+ .Build()
+ };
+
+ return (events, students, teams);
+ }
+
+ ///
+ /// Helper to add event rankings to a student.
+ ///
+ private static void AddRankingsToStudent(Student student, EventDefinition[] events, int[] eventIndices)
+ {
+ for (int i = 0; i < eventIndices.Length; i++)
+ {
+ var eventIndex = eventIndices[i];
+ if (eventIndex >= 0 && eventIndex < events.Length)
+ {
+ StudentEventRankingBuilder.Default()
+ .ForStudent(student)
+ .ForEvent(events[eventIndex])
+ .WithRank(i + 1)
+ .Build();
+ }
+ }
+ }
+
+ ///
+ /// Returns just events from the large fixture.
+ ///
+ public static EventDefinition[] Events()
+ {
+ BuilderExtensions.ResetAllBuilders();
+ return Full().Events;
+ }
+
+ ///
+ /// Returns just students from the large fixture.
+ ///
+ public static Student[] Students()
+ {
+ BuilderExtensions.ResetAllBuilders();
+ return Full().Students;
+ }
+ }
+
+ ///
+ /// Custom helpers for creating specific numbers of minimal test entities.
+ ///
+ public static class Custom
+ {
+ ///
+ /// Creates N simple individual events with generic names.
+ ///
+ public static EventDefinition[] MinimalEvents(int count)
+ {
+ BuilderExtensions.ResetAllBuilders();
+ var events = new EventDefinition[count];
+ for (int i = 0; i < count; i++)
+ {
+ events[i] = EventDefinitionBuilder.Individual($"Event{i + 1}").Build();
+ }
+ return events;
+ }
+
+ ///
+ /// Creates N simple students with sequential names.
+ ///
+ public static Student[] MinimalStudents(int count)
+ {
+ BuilderExtensions.ResetAllBuilders();
+ return BuilderExtensions.CreateStudents(count);
+ }
+
+ ///
+ /// Creates N simple teams for a given event.
+ ///
+ public static Team[] MinimalTeams(EventDefinition eventDef, int teamCount, int studentsPerTeam)
+ {
+ var allStudents = MinimalStudents(teamCount * studentsPerTeam);
+ var teams = new Team[teamCount];
+
+ for (int i = 0; i < teamCount; i++)
+ {
+ var teamStudents = allStudents.Skip(i * studentsPerTeam).Take(studentsPerTeam).ToArray();
+ teams[i] = TeamBuilder.Default().ForEvent(eventDef)
+ .WithStudents(teamStudents)
+ .WithCaptain(teamStudents[0])
+ .WithIdentifier($"Team{i + 1}")
+ .Build();
+ }
+
+ return teams;
+ }
+ }
+}