From f7ee480107889156e9eff8705b64c261decebfab Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Sun, 2 Jun 2024 19:46:43 +0200 Subject: [PATCH] feat!: use FormatException instead of custom ValidationException --- lib/src/binding_coap/coap_extensions.dart | 2 +- lib/src/binding_mqtt/mqtt_extensions.dart | 2 +- lib/src/core/definitions/context.dart | 10 +++---- .../definitions/extensions/json_parser.dart | 13 ++++----- lib/src/core/definitions/operation_type.dart | 3 +- .../core/definitions/thing_description.dart | 3 +- lib/src/core/exceptions.dart | 28 ------------------- .../core/implementation/augmented_form.dart | 5 ++-- .../core/implementation/content_serdes.dart | 5 ++-- .../core/implementation/thing_discovery.dart | 2 +- test/binding_coap/coap_definitions_test.dart | 4 +-- test/binding_mqtt/mqtt_extension_test.dart | 2 +- test/core/augmented_form_test.dart | 4 +-- test/core/consumed_thing_test.dart | 2 +- test/core/content_serdes_test.dart | 7 ++--- test/core/context_test.dart | 5 ++-- test/core/definitions_test.dart | 12 ++++---- test/core/exceptions_test.dart | 10 ------- test/core/thing_description_test.dart | 4 +-- 19 files changed, 38 insertions(+), 85 deletions(-) diff --git a/lib/src/binding_coap/coap_extensions.dart b/lib/src/binding_coap/coap_extensions.dart index 1a463c2b..2789d445 100644 --- a/lib/src/binding_coap/coap_extensions.dart +++ b/lib/src/binding_coap/coap_extensions.dart @@ -83,7 +83,7 @@ extension CoapFormExtension on AugmentedForm { return BlockSize.fromDecodedValue(value); // ignore: avoid_catching_errors } on ArgumentError { - throw ValidationException( + throw FormatException( "Encountered invalid blocksize $value in CoAP form", ); } diff --git a/lib/src/binding_mqtt/mqtt_extensions.dart b/lib/src/binding_mqtt/mqtt_extensions.dart index 9adff68e..6607cc0f 100644 --- a/lib/src/binding_mqtt/mqtt_extensions.dart +++ b/lib/src/binding_mqtt/mqtt_extensions.dart @@ -138,7 +138,7 @@ extension MqttFormExtension on AugmentedForm { // TODO: This validation should maybe already happen earlier. if (qosValue != null) { - throw ValidationException( + throw FormatException( "Encountered unknown QoS value $qosValue. " "in form with href $href of Thing Description with Identifier " "$tdIdentifier.", diff --git a/lib/src/core/definitions/context.dart b/lib/src/core/definitions/context.dart index 54d462ec..c06e9a32 100644 --- a/lib/src/core/definitions/context.dart +++ b/lib/src/core/definitions/context.dart @@ -8,8 +8,6 @@ import "package:collection/collection.dart"; import "package:curie/curie.dart"; import "package:meta/meta.dart"; -import "../exceptions.dart"; - const _tdVersion10ContextUrl = "https://www.w3.org/2019/wot/td/v1"; const _tdVersion11ContextUrl = "https://www.w3.org/2022/wot/td/v1.1"; @@ -30,14 +28,14 @@ final class Context { final firstContextEntry = contextEntries.firstOrNull; if (firstContextEntry is! SingleContextEntry) { - throw const ValidationException("Missing TD context URL."); + throw const FormatException("Missing TD context URL."); } final firstContextValue = firstContextEntry.value; if (![_tdVersion10ContextUrl, _tdVersion11ContextUrl] .contains(firstContextValue)) { - throw ValidationException( + throw FormatException( "Encountered invalid TD context URL $firstContextEntry", ); } @@ -142,12 +140,12 @@ final class SingleContextEntry extends ContextEntry { /// Creates a new [SingleContextEntry] from a [string] that represents a URI. /// /// If the [string] should not be a valid URI, this factory constructor will - /// throw a [ValidationException]. + /// throw a [FormatException]. factory SingleContextEntry.fromString(String string) { final parsedUri = Uri.tryParse(string); if (parsedUri == null) { - throw ValidationException("Encountered invalid URI $string"); + throw FormatException("Encountered invalid URI $string"); } return SingleContextEntry(parsedUri); diff --git a/lib/src/core/definitions/extensions/json_parser.dart b/lib/src/core/definitions/extensions/json_parser.dart index fe787631..d573bd47 100644 --- a/lib/src/core/definitions/extensions/json_parser.dart +++ b/lib/src/core/definitions/extensions/json_parser.dart @@ -6,7 +6,6 @@ import "package:curie/curie.dart"; -import "../../exceptions.dart"; import "../additional_expected_response.dart"; import "../context.dart"; import "../data_schema.dart"; @@ -96,7 +95,7 @@ extension ParseField on Map { } /// Parses a single field with a given [name] and throws a - /// [ValidationException] if the field is not present or does not have the + /// [FormatException] if the field is not present or does not have the /// type [T]. /// /// Like [parseField], it adds the field [name] to the set of [parsedFields], @@ -105,7 +104,7 @@ extension ParseField on Map { final fieldValue = parseField(name, parsedFields); if (fieldValue is! T) { - throw ValidationException( + throw FormatException( "Value for field $name has wrong data type or is missing. " "Expected ${T.runtimeType}, got ${fieldValue.runtimeType}.", ); @@ -115,7 +114,7 @@ extension ParseField on Map { } /// Parses a single field with a given [name] as a [Uri] and throws a - /// [ValidationException] if the field is not present or cannot be parsed. + /// [FormatException] if the field is not present or cannot be parsed. /// /// If a [Set] of [parsedFields] is passed to this function, the field [name] /// will added. This can be used for filtering when parsing additional fields. @@ -284,7 +283,7 @@ extension ParseField on Map { return forms; } - throw const ValidationException( + throw const FormatException( 'Missing "forms" member in InteractionAffordance', ); } @@ -610,7 +609,7 @@ Iterable _parseContextEntries(dynamic json) sync* { final value = entry.value; if (value is! String) { - throw ValidationException( + throw FormatException( "Expected $value to be a String or a Map " "as @context entry, got ${value.runtimeType} instead."); } @@ -625,7 +624,7 @@ Iterable _parseContextEntries(dynamic json) sync* { }); } default: - throw ValidationException( + throw FormatException( "Expected the @context entry $json to " "either be a String or a Map, " "got ${json.runtimeType} instead.", diff --git a/lib/src/core/definitions/operation_type.dart b/lib/src/core/definitions/operation_type.dart index 90d0b325..f23c0fc6 100644 --- a/lib/src/core/definitions/operation_type.dart +++ b/lib/src/core/definitions/operation_type.dart @@ -4,7 +4,6 @@ // // SPDX-License-Identifier: BSD-3-Clause -import "../exceptions.dart"; import "interaction_affordances/interaction_affordance.dart"; /// Enumeration for the possible WoT operation types. @@ -55,7 +54,7 @@ enum OperationType { final operationType = OperationType._registry[stringValue]; if (operationType == null) { - throw ValidationException( + throw FormatException( "Encountered unknown OperationType $stringValue.", ); } diff --git a/lib/src/core/definitions/thing_description.dart b/lib/src/core/definitions/thing_description.dart index 0ca2aa9f..f17e1a09 100644 --- a/lib/src/core/definitions/thing_description.dart +++ b/lib/src/core/definitions/thing_description.dart @@ -7,7 +7,6 @@ import "package:curie/curie.dart"; import "package:meta/meta.dart"; -import "../exceptions.dart"; import "additional_expected_response.dart"; import "context.dart"; import "data_schema.dart"; @@ -60,7 +59,7 @@ class ThingDescription { if (validate) { final validationResult = thingDescriptionSchema.validate(json); if (!validationResult.isValid) { - throw ValidationException( + throw FormatException( "Validation of Thing Description failed.", validationResult.errors, ); diff --git a/lib/src/core/exceptions.dart b/lib/src/core/exceptions.dart index e3d79785..25d472d5 100644 --- a/lib/src/core/exceptions.dart +++ b/lib/src/core/exceptions.dart @@ -24,34 +24,6 @@ base class DartWotException implements Exception { String toString() => "$exceptionType: $message"; } -/// An [Exception] that is thrown when the validation of a definition fails. -base class ValidationException extends DartWotException { - /// Constructor. - const ValidationException(super.message, [this._validationErrors]); - - final List? _validationErrors; - - @override - String get exceptionType => "ValidationException"; - - @override - String toString() { - final String formattedValidationErrors; - - final validationErrors = _validationErrors; - if (validationErrors != null) { - formattedValidationErrors = [ - "\n\nErrors:\n", - ...validationErrors, - ].join("\n"); - } else { - formattedValidationErrors = ""; - } - - return "$exceptionType: $message$formattedValidationErrors"; - } -} - /// Custom [Exception] that is thrown when the discovery process fails. final class DiscoveryException extends DartWotException { /// Creates a new [DiscoveryException] with the specified error [message]. diff --git a/lib/src/core/implementation/augmented_form.dart b/lib/src/core/implementation/augmented_form.dart index 78bc4ab0..67e4c223 100644 --- a/lib/src/core/implementation/augmented_form.dart +++ b/lib/src/core/implementation/augmented_form.dart @@ -10,7 +10,6 @@ import "package:meta/meta.dart"; import "package:uri/uri.dart"; import "../definitions.dart"; -import "../exceptions.dart"; /// A [Form] augmented with information from its associated [_thingDescription] /// and [_interactionAffordance]. @@ -140,7 +139,7 @@ final class AugmentedForm implements Form { .where((element) => !affordanceUriVariables.containsKey(element)); if (uncoveredHrefUriVariables.isNotEmpty) { - throw ValidationException( + throw FormatException( "The following URI template variables defined in the form's href " "but are not covered by a uriVariable entry at the TD or affordance " "level: ${uncoveredHrefUriVariables.join(", ")}."); @@ -162,7 +161,7 @@ final class AugmentedForm implements Form { final result = schema.validate(userProvidedValue); if (!result.isValid) { - throw ValidationException("Invalid type for URI variable $key"); + throw FormatException("Invalid type for URI variable $key"); } } } diff --git a/lib/src/core/implementation/content_serdes.dart b/lib/src/core/implementation/content_serdes.dart index f3475c16..e534344f 100644 --- a/lib/src/core/implementation/content_serdes.dart +++ b/lib/src/core/implementation/content_serdes.dart @@ -10,7 +10,6 @@ import "package:http_parser/http_parser.dart"; import "package:json_schema/json_schema.dart"; import "../definitions/data_schema.dart"; -import "../exceptions.dart"; import "../scripting_api/data_schema_value.dart"; import "codecs/cbor_codec.dart"; import "codecs/codec_media_type.dart"; @@ -145,7 +144,7 @@ class ContentSerdes { } if (dataSchemaValue == null) { - throw const ValidationException("Expected a defined dataSchemaValue"); + throw const FormatException("Expected a defined dataSchemaValue"); } final schema = JsonSchema.create( @@ -153,7 +152,7 @@ class ContentSerdes { schemaVersion: SchemaVersion.draft7, ); if (!schema.validate(dataSchemaValue.value).isValid) { - throw const ValidationException("JSON Schema validation failed."); + throw const FormatException("JSON Schema validation failed."); } } diff --git a/lib/src/core/implementation/thing_discovery.dart b/lib/src/core/implementation/thing_discovery.dart index 5c916daf..28e40776 100644 --- a/lib/src/core/implementation/thing_discovery.dart +++ b/lib/src/core/implementation/thing_discovery.dart @@ -409,7 +409,7 @@ class ThingDiscovery extends Stream return dataSchemaValue.value.toThingDescription(); } - throw ValidationException( + throw FormatException( "Encountered wrong datatype ${dataSchemaValue.runtimeType} that cannot " "be processed as a Thing Description.", ); diff --git a/test/binding_coap/coap_definitions_test.dart b/test/binding_coap/coap_definitions_test.dart index d627a019..f525bb12 100644 --- a/test/binding_coap/coap_definitions_test.dart +++ b/test/binding_coap/coap_definitions_test.dart @@ -80,11 +80,11 @@ void main() { ); expect( () => invalidForm.block1Size, - throwsA(isA()), + throwsA(isA()), ); expect( () => invalidForm.block2Size, - throwsA(isA()), + throwsA(isA()), ); }); }); diff --git a/test/binding_mqtt/mqtt_extension_test.dart b/test/binding_mqtt/mqtt_extension_test.dart index 99fa4a2f..1afb4e3c 100644 --- a/test/binding_mqtt/mqtt_extension_test.dart +++ b/test/binding_mqtt/mqtt_extension_test.dart @@ -52,7 +52,7 @@ void main() { expect( () => augmentedForm.qualityOfService, - throwsA(isA()), + throwsA(isA()), ); }); }); diff --git a/test/core/augmented_form_test.dart b/test/core/augmented_form_test.dart index 9e38e9f2..caaae7bb 100644 --- a/test/core/augmented_form_test.dart +++ b/test/core/augmented_form_test.dart @@ -194,7 +194,7 @@ void main() { expect( () => augmentedForm4.resolvedHref, - throwsA(isA()), + throwsA(isA()), ); final augmentedForm5 = AugmentedForm( @@ -209,7 +209,7 @@ void main() { expect( () => augmentedForm5.resolvedHref, - throwsA(isA()), + throwsA(isA()), ); final augmentedForm6 = AugmentedForm( diff --git a/test/core/consumed_thing_test.dart b/test/core/consumed_thing_test.dart index 5e00de3d..29830b3c 100644 --- a/test/core/consumed_thing_test.dart +++ b/test/core/consumed_thing_test.dart @@ -258,7 +258,7 @@ void main() { "status2", uriVariables: uriVariables, ), - throwsA(const TypeMatcher()), + throwsA(const TypeMatcher()), ); await servient.shutdown(); diff --git a/test/core/content_serdes_test.dart b/test/core/content_serdes_test.dart index 997f6e3e..a4de1102 100644 --- a/test/core/content_serdes_test.dart +++ b/test/core/content_serdes_test.dart @@ -6,7 +6,6 @@ import "package:curie/curie.dart"; import "package:dart_wot/src/core/definitions/data_schema.dart"; -import "package:dart_wot/src/core/exceptions.dart"; import "package:dart_wot/src/core/implementation/codecs/json_codec.dart"; import "package:dart_wot/src/core/implementation/content.dart"; import "package:dart_wot/src/core/implementation/content_serdes.dart"; @@ -41,7 +40,7 @@ void main() { expect( contentSerdes.contentToValue(testContent2, failingSchema), - throwsA(const TypeMatcher()), + throwsA(const TypeMatcher()), ); expect( @@ -49,7 +48,7 @@ void main() { DataSchemaValue.tryParse(42), failingSchema, ), - throwsA(const TypeMatcher()), + throwsA(const TypeMatcher()), ); final testContent3 = _getTestContent(""); @@ -150,7 +149,7 @@ void main() { // FIXME(JKRhb): Should not be necessary to use fromJson here DataSchema.fromJson(const {"type": "object"}, PrefixMapping()), ), - throwsA(isA()), + throwsA(isA()), ); }); diff --git a/test/core/context_test.dart b/test/core/context_test.dart index f6f1bfab..ecf8f4aa 100644 --- a/test/core/context_test.dart +++ b/test/core/context_test.dart @@ -4,7 +4,6 @@ // // SPDX-License-Identifier: BSD-3-Clause -import "package:dart_wot/core.dart"; import "package:dart_wot/src/core/definitions/context.dart"; import "package:dart_wot/src/core/definitions/extensions/json_parser.dart"; import "package:test/test.dart"; @@ -17,7 +16,7 @@ void main() { expect( () => Context([illegalSingleContextEntry]), - throwsA(isA()), + throwsA(isA()), ); }); @@ -90,7 +89,7 @@ void main() { test("only be valid when created from a valid URI", () { expect( () => SingleContextEntry.fromString("::foobar::"), - throwsA(isA()), + throwsA(isA()), ); }); diff --git a/test/core/definitions_test.dart b/test/core/definitions_test.dart index fa125791..7b0081f7 100644 --- a/test/core/definitions_test.dart +++ b/test/core/definitions_test.dart @@ -23,7 +23,7 @@ void main() { expect( () => ThingDescription.fromJson(illegalThingDescription), - throwsA(isA()), + throwsA(isA()), ); }); @@ -220,7 +220,7 @@ void main() { PrefixMapping(), {}, ), - throwsA(isA()), + throwsA(isA()), ); }); @@ -481,7 +481,7 @@ void main() { expect( () => OperationType.fromString("test"), - throwsA(isA()), + throwsA(isA()), ); }); @@ -520,7 +520,7 @@ void main() { invalidThingDescription1, validate: false, ), - throwsA(isA()), + throwsA(isA()), ); final invalidThingDescription2 = { @@ -534,7 +534,7 @@ void main() { expect( () => ThingDescription.fromJson(invalidThingDescription2), - throwsA(isA()), + throwsA(isA()), ); }); @@ -556,7 +556,7 @@ void main() { expect( () => ThingDescription.fromJson(invalidThingDescription1), - throwsA(isA()), + throwsA(isA()), ); }); } diff --git a/test/core/exceptions_test.dart b/test/core/exceptions_test.dart index 81098ec0..9b45a76b 100644 --- a/test/core/exceptions_test.dart +++ b/test/core/exceptions_test.dart @@ -15,16 +15,6 @@ void main() { "DartWotException: test", ); - expect( - const ValidationException("test").toString(), - "ValidationException: test", - ); - - expect( - const ValidationException("test", ["test", "test"]).toString(), - "ValidationException: test\n\nErrors:\n\ntest\ntest", - ); - expect( const DiscoveryException("test").toString(), "DiscoveryException: test", diff --git a/test/core/thing_description_test.dart b/test/core/thing_description_test.dart index aa5d7ca0..8f093c6a 100644 --- a/test/core/thing_description_test.dart +++ b/test/core/thing_description_test.dart @@ -39,7 +39,7 @@ void main() { expect(thingDescriptionJson, thingDescription.toJson()); }); - test("throw a ValidationException when it is invalid during parsing", () { + test("throw a FormatException when it is invalid during parsing", () { const thingDescriptionJson = { "@context": [ "https://www.w3.org/2022/wot/td/v1.1", @@ -52,7 +52,7 @@ void main() { expect( () => ThingDescription.fromJson(thingDescriptionJson), - throwsA(isA()), + throwsA(isA()), ); });