diff --git a/geocoding_platform_interface/CHANGELOG.md b/geocoding_platform_interface/CHANGELOG.md index 12d85d3..2614f1e 100644 --- a/geocoding_platform_interface/CHANGELOG.md +++ b/geocoding_platform_interface/CHANGELOG.md @@ -1,3 +1,12 @@ +## 4.0.0 + +- **BREAKING CHANGES:** + - Releases new interface making the Geocoding plugin easier to extend and + implement on different platforms. + - Moves the old interface into the `legacy` folder. This interface will + remain available but will no longer be maintained. To import the old + interface use `import 'package:geocoding_platform_interface/legacy/geocoding_platform_interface.dart`. + ## 3.2.1 - Fixed analysis warnings from `flutter analyse`. diff --git a/geocoding_platform_interface/lib/geocoding_platform_interface.dart b/geocoding_platform_interface/lib/geocoding_platform_interface.dart index 579f469..12b4a95 100644 --- a/geocoding_platform_interface/lib/geocoding_platform_interface.dart +++ b/geocoding_platform_interface/lib/geocoding_platform_interface.dart @@ -1,3 +1,3 @@ -export 'src/errors/errors.dart'; -export 'src/geocoding_platform_interface.dart'; -export 'src/models/models.dart'; +export 'src/geocoding.dart'; +export 'src/geocoding_platform_factory.dart'; +export 'src/types/types.dart'; diff --git a/geocoding_platform_interface/lib/legacy/geocoding_platform_interface.dart b/geocoding_platform_interface/lib/legacy/geocoding_platform_interface.dart new file mode 100644 index 0000000..579f469 --- /dev/null +++ b/geocoding_platform_interface/lib/legacy/geocoding_platform_interface.dart @@ -0,0 +1,3 @@ +export 'src/errors/errors.dart'; +export 'src/geocoding_platform_interface.dart'; +export 'src/models/models.dart'; diff --git a/geocoding_platform_interface/lib/src/errors/errors.dart b/geocoding_platform_interface/lib/legacy/src/errors/errors.dart similarity index 100% rename from geocoding_platform_interface/lib/src/errors/errors.dart rename to geocoding_platform_interface/lib/legacy/src/errors/errors.dart diff --git a/geocoding_platform_interface/lib/src/errors/no_result_found_exception.dart b/geocoding_platform_interface/lib/legacy/src/errors/no_result_found_exception.dart similarity index 100% rename from geocoding_platform_interface/lib/src/errors/no_result_found_exception.dart rename to geocoding_platform_interface/lib/legacy/src/errors/no_result_found_exception.dart diff --git a/geocoding_platform_interface/lib/src/geocoding_platform_interface.dart b/geocoding_platform_interface/lib/legacy/src/geocoding_platform_interface.dart similarity index 87% rename from geocoding_platform_interface/lib/src/geocoding_platform_interface.dart rename to geocoding_platform_interface/lib/legacy/src/geocoding_platform_interface.dart index c046192..9753064 100644 --- a/geocoding_platform_interface/lib/src/geocoding_platform_interface.dart +++ b/geocoding_platform_interface/lib/legacy/src/geocoding_platform_interface.dart @@ -38,11 +38,10 @@ abstract class GeocodingPlatform extends PlatformInterface { /// /// The `localeIdentifier` should be formatted using the syntax: /// [languageCode]_[countryCode] (eg. en_US or nl_NL). - Future setLocaleIdentifier( - String localeIdentifier, - ) { + Future setLocaleIdentifier(String localeIdentifier) { throw UnimplementedError( - 'setLocaleIdentifier() has not been implementated.'); + 'setLocaleIdentifier() has not been implementated.', + ); } /// Returns a list of [Location] instances found for the supplied address. @@ -51,11 +50,10 @@ abstract class GeocodingPlatform extends PlatformInterface { /// However in some situations where the supplied address could not be /// resolved into a single [Location], multiple [Location] instances may be /// returned. - Future> locationFromAddress( - String address, - ) { + Future> locationFromAddress(String address) { throw UnimplementedError( - 'locationFromAddress() has not been implementated.'); + 'locationFromAddress() has not been implementated.', + ); } /// Returns true if there is a geocoder implementation present that may return results. @@ -80,7 +78,8 @@ abstract class GeocodingPlatform extends PlatformInterface { double longitude, ) { throw UnimplementedError( - 'placemarkFromCoordinates() has not been implementated.'); + 'placemarkFromCoordinates() has not been implementated.', + ); } /// Returns a list of [Placemark] instances found for the supplied address. @@ -89,10 +88,9 @@ abstract class GeocodingPlatform extends PlatformInterface { /// However in some situations where the supplied address could not be /// resolved into a single [Placemark], multiple [Placemark] instances may be /// returned. - Future> placemarkFromAddress( - String address, - ) { + Future> placemarkFromAddress(String address) { throw UnimplementedError( - 'placemarkFromAddress() has not been implementated.'); + 'placemarkFromAddress() has not been implementated.', + ); } } diff --git a/geocoding_platform_interface/lib/src/models/location.dart b/geocoding_platform_interface/lib/legacy/src/models/location.dart similarity index 89% rename from geocoding_platform_interface/lib/src/models/location.dart rename to geocoding_platform_interface/lib/legacy/src/models/location.dart index 48dd0d6..5daf5bb 100644 --- a/geocoding_platform_interface/lib/src/models/location.dart +++ b/geocoding_platform_interface/lib/legacy/src/models/location.dart @@ -56,12 +56,14 @@ class Location { final Map locationMap = message; final timestamp = DateTime.fromMillisecondsSinceEpoch( - locationMap['timestamp'].toInt(), - isUtc: true); + locationMap['timestamp'].toInt(), + isUtc: true, + ); if (locationMap['latitude'] == null || locationMap['longitude'] == null) { throw ArgumentError( - 'The parameters latitude and longitude should not be null.'); + 'The parameters latitude and longitude should not be null.', + ); } return Location._( @@ -74,10 +76,10 @@ class Location { /// Converts the [Location] instance into a [Map] instance that can be /// serialized to JSON. Map toJson() => { - 'latitude': latitude, - 'longitude': longitude, - 'timestamp': timestamp.millisecondsSinceEpoch, - }; + 'latitude': latitude, + 'longitude': longitude, + 'timestamp': timestamp.millisecondsSinceEpoch, + }; @override String toString() { diff --git a/geocoding_platform_interface/lib/src/models/models.dart b/geocoding_platform_interface/lib/legacy/src/models/models.dart similarity index 100% rename from geocoding_platform_interface/lib/src/models/models.dart rename to geocoding_platform_interface/lib/legacy/src/models/models.dart diff --git a/geocoding_platform_interface/lib/src/models/placemark.dart b/geocoding_platform_interface/lib/legacy/src/models/placemark.dart similarity index 91% rename from geocoding_platform_interface/lib/src/models/placemark.dart rename to geocoding_platform_interface/lib/legacy/src/models/placemark.dart index e833847..b451a3b 100644 --- a/geocoding_platform_interface/lib/src/models/placemark.dart +++ b/geocoding_platform_interface/lib/legacy/src/models/placemark.dart @@ -132,18 +132,18 @@ class Placemark { /// Converts the [Placemark] instance into a [Map] instance that can be /// serialized to JSON. Map toJson() => { - 'name': name, - 'street': street, - 'isoCountryCode': isoCountryCode, - 'country': country, - 'postalCode': postalCode, - 'administrativeArea': administrativeArea, - 'subAdministrativeArea': subAdministrativeArea, - 'locality': locality, - 'subLocality': subLocality, - 'thoroughfare': thoroughfare, - 'subThoroughfare': subThoroughfare, - }; + 'name': name, + 'street': street, + 'isoCountryCode': isoCountryCode, + 'country': country, + 'postalCode': postalCode, + 'administrativeArea': administrativeArea, + 'subAdministrativeArea': subAdministrativeArea, + 'locality': locality, + 'subLocality': subLocality, + 'thoroughfare': thoroughfare, + 'subThoroughfare': subThoroughfare, + }; @override String toString() { diff --git a/geocoding_platform_interface/lib/src/geocoding.dart b/geocoding_platform_interface/lib/src/geocoding.dart new file mode 100644 index 0000000..6d2e7e7 --- /dev/null +++ b/geocoding_platform_interface/lib/src/geocoding.dart @@ -0,0 +1,97 @@ +import 'package:flutter/widgets.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +import 'geocoding_platform_factory.dart'; +import 'types/types.dart'; + +/// Interface for a platform implementation of a [Geocoding] instance. +/// +/// Platform implementations should extend this class rather than implement it +/// as `geocoding` package does not consider newly added methods to be breaking +/// changes. Extending this class (using `extends`) ensures that the subclass +/// will get the default implementation, while platform implementations that +/// `implements` this interface will be broken by newly added +/// [Geocoding] methods. +abstract class Geocoding extends PlatformInterface { + /// Creates a new [PlatformWebViewController] + factory Geocoding(GeocodingCreationParams params) { + assert( + GeocodingPlatformFactory.instance != null, + 'A platform implementation for `geocoding` has not been set. Please ' + 'ensure that an implementation of `GeocodingPlatformFactory` has been ' + 'set te `GeocodingPlatformFactory.instance` before use. For unit ' + 'testing, `GeocodingPlatformFactory.instance` can be set with your own ' + 'test implementation.', + ); + final Geocoding geocoding = GeocodingPlatformFactory.instance! + .createGeocoding(params); + PlatformInterface.verify(geocoding, _token); + return geocoding; + } + + /// Used by the platform implementation to create a new [Geocoding]. + /// + /// Should only be used by platform implementations because they can't extend + /// a class that only contains a factory constructor. + @protected + Geocoding.implementation(this.params) : super(token: _token); + + static final Object _token = Object(); + + /// The parameters used to initialize the [Geocoding] instance. + final GeocodingCreationParams params; + + /// Returns a list of [Location] instances found for the supplied address. + /// + /// In most situations the returned list should only contain one entry. + /// However in some situations where the supplied address could not be + /// resolved into a single [Location], multiple [Location] instances may be + /// returned. + Future> locationFromAddress(String address, {Locale? locale}) { + throw UnimplementedError( + 'locationFromAddress() has not been implementated.', + ); + } + + /// Returns true if there is a geocoder implementation present that may return results. + /// If true, there is still no guarantee that any individual geocoding attempt will succeed. + /// + /// + /// This method is only implemented on Android, calling this on iOS always + /// returns [true]. + Future isPresent() { + throw UnimplementedError('isPresent() has not been implementated.'); + } + + /// Returns a list of [Placemark] instances found for the supplied + /// coordinates. + /// + /// In most situations the returned list should only contain one entry. + /// However in some situations where the supplied coordinates could not be + /// resolved into a single [Placemark], multiple [Placemark] instances may be + /// returned. + Future> placemarkFromCoordinates( + double latitude, + double longitude, { + Locale? locale, + }) { + throw UnimplementedError( + 'placemarkFromCoordinates() has not been implementated.', + ); + } + + /// Returns a list of [Placemark] instances found for the supplied address. + /// + /// In most situations the returned list should only contain one entry. + /// However in some situations where the supplied address could not be + /// resolved into a single [Placemark], multiple [Placemark] instances may be + /// returned. + Future> placemarkFromAddress( + String address, { + Locale? locale, + }) { + throw UnimplementedError( + 'placemarkFromAddress() has not been implementated.', + ); + } +} diff --git a/geocoding_platform_interface/lib/src/geocoding_platform_factory.dart b/geocoding_platform_interface/lib/src/geocoding_platform_factory.dart new file mode 100644 index 0000000..88c619a --- /dev/null +++ b/geocoding_platform_interface/lib/src/geocoding_platform_factory.dart @@ -0,0 +1,44 @@ +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +import 'geocoding.dart'; +import 'types/types.dart'; + +/// Interface for a platform specific implementation of the geocoding features. +abstract class GeocodingPlatformFactory extends PlatformInterface { + /// Creates a new [GeocodingPlatformFactory]. + GeocodingPlatformFactory() : super(token: _token); + + static final Object _token = Object(); + + static GeocodingPlatformFactory? _instance; + + /// The instance of [GeocodingPlatformFactory] to use. + /// + /// This should return a platform specific instance, which can be used to + /// access geocoding features for that platform. + static GeocodingPlatformFactory? get instance => _instance; + + /// Platform-specific plugins should set this with their own platform-specific + /// class that extends [GeocodingPlatformFactory] when they register + /// themselves. + static set instance(GeocodingPlatformFactory? instance) { + if (instance == null) { + throw AssertionError( + 'Platform interface can only be set to a non-null instance', + ); + } + + PlatformInterface.verify(instance, _token); + _instance = instance; + } + + /// Creates a new [Geocoding]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [Geocoding] in `geocoding` package instead. + Geocoding createGeocoding(GeocodingCreationParams params) { + throw UnimplementedError( + 'createGeocoding is not implemented on the current platform.', + ); + } +} diff --git a/geocoding_platform_interface/lib/src/types/geocoding_creation_params.dart b/geocoding_platform_interface/lib/src/types/geocoding_creation_params.dart new file mode 100644 index 0000000..cf5b544 --- /dev/null +++ b/geocoding_platform_interface/lib/src/types/geocoding_creation_params.dart @@ -0,0 +1,39 @@ +import 'package:meta/meta.dart'; + +/// Object specifying creation parameters for creating a [Geocoding]. +/// +/// Platform specific implementations can add additional fields by extending +/// this class. +/// +/// This example demonstrates how to extend the [GeocodingCreationParams] to +/// provide additional platform specific parameters. +/// +/// When extending [GeocodingCreationParams] additional +/// parameters should always accept `null` or have a default value to prevent +/// breaking changes. +/// +/// ```dart +/// class AndroidGeocodingCreationParams extends GeocodingCreationParams { +/// AndroidGeocodingCreationParams._( +/// // This parameter prevents breaking changes later. +/// // ignore: avoid_unused_constructor_parameters +/// GeocodingCreationParams params, { +/// this.filter, +/// }) : super(); +/// +/// factory AndroidGeocodingCreationParams.fromGeocodingCreationParams( +/// GeocodingCreationParams params, { +/// String? filter, +/// }) { +/// return AndroidGeocodingCreationParams._(params, filter: filter); +/// } +/// +/// final String? filter; +/// } +/// ``` +@immutable +class GeocodingCreationParams { + /// Used by the platform implementation to create a new + /// [GeocodingCreationParams]. + const GeocodingCreationParams(); +} diff --git a/geocoding_platform_interface/lib/src/types/location.dart b/geocoding_platform_interface/lib/src/types/location.dart new file mode 100644 index 0000000..0ff6d0c --- /dev/null +++ b/geocoding_platform_interface/lib/src/types/location.dart @@ -0,0 +1,35 @@ +import 'package:meta/meta.dart'; + +/// Describes a location on earth represented by geographical coordinates.the +/// +/// Platform specific implementations can add additional fields by extending +/// this class. +@immutable +class Location { + /// Creates a [Location]. + const Location({ + required this.latitude, + required this.longitude, + required this.timestamp, + }); + + /// The latitude associated with the placemark. + final double latitude; + + /// The longitude associated with the placemark. + final double longitude; + + /// The UTC timestamp the coordinates have been requested. + final DateTime timestamp; + + @override + bool operator ==(Object other) => + other is Location && + other.latitude == latitude && + other.longitude == longitude && + other.timestamp == timestamp; + + @override + int get hashCode => + latitude.hashCode ^ longitude.hashCode ^ timestamp.hashCode; +} diff --git a/geocoding_platform_interface/lib/src/types/placemark.dart b/geocoding_platform_interface/lib/src/types/placemark.dart new file mode 100644 index 0000000..672cee4 --- /dev/null +++ b/geocoding_platform_interface/lib/src/types/placemark.dart @@ -0,0 +1,83 @@ +import 'package:meta/meta.dart'; + +/// Defines the parameters that describe a result of the (reserve)geocoding +/// action. +@immutable +class Placemark { + /// Creates a [Placemark]. + const Placemark({ + this.name, + this.street, + this.isoCountryCode, + this.country, + this.postalCode, + this.administrativeArea, + this.subAdministrativeArea, + this.locality, + this.subLocality, + this.thoroughfare, + this.subThoroughfare, + }); + + /// The name associated with the placemark. + final String? name; + + /// The street associated with the placemark. + final String? street; + + /// The abbreviated country name, according to the two letter (alpha-2) [ISO standard](https://www.iso.org/iso-3166-country-codes.html). + final String? isoCountryCode; + + /// The name of the country associated with the placemark. + final String? country; + + /// The postal code associated with the placemark. + final String? postalCode; + + /// The name of the state or province associated with the placemark. + final String? administrativeArea; + + /// Additional administrative area information for the placemark. + final String? subAdministrativeArea; + + /// The name of the city associated with the placemark. + final String? locality; + + /// Additional city-level information for the placemark. + final String? subLocality; + + /// The street address associated with the placemark. + final String? thoroughfare; + + /// Additional street address information for the placemark. + final String? subThoroughfare; + + @override + bool operator ==(Object other) => + other is Placemark && + other.administrativeArea == administrativeArea && + other.country == country && + other.isoCountryCode == isoCountryCode && + other.locality == locality && + other.name == name && + other.postalCode == postalCode && + other.street == street && + other.subAdministrativeArea == subAdministrativeArea && + other.subLocality == subLocality && + other.subThoroughfare == subThoroughfare && + other.thoroughfare == thoroughfare; + + @override + int get hashCode => + administrativeArea.hashCode ^ + country.hashCode ^ + isoCountryCode.hashCode ^ + locality.hashCode ^ + name.hashCode ^ + postalCode.hashCode ^ + street.hashCode ^ + subAdministrativeArea.hashCode ^ + subLocality.hashCode ^ + subThoroughfare.hashCode ^ + thoroughfare.hashCode; +} diff --git a/geocoding_platform_interface/lib/src/types/types.dart b/geocoding_platform_interface/lib/src/types/types.dart new file mode 100644 index 0000000..15bc468 --- /dev/null +++ b/geocoding_platform_interface/lib/src/types/types.dart @@ -0,0 +1,5 @@ +// A barrel file exporting all publicly available types. + +export 'geocoding_creation_params.dart'; +export 'location.dart'; +export 'placemark.dart'; diff --git a/geocoding_platform_interface/pubspec.yaml b/geocoding_platform_interface/pubspec.yaml index 0805f12..1e8e5bd 100644 --- a/geocoding_platform_interface/pubspec.yaml +++ b/geocoding_platform_interface/pubspec.yaml @@ -3,11 +3,11 @@ description: A common platform interface for the geocoding plugin. homepage: https://github.com/baseflow/flutter-geocoding/tree/main/geocoding_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: 3.2.1 +version: 4.0.0 environment: - sdk: ">=3.3.0 <4.0.0" - flutter: ">=3.0.0" + sdk: ^3.8.1 + flutter: ">=3.7.0" dependencies: flutter: @@ -20,6 +20,7 @@ dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^5.0.0 + flutter_lints: ^6.0.0 mockito: ^5.0.0 + build_runner: ^2.5.4 diff --git a/geocoding_platform_interface/test/geocoding_platform_interface_test.dart b/geocoding_platform_interface/test/legacy/geocoding_platform_interface_test.dart similarity index 53% rename from geocoding_platform_interface/test/geocoding_platform_interface_test.dart rename to geocoding_platform_interface/test/legacy/geocoding_platform_interface_test.dart index ce0df16..a90dd0a 100644 --- a/geocoding_platform_interface/test/geocoding_platform_interface_test.dart +++ b/geocoding_platform_interface/test/legacy/geocoding_platform_interface_test.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import 'package:flutter_test/flutter_test.dart'; -import 'package:geocoding_platform_interface/geocoding_platform_interface.dart'; +import 'package:geocoding_platform_interface/legacy/geocoding_platform_interface.dart'; import 'package:mockito/mockito.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -38,60 +38,61 @@ void main() { }); test( - // ignore: lines_longer_than_80_chars - 'Default implementation of locationFromAddress should throw unimplemented error', - () { - // Arrange - final geocodingPlatform = ExtendsGeocodingPlatform(); - - // Act & Assert - expect( - () => geocodingPlatform.locationFromAddress('address'), - throwsUnimplementedError, - ); - }); + // ignore: lines_longer_than_80_chars + 'Default implementation of locationFromAddress should throw unimplemented error', + () { + // Arrange + final geocodingPlatform = ExtendsGeocodingPlatform(); + + // Act & Assert + expect( + () => geocodingPlatform.locationFromAddress('address'), + throwsUnimplementedError, + ); + }, + ); test( - // ignore: lines_longer_than_80_chars - 'Default implementation of isPresent should throw unimplemented error', - () { - // Arrange - final geocodingPlatform = ExtendsGeocodingPlatform(); - - // Act & Assert - expect( - () => geocodingPlatform.isPresent(), - throwsUnimplementedError, - ); - }); + // ignore: lines_longer_than_80_chars + 'Default implementation of isPresent should throw unimplemented error', + () { + // Arrange + final geocodingPlatform = ExtendsGeocodingPlatform(); + + // Act & Assert + expect(() => geocodingPlatform.isPresent(), throwsUnimplementedError); + }, + ); test( - // ignore: lines_longer_than_80_chars - 'Default implementation of placemarkFromCoordinates should throw unimplemented error', - () { - // Arrange - final geocodingPlatform = ExtendsGeocodingPlatform(); - - // Act & Assert - expect( - () => geocodingPlatform.placemarkFromCoordinates(0, 0), - throwsUnimplementedError, - ); - }); + // ignore: lines_longer_than_80_chars + 'Default implementation of placemarkFromCoordinates should throw unimplemented error', + () { + // Arrange + final geocodingPlatform = ExtendsGeocodingPlatform(); + + // Act & Assert + expect( + () => geocodingPlatform.placemarkFromCoordinates(0, 0), + throwsUnimplementedError, + ); + }, + ); test( - // ignore: lines_longer_than_80_chars - 'Default implementation of setLocale should throw unimplemented error', - () { - // Arrange - final geocodingPlatform = ExtendsGeocodingPlatform(); - - // Act & Assert - expect( - () => geocodingPlatform.setLocaleIdentifier('en_US'), - throwsUnimplementedError, - ); - }); + // ignore: lines_longer_than_80_chars + 'Default implementation of setLocale should throw unimplemented error', + () { + // Arrange + final geocodingPlatform = ExtendsGeocodingPlatform(); + + // Act & Assert + expect( + () => geocodingPlatform.setLocaleIdentifier('en_US'), + throwsUnimplementedError, + ); + }, + ); }); } @@ -104,7 +105,6 @@ class MockGeocodingPlatform extends Mock with // ignore: prefer_mixin MockPlatformInterfaceMixin - implements - GeocodingPlatform {} + implements GeocodingPlatform {} class ExtendsGeocodingPlatform extends GeocodingPlatform {} diff --git a/geocoding_platform_interface/test/legacy/src/models/location_test.dart b/geocoding_platform_interface/test/legacy/src/models/location_test.dart new file mode 100644 index 0000000..60ef96b --- /dev/null +++ b/geocoding_platform_interface/test/legacy/src/models/location_test.dart @@ -0,0 +1,122 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:geocoding_platform_interface/legacy/geocoding_platform_interface.dart'; + +void main() { + group('hashCode tests:', () { + test( + 'hashCode hould be the same for two instances with the same values', + () { + // Arrange + final firstLocation = Location( + latitude: 0, + longitude: 0, + timestamp: DateTime.fromMillisecondsSinceEpoch((0)), + ); + final secondLocation = Location( + latitude: 0, + longitude: 0, + timestamp: DateTime.fromMillisecondsSinceEpoch((0)), + ); + + // Act & Assert + expect(firstLocation.hashCode, secondLocation.hashCode); + }, + ); + + test( + 'hashCode should not match when the latitude property is different', + () { + // Arrange + final firstLocation = Location( + latitude: 0, + longitude: 0, + timestamp: DateTime.fromMillisecondsSinceEpoch(0), + ); + final secondLocation = Location( + latitude: 1, + longitude: 0, + timestamp: DateTime.fromMillisecondsSinceEpoch(0), + ); + + // Act & Assert + expect(firstLocation.hashCode != secondLocation.hashCode, true); + }, + ); + + test( + 'hashCode should not match when the longitude property is different', + () { + // Arrange + final firstLocation = Location( + latitude: 0, + longitude: 0, + timestamp: DateTime.fromMillisecondsSinceEpoch(0), + ); + final secondLocation = Location( + latitude: 0, + longitude: 1, + timestamp: DateTime.fromMillisecondsSinceEpoch(0), + ); + + // Act & Assert + expect(firstLocation.hashCode != secondLocation.hashCode, true); + }, + ); + + test( + 'hashCode should not match when the timestamp property is different', + () { + // Arrange + final firstLocation = Location( + latitude: 0, + longitude: 0, + timestamp: DateTime.fromMillisecondsSinceEpoch(0), + ); + final secondLocation = Location( + latitude: 0, + longitude: 0, + timestamp: DateTime.fromMillisecondsSinceEpoch(1), + ); + + // Act & Assert + expect(firstLocation.hashCode != secondLocation.hashCode, true); + }, + ); + }); + + group('fromMap tests:', () { + test('fromMap should throw argument error when message is null', () { + expect(() => Location.fromMap(null), throwsArgumentError); + }); + + test( + 'fromMap throws argument error when latitude or longitude are null', + () { + final location = { + 'latitude': null, + 'longitude': null, + 'timestamp': 1615216821218, + }; + expect(() => Location.fromMap(location), throwsArgumentError); + }, + ); + }); + + group('toString tests:', () { + test('toString should list the contents of all properties', () { + final mockLocation = Location( + latitude: 52.2165157, + longitude: 6.9437819, + timestamp: DateTime.fromMillisecondsSinceEpoch(0).toUtc(), + ); + + final expected = + ''' + Latitude: ${mockLocation.latitude}, + Longitude: ${mockLocation.longitude}, + Timestamp: ${mockLocation.timestamp}'''; + + expect(mockLocation.toString(), expected); + }); + }); +} diff --git a/geocoding_platform_interface/test/legacy/src/models/placemark_test.dart b/geocoding_platform_interface/test/legacy/src/models/placemark_test.dart new file mode 100644 index 0000000..5d331b2 --- /dev/null +++ b/geocoding_platform_interface/test/legacy/src/models/placemark_test.dart @@ -0,0 +1,465 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:geocoding_platform_interface/legacy/geocoding_platform_interface.dart'; + +void main() { + group('hashCode tests:', () { + test( + 'hashCode hould be the same for two instances with the same values', + () { + // Arrange + const firstPlacemark = Placemark(); + const secondPlacemark = Placemark(); + + // Act & Assert + expect(firstPlacemark.hashCode, secondPlacemark.hashCode); + }, + ); + + test('hashCode should not match when the name property is different', () { + // Arrange + const firstPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + const secondPlacemark = Placemark( + name: 'different test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + + // Act & Assert + expect(firstPlacemark.hashCode != secondPlacemark.hashCode, true); + }); + + test( + // ignore: lines_longer_than_80_chars + 'hashCode should not match when the street property is different', + () { + // Arrange + const firstPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + const secondPlacemark = Placemark( + name: 'test value', + street: 'different test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + + // Act & Assert + expect(firstPlacemark.hashCode != secondPlacemark.hashCode, true); + }, + ); + + test( + // ignore: lines_longer_than_80_chars + 'hashCode should not match when the isoCountryCode property is different', + () { + // Arrange + const firstPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + const secondPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'different test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + + // Act & Assert + expect(firstPlacemark.hashCode != secondPlacemark.hashCode, true); + }, + ); + + test( + 'hashCode should not match when the country property is different', + () { + // Arrange + const firstPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + const secondPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'different test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + + // Act & Assert + expect(firstPlacemark.hashCode != secondPlacemark.hashCode, true); + }, + ); + + test( + 'hashCode should not match when the postalCode property is different', + () { + // Arrange + const firstPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + const secondPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'different test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + + // Act & Assert + expect(firstPlacemark.hashCode != secondPlacemark.hashCode, true); + }, + ); + + test( + // ignore: lines_longer_than_80_chars + 'hashCode should not match when the administrativeArea property is different', + () { + // Arrange + const firstPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + const secondPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'different test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + + // Act & Assert + expect(firstPlacemark.hashCode != secondPlacemark.hashCode, true); + }, + ); + + test( + // ignore: lines_longer_than_80_chars + 'hashCode should not match when the subAdministrativeArea property is different', + () { + // Arrange + const firstPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + const secondPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'different test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + + // Act & Assert + expect(firstPlacemark.hashCode != secondPlacemark.hashCode, true); + }, + ); + + test( + // ignore: lines_longer_than_80_chars + 'hashCode should not match when the locality property is different', + () { + // Arrange + const firstPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + const secondPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'different test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + + // Act & Assert + expect(firstPlacemark.hashCode != secondPlacemark.hashCode, true); + }, + ); + + test( + // ignore: lines_longer_than_80_chars + 'hashCode should not match when the subLocality property is different', + () { + // Arrange + const firstPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + const secondPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'different test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + + // Act & Assert + expect(firstPlacemark.hashCode != secondPlacemark.hashCode, true); + }, + ); + + test( + // ignore: lines_longer_than_80_chars + 'hashCode should not match when the thoroughfare property is different', + () { + // Arrange + const firstPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + const secondPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'different test value', + subThoroughfare: 'test value', + ); + + // Act & Assert + expect(firstPlacemark.hashCode != secondPlacemark.hashCode, true); + }, + ); + + test( + // ignore: lines_longer_than_80_chars + 'hashCode should not match when the subThoroughfare property is different', + () { + // Arrange + const firstPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'test value', + ); + const secondPlacemark = Placemark( + name: 'test value', + street: 'test value', + isoCountryCode: 'test value', + country: 'test value', + postalCode: 'test value', + administrativeArea: 'test value', + subAdministrativeArea: 'test value', + locality: 'test value', + subLocality: 'test value', + thoroughfare: 'test value', + subThoroughfare: 'different test value', + ); + + // Act & Assert + expect(firstPlacemark.hashCode != secondPlacemark.hashCode, true); + }, + ); + }); + + group('fromMaps tests:', () { + test('fromMaps should throw argument error when message is null', () { + expect(() => Placemark.fromMaps(null), throwsArgumentError); + }); + }); + + group('fromMap tests:', () { + test('fromMap should throw argument error when message is null', () { + expect(() => Placemark.fromMap(null), throwsArgumentError); + }); + }); + + group('toString tests:', () { + test('toString should list the contents of all properties', () { + const mockPlacemark = Placemark( + administrativeArea: 'Overijssel', + country: 'Netherlands', + isoCountryCode: 'NL', + locality: 'Enschede', + name: 'Gronausestraat', + postalCode: '', + street: 'Gronausestraat 710', + subAdministrativeArea: 'Enschede', + subLocality: 'Enschmarke', + subThoroughfare: '', + thoroughfare: 'Gronausestraat', + ); + + final expected = + ''' + Name: ${mockPlacemark.name}, + Street: ${mockPlacemark.street}, + ISO Country Code: ${mockPlacemark.isoCountryCode}, + Country: ${mockPlacemark.country}, + Postal code: ${mockPlacemark.postalCode}, + Administrative area: ${mockPlacemark.administrativeArea}, + Subadministrative area: ${mockPlacemark.subAdministrativeArea}, + Locality: ${mockPlacemark.locality}, + Sublocality: ${mockPlacemark.subLocality}, + Thoroughfare: ${mockPlacemark.thoroughfare}, + Subthoroughfare: ${mockPlacemark.subThoroughfare}'''; + + expect(mockPlacemark.toString(), expected); + }); + }); +} diff --git a/geocoding_platform_interface/test/src/geocoding_platform_factory_test.dart b/geocoding_platform_interface/test/src/geocoding_platform_factory_test.dart new file mode 100644 index 0000000..d9c72ce --- /dev/null +++ b/geocoding_platform_interface/test/src/geocoding_platform_factory_test.dart @@ -0,0 +1,71 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:geocoding_platform_interface/geocoding_platform_interface.dart'; +import 'package:mockito/mockito.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$GeocodingPlatformFactory', () { + test('Default instance equals null', () { + expect(GeocodingPlatformFactory.instance, isNull); + }); + + test('Cannot be implemented with `implements`', () { + expect(() { + GeocodingPlatformFactory.instance = + ImplementsGeocodingPlatformFactory(); + // In versions of `package:plugin_platform_interface` prior to fixing + // https://github.com/flutter/flutter/issues/109339, an attempt to + // implement a platform interface using `implements` would sometimes + // throw a `NoSuchMethodError` and other times throw an + // `AssertionError`. After the issue is fixed, an `AssertionError` will + // always be thrown. For the purpose of this test, we don't really care + // what exception is thrown, so just allow any exception. + }, throwsA(anything)); + }); + + test('Can be extended', () { + GeocodingPlatformFactory.instance = ExtendsGeocodingPlatformFactory(); + }); + + test('Can be mocked with `implements`', () { + final mock = MockGeocodingPlatformFactory(); + GeocodingPlatformFactory.instance = mock; + }); + + test( + // ignore: lines_longer_than_80_chars + 'Default implementation of createGeocoding should throw unimplemented error', + () { + // Arrange + final geocodingPlatform = ExtendsGeocodingPlatformFactory(); + + // Act & Assert + expect( + () => geocodingPlatform.createGeocoding( + const GeocodingCreationParams(), + ), + throwsUnimplementedError, + ); + }, + ); + }); +} + +class ImplementsGeocodingPlatformFactory implements GeocodingPlatformFactory { + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +class MockGeocodingPlatformFactory extends Mock + with + // ignore: prefer_mixin + MockPlatformInterfaceMixin + implements GeocodingPlatformFactory {} + +class ExtendsGeocodingPlatformFactory extends GeocodingPlatformFactory {} diff --git a/geocoding_platform_interface/test/src/geocoding_test.dart b/geocoding_platform_interface/test/src/geocoding_test.dart new file mode 100644 index 0000000..ab8cdce --- /dev/null +++ b/geocoding_platform_interface/test/src/geocoding_test.dart @@ -0,0 +1,141 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:geocoding_platform_interface/geocoding_platform_interface.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +import 'geocoding_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + setUp(() { + GeocodingPlatformFactory.instance = MockGeocodingPlatformFactoryWithMixin(); + }); + + test('Cannot be implemented with `implements`', () { + when( + (GeocodingPlatformFactory.instance! as MockGeocodingPlatformFactory) + .createGeocoding(any), + ).thenReturn(ImplementsGeocoding()); + + expect(() { + Geocoding(const GeocodingCreationParams()); + + // In versions of `package:plugin_platform_interface` prior to fixing + // https://github.com/flutter/flutter/issues/109339, an attempt to + // implement a platform interface using `implements` would sometimes + // throw a `NoSuchMethodError` and other times throw an + // `AssertionError`. After the issue is fixed, an `AssertionError` will + // always be thrown. For the purpose of this test, we don't really care + // what exception is thrown, so just allow any exception. + }, throwsA(anything)); + }); + + test('Can be extended', () { + const GeocodingCreationParams params = GeocodingCreationParams(); + when( + (GeocodingPlatformFactory.instance! as MockGeocodingPlatformFactory) + .createGeocoding(any), + ).thenReturn(ExtendsGeocoding(params)); + + expect(Geocoding(params), isNotNull); + }); + + test('Can be mocked with `implements`', () { + when( + (GeocodingPlatformFactory.instance! as MockGeocodingPlatformFactory) + .createGeocoding(any), + ).thenReturn(MockGeocoding()); + + expect(Geocoding(const GeocodingCreationParams()), isNotNull); + }); + + test( + // ignore: lines_longer_than_80_chars + 'Default implementation of locationFromAddress should throw unimplemented error', + () { + // Arrange + final geocodingPlatform = ExtendsGeocoding( + const GeocodingCreationParams(), + ); + + // Act & Assert + expect( + () => geocodingPlatform.locationFromAddress('address'), + throwsUnimplementedError, + ); + }, + ); + + test( + // ignore: lines_longer_than_80_chars + 'Default implementation of isPresent should throw unimplemented error', + () { + // Arrange + final geocodingPlatform = ExtendsGeocoding( + const GeocodingCreationParams(), + ); + + // Act & Assert + expect(() => geocodingPlatform.isPresent(), throwsUnimplementedError); + }, + ); + + test( + // ignore: lines_longer_than_80_chars + 'Default implementation of placemarkFromAddress should throw unimplemented error', + () { + // Arrange + final geocodingPlatform = ExtendsGeocoding( + const GeocodingCreationParams(), + ); + + // Act & Assert + expect( + () => geocodingPlatform.placemarkFromAddress('address'), + throwsUnimplementedError, + ); + }, + ); + + test( + // ignore: lines_longer_than_80_chars + 'Default implementation of placemarkFromCoordinates should throw unimplemented error', + () { + // Arrange + final geocodingPlatform = ExtendsGeocoding( + const GeocodingCreationParams(), + ); + + // Act & Assert + expect( + () => geocodingPlatform.placemarkFromCoordinates(0.0, 0.0), + throwsUnimplementedError, + ); + }, + ); +} + +class MockGeocodingPlatformFactoryWithMixin extends MockGeocodingPlatformFactory + with + // ignore: prefer_mixin + MockPlatformInterfaceMixin {} + +class ImplementsGeocoding implements Geocoding { + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +class MockGeocoding extends Mock + with + // ignore: prefer_mixin + MockPlatformInterfaceMixin + implements Geocoding {} + +class ExtendsGeocoding extends Geocoding { + ExtendsGeocoding(super.params) : super.implementation(); +} diff --git a/geocoding_platform_interface/test/src/geocoding_test.mocks.dart b/geocoding_platform_interface/test/src/geocoding_test.mocks.dart new file mode 100644 index 0000000..aba4b61 --- /dev/null +++ b/geocoding_platform_interface/test/src/geocoding_test.mocks.dart @@ -0,0 +1,49 @@ +// Mocks generated by Mockito 5.4.4 from annotations +// in geocoding_platform_interface/test/src/geocoding_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:geocoding_platform_interface/src/geocoding.dart' as _i2; +import 'package:geocoding_platform_interface/src/geocoding_platform_factory.dart' + as _i3; +import 'package:geocoding_platform_interface/src/types/types.dart' as _i4; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeGeocoding_0 extends _i1.SmartFake implements _i2.Geocoding { + _FakeGeocoding_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [GeocodingPlatformFactory]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockGeocodingPlatformFactory extends _i1.Mock + implements _i3.GeocodingPlatformFactory { + @override + _i2.Geocoding createGeocoding(_i4.GeocodingCreationParams? params) => + (super.noSuchMethod( + Invocation.method(#createGeocoding, [params]), + returnValue: _FakeGeocoding_0( + this, + Invocation.method(#createGeocoding, [params]), + ), + returnValueForMissingStub: _FakeGeocoding_0( + this, + Invocation.method(#createGeocoding, [params]), + ), + ) + as _i2.Geocoding); +} diff --git a/geocoding_platform_interface/test/src/models/location_test.dart b/geocoding_platform_interface/test/src/models/location_test.dart deleted file mode 100644 index cc8d975..0000000 --- a/geocoding_platform_interface/test/src/models/location_test.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:geocoding_platform_interface/geocoding_platform_interface.dart'; - -void main() { - group('hashCode tests:', () { - test('hashCode hould be the same for two instances with the same values', - () { - // Arrange - final firstLocation = Location( - latitude: 0, - longitude: 0, - timestamp: DateTime.fromMillisecondsSinceEpoch((0))); - final secondLocation = Location( - latitude: 0, - longitude: 0, - timestamp: DateTime.fromMillisecondsSinceEpoch((0))); - - // Act & Assert - expect( - firstLocation.hashCode, - secondLocation.hashCode, - ); - }); - - test('hashCode should not match when the latitude property is different', - () { - // Arrange - final firstLocation = Location( - latitude: 0, - longitude: 0, - timestamp: DateTime.fromMillisecondsSinceEpoch(0), - ); - final secondLocation = Location( - latitude: 1, - longitude: 0, - timestamp: DateTime.fromMillisecondsSinceEpoch(0), - ); - - // Act & Assert - expect( - firstLocation.hashCode != secondLocation.hashCode, - true, - ); - }); - - test('hashCode should not match when the longitude property is different', - () { - // Arrange - final firstLocation = Location( - latitude: 0, - longitude: 0, - timestamp: DateTime.fromMillisecondsSinceEpoch(0), - ); - final secondLocation = Location( - latitude: 0, - longitude: 1, - timestamp: DateTime.fromMillisecondsSinceEpoch(0), - ); - - // Act & Assert - expect( - firstLocation.hashCode != secondLocation.hashCode, - true, - ); - }); - - test('hashCode should not match when the timestamp property is different', - () { - // Arrange - final firstLocation = Location( - latitude: 0, - longitude: 0, - timestamp: DateTime.fromMillisecondsSinceEpoch(0), - ); - final secondLocation = Location( - latitude: 0, - longitude: 0, - timestamp: DateTime.fromMillisecondsSinceEpoch(1), - ); - - // Act & Assert - expect( - firstLocation.hashCode != secondLocation.hashCode, - true, - ); - }); - }); - - group('fromMap tests:', () { - test('fromMap should throw argument error when message is null', () { - expect(() => Location.fromMap(null), throwsArgumentError); - }); - - test('fromMap throws argument error when latitude or longitude are null', - () { - final location = { - 'latitude': null, - 'longitude': null, - 'timestamp': 1615216821218, - }; - expect(() => Location.fromMap(location), throwsArgumentError); - }); - }); - - group('toString tests:', () { - test('toString should list the contents of all properties', () { - final mockLocation = Location( - latitude: 52.2165157, - longitude: 6.9437819, - timestamp: DateTime.fromMillisecondsSinceEpoch(0).toUtc(), - ); - - final expected = ''' - Latitude: ${mockLocation.latitude}, - Longitude: ${mockLocation.longitude}, - Timestamp: ${mockLocation.timestamp}'''; - - expect(mockLocation.toString(), expected); - }); - }); -} diff --git a/geocoding_platform_interface/test/src/models/placemark_test.dart b/geocoding_platform_interface/test/src/models/placemark_test.dart deleted file mode 100644 index d1eb270..0000000 --- a/geocoding_platform_interface/test/src/models/placemark_test.dart +++ /dev/null @@ -1,484 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:geocoding_platform_interface/geocoding_platform_interface.dart'; - -void main() { - group('hashCode tests:', () { - test('hashCode hould be the same for two instances with the same values', - () { - // Arrange - const firstPlacemark = Placemark(); - const secondPlacemark = Placemark(); - - // Act & Assert - expect( - firstPlacemark.hashCode, - secondPlacemark.hashCode, - ); - }); - - test('hashCode should not match when the name property is different', () { - // Arrange - const firstPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - const secondPlacemark = Placemark( - name: 'different test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - - // Act & Assert - expect( - firstPlacemark.hashCode != secondPlacemark.hashCode, - true, - ); - }); - - test( - // ignore: lines_longer_than_80_chars - 'hashCode should not match when the street property is different', () { - // Arrange - const firstPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - const secondPlacemark = Placemark( - name: 'test value', - street: 'different test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - - // Act & Assert - expect( - firstPlacemark.hashCode != secondPlacemark.hashCode, - true, - ); - }); - - test( - // ignore: lines_longer_than_80_chars - 'hashCode should not match when the isoCountryCode property is different', - () { - // Arrange - const firstPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - const secondPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'different test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - - // Act & Assert - expect( - firstPlacemark.hashCode != secondPlacemark.hashCode, - true, - ); - }); - - test('hashCode should not match when the country property is different', - () { - // Arrange - const firstPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - const secondPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'different test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - - // Act & Assert - expect( - firstPlacemark.hashCode != secondPlacemark.hashCode, - true, - ); - }); - - test('hashCode should not match when the postalCode property is different', - () { - // Arrange - const firstPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - const secondPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'different test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - - // Act & Assert - expect( - firstPlacemark.hashCode != secondPlacemark.hashCode, - true, - ); - }); - - test( - // ignore: lines_longer_than_80_chars - 'hashCode should not match when the administrativeArea property is different', - () { - // Arrange - const firstPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - const secondPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'different test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - - // Act & Assert - expect( - firstPlacemark.hashCode != secondPlacemark.hashCode, - true, - ); - }); - - test( - // ignore: lines_longer_than_80_chars - 'hashCode should not match when the subAdministrativeArea property is different', - () { - // Arrange - const firstPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - const secondPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'different test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - - // Act & Assert - expect( - firstPlacemark.hashCode != secondPlacemark.hashCode, - true, - ); - }); - - test( - // ignore: lines_longer_than_80_chars - 'hashCode should not match when the locality property is different', - () { - // Arrange - const firstPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - const secondPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'different test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - - // Act & Assert - expect( - firstPlacemark.hashCode != secondPlacemark.hashCode, - true, - ); - }); - - test( - // ignore: lines_longer_than_80_chars - 'hashCode should not match when the subLocality property is different', - () { - // Arrange - const firstPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - const secondPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'different test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - - // Act & Assert - expect( - firstPlacemark.hashCode != secondPlacemark.hashCode, - true, - ); - }); - - test( - // ignore: lines_longer_than_80_chars - 'hashCode should not match when the thoroughfare property is different', - () { - // Arrange - const firstPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - const secondPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'different test value', - subThoroughfare: 'test value', - ); - - // Act & Assert - expect( - firstPlacemark.hashCode != secondPlacemark.hashCode, - true, - ); - }); - - test( - // ignore: lines_longer_than_80_chars - 'hashCode should not match when the subThoroughfare property is different', - () { - // Arrange - const firstPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'test value', - ); - const secondPlacemark = Placemark( - name: 'test value', - street: 'test value', - isoCountryCode: 'test value', - country: 'test value', - postalCode: 'test value', - administrativeArea: 'test value', - subAdministrativeArea: 'test value', - locality: 'test value', - subLocality: 'test value', - thoroughfare: 'test value', - subThoroughfare: 'different test value', - ); - - // Act & Assert - expect( - firstPlacemark.hashCode != secondPlacemark.hashCode, - true, - ); - }); - }); - - group('fromMaps tests:', () { - test('fromMaps should throw argument error when message is null', () { - expect(() => Placemark.fromMaps(null), throwsArgumentError); - }); - }); - - group('fromMap tests:', () { - test('fromMap should throw argument error when message is null', () { - expect(() => Placemark.fromMap(null), throwsArgumentError); - }); - }); - - group('toString tests:', () { - test('toString should list the contents of all properties', () { - const mockPlacemark = Placemark( - administrativeArea: 'Overijssel', - country: 'Netherlands', - isoCountryCode: 'NL', - locality: 'Enschede', - name: 'Gronausestraat', - postalCode: '', - street: 'Gronausestraat 710', - subAdministrativeArea: 'Enschede', - subLocality: 'Enschmarke', - subThoroughfare: '', - thoroughfare: 'Gronausestraat'); - - final expected = ''' - Name: ${mockPlacemark.name}, - Street: ${mockPlacemark.street}, - ISO Country Code: ${mockPlacemark.isoCountryCode}, - Country: ${mockPlacemark.country}, - Postal code: ${mockPlacemark.postalCode}, - Administrative area: ${mockPlacemark.administrativeArea}, - Subadministrative area: ${mockPlacemark.subAdministrativeArea}, - Locality: ${mockPlacemark.locality}, - Sublocality: ${mockPlacemark.subLocality}, - Thoroughfare: ${mockPlacemark.thoroughfare}, - Subthoroughfare: ${mockPlacemark.subThoroughfare}'''; - - expect(mockPlacemark.toString(), expected); - }); - }); -}