Skip to content

Commit a90fef1

Browse files
authored
Merge f9bf16b into e84a9aa
2 parents e84a9aa + f9bf16b commit a90fef1

File tree

3 files changed

+233
-0
lines changed

3 files changed

+233
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2025 Google LLC
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.table;
18+
19+
import org.mobilitydata.gtfsvalidator.annotation.*;
20+
21+
@GtfsTable("fare_leg_join_rules.txt")
22+
public interface GtfsFareLegJoinRuleSchema extends GtfsEntity {
23+
@FieldType(FieldTypeEnum.ID)
24+
@Required
25+
String fromNetworkId();
26+
27+
@FieldType(FieldTypeEnum.ID)
28+
@Required
29+
String toNetworkId();
30+
31+
@FieldType(FieldTypeEnum.ID)
32+
@ConditionallyRequired
33+
@ForeignKey(table = "stops.txt", field = "stop_id")
34+
String fromStopId();
35+
36+
@FieldType(FieldTypeEnum.ID)
37+
@ConditionallyRequired
38+
@ForeignKey(table = "stops.txt", field = "stop_id")
39+
String toStopId();
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright 2025 Google LLC, MobilityData IO
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+
package org.mobilitydata.gtfsvalidator.validator;
17+
18+
import javax.inject.Inject;
19+
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator;
20+
import org.mobilitydata.gtfsvalidator.notice.ForeignKeyViolationNotice;
21+
import org.mobilitydata.gtfsvalidator.notice.MissingRequiredFieldNotice;
22+
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
23+
import org.mobilitydata.gtfsvalidator.table.*;
24+
25+
/**
26+
* Validates GtfsFareLegJoinRule entities
27+
*
28+
* <p>Generated notices:
29+
*
30+
* <ul>
31+
* <li>{@link ForeignKeyViolationNotice}
32+
* <li>{@link MissingRequiredFieldNotice}
33+
* </ul>
34+
*/
35+
@GtfsValidator
36+
public class FareLegJoinRuleValidator extends FileValidator {
37+
GtfsNetworkTableContainer networkTable;
38+
GtfsRouteTableContainer routeTable;
39+
GtfsFareLegJoinRuleTableContainer fareLegJoinRuleTable;
40+
41+
@Inject
42+
public FareLegJoinRuleValidator(
43+
GtfsNetworkTableContainer networkTable,
44+
GtfsRouteTableContainer routeTable,
45+
GtfsFareLegJoinRuleTableContainer fareLegJoinRuleTable) {
46+
this.networkTable = networkTable;
47+
this.routeTable = routeTable;
48+
this.fareLegJoinRuleTable = fareLegJoinRuleTable;
49+
}
50+
51+
@Override
52+
public void validate(NoticeContainer noticeContainer) {
53+
for (GtfsFareLegJoinRule entity : fareLegJoinRuleTable.getEntities()) {
54+
validate(entity, noticeContainer);
55+
}
56+
}
57+
58+
public void validate(GtfsFareLegJoinRule entity, NoticeContainer noticeContainer) {
59+
// Validate foreign key reference - from_network_id references a network or route
60+
if (!networkTable.byNetworkId(entity.fromNetworkId()).isPresent()
61+
&& routeTable.byNetworkId(entity.fromNetworkId()).isEmpty()) {
62+
noticeContainer.addValidationNotice(
63+
new ForeignKeyViolationNotice(
64+
GtfsFareLegJoinRule.FILENAME,
65+
GtfsFareLegJoinRule.FROM_NETWORK_ID_FIELD_NAME,
66+
GtfsRoute.FILENAME + " or " + GtfsNetwork.FILENAME,
67+
GtfsNetwork.NETWORK_ID_FIELD_NAME,
68+
entity.fromNetworkId(),
69+
entity.csvRowNumber()));
70+
}
71+
72+
// Validate foreign key reference - to_network_id references a network or route
73+
if (!networkTable.byNetworkId(entity.toNetworkId()).isPresent()
74+
&& routeTable.byNetworkId(entity.toNetworkId()).isEmpty()) {
75+
noticeContainer.addValidationNotice(
76+
new ForeignKeyViolationNotice(
77+
GtfsFareLegJoinRule.FILENAME,
78+
GtfsFareLegJoinRule.TO_NETWORK_ID_FIELD_NAME,
79+
GtfsRoute.FILENAME + " or " + GtfsNetwork.FILENAME,
80+
GtfsNetwork.NETWORK_ID_FIELD_NAME,
81+
entity.toNetworkId(),
82+
entity.csvRowNumber()));
83+
}
84+
85+
// Validate conditionally required fields - from_stop_id and to_stop_id
86+
if (entity.hasFromStopId() && !entity.hasToStopId()) {
87+
noticeContainer.addValidationNotice(
88+
new MissingRequiredFieldNotice(
89+
GtfsFareLegJoinRule.FILENAME,
90+
entity.csvRowNumber(),
91+
GtfsFareLegJoinRule.TO_STOP_ID_FIELD_NAME));
92+
} else if (entity.hasToStopId() && !entity.hasFromStopId()) {
93+
noticeContainer.addValidationNotice(
94+
new MissingRequiredFieldNotice(
95+
GtfsFareLegJoinRule.FILENAME,
96+
entity.csvRowNumber(),
97+
GtfsFareLegJoinRule.FROM_STOP_ID_FIELD_NAME));
98+
}
99+
}
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package org.mobilitydata.gtfsvalidator.validator;
2+
3+
import static com.google.common.truth.Truth.assertThat;
4+
5+
import java.util.List;
6+
import org.junit.Test;
7+
import org.junit.runner.RunWith;
8+
import org.junit.runners.JUnit4;
9+
import org.mobilitydata.gtfsvalidator.notice.ForeignKeyViolationNotice;
10+
import org.mobilitydata.gtfsvalidator.notice.MissingRequiredFieldNotice;
11+
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
12+
import org.mobilitydata.gtfsvalidator.table.*;
13+
14+
@RunWith(JUnit4.class)
15+
public class FareLegJoinRuleValidatorTest {
16+
17+
@Test
18+
public void missingForeignKey_yieldsNotice() {
19+
NoticeContainer noticeContainer = new NoticeContainer();
20+
GtfsFareLegJoinRuleTableContainer fareLegJoinRuleTableContainer =
21+
GtfsFareLegJoinRuleTableContainer.forEntities(
22+
List.of(
23+
new GtfsFareLegJoinRule.Builder()
24+
.setCsvRowNumber(1)
25+
.setFromNetworkId("network1")
26+
.setToNetworkId("network2")
27+
.build()),
28+
noticeContainer);
29+
GtfsRouteTableContainer routeTableContainer =
30+
GtfsRouteTableContainer.forEntities(
31+
List.of(
32+
new GtfsRoute.Builder()
33+
.setCsvRowNumber(1)
34+
.setRouteId("route1")
35+
.setNetworkId("network1")
36+
.build()),
37+
noticeContainer);
38+
GtfsNetworkTableContainer networkTableContainer =
39+
GtfsNetworkTableContainer.forEntities(
40+
List.of(new GtfsNetwork.Builder().setCsvRowNumber(1).setNetworkId("network1").build()),
41+
noticeContainer);
42+
FareLegJoinRuleValidator underTest =
43+
new FareLegJoinRuleValidator(
44+
networkTableContainer, routeTableContainer, fareLegJoinRuleTableContainer);
45+
46+
underTest.validate(noticeContainer);
47+
assertThat(
48+
(int)
49+
noticeContainer.getValidationNotices().stream()
50+
.filter(n -> n instanceof ForeignKeyViolationNotice)
51+
.count())
52+
.isEqualTo(1);
53+
}
54+
55+
@Test
56+
public void missingRequiredField_yieldsNotice() {
57+
NoticeContainer noticeContainer = new NoticeContainer();
58+
GtfsFareLegJoinRuleTableContainer fareLegJoinRuleTableContainer =
59+
GtfsFareLegJoinRuleTableContainer.forEntities(
60+
List.of(
61+
new GtfsFareLegJoinRule.Builder()
62+
.setCsvRowNumber(1)
63+
.setFromNetworkId("network1")
64+
.setToNetworkId("network2")
65+
.setFromStopId("stop1")
66+
.build()),
67+
noticeContainer);
68+
GtfsRouteTableContainer routeTableContainer =
69+
GtfsRouteTableContainer.forEntities(
70+
List.of(
71+
new GtfsRoute.Builder()
72+
.setCsvRowNumber(1)
73+
.setRouteId("route1")
74+
.setNetworkId("network1")
75+
.build()),
76+
noticeContainer);
77+
GtfsNetworkTableContainer networkTableContainer =
78+
GtfsNetworkTableContainer.forEntities(
79+
List.of(new GtfsNetwork.Builder().setCsvRowNumber(1).setNetworkId("network2").build()),
80+
noticeContainer);
81+
FareLegJoinRuleValidator underTest =
82+
new FareLegJoinRuleValidator(
83+
networkTableContainer, routeTableContainer, fareLegJoinRuleTableContainer);
84+
85+
underTest.validate(noticeContainer);
86+
assertThat(
87+
(int)
88+
noticeContainer.getValidationNotices().stream()
89+
.filter(n -> n instanceof MissingRequiredFieldNotice)
90+
.count())
91+
.isEqualTo(1);
92+
}
93+
}

0 commit comments

Comments
 (0)