Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,10 @@ pub enum ParserError {
/// The geometry section of a feature is malformed.
#[error("Geometry section contains errors")]
InvalidGeometry,

/// A coordinate value does not fit in the requested numeric type.
#[error("Coordinate value {value} overflows the requested type")]
CoordinateOverflow {
value: i32,
}
}
9 changes: 5 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,10 +428,11 @@ fn parse_geometry<T: CoordNum>(
Some(result) => result,
None => i32::MAX, // clip value
};
coordinates.push(Coord {
x: NumCast::from(cursor[0]).unwrap_or_else(T::zero),
y: NumCast::from(cursor[1]).unwrap_or_else(T::zero),
});
let x = NumCast::from(cursor[0])
.ok_or(error::ParserError::CoordinateOverflow { value: cursor[0] })?;
let y = NumCast::from(cursor[1])
.ok_or(error::ParserError::CoordinateOverflow { value: cursor[1] })?;
coordinates.push(Coord { x, y });
}
parameter_count -= 1;
}
Expand Down
46 changes: 46 additions & 0 deletions tests/coordinate_overflow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use std::fs::read;

use mvt_reader::{Reader, error::ParserError};

#[test]
fn u8_coordinate_overflow_returns_error() {
// Fixture 053 has coordinates (0,0), (4096,0), (4096,4096), (0,4096)
// which clearly exceed u8 max (255)
let bytes = read("mvt-fixtures/fixtures/053/tile.mvt").unwrap();
let reader = Reader::new(bytes).unwrap();

let result = reader.get_features_as::<u8>(0);
assert!(
matches!(result, Err(ParserError::CoordinateOverflow { .. })),
"Expected CoordinateOverflow error for coordinates exceeding u8 range, got: {:?}",
result
);
}

#[test]
fn u8_coordinate_within_range_succeeds() {
// Fixture 002 has a point at (25, 17) which fits in u8
let bytes = read("mvt-fixtures/fixtures/002/tile.mvt").unwrap();
let reader = Reader::new(bytes).unwrap();

let result = reader.get_features_as::<u8>(0);
assert!(
result.is_ok(),
"Expected success for coordinates within u8 range, got: {:?}",
result
);
}

#[test]
fn i32_coordinate_large_values_succeeds() {
// Fixture 053 has coordinates up to 4096 which fit in i32
let bytes = read("mvt-fixtures/fixtures/053/tile.mvt").unwrap();
let reader = Reader::new(bytes).unwrap();

let result = reader.get_features_as::<i32>(0);
assert!(
result.is_ok(),
"Expected success for coordinates within i32 range, got: {:?}",
result
);
}
8 changes: 7 additions & 1 deletion tests/real_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,13 @@ fn assert_all_fixtures_readable<T: CoordNum>(label: &str) -> Result<(), io::Erro
let layer_names = reader.get_layer_names().expect("Failed to get layer names");
for (i, _) in layer_names.iter().enumerate() {
let features = reader.get_features_as::<T>(i);
assert!(!features.unwrap().is_empty());
match features {
Ok(f) => assert!(!f.is_empty()),
Err(ParserError::CoordinateOverflow { .. }) => {
println!("CoordinateOverflow for layer {} (expected for small types)", i);
}
Err(e) => panic!("Unexpected error: {:?}", e),
}
}
println!("found layer names: {:?}", layer_names);
}
Expand Down