Skip to content

Commit

Permalink
fix: mark transfer from and to stop ids as conditional required fields (
Browse files Browse the repository at this point in the history
  • Loading branch information
davidgamez committed May 28, 2024
1 parent dda1918 commit d71580b
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@
@GtfsTable("transfers.txt")
public interface GtfsTransferSchema extends GtfsEntity {
@FieldType(FieldTypeEnum.ID)
@Required
@ConditionallyRequired
@ForeignKey(table = "stops.txt", field = "stop_id")
@PrimaryKey(translationRecordIdType = RECORD_ID)
String fromStopId();

@FieldType(FieldTypeEnum.ID)
@Required
@ConditionallyRequired
@ForeignKey(table = "stops.txt", field = "stop_id")
@PrimaryKey(translationRecordIdType = RECORD_SUB_ID)
String toStopId();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2024 MobilityData
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.mobilitydata.gtfsvalidator.validator;

import static org.mobilitydata.gtfsvalidator.table.GtfsTransferType.IN_SEAT_TRANSFER_ALLOWED;
import static org.mobilitydata.gtfsvalidator.table.GtfsTransferType.IN_SEAT_TRANSFER_NOT_ALLOWED;

import javax.inject.Inject;
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator;
import org.mobilitydata.gtfsvalidator.notice.MissingRequiredFieldNotice;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.table.GtfsTransfer;
import org.mobilitydata.gtfsvalidator.table.GtfsTransferTableContainer;

/**
* Validates the conditional requirement of {@code transfers.from_stop_id} and {@code to_stop_id}.
*
* <p>Generated notice:
*
* <ul>
* <li>{@link MissingRequiredFieldNotice} - {@code from_stop_id} is missing or {@code to_stop_id}
* is missing for all transfer types except for in-seat transfer types
* </ul>
*/
@GtfsValidator
public class TransferStopIdsConditionalValidator extends FileValidator {

private final GtfsTransferTableContainer transfersContainer;

@Inject
public TransferStopIdsConditionalValidator(GtfsTransferTableContainer transfersContainer) {
this.transfersContainer = transfersContainer;
}

@Override
public void validate(NoticeContainer noticeContainer) {
for (GtfsTransfer transfer : transfersContainer.getEntities()) {
if (transfer.hasTransferType()) {
validateTransferEntity(transfer, noticeContainer);
}
}
}

private boolean isTransferTypeInSeat(GtfsTransfer transfer) {
return IN_SEAT_TRANSFER_ALLOWED.equals(transfer.transferType())
|| IN_SEAT_TRANSFER_NOT_ALLOWED.equals(transfer.transferType());
}

private void validateTransferEntity(GtfsTransfer transfer, NoticeContainer noticeContainer) {
if (!isTransferTypeInSeat(transfer)) {
if (!transfer.hasFromStopId()) {
noticeContainer.addValidationNotice(
new MissingRequiredFieldNotice(
transfersContainer.gtfsFilename(), transfer.csvRowNumber(), "from_stop_id"));
}
if (!transfer.hasToStopId()) {
noticeContainer.addValidationNotice(
new MissingRequiredFieldNotice(
transfersContainer.gtfsFilename(), transfer.csvRowNumber(), "to_stop_id"));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package org.mobilitydata.gtfsvalidator.validator;

import static com.google.common.truth.Truth.assertThat;

import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.mobilitydata.gtfsvalidator.notice.MissingRequiredFieldNotice;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.table.GtfsTransfer;
import org.mobilitydata.gtfsvalidator.table.GtfsTransferTableContainer;
import org.mobilitydata.gtfsvalidator.table.GtfsTransferType;

public class TransferStopIdsConditionalValidatorTest {

private NoticeContainer noticeContainer;

@Before
public void setUp() {
noticeContainer = new NoticeContainer();
}

/**
* This test is used to verify that the validator does not generate a notice when the {@code
* from_stop_id} is missing for in-seat transfer types.
*/
@Test
public void testTransferFromStopIdNoInSeatTransferNoNotice() {
// In seat transfer types are 4 and 5, so we test for all other types
for (int i = 4; i <= 5; i++) {
GtfsTransferType transferType = GtfsTransferType.forNumber(i);
GtfsTransferTableContainer gtfsTransferTableContainer =
GtfsTransferTableContainer.forEntities(
ImmutableList.of(new GtfsTransfer.Builder().setTransferType(transferType).build()),
noticeContainer);

new TransferStopIdsConditionalValidator(gtfsTransferTableContainer).validate(noticeContainer);

assertThat(noticeContainer.getValidationNotices()).isEmpty();
noticeContainer.getValidationNotices().clear();
}
}

/**
* This test is used to verify that the validator generates a notice when the {@code from_stop_id}
* is missing for transfer types other than in-seat transfer types.
*/
@Test
public void testTransferMissingFromStopIdNoInSeatTransfer() {
for (int i = 0; i < 4; i++) {
GtfsTransferType transferType = GtfsTransferType.forNumber(i);
GtfsTransferTableContainer gtfsTransferTableContainer =
GtfsTransferTableContainer.forEntities(
ImmutableList.of(new GtfsTransfer.Builder().setTransferType(transferType).build()),
noticeContainer);

new TransferStopIdsConditionalValidator(gtfsTransferTableContainer).validate(noticeContainer);

assertThat(noticeContainer.getValidationNotices()).isNotEmpty();
assertThat(noticeContainer.getValidationNotices())
.containsExactlyElementsIn(
Arrays.asList(
new MissingRequiredFieldNotice(
GtfsTransfer.FILENAME, 0, GtfsTransfer.FROM_STOP_ID_FIELD_NAME),
new MissingRequiredFieldNotice(
GtfsTransfer.FILENAME, 0, GtfsTransfer.TO_STOP_ID_FIELD_NAME)));

noticeContainer.getValidationNotices().clear();
}
}

/**
* This test is used to verify that the validator doesn't generate a notice when the {@code
* to_stop_id} and {@code from_stop_id} are present for all transfer types.
*/
@Test
public void testTransferFromStopIdNoInSeatTransfer() {
for (int i = 0; i <= 5; i++) {
GtfsTransferType transferType = GtfsTransferType.forNumber(i);
GtfsTransferTableContainer gtfsTransferTableContainer =
GtfsTransferTableContainer.forEntities(
ImmutableList.of(
new GtfsTransfer.Builder()
.setFromStopId("stop1")
.setToStopId("stop2")
.setTransferType(transferType)
.build()),
noticeContainer);

new TransferStopIdsConditionalValidator(gtfsTransferTableContainer).validate(noticeContainer);

assertThat(noticeContainer.getValidationNotices()).isEmpty();
noticeContainer.getValidationNotices().clear();
}
}
}

0 comments on commit d71580b

Please sign in to comment.