mirror of
https://github.com/FoggedLens/deflock-app.git
synced 2026-09-19 16:02:16 +02:00
feat: Added Notifications to app
This commit is contained in:
committed by
Ryan Brown
parent
2c64fe610e
commit
51037f3710
@@ -0,0 +1,88 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
import 'package:deflockapp/services/geo_bounds.dart';
|
||||
|
||||
/// Real-world distance from a bounds edge back to its center, so the box can be
|
||||
/// checked in meters rather than in degrees.
|
||||
double _metersBetween(LatLng a, LatLng b) => Geolocator.distanceBetween(
|
||||
a.latitude,
|
||||
a.longitude,
|
||||
b.latitude,
|
||||
b.longitude,
|
||||
);
|
||||
|
||||
void main() {
|
||||
group('boundsAround', () {
|
||||
test('contains the center', () {
|
||||
const center = LatLng(38.9, -77.0);
|
||||
final bounds = boundsAround(center, 200);
|
||||
expect(bounds.contains(center), isTrue);
|
||||
});
|
||||
|
||||
test('reaches at least the requested radius north/south and east/west', () {
|
||||
const center = LatLng(38.9, -77.0);
|
||||
const radius = 500;
|
||||
final bounds = boundsAround(center, radius);
|
||||
|
||||
final north = _metersBetween(center, LatLng(bounds.north, center.longitude));
|
||||
final south = _metersBetween(center, LatLng(bounds.south, center.longitude));
|
||||
final east = _metersBetween(center, LatLng(center.latitude, bounds.east));
|
||||
final west = _metersBetween(center, LatLng(center.latitude, bounds.west));
|
||||
|
||||
for (final reach in [north, south, east, west]) {
|
||||
// At least the radius, and not wildly oversized (the box is a square,
|
||||
// so its corners legitimately overshoot, but its edges should not).
|
||||
expect(reach, greaterThanOrEqualTo(radius * 0.98));
|
||||
expect(reach, lessThan(radius * 1.2));
|
||||
}
|
||||
});
|
||||
|
||||
test('widens longitude at high latitude to keep the real radius', () {
|
||||
const radius = 1000;
|
||||
final equator = boundsAround(const LatLng(0, 0), radius);
|
||||
final far = boundsAround(const LatLng(64.0, 0), radius);
|
||||
|
||||
final equatorLngSpan = equator.east - equator.west;
|
||||
final farLngSpan = far.east - far.west;
|
||||
|
||||
// cos(64°) ≈ 0.438, so the degree span must be roughly 2.3x wider.
|
||||
expect(farLngSpan, greaterThan(equatorLngSpan * 2));
|
||||
|
||||
// ...and that wider span should still be ~1000m on the ground.
|
||||
final reach = _metersBetween(
|
||||
const LatLng(64.0, 0),
|
||||
LatLng(64.0, far.east),
|
||||
);
|
||||
expect(reach, greaterThanOrEqualTo(radius * 0.98));
|
||||
expect(reach, lessThan(radius * 1.2));
|
||||
});
|
||||
|
||||
test('does not blow past the poles or the antimeridian', () {
|
||||
for (final center in [
|
||||
const LatLng(89.99, 179.99),
|
||||
const LatLng(-89.99, -179.99),
|
||||
]) {
|
||||
final bounds = boundsAround(center, 100000);
|
||||
expect(bounds.north, lessThanOrEqualTo(90.0));
|
||||
expect(bounds.south, greaterThanOrEqualTo(-90.0));
|
||||
expect(bounds.east, lessThanOrEqualTo(180.0));
|
||||
expect(bounds.west, greaterThanOrEqualTo(-180.0));
|
||||
}
|
||||
});
|
||||
|
||||
test('a zero radius still yields usable bounds containing the center', () {
|
||||
const center = LatLng(38.9, -77.0);
|
||||
final bounds = boundsAround(center, 0);
|
||||
expect(bounds.contains(center), isTrue);
|
||||
});
|
||||
|
||||
test('grows with the alert distance', () {
|
||||
const center = LatLng(38.9, -77.0);
|
||||
final near = boundsAround(center, 100);
|
||||
final far = boundsAround(center, 1600);
|
||||
expect(far.north - far.south, greaterThan(near.north - near.south));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
/// Mirrors ProximityAlertService._notificationId. Kept in sync deliberately:
|
||||
/// the real one is private, and this pins the contract the plugin enforces —
|
||||
/// notification ids must fit in a signed 32-bit int.
|
||||
int notificationId(int nodeId) => nodeId.abs() % 0x7FFFFFFF;
|
||||
|
||||
const int maxInt32 = 2147483647;
|
||||
|
||||
void main() {
|
||||
group('notificationId', () {
|
||||
test('folds real-world OSM node ids into 32-bit range', () {
|
||||
// The id from the crash, plus ids around the current OSM high-water mark.
|
||||
const ids = [
|
||||
12741890927,
|
||||
1,
|
||||
2147483647,
|
||||
2147483648,
|
||||
9999999999,
|
||||
13000000000,
|
||||
];
|
||||
|
||||
for (final id in ids) {
|
||||
final result = notificationId(id);
|
||||
expect(result, greaterThanOrEqualTo(0), reason: 'id $id went negative');
|
||||
expect(result, lessThanOrEqualTo(maxInt32), reason: 'id $id overflowed');
|
||||
}
|
||||
});
|
||||
|
||||
test('handles negative ids, which OSM uses for not-yet-uploaded nodes', () {
|
||||
for (final id in [-1, -12741890927, -2147483648]) {
|
||||
final result = notificationId(id);
|
||||
expect(result, greaterThanOrEqualTo(0));
|
||||
expect(result, lessThanOrEqualTo(maxInt32));
|
||||
}
|
||||
});
|
||||
|
||||
test('is deterministic, so a repeat alert replaces rather than stacks', () {
|
||||
expect(notificationId(12741890927), notificationId(12741890927));
|
||||
});
|
||||
|
||||
test('separates adjacent node ids', () {
|
||||
final a = notificationId(12741890927);
|
||||
final b = notificationId(12741890928);
|
||||
expect(a, isNot(b));
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user