import 'package:swarm/swarm.dart'; import 'package:test/test.dart'; void main() { late GeoActor actor; setUp(() => actor = GeoActor()); group('GeoActor', () { group('EncodeLocation', () { test('returns GeohashEncoded with correct length', () async { final result = await actor.handle( const EncodeLocation( latitude: 48.8566, longitude: 2.3522, precision: 6), ); expect(result, isA()); expect((result as GeohashEncoded).geohash, hasLength(6)); }); test('default precision is 9', () async { final result = await actor.handle( const EncodeLocation(latitude: 51.5074, longitude: -0.1278), ); expect((result as GeohashEncoded).geohash, hasLength(9)); }); test( 'higher precision produces longer hash with lower precision as prefix', () async { const lat = 52.52, lon = 13.405; final r6 = await actor.handle( const EncodeLocation(latitude: lat, longitude: lon, precision: 6), ); final r9 = await actor.handle( const EncodeLocation(latitude: lat, longitude: lon, precision: 9), ); final h6 = (r6 as GeohashEncoded).geohash; final h9 = (r9 as GeohashEncoded).geohash; expect(h9, startsWith(h6)); }); }); group('DecodeGeohash', () { test('returns LocationDecoded', () async { final result = await actor.handle(const DecodeGeohash('u33dbf')); expect(result, isA()); }); test('decoded coordinates are within cell bounds for precision 6', () async { // precision-6 cell error: ±0.0034° lat, ±0.0017° lon final result = await actor.handle(const DecodeGeohash('u33dbf')); final loc = result as LocationDecoded; expect(loc.latitude, inInclusiveRange(52.0, 53.0)); expect(loc.longitude, inInclusiveRange(13.0, 14.0)); }); test('roundtrip encode→decode recovers coordinates within cell error', () async { const lat = 48.8566, lon = 2.3522; final encoded = await actor.handle( const EncodeLocation(latitude: lat, longitude: lon, precision: 9), ); final decoded = await actor.handle( DecodeGeohash((encoded as GeohashEncoded).geohash), ); final loc = decoded as LocationDecoded; // precision-9 cell error: ±0.000021° lat, ±0.000021° lon expect(loc.latitude, closeTo(lat, 0.001)); expect(loc.longitude, closeTo(lon, 0.001)); }); }); group('NeighborsOf', () { const directions = [ 'NORTH', 'NORTHEAST', 'EAST', 'SOUTHEAST', 'SOUTH', 'SOUTHWEST', 'WEST', 'NORTHWEST', 'CENTRAL', ]; test('returns NeighborsResult with 9 entries', () async { final result = await actor.handle(const NeighborsOf('u33dbf')); expect(result, isA()); expect((result as NeighborsResult).neighbors, hasLength(9)); }); test('result contains all 8 compass directions plus CENTRAL', () async { final result = await actor.handle(const NeighborsOf('u33dbf')); expect( (result as NeighborsResult).neighbors.keys, containsAll(directions), ); }); test('CENTRAL equals the input geohash', () async { const hash = 'u33dbf'; final result = await actor.handle(const NeighborsOf(hash)); expect((result as NeighborsResult).neighbors['CENTRAL'], equals(hash)); }); test('all neighbor hashes have the same precision as input', () async { const hash = 'u33dbf'; final result = await actor.handle(const NeighborsOf(hash)); for (final neighbor in (result as NeighborsResult).neighbors.values) { expect(neighbor, hasLength(hash.length)); } }); test('neighbor hashes are all distinct', () async { final result = await actor.handle(const NeighborsOf('u33dbf')); final values = (result as NeighborsResult).neighbors.values.toList(); expect(values.toSet(), hasLength(values.length)); }); }); }); }