tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

NDEFRecord_constructor.https.window.js (32641B)


      1 // META: script=resources/nfc-helpers.js
      2 
      3 // NDEFRecord constructor
      4 // https://w3c.github.io/web-nfc/#dom-ndefrecord
      5 
      6 test(() => {
      7  assert_equals(NDEFRecord.length, 1);
      8  assert_throws_js(TypeError, () => new NDEFRecord());
      9 }, 'NDEFRecord constructor without init dict');
     10 
     11 test(() => {
     12  assert_throws_js(
     13      TypeError, () => new NDEFRecord(null),
     14      'NDEFRecordInit#recordType is a required field.');
     15 }, 'NDEFRecord constructor with null init dict');
     16 
     17 test(() => {
     18  assert_throws_js(
     19      TypeError,
     20      () => new NDEFRecord({id: test_record_id, data: test_text_data}),
     21      'NDEFRecordInit#recordType is a required field.');
     22 }, 'NDEFRecord constructor without NDEFRecordInit#recordType field');
     23 
     24 test(() => {
     25  assert_throws_js(
     26      TypeError,
     27      () =>
     28          new NDEFRecord(createRecord('empty', test_text_data, test_record_id)),
     29      'id does not apply for empty record type.');
     30 }, 'NDEFRecord constructor with empty record type and id');
     31 
     32 test(() => {
     33  assert_throws_js(
     34      TypeError,
     35      () => new NDEFRecord(
     36          createRecord('empty', test_text_data, test_record_id, 'text/plain')),
     37      'mediaType does not apply for empty record type.');
     38  assert_throws_js(
     39      TypeError,
     40      () => new NDEFRecord(
     41          createRecord('text', test_text_data, test_record_id, 'text/plain')),
     42      'mediaType does not apply for text record type.');
     43  assert_throws_js(
     44      TypeError,
     45      () => new NDEFRecord(
     46          createRecord('url', test_url_data, test_record_id, 'text/plain')),
     47      'mediaType does not apply for url record type.');
     48  assert_throws_js(
     49      TypeError,
     50      () => new NDEFRecord(createRecord(
     51          'absolute-url', test_url_data, test_record_id, 'text/plain')),
     52      'mediaType does not apply for absolute-url record type.');
     53  assert_throws_js(
     54      TypeError,
     55      () => new NDEFRecord(createRecord(
     56          'unknown', test_buffer_data, test_record_id,
     57          'application/octet-stream')),
     58      'mediaType does not apply for unknown record type.');
     59  assert_throws_js(
     60      TypeError,
     61      () => new NDEFRecord(createRecord(
     62          'foo.example.com:bar', test_buffer_data, test_record_id,
     63          'application/octet-stream')),
     64      'mediaType does not apply for external record type.');
     65 }, 'NDEFRecord constructor should only accept mediaType for mime record type');
     66 
     67 test(
     68    () => {
     69      {
     70        const record = new NDEFRecord(createRecord('text', test_text_data));
     71        assert_equals(record.id, null, 'id');
     72      } {const record =
     73             new NDEFRecord(createRecord('text', test_text_data, ''));
     74         assert_equals(record.id, '', 'id');} {
     75        const dummy_id = 'https://dummy_host/mypath/myid';
     76        const record =
     77            new NDEFRecord(createRecord('text', test_text_data, dummy_id));
     78        assert_equals(record.id, dummy_id, 'id');
     79      } {const dummy_id = 'http://dummy_host/mypath/myid';
     80         const record =
     81             new NDEFRecord(createRecord('text', test_text_data, dummy_id));
     82         assert_equals(record.id, dummy_id, 'id');} {
     83        const dummy_id = 'mypath/myid';
     84        const record =
     85            new NDEFRecord(createRecord('text', test_text_data, dummy_id));
     86        assert_equals(record.id, dummy_id, 'id');
     87      }
     88    },
     89    'NDEFRecord constructor with custom record ids');
     90 
     91 test(() => {
     92  const record = new NDEFRecord(createRecord('empty'));
     93  assert_equals(record.recordType, 'empty', 'recordType');
     94  assert_equals(record.mediaType, null, 'mediaType');
     95  assert_equals(record.id, null, 'id');
     96  assert_equals(record.encoding, null, 'encoding');
     97  assert_equals(record.lang, null, 'lang');
     98  assert_equals(record.data, null, 'data');
     99  assert_throws_dom(
    100      'NotSupportedError', () => record.toRecords(),
    101      'Only smart-poster, external type and local type records could have embedded records.');
    102 }, 'NDEFRecord constructor with empty record type');
    103 
    104 test(() => {
    105  const record = new NDEFRecord(createTextRecord(test_text_data));
    106  assert_equals(record.recordType, 'text', 'recordType');
    107  assert_equals(record.mediaType, null, 'mediaType');
    108  assert_equals(record.id, test_record_id, 'id');
    109  assert_equals(record.encoding, 'utf-8', 'encoding');
    110  assert_equals(record.lang, 'en', 'lang');
    111  const decoder = new TextDecoder();
    112  assert_equals(
    113      decoder.decode(record.data), test_text_data,
    114      'data has the same content with the original dictionary');
    115  assert_throws_dom(
    116      'NotSupportedError', () => record.toRecords(),
    117      'Only smart-poster, external type and local type records could have embedded records.');
    118 }, 'NDEFRecord constructor with text record type and string data');
    119 
    120 test(() => {
    121  const encoder = new TextEncoder();
    122  const uint8Array = encoder.encode(test_text_data);
    123  const record = new NDEFRecord(createTextRecord(uint8Array.buffer));
    124  assert_equals(record.recordType, 'text', 'recordType');
    125  assert_equals(record.mediaType, null, 'mediaType');
    126  assert_equals(record.id, test_record_id, 'id');
    127  // By default, 'utf-8'.
    128  assert_equals(record.encoding, 'utf-8', 'encoding');
    129  assert_equals(record.lang, 'en', 'lang');
    130  const decoder = new TextDecoder();
    131  assert_equals(
    132      decoder.decode(record.data), test_text_data,
    133      'data has the same content with the original dictionary');
    134  assert_throws_dom(
    135      'NotSupportedError', () => record.toRecords(),
    136      'Only smart-poster, external type and local type records could have embedded records.');
    137 }, 'NDEFRecord constructor with text record type and arrayBuffer data');
    138 
    139 test(() => {
    140  const encoder = new TextEncoder();
    141  const uint8Array = encoder.encode(test_text_data);
    142  const record = new NDEFRecord(createTextRecord(uint8Array));
    143  assert_equals(record.recordType, 'text', 'recordType');
    144  assert_equals(record.mediaType, null, 'mediaType');
    145  assert_equals(record.id, test_record_id, 'id');
    146  // By default, 'utf-8'.
    147  assert_equals(record.encoding, 'utf-8', 'encoding');
    148  assert_equals(record.lang, 'en', 'lang');
    149  const decoder = new TextDecoder();
    150  assert_equals(
    151      decoder.decode(record.data), test_text_data,
    152      'data has the same content with the original dictionary');
    153  assert_throws_dom(
    154      'NotSupportedError', () => record.toRecords(),
    155      'Only smart-poster, external type and local type records could have embedded records.');
    156 }, 'NDEFRecord constructor with text record type and arrayBufferView data');
    157 
    158 test(() => {
    159  assert_throws_js(
    160      TypeError,
    161      () =>
    162          new NDEFRecord(createTextRecord(test_text_data, 'random-encoding')));
    163  assert_throws_js(
    164      TypeError,
    165      () => new NDEFRecord(createTextRecord(test_text_data, 'utf-16')));
    166  // Only 'utf-8' is OK for a DOMString data source.
    167  const record =
    168      new NDEFRecord(createTextRecord(test_text_data, 'utf-8', 'fr'));
    169  assert_equals(record.recordType, 'text', 'recordType');
    170  assert_equals(record.encoding, 'utf-8', 'encoding');
    171  assert_equals(record.lang, 'fr', 'lang');
    172  const decoder = new TextDecoder();
    173  assert_equals(
    174      decoder.decode(record.data), test_text_data,
    175      'data has the same content with the original text');
    176 
    177  assert_throws_js(
    178      TypeError,
    179      () => new NDEFRecord(createTextRecord(
    180          encodeTextToArrayBuffer(test_text_data, 'utf-8'),
    181          'random-encoding')));
    182  // The encoding list valid for a BufferSource data source.
    183  const encodings = ['utf-8', 'utf-16', 'utf-16be', 'utf-16le'];
    184  for (const encoding of encodings) {
    185    const record = new NDEFRecord(createTextRecord(
    186        encodeTextToArrayBuffer(test_text_data, encoding), encoding, 'fr'));
    187    assert_equals(record.recordType, 'text', 'recordType');
    188    assert_equals(record.encoding, encoding, 'encoding');
    189    assert_equals(record.lang, 'fr', 'lang');
    190    const decoder = new TextDecoder(record.encoding);
    191    assert_equals(
    192        decoder.decode(record.data), test_text_data,
    193        'data has the same content with the original text. encoding: ' +
    194            encoding);
    195  }
    196 }, 'NDEFRecord constructor with text record type, encoding, and lang');
    197 
    198 test(t => {
    199  const previous_lang = document.querySelector('html').getAttribute('lang');
    200  const test_lang = 'fr';
    201  document.querySelector('html').setAttribute('lang', test_lang);
    202  t.add_cleanup(() => {
    203    document.querySelector('html').setAttribute('lang', previous_lang);
    204  });
    205  const record = new NDEFRecord(createTextRecord(test_text_data));
    206  assert_equals(record.recordType, 'text', 'recordType');
    207  assert_equals(record.mediaType, null, 'mediaType');
    208  assert_equals(record.id, test_record_id, 'id');
    209  assert_equals(record.encoding, 'utf-8', 'encoding');
    210  assert_equals(record.lang, test_lang, 'lang');
    211  const decoder = new TextDecoder();
    212  assert_equals(
    213      decoder.decode(record.data), test_text_data,
    214      'data has the same content with the original dictionary');
    215 }, 'NDEFRecord constructor with text record type and custom document language');
    216 
    217 test(() => {
    218  const record = new NDEFRecord(createUrlRecord(test_url_data));
    219  assert_equals(record.recordType, 'url', 'recordType');
    220  assert_equals(record.mediaType, null, 'mediaType');
    221  assert_equals(record.id, test_record_id, 'id');
    222  const decoder = new TextDecoder();
    223  assert_equals(
    224      decoder.decode(record.data), test_url_data,
    225      'data has the same content with the original dictionary');
    226  assert_throws_dom(
    227      'NotSupportedError', () => record.toRecords(),
    228      'Only smart-poster, external type and local type records could have embedded records.');
    229 }, 'NDEFRecord constructor with url record type');
    230 
    231 test(() => {
    232  const record = new NDEFRecord(createUrlRecord(test_url_data, true));
    233  assert_equals(record.recordType, 'absolute-url', 'recordType');
    234  assert_equals(record.mediaType, null, 'mediaType');
    235  assert_equals(record.id, test_record_id, 'id');
    236  const decoder = new TextDecoder();
    237  assert_equals(
    238      decoder.decode(record.data), test_url_data,
    239      'data has the same content with the original dictionary');
    240  assert_throws_dom(
    241      'NotSupportedError', () => record.toRecords(),
    242      'Only smart-poster, external type and local type records could have embedded records.');
    243 }, 'NDEFRecord constructor with absolute-url record type');
    244 
    245 test(() => {
    246  assert_throws_js(
    247      TypeError,
    248      () => new NDEFRecord(createMimeRecord('A string is not a BufferSource')),
    249      'Only BufferSource is allowed to be the record data.');
    250 
    251  let buffer = new ArrayBuffer(4);
    252  new Uint8Array(buffer).set([1, 2, 3, 4]);
    253  // Feed ArrayBuffer.
    254  {
    255    const record = new NDEFRecord(createMimeRecord(buffer));
    256    assert_equals(record.recordType, 'mime', 'recordType');
    257    assert_equals(record.mediaType, 'application/octet-stream', 'mediaType');
    258    assert_equals(record.id, test_record_id, 'id');
    259    assert_array_equals(
    260        new Uint8Array(record.data.buffer), [1, 2, 3, 4],
    261        'data has the same content with the original buffer');
    262    assert_throws_dom(
    263        'NotSupportedError', () => record.toRecords(),
    264        'Only smart-poster, external type and local type records could have embedded records.');
    265  }
    266  // Feed ArrayBufferView.
    267  {
    268    let buffer_view = new Uint8Array(buffer, 1);
    269    const record = new NDEFRecord(createMimeRecord(buffer_view));
    270    assert_equals(record.recordType, 'mime', 'recordType');
    271    assert_equals(record.id, test_record_id, 'id');
    272    assert_array_equals(
    273        new Uint8Array(record.data.buffer), [2, 3, 4],
    274        'data has the same content with the original buffer view');
    275    assert_throws_dom(
    276        'NotSupportedError', () => record.toRecords(),
    277        'Only smart-poster, external type and local type records could have embedded records.');
    278  }
    279 }, 'NDEFRecord constructor with mime record type and stream data');
    280 
    281 test(() => {
    282  const record = new NDEFRecord(createMimeRecordFromJson(test_json_data));
    283  assert_equals(record.recordType, 'mime', 'recordType');
    284  assert_equals(record.mediaType, 'application/json', 'mediaType');
    285  assert_equals(record.id, test_record_id, 'id');
    286  assert_object_equals(
    287      JSON.parse(new TextDecoder().decode(record.data)), test_json_data,
    288      'data has the same content with the original json');
    289  assert_throws_dom(
    290      'NotSupportedError', () => record.toRecords(),
    291      'Only smart-poster, external type and local type records could have embedded records.');
    292 }, 'NDEFRecord constructor with mime record type and json data');
    293 
    294 test(() => {
    295  assert_throws_js(
    296      TypeError,
    297      () =>
    298          new NDEFRecord(createUnknownRecord('A string is not a BufferSource')),
    299      'Only BufferSource is allowed to be the record data.');
    300 
    301  let buffer = new ArrayBuffer(4);
    302  new Uint8Array(buffer).set([1, 2, 3, 4]);
    303  // Feed ArrayBuffer.
    304  {
    305    const record = new NDEFRecord(createUnknownRecord(buffer));
    306    assert_equals(record.recordType, 'unknown', 'recordType');
    307    assert_equals(record.id, test_record_id, 'id');
    308    assert_array_equals(
    309        new Uint8Array(record.data.buffer), [1, 2, 3, 4],
    310        'data has the same content with the original buffer');
    311    assert_throws_dom(
    312        'NotSupportedError', () => record.toRecords(),
    313        'Only smart-poster, external type and local type records could have embedded records.');
    314  }
    315  // Feed ArrayBufferView.
    316  {
    317    let buffer_view = new Uint8Array(buffer, 1);
    318    const record = new NDEFRecord(createUnknownRecord(buffer_view));
    319    assert_equals(record.recordType, 'unknown', 'recordType');
    320    assert_equals(record.id, test_record_id, 'id');
    321    assert_array_equals(
    322        new Uint8Array(record.data.buffer), [2, 3, 4],
    323        'data has the same content with the original buffer view');
    324    assert_throws_dom(
    325        'NotSupportedError', () => record.toRecords(),
    326        'Only smart-poster, external type and local type records could have embedded records.');
    327  }
    328 }, 'NDEFRecord constructor with unknown record type');
    329 
    330 test(() => {
    331  assert_throws_js(
    332      TypeError,
    333      () => new NDEFRecord(createRecord(
    334          'foo.eXamPle.com:bAr*-',
    335          'A string is not a BufferSource or NDEFMessageInit')),
    336      'Only BufferSource and NDEFMessageInit are allowed to be the record data.');
    337 
    338  let buffer = new ArrayBuffer(4);
    339  new Uint8Array(buffer).set([1, 2, 3, 4]);
    340  // Feed ArrayBuffer.
    341  {
    342    const record = new NDEFRecord(
    343        createRecord('foo.eXamPle.com:bAr*-', buffer, test_record_id));
    344    assert_equals(record.recordType, 'foo.eXamPle.com:bAr*-', 'recordType');
    345    assert_equals(record.mediaType, null, 'mediaType');
    346    assert_equals(record.id, test_record_id, 'id');
    347    assert_array_equals(
    348        new Uint8Array(record.data.buffer), [1, 2, 3, 4],
    349        'data has the same content with the original buffer');
    350    assert_equals(
    351        record.toRecords(), null,
    352        'toRecords() returns null if the payload is not an NDEF message.');
    353  }
    354  // Feed ArrayBufferView.
    355  {
    356    let buffer_view = new Uint8Array(buffer, 1);
    357    const record = new NDEFRecord(
    358        createRecord('foo.eXamPle.com:bAr*-', buffer_view, test_record_id));
    359    assert_equals(record.recordType, 'foo.eXamPle.com:bAr*-', 'recordType');
    360    assert_equals(record.mediaType, null, 'mediaType');
    361    assert_equals(record.id, test_record_id, 'id');
    362    assert_array_equals(
    363        new Uint8Array(record.data.buffer), [2, 3, 4],
    364        'data has the same content with the original buffer view');
    365    assert_equals(
    366        record.toRecords(), null,
    367        'toRecords() returns null if the payload is not an NDEF message.');
    368  }
    369  // Feed NDEFMessageInit.
    370  {
    371    const payload_message = createMessage([createTextRecord(test_text_data)]);
    372    const record = new NDEFRecord(createRecord(
    373        'foo.eXamPle.com:bAr*-', payload_message, 'dummy_record_id'));
    374    assert_equals(record.recordType, 'foo.eXamPle.com:bAr*-', 'recordType');
    375    assert_equals(record.mediaType, null, 'mediaType');
    376    assert_equals(record.id, 'dummy_record_id', 'id');
    377    const embedded_records = record.toRecords();
    378    assert_equals(embedded_records.length, 1, 'Only one embedded record.');
    379    // The only one embedded record has correct content.
    380    assert_equals(embedded_records[0].recordType, 'text', 'recordType');
    381    assert_equals(embedded_records[0].mediaType, null, 'mediaType');
    382    assert_equals(embedded_records[0].id, test_record_id, 'id');
    383    const decoder = new TextDecoder();
    384    assert_equals(
    385        decoder.decode(embedded_records[0].data), test_text_data,
    386        'data has the same content with the original dictionary');
    387  }
    388 }, 'NDEFRecord constructor with external record type');
    389 
    390 test(() => {
    391  assert_throws_js(
    392      TypeError, () => new NDEFRecord(createRecord(':xyz', test_buffer_data)),
    393      'The local type record must be embedded in the payload of another record (smart-poster, external, or local)');
    394 
    395  // The following test cases use an external type record embedding our target
    396  // local type record.
    397 
    398  const local_record =
    399      createRecord(':xyz', undefined /* data */, 'dummy_id_for_local_type');
    400  const payload_message = createMessage([local_record]);
    401  const external_record_embedding_local_record =
    402      createRecord('example.com:foo', payload_message);
    403 
    404  local_record.data = 'A string is not a BufferSource or NDEFMessageInit';
    405  assert_throws_js(
    406      TypeError, () => new NDEFRecord(external_record_embedding_local_record),
    407      'Only BufferSource and NDEFMessageInit are allowed to be the record data.');
    408 
    409  let buffer = new ArrayBuffer(4);
    410  new Uint8Array(buffer).set([1, 2, 3, 4]);
    411  // Feed ArrayBuffer.
    412  {
    413    local_record.data = buffer;
    414    const record = new NDEFRecord(external_record_embedding_local_record);
    415    const embedded_records = record.toRecords();
    416    assert_equals(
    417        embedded_records.length, 1, 'Only the one embedded local record.');
    418    // The embedded local record is actually from |local_record|.
    419    assert_equals(embedded_records[0].recordType, ':xyz', 'recordType');
    420    assert_equals(embedded_records[0].mediaType, null, 'mediaType');
    421    assert_equals(embedded_records[0].id, 'dummy_id_for_local_type', 'id');
    422    assert_array_equals(
    423        new Uint8Array(embedded_records[0].data.buffer), [1, 2, 3, 4],
    424        'data has the same content with the original buffer');
    425    assert_equals(
    426        embedded_records[0].toRecords(), null,
    427        'toRecords() returns null if the payload is not an NDEF message.');
    428  }
    429  // Feed ArrayBufferView.
    430  {
    431    let buffer_view = new Uint8Array(buffer, 1);
    432    local_record.data = buffer_view;
    433    const record = new NDEFRecord(external_record_embedding_local_record);
    434    const embedded_records = record.toRecords();
    435    assert_equals(
    436        embedded_records.length, 1, 'Only the one embedded local record.');
    437    // The embedded local record is actually from |local_record|.
    438    assert_equals(embedded_records[0].recordType, ':xyz', 'recordType');
    439    assert_equals(embedded_records[0].mediaType, null, 'mediaType');
    440    assert_equals(embedded_records[0].id, 'dummy_id_for_local_type', 'id');
    441    assert_array_equals(
    442        new Uint8Array(embedded_records[0].data.buffer), [2, 3, 4],
    443        'data has the same content with the original buffer view');
    444    assert_equals(
    445        embedded_records[0].toRecords(), null,
    446        'toRecords() returns null if the payload is not an NDEF message.');
    447  }
    448  // Feed NDEFMessageInit.
    449  {
    450    const payload_message = createMessage([createTextRecord(test_text_data)]);
    451    local_record.data = payload_message;
    452    const record = new NDEFRecord(external_record_embedding_local_record);
    453    const embedded_records = record.toRecords();
    454    assert_equals(
    455        embedded_records.length, 1, 'Only the one embedded local record.');
    456    // The embedded local record is actually from |local_record|.
    457    assert_equals(embedded_records[0].recordType, ':xyz', 'recordType');
    458    assert_equals(embedded_records[0].mediaType, null, 'mediaType');
    459    assert_equals(embedded_records[0].id, 'dummy_id_for_local_type', 'id');
    460    // The embedded local record embeds another text record that's from
    461    // |payload_message|.
    462    const embedded_records_in_local_record = embedded_records[0].toRecords();
    463    assert_equals(
    464        embedded_records_in_local_record.length, 1,
    465        'Only one embedded record.');
    466    // The only one embedded record has correct content.
    467    assert_equals(
    468        embedded_records_in_local_record[0].recordType, 'text', 'recordType');
    469    assert_equals(
    470        embedded_records_in_local_record[0].mediaType, null, 'mediaType');
    471    assert_equals(embedded_records_in_local_record[0].id, test_record_id, 'id');
    472    const decoder = new TextDecoder();
    473    assert_equals(
    474        decoder.decode(embedded_records_in_local_record[0].data),
    475        test_text_data,
    476        'data has the same content with the original dictionary');
    477  }
    478 }, 'NDEFRecord constructor with local record type');
    479 
    480 test(() => {
    481  let buffer = new ArrayBuffer(4);
    482  new Uint8Array(buffer).set([1, 2, 3, 4]);
    483  const encoder = new TextEncoder();
    484  const uri_record = createUrlRecord(test_url_data);
    485  const title_record = createTextRecord(test_text_data, 'utf-8', 'en');
    486  const type_record = createRecord(':t', encoder.encode('image/gif'));
    487  const size_record = createRecord(':s', new Uint32Array([4096]));
    488  const action_record = createRecord(':act', new Uint8Array([3]));
    489  const icon_record = createRecord('mime', buffer, test_record_id, 'image/gif');
    490  const payload_message = createMessage([
    491    uri_record, title_record, type_record, size_record, action_record,
    492    icon_record
    493  ]);
    494  const smart_poster_record =
    495      createRecord('smart-poster', payload_message, 'dummy_record_id');
    496 
    497  const record = new NDEFRecord(smart_poster_record);
    498  assert_equals(record.recordType, 'smart-poster', 'recordType');
    499  assert_equals(record.mediaType, null, 'mediaType');
    500  assert_equals(record.id, 'dummy_record_id', 'id');
    501  const embedded_records = record.toRecords();
    502  assert_equals(embedded_records.length, 6, 'length');
    503 
    504  const decoder = new TextDecoder();
    505  let embedded_record_types = [];
    506  for (let record of embedded_records) {
    507    embedded_record_types.push(record.recordType);
    508    switch (record.recordType) {
    509      case 'url':
    510        assert_equals(record.mediaType, null, 'uri record\'s mediaType');
    511        assert_equals(record.id, test_record_id, 'uri record\'s id');
    512        assert_equals(
    513            decoder.decode(record.data), test_url_data, 'uri record\'s data');
    514        break;
    515      case 'text':
    516        assert_equals(record.mediaType, null, 'title record\'s mediaType');
    517        assert_equals(record.id, test_record_id, 'title record\'s id');
    518        assert_equals(record.encoding, 'utf-8', 'title record\'s encoding');
    519        assert_equals(record.lang, 'en', 'title record\'s lang');
    520        assert_equals(
    521            decoder.decode(record.data), test_text_data,
    522            'title record\'s data');
    523        break;
    524      case ':t':
    525        assert_equals(record.mediaType, null, 'type record\'s mediaType');
    526        assert_equals(record.id, null, 'type record\'s id');
    527        assert_equals(
    528            decoder.decode(record.data), 'image/gif', 'type record\'s data');
    529        break;
    530      case ':s':
    531        assert_equals(record.mediaType, null, 'size record\'s mediaType');
    532        assert_equals(record.id, null, 'size record\'s id');
    533        assert_equals(
    534            record.data.byteLength, 4, 'byteLength of size record\'s data');
    535        assert_equals(
    536            new Uint32Array(record.data.buffer)[0], 4096,
    537            'value of size record\'s data');
    538        break;
    539      case ':act':
    540        assert_equals(record.mediaType, null, 'action record\'s mediaType');
    541        assert_equals(record.id, null, 'action record\'s id');
    542        assert_equals(
    543            record.data.byteLength, 1, 'byteLength of action record\'s data');
    544        assert_equals(
    545            new Uint8Array(record.data.buffer)[0], 3,
    546            'value of action record\'s data');
    547        break;
    548      case 'mime':
    549        assert_equals(
    550            record.mediaType, 'image/gif', 'icon record\'s mediaType');
    551        assert_equals(record.id, test_record_id, 'icon record\'s id');
    552        assert_array_equals(
    553            new Uint8Array(record.data.buffer), [1, 2, 3, 4],
    554            'icon record\'s mediaType');
    555        break;
    556      default:
    557        assert_unreached('Unknown recordType');
    558    }
    559  }
    560  assert_array_equals(
    561      embedded_record_types.sort(), [':act', ':s', ':t', 'mime', 'text', 'url'],
    562      'smart-poster record\'s contained record types');
    563 }, 'NDEFRecord constructor with smart-poster record type');
    564 
    565 test(() => {
    566  const uri_record = createUrlRecord(test_url_data);
    567  const smart_poster_record = createRecord(
    568      'smart-poster', createMessage([uri_record]), 'dummy_record_id');
    569  const record = new NDEFRecord(smart_poster_record);
    570  assert_equals(record.recordType, 'smart-poster', 'recordType');
    571  assert_equals(record.mediaType, null, 'mediaType');
    572  assert_equals(record.id, 'dummy_record_id', 'id');
    573  const embedded_records = record.toRecords();
    574 
    575  // smart-poster record only contains a uri record.
    576  assert_equals(embedded_records.length, 1, 'length');
    577  const decoder = new TextDecoder();
    578  assert_equals(
    579      embedded_records[0].recordType, 'url', 'uri record\'s recordType');
    580  assert_equals(embedded_records[0].mediaType, null, 'uri record\'s mediaType');
    581  assert_equals(embedded_records[0].id, test_record_id, 'uri record\'s id');
    582  assert_equals(
    583      decoder.decode(embedded_records[0].data), test_url_data,
    584      'uri record\'s data');
    585 }, 'NDEFRecord constructor with smart-poster record type that contains only a mandatory uri record');
    586 
    587 test(() => {
    588  assert_throws_js(
    589      TypeError, () => new NDEFRecord(createRecord('EMptY')),
    590      'Unknown record type.');
    591  assert_throws_js(
    592      TypeError, () => new NDEFRecord(createRecord('TeXt', test_text_data)),
    593      'Unknown record type.');
    594  assert_throws_js(
    595      TypeError, () => new NDEFRecord(createRecord('uRL', test_url_data)),
    596      'Unknown record type.');
    597  assert_throws_js(
    598      TypeError, () => new NDEFRecord(createRecord('Mime', test_buffer_data)),
    599      'Unknown record type.');
    600  assert_throws_js(
    601      TypeError,
    602      () => new NDEFRecord(createRecord('sMart-PosTER', test_url_data)),
    603      'Unknown record type.');
    604 }, 'NDEFRecord constructor with record type string being treated as case sensitive');
    605 
    606 test(() => {
    607  assert_throws_js(
    608      TypeError,
    609      () => new NDEFRecord(createRecord('example.com:hellö', test_buffer_data)),
    610      'The external type must be an ASCII string.');
    611 
    612  // Length of the external type is 255, OK.
    613  const record = new NDEFRecord(createRecord(
    614      [...Array(251)].map(_ => 'a').join('') + ':xyz', test_buffer_data));
    615  // Exceeding 255, Throws.
    616  assert_throws_js(
    617      TypeError,
    618      () => new NDEFRecord(createRecord(
    619          [...Array(252)].map(_ => 'a').join('') + ':xyz', test_buffer_data)),
    620      'The external type should not be longer than 255.');
    621 
    622  assert_throws_js(
    623      TypeError, () => new NDEFRecord(createRecord('xyz', test_buffer_data)),
    624      'The external type must have a \':\'.');
    625  assert_throws_js(
    626      TypeError, () => new NDEFRecord(createRecord(':xyz', test_buffer_data)),
    627      'The domain should not be empty.');
    628  assert_throws_js(
    629      TypeError,
    630      () => new NDEFRecord(createRecord('example.com:', test_buffer_data)),
    631      'The type should not be empty.');
    632  assert_throws_js(
    633      TypeError,
    634      () => new NDEFRecord(createRecord('example.com:xyz[', test_buffer_data)),
    635      'The type should not contain \'[\'.');
    636  assert_throws_js(
    637      TypeError,
    638      () => new NDEFRecord(createRecord('example.com:xyz~', test_buffer_data)),
    639      'The type should not contain \'~\'.');
    640  assert_throws_js(
    641      TypeError,
    642      () => new NDEFRecord(createRecord('example.com:xyz/', test_buffer_data)),
    643      'The type should not contain \'/\'.');
    644 }, 'NDEFRecord constructor with invalid external record type');
    645 
    646 test(() => {
    647  const encoder = new TextEncoder();
    648  const uri_record = createUrlRecord(test_url_data);
    649  const title_record = createTextRecord(test_text_data, 'utf-8', 'en');
    650  const type_record = createRecord(':t', encoder.encode('image/gif'));
    651  const size_record = createRecord(':s', new Uint32Array([4096]));
    652  const action_record = createRecord(':act', new Uint8Array([0]));
    653  const icon_record =
    654      createRecord('mime', test_buffer_data, test_record_id, 'image/gif');
    655 
    656  const invalid_data_list = [
    657    {
    658      data: 'A string is not a NDEFMessageInit',
    659      message: 'A string is not allowed.'
    660    },
    661    {data: test_buffer_data, message: 'An ArrayBuffer is not allowed.'}, {
    662      data: createMessage(
    663          [title_record, type_record, size_record, action_record, icon_record]),
    664      message: 'Must contain a URI record.'
    665    },
    666    {
    667      data: createMessage([
    668        uri_record, title_record, type_record, size_record, action_record,
    669        icon_record, uri_record
    670      ]),
    671      message: 'Must not contain more than one uri record.'
    672    },
    673    {
    674      data: createMessage([
    675        uri_record, title_record, type_record, size_record, action_record,
    676        icon_record, type_record
    677      ]),
    678      message: 'Must not contain more than one type record.'
    679    },
    680    {
    681      data: createMessage([
    682        uri_record, title_record, type_record, size_record, action_record,
    683        icon_record, size_record
    684      ]),
    685      message: 'Must not contain more than one size record.'
    686    },
    687    {
    688      data: createMessage([
    689        uri_record, title_record, type_record, size_record, action_record,
    690        icon_record, action_record
    691      ]),
    692      message: 'Must not contain more than one action record.'
    693    },
    694    {
    695      data: createMessage([
    696        uri_record, title_record, type_record, action_record, icon_record,
    697        createRecord(':s', new Uint8Array([1]))
    698      ]),
    699      message:
    700          'Size record must have payload as 4-byte 32 bit unsigned integer.'
    701    },
    702    {
    703      data: createMessage([
    704        uri_record, title_record, type_record, size_record, icon_record,
    705        createRecord(':act', new Uint32Array([0]))
    706      ]),
    707      message:
    708          'Action record must have payload as 1-byte 8 bit unsigned integer.'
    709    }
    710  ];
    711 
    712  invalid_data_list.forEach(entry => {
    713    assert_throws_js(
    714        TypeError,
    715        () => new NDEFRecord(createRecord('smart-poster', entry.data)),
    716        entry.message);
    717  });
    718 }, 'NDEFRecord constructor for smart-poster record with invalid embedded records.');
    719 
    720 test(() => {
    721  assert_throws_js(
    722      TypeError, () => new NDEFRecord(createRecord(':xyz', test_buffer_data)),
    723      'The local type record must be embedded in the payload of another record (smart-poster, external, or local)');
    724 
    725  // The following test cases use an external type record embedding our target
    726  // local type record.
    727 
    728  const local_record = createRecord(':xyz', test_buffer_data);
    729  const payload_message = createMessage([local_record]);
    730  const external_record_embedding_local_record =
    731      createRecord('example.com:foo', payload_message);
    732 
    733  // OK.
    734  new NDEFRecord(external_record_embedding_local_record);
    735  local_record.recordType = ':xyZ123';
    736  new NDEFRecord(external_record_embedding_local_record);
    737  local_record.recordType = ':123XYz';
    738  new NDEFRecord(external_record_embedding_local_record);
    739 
    740  local_record.recordType = ':hellö';
    741  assert_throws_js(
    742      TypeError, () => new NDEFRecord(external_record_embedding_local_record),
    743      'The local type must be an ASCII string.');
    744 
    745  // Length of the local type excluding the prefix ':' is 255, OK.
    746  local_record.recordType = ':' + [...Array(255)].map(_ => 'a').join('');
    747  const record_255 = new NDEFRecord(external_record_embedding_local_record);
    748 
    749  // Exceeding 255, Throws.
    750  local_record.recordType = ':' + [...Array(256)].map(_ => 'a').join('');
    751  assert_throws_js(
    752      TypeError, () => new NDEFRecord(external_record_embedding_local_record),
    753      'The local type excluding the prefix \':\' should not be longer than 255.');
    754 
    755  local_record.recordType = 'xyz';
    756  assert_throws_js(
    757      TypeError, () => new NDEFRecord(external_record_embedding_local_record),
    758      'The local type must start with a \':\'.');
    759 
    760  local_record.recordType = ':Xyz';
    761  assert_throws_js(
    762      TypeError, () => new NDEFRecord(external_record_embedding_local_record),
    763      'The local type must have a lower case letter or digit following the prefix \':\'.');
    764 
    765  local_record.recordType = ':-xyz';
    766  assert_throws_js(
    767      TypeError, () => new NDEFRecord(external_record_embedding_local_record),
    768      'The local type must have a lower case letter or digit following the prefix \':\'.');
    769 }, 'NDEFRecord constructor with various local record types');