Skip to content

Commit cb45764

Browse files
authored
Merge c0d19d9 into dda1918
2 parents dda1918 + c0d19d9 commit cb45764

File tree

3 files changed

+176
-2
lines changed

3 files changed

+176
-2
lines changed

main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsTransferSchema.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
@GtfsTable("transfers.txt")
2424
public interface GtfsTransferSchema extends GtfsEntity {
2525
@FieldType(FieldTypeEnum.ID)
26-
@Required
26+
@ConditionallyRequired
2727
@ForeignKey(table = "stops.txt", field = "stop_id")
2828
@PrimaryKey(translationRecordIdType = RECORD_ID)
2929
String fromStopId();
3030

3131
@FieldType(FieldTypeEnum.ID)
32-
@Required
32+
@ConditionallyRequired
3333
@ForeignKey(table = "stops.txt", field = "stop_id")
3434
@PrimaryKey(translationRecordIdType = RECORD_SUB_ID)
3535
String toStopId();
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2024 MobilityData
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.mobilitydata.gtfsvalidator.validator;
18+
19+
import static org.mobilitydata.gtfsvalidator.table.GtfsTransferType.IN_SEAT_TRANSFER_ALLOWED;
20+
import static org.mobilitydata.gtfsvalidator.table.GtfsTransferType.IN_SEAT_TRANSFER_NOT_ALLOWED;
21+
22+
import javax.inject.Inject;
23+
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator;
24+
import org.mobilitydata.gtfsvalidator.notice.MissingRequiredFieldNotice;
25+
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
26+
import org.mobilitydata.gtfsvalidator.table.GtfsTransfer;
27+
import org.mobilitydata.gtfsvalidator.table.GtfsTransferTableContainer;
28+
29+
/**
30+
* Validates the conditional requirement of {@code transfers.from_stop_id} and {@code to_stop_id}.
31+
*
32+
* <p>Generated notice:
33+
*
34+
* <ul>
35+
* <li>{@link MissingRequiredFieldNotice} - {@code from_stop_id} is missing or {@code to_stop_id}
36+
* is missing for all transfer types except for in-seat transfer types
37+
* </ul>
38+
*/
39+
@GtfsValidator
40+
public class TransferStopIdsConditionalValidator extends FileValidator {
41+
42+
private final GtfsTransferTableContainer transfersContainer;
43+
44+
@Inject
45+
public TransferStopIdsConditionalValidator(GtfsTransferTableContainer transfersContainer) {
46+
this.transfersContainer = transfersContainer;
47+
}
48+
49+
@Override
50+
public void validate(NoticeContainer noticeContainer) {
51+
for (GtfsTransfer transfer : transfersContainer.getEntities()) {
52+
if (transfer.hasTransferType()) {
53+
validateTransferEntity(transfer, noticeContainer);
54+
}
55+
}
56+
}
57+
58+
private boolean isTransferTypeInSeat(GtfsTransfer transfer) {
59+
return IN_SEAT_TRANSFER_ALLOWED.equals(transfer.transferType())
60+
|| IN_SEAT_TRANSFER_NOT_ALLOWED.equals(transfer.transferType());
61+
}
62+
63+
private void validateTransferEntity(GtfsTransfer transfer, NoticeContainer noticeContainer) {
64+
if (!isTransferTypeInSeat(transfer)) {
65+
if (!transfer.hasFromStopId()) {
66+
noticeContainer.addValidationNotice(
67+
new MissingRequiredFieldNotice(
68+
transfersContainer.gtfsFilename(), transfer.csvRowNumber(), "from_stop_id"));
69+
}
70+
if (!transfer.hasToStopId()) {
71+
noticeContainer.addValidationNotice(
72+
new MissingRequiredFieldNotice(
73+
transfersContainer.gtfsFilename(), transfer.csvRowNumber(), "to_stop_id"));
74+
}
75+
}
76+
}
77+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package org.mobilitydata.gtfsvalidator.validator;
2+
3+
import static com.google.common.truth.Truth.assertThat;
4+
5+
import com.google.common.collect.ImmutableList;
6+
import java.util.Arrays;
7+
import org.junit.Before;
8+
import org.junit.Test;
9+
import org.mobilitydata.gtfsvalidator.notice.MissingRequiredFieldNotice;
10+
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
11+
import org.mobilitydata.gtfsvalidator.table.GtfsTransfer;
12+
import org.mobilitydata.gtfsvalidator.table.GtfsTransferTableContainer;
13+
import org.mobilitydata.gtfsvalidator.table.GtfsTransferType;
14+
15+
public class TransferStopIdsConditionalValidatorTest {
16+
17+
private NoticeContainer noticeContainer;
18+
19+
@Before
20+
public void setUp() {
21+
noticeContainer = new NoticeContainer();
22+
}
23+
24+
/**
25+
* This test is used to verify that the validator does not generate a notice when the {@code
26+
* from_stop_id} is missing for in-seat transfer types.
27+
*/
28+
@Test
29+
public void testTransferFromStopIdNoInSeatTransferNoNotice() {
30+
// In seat transfer types are 4 and 5, so we test for all other types
31+
for (int i = 4; i <= 5; i++) {
32+
GtfsTransferType transferType = GtfsTransferType.forNumber(i);
33+
GtfsTransferTableContainer gtfsTransferTableContainer =
34+
GtfsTransferTableContainer.forEntities(
35+
ImmutableList.of(new GtfsTransfer.Builder().setTransferType(transferType).build()),
36+
noticeContainer);
37+
38+
new TransferStopIdsConditionalValidator(gtfsTransferTableContainer).validate(noticeContainer);
39+
40+
assertThat(noticeContainer.getValidationNotices()).isEmpty();
41+
noticeContainer.getValidationNotices().clear();
42+
}
43+
}
44+
45+
/**
46+
* This test is used to verify that the validator generates a notice when the {@code from_stop_id}
47+
* is missing for transfer types other than in-seat transfer types.
48+
*/
49+
@Test
50+
public void testTransferMissingFromStopIdNoInSeatTransfer() {
51+
for (int i = 0; i < 4; i++) {
52+
GtfsTransferType transferType = GtfsTransferType.forNumber(i);
53+
GtfsTransferTableContainer gtfsTransferTableContainer =
54+
GtfsTransferTableContainer.forEntities(
55+
ImmutableList.of(new GtfsTransfer.Builder().setTransferType(transferType).build()),
56+
noticeContainer);
57+
58+
new TransferStopIdsConditionalValidator(gtfsTransferTableContainer).validate(noticeContainer);
59+
60+
assertThat(noticeContainer.getValidationNotices()).isNotEmpty();
61+
assertThat(noticeContainer.getValidationNotices())
62+
.containsExactlyElementsIn(
63+
Arrays.asList(
64+
new MissingRequiredFieldNotice(
65+
GtfsTransfer.FILENAME, 0, GtfsTransfer.FROM_STOP_ID_FIELD_NAME),
66+
new MissingRequiredFieldNotice(
67+
GtfsTransfer.FILENAME, 0, GtfsTransfer.TO_STOP_ID_FIELD_NAME)));
68+
69+
noticeContainer.getValidationNotices().clear();
70+
}
71+
}
72+
73+
/**
74+
* This test is used to verify that the validator doesn't generate a notice when the {@code
75+
* to_stop_id} and {@code from_stop_id} are present for all transfer types.
76+
*/
77+
@Test
78+
public void testTransferFromStopIdNoInSeatTransfer() {
79+
for (int i = 0; i <= 5; i++) {
80+
GtfsTransferType transferType = GtfsTransferType.forNumber(i);
81+
GtfsTransferTableContainer gtfsTransferTableContainer =
82+
GtfsTransferTableContainer.forEntities(
83+
ImmutableList.of(
84+
new GtfsTransfer.Builder()
85+
.setFromStopId("stop1")
86+
.setToStopId("stop2")
87+
.setTransferType(transferType)
88+
.build()),
89+
noticeContainer);
90+
91+
new TransferStopIdsConditionalValidator(gtfsTransferTableContainer).validate(noticeContainer);
92+
93+
assertThat(noticeContainer.getValidationNotices()).isEmpty();
94+
noticeContainer.getValidationNotices().clear();
95+
}
96+
}
97+
}

0 commit comments

Comments
 (0)