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');