Commit 919b7cee authored by Leon Han's avatar Leon Han Committed by Commit Bot

[webnfc] Use AbortController for NFCReader

This CL uses AbortController to replace the stop() method of NFCReader
interface.

The corresponding spec change is from:
https://github.com/w3c/web-nfc/pull/300

BUG=520391

Change-Id: Ia28bfb283a7ad66fb9c4cb0fc744582671a62fa0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1769245Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Reviewed-by: default avatarRijubrata Bhaumik <rijubrata.bhaumik@intel.com>
Commit-Queue: Leon Han <leon.han@intel.com>
Cr-Commit-Position: refs/heads/master@{#691988}
parent f52f5199
......@@ -31,7 +31,7 @@ import org.chromium.device.mojom.NfcError;
import org.chromium.device.mojom.NfcErrorType;
import org.chromium.device.mojom.NfcPushOptions;
import org.chromium.device.mojom.NfcPushTarget;
import org.chromium.device.mojom.NfcReaderOptions;
import org.chromium.device.mojom.NfcScanOptions;
import org.chromium.mojo.bindings.Callbacks;
import org.chromium.mojo.system.MojoException;
......@@ -103,12 +103,12 @@ public class NfcImpl implements Nfc {
private int mWatcherId;
/**
* Map of watchId <-> NfcReaderOptions. All NfcReaderOptions are matched against tag that is in
* Map of watchId <-> NfcScanOptions. All NfcScanOptions are matched against tag that is in
* proximity, when match algorithm (@see #matchesWatchOptions) returns true, watcher with
* corresponding ID would be notified using NfcClient interface.
* @see NfcClient#onWatch(int[] id, String serial_number, NdefMessage message)
*/
private final SparseArray<NfcReaderOptions> mWatchers = new SparseArray<>();
private final SparseArray<NfcScanOptions> mWatchers = new SparseArray<>();
/**
* Handler that runs delayed push timeout task.
......@@ -163,8 +163,8 @@ public class NfcImpl implements Nfc {
/**
* Sets NfcClient. NfcClient interface is used to notify mojo NFC service client when NFC
* device is in proximity and has NdefMessage that matches NfcReaderOptions criteria.
* @see Nfc#watch(NfcReaderOptions options, int id, WatchResponse callback)
* device is in proximity and has NdefMessage that matches NfcScanOptions criteria.
* @see Nfc#watch(NfcScanOptions options, int id, WatchResponse callback)
*
* @param client @see NfcClient
*/
......@@ -237,15 +237,15 @@ public class NfcImpl implements Nfc {
/**
* Watch method allows to set filtering criteria for NdefMessages that are found when NFC device
* is within proximity. When NdefMessage that matches NfcReaderOptions is found, it is passed to
* is within proximity. When NdefMessage that matches NfcScanOptions is found, it is passed to
* NfcClient interface together with corresponding watch ID.
* @see NfcClient#onWatch(int[] id, String serial_number, NdefMessage message)
*
* @param options used to filter NdefMessages, @see NfcReaderOptions.
* @param options used to filter NdefMessages, @see NfcScanOptions.
* @param callback that is used to notify caller when watch() is completed.
*/
@Override
public void watch(NfcReaderOptions options, int id, WatchResponse callback) {
public void watch(NfcScanOptions options, int id, WatchResponse callback) {
if (!checkIfReady(callback)) return;
// We received a duplicate |id| here that should never happen, in such a case we should
// report a bad message to Mojo but unfortunately Mojo bindings for Java does not support
......@@ -577,7 +577,7 @@ public class NfcImpl implements Nfc {
}
/**
* Iterates through active watchers and if any of those match NfcReaderOptions criteria,
* Iterates through active watchers and if any of those match NfcScanOptions criteria,
* delivers NdefMessage to the client.
*/
private void notifyMatchingWatchers(android.nfc.NdefMessage message, int compatibility) {
......@@ -585,7 +585,7 @@ public class NfcImpl implements Nfc {
NdefMessage ndefMessage = NdefMessageUtils.toNdefMessage(message);
List<Integer> watchIds = new ArrayList<Integer>();
for (int i = 0; i < mWatchers.size(); i++) {
NfcReaderOptions options = mWatchers.valueAt(i);
NfcScanOptions options = mWatchers.valueAt(i);
if (matchesWatchOptions(ndefMessage, compatibility, options))
watchIds.add(mWatchers.keyAt(i));
}
......@@ -606,7 +606,7 @@ public class NfcImpl implements Nfc {
* Implements matching algorithm.
*/
private boolean matchesWatchOptions(
NdefMessage message, int compatibility, NfcReaderOptions options) {
NdefMessage message, int compatibility, NfcScanOptions options) {
// 'nfc-forum' option can only read messages from NFC standard devices and 'vendor' option
// can only read from vendor specific ones.
if (options.compatibility != NdefCompatibility.ANY
......
......@@ -69,7 +69,7 @@ struct NDEFMessage {
// The |url| field is an ASCII serialized origin, optionally followed by a URL
// path. It represents Web NFC id, that can be used for matching Web NFC
// content with the filter specified by |url| field in NFCReaderOptions.
// content with the filter specified by |url| field in NFCScanOptions.
string? url;
// Maximum size of NFC message that can be sent over IPC is 32KB.
......@@ -95,7 +95,7 @@ struct NDEFRecordTypeFilter {
NDEFRecordType record_type;
};
struct NFCReaderOptions {
struct NFCScanOptions {
// Defines filtering constraint for NFC messages with specified |url|.
string? url;
......@@ -124,9 +124,9 @@ interface NFC {
CancelPush(NFCPushTarget target) => (NFCError? error);
// Starts watching for nearby NFC devices with data that matches
// NFCReaderOptions filtering criteria. |id| identifies each watch request on
// NFCScanOptions filtering criteria. |id| identifies each watch request on
// the current Mojo connection.
Watch(NFCReaderOptions options, uint32 id) => (NFCError? error);
Watch(NFCScanOptions options, uint32 id) => (NFCError? error);
// Cancels watch operation with provided id.
CancelWatch (uint32 id) => (NFCError? error);
......
......@@ -687,11 +687,11 @@ modules_dictionary_idl_files =
"native_file_system/get_system_directory_options.idl",
"native_file_system/native_file_system_directory_iterator_entry.idl",
"nfc/ndef_message_init.idl",
"nfc/nfc_push_options.idl",
"nfc/ndef_record_init.idl",
"nfc/nfc_reader_options.idl",
"nfc/nfc_error_event_init.idl",
"nfc/nfc_push_options.idl",
"nfc/nfc_reading_event_init.idl",
"nfc/nfc_scan_options.idl",
"notifications/get_notification_options.idl",
"notifications/notification_action.idl",
"notifications/notification_event_init.idl",
......
......@@ -54,15 +54,14 @@ void NFCProxy::Trace(blink::Visitor* visitor) {
Supplement<Document>::Trace(visitor);
}
void NFCProxy::StartReading(NFCReader* reader) {
void NFCProxy::StartReading(NFCReader* reader, const NFCScanOptions* options) {
DCHECK(reader);
if (readers_.Contains(reader))
return;
EnsureMojoConnection();
nfc_remote_->Watch(
device::mojom::blink::NFCReaderOptions::From(reader->options()),
next_watch_id_,
device::mojom::blink::NFCScanOptions::From(options), next_watch_id_,
WTF::Bind(&NFCProxy::OnReaderRegistered, WrapPersistent(this),
WrapPersistent(reader), next_watch_id_));
readers_.insert(reader, next_watch_id_);
......
......@@ -17,6 +17,7 @@
namespace blink {
class Document;
class NFCScanOptions;
class NFCReader;
class NFCWriter;
......@@ -47,7 +48,7 @@ class MODULES_EXPORT NFCProxy final
// collected.
void AddWriter(NFCWriter*);
void StartReading(NFCReader*);
void StartReading(NFCReader*, const NFCScanOptions*);
void StopReading(NFCReader*);
bool IsReading(const NFCReader*);
void Push(device::mojom::blink::NDEFMessagePtr,
......
......@@ -15,7 +15,7 @@
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/modules/nfc/nfc_proxy.h"
#include "third_party/blink/renderer/modules/nfc/nfc_reader.h"
#include "third_party/blink/renderer/modules/nfc/nfc_reader_options.h"
#include "third_party/blink/renderer/modules/nfc/nfc_scan_options.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink {
......@@ -46,9 +46,8 @@ MATCHER_P(MessageEquals, expected, "") {
class MockNFCReader : public NFCReader {
public:
explicit MockNFCReader(ExecutionContext* execution_context,
NFCReaderOptions* options)
: NFCReader(execution_context, options) {}
explicit MockNFCReader(ExecutionContext* execution_context)
: NFCReader(execution_context) {}
MOCK_METHOD2(OnReading,
void(const String& serial_number,
......@@ -119,7 +118,7 @@ class FakeNfcService : public device::mojom::blink::NFC {
CancelPushCallback callback) override {
std::move(callback).Run(nullptr);
}
void Watch(device::mojom::blink::NFCReaderOptionsPtr options,
void Watch(device::mojom::blink::NFCScanOptionsPtr options,
uint32_t id,
WatchCallback callback) override {
watches_.emplace(id, std::move(options));
......@@ -142,7 +141,7 @@ class FakeNfcService : public device::mojom::blink::NFC {
device::mojom::blink::NDEFMessagePtr tag_message_;
mojo::Remote<device::mojom::blink::NFCClient> client_;
std::map<uint32_t, device::mojom::blink::NFCReaderOptionsPtr> watches_;
std::map<uint32_t, device::mojom::blink::NFCScanOptionsPtr> watches_;
mojo::Receiver<device::mojom::blink::NFC> receiver_;
};
......@@ -173,11 +172,11 @@ class NFCProxyTest : public PageTestBase {
TEST_F(NFCProxyTest, SuccessfulPath) {
auto& document = GetDocument();
auto* nfc_proxy = NFCProxy::From(document);
auto* read_options = NFCReaderOptions::Create();
read_options->setURL(kTestUrl);
auto* reader = MakeGarbageCollected<MockNFCReader>(&document, read_options);
auto* scan_options = NFCScanOptions::Create();
scan_options->setURL(kTestUrl);
auto* reader = MakeGarbageCollected<MockNFCReader>(&document);
nfc_proxy->StartReading(reader);
nfc_proxy->StartReading(reader, scan_options);
EXPECT_TRUE(nfc_proxy->IsReading(reader));
test::RunPendingTasks();
EXPECT_EQ(nfc_service()->GetWatches().size(), 1u);
......@@ -216,11 +215,11 @@ TEST_F(NFCProxyTest, SuccessfulPath) {
TEST_F(NFCProxyTest, ErrorPath) {
auto& document = GetDocument();
auto* nfc_proxy = NFCProxy::From(document);
auto* read_options = NFCReaderOptions::Create();
read_options->setURL(kTestUrl);
auto* reader = MakeGarbageCollected<MockNFCReader>(&document, read_options);
auto* scan_options = NFCScanOptions::Create();
scan_options->setURL(kTestUrl);
auto* reader = MakeGarbageCollected<MockNFCReader>(&document);
nfc_proxy->StartReading(reader);
nfc_proxy->StartReading(reader, scan_options);
EXPECT_TRUE(nfc_proxy->IsReading(reader));
test::RunPendingTasks();
......
......@@ -7,26 +7,26 @@
#include <utility>
#include "services/device/public/mojom/nfc.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/abort_signal.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/nfc/ndef_message.h"
#include "third_party/blink/renderer/modules/nfc/nfc_constants.h"
#include "third_party/blink/renderer/modules/nfc/nfc_error_event.h"
#include "third_party/blink/renderer/modules/nfc/nfc_proxy.h"
#include "third_party/blink/renderer/modules/nfc/nfc_reader_options.h"
#include "third_party/blink/renderer/modules/nfc/nfc_reading_event.h"
#include "third_party/blink/renderer/modules/nfc/nfc_scan_options.h"
#include "third_party/blink/renderer/modules/nfc/nfc_utils.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
// static
NFCReader* NFCReader::Create(ExecutionContext* context,
NFCReaderOptions* options) {
return MakeGarbageCollected<NFCReader>(context, options);
NFCReader* NFCReader::Create(ExecutionContext* context) {
return MakeGarbageCollected<NFCReader>(context);
}
NFCReader::NFCReader(ExecutionContext* context, NFCReaderOptions* options)
: ContextLifecycleObserver(context), options_(options) {}
NFCReader::NFCReader(ExecutionContext* context)
: ContextLifecycleObserver(context) {}
NFCReader::~NFCReader() = default;
......@@ -43,32 +43,39 @@ bool NFCReader::HasPendingActivity() const {
HasEventListeners();
}
void NFCReader::start() {
// https://w3c.github.io/web-nfc/#the-scan-method
void NFCReader::scan(const NFCScanOptions* options) {
if (!CheckSecurity())
return;
// https://w3c.github.io/web-nfc/#dom-nfcreader-start (Step 3.4)
if (options_->hasURL() && !options_->url().IsEmpty()) {
KURL pattern_url(options_->url());
if (options->hasSignal()) {
// 6. If reader.[[Signal]]'s aborted flag is set, then return.
if (options->signal()->aborted())
return;
// 7. If reader.[[Signal]] is not null, then add the following abort steps
// to reader.[[Signal]]:
options->signal()->AddAlgorithm(
WTF::Bind(&NFCReader::Abort, WrapPersistent(this)));
}
// Step 8.4, if the url is not an empty string and it is not a valid URL
// pattern, fire a NFCErrorEvent with "SyntaxError" DOMException, then return.
if (options->hasURL() && !options->url().IsEmpty()) {
KURL pattern_url(options->url());
if (!pattern_url.IsValid() || pattern_url.Protocol() != kNfcProtocolHttps) {
DispatchEvent(*MakeGarbageCollected<NFCErrorEvent>(
event_type_names::kError,
MakeGarbageCollected<DOMException>(DOMExceptionCode::kSyntaxError,
kNfcUrlPatternError)));
return;
}
}
GetNfcProxy()->StartReading(this);
}
void NFCReader::stop() {
if (!CheckSecurity())
return;
GetNfcProxy()->StopReading(this);
GetNfcProxy()->StartReading(this, options);
}
void NFCReader::Trace(blink::Visitor* visitor) {
visitor->Trace(options_);
EventTargetWithInlineData::Trace(visitor);
ActiveScriptWrappable::Trace(visitor);
ContextLifecycleObserver::Trace(visitor);
......@@ -91,6 +98,10 @@ void NFCReader::ContextDestroyed(ExecutionContext*) {
GetNfcProxy()->StopReading(this);
}
void NFCReader::Abort() {
GetNfcProxy()->StopReading(this);
}
bool NFCReader::CheckSecurity() {
ExecutionContext* execution_context = GetExecutionContext();
if (!execution_context)
......
......@@ -16,7 +16,7 @@ namespace blink {
class ExecutionContext;
class NFCProxy;
class NFCReaderOptions;
class NFCScanOptions;
class MODULES_EXPORT NFCReader : public EventTargetWithInlineData,
public ActiveScriptWrappable<NFCReader>,
......@@ -25,9 +25,9 @@ class MODULES_EXPORT NFCReader : public EventTargetWithInlineData,
DEFINE_WRAPPERTYPEINFO();
public:
static NFCReader* Create(ExecutionContext*, NFCReaderOptions*);
static NFCReader* Create(ExecutionContext*);
NFCReader(ExecutionContext*, NFCReaderOptions*);
NFCReader(ExecutionContext*);
~NFCReader() override;
// EventTarget overrides.
......@@ -39,13 +39,10 @@ class MODULES_EXPORT NFCReader : public EventTargetWithInlineData,
DEFINE_ATTRIBUTE_EVENT_LISTENER(error, kError)
DEFINE_ATTRIBUTE_EVENT_LISTENER(reading, kReading)
void start();
void stop();
void scan(const NFCScanOptions*);
void Trace(blink::Visitor*) override;
const NFCReaderOptions* options() const { return options_; }
// Called by NFCProxy for dispatching events.
virtual void OnReading(const String& serial_number,
const device::mojom::blink::NDEFMessage& message);
......@@ -55,11 +52,11 @@ class MODULES_EXPORT NFCReader : public EventTargetWithInlineData,
// ContextLifecycleObserver overrides.
void ContextDestroyed(ExecutionContext*) override;
void Abort();
NFCProxy* GetNfcProxy() const;
bool CheckSecurity();
const Member<NFCReaderOptions> options_;
};
} // namespace blink
......
......@@ -8,13 +8,12 @@
RuntimeEnabled=WebNFC,
ActiveScriptWrappable,
SecureContext,
Constructor(optional NFCReaderOptions options),
Constructor(),
ConstructorCallWith=ExecutionContext,
Exposed=Window
] interface NFCReader : EventTarget {
attribute EventHandler onreading;
attribute EventHandler onerror;
void start();
void stop();
void scan(optional NFCScanOptions options);
};
......@@ -6,8 +6,9 @@
// http://w3c.github.io/web-nfc/#dom-ndefcompatibility
enum NDEFCompatibility { "nfc-forum", "vendor", "any" };
// https://w3c.github.io/web-nfc/#dom-nfcreaderoptions
dictionary NFCReaderOptions {
// https://w3c.github.io/web-nfc/#the-nfcscanoptions-dictionary
dictionary NFCScanOptions {
AbortSignal? signal;
USVString url = "";
NDEFRecordType? recordType;
USVString mediaType = "";
......
......@@ -12,7 +12,7 @@
#include "third_party/blink/renderer/modules/nfc/ndef_message.h"
#include "third_party/blink/renderer/modules/nfc/ndef_record.h"
#include "third_party/blink/renderer/modules/nfc/nfc_push_options.h"
#include "third_party/blink/renderer/modules/nfc/nfc_reader_options.h"
#include "third_party/blink/renderer/modules/nfc/nfc_scan_options.h"
#include "third_party/blink/renderer/modules/nfc/nfc_utils.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
......@@ -27,8 +27,8 @@ using device::mojom::blink::NDEFRecordTypeFilter;
using device::mojom::blink::NFCPushOptions;
using device::mojom::blink::NFCPushOptionsPtr;
using device::mojom::blink::NFCPushTarget;
using device::mojom::blink::NFCReaderOptions;
using device::mojom::blink::NFCReaderOptionsPtr;
using device::mojom::blink::NFCScanOptions;
using device::mojom::blink::NFCScanOptionsPtr;
using WTF::String;
......@@ -236,25 +236,25 @@ TypeConverter<NFCPushOptionsPtr, const blink::NFCPushOptions*>::Convert(
return pushOptionsPtr;
}
NFCReaderOptionsPtr
TypeConverter<NFCReaderOptionsPtr, const blink::NFCReaderOptions*>::Convert(
const blink::NFCReaderOptions* watchOptions) {
// https://w3c.github.io/web-nfc/#dom-nfcreaderoptions
// Default values for NFCReaderOptions dictionary are:
NFCScanOptionsPtr
TypeConverter<NFCScanOptionsPtr, const blink::NFCScanOptions*>::Convert(
const blink::NFCScanOptions* scanOptions) {
// https://w3c.github.io/web-nfc/#dom-nfcscanoptions
// Default values for NFCScanOptions dictionary are:
// url = "", recordType = null, mediaType = "", compatibility = "nfc-forum"
NFCReaderOptionsPtr watchOptionsPtr = NFCReaderOptions::New();
watchOptionsPtr->url = watchOptions->url();
watchOptionsPtr->media_type = watchOptions->mediaType();
watchOptionsPtr->compatibility =
blink::StringToNDEFCompatibility(watchOptions->compatibility());
if (watchOptions->hasRecordType()) {
watchOptionsPtr->record_filter = NDEFRecordTypeFilter::New();
watchOptionsPtr->record_filter->record_type =
blink::StringToNDEFRecordType(watchOptions->recordType());
NFCScanOptionsPtr scanOptionsPtr = NFCScanOptions::New();
scanOptionsPtr->url = scanOptions->url();
scanOptionsPtr->media_type = scanOptions->mediaType();
scanOptionsPtr->compatibility =
blink::StringToNDEFCompatibility(scanOptions->compatibility());
if (scanOptions->hasRecordType()) {
scanOptionsPtr->record_filter = NDEFRecordTypeFilter::New();
scanOptionsPtr->record_filter->record_type =
blink::StringToNDEFRecordType(scanOptions->recordType());
}
return watchOptionsPtr;
return scanOptionsPtr;
}
} // namespace mojo
......@@ -14,7 +14,7 @@ namespace blink {
class DOMArrayBuffer;
class NDEFRecordInit;
class NDEFMessageInit;
class NFCReaderOptions;
class NFCScanOptions;
class NFCPushOptions;
} // namespace blink
......@@ -100,10 +100,10 @@ struct TypeConverter<device::mojom::blink::NFCPushOptionsPtr,
};
template <>
struct TypeConverter<device::mojom::blink::NFCReaderOptionsPtr,
const blink::NFCReaderOptions*> {
static device::mojom::blink::NFCReaderOptionsPtr Convert(
const blink::NFCReaderOptions* watchOptions);
struct TypeConverter<device::mojom::blink::NFCScanOptionsPtr,
const blink::NFCScanOptions*> {
static device::mojom::blink::NFCScanOptionsPtr Convert(
const blink::NFCScanOptions* scanOptions);
};
} // namespace mojo
......
......@@ -10,122 +10,125 @@
"use strict";
function waitSyntaxErrorPromise(t, reader) {
function waitSyntaxErrorPromise(t, scan_options) {
const reader = new NFCReader();
const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
const promise = readerWatcher.wait_for("error").then(event => {
assert_equals(event.error.name, 'SyntaxError');
});
// NFCReader#start() asynchronously dispatches the syntax error event.
reader.start();
// NFCReader#scan() asynchronously dispatches the syntax error event.
reader.scan(scan_options);
return promise;
}
promise_test(async t => {
const reader = new NFCReader({url: "www.a.com"});
await waitSyntaxErrorPromise(t, reader);
}, "Test that NFCReader.start fails if NFCReaderOptions.url is missing \
await waitSyntaxErrorPromise(t, {url: "www.a.com"});
}, "Test that NFCReader.scan fails if NFCScanOptions.url is missing \
components.");
promise_test(async t => {
const reader = new NFCReader({url: "invalid"});
await waitSyntaxErrorPromise(t, reader);
}, "Test that NFCReader.start fails if NFCReaderOptions.url is invalid.");
await waitSyntaxErrorPromise(t, {url: "invalid"});
}, "Test that NFCReader.scan fails if NFCScanOptions.url is invalid.");
promise_test(async t => {
const reader = new NFCReader({url: "http://a.com"});
await waitSyntaxErrorPromise(t, reader);
}, "Test that NFCReader.start fails if NFCReaderOptions.url has wrong \
await waitSyntaxErrorPromise(t, {url: "http://a.com"});
}, "Test that NFCReader.scan fails if NFCScanOptions.url has wrong \
protocol.");
nfc_test(async (t, mockNFC) => {
const reader = new NFCReader();
const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
reader.start();
reader.scan();
mockNFC.setHWStatus(NFCHWStatus.DISABLED);
const event = await readerWatcher.wait_for("error");
assert_equals(event.error.name, 'NotReadableError');
}, "NFCReader.start should fail if NFC HW is disabled.");
}, "NFCReader.scan should fail if NFC HW is disabled.");
nfc_test(async (t, mockNFC) => {
const reader = new NFCReader();
const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
reader.start();
reader.scan();
mockNFC.setHWStatus(NFCHWStatus.NOT_SUPPORTED);
const event = await readerWatcher.wait_for("error");
assert_equals(event.error.name, 'NotSupportedError');
}, "NFCReader.start should fail if NFC HW is not supported.");
}, "NFCReader.scan should fail if NFC HW is not supported.");
nfc_test(async (t, mockNFC) => {
const reader = new NFCReader();
const controller = new AbortController();
const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
mockNFC.setReadingMessage(createMessage([createTextRecord(test_text_data)]));
const promise = readerWatcher.wait_for("reading").then(event => {
assert_true(event instanceof NFCReadingEvent);
reader.stop();
controller.abort();
});
// NFCReader#start() asynchronously dispatches the reading event.
reader.start();
// NFCReader#scan() asynchronously dispatches the reading event.
reader.scan({signal : controller.signal});
await promise;
}, "Test that nfc watch success if NFC HW is enabled.");
nfc_test(async (t, mockNFC) => {
const reader = new NFCReader({url: "https://a.com"});
const reader = new NFCReader();
const controller = new AbortController();
const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
mockNFC.setReadingMessage(createMessage([createTextRecord(test_text_data)]));
const promise = readerWatcher.wait_for("reading").then(event => {
assert_true(event instanceof NFCReadingEvent);
reader.stop();
controller.abort();
});
// NFCReader#start() asynchronously dispatches the reading event.
reader.start();
// NFCReader#scan() asynchronously dispatches the reading event.
reader.scan({signal : controller.signal, url: "https://a.com"});
await promise;
}, "Test that NFCReader.start succeeds if NFCReaderOptions.url is valid URL.");
}, "Test that NFCReader.scan succeeds if NFCScanOptions.url is valid URL.");
nfc_test(async (t, mockNFC) => {
const reader = new NFCReader({url: "https://a.com/*"});
const reader = new NFCReader();
const controller = new AbortController();
const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
mockNFC.setReadingMessage(createMessage([createTextRecord(test_text_data)]));
const promise = readerWatcher.wait_for("reading").then(event => {
assert_true(event instanceof NFCReadingEvent);
reader.stop();
controller.abort();
});
// NFCReader#start() asynchronously dispatches the reading event.
reader.start();
// NFCReader#scan() asynchronously dispatches the reading event.
reader.scan({signal : controller.signal, url: "https://a.com/*"});
await promise;
}, "Test that NFCReader.start succeeds if NFCReaderOptions.url is valid URL \
}, "Test that NFCReader.scan succeeds if NFCScanOptions.url is valid URL \
with '*' wildcard character in path.");
nfc_test(async (t, mockNFC) => {
const reader = new NFCReader({url: "https://a.com/*/bar"});
const reader = new NFCReader();
const controller = new AbortController();
const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
mockNFC.setReadingMessage(createMessage([createTextRecord(test_text_data)]));
const promise = readerWatcher.wait_for("reading").then(event => {
assert_true(event instanceof NFCReadingEvent);
reader.stop();
controller.abort();
});
// NFCReader#start() asynchronously dispatches the reading event.
reader.start();
// NFCReader#scan() asynchronously dispatches the reading event.
reader.scan({signal : controller.signal, url: "https://a.com/*/bar"});
await promise;
}, "Test that NFCReader.start succeeds if NFCReaderOptions.url is valid URL \
}, "Test that NFCReader.scan succeeds if NFCScanOptions.url is valid URL \
with '*' wildcard character in the beginning of path component followed by \
subpath.");
nfc_test(async (t, mockNFC) => {
const reader = new NFCReader({url: ""});
const controller = new AbortController();
const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
mockNFC.setReadingMessage(createMessage([createTextRecord(test_text_data)]));
const promise = readerWatcher.wait_for("reading").then(event => {
assert_true(event instanceof NFCReadingEvent);
reader.stop();
controller.abort();
});
// NFCReader#start() asynchronously dispatches the reading event.
reader.start();
// NFCReader#scan() asynchronously dispatches the reading event.
reader.scan({signal : controller.signal, url: ""});
await promise;
}, "Test that NFCReader.start succeeds if NFCReaderOptions.url is empty.");
}, "Test that NFCReader.scan succeeds if NFCScanOptions.url is empty.");
</script>
......@@ -13,60 +13,60 @@
const NFCReaderOptionTests =
[
{
desc: "Test that reading data succeed when NFCReaderOptions'" +
desc: "Test that reading data succeed when NFCScanOptions'" +
" recordType is set to 'empty'.",
readOptions: {recordType: "empty"},
unmatchedReadOptions: {recordType: "json"},
scanOptions: {recordType: "empty"},
unmatchedScanOptions: {recordType: "json"},
message: createMessage([createRecord('empty', '')])
},
{
desc: "Test that reading data succeed when NFCReaderOptions'" +
desc: "Test that reading data succeed when NFCScanOptions'" +
" recordType is set to 'json'.",
readOptions: {recordType: "json"},
unmatchedReadOptions: {recordType: "url"},
scanOptions: {recordType: "json"},
unmatchedScanOptions: {recordType: "url"},
message: createMessage([createJsonRecord(test_json_data)])
},
{
desc: "Test that reading data succeed when NFCReaderOptions'" +
desc: "Test that reading data succeed when NFCScanOptions'" +
" recordType is set to 'opaque'.",
readOptions: {recordType: "opaque"},
unmatchedReadOptions: {recordType: "json"},
scanOptions: {recordType: "opaque"},
unmatchedScanOptions: {recordType: "json"},
message: createMessage([createOpaqueRecord(test_buffer_data)])
},
{
desc: "Test that reading data succeed when NFCReaderOptions'" +
desc: "Test that reading data succeed when NFCScanOptions'" +
" recordType is set to 'text'.",
readOptions: {recordType: "text"},
unmatchedReadOptions: {recordType: "json"},
scanOptions: {recordType: "text"},
unmatchedScanOptions: {recordType: "json"},
message: createMessage([createTextRecord(test_text_data)])
},
{
desc: "Test that reading data succeed when NFCReaderOptions'" +
desc: "Test that reading data succeed when NFCScanOptions'" +
" recordType is set to 'url'.",
readOptions: {recordType: "url"},
unmatchedReadOptions: {recordType: "json"},
scanOptions: {recordType: "url"},
unmatchedScanOptions: {recordType: "json"},
message: createMessage([createUrlRecord(test_url_data)])
},
{
desc: "Test that the url of NFCReaderOptions filters relevant data" +
desc: "Test that the url of NFCScanOptions filters relevant data" +
" sources correctly.",
readOptions: {url: `${location.origin}/custom/path`},
unmatchedReadOptions: {url: `${location.origin}/custom/invalid`},
scanOptions: {url: `${location.origin}/custom/path`},
unmatchedScanOptions: {url: `${location.origin}/custom/invalid`},
message: {url: `${location.origin}/custom/path/update`,
records: [createTextRecord(test_text_data)]}
},
{
desc: "Test that the mediaType of NFCReaderOptions filters relevant data" +
desc: "Test that the mediaType of NFCScanOptions filters relevant data" +
" sources correctly.",
readOptions: {mediaType: "application/octet-stream"},
unmatchedReadOptions: {mediaType: "application/json"},
scanOptions: {mediaType: "application/octet-stream"},
unmatchedScanOptions: {mediaType: "application/json"},
message: createMessage([createOpaqueRecord(test_buffer_data)])
},
{
desc: "Test that the compatibility of NFCReaderOptions filters relevant data" +
desc: "Test that the compatibility of NFCScanOptions filters relevant data" +
" sources correctly.",
readOptions: {compatibility: "vendor"},
unmatchedReadOptions: {compatibility: "nfc-forum"},
scanOptions: {compatibility: "vendor"},
unmatchedScanOptions: {compatibility: "nfc-forum"},
message: createMessage([createTextRecord(test_text_data)]),
}
];
......@@ -75,43 +75,43 @@ const ReadMultiMessagesTests =
[
{
desc: "Test that filtering 'empty' record from different messages" +
" correctly with NFCReaderOptions' recordType is set to 'empty'.",
readOptions: {recordType: "empty"},
" correctly with NFCScanOptions' recordType is set to 'empty'.",
scanOptions: {recordType: "empty"},
message: createMessage([createRecord('empty', '')]),
unmatchedMessage: createMessage([createJsonRecord(test_json_data)]),
},
{
desc: "Test that filtering 'json' record from different messages" +
" correctly with NFCReaderOptions' recordType is set to 'json'.",
readOptions: {recordType: "json"},
" correctly with NFCScanOptions' recordType is set to 'json'.",
scanOptions: {recordType: "json"},
message: createMessage([createJsonRecord(test_json_data)]),
unmatchedMessage: createMessage([createUrlRecord(test_url_data)])
},
{
desc: "Test that filtering 'opaque' record from different messages" +
" correctly with NFCReaderOptions' recordType is set to 'opaque'.",
readOptions: {recordType: "opaque"},
" correctly with NFCScanOptions' recordType is set to 'opaque'.",
scanOptions: {recordType: "opaque"},
message: createMessage([createOpaqueRecord(test_buffer_data)]),
unmatchedMessage: createMessage([createJsonRecord(test_json_data)])
},
{
desc: "Test that filtering 'text' record from different messages" +
" correctly with NFCReaderOptions' recordType is set to 'text'.",
readOptions: {recordType: "text"},
" correctly with NFCScanOptions' recordType is set to 'text'.",
scanOptions: {recordType: "text"},
message: createMessage([createTextRecord(test_text_data)]),
unmatchedMessage: createMessage([createUrlRecord(test_url_data)])
},
{
desc: "Test that filtering 'url' record from different messages" +
" correctly with NFCReaderOptions' recordType is set to 'url'.",
readOptions: {recordType: "url"},
" correctly with NFCScanOptions' recordType is set to 'url'.",
scanOptions: {recordType: "url"},
message: createMessage([createUrlRecord(test_url_data)]),
unmatchedMessage: createMessage([createTextRecord(test_text_data)])
},
{
desc: "Test that filtering 'text' record from different messages" +
" correctly with NFCReaderOptions' url set.",
readOptions: {url: `${location.origin}/custom/path`},
" correctly with NFCScanOptions' url set.",
scanOptions: {url: `${location.origin}/custom/path`},
message: {url: `${location.origin}/custom/path/update`,
records: [createTextRecord(test_text_data)]},
unmatchedMessage: {url: `${location.origin}/custom/invalid`,
......@@ -119,15 +119,15 @@ const ReadMultiMessagesTests =
},
{
desc: "Test that filtering 'opaque' record from different messages" +
" correctly with NFCReaderOptions' mediaType set.",
readOptions: {mediaType: "application/octet-stream"},
" correctly with NFCScanOptions' mediaType set.",
scanOptions: {mediaType: "application/octet-stream"},
message: createMessage([createOpaqueRecord(test_buffer_data)]),
unmatchedMessage: createMessage([createJsonRecord(test_json_data)])
},
{
desc: "Test that filtering 'text' record from different messages" +
" correctly with NFCReaderOptions' compatibility set.",
readOptions: {compatibility: "nfc-forum"},
" correctly with NFCScanOptions' compatibility set.",
scanOptions: {compatibility: "nfc-forum"},
message: createMessage([createTextRecord(test_text_data)]),
unmatchedMessage: createMessage([createJsonRecord(test_json_data)]),
unmatchedCompatibility: "vendor"
......@@ -135,10 +135,10 @@ const ReadMultiMessagesTests =
];
for (let NFCReaderOptionTest of NFCReaderOptionTests) {
testNFCReaderOptions(
testNFCScanOptions(
NFCReaderOptionTest.message,
NFCReaderOptionTest.readOptions,
NFCReaderOptionTest.unmatchedReadOptions,
NFCReaderOptionTest.scanOptions,
NFCReaderOptionTest.unmatchedScanOptions,
NFCReaderOptionTest.desc
);
}
......@@ -151,7 +151,7 @@ for (let readMultiMessagesTest of ReadMultiMessagesTests) {
testReadingMultiMessages(
readMultiMessagesTest.message,
readMultiMessagesTest.readOptions,
readMultiMessagesTest.scanOptions,
readMultiMessagesTest.unmatchedMessage,
unmatchedCompatibility,
readMultiMessagesTest.desc
......
This is a testharness.js-based test.
Found 68 tests; 65 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN.
PASS idl_test setup
PASS NDEFMessage interface: existence and properties of interface object
PASS NDEFMessage interface object length
PASS NDEFMessage interface object name
PASS NDEFMessage interface: existence and properties of interface prototype object
PASS NDEFMessage interface: existence and properties of interface prototype object's "constructor" property
PASS NDEFMessage interface: existence and properties of interface prototype object's @@unscopables property
PASS NDEFMessage interface: attribute url
PASS NDEFMessage interface: attribute records
PASS NDEFRecord interface: existence and properties of interface object
PASS NDEFRecord interface object length
PASS NDEFRecord interface object name
PASS NDEFRecord interface: existence and properties of interface prototype object
PASS NDEFRecord interface: existence and properties of interface prototype object's "constructor" property
PASS NDEFRecord interface: existence and properties of interface prototype object's @@unscopables property
PASS NDEFRecord interface: attribute recordType
PASS NDEFRecord interface: attribute mediaType
PASS NDEFRecord interface: operation toText()
PASS NDEFRecord interface: operation toArrayBuffer()
PASS NDEFRecord interface: operation toJSON()
PASS NFCWriter interface: existence and properties of interface object
PASS NFCWriter interface object length
PASS NFCWriter interface object name
PASS NFCWriter interface: existence and properties of interface prototype object
PASS NFCWriter interface: existence and properties of interface prototype object's "constructor" property
PASS NFCWriter interface: existence and properties of interface prototype object's @@unscopables property
PASS NFCWriter interface: operation push(NDEFMessageSource, NFCPushOptions)
PASS NFCWriter must be primary interface of new NFCWriter();
PASS Stringification of new NFCWriter();
PASS NFCWriter interface: new NFCWriter(); must inherit property "push(NDEFMessageSource, NFCPushOptions)" with the proper type
PASS NFCWriter interface: calling push(NDEFMessageSource, NFCPushOptions) on new NFCWriter(); with too few arguments must throw TypeError
PASS NFCReader interface: existence and properties of interface object
PASS NFCReader interface object length
PASS NFCReader interface object name
PASS NFCReader interface: existence and properties of interface prototype object
PASS NFCReader interface: existence and properties of interface prototype object's "constructor" property
PASS NFCReader interface: existence and properties of interface prototype object's @@unscopables property
PASS NFCReader interface: attribute onreading
PASS NFCReader interface: attribute onerror
FAIL NFCReader interface: operation scan(NFCScanOptions) assert_own_property: interface prototype object missing non-static operation expected property "scan" missing
PASS NFCReader must be primary interface of new NFCReader();
PASS Stringification of new NFCReader();
PASS NFCReader interface: new NFCReader(); must inherit property "onreading" with the proper type
PASS NFCReader interface: new NFCReader(); must inherit property "onerror" with the proper type
FAIL NFCReader interface: new NFCReader(); must inherit property "scan(NFCScanOptions)" with the proper type assert_inherits: property "scan" not found in prototype chain
FAIL NFCReader interface: calling scan(NFCScanOptions) on new NFCReader(); with too few arguments must throw TypeError assert_inherits: property "scan" not found in prototype chain
PASS NFCReadingEvent interface: existence and properties of interface object
PASS NFCReadingEvent interface object length
PASS NFCReadingEvent interface object name
PASS NFCReadingEvent interface: existence and properties of interface prototype object
PASS NFCReadingEvent interface: existence and properties of interface prototype object's "constructor" property
PASS NFCReadingEvent interface: existence and properties of interface prototype object's @@unscopables property
PASS NFCReadingEvent interface: attribute serialNumber
PASS NFCReadingEvent interface: attribute message
PASS NFCReadingEvent must be primary interface of new NFCReadingEvent("reading", { message: {"url":"/custom/path","records":[{"recordType":"text","data":"Hello World"}]} })
PASS Stringification of new NFCReadingEvent("reading", { message: {"url":"/custom/path","records":[{"recordType":"text","data":"Hello World"}]} })
PASS NFCReadingEvent interface: new NFCReadingEvent("reading", { message: {"url":"/custom/path","records":[{"recordType":"text","data":"Hello World"}]} }) must inherit property "serialNumber" with the proper type
PASS NFCReadingEvent interface: new NFCReadingEvent("reading", { message: {"url":"/custom/path","records":[{"recordType":"text","data":"Hello World"}]} }) must inherit property "message" with the proper type
PASS NFCErrorEvent interface: existence and properties of interface object
PASS NFCErrorEvent interface object length
PASS NFCErrorEvent interface object name
PASS NFCErrorEvent interface: existence and properties of interface prototype object
PASS NFCErrorEvent interface: existence and properties of interface prototype object's "constructor" property
PASS NFCErrorEvent interface: existence and properties of interface prototype object's @@unscopables property
PASS NFCErrorEvent interface: attribute error
PASS NFCErrorEvent must be primary interface of new NFCErrorEvent("error", { error: new DOMException() });
PASS Stringification of new NFCErrorEvent("error", { error: new DOMException() });
PASS NFCErrorEvent interface: new NFCErrorEvent("error", { error: new DOMException() }); must inherit property "error" with the proper type
Harness: the test ran to completion.
......@@ -172,42 +172,46 @@ function assertWebNDEFMessagesEqual(message, expectedMessage) {
}
}
function testNFCReaderOptions(message, readOptions, unmatchedReadOptions, desc) {
function testNFCScanOptions(message, scanOptions, unmatchedScanOptions, desc) {
nfc_test(async (t, mockNFC) => {
const reader1 = new NFCReader(unmatchedReadOptions);
const reader2 = new NFCReader(readOptions);
const reader1 = new NFCReader();
const reader2 = new NFCReader();
const controller = new AbortController();
mockNFC.setReadingMessage(message, readOptions.compatibility);
mockNFC.setReadingMessage(message, scanOptions.compatibility);
// Reading from unmatched reader will not be triggered
reader1.onreading = t.unreached_func("reading event should not be fired.");
reader1.start();
unmatchedScanOptions.signal = controller.signal;
reader1.scan(unmatchedScanOptions);
const readerWatcher = new EventWatcher(t, reader2, ["reading", "error"]);
const promise = readerWatcher.wait_for("reading").then(event => {
reader1.stop();
reader2.stop();
controller.abort();
assertWebNDEFMessagesEqual(event.message, new NDEFMessage(message));
});
// NFCReader#start() asynchronously dispatches the onreading event.
reader2.start();
// NFCReader#scan() asynchronously dispatches the onreading event.
scanOptions.signal = controller.signal;
reader2.scan(scanOptions);
await promise;
}, desc);
}
function testReadingMultiMessages(message, readOptions, unmatchedMessage,
function testReadingMultiMessages(message, scanOptions, unmatchedMessage,
unmatchedCompatibility, desc) {
nfc_test(async (t, mockNFC) => {
const reader = new NFCReader(readOptions);
const reader = new NFCReader(scanOptions);
const controller = new AbortController();
const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
const promise = readerWatcher.wait_for("reading").then(event => {
reader.stop();
controller.abort();
assertWebNDEFMessagesEqual(event.message, new NDEFMessage(message));
});
// NFCReader#start() asynchronously dispatches the onreading event.
reader.start();
// NFCReader#scan() asynchronously dispatches the onreading event.
scanOptions.signal = controller.signal;
reader.scan(scanOptions);
// Unmatched message will not be read
mockNFC.setReadingMessage(unmatchedMessage, unmatchedCompatibility);
......
......@@ -5051,8 +5051,7 @@ interface NFCReader : EventTarget
getter onerror
getter onreading
method constructor
method start
method stop
method scan
setter onerror
setter onreading
interface NFCReadingEvent : Event
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment