Store leftover CSV columns on hidden student notes, move catalog import to /events/import, and persist Students index columns from Chapter Settings. Co-authored-by: Cursor <cursoragent@cursor.com>
197 lines
7.0 KiB
C#
197 lines
7.0 KiB
C#
using System.Text;
|
|
using Core.Notes;
|
|
using Core.Parsers;
|
|
using Tests.Builders;
|
|
|
|
namespace Tests.Parsers;
|
|
|
|
[TestFixture]
|
|
public class StudentNotesFieldParser_Tests
|
|
{
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
BuilderExtensions.ResetAllBuilders();
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_MatchesStudentAndReportsUnmatched()
|
|
{
|
|
var aria = StudentBuilder.Create("Aria", "Chittenden").Build();
|
|
const string csv = """
|
|
Student Name,Interview Time,Application
|
|
"Chittenden, Aria",3:20-3:35,x
|
|
Nobody Here,1:00-1:15,x
|
|
""";
|
|
|
|
var result = Parse(csv, [aria]);
|
|
|
|
Assert.That(result.IsSuccess, Is.True);
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(result.Matches[0].Student, Is.SameAs(aria));
|
|
Assert.That(result.Matches[0].Merge.Changed, Is.True);
|
|
Assert.That(result.Issues, Has.Count.EqualTo(1));
|
|
Assert.That(result.Issues[0].RawStudentName, Is.EqualTo("Nobody Here"));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_SameExistingNote_HasNoChanges()
|
|
{
|
|
var aria = StudentBuilder.Create("Aria", "Chittenden").Build();
|
|
var existing = ImportedFieldsTable.Merge(null,
|
|
[
|
|
new ImportedField("Interview Time", "3:20-3:35"),
|
|
new ImportedField("Application", "Yes")
|
|
]).Markdown;
|
|
|
|
const string csv = """
|
|
Student Name,Interview Time,Application
|
|
Aria Chittenden,3:20-3:35,x
|
|
""";
|
|
|
|
var result = Parse(csv, [aria], new Dictionary<int, string?> { [aria.Id] = existing });
|
|
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(result.Matches[0].Merge.Changed, Is.False);
|
|
Assert.That(result.StudentsWithChanges, Is.EqualTo(0));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_MissingStudentNameColumn_IsError()
|
|
{
|
|
var aria = StudentBuilder.Create("Aria", "Chittenden").Build();
|
|
const string csv = """
|
|
Name,Interview Time
|
|
Aria Chittenden,3:20-3:35
|
|
""";
|
|
|
|
var result = Parse(csv, [aria]);
|
|
|
|
Assert.That(result.IsSuccess, Is.False);
|
|
Assert.That(result.Errors, Has.Some.Contains("Student Name"));
|
|
Assert.That(result.Matches, Is.Empty);
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_PreservesFieldsNotInCsv()
|
|
{
|
|
var aria = StudentBuilder.Create("Aria", "Chittenden").Build();
|
|
var existing = ImportedFieldsTable.Merge(null,
|
|
[
|
|
new ImportedField("Interview Time", "1:00-1:15"),
|
|
new ImportedField("Teacher Rec 1", "Fuqua")
|
|
]).Markdown;
|
|
|
|
const string csv = """
|
|
Student Name,Interview Time
|
|
Aria Chittenden,3:20-3:35
|
|
""";
|
|
|
|
var result = Parse(csv, [aria], new Dictionary<int, string?> { [aria.Id] = existing });
|
|
var fields = ImportedFieldsTable.ParseFields(result.Matches[0].Merge.Markdown);
|
|
|
|
Assert.That(result.Matches[0].Merge.Changed, Is.True);
|
|
Assert.That(fields.Single(f => f.Name == "Interview Time").Value, Is.EqualTo("3:20-3:35"));
|
|
Assert.That(fields.Single(f => f.Name == "Teacher Rec 1").Value, Is.EqualTo("Fuqua"));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_X_BecomesYes_AndBlankFieldsRoundTrip()
|
|
{
|
|
var aria = StudentBuilder.Create("Aria", "Chittenden").Build();
|
|
const string csv = """
|
|
Student Name,Application,Teacher Rec 3
|
|
Aria Chittenden,x,
|
|
""";
|
|
|
|
var first = Parse(csv, [aria]);
|
|
var markdown = first.Matches[0].Merge.Markdown;
|
|
|
|
Assert.That(ImportedFieldsTable.GetFieldValue(markdown, "Application"), Is.EqualTo("Yes"));
|
|
Assert.That(ImportedFieldsTable.GetFieldValue(markdown, "Teacher Rec 3"), Is.EqualTo(string.Empty));
|
|
|
|
var second = Parse(csv, [aria], new Dictionary<int, string?> { [aria.Id] = markdown });
|
|
Assert.That(second.Matches[0].Merge.Changed, Is.False);
|
|
Assert.That(second.StudentsWithChanges, Is.EqualTo(0));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_DuplicateStudentRows_LastValueWins_OneMatch()
|
|
{
|
|
var aria = StudentBuilder.Create("Aria", "Chittenden").Build();
|
|
const string csv = """
|
|
Student Name,Interview Time,Teacher Rec 1
|
|
Aria Chittenden,1:00-1:15,Fuqua
|
|
"Chittenden, Aria",3:20-3:35,Young
|
|
""";
|
|
|
|
var result = Parse(csv, [aria]);
|
|
var fields = ImportedFieldsTable.ParseFields(result.Matches[0].Merge.Markdown);
|
|
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(fields.Single(f => f.Name == "Interview Time").Value, Is.EqualTo("3:20-3:35"));
|
|
Assert.That(fields.Single(f => f.Name == "Teacher Rec 1").Value, Is.EqualTo("Young"));
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_NameOnlyCsv_WarnsAndMatchesWithoutFieldChanges()
|
|
{
|
|
var aria = StudentBuilder.Create("Aria", "Chittenden").Build();
|
|
const string csv = """
|
|
Student Name
|
|
Aria Chittenden
|
|
""";
|
|
|
|
var result = Parse(csv, [aria]);
|
|
|
|
Assert.That(result.IsSuccess, Is.True);
|
|
Assert.That(result.Warnings, Has.Some.Contains("No leftover field columns"));
|
|
Assert.That(result.Matches, Has.Count.EqualTo(1));
|
|
Assert.That(result.Matches[0].Merge.Changed, Is.False);
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_ExcludesRosterAndRankingColumns()
|
|
{
|
|
var aria = StudentBuilder.Create("Aria", "Chittenden").Build();
|
|
const string csv = """
|
|
Student Name,Grade,TSA year,State ID,Regional ID,National ID,Officer,1,2,TOTAL # OF EVENTS,Interview Time,Application
|
|
Aria Chittenden,6,1st,,,,,Coding,JSS,2,3:20-3:35,x
|
|
""";
|
|
|
|
var result = Parse(csv, [aria]);
|
|
var fields = ImportedFieldsTable.ParseFields(result.Matches[0].Merge.Markdown);
|
|
|
|
Assert.That(result.FieldNames, Is.EquivalentTo(["Interview Time", "Application"]));
|
|
Assert.That(fields.Select(f => f.Name), Is.EquivalentTo(["Interview Time", "Application"]));
|
|
Assert.That(fields.Single(f => f.Name == "Application").Value, Is.EqualTo("Yes"));
|
|
Assert.That(fields.Any(f => f.Name is "Grade" or "1" or "Officer"), Is.False);
|
|
}
|
|
|
|
[Test]
|
|
public void Parse_RosterOnlyCsv_HasNoLeftoverFields()
|
|
{
|
|
var aria = StudentBuilder.Create("Aria", "Chittenden").Build();
|
|
const string csv = """
|
|
Student Name,Grade,TSA year,State ID,Regional ID,National ID
|
|
Aria Chittenden,6,1st,,,
|
|
""";
|
|
|
|
var result = Parse(csv, [aria]);
|
|
|
|
Assert.That(result.FieldNames, Is.Empty);
|
|
Assert.That(result.Matches[0].Merge.Changed, Is.False);
|
|
Assert.That(result.Warnings, Has.Some.Contains("No leftover field columns"));
|
|
}
|
|
|
|
private static Core.Models.StudentNotesImportResult Parse(
|
|
string csv,
|
|
ICollection<Core.Entities.Student> students,
|
|
IReadOnlyDictionary<int, string?>? notes = null)
|
|
{
|
|
using var reader = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(csv)));
|
|
using var parser = new StudentNotesFieldParser(reader);
|
|
return parser.Parse(students, notes ?? new Dictionary<int, string?>());
|
|
}
|
|
}
|