Skip to content

Commit

Permalink
feat: flex - forbidden_real_time_booking_field_value validation not…
Browse files Browse the repository at this point in the history
…ice (#1845)
  • Loading branch information
cka-y committed Sep 24, 2024
1 parent 9b83e21 commit 9b60fff
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 1 deletion.
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

0 comments on commit 9b60fff

Please sign in to comment.