зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1609065 [wpt PR 21157] - [webnfc] Support writing/reading local type records, a=testonly
Automatic update from web-platform-tests [webnfc] Support writing/reading local type records Some notable points: 1) Local type in WebNFC APIs is always prefixed by ':', but, the ':' will be omitted when it's actually written into the nfc tag. ":act" --> "act" to be written as the TYPE field into the nfc tag. ":text" --> "text" The reading direction is vice versa. "act" --> ":act" to be exposed as NDEFRecord#recordType. "text" --> ":text" 2) Only "smart-poster", external, and local type records are supposed to be able to carry a ndef message as payload. 3) Local type is only expected to exist inside a ndef message that is another ndef record's payload. Top level ndef message is not allowed to have a local type record. The spec changes: https://github.com/w3c/web-nfc/pull/491 https://github.com/w3c/web-nfc/pull/493 https://github.com/w3c/web-nfc/pull/495 https://github.com/w3c/web-nfc/pull/502 https://github.com/w3c/web-nfc/pull/506 BUG=520391 Change-Id: Ic2890c031109aa583437ac93a8901ff71992af78 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1996946 Reviewed-by: Daniel Cheng <dcheng@chromium.org> Reviewed-by: Reilly Grant <reillyg@chromium.org> Commit-Queue: Leon Han <leon.han@intel.com> Cr-Commit-Position: refs/heads/master@{#737290} -- wpt-commits: a1652e2faab5c92db0d3a2523ef9a94003e1e8f5 wpt-pr: 21157
This commit is contained in:
Родитель
2050493dae
Коммит
6cca16717b
|
@ -13,10 +13,12 @@ function toMojoNDEFMessage(message) {
|
|||
|
||||
function toMojoNDEFRecord(record) {
|
||||
let nfcRecord = new device.mojom.NDEFRecord();
|
||||
if (record.recordType.search(':') != -1) {
|
||||
// Simply checks the existence of ':' to decide whether it's an external
|
||||
// type. As a mock, no need to really implement the validation algo at
|
||||
// https://w3c.github.io/web-nfc/#dfn-validate-external-type.
|
||||
// Simply checks the existence of ':' to decide whether it's an external
|
||||
// type or a local type. As a mock, no need to really implement the validation
|
||||
// algorithms for them.
|
||||
if (record.recordType.startsWith(':')) {
|
||||
nfcRecord.category = device.mojom.NDEFRecordTypeCategory.kLocal;
|
||||
} else if (record.recordType.search(':') != -1) {
|
||||
nfcRecord.category = device.mojom.NDEFRecordTypeCategory.kExternal;
|
||||
} else {
|
||||
nfcRecord.category = device.mojom.NDEFRecordTypeCategory.kStandardized;
|
||||
|
|
|
@ -146,23 +146,32 @@ nfc_test(async (t, mockNFC) => {
|
|||
const promise = readerWatcher.wait_for("reading").then(event => {
|
||||
controller.abort();
|
||||
assert_true(event instanceof NDEFReadingEvent);
|
||||
// The message contains only an external type record.
|
||||
|
||||
// The message in the event contains only the external type record.
|
||||
assert_equals(event.message.records.length, 1);
|
||||
assert_equals(event.message.records[0].recordType, 'example.com:payloadIsMessage', 'recordType');
|
||||
// The external type record's payload is a message, which contains only a text record.
|
||||
const embeddedRecords = event.message.records[0].toRecords();
|
||||
assert_equals(embeddedRecords.length, 1);
|
||||
assert_equals(embeddedRecords[0].recordType, 'text', 'recordType');
|
||||
assert_equals(embeddedRecords[0].mediaType, null, 'mediaType');
|
||||
assert_equals(event.message.records[0].recordType, 'example.com:containsLocalRecord',
|
||||
'recordType');
|
||||
|
||||
// The external type record contains only the local type record.
|
||||
assert_equals(event.message.records[0].toRecords().length, 1);
|
||||
assert_equals(event.message.records[0].toRecords()[0].recordType, ':containsTextRecord',
|
||||
'recordType');
|
||||
|
||||
// The local type record contains only the text record.
|
||||
assert_equals(event.message.records[0].toRecords()[0].toRecords()[0].recordType, 'text',
|
||||
'recordType');
|
||||
const decoder = new TextDecoder();
|
||||
assert_equals(decoder.decode(embeddedRecords[0].data), test_text_data,
|
||||
'data has the same content with the original dictionary');
|
||||
assert_equals(decoder.decode(event.message.records[0].toRecords()[0].toRecords()[0].data),
|
||||
test_text_data, 'data has the same content with the original dictionary');
|
||||
});
|
||||
await reader.scan({signal : controller.signal});
|
||||
|
||||
const payloadMessage = createMessage([createTextRecord(test_text_data)]);
|
||||
const message = createMessage([createRecord('example.com:payloadIsMessage',
|
||||
payloadMessage)]);
|
||||
// An external type record --contains-> a local type record --contains-> a text record.
|
||||
const messageContainText = createMessage([createTextRecord(test_text_data)]);
|
||||
const messageContainLocal= createMessage([createRecord(':containsTextRecord',
|
||||
messageContainText)]);
|
||||
const message = createMessage([createRecord('example.com:containsLocalRecord',
|
||||
messageContainLocal)]);
|
||||
mockNFC.setReadingMessage(message);
|
||||
await promise;
|
||||
}, "NDEFRecord.toRecords returns its embedded records correctly.");
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
assert_equals(record.lang, null, 'lang');
|
||||
assert_equals(record.data, null, 'data');
|
||||
assert_throws_dom('NotSupportedError', () => record.toRecords(),
|
||||
'Only smart-poster records and external type records could have embedded records.');
|
||||
'Only smart-poster, external type and local type records could have embedded records.');
|
||||
}, 'NDEFRecord constructor with empty record type');
|
||||
|
||||
test(() => {
|
||||
|
@ -97,7 +97,7 @@
|
|||
assert_equals(decoder.decode(record.data), test_text_data,
|
||||
'data has the same content with the original dictionary');
|
||||
assert_throws_dom('NotSupportedError', () => record.toRecords(),
|
||||
'Only smart-poster records and external type records could have embedded records.');
|
||||
'Only smart-poster, external type and local type records could have embedded records.');
|
||||
}, 'NDEFRecord constructor with text record type and string data');
|
||||
|
||||
test(() => {
|
||||
|
@ -114,7 +114,7 @@
|
|||
assert_equals(decoder.decode(record.data), test_text_data,
|
||||
'data has the same content with the original dictionary');
|
||||
assert_throws_dom('NotSupportedError', () => record.toRecords(),
|
||||
'Only smart-poster records and external type records could have embedded records.');
|
||||
'Only smart-poster, external type and local type records could have embedded records.');
|
||||
}, 'NDEFRecord constructor with text record type and arrayBuffer data');
|
||||
|
||||
test(() => {
|
||||
|
@ -131,7 +131,7 @@
|
|||
assert_equals(decoder.decode(record.data), test_text_data,
|
||||
'data has the same content with the original dictionary');
|
||||
assert_throws_dom('NotSupportedError', () => record.toRecords(),
|
||||
'Only smart-poster records and external type records could have embedded records.');
|
||||
'Only smart-poster, external type and local type records could have embedded records.');
|
||||
}, 'NDEFRecord constructor with text record type and arrayBufferView data');
|
||||
|
||||
test(() => {
|
||||
|
@ -191,7 +191,7 @@
|
|||
assert_equals(decoder.decode(record.data), test_url_data,
|
||||
'data has the same content with the original dictionary');
|
||||
assert_throws_dom('NotSupportedError', () => record.toRecords(),
|
||||
'Only smart-poster records and external type records could have embedded records.');
|
||||
'Only smart-poster, external type and local type records could have embedded records.');
|
||||
}, 'NDEFRecord constructor with url record type');
|
||||
|
||||
test(() => {
|
||||
|
@ -203,7 +203,7 @@
|
|||
assert_equals(decoder.decode(record.data), test_url_data,
|
||||
'data has the same content with the original dictionary');
|
||||
assert_throws_dom('NotSupportedError', () => record.toRecords(),
|
||||
'Only smart-poster records and external type records could have embedded records.');
|
||||
'Only smart-poster, external type and local type records could have embedded records.');
|
||||
}, 'NDEFRecord constructor with absolute-url record type');
|
||||
|
||||
test(() => {
|
||||
|
@ -222,7 +222,7 @@
|
|||
assert_array_equals(new Uint8Array(record.data.buffer), [1, 2, 3, 4],
|
||||
'data has the same content with the original buffer');
|
||||
assert_throws_dom('NotSupportedError', () => record.toRecords(),
|
||||
'Only smart-poster records and external type records could have embedded records.');
|
||||
'Only smart-poster, external type and local type records could have embedded records.');
|
||||
}
|
||||
// Feed ArrayBufferView.
|
||||
{
|
||||
|
@ -233,7 +233,7 @@
|
|||
assert_array_equals(new Uint8Array(record.data.buffer), [2, 3, 4],
|
||||
'data has the same content with the original buffer view');
|
||||
assert_throws_dom('NotSupportedError', () => record.toRecords(),
|
||||
'Only smart-poster records and external type records could have embedded records.');
|
||||
'Only smart-poster, external type and local type records could have embedded records.');
|
||||
}
|
||||
}, 'NDEFRecord constructor with mime record type and stream data');
|
||||
|
||||
|
@ -246,7 +246,7 @@
|
|||
test_json_data,
|
||||
'data has the same content with the original json');
|
||||
assert_throws_dom('NotSupportedError', () => record.toRecords(),
|
||||
'Only smart-poster records and external type records could have embedded records.');
|
||||
'Only smart-poster, external type and local type records could have embedded records.');
|
||||
}, 'NDEFRecord constructor with mime record type and json data');
|
||||
|
||||
test(() => {
|
||||
|
@ -264,7 +264,7 @@
|
|||
assert_array_equals(new Uint8Array(record.data.buffer), [1, 2, 3, 4],
|
||||
'data has the same content with the original buffer');
|
||||
assert_throws_dom('NotSupportedError', () => record.toRecords(),
|
||||
'Only smart-poster records and external type records could have embedded records.');
|
||||
'Only smart-poster, external type and local type records could have embedded records.');
|
||||
}
|
||||
// Feed ArrayBufferView.
|
||||
{
|
||||
|
@ -275,7 +275,7 @@
|
|||
assert_array_equals(new Uint8Array(record.data.buffer), [2, 3, 4],
|
||||
'data has the same content with the original buffer view');
|
||||
assert_throws_dom('NotSupportedError', () => record.toRecords(),
|
||||
'Only smart-poster records and external type records could have embedded records.');
|
||||
'Only smart-poster, external type and local type records could have embedded records.');
|
||||
}
|
||||
}, 'NDEFRecord constructor with unknown record type');
|
||||
|
||||
|
@ -330,6 +330,77 @@
|
|||
}
|
||||
}, 'NDEFRecord constructor with external record type');
|
||||
|
||||
test(() => {
|
||||
assert_throws_js(TypeError, () => new NDEFRecord(createRecord(':xyz', test_buffer_data)),
|
||||
'The local type record must be embedded in the payload of another record (smart-poster, external, or local)');
|
||||
|
||||
// The following test cases use an external type record embedding our target local type record.
|
||||
|
||||
const local_record= createRecord(':xyz', undefined /* data */, 'dummy_id_for_local_type');
|
||||
const payload_message = createMessage([local_record]);
|
||||
const external_record_embedding_local_record = createRecord('example.com:foo', payload_message);
|
||||
|
||||
local_record.data = "A string is not a BufferSource or NDEFMessageInit";
|
||||
assert_throws_js(TypeError, () => new NDEFRecord(external_record_embedding_local_record),
|
||||
'Only BufferSource and NDEFMessageInit are allowed to be the record data.');
|
||||
|
||||
let buffer = new ArrayBuffer(4);
|
||||
new Uint8Array(buffer).set([1, 2, 3, 4]);
|
||||
// Feed ArrayBuffer.
|
||||
{
|
||||
local_record.data = buffer;
|
||||
const record = new NDEFRecord(external_record_embedding_local_record);
|
||||
const embedded_records = record.toRecords();
|
||||
assert_equals(embedded_records.length, 1, 'Only the one embedded local record.');
|
||||
// The embedded local record is actually from |local_record|.
|
||||
assert_equals(embedded_records[0].recordType, ':xyz', 'recordType');
|
||||
assert_equals(embedded_records[0].mediaType, null, 'mediaType');
|
||||
assert_equals(embedded_records[0].id, 'dummy_id_for_local_type', 'id');
|
||||
assert_array_equals(new Uint8Array(embedded_records[0].data.buffer), [1, 2, 3, 4],
|
||||
'data has the same content with the original buffer');
|
||||
assert_equals(embedded_records[0].toRecords(), null,
|
||||
'toRecords() returns null if the payload is not an NDEF message.');
|
||||
}
|
||||
// Feed ArrayBufferView.
|
||||
{
|
||||
let buffer_view = new Uint8Array(buffer, 1);
|
||||
local_record.data = buffer_view;
|
||||
const record = new NDEFRecord(external_record_embedding_local_record);
|
||||
const embedded_records = record.toRecords();
|
||||
assert_equals(embedded_records.length, 1, 'Only the one embedded local record.');
|
||||
// The embedded local record is actually from |local_record|.
|
||||
assert_equals(embedded_records[0].recordType, ':xyz', 'recordType');
|
||||
assert_equals(embedded_records[0].mediaType, null, 'mediaType');
|
||||
assert_equals(embedded_records[0].id, 'dummy_id_for_local_type', 'id');
|
||||
assert_array_equals(new Uint8Array(embedded_records[0].data.buffer), [2, 3, 4],
|
||||
'data has the same content with the original buffer view');
|
||||
assert_equals(embedded_records[0].toRecords(), null,
|
||||
'toRecords() returns null if the payload is not an NDEF message.');
|
||||
}
|
||||
// Feed NDEFMessageInit.
|
||||
{
|
||||
const payload_message = createMessage([createTextRecord(test_text_data)]);
|
||||
local_record.data = payload_message;
|
||||
const record = new NDEFRecord(external_record_embedding_local_record);
|
||||
const embedded_records = record.toRecords();
|
||||
assert_equals(embedded_records.length, 1, 'Only the one embedded local record.');
|
||||
// The embedded local record is actually from |local_record|.
|
||||
assert_equals(embedded_records[0].recordType, ':xyz', 'recordType');
|
||||
assert_equals(embedded_records[0].mediaType, null, 'mediaType');
|
||||
assert_equals(embedded_records[0].id, 'dummy_id_for_local_type', 'id');
|
||||
// The embedded local record embeds another text record that's from |payload_message|.
|
||||
const embedded_records_in_local_record = embedded_records[0].toRecords();
|
||||
assert_equals(embedded_records_in_local_record.length, 1, 'Only one embedded record.');
|
||||
// The only one embedded record has correct content.
|
||||
assert_equals(embedded_records_in_local_record[0].recordType, 'text', 'recordType');
|
||||
assert_equals(embedded_records_in_local_record[0].mediaType, null, 'mediaType');
|
||||
assert_equals(embedded_records_in_local_record[0].id, test_record_id, 'id');
|
||||
const decoder = new TextDecoder();
|
||||
assert_equals(decoder.decode(embedded_records_in_local_record[0].data), test_text_data,
|
||||
'data has the same content with the original dictionary');
|
||||
}
|
||||
}, 'NDEFRecord constructor with local record type');
|
||||
|
||||
test(() => {
|
||||
assert_throws_js(TypeError, () => new NDEFRecord(createRecord('EMptY')),
|
||||
'Unknown record type.');
|
||||
|
@ -370,4 +441,47 @@
|
|||
'example.com:xyz/', test_buffer_data)), 'The type should not contain \'/\'.');
|
||||
}, 'NDEFRecord constructor with invalid external record type');
|
||||
|
||||
test(() => {
|
||||
assert_throws_js(TypeError, () => new NDEFRecord(createRecord(':xyz', test_buffer_data)),
|
||||
'The local type record must be embedded in the payload of another record (smart-poster, external, or local)');
|
||||
|
||||
// The following test cases use an external type record embedding our target local type record.
|
||||
|
||||
const local_record= createRecord(':xyz', test_buffer_data);
|
||||
const payload_message = createMessage([local_record]);
|
||||
const external_record_embedding_local_record = createRecord('example.com:foo', payload_message);
|
||||
|
||||
// OK.
|
||||
new NDEFRecord(external_record_embedding_local_record);
|
||||
local_record.recordType = ':xyZ123';
|
||||
new NDEFRecord(external_record_embedding_local_record);
|
||||
local_record.recordType = ':123XYz';
|
||||
new NDEFRecord(external_record_embedding_local_record);
|
||||
|
||||
local_record.recordType = ':hellö';
|
||||
assert_throws_js(TypeError, () => new NDEFRecord(external_record_embedding_local_record),
|
||||
'The local type must be an ASCII string.');
|
||||
|
||||
// Length of the local type excluding the prefix ':' is 255, OK.
|
||||
local_record.recordType = ':' + [...Array(255)].map(_ => 'a').join('');
|
||||
const record_255 = new NDEFRecord(external_record_embedding_local_record);
|
||||
|
||||
// Exceeding 255, Throws.
|
||||
local_record.recordType = ':' + [...Array(256)].map(_ => 'a').join('');
|
||||
assert_throws_js(TypeError, () => new NDEFRecord(external_record_embedding_local_record),
|
||||
'The local type excluding the prefix \':\' should not be longer than 255.');
|
||||
|
||||
local_record.recordType = 'xyz';
|
||||
assert_throws_js(TypeError, () => new NDEFRecord(external_record_embedding_local_record),
|
||||
'The local type must start with a \':\'.');
|
||||
|
||||
local_record.recordType = ':Xyz';
|
||||
assert_throws_js(TypeError, () => new NDEFRecord(external_record_embedding_local_record),
|
||||
'The local type must have a lower case letter or digit following the prefix \':\'.');
|
||||
|
||||
local_record.recordType = ':-xyz';
|
||||
assert_throws_js(TypeError, () => new NDEFRecord(external_record_embedding_local_record),
|
||||
'The local type must have a lower case letter or digit following the prefix \':\'.');
|
||||
}, 'NDEFRecord constructor with various local record types');
|
||||
|
||||
</script>
|
||||
|
|
|
@ -72,14 +72,23 @@ const invalid_type_messages =
|
|||
// NDEFRecord must have data.
|
||||
createMessage([createRecord('w3.org:xyz')]),
|
||||
|
||||
// NDEFRecord.data for external record must be ArrayBuffer.
|
||||
// NDEFRecord.data for external record must be a BufferSource or NDEFMessageInit.
|
||||
createMessage([createRecord('w3.org:xyz', test_text_data)]),
|
||||
createMessage([createRecord('w3.org:xyz', test_number_data)]),
|
||||
createMessage([createRecord('w3.org:xyz', test_json_data)]),
|
||||
|
||||
// https://w3c.github.io/web-nfc/#dfn-map-local-type-to-ndef
|
||||
// NDEFRecord must have data.
|
||||
createMessage([createRecord(':xyz')]),
|
||||
|
||||
// NDEFRecord.data for local type record must be a BufferSource or NDEFMessageInit.
|
||||
createMessage([createRecord(':xyz', test_text_data)]),
|
||||
createMessage([createRecord(':xyz', test_number_data)]),
|
||||
createMessage([createRecord(':xyz', test_json_data)]),
|
||||
|
||||
// https://w3c.github.io/web-nfc/#ndef-record-types
|
||||
// The record type is neither a known type ('text', 'mime' etc.) nor a
|
||||
// valid custom type for an external type record.
|
||||
// valid external/local type.
|
||||
createMessage([createRecord('unmatched_type', test_buffer_data)])
|
||||
];
|
||||
|
||||
|
@ -283,10 +292,13 @@ nfc_test(async (t, mockNFC) => {
|
|||
and external records with default NDEFWriteOptions.");
|
||||
|
||||
nfc_test(async (t, mockNFC) => {
|
||||
const payloadMessage = createMessage([createTextRecord(test_text_data)]);
|
||||
// Prepare a message containing an external record that uses |payloadMessage| as its payload.
|
||||
const message = createMessage([createRecord('example.com:payloadIsMessage',
|
||||
payloadMessage)]);
|
||||
const messageContainText = createMessage([createTextRecord(test_text_data)]);
|
||||
|
||||
// Prepare a local type record that uses |messageContainText| as its payload.
|
||||
const messageContainLocal = createMessage([createRecord(':containsTextRecord', messageContainText)]);
|
||||
|
||||
// Prepare an external type record that uses |messageContainLocal| as its payload.
|
||||
const message = createMessage([createRecord('example.com:containsLocalRecord', messageContainLocal)]);
|
||||
|
||||
const writer = new NDEFWriter();
|
||||
await writer.write(message);
|
||||
|
@ -294,11 +306,20 @@ nfc_test(async (t, mockNFC) => {
|
|||
|
||||
// The mojom message received by mock nfc contains only the external type record.
|
||||
assert_equals(pushed_message.data.length, 1);
|
||||
assert_equals(pushed_message.data[0].recordType, 'example.com:payloadIsMessage', 'recordType');
|
||||
// The external type record's payload is from the original |payloadMessage|.
|
||||
assert_equals(pushed_message.data[0].recordType, 'example.com:containsLocalRecord', 'recordType');
|
||||
|
||||
// The external type record's payload is from the original |messageContainLocal|,
|
||||
// containing only the local type record.
|
||||
assert_array_equals(pushed_message.data[0].data, new Uint8Array(0),
|
||||
'payloadMessage is used instead');
|
||||
assertNDEFMessagesEqual(payloadMessage, pushed_message.data[0].payloadMessage);
|
||||
assert_equals(pushed_message.data[0].payloadMessage.data.length, 1);
|
||||
assert_equals(pushed_message.data[0].payloadMessage.data[0].recordType, ':containsTextRecord', 'recordType');
|
||||
|
||||
// The local type record's payload is from the original |messageContainText|,
|
||||
// containing only the text record.
|
||||
assert_array_equals(pushed_message.data[0].payloadMessage.data[0].data, new Uint8Array(0),
|
||||
'payloadMessage is used instead');
|
||||
assertNDEFMessagesEqual(messageContainText, pushed_message.data[0].payloadMessage.data[0].payloadMessage);
|
||||
}, "NDEFWriter.write NDEFMessage containing embedded records.");
|
||||
|
||||
nfc_test(async (t, mockNFC) => {
|
||||
|
|
Загрузка…
Ссылка в новой задаче