Skip to content

Commit

Permalink
platform: Correctly handle integer-like numbers from JSON (#1531)
Browse files Browse the repository at this point in the history
In JSON, an allowed representation for doubles without a fractional
part like `1.0` is actually `1`. This is, for example, the behavior of
[JSONEncoder][1].

When using `jsonDecode`, a `0` or `1` is deserialized to an `int`, which
would then cause `Position.fromMap` to crash. Instead, use `toDouble()` to
ensure that the value is converted to a `double`.

[1]: https://developer.apple.com/documentation/foundation/jsonencoder
  • Loading branch information
rohansingh committed Jun 18, 2024
1 parent 026534d commit 39c39ae
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 8 deletions.
4 changes: 4 additions & 0 deletions geolocator_platform_interface/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 4.2.4

- Correctly handle integer-like numbers when decoding `Position` from JSON.

## 4.2.3

- Fixes several grammar mistakes in the API documentation.
Expand Down
22 changes: 15 additions & 7 deletions geolocator_platform_interface/lib/src/models/position.dart
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,14 @@ class Position {
latitude: positionMap['latitude'],
longitude: positionMap['longitude'],
timestamp: timestamp,
altitude: positionMap['altitude'] ?? 0.0,
altitudeAccuracy: positionMap['altitude_accuracy'] ?? 0.0,
accuracy: positionMap['accuracy'] ?? 0.0,
heading: positionMap['heading'] ?? 0.0,
headingAccuracy: positionMap['heading_accuracy'] ?? 0.0,
altitude: _toDouble(positionMap['altitude']),
altitudeAccuracy: _toDouble(positionMap['altitude_accuracy']),
accuracy: _toDouble(positionMap['accuracy']),
heading: _toDouble(positionMap['heading']),
headingAccuracy: _toDouble(positionMap['heading_accuracy']),
floor: positionMap['floor'],
speed: positionMap['speed'] ?? 0.0,
speedAccuracy: positionMap['speed_accuracy'] ?? 0.0,
speed: _toDouble(positionMap['speed']),
speedAccuracy: _toDouble(positionMap['speed_accuracy']),
isMocked: positionMap['is_mocked'] ?? false,
);
}
Expand All @@ -182,4 +182,12 @@ class Position {
'speed_accuracy': speedAccuracy,
'is_mocked': isMocked,
};

static double _toDouble(dynamic value) {
if (value == null) {
return 0.0;
}

return value.toDouble();
}
}
2 changes: 1 addition & 1 deletion geolocator_platform_interface/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: A common platform interface for the geolocator plugin.
repository: https://github.com/baseflow/flutter-geolocator/tree/main/geolocator_platform_interface
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
version: 4.2.3
version: 4.2.4

dependencies:
flutter:
Expand Down
18 changes: 18 additions & 0 deletions geolocator_platform_interface/test/src/models/position_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:convert';

import 'package:flutter_test/flutter_test.dart';
import 'package:geolocator_platform_interface/geolocator_platform_interface.dart';

Expand Down Expand Up @@ -512,6 +514,22 @@ void main() {
// Act & Assert
expect(() => Position.fromMap(map), throwsArgumentError);
});

test('fromMap should handle a map returned by jsonDecode', () {
// Arrange
const json = '''{
"is_mocked": true,
"longitude": -122.406417,
"timestamp": 1718643179305.9131,
"latitude": 37.785834000000001,
"heading_accuracy": -1,
"accuracy": 5,
"heading": -1.5
}''';

// Act & Assert
expect(() => Position.fromMap(jsonDecode(json)), returnsNormally);
});
});

group('toString tests:', () {
Expand Down

0 comments on commit 39c39ae

Please sign in to comment.