Keep legal first and last names for formal lists; show DisplayFirstName on teams, calendars, and import matching so two Josiahs can be told apart. Co-authored-by: Cursor <cursoragent@cursor.com>
276 lines
10 KiB
C#
276 lines
10 KiB
C#
using System.Text;
|
|
using Core.Entities;
|
|
using Core.Models;
|
|
using Core.Parsers;
|
|
using Tests.Builders;
|
|
|
|
namespace Tests.Parsers;
|
|
|
|
[TestFixture]
|
|
public class StudentEventRankingParser_Tests
|
|
{
|
|
private Student _aria = null!;
|
|
private EventDefinition _videoGame = null!;
|
|
private EventDefinition _coding = null!;
|
|
private EventDefinition _jss = null!;
|
|
private EventDefinition _digitalPhoto = null!;
|
|
private EventDefinition _biotech = null!;
|
|
private EventDefinition _inventions = null!;
|
|
private EventDefinition _techBowl = null!;
|
|
private EventDefinition _techDesign = null!;
|
|
private List<Student> _students = null!;
|
|
private List<EventDefinition> _events = null!;
|
|
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
BuilderExtensions.ResetAllBuilders();
|
|
|
|
_aria = StudentBuilder.Create("Aria", "Chittenden").Build();
|
|
_videoGame = EventDefinitionBuilder.Team("Video Game Design", 2, 6).WithShortName("Video Game").Build();
|
|
_coding = EventDefinitionBuilder.Team("Coding", 2, 2).WithShortName("Coding").Build();
|
|
_jss = EventDefinitionBuilder.Team("Junior Solar Sprint", 2, 4).WithShortName("JSS").Build();
|
|
_digitalPhoto = EventDefinitionBuilder.Individual("Digital Photography").WithShortName("Digital Photo").Build();
|
|
_biotech = EventDefinitionBuilder.Team("Biotechnology", 2, 6).WithShortName("Biotech").Build();
|
|
_inventions = EventDefinitionBuilder.Team("Inventions & Innovations", 3, 6).WithShortName("I&I").Build();
|
|
_techBowl = EventDefinitionBuilder.Team("Tech Bowl", 3, 3).WithShortName("Tech Bowl").Build();
|
|
_techDesign = EventDefinitionBuilder.Team("Technical Design", 2, 2).WithShortName("Tech Design").Build();
|
|
|
|
_students = [_aria];
|
|
_events = [_videoGame, _coding, _jss, _digitalPhoto, _biotech, _inventions, _techBowl, _techDesign];
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_LastCommaFirst_MatchesStudent()
|
|
{
|
|
var result = ParseCsv("""
|
|
Student Name,1
|
|
"Chittenden, Aria",Coding
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.IsSuccess, Is.True);
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(result.Matches[0].Ranking.Student, Is.SameAs(_aria));
|
|
Assert.That(result.Matches[0].Ranking.EventDefinition, Is.SameAs(_coding));
|
|
Assert.That(result.Matches[0].Ranking.Rank, Is.EqualTo(1));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_FirstLast_MatchesStudent()
|
|
{
|
|
var result = ParseCsv("""
|
|
Student Name,1
|
|
Aria Chittenden,Coding
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.IsSuccess, Is.True);
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(result.Matches[0].Ranking.Student, Is.SameAs(_aria));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_NicknamePlusLastName_MatchesStudent()
|
|
{
|
|
var jo = StudentBuilder.Create("Josiah", "Brown").WithNickname("Jo").Build();
|
|
|
|
var result = ParseCsv("""
|
|
Student Name,1
|
|
Jo Brown,Coding
|
|
""", [jo], _events);
|
|
|
|
Assert.That(result.IsSuccess, Is.True);
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(result.Matches[0].Ranking.Student, Is.SameAs(jo));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_ShortName_MatchesEvent()
|
|
{
|
|
var result = ParseCsv("""
|
|
Student Name,1,2,3
|
|
Aria Chittenden,Video Game,JSS,I&I
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.Issues, Is.Empty);
|
|
Assert.That(result.Matches, Has.Count.EqualTo(3));
|
|
Assert.That(result.Matches.Select(m => m.Ranking.EventDefinition), Is.EqualTo(new[] { _videoGame, _jss, _inventions }));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_NearMissFullName_MatchesEvent()
|
|
{
|
|
var result = ParseCsv("""
|
|
Student Name,1
|
|
Aria Chittenden,Digital Photo
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(result.Matches[0].Ranking.EventDefinition, Is.SameAs(_digitalPhoto));
|
|
Assert.That(result.Matches[0].EventScore, Is.GreaterThanOrEqualTo(StudentEventRankingParser.EventMatchThreshold));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_BiotechShortName_MatchesBiotechnology()
|
|
{
|
|
var result = ParseCsv("""
|
|
Student Name,1
|
|
Aria Chittenden,Biotech
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(result.Matches[0].Ranking.EventDefinition, Is.SameAs(_biotech));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_UnmatchedStudent_IsReported()
|
|
{
|
|
var result = ParseCsv("""
|
|
Student Name,1
|
|
Nobody Here,Coding
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.Matches, Is.Empty);
|
|
Assert.That(result.Issues, Has.Count.EqualTo(1));
|
|
Assert.That(result.Issues[0].IssueType, Is.EqualTo(StudentEventRankingIssueType.UnmatchedStudent));
|
|
Assert.That(result.Issues[0].RawStudentName, Is.EqualTo("Nobody Here"));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_SolarRacer_MatchesJuniorSolarSprint()
|
|
{
|
|
var result = ParseCsv("""
|
|
Student Name,1
|
|
Aria Chittenden,Solar Racer
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.Issues, Is.Empty);
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(result.Matches[0].Ranking.EventDefinition, Is.SameAs(_jss));
|
|
}
|
|
|
|
[TestCase("Solar Racer", "Junior Solar Sprint")]
|
|
[TestCase("Solar Race", "Junior Solar Sprint")]
|
|
[TestCase("Challenging Tech", "Challenging Technology Issues")]
|
|
[TestCase("Digital Photo", "Digital Photography")]
|
|
[TestCase("Forensics", "Forensic Technology")]
|
|
[TestCase("Micro Controller", "Microcontroller Design")]
|
|
[TestCase("Med Tech", "Medical Technology")]
|
|
[TestCase("Innovations & Inventions", "Inventions & Innovations")]
|
|
[TestCase("Inventions and Innovations", "Inventions & Innovations")]
|
|
[TestCase("Systems Control Tech", "System Control Technology")]
|
|
[TestCase("Systems Control Technology", "System Control Technology")]
|
|
[TestCase("Structural Eng", "Structural Engineering")]
|
|
[TestCase("Drone Challenge", "Drone Challenge (UAV)")]
|
|
[TestCase("Robotics", "TSA Robotics")]
|
|
[TestCase("Audio Podcast", "Audio Podcasting")]
|
|
public void Parse_KnownAlias_MatchesOfficialEvent(string alias, string officialName)
|
|
{
|
|
var events = TestEntityHandler.GetEvents().ToList();
|
|
events.AddRange(
|
|
[
|
|
EventDefinitionBuilder.Team("Drone Challenge (UAV)", 2, 6).WithShortName("Drone").Build(),
|
|
EventDefinitionBuilder.Team("TSA Robotics", 2, 6).WithShortName("Robotics").Build(),
|
|
EventDefinitionBuilder.Team("Audio Podcasting", 2, 6).WithShortName("Podcasting").Build()
|
|
]);
|
|
|
|
var result = ParseCsv($"""
|
|
Student Name,1
|
|
Aria Chittenden,{alias}
|
|
""", _students, events);
|
|
|
|
Assert.That(result.Issues, Is.Empty, $"Expected '{alias}' to match '{officialName}'");
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(result.Matches[0].Ranking.EventDefinition.Name, Is.EqualTo(officialName));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_UnmatchedEvent_IsReported()
|
|
{
|
|
var result = ParseCsv("""
|
|
Student Name,1
|
|
Aria Chittenden,Underwater Basket Weaving
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.Matches, Is.Empty);
|
|
Assert.That(result.Issues, Has.Count.EqualTo(1));
|
|
Assert.That(result.Issues[0].IssueType, Is.EqualTo(StudentEventRankingIssueType.UnmatchedEvent));
|
|
Assert.That(result.Issues[0].RawEventName, Is.EqualTo("Underwater Basket Weaving"));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_AmbiguousEvent_IsReported()
|
|
{
|
|
var result = ParseCsv("""
|
|
Student Name,1
|
|
Aria Chittenden,Tech
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.Matches, Is.Empty);
|
|
Assert.That(result.Issues, Has.Count.EqualTo(1));
|
|
Assert.That(result.Issues[0].IssueType, Is.EqualTo(StudentEventRankingIssueType.AmbiguousEvent));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_RankColumnsBeyondSix_AreRead()
|
|
{
|
|
var result = ParseCsv("""
|
|
Student Name,1,2,3,4,5,6,7
|
|
Aria Chittenden,Coding,,,,,,JSS
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.Matches, Has.Count.EqualTo(2));
|
|
Assert.That(result.Matches.Select(m => m.Ranking.Rank), Is.EqualTo(new[] { 1, 7 }));
|
|
Assert.That(result.Matches[1].Ranking.EventDefinition, Is.SameAs(_jss));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_DuplicateEvent_IsReported()
|
|
{
|
|
var result = ParseCsv("""
|
|
Student Name,1,2
|
|
Aria Chittenden,Coding,Coding
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(result.Issues, Has.Count.EqualTo(1));
|
|
Assert.That(result.Issues[0].IssueType, Is.EqualTo(StudentEventRankingIssueType.DuplicateEvent));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_MissingStudentNameHeader_IsError()
|
|
{
|
|
var result = ParseCsv("""
|
|
Name,1
|
|
Aria Chittenden,Coding
|
|
""", _students, _events);
|
|
|
|
Assert.That(result.IsSuccess, Is.False);
|
|
Assert.That(result.Errors, Is.Not.Empty);
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_2024RankingsFile_MatchesKnownStudentsAndEvents()
|
|
{
|
|
var events = TestEntityHandler.GetEvents();
|
|
var students = TestEntityHandler.GetStudents(events);
|
|
var rankings = TestEntityHandler.GetStudentEventRankings(students, events);
|
|
|
|
Assert.That(students, Has.Length.EqualTo(29));
|
|
Assert.That(rankings, Is.Not.Empty);
|
|
Assert.That(rankings.Select(r => r.Student.FirstNameLastName).Distinct().Count(), Is.EqualTo(29));
|
|
Assert.That(rankings.All(r => r.EventDefinition is not null), Is.True);
|
|
Assert.That(rankings.All(r => r.Rank is >= 1 and <= 10), Is.True);
|
|
Assert.That(rankings.Count(r => r.Student.FirstName == "First26"), Is.EqualTo(7));
|
|
}
|
|
|
|
private static StudentEventRankingParseResult ParseCsv(
|
|
string csv,
|
|
ICollection<Student> students,
|
|
ICollection<EventDefinition> events)
|
|
{
|
|
using var reader = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(csv)));
|
|
using var parser = new StudentEventRankingParser(reader);
|
|
return parser.Parse(students, events);
|
|
}
|
|
}
|