Skip to content

Commit

Permalink
new rule for shapes with single shape point
Browse files Browse the repository at this point in the history
  • Loading branch information
praneethd7 committed May 9, 2024
1 parent 0d13c65 commit ceeabdc
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.mobilitydata.gtfsvalidator.validator;

import org.mobilitydata.gtfsvalidator.annotation.GtfsValidationNotice;
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.notice.ValidationNotice;
import org.mobilitydata.gtfsvalidator.table.GtfsShape;
import org.mobilitydata.gtfsvalidator.table.GtfsShapeSchema;
import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer;

import javax.inject.Inject;
import java.util.HashMap;
import java.util.Map;

import static org.mobilitydata.gtfsvalidator.notice.SeverityLevel.WARNING;

/**
* Validates that every shape (identified by shape_id) has more than one shape_point
*
* <p>Generated notice: {@link SingleShapePointNotice}</p>
*/
@GtfsValidator
public class SingleShapePointValidator extends FileValidator {
private final GtfsShapeTableContainer shapeTable;

@Inject
SingleShapePointValidator(GtfsShapeTableContainer shapeTable){
this.shapeTable = shapeTable;
}

@Override
public void validate(NoticeContainer noticeContainer) {
Map<String, Integer> shapePointCounts = new HashMap<>();
Map<String, Integer> shapePointRowNumbers = new HashMap<>();
for (GtfsShape shape : shapeTable.getEntities()) {
String shapeId = shape.shapeId();
shapePointCounts.put(shapeId, shapePointCounts.getOrDefault(shapeId, 0) + 1);
shapePointRowNumbers.put(shapeId, shape.csvRowNumber());
}

for (Map.Entry<String, Integer> entry : shapePointCounts.entrySet()) {
if (entry.getValue() == 1) {
noticeContainer.addValidationNotice(new SingleShapePointNotice(entry.getKey(),shapePointRowNumbers.getOrDefault(entry.getKey(),0)));
}
}
}

/**
* The shape within `shapes.txt` contains a single shape point.
*
* <p>A shape should contain more than one shape point to visualize the route on any GIS software (which require LineString).</p>
*/
@GtfsValidationNotice(
severity = WARNING,
files = @GtfsValidationNotice.FileRefs({GtfsShapeSchema.class})
)

static class SingleShapePointNotice extends ValidationNotice {
/** The faulty record's id. */
private final String shapeId;

/** The row number of the faulty record. */
private final int csvRowNumber;

SingleShapePointNotice(String shapeId, int csvRowNumber) {
this.shapeId = shapeId;
this.csvRowNumber = csvRowNumber;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.mobilitydata.gtfsvalidator.validator;

import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.notice.ValidationNotice;
import org.mobilitydata.gtfsvalidator.table.GtfsShape;
import org.mobilitydata.gtfsvalidator.table.GtfsShapeTableContainer;

import java.util.List;

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

public class SingleShapePointValidatorTest {
public static GtfsShape createShapePoint(
int csvRowNumber,
String shapeId,
double shapePtLat,
double shapePtLon,
int shapePtSequence,
double shapeDistTraveled) {
return new GtfsShape.Builder()
.setCsvRowNumber(csvRowNumber)
.setShapeId(shapeId)
.setShapePtLat(shapePtLat)
.setShapePtLon(shapePtLon)
.setShapePtSequence(shapePtSequence)
.setShapeDistTraveled(shapeDistTraveled)
.build();
}


private static List<ValidationNotice> generateNotices(
List<GtfsShape> shapes) {
NoticeContainer noticeContainer = new NoticeContainer();
new SingleShapePointValidator(
GtfsShapeTableContainer.forEntities(shapes, noticeContainer))
.validate(noticeContainer);
return noticeContainer.getValidationNotices();
}

@Test
public void shapeWithMoreThanOneShapePointShouldNotGenerateNotice() {
assertThat(
generateNotices(
ImmutableList.of(
createShapePoint(1, "first shape id", 45.0d, 45.0d, 1, 0.0d),
createShapePoint(2, "first shape id", 45.1d, 45.0d, 2, 40.0d)
))
).isEmpty();
}

@Test
public void unusedShapeShouldGenerateNotice() {
assertThat(
generateNotices(
ImmutableList.of(
createShapePoint(1, "first shape id", 45.0d, 45.0d, 1, 40.0d),
createShapePoint(2, "first shape id", 45.1d, 45.0d, 2, 40.0d),
createShapePoint(3, "second shape id", 45.0d, 45.0d, 1, 40.0d)))
).containsExactly(new SingleShapePointValidator.SingleShapePointNotice("second shape id", 3));
}
}

0 comments on commit ceeabdc

Please sign in to comment.