Skip to content

Commit

Permalink
Merge pull request #106 from eclipse-thingweb/output-value
Browse files Browse the repository at this point in the history
feat!: improve InteractionOutput implementation
  • Loading branch information
JKRhb authored Jan 27, 2024
2 parents 457a113 + a4af92b commit 89fe292
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 10 deletions.
2 changes: 2 additions & 0 deletions lib/src/core/exceptions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
//
// SPDX-License-Identifier: BSD-3-Clause

export "exceptions/web_idl.dart";

/// Base class for custom exceptions defined in `dart_wot`.
base class DartWotException implements Exception {
/// Constructor.
Expand Down
20 changes: 20 additions & 0 deletions lib/src/core/exceptions/web_idl.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2024 Contributors to the Eclipse Foundation. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// SPDX-License-Identifier: BSD-3-Clause

import "../exceptions.dart";

/// Indicates that an I/O read operation failed.
///
/// Corresponds with the Web IDL exception type [NotReadableError].
///
/// [NotReadableError]: https://webidl.spec.whatwg.org/#notreadableerror
final class NotReadableException extends DartWotException {
/// Instantiates a new [NotReadableException] with the given [message].
NotReadableException(super.message);

@override
String get exceptionType => "NotReadableException";
}
31 changes: 23 additions & 8 deletions lib/src/core/implementation/interaction_output.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "dart:typed_data";

import "../definitions/data_schema.dart";
import "../definitions/form.dart";
import "../exceptions.dart";
import "../scripting_api.dart" as scripting_api;
import "content.dart";
import "content_serdes.dart";
Expand All @@ -16,17 +17,24 @@ import "content_serdes.dart";
class InteractionOutput implements scripting_api.InteractionOutput {
/// Creates a new [InteractionOutput] based on a [Content] object.
///
/// A [ContentSerdes] object has to be passed for decoding the raw
/// payload contained in the [Content] object.
/// A [_contentSerdes] object has to be passed for decoding the raw
/// payload contained in the [_content] object.
///
/// In contrast to the interface definition in the
/// [Scripting API specification], [_form] is defined as non-nullable here,
/// since other parts of the code never pass a `null` value as an argument for
/// this parameter.
///
/// [Scripting API specification]: https://w3c.github.io/wot-scripting-api/#the-interactionoutput-interface
InteractionOutput(
this._content,
this._contentSerdes, [
this._contentSerdes,
this._form,
this._schema,
]) : _data = _content.body;
) : _data = _content.body;

final Content _content;
final Form? _form;
final Form _form;
final DataSchema? _schema;
final Stream<List<int>> _data;

Expand All @@ -38,6 +46,10 @@ class InteractionOutput implements scripting_api.InteractionOutput {

@override
Future<ByteBuffer> arrayBuffer() async {
if (dataUsed) {
throw NotReadableException("Data has already been read");
}

_dataUsed = true;
return _content.byteBuffer;
}
Expand All @@ -52,8 +64,11 @@ class InteractionOutput implements scripting_api.InteractionOutput {
return existingValue.value;
}

// TODO(JKRhb): Should a NotReadableError be thrown if schema is null?
// C.f. https://w3c.github.io/wot-scripting-api/#the-value-function
if (schema == null) {
throw NotReadableException(
"Can't convert data to a value because no DataSchema is present.",
);
}

final value = await _contentSerdes.contentToValue(
_content,
Expand All @@ -72,5 +87,5 @@ class InteractionOutput implements scripting_api.InteractionOutput {
DataSchema? get schema => _schema;

@override
Form? get form => _form;
Form get form => _form;
}
11 changes: 11 additions & 0 deletions lib/src/core/scripting_api/interaction_output.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,19 @@ abstract interface class InteractionOutput {

/// Asyncronously creates a [ByteBuffer] representation of the value of
/// of the [InteractionOutput].
///
/// Follows the algorithm defined for the `arrayBuffer()` function in the
/// Scripting API specification.
///
/// [algorithm]: https://w3c.github.io/wot-scripting-api/#the-arraybuffer-function
Future<ByteBuffer> arrayBuffer();

/// The parsed value of the [InteractionOutput].
///
///
/// Follows the algorithm defined for the `arrayBuffer()` function in the
/// Scripting API specification.
///
/// [algorithm]: https://w3c.github.io/wot-scripting-api/#the-value-function
Future<Object?> value();
}
5 changes: 5 additions & 0 deletions test/core/exceptions_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ void main() {
DiscoveryException("test").toString(),
"DiscoveryException: test",
);

expect(
NotReadableException("test").toString(),
"NotReadableException: test",
);
});
});
}
85 changes: 83 additions & 2 deletions test/core/interaction_output_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ void main() {
]),
);

final interactionOutput = InteractionOutput(content, contentSerdes);
final interactionOutput = InteractionOutput(
content,
contentSerdes,
Form(Uri.parse("http://example.org")),
const DataSchema(),
);

final value1 = await interactionOutput.value();
expect(value1, inputValue);
Expand All @@ -46,13 +51,89 @@ void main() {
]),
);

final interactionOutput = InteractionOutput(content, contentSerdes);
final interactionOutput = InteractionOutput(
content,
contentSerdes,
Form(Uri.parse("http://example.org")),
const DataSchema(),
);

final value1 = await interactionOutput.value();
expect(value1, inputValue);

final value2 = await interactionOutput.value();
expect(value1, value2);
});

test(
"throw a NotReadableException when calling the arrayBuffer() method "
"twice", () async {
final contentSerdes = ContentSerdes();
final content = Content(
"text/plain",
const Stream.empty(),
);

final interactionOutput = InteractionOutput(
content,
contentSerdes,
Form(Uri.parse("http://example.org")),
const DataSchema(),
);

await interactionOutput.arrayBuffer();

final result = interactionOutput.arrayBuffer();
await expectLater(
result,
throwsA(
isA<NotReadableException>(),
),
);
});
});

test(
"throw a NotReadableException in the value() method when no schema is "
"defined", () async {
final contentSerdes = ContentSerdes();
final content = Content(
"text/plain",
const Stream.empty(),
);

final interactionOutput = InteractionOutput(
content,
contentSerdes,
Form(Uri.parse("http://example.org")),
null,
);

final result = interactionOutput.value();
await expectLater(
result,
throwsA(
isA<NotReadableException>(),
),
);
});

test("allow accessing the form field", () async {
final contentSerdes = ContentSerdes();
final content = Content(
"text/plain",
const Stream.empty(),
);

final uri = Uri.parse("http://example.org");

final interactionOutput = InteractionOutput(
content,
contentSerdes,
Form(uri),
const DataSchema(),
);

expect(interactionOutput.form.href, uri);
});
}

0 comments on commit 89fe292

Please sign in to comment.