Enhance event occurrence parsing to skip unmatched high school section headers

This commit introduces a new property to track skipped high school section headers in the EventOccurrenceParseResult and EventOccurrenceParserResult classes. The EventOccurrenceParser has been updated to gracefully skip HS section headers that do not match any event definitions, improving the parsing logic. Additionally, the LocationParsingConfiguration has been removed from the EventOccurrenceParser, simplifying its constructor. Unit tests have been updated to reflect these changes and ensure correct behavior during parsing.
This commit is contained in:
2026-01-09 00:14:19 -05:00
parent f916cfad6b
commit 19e5ef0675
10 changed files with 279 additions and 372 deletions
@@ -156,18 +156,19 @@ public class EventOccurrenceParserIssues_Tests
}
[Test]
public void Parse_LocationParseFailure_ReportsIssue()
public void Parse_LocationExtraction_WorksWithoutPatterns()
{
// Arrange
// Locations that don't match "Room *" or "Hall *" patterns
// The timeLocationRegex needs to match to extract location, so we need valid time format
var testContent = "Test Event March 15 2:00 p.m. Auditorium A\n" + // Doesn't match Room * or Hall *
"Test Event March 15 3:00 p.m. Room 101\n" + // This should match "Room *"
"Test Event March 15 4:00 p.m. Conference Center"; // Doesn't match any pattern
// Test that locations are extracted correctly without pattern matching
// Locations should be extracted as everything after the time
var testContent = "Test Event - MS\n" +
"Submit Entry March 15 2:00 p.m. Auditorium A\n" +
"Judging March 15 3:00 p.m. Room 101\n" +
"Pick-up March 15 4:00 p.m. Conference Center\n" +
"Final March 15 5:00 p.m."; // No location
var tempFile = EventOccurrenceParserTestHelpers.CreateTempFile(testContent);
var events = new[] { EventOccurrenceParserTestHelpers.CreateTestEvent("Test Event") };
var locationConfig = EventOccurrenceParserTestHelpers.CreateLocationConfig("Room *", "Hall *");
var parser = new EventOccurrenceParser(tempFile, events, locationConfig);
var parser = new EventOccurrenceParser(tempFile, events);
try
{
@@ -175,32 +176,16 @@ public class EventOccurrenceParserIssues_Tests
var result = parser.Parse();
// Assert
// Should have location parse failures for unmatched locations
// Note: Location issues are only reported when:
// 1. Time/location regex matches (can extract location)
// 2. Location part is not empty
// 3. Patterns are configured
// 4. No pattern matches
var locationIssues = result.Issues.Where(i => i.IssueType == ParsingIssueType.LocationParseFailure).ToList();
// Should parse successfully - location parsing no longer uses patterns, locations are extracted as-is
// Verify that locations are extracted correctly without pattern validation
// The parser should report location parse failures for "Auditorium A" and "Conference Center"
// But only if the timeLocationRegex successfully extracts them as locations
if (locationIssues.Any())
{
foreach (var issue in locationIssues)
{
Assert.That(issue.Message, Does.Contain("does not match any configured pattern"));
}
// Verify that "Room 101" was parsed successfully (no issue for it)
Assert.That(locationIssues, Has.None.Matches<ParsingIssue>(i => i.LineContent.Contains("Room 101")));
}
else
{
// If no location issues, it might be because the regex didn't extract locations properly
// This is still a valid test - we're verifying the parser behavior
Assert.Pass("Location parsing may not extract locations in all cases - this is acceptable behavior");
}
// Verify that locations are extracted correctly
var occurrences = result.Occurrences.Values.SelectMany(list => list).ToList();
Assert.That(occurrences, Has.Count.GreaterThan(0), "Should parse at least some occurrences");
// Verify locations are extracted
var locations = occurrences.Select(eo => eo.Location).Where(loc => !string.IsNullOrWhiteSpace(loc)).ToList();
Assert.That(locations, Has.Count.GreaterThan(0), "Should extract at least some locations");
}
finally
{
@@ -216,12 +201,11 @@ public class EventOccurrenceParserIssues_Tests
"Unknown Event March 15 2:00 p.m. Room 101\n" + // MissingEventDefinition
"Test Event February 30 2:00 p.m. Room 101\n" + // DateParseFailure (invalid date)
"Test Event March 15 invalid time format Room 101\n" + // TimeParseFailure (no AM/PM)
"Test Event March 15 3:00 p.m. Unmatched Location\n" + // LocationParseFailure (if location extracted)
"Test Event March 15 3:00 p.m. Unmatched Location\n" + // Location extracted as-is (no validation)
"Valid Event March 20 4:00 p.m. Room 202"; // Valid line
var tempFile = EventOccurrenceParserTestHelpers.CreateTempFile(testContent);
var events = new[] { EventOccurrenceParserTestHelpers.CreateTestEvent("Valid Event"), EventOccurrenceParserTestHelpers.CreateTestEvent("Test Event") };
var locationConfig = EventOccurrenceParserTestHelpers.CreateLocationConfig("Room *");
var parser = new EventOccurrenceParser(tempFile, events, locationConfig);
var parser = new EventOccurrenceParser(tempFile, events);
try
{
@@ -349,9 +333,8 @@ public class EventOccurrenceParserIssues_Tests
EventOccurrenceParserTestHelpers.CreateTestEvent("Test Event"),
EventOccurrenceParserTestHelpers.CreateTestEvent("Another Event")
};
// All locations match the patterns
var locationConfig = EventOccurrenceParserTestHelpers.CreateLocationConfig("Room *", "Hall *");
var parser = new EventOccurrenceParser(tempFile, events, locationConfig);
// Locations are extracted without pattern matching
var parser = new EventOccurrenceParser(tempFile, events);
try
{
@@ -378,26 +361,15 @@ public class EventOccurrenceParserIssues_Tests
// Note: If the test event wasn't parsed, it might be due to location parsing or other edge cases
// The important thing is that the parser doesn't crash and processes the input
// Verify no location parse failures for locations that match patterns
// Note: Location parsing only reports failures when:
// 1. Location is successfully extracted from time/location string
// 2. Patterns are configured
// 3. No pattern matches
// If location isn't extracted, no issue is created (which is also acceptable)
var locationIssues = result.Issues.Where(i => i.IssueType == ParsingIssueType.LocationParseFailure).ToList();
// Verify that locations that match patterns don't create issues
// "Room 101" should match "Room *", "Hall A" and "Hall B" should match "Hall *"
// Note: The parser might create location issues if the location extraction doesn't work perfectly,
// but we verify that at least the test event lines don't create false positives
var locationIssuesForTestEvents = locationIssues.Where(i =>
i.LineContent.Contains("Test Event") && i.LineContent.Contains("Room 101") ||
i.LineContent.Contains("Another Event") && i.LineContent.Contains("Hall B")).ToList();
// The important thing is that matching locations for our test events don't create false positives
// "Opening Session" might have different behavior since it's in GeneralSchedule section
Assert.That(locationIssuesForTestEvents, Has.Count.EqualTo(0),
"Should have no location parse failures for test event locations that match configured patterns");
// Verify locations are extracted correctly (pattern matching is no longer used)
var testEventOccurrence = result.Occurrences.ContainsKey(testEvent)
? result.Occurrences[testEvent].FirstOrDefault()
: null;
if (testEventOccurrence != null)
{
Assert.That(testEventOccurrence.Location, Is.EqualTo("Room 101"),
"Location should be extracted correctly without pattern matching");
}
}
finally
{
@@ -419,8 +391,7 @@ public class EventOccurrenceParserIssues_Tests
// For General Schedule section, we don't need a specific event definition
// The parser will use EventDefinition.GeneralSchedule
var events = Array.Empty<EventDefinition>();
var locationConfig = EventOccurrenceParserTestHelpers.CreateLocationConfig("Mtg. Room *", "Room *");
var parser = new EventOccurrenceParser(tempFile, events, locationConfig);
var parser = new EventOccurrenceParser(tempFile, events);
try
{
@@ -477,14 +448,13 @@ public class EventOccurrenceParserIssues_Tests
var months = new[] { "January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December" };
var events = new[] { EventOccurrenceParserTestHelpers.CreateTestEvent("Test Event") };
var locationConfig = EventOccurrenceParserTestHelpers.CreateLocationConfig("Room *");
foreach (var month in months)
{
var testContent = $"Test Event MS\n" +
$"Submit Entry {month} 15 3:00 p.m. Room A";
var tempFile = EventOccurrenceParserTestHelpers.CreateTempFile(testContent);
var parser = new EventOccurrenceParser(tempFile, events, locationConfig);
var parser = new EventOccurrenceParser(tempFile, events);
try
{