Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: flex - forbidden_real_time_booking_field_value validation notice #1845

Merged
merged 3 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.mobilitydata.gtfsvalidator.validator;

import java.util.ArrayList;
import java.util.List;
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice;
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice.FileRefs;
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.notice.SeverityLevel;
import org.mobilitydata.gtfsvalidator.notice.ValidationNotice;
import org.mobilitydata.gtfsvalidator.table.GtfsBookingRules;
import org.mobilitydata.gtfsvalidator.table.GtfsBookingRulesSchema;
import org.mobilitydata.gtfsvalidator.table.GtfsBookingType;

@GtfsValidator
public class BookingRulesEntityValidator extends SingleEntityValidator<GtfsBookingRules> {

@Override
public void validate(GtfsBookingRules entity, NoticeContainer noticeContainer) {
// Only validate entities with REALTIME booking type
if (entity.bookingType() != GtfsBookingType.REALTIME) {
return;
}

// Retrieve the list of forbidden fields
List<String> forbiddenFields = findForbiddenRealTimeFields(entity);

// If there are any forbidden fields, add a validation notice
if (!forbiddenFields.isEmpty()) {
noticeContainer.addValidationNotice(
new ForbiddenRealTimeBookingFieldValueNotice(entity, forbiddenFields));
}
}

/** Finds forbidden fields that should not be present for real-time booking rules. */
public static List<String> findForbiddenRealTimeFields(GtfsBookingRules bookingRule) {
List<String> fields = new ArrayList<>();

// Check each field and add its name to the list if it's present
if (bookingRule.hasPriorNoticeDurationMin()) {
fields.add(GtfsBookingRules.PRIOR_NOTICE_DURATION_MIN_FIELD_NAME);
}
if (bookingRule.hasPriorNoticeDurationMax()) {
fields.add(GtfsBookingRules.PRIOR_NOTICE_DURATION_MAX_FIELD_NAME);
}
if (bookingRule.hasPriorNoticeLastDay()) {
fields.add(GtfsBookingRules.PRIOR_NOTICE_LAST_DAY_FIELD_NAME);
}
if (bookingRule.hasPriorNoticeLastTime()) {
fields.add(GtfsBookingRules.PRIOR_NOTICE_LAST_TIME_FIELD_NAME);
}
if (bookingRule.hasPriorNoticeStartDay()) {
fields.add(GtfsBookingRules.PRIOR_NOTICE_START_DAY_FIELD_NAME);
}
if (bookingRule.hasPriorNoticeStartTime()) {
fields.add(GtfsBookingRules.PRIOR_NOTICE_START_TIME_FIELD_NAME);
}
if (bookingRule.hasPriorNoticeServiceId()) {
fields.add(GtfsBookingRules.PRIOR_NOTICE_SERVICE_ID_FIELD_NAME);
}

return fields;
}

/** A forbidden field value is present for a real-time booking rule in `booking_rules.txt`. */
@GtfsValidationNotice(
severity = SeverityLevel.ERROR,
files = @FileRefs(GtfsBookingRulesSchema.class))
static class ForbiddenRealTimeBookingFieldValueNotice extends ValidationNotice {
/** The row number of the faulty record. */
private final int csvRowNumber;

/** The `booking_rules.booking_rule_id` of the faulty record. */
private final String bookingRuleId;

/** The names of the forbidden fields comma-separated. */
private final String fieldNames;

ForbiddenRealTimeBookingFieldValueNotice(
GtfsBookingRules bookingRule, List<String> forbiddenFields) {
this.csvRowNumber = bookingRule.csvRowNumber();
this.bookingRuleId = bookingRule.bookingRuleId();
this.fieldNames = String.join(", ", forbiddenFields);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.mobilitydata.gtfsvalidator.validator;

import static com.google.common.truth.Truth.assertThat;
import static org.mobilitydata.gtfsvalidator.table.GtfsBookingType.REALTIME;

import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.notice.ValidationNotice;
import org.mobilitydata.gtfsvalidator.table.GtfsBookingRules;
import org.mobilitydata.gtfsvalidator.table.GtfsBookingType;
import org.mobilitydata.gtfsvalidator.type.GtfsTime;
import org.mobilitydata.gtfsvalidator.validator.BookingRulesEntityValidator.ForbiddenRealTimeBookingFieldValueNotice;

@RunWith(JUnit4.class)
public class BookingRulesEntityValidatorTest {

private static List<ValidationNotice> generateNotices(GtfsBookingRules bookingRule) {
NoticeContainer noticeContainer = new NoticeContainer();
BookingRulesEntityValidator validator = new BookingRulesEntityValidator();
validator.validate(bookingRule, noticeContainer);
return noticeContainer.getValidationNotices();
}

@Test
public void realTimeBookingWithForbiddenFieldsShouldGenerateNotice() {
GtfsBookingRules bookingRule =
new GtfsBookingRules.Builder()
.setCsvRowNumber(1)
.setBookingRuleId("rule-1")
.setBookingType(REALTIME)
.setPriorNoticeDurationMin(30) // Forbidden field
.setPriorNoticeLastDay(2) // Forbidden field
.build();

assertThat(generateNotices(bookingRule))
.containsExactly(
new ForbiddenRealTimeBookingFieldValueNotice(
bookingRule,
List.of(
GtfsBookingRules.PRIOR_NOTICE_DURATION_MIN_FIELD_NAME,
GtfsBookingRules.PRIOR_NOTICE_LAST_DAY_FIELD_NAME)));
}

@Test
public void realTimeBookingWithoutForbiddenFieldsShouldNotGenerateNotice() {
GtfsBookingRules bookingRule =
new GtfsBookingRules.Builder()
.setCsvRowNumber(1)
.setBookingRuleId("rule-2")
.setBookingType(REALTIME)
.build();

assertThat(generateNotices(bookingRule)).isEmpty();
}

@Test
public void scheduledBookingShouldNotGenerateNotice() {
GtfsBookingRules bookingRule =
new GtfsBookingRules.Builder()
.setCsvRowNumber(1)
.setBookingRuleId("rule-3")
.setBookingType(GtfsBookingType.SAMEDAY)
.build();

assertThat(generateNotices(bookingRule)).isEmpty();
}

@Test
public void realTimeBookingWithMultipleForbiddenFieldsShouldGenerateNotice() {
GtfsBookingRules bookingRule =
new GtfsBookingRules.Builder()
.setCsvRowNumber(1)
.setBookingRuleId("rule-4")
.setBookingType(REALTIME)
.setPriorNoticeDurationMax(60) // Forbidden field
.setPriorNoticeStartTime(GtfsTime.fromSecondsSinceMidnight(2)) // Forbidden field
.setPriorNoticeServiceId("service-1") // Forbidden field
.build();

assertThat(generateNotices(bookingRule))
.containsExactly(
new ForbiddenRealTimeBookingFieldValueNotice(
bookingRule,
List.of(
GtfsBookingRules.PRIOR_NOTICE_DURATION_MAX_FIELD_NAME,
GtfsBookingRules.PRIOR_NOTICE_START_TIME_FIELD_NAME,
GtfsBookingRules.PRIOR_NOTICE_SERVICE_ID_FIELD_NAME)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,9 @@ public void testNoticeClassFieldNames() {
"pathwayMode",
"isBidirectional",
"locationGroupId",
"locationId");
"locationId",
"bookingRuleId",
"fieldNames");
}

private static List<String> discoverValidationNoticeFieldNames() {
Expand Down
Loading