Commit dbd07288 authored by Wanming Lin's avatar Wanming Lin Committed by Commit Bot

[WebNFC] Add tests for unformatted NDEF tag

This CL adds a few tests to cover various checkpoints:
 - Read/write data from/to an unformatted NDEF tag, as well as interaction with
NDEFPushOptions.overwrite attribute.
 - Read/write data from/to a non-NDEF tag, throws error.

Relevant discussion in spec: https://github.com/w3c/web-nfc/issues/367

Bug: 520391, 1012463
Change-Id: I87cb7dc4611f8575b5616ecd98cc64249d79c4db
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1880537
Commit-Queue: Wanming Lin <wanming.lin@intel.com>
Reviewed-by: default avatarFrançois Beaufort <beaufort.francois@gmail.com>
Reviewed-by: default avatarLeon Han <leon.han@intel.com>
Cr-Commit-Position: refs/heads/master@{#710249}
parent 30f35cbf
......@@ -32,7 +32,7 @@ function toMojoNDEFRecord(record) {
}
function toByteArray(data) {
// Convert JS objects to byte array.
// Converts JS objects to byte array.
let byteArray = new Uint8Array(0);
let tmpData = data;
......@@ -53,7 +53,7 @@ function toByteArray(data) {
function compareNDEFRecords(providedRecord, receivedRecord) {
assert_equals(providedRecord.recordType, receivedRecord.recordType);
// Compare media types without charset.
// Compares media types without charset.
// Charset should be compared when watch method is implemented, in order
// to check that written and read strings are equal.
assert_equals(providedRecord.mediaType,
......@@ -176,6 +176,8 @@ var WebNFCTest = (() => {
this.watchers_ = [];
this.reading_messages_ = [];
this.operations_suspended_ = false;
this.is_ndef_tech_ = true;
this.is_formatted_tag_ = false;
}
// NFC delegate functions.
......@@ -183,7 +185,7 @@ var WebNFCTest = (() => {
let error = this.getHWError();
if (error)
return error;
// Cancel previous pending push operation.
// Cancels previous pending push operation.
if (this.pending_promise_func_) {
this.cancelPendingPushOperation();
}
......@@ -193,16 +195,23 @@ var WebNFCTest = (() => {
return new Promise(resolve => {
this.pending_promise_func_ = resolve;
// Pend push operation if NFC operation is suspended.
if (this.operations_suspended_) {
// Do nothing, pends push operation.
// Pends push operation if NFC operation is suspended.
} else if (options.timeout && options.timeout !== Infinity &&
!this.push_completed_) {
// Resolve with TimeoutError, else pend push operation.
// Resolves with TimeoutError, else pend push operation.
if (this.push_should_timeout_) {
resolve(
createNDEFError(device.mojom.NDEFErrorType.TIMER_EXPIRED));
}
} else if (!this.is_ndef_tech_) {
// Resolves with NotSupportedError if the device does not expose
// NDEF technology.
resolve(createNDEFError(device.mojom.NDEFErrorType.NOT_SUPPORTED));
} else if (this.is_formatted_tag_ && !options.overwrite) {
// Resolves with NotAllowedError if there are NDEF records on the device
// and overwrite is false.
resolve(createNDEFError(device.mojom.NDEFErrorType.NOT_ALLOWED));
} else {
resolve(createNDEFError(null));
}
......@@ -230,8 +239,9 @@ var WebNFCTest = (() => {
}
this.watchers_.push({id: id, options: options});
// Ignore reading if NFC operation is suspended.
if(!this.operations_suspended_) {
// Ignores reading if NFC operation is suspended
// or the NFC tag does not expose NDEF technology.
if(!this.operations_suspended_ && this.is_ndef_tech_) {
// Triggers onWatch if the new watcher matches existing messages.
for (let message of this.reading_messages_) {
if (matchesWatchOptions(message, options)) {
......@@ -301,6 +311,8 @@ var WebNFCTest = (() => {
this.cancelPendingPushOperation();
this.bindingSet_.closeAllBindings();
this.interceptor_.stop();
this.is_ndef_tech_ = true;
this.is_formatted_tag_ = false;
}
cancelPendingPushOperation() {
......@@ -319,9 +331,11 @@ var WebNFCTest = (() => {
// Sets message that is used to deliver NFC reading updates.
setReadingMessage(message) {
this.reading_messages_.push(message);
// Ignore reading if NFC operation is suspended.
// Ignores reading if the NFC tag does not expose NDEF technology.
if(!this.is_ndef_tech_) return;
// Ignores reading if NFC operation is suspended.
if(this.operations_suspended_) return;
// Ignore reading if NDEFPushOptions.ignoreRead is true.
// Ignores reading if NDEFPushOptions.ignoreRead is true.
if(this.push_options_ && this.push_options_.ignoreRead)
return;
// Triggers onWatch if the new message matches existing watchers.
......@@ -350,7 +364,7 @@ var WebNFCTest = (() => {
// Resumes pending NFC reading.
for (let watcher of this.watchers_) {
for (let message of this.reading_messages_) {
if (matchesWatchOptions(message, watcher.options)) {
if (matchesWatchOptions(message, watcher.options) && this.is_ndef_tech_) {
this.client_.onWatch(
[watcher.id], fake_tag_serial_number,
toMojoNDEFMessage(message));
......@@ -362,6 +376,14 @@ var WebNFCTest = (() => {
this.pending_promise_func_(createNDEFError(null));
}
}
setIsNDEFTech(isNdef) {
this.is_ndef_tech_ = isNdef;
}
setIsFormattedTag(isFormatted) {
this.is_formatted_tag_ = isFormatted;
}
}
let testInternal = {
......@@ -371,7 +393,7 @@ var WebNFCTest = (() => {
class NFCTestChromium {
constructor() {
Object.freeze(this); // Make it immutable.
Object.freeze(this); // Makes it immutable.
}
initialize() {
......
......@@ -191,4 +191,34 @@ test(() => {
});
}, "NDEFReader.scan should fail if signal is not an AbortSignal.");
nfc_test(async (t, mockNFC) => {
const reader = new NDEFReader();
mockNFC.setIsNDEFTech(false);
mockNFC.setReadingMessage(createMessage([createTextRecord(test_text_data)]));
await new Promise((resolve, reject) => {
reader.onreading = () => reject("reading event should not be fired.");
reader.scan();
t.step_timeout(resolve, 100);
});
}, "Test that NDEFReader.onreading should not be fired if the NFC tag does not \
expose NDEF technology.");
nfc_test(async (t, mockNFC) => {
const reader = new NDEFReader();
const controller = new AbortController();
mockNFC.setReadingMessage({ records: [] });
const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
const promise = readerWatcher.wait_for("reading").then(event => {
assert_equals(event.serialNumber, fake_tag_serial_number);
assert_equals(event.message.records.length, 0);
controller.abort();
});
// NDEFReader#scan() asynchronously dispatches the reading event.
reader.scan({signal : controller.signal});
await promise;
}, "Test that NDEFReader.onreading should be fired on an unformatted NFC tag \
with empty records array for NDEFMessage.");
</script>
......@@ -33,5 +33,9 @@ PASS Test that mediaType should be set to 'application/octet-stream' if NDEFReco
PASS Test that mediaType should be set to 'application/json' if NDEFRecordInit.record's recordType is 'json' and NDEFRecordInit.record's mediaType is undefined.
FAIL Test that mediaType should be set to 'text/plain' if NDEFRecordInit.record's recordType is 'url' and NDEFRecordInit.record's mediaType is undefined. promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'substring' of null"
PASS Test that mediaType should be set to 'application/octet-stream' if NDEFRecordInit.record's recordType is external type and NDEFRecordInit.record's mediaType is undefined.
PASS NDEFWriter.push should fail when the NFC device does not expose NDEF technology.
PASS NDEFWriter.push should succeed to push data to an unformatted NFC device when the NDEFPushOptions.overwrite is false.
PASS NDEFWriter.push should succeed to overwrite the existing data when the NDEFPushOptions.overwrite is true.
FAIL NDEFWriter.push should fail when there are NDEF records on the NFC device and NDEFPushOptions.overwrite is false. assert_unreached: Should have rejected: undefined Reached unreachable code
Harness: the test ran to completion.
......@@ -19,6 +19,10 @@ const invalid_type_messages =
// https://w3c.github.io/web-nfc/#the-push-method - Step 8.
createMessage([{}]),
// NDEFMessageSource: not NDEF-formatable.
// https://w3c.github.io/web-nfc/#the-push-method - Step 8.
createMessage([]),
// https://w3c.github.io/web-nfc/#dfn-map-text-to-ndef
// NDEFRecord must have data.
createMessage([createTextRecord()]),
......@@ -442,4 +446,35 @@ nfc_test(async (t, mockNFC) => {
}, "Test that mediaType should be set to 'application/octet-stream' if \
NDEFRecordInit.record's recordType is external type and NDEFRecordInit.record's \
mediaType is undefined.");
nfc_test(async (t, mockNFC) => {
const writer = new NDEFWriter();
mockNFC.setIsNDEFTech(false);
await promise_rejects(t, 'NotSupportedError', writer.push(test_text_data));
}, "NDEFWriter.push should fail when the NFC device does not expose \
NDEF technology.");
nfc_test(async (t, mockNFC) => {
const writer = new NDEFWriter();
await writer.push(test_text_data, { overwrite: false });
assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
}, "NDEFWriter.push should succeed to push data to an unformatted NFC device \
when the NDEFPushOptions.overwrite is false.");
nfc_test(async (t, mockNFC) => {
const writer = new NDEFWriter();
await writer.push(test_buffer_data);
assertNDEFMessagesEqual(test_buffer_data, mockNFC.pushedMessage());
await writer.push(test_text_data, { overwrite: true });
assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
}, "NDEFWriter.push should succeed to overwrite the existing data \
when the NDEFPushOptions.overwrite is true.");
nfc_test(async (t, mockNFC) => {
const writer = new NDEFWriter();
const p = writer.push(test_text_data, { overwrite: false });
mockNFC.setIsFormattedTag(true);
await promise_rejects(t, 'NotAllowedError', p);
}, "NDEFWriter.push should fail when there are NDEF records on the NFC device \
and NDEFPushOptions.overwrite is false.");
</script>
......@@ -17,6 +17,8 @@ The `WebNFCTest` interface is defined as:
setPushShouldTimeout(boolean result); // Sets flag to trigger the pending push to timeout.
pushedMessage(); // Gets the pushed `NDEFMessageSource`.
pushOptions(); // Gets the pushed `NDEFPushOptions`.
setIsNDEFTech(boolean isNDEF); // Sets if the NFC device exposes NDEF technology.
setIsFormattedTag(boolean isFormatted); // Sets if the NFC tag has formatted NDEF message.
};
```
......
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