michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); michael@0: michael@0: function run_test() { michael@0: run_next_test(); michael@0: } michael@0: michael@0: /** michael@0: * Helper function. michael@0: */ michael@0: function newUint8Worker() { michael@0: let worker = newWorker(); michael@0: let index = 0; // index for read michael@0: let buf = []; michael@0: michael@0: let context = worker.ContextPool._contexts[0]; michael@0: context.Buf.writeUint8 = function(value) { michael@0: buf.push(value); michael@0: }; michael@0: michael@0: context.Buf.readUint8 = function() { michael@0: return buf[index++]; michael@0: }; michael@0: michael@0: context.Buf.seekIncoming = function(offset) { michael@0: index += offset; michael@0: }; michael@0: michael@0: context.Buf.getReadAvailable = function() { michael@0: return buf.length - index; michael@0: }; michael@0: michael@0: worker.debug = do_print; michael@0: michael@0: return worker; michael@0: } michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper#readICCUCS2String() michael@0: */ michael@0: add_test(function test_read_icc_ucs2_string() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: michael@0: // 0x80 michael@0: let text = "TEST"; michael@0: helper.writeUCS2String(text); michael@0: // Also write two unused octets. michael@0: let ffLen = 2; michael@0: for (let i = 0; i < ffLen; i++) { michael@0: helper.writeHexOctet(0xff); michael@0: } michael@0: do_check_eq(iccHelper.readICCUCS2String(0x80, (2 * text.length) + ffLen), text); michael@0: michael@0: // 0x81 michael@0: let array = [0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, michael@0: 0xff, 0xff]; michael@0: let len = array.length; michael@0: for (let i = 0; i < len; i++) { michael@0: helper.writeHexOctet(array[i]); michael@0: } michael@0: do_check_eq(iccHelper.readICCUCS2String(0x81, len), "Mozilla\u694a"); michael@0: michael@0: // 0x82 michael@0: let array2 = [0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, michael@0: 0xca, 0xff, 0xff]; michael@0: let len2 = array2.length; michael@0: for (let i = 0; i < len2; i++) { michael@0: helper.writeHexOctet(array2[i]); michael@0: } michael@0: do_check_eq(iccHelper.readICCUCS2String(0x82, len2), "Mozilla\u694a"); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper#readDiallingNumber michael@0: */ michael@0: add_test(function test_read_dialling_number() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: let str = "123456789"; michael@0: michael@0: helper.readHexOctet = function() { michael@0: return 0x81; michael@0: }; michael@0: michael@0: helper.readSwappedNibbleBcdString = function(len) { michael@0: return str.substring(0, len); michael@0: }; michael@0: michael@0: for (let i = 0; i < str.length; i++) { michael@0: do_check_eq(str.substring(0, i - 1), // -1 for the TON michael@0: iccHelper.readDiallingNumber(i)); michael@0: } michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper#read8BitUnpackedToString michael@0: */ michael@0: add_test(function test_read_8bit_unpacked_to_string() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; michael@0: const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; michael@0: michael@0: // Test 1: Read GSM alphabets. michael@0: // Write alphabets before ESCAPE. michael@0: for (let i = 0; i < PDU_NL_EXTENDED_ESCAPE; i++) { michael@0: helper.writeHexOctet(i); michael@0: } michael@0: michael@0: // Write two ESCAPEs to make it become ' '. michael@0: helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); michael@0: helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); michael@0: michael@0: for (let i = PDU_NL_EXTENDED_ESCAPE + 1; i < langTable.length; i++) { michael@0: helper.writeHexOctet(i); michael@0: } michael@0: michael@0: // Also write two unused fields. michael@0: let ffLen = 2; michael@0: for (let i = 0; i < ffLen; i++) { michael@0: helper.writeHexOctet(0xff); michael@0: } michael@0: michael@0: do_check_eq(iccHelper.read8BitUnpackedToString(PDU_NL_EXTENDED_ESCAPE), michael@0: langTable.substring(0, PDU_NL_EXTENDED_ESCAPE)); michael@0: do_check_eq(iccHelper.read8BitUnpackedToString(2), " "); michael@0: do_check_eq(iccHelper.read8BitUnpackedToString(langTable.length - michael@0: PDU_NL_EXTENDED_ESCAPE - 1 + ffLen), michael@0: langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1)); michael@0: michael@0: // Test 2: Read GSM extended alphabets. michael@0: for (let i = 0; i < langShiftTable.length; i++) { michael@0: helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); michael@0: helper.writeHexOctet(i); michael@0: } michael@0: michael@0: // Read string before RESERVED_CONTROL. michael@0: do_check_eq(iccHelper.read8BitUnpackedToString(PDU_NL_RESERVED_CONTROL * 2), michael@0: langShiftTable.substring(0, PDU_NL_RESERVED_CONTROL)); michael@0: // ESCAPE + RESERVED_CONTROL will become ' '. michael@0: do_check_eq(iccHelper.read8BitUnpackedToString(2), " "); michael@0: // Read string between RESERVED_CONTROL and EXTENDED_ESCAPE. michael@0: do_check_eq(iccHelper.read8BitUnpackedToString( michael@0: (PDU_NL_EXTENDED_ESCAPE - PDU_NL_RESERVED_CONTROL - 1) * 2), michael@0: langShiftTable.substring(PDU_NL_RESERVED_CONTROL + 1, michael@0: PDU_NL_EXTENDED_ESCAPE)); michael@0: // ESCAPE + ESCAPE will become ' '. michael@0: do_check_eq(iccHelper.read8BitUnpackedToString(2), " "); michael@0: // Read remaining string. michael@0: do_check_eq(iccHelper.read8BitUnpackedToString( michael@0: (langShiftTable.length - PDU_NL_EXTENDED_ESCAPE - 1) * 2), michael@0: langShiftTable.substring(PDU_NL_EXTENDED_ESCAPE + 1)); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper#writeStringTo8BitUnpacked. michael@0: * michael@0: * Test writing GSM 8 bit alphabets. michael@0: */ michael@0: add_test(function test_write_string_to_8bit_unpacked() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; michael@0: const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; michael@0: // Length of trailing 0xff. michael@0: let ffLen = 2; michael@0: let str; michael@0: michael@0: // Test 1, write GSM alphabets. michael@0: iccHelper.writeStringTo8BitUnpacked(langTable.length + ffLen, langTable); michael@0: michael@0: for (let i = 0; i < langTable.length; i++) { michael@0: do_check_eq(helper.readHexOctet(), i); michael@0: } michael@0: michael@0: for (let i = 0; i < ffLen; i++) { michael@0: do_check_eq(helper.readHexOctet(), 0xff); michael@0: } michael@0: michael@0: // Test 2, write GSM extended alphabets. michael@0: str = "\u000c\u20ac"; michael@0: iccHelper.writeStringTo8BitUnpacked(4, str); michael@0: michael@0: do_check_eq(iccHelper.read8BitUnpackedToString(4), str); michael@0: michael@0: // Test 3, write GSM and GSM extended alphabets. michael@0: // \u000c, \u20ac are from gsm extended alphabets. michael@0: // \u00a3 is from gsm alphabet. michael@0: str = "\u000c\u20ac\u00a3"; michael@0: michael@0: // 2 octets * 2 = 4 octets for 2 gsm extended alphabets, michael@0: // 1 octet for 1 gsm alphabet, michael@0: // 2 octes for trailing 0xff. michael@0: // "Totally 7 octets are to be written." michael@0: iccHelper.writeStringTo8BitUnpacked(7, str); michael@0: michael@0: do_check_eq(iccHelper.read8BitUnpackedToString(7), str); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper#writeStringTo8BitUnpacked with maximum octets written. michael@0: */ michael@0: add_test(function test_write_string_to_8bit_unpacked_with_max_octets_written() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; michael@0: const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; michael@0: michael@0: // The maximum of the number of octets that can be written is 3. michael@0: // Only 3 characters shall be written even the length of the string is 4. michael@0: iccHelper.writeStringTo8BitUnpacked(3, langTable.substring(0, 4)); michael@0: helper.writeHexOctet(0xff); // dummy octet. michael@0: for (let i = 0; i < 3; i++) { michael@0: do_check_eq(helper.readHexOctet(), i); michael@0: } michael@0: do_check_false(helper.readHexOctet() == 4); michael@0: michael@0: // \u000c is GSM extended alphabet, 2 octets. michael@0: // \u00a3 is GSM alphabet, 1 octet. michael@0: let str = "\u000c\u00a3"; michael@0: iccHelper.writeStringTo8BitUnpacked(3, str); michael@0: do_check_eq(iccHelper.read8BitUnpackedToString(3), str); michael@0: michael@0: str = "\u00a3\u000c"; michael@0: iccHelper.writeStringTo8BitUnpacked(3, str); michael@0: do_check_eq(iccHelper.read8BitUnpackedToString(3), str); michael@0: michael@0: // 2 GSM extended alphabets cost 4 octets, but maximum is 3, so only the 1st michael@0: // alphabet can be written. michael@0: str = "\u000c\u000c"; michael@0: iccHelper.writeStringTo8BitUnpacked(3, str); michael@0: helper.writeHexOctet(0xff); // dummy octet. michael@0: do_check_eq(iccHelper.read8BitUnpackedToString(4), str.substring(0, 1)); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper.readAlphaIdentifier michael@0: */ michael@0: add_test(function test_read_alpha_identifier() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: michael@0: // UCS2: 0x80 michael@0: let text = "TEST"; michael@0: helper.writeHexOctet(0x80); michael@0: helper.writeUCS2String(text); michael@0: // Also write two unused octets. michael@0: let ffLen = 2; michael@0: for (let i = 0; i < ffLen; i++) { michael@0: helper.writeHexOctet(0xff); michael@0: } michael@0: do_check_eq(iccHelper.readAlphaIdentifier(1 + (2 * text.length) + ffLen), text); michael@0: michael@0: // UCS2: 0x81 michael@0: let array = [0x81, 0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff]; michael@0: for (let i = 0; i < array.length; i++) { michael@0: helper.writeHexOctet(array[i]); michael@0: } michael@0: do_check_eq(iccHelper.readAlphaIdentifier(array.length), "Mozilla\u694a"); michael@0: michael@0: // UCS2: 0x82 michael@0: let array2 = [0x82, 0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff]; michael@0: for (let i = 0; i < array2.length; i++) { michael@0: helper.writeHexOctet(array2[i]); michael@0: } michael@0: do_check_eq(iccHelper.readAlphaIdentifier(array2.length), "Mozilla\u694a"); michael@0: michael@0: // GSM 8 Bit Unpacked michael@0: const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; michael@0: for (let i = 0; i < PDU_NL_EXTENDED_ESCAPE; i++) { michael@0: helper.writeHexOctet(i); michael@0: } michael@0: do_check_eq(iccHelper.readAlphaIdentifier(PDU_NL_EXTENDED_ESCAPE), michael@0: langTable.substring(0, PDU_NL_EXTENDED_ESCAPE)); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper.writeAlphaIdentifier michael@0: */ michael@0: add_test(function test_write_alpha_identifier() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: // Length of trailing 0xff. michael@0: let ffLen = 2; michael@0: michael@0: // Removal michael@0: iccHelper.writeAlphaIdentifier(10, null); michael@0: do_check_eq(iccHelper.readAlphaIdentifier(10), ""); michael@0: michael@0: // GSM 8 bit michael@0: let str = "Mozilla"; michael@0: iccHelper.writeAlphaIdentifier(str.length + ffLen, str); michael@0: do_check_eq(iccHelper.readAlphaIdentifier(str.length + ffLen), str); michael@0: michael@0: // UCS2 michael@0: str = "Mozilla\u694a"; michael@0: iccHelper.writeAlphaIdentifier(str.length * 2 + ffLen, str); michael@0: // * 2 for each character will be encoded to UCS2 alphabets. michael@0: do_check_eq(iccHelper.readAlphaIdentifier(str.length * 2 + ffLen), str); michael@0: michael@0: // Test with maximum octets written. michael@0: // 1 coding scheme (0x80) and 1 UCS2 character, total 3 octets. michael@0: str = "\u694a"; michael@0: iccHelper.writeAlphaIdentifier(3, str); michael@0: do_check_eq(iccHelper.readAlphaIdentifier(3), str); michael@0: michael@0: // 1 coding scheme (0x80) and 2 UCS2 characters, total 5 octets. michael@0: // numOctets is limited to 4, so only 1 UCS2 character can be written. michael@0: str = "\u694a\u694a"; michael@0: iccHelper.writeAlphaIdentifier(4, str); michael@0: helper.writeHexOctet(0xff); // dummy octet. michael@0: do_check_eq(iccHelper.readAlphaIdentifier(5), str.substring(0, 1)); michael@0: michael@0: // Write 0 octet. michael@0: iccHelper.writeAlphaIdentifier(0, "1"); michael@0: helper.writeHexOctet(0xff); // dummy octet. michael@0: do_check_eq(iccHelper.readAlphaIdentifier(1), ""); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper.readAlphaIdDiallingNumber michael@0: */ michael@0: add_test(function test_read_alpha_id_dialling_number() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: let buf = context.Buf; michael@0: const recordSize = 32; michael@0: michael@0: function testReadAlphaIdDiallingNumber(contact) { michael@0: iccHelper.readAlphaIdentifier = function() { michael@0: return contact.alphaId; michael@0: }; michael@0: michael@0: iccHelper.readNumberWithLength = function() { michael@0: return contact.number; michael@0: }; michael@0: michael@0: let strLen = recordSize * 2; michael@0: buf.writeInt32(strLen); // fake length michael@0: helper.writeHexOctet(0xff); // fake CCP michael@0: helper.writeHexOctet(0xff); // fake EXT1 michael@0: buf.writeStringDelimiter(strLen); michael@0: michael@0: let contactR = iccHelper.readAlphaIdDiallingNumber(recordSize); michael@0: if (contact.alphaId == "" && contact.number == "") { michael@0: do_check_eq(contactR, null); michael@0: } else { michael@0: do_check_eq(contactR.alphaId, contact.alphaId); michael@0: do_check_eq(contactR.number, contact.number); michael@0: } michael@0: } michael@0: michael@0: testReadAlphaIdDiallingNumber({alphaId: "AlphaId", number: "0987654321"}); michael@0: testReadAlphaIdDiallingNumber({alphaId: "", number: ""}); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper.writeAlphaIdDiallingNumber michael@0: */ michael@0: add_test(function test_write_alpha_id_dialling_number() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.ICCPDUHelper; michael@0: const recordSize = 32; michael@0: michael@0: // Write a normal contact. michael@0: let contactW = { michael@0: alphaId: "Mozilla", michael@0: number: "1234567890" michael@0: }; michael@0: helper.writeAlphaIdDiallingNumber(recordSize, contactW.alphaId, michael@0: contactW.number); michael@0: michael@0: let contactR = helper.readAlphaIdDiallingNumber(recordSize); michael@0: do_check_eq(contactW.alphaId, contactR.alphaId); michael@0: do_check_eq(contactW.number, contactR.number); michael@0: michael@0: // Write a contact with alphaId encoded in UCS2 and number has '+'. michael@0: let contactUCS2 = { michael@0: alphaId: "火狐", michael@0: number: "+1234567890" michael@0: }; michael@0: helper.writeAlphaIdDiallingNumber(recordSize, contactUCS2.alphaId, michael@0: contactUCS2.number); michael@0: contactR = helper.readAlphaIdDiallingNumber(recordSize); michael@0: do_check_eq(contactUCS2.alphaId, contactR.alphaId); michael@0: do_check_eq(contactUCS2.number, contactR.number); michael@0: michael@0: // Write a null contact (Removal). michael@0: helper.writeAlphaIdDiallingNumber(recordSize); michael@0: contactR = helper.readAlphaIdDiallingNumber(recordSize); michael@0: do_check_eq(contactR, null); michael@0: michael@0: // Write a longer alphaId/dialling number michael@0: // Dialling Number : Maximum 20 digits(10 octets). michael@0: // Alpha Identifier: 32(recordSize) - 14 (10 octets for Dialling Number, 1 michael@0: // octet for TON/NPI, 1 for number length octet, and 2 for michael@0: // Ext) = Maximum 18 octets. michael@0: let longContact = { michael@0: alphaId: "AAAAAAAAABBBBBBBBBCCCCCCCCC", michael@0: number: "123456789012345678901234567890", michael@0: }; michael@0: helper.writeAlphaIdDiallingNumber(recordSize, longContact.alphaId, michael@0: longContact.number); michael@0: contactR = helper.readAlphaIdDiallingNumber(recordSize); michael@0: do_check_eq(contactR.alphaId, "AAAAAAAAABBBBBBBBB"); michael@0: do_check_eq(contactR.number, "12345678901234567890"); michael@0: michael@0: // Add '+' to number and test again. michael@0: longContact.number = "+123456789012345678901234567890"; michael@0: helper.writeAlphaIdDiallingNumber(recordSize, longContact.alphaId, michael@0: longContact.number); michael@0: contactR = helper.readAlphaIdDiallingNumber(recordSize); michael@0: do_check_eq(contactR.alphaId, "AAAAAAAAABBBBBBBBB"); michael@0: do_check_eq(contactR.number, "+12345678901234567890"); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper.writeDiallingNumber michael@0: */ michael@0: add_test(function test_write_dialling_number() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.ICCPDUHelper; michael@0: michael@0: // with + michael@0: let number = "+123456"; michael@0: let len = 4; michael@0: helper.writeDiallingNumber(number); michael@0: do_check_eq(helper.readDiallingNumber(len), number); michael@0: michael@0: // without + michael@0: number = "987654"; michael@0: len = 4; michael@0: helper.writeDiallingNumber(number); michael@0: do_check_eq(helper.readDiallingNumber(len), number); michael@0: michael@0: number = "9876543"; michael@0: len = 5; michael@0: helper.writeDiallingNumber(number); michael@0: do_check_eq(helper.readDiallingNumber(len), number); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper.readNumberWithLength michael@0: */ michael@0: add_test(function test_read_number_with_length() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: let number = "123456789"; michael@0: michael@0: iccHelper.readDiallingNumber = function(numLen) { michael@0: return number.substring(0, numLen); michael@0: }; michael@0: michael@0: helper.writeHexOctet(number.length + 1); michael@0: helper.writeHexOctet(PDU_TOA_ISDN); michael@0: do_check_eq(iccHelper.readNumberWithLength(), number); michael@0: michael@0: helper.writeHexOctet(0xff); michael@0: do_check_eq(iccHelper.readNumberWithLength(), null); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCPDUHelper.writeNumberWithLength michael@0: */ michael@0: add_test(function test_write_number_with_length() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: michael@0: function test(number, expectedNumber) { michael@0: expectedNumber = expectedNumber || number; michael@0: iccHelper.writeNumberWithLength(number); michael@0: let numLen = helper.readHexOctet(); michael@0: do_check_eq(expectedNumber, iccHelper.readDiallingNumber(numLen)); michael@0: for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) { michael@0: do_check_eq(0xff, helper.readHexOctet()); michael@0: } michael@0: } michael@0: michael@0: // without + michael@0: test("123456789"); michael@0: michael@0: // with + michael@0: test("+987654321"); michael@0: michael@0: // extended BCD coding michael@0: test("1*2#3,4*5#6,"); michael@0: michael@0: // with + and extended BCD coding michael@0: test("+1*2#3,4*5#6,"); michael@0: michael@0: // non-supported characters should not be written. michael@0: test("(1)23-456+789", "123456789"); michael@0: michael@0: test("++(01)2*3-4#5,6+7(8)9*0#1,", "+012*34#5,6789*0#1,"); michael@0: michael@0: // null michael@0: iccHelper.writeNumberWithLength(null); michael@0: for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES + 1); i++) { michael@0: do_check_eq(0xff, helper.readHexOctet()); michael@0: } michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify GsmPDUHelper.writeTimestamp michael@0: */ michael@0: add_test(function test_write_timestamp() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: michael@0: // current date michael@0: let dateInput = new Date(); michael@0: let dateOutput = new Date(); michael@0: helper.writeTimestamp(dateInput); michael@0: dateOutput.setTime(helper.readTimestamp()); michael@0: michael@0: do_check_eq(dateInput.getFullYear(), dateOutput.getFullYear()); michael@0: do_check_eq(dateInput.getMonth(), dateOutput.getMonth()); michael@0: do_check_eq(dateInput.getDate(), dateOutput.getDate()); michael@0: do_check_eq(dateInput.getHours(), dateOutput.getHours()); michael@0: do_check_eq(dateInput.getMinutes(), dateOutput.getMinutes()); michael@0: do_check_eq(dateInput.getSeconds(), dateOutput.getSeconds()); michael@0: do_check_eq(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset()); michael@0: michael@0: // 2034-01-23 12:34:56 -0800 GMT michael@0: let time = Date.UTC(2034, 1, 23, 12, 34, 56); michael@0: time = time - (8 * 60 * 60 * 1000); michael@0: dateInput.setTime(time); michael@0: helper.writeTimestamp(dateInput); michael@0: dateOutput.setTime(helper.readTimestamp()); michael@0: michael@0: do_check_eq(dateInput.getFullYear(), dateOutput.getFullYear()); michael@0: do_check_eq(dateInput.getMonth(), dateOutput.getMonth()); michael@0: do_check_eq(dateInput.getDate(), dateOutput.getDate()); michael@0: do_check_eq(dateInput.getHours(), dateOutput.getHours()); michael@0: do_check_eq(dateInput.getMinutes(), dateOutput.getMinutes()); michael@0: do_check_eq(dateInput.getSeconds(), dateOutput.getSeconds()); michael@0: do_check_eq(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset()); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify GsmPDUHelper.octectToBCD and GsmPDUHelper.BCDToOctet michael@0: */ michael@0: add_test(function test_octect_BCD() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: michael@0: // 23 michael@0: let number = 23; michael@0: let octet = helper.BCDToOctet(number); michael@0: do_check_eq(helper.octetToBCD(octet), number); michael@0: michael@0: // 56 michael@0: number = 56; michael@0: octet = helper.BCDToOctet(number); michael@0: do_check_eq(helper.octetToBCD(octet), number); michael@0: michael@0: // 0x23 michael@0: octet = 0x23; michael@0: number = helper.octetToBCD(octet); michael@0: do_check_eq(helper.BCDToOctet(number), octet); michael@0: michael@0: // 0x56 michael@0: octet = 0x56; michael@0: number = helper.octetToBCD(octet); michael@0: do_check_eq(helper.BCDToOctet(number), octet); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCUtilsHelper.isICCServiceAvailable. michael@0: */ michael@0: add_test(function test_is_icc_service_available() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ICCUtilsHelper = context.ICCUtilsHelper; michael@0: let RIL = context.RIL; michael@0: michael@0: function test_table(sst, geckoService, simEnabled, usimEnabled) { michael@0: RIL.iccInfoPrivate.sst = sst; michael@0: RIL.appType = CARD_APPTYPE_SIM; michael@0: do_check_eq(ICCUtilsHelper.isICCServiceAvailable(geckoService), simEnabled); michael@0: RIL.appType = CARD_APPTYPE_USIM; michael@0: do_check_eq(ICCUtilsHelper.isICCServiceAvailable(geckoService), usimEnabled); michael@0: } michael@0: michael@0: test_table([0x08], "ADN", true, false); michael@0: test_table([0x08], "FDN", false, false); michael@0: test_table([0x08], "SDN", false, true); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCUtilsHelper.isGsm8BitAlphabet michael@0: */ michael@0: add_test(function test_is_gsm_8bit_alphabet() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ICCUtilsHelper = context.ICCUtilsHelper; michael@0: const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; michael@0: const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; michael@0: michael@0: do_check_eq(ICCUtilsHelper.isGsm8BitAlphabet(langTable), true); michael@0: do_check_eq(ICCUtilsHelper.isGsm8BitAlphabet(langShiftTable), true); michael@0: do_check_eq(ICCUtilsHelper.isGsm8BitAlphabet("\uaaaa"), false); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify RIL.iccGetCardLockState("fdn") michael@0: */ michael@0: add_test(function test_icc_get_card_lock_state_fdn() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ril = context.RIL; michael@0: let buf = context.Buf; michael@0: michael@0: buf.sendParcel = function() { michael@0: // Request Type. michael@0: do_check_eq(this.readInt32(), REQUEST_QUERY_FACILITY_LOCK) michael@0: michael@0: // Token : we don't care. michael@0: this.readInt32(); michael@0: michael@0: // String Array Length. michael@0: do_check_eq(this.readInt32(), ril.v5Legacy ? 3 : 4); michael@0: michael@0: // Facility. michael@0: do_check_eq(this.readString(), ICC_CB_FACILITY_FDN); michael@0: michael@0: // Password. michael@0: do_check_eq(this.readString(), ""); michael@0: michael@0: // Service class. michael@0: do_check_eq(this.readString(), (ICC_SERVICE_CLASS_VOICE | michael@0: ICC_SERVICE_CLASS_DATA | michael@0: ICC_SERVICE_CLASS_FAX).toString()); michael@0: michael@0: if (!ril.v5Legacy) { michael@0: // AID. Ignore because it's from modem. michael@0: this.readInt32(); michael@0: } michael@0: michael@0: run_next_test(); michael@0: }; michael@0: michael@0: ril.iccGetCardLockState({lockType: "fdn"}); michael@0: }); michael@0: michael@0: add_test(function test_get_network_name_from_icc() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let RIL = context.RIL; michael@0: let ICCUtilsHelper = context.ICCUtilsHelper; michael@0: michael@0: function testGetNetworkNameFromICC(operatorData, expectedResult) { michael@0: let result = ICCUtilsHelper.getNetworkNameFromICC(operatorData.mcc, michael@0: operatorData.mnc, michael@0: operatorData.lac); michael@0: michael@0: if (expectedResult == null) { michael@0: do_check_eq(result, expectedResult); michael@0: } else { michael@0: do_check_eq(result.fullName, expectedResult.longName); michael@0: do_check_eq(result.shortName, expectedResult.shortName); michael@0: } michael@0: } michael@0: michael@0: // Before EF_OPL and EF_PNN have been loaded. michael@0: testGetNetworkNameFromICC({mcc: 123, mnc: 456, lac: 0x1000}, null); michael@0: testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x2000}, null); michael@0: michael@0: // Set HPLMN michael@0: RIL.iccInfo.mcc = 123; michael@0: RIL.iccInfo.mnc = 456; michael@0: michael@0: RIL.voiceRegistrationState = { michael@0: cell: { michael@0: gsmLocationAreaCode: 0x1000 michael@0: } michael@0: }; michael@0: RIL.operator = {}; michael@0: michael@0: // Set EF_PNN michael@0: RIL.iccInfoPrivate = { michael@0: PNN: [ michael@0: {"fullName": "PNN1Long", "shortName": "PNN1Short"}, michael@0: {"fullName": "PNN2Long", "shortName": "PNN2Short"}, michael@0: {"fullName": "PNN3Long", "shortName": "PNN3Short"}, michael@0: {"fullName": "PNN4Long", "shortName": "PNN4Short"} michael@0: ] michael@0: }; michael@0: michael@0: // EF_OPL isn't available and current isn't in HPLMN, michael@0: testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x1000}, null); michael@0: michael@0: // EF_OPL isn't available and current is in HPLMN, michael@0: // the first record of PNN should be returned. michael@0: testGetNetworkNameFromICC({mcc: 123, mnc: 456, lac: 0x1000}, michael@0: {longName: "PNN1Long", shortName: "PNN1Short"}); michael@0: michael@0: // Set EF_OPL michael@0: RIL.iccInfoPrivate.OPL = [ michael@0: { michael@0: "mcc": 123, michael@0: "mnc": 456, michael@0: "lacTacStart": 0, michael@0: "lacTacEnd": 0xFFFE, michael@0: "pnnRecordId": 4 michael@0: }, michael@0: { michael@0: "mcc": 321, michael@0: "mnc": 654, michael@0: "lacTacStart": 0, michael@0: "lacTacEnd": 0x0010, michael@0: "pnnRecordId": 3 michael@0: }, michael@0: { michael@0: "mcc": 321, michael@0: "mnc": 654, michael@0: "lacTacStart": 0x0100, michael@0: "lacTacEnd": 0x1010, michael@0: "pnnRecordId": 2 michael@0: } michael@0: ]; michael@0: michael@0: // Both EF_PNN and EF_OPL are presented, and current PLMN is HPLMN, michael@0: testGetNetworkNameFromICC({mcc: 123, mnc: 456, lac: 0x1000}, michael@0: {longName: "PNN4Long", shortName: "PNN4Short"}); michael@0: michael@0: // Current PLMN is not HPLMN, and according to LAC, we should get michael@0: // the second PNN record. michael@0: testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x1000}, michael@0: {longName: "PNN2Long", shortName: "PNN2Short"}); michael@0: michael@0: // Current PLMN is not HPLMN, and according to LAC, we should get michael@0: // the thrid PNN record. michael@0: testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x0001}, michael@0: {longName: "PNN3Long", shortName: "PNN3Short"}); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function test_path_id_for_spid_and_spn() { michael@0: let worker = newWorker({ michael@0: postRILMessage: function(data) { michael@0: // Do nothing michael@0: }, michael@0: postMessage: function(message) { michael@0: // Do nothing michael@0: }}); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let RIL = context.RIL; michael@0: let ICCFileHelper = context.ICCFileHelper; michael@0: michael@0: // Test SIM michael@0: RIL.appType = CARD_APPTYPE_SIM; michael@0: do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPDI), michael@0: EF_PATH_MF_SIM + EF_PATH_DF_GSM); michael@0: do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPN), michael@0: EF_PATH_MF_SIM + EF_PATH_DF_GSM); michael@0: michael@0: // Test USIM michael@0: RIL.appType = CARD_APPTYPE_USIM; michael@0: do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPDI), michael@0: EF_PATH_MF_SIM + EF_PATH_ADF_USIM); michael@0: do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPDI), michael@0: EF_PATH_MF_SIM + EF_PATH_ADF_USIM); michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCUtilsHelper.parsePbrTlvs michael@0: */ michael@0: add_test(function test_parse_pbr_tlvs() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let buf = context.Buf; michael@0: michael@0: let pbrTlvs = [ michael@0: {tag: ICC_USIM_TYPE1_TAG, michael@0: length: 0x0F, michael@0: value: [{tag: ICC_USIM_EFADN_TAG, michael@0: length: 0x03, michael@0: value: [0x4F, 0x3A, 0x02]}, michael@0: {tag: ICC_USIM_EFIAP_TAG, michael@0: length: 0x03, michael@0: value: [0x4F, 0x25, 0x01]}, michael@0: {tag: ICC_USIM_EFPBC_TAG, michael@0: length: 0x03, michael@0: value: [0x4F, 0x09, 0x04]}] michael@0: }, michael@0: {tag: ICC_USIM_TYPE2_TAG, michael@0: length: 0x05, michael@0: value: [{tag: ICC_USIM_EFEMAIL_TAG, michael@0: length: 0x03, michael@0: value: [0x4F, 0x50, 0x0B]}, michael@0: {tag: ICC_USIM_EFANR_TAG, michael@0: length: 0x03, michael@0: value: [0x4F, 0x11, 0x02]}, michael@0: {tag: ICC_USIM_EFANR_TAG, michael@0: length: 0x03, michael@0: value: [0x4F, 0x12, 0x03]}] michael@0: }, michael@0: {tag: ICC_USIM_TYPE3_TAG, michael@0: length: 0x0A, michael@0: value: [{tag: ICC_USIM_EFCCP1_TAG, michael@0: length: 0x03, michael@0: value: [0x4F, 0x3D, 0x0A]}, michael@0: {tag: ICC_USIM_EFEXT1_TAG, michael@0: length: 0x03, michael@0: value: [0x4F, 0x4A, 0x03]}] michael@0: }, michael@0: ]; michael@0: michael@0: let pbr = context.ICCUtilsHelper.parsePbrTlvs(pbrTlvs); michael@0: do_check_eq(pbr.adn.fileId, 0x4F3a); michael@0: do_check_eq(pbr.iap.fileId, 0x4F25); michael@0: do_check_eq(pbr.pbc.fileId, 0x4F09); michael@0: do_check_eq(pbr.email.fileId, 0x4F50); michael@0: do_check_eq(pbr.anr0.fileId, 0x4f11); michael@0: do_check_eq(pbr.anr1.fileId, 0x4f12); michael@0: do_check_eq(pbr.ccp1.fileId, 0x4F3D); michael@0: do_check_eq(pbr.ext1.fileId, 0x4F4A); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCIOHelper.loadLinearFixedEF with recordSize. michael@0: */ michael@0: add_test(function test_load_linear_fixed_ef() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ril = context.RIL; michael@0: let io = context.ICCIOHelper; michael@0: michael@0: io.getResponse = function fakeGetResponse(options) { michael@0: // When recordSize is provided, loadLinearFixedEF should call iccIO directly. michael@0: do_check_true(false); michael@0: run_next_test(); michael@0: }; michael@0: michael@0: ril.iccIO = function fakeIccIO(options) { michael@0: do_check_true(true); michael@0: run_next_test(); michael@0: }; michael@0: michael@0: io.loadLinearFixedEF({recordSize: 0x20}); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCIOHelper.loadLinearFixedEF without recordSize. michael@0: */ michael@0: add_test(function test_load_linear_fixed_ef() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ril = context.RIL; michael@0: let io = context.ICCIOHelper; michael@0: michael@0: io.getResponse = function fakeGetResponse(options) { michael@0: do_check_true(true); michael@0: run_next_test(); michael@0: }; michael@0: michael@0: ril.iccIO = function fakeIccIO(options) { michael@0: // When recordSize is not provided, loadLinearFixedEF should call getResponse. michael@0: do_check_true(false); michael@0: run_next_test(); michael@0: }; michael@0: michael@0: io.loadLinearFixedEF({}); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCRecordHelper.readPBR michael@0: */ michael@0: add_test(function test_read_pbr() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let record = context.ICCRecordHelper; michael@0: let buf = context.Buf; michael@0: let io = context.ICCIOHelper; michael@0: michael@0: io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { michael@0: let pbr_1 = [ michael@0: 0xa8, 0x05, 0xc0, 0x03, 0x4f, 0x3a, 0x01 michael@0: ]; michael@0: michael@0: // Write data size michael@0: buf.writeInt32(pbr_1.length * 2); michael@0: michael@0: // Write pbr michael@0: for (let i = 0; i < pbr_1.length; i++) { michael@0: helper.writeHexOctet(pbr_1[i]); michael@0: } michael@0: michael@0: // Write string delimiter michael@0: buf.writeStringDelimiter(pbr_1.length * 2); michael@0: michael@0: options.totalRecords = 2; michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: }; michael@0: michael@0: io.loadNextRecord = function fakeLoadNextRecord(options) { michael@0: let pbr_2 = [ michael@0: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff michael@0: ]; michael@0: michael@0: options.p1++; michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: }; michael@0: michael@0: let successCb = function successCb(pbrs) { michael@0: do_check_eq(pbrs[0].adn.fileId, 0x4f3a); michael@0: do_check_eq(pbrs.length, 1); michael@0: }; michael@0: michael@0: let errorCb = function errorCb(errorMsg) { michael@0: do_print("Reading EF_PBR failed, msg = " + errorMsg); michael@0: do_check_true(false); michael@0: }; michael@0: michael@0: record.readPBR(successCb, errorCb); michael@0: michael@0: // Check cache pbrs when 2nd call michael@0: let ifLoadEF = false; michael@0: io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { michael@0: ifLoadEF = true; michael@0: } michael@0: record.readPBR(successCb, errorCb); michael@0: do_check_false(ifLoadEF); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCRecordHelper.readEmail michael@0: */ michael@0: add_test(function test_read_email() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let record = context.ICCRecordHelper; michael@0: let buf = context.Buf; michael@0: let io = context.ICCIOHelper; michael@0: let recordSize; michael@0: michael@0: io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { michael@0: let email_1 = [ michael@0: 0x65, 0x6D, 0x61, 0x69, 0x6C, michael@0: 0x00, 0x6D, 0x6F, 0x7A, 0x69, michael@0: 0x6C, 0x6C, 0x61, 0x2E, 0x63, michael@0: 0x6F, 0x6D, 0x02, 0x23]; michael@0: michael@0: // Write data size michael@0: buf.writeInt32(email_1.length * 2); michael@0: michael@0: // Write email michael@0: for (let i = 0; i < email_1.length; i++) { michael@0: helper.writeHexOctet(email_1[i]); michael@0: } michael@0: michael@0: // Write string delimiter michael@0: buf.writeStringDelimiter(email_1.length * 2); michael@0: michael@0: recordSize = email_1.length; michael@0: options.recordSize = recordSize; michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: }; michael@0: michael@0: function doTestReadEmail(type, expectedResult) { michael@0: let fileId = 0x6a75; michael@0: let recordNumber = 1; michael@0: michael@0: // fileId and recordNumber are dummy arguments. michael@0: record.readEmail(fileId, type, recordNumber, function(email) { michael@0: do_check_eq(email, expectedResult); michael@0: }); michael@0: }; michael@0: michael@0: doTestReadEmail(ICC_USIM_TYPE1_TAG, "email@mozilla.com$#"); michael@0: doTestReadEmail(ICC_USIM_TYPE2_TAG, "email@mozilla.com"); michael@0: do_check_eq(record._emailRecordSize, recordSize); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCRecordHelper.updateEmail michael@0: */ michael@0: add_test(function test_update_email() { michael@0: const recordSize = 0x20; michael@0: const recordNumber = 1; michael@0: const fileId = 0x4f50; michael@0: const NUM_TESTS = 2; michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let pduHelper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: let ril = context.RIL; michael@0: ril.appType = CARD_APPTYPE_USIM; michael@0: let recordHelper = context.ICCRecordHelper; michael@0: let buf = context.Buf; michael@0: let ioHelper = context.ICCIOHelper; michael@0: let pbr = {email: {fileId: fileId, fileType: ICC_USIM_TYPE1_TAG}, michael@0: adn: {sfi: 1}}; michael@0: let count = 0; michael@0: michael@0: // Override. michael@0: ioHelper.updateLinearFixedEF = function(options) { michael@0: options.pathId = context.ICCFileHelper.getEFPath(options.fileId); michael@0: options.command = ICC_COMMAND_UPDATE_RECORD; michael@0: options.p1 = options.recordNumber; michael@0: options.p2 = READ_RECORD_ABSOLUTE_MODE; michael@0: options.p3 = recordSize; michael@0: ril.iccIO(options); michael@0: }; michael@0: michael@0: function do_test(pbr, expectedEmail, expectedAdnRecordId) { michael@0: buf.sendParcel = function() { michael@0: count++; michael@0: michael@0: // Request Type. michael@0: do_check_eq(this.readInt32(), REQUEST_SIM_IO); michael@0: michael@0: // Token : we don't care michael@0: this.readInt32(); michael@0: michael@0: // command. michael@0: do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); michael@0: michael@0: // fileId. michael@0: do_check_eq(this.readInt32(), fileId); michael@0: michael@0: // pathId. michael@0: do_check_eq(this.readString(), michael@0: EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); michael@0: michael@0: // p1. michael@0: do_check_eq(this.readInt32(), recordNumber); michael@0: michael@0: // p2. michael@0: do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); michael@0: michael@0: // p3. michael@0: do_check_eq(this.readInt32(), recordSize); michael@0: michael@0: // data. michael@0: let strLen = this.readInt32(); michael@0: let email; michael@0: if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) { michael@0: email = iccHelper.read8BitUnpackedToString(recordSize); michael@0: } else { michael@0: email = iccHelper.read8BitUnpackedToString(recordSize - 2); michael@0: do_check_eq(pduHelper.readHexOctet(), pbr.adn.sfi); michael@0: do_check_eq(pduHelper.readHexOctet(), expectedAdnRecordId); michael@0: } michael@0: this.readStringDelimiter(strLen); michael@0: do_check_eq(email, expectedEmail); michael@0: michael@0: // pin2. michael@0: do_check_eq(this.readString(), null); michael@0: michael@0: if (!ril.v5Legacy) { michael@0: // AID. Ignore because it's from modem. michael@0: this.readInt32(); michael@0: } michael@0: michael@0: if (count == NUM_TESTS) { michael@0: run_next_test(); michael@0: } michael@0: }; michael@0: recordHelper.updateEmail(pbr, recordNumber, expectedEmail, expectedAdnRecordId); michael@0: } michael@0: michael@0: do_test(pbr, "test@mail.com"); michael@0: pbr.email.fileType = ICC_USIM_TYPE2_TAG; michael@0: do_test(pbr, "test@mail.com", 1); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCRecordHelper.readANR michael@0: */ michael@0: add_test(function test_read_anr() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let record = context.ICCRecordHelper; michael@0: let buf = context.Buf; michael@0: let io = context.ICCIOHelper; michael@0: let recordSize; michael@0: michael@0: io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { michael@0: let anr_1 = [ michael@0: 0x01, 0x05, 0x81, 0x10, 0x32, michael@0: 0x54, 0xF6, 0xFF, 0xFF]; michael@0: michael@0: // Write data size michael@0: buf.writeInt32(anr_1.length * 2); michael@0: michael@0: // Write anr michael@0: for (let i = 0; i < anr_1.length; i++) { michael@0: helper.writeHexOctet(anr_1[i]); michael@0: } michael@0: michael@0: // Write string delimiter michael@0: buf.writeStringDelimiter(anr_1.length * 2); michael@0: michael@0: recordSize = anr_1.length; michael@0: options.recordSize = recordSize; michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: }; michael@0: michael@0: function doTestReadAnr(fileType, expectedResult) { michael@0: let fileId = 0x4f11; michael@0: let recordNumber = 1; michael@0: michael@0: // fileId and recordNumber are dummy arguments. michael@0: record.readANR(fileId, fileType, recordNumber, function(anr) { michael@0: do_check_eq(anr, expectedResult); michael@0: }); michael@0: }; michael@0: michael@0: doTestReadAnr(ICC_USIM_TYPE1_TAG, "0123456"); michael@0: do_check_eq(record._anrRecordSize, recordSize); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCRecordHelper.updateANR michael@0: */ michael@0: add_test(function test_update_anr() { michael@0: const recordSize = 0x20; michael@0: const recordNumber = 1; michael@0: const fileId = 0x4f11; michael@0: const NUM_TESTS = 2; michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let pduHelper = context.GsmPDUHelper; michael@0: let iccHelper = context.ICCPDUHelper; michael@0: let ril = context.RIL; michael@0: ril.appType = CARD_APPTYPE_USIM; michael@0: let recordHelper = context.ICCRecordHelper; michael@0: let buf = context.Buf; michael@0: let ioHelper = context.ICCIOHelper; michael@0: let pbr = {anr0: {fileId: fileId, fileType: ICC_USIM_TYPE1_TAG}, michael@0: adn: {sfi: 1}}; michael@0: let count = 0; michael@0: michael@0: // Override. michael@0: ioHelper.updateLinearFixedEF = function(options) { michael@0: options.pathId = context.ICCFileHelper.getEFPath(options.fileId); michael@0: options.command = ICC_COMMAND_UPDATE_RECORD; michael@0: options.p1 = options.recordNumber; michael@0: options.p2 = READ_RECORD_ABSOLUTE_MODE; michael@0: options.p3 = recordSize; michael@0: ril.iccIO(options); michael@0: }; michael@0: michael@0: function do_test(pbr, expectedANR, expectedAdnRecordId) { michael@0: buf.sendParcel = function() { michael@0: count++; michael@0: michael@0: // Request Type. michael@0: do_check_eq(this.readInt32(), REQUEST_SIM_IO); michael@0: michael@0: // Token : we don't care michael@0: this.readInt32(); michael@0: michael@0: // command. michael@0: do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); michael@0: michael@0: // fileId. michael@0: do_check_eq(this.readInt32(), fileId); michael@0: michael@0: // pathId. michael@0: do_check_eq(this.readString(), michael@0: EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); michael@0: michael@0: // p1. michael@0: do_check_eq(this.readInt32(), recordNumber); michael@0: michael@0: // p2. michael@0: do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); michael@0: michael@0: // p3. michael@0: do_check_eq(this.readInt32(), recordSize); michael@0: michael@0: // data. michael@0: let strLen = this.readInt32(); michael@0: // EF_AAS, ignore. michael@0: pduHelper.readHexOctet(); michael@0: do_check_eq(iccHelper.readNumberWithLength(), expectedANR); michael@0: // EF_CCP, ignore. michael@0: pduHelper.readHexOctet(); michael@0: // EF_EXT1, ignore. michael@0: pduHelper.readHexOctet(); michael@0: if (pbr.anr0.fileType === ICC_USIM_TYPE2_TAG) { michael@0: do_check_eq(pduHelper.readHexOctet(), pbr.adn.sfi); michael@0: do_check_eq(pduHelper.readHexOctet(), expectedAdnRecordId); michael@0: } michael@0: this.readStringDelimiter(strLen); michael@0: michael@0: // pin2. michael@0: do_check_eq(this.readString(), null); michael@0: michael@0: if (!ril.v5Legacy) { michael@0: // AID. Ignore because it's from modem. michael@0: this.readInt32(); michael@0: } michael@0: michael@0: if (count == NUM_TESTS) { michael@0: run_next_test(); michael@0: } michael@0: }; michael@0: recordHelper.updateANR(pbr, recordNumber, expectedANR, expectedAdnRecordId); michael@0: } michael@0: michael@0: do_test(pbr, "+123456789"); michael@0: pbr.anr0.fileType = ICC_USIM_TYPE2_TAG; michael@0: do_test(pbr, "123456789", 1); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCRecordHelper.readIAP michael@0: */ michael@0: add_test(function test_read_iap() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let record = context.ICCRecordHelper; michael@0: let buf = context.Buf; michael@0: let io = context.ICCIOHelper; michael@0: let recordSize; michael@0: michael@0: io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { michael@0: let iap_1 = [0x01, 0x02]; michael@0: michael@0: // Write data size/ michael@0: buf.writeInt32(iap_1.length * 2); michael@0: michael@0: // Write iap. michael@0: for (let i = 0; i < iap_1.length; i++) { michael@0: helper.writeHexOctet(iap_1[i]); michael@0: } michael@0: michael@0: // Write string delimiter. michael@0: buf.writeStringDelimiter(iap_1.length * 2); michael@0: michael@0: recordSize = iap_1.length; michael@0: options.recordSize = recordSize; michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: }; michael@0: michael@0: function doTestReadIAP(expectedIAP) { michael@0: const fileId = 0x4f17; michael@0: const recordNumber = 1; michael@0: michael@0: let successCb = function successCb(iap) { michael@0: for (let i = 0; i < iap.length; i++) { michael@0: do_check_eq(expectedIAP[i], iap[i]); michael@0: } michael@0: run_next_test(); michael@0: }.bind(this); michael@0: michael@0: let errorCb = function errorCb(errorMsg) { michael@0: do_print(errorMsg); michael@0: do_check_true(false); michael@0: run_next_test(); michael@0: }.bind(this); michael@0: michael@0: record.readIAP(fileId, recordNumber, successCb, errorCb); michael@0: }; michael@0: michael@0: doTestReadIAP([1, 2]); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCRecordHelper.updateIAP michael@0: */ michael@0: add_test(function test_update_iap() { michael@0: const recordSize = 2; michael@0: const recordNumber = 1; michael@0: const fileId = 0x4f17; michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let pduHelper = context.GsmPDUHelper; michael@0: let ril = context.RIL; michael@0: ril.appType = CARD_APPTYPE_USIM; michael@0: let recordHelper = context.ICCRecordHelper; michael@0: let buf = context.Buf; michael@0: let ioHelper = context.ICCIOHelper; michael@0: let count = 0; michael@0: michael@0: // Override. michael@0: ioHelper.updateLinearFixedEF = function(options) { michael@0: options.pathId = context.ICCFileHelper.getEFPath(options.fileId); michael@0: options.command = ICC_COMMAND_UPDATE_RECORD; michael@0: options.p1 = options.recordNumber; michael@0: options.p2 = READ_RECORD_ABSOLUTE_MODE; michael@0: options.p3 = recordSize; michael@0: ril.iccIO(options); michael@0: }; michael@0: michael@0: function do_test(expectedIAP) { michael@0: buf.sendParcel = function() { michael@0: // Request Type. michael@0: do_check_eq(this.readInt32(), REQUEST_SIM_IO); michael@0: michael@0: // Token : we don't care michael@0: this.readInt32(); michael@0: michael@0: // command. michael@0: do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); michael@0: michael@0: // fileId. michael@0: do_check_eq(this.readInt32(), fileId); michael@0: michael@0: // pathId. michael@0: do_check_eq(this.readString(), michael@0: EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); michael@0: michael@0: // p1. michael@0: do_check_eq(this.readInt32(), recordNumber); michael@0: michael@0: // p2. michael@0: do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); michael@0: michael@0: // p3. michael@0: do_check_eq(this.readInt32(), recordSize); michael@0: michael@0: // data. michael@0: let strLen = this.readInt32(); michael@0: for (let i = 0; i < recordSize; i++) { michael@0: do_check_eq(expectedIAP[i], pduHelper.readHexOctet()); michael@0: } michael@0: this.readStringDelimiter(strLen); michael@0: michael@0: // pin2. michael@0: do_check_eq(this.readString(), null); michael@0: michael@0: if (!ril.v5Legacy) { michael@0: // AID. Ignore because it's from modem. michael@0: this.readInt32(); michael@0: } michael@0: michael@0: run_next_test(); michael@0: }; michael@0: recordHelper.updateIAP(fileId, recordNumber, expectedIAP); michael@0: } michael@0: michael@0: do_test([1, 2]); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCRecordHelper.updateADNLike. michael@0: */ michael@0: add_test(function test_update_adn_like() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ril = context.RIL; michael@0: let record = context.ICCRecordHelper; michael@0: let io = context.ICCIOHelper; michael@0: let pdu = context.ICCPDUHelper; michael@0: let buf = context.Buf; michael@0: michael@0: ril.appType = CARD_APPTYPE_SIM; michael@0: const recordSize = 0x20; michael@0: let fileId; michael@0: michael@0: // Override. michael@0: io.updateLinearFixedEF = function(options) { michael@0: options.pathId = context.ICCFileHelper.getEFPath(options.fileId); michael@0: options.command = ICC_COMMAND_UPDATE_RECORD; michael@0: options.p1 = options.recordNumber; michael@0: options.p2 = READ_RECORD_ABSOLUTE_MODE; michael@0: options.p3 = recordSize; michael@0: ril.iccIO(options); michael@0: }; michael@0: michael@0: buf.sendParcel = function() { michael@0: // Request Type. michael@0: do_check_eq(this.readInt32(), REQUEST_SIM_IO); michael@0: michael@0: // Token : we don't care michael@0: this.readInt32(); michael@0: michael@0: // command. michael@0: do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); michael@0: michael@0: // fileId. michael@0: do_check_eq(this.readInt32(), fileId); michael@0: michael@0: // pathId. michael@0: do_check_eq(this.readString(), EF_PATH_MF_SIM + EF_PATH_DF_TELECOM); michael@0: michael@0: // p1. michael@0: do_check_eq(this.readInt32(), 1); michael@0: michael@0: // p2. michael@0: do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); michael@0: michael@0: // p3. michael@0: do_check_eq(this.readInt32(), 0x20); michael@0: michael@0: // data. michael@0: let contact = pdu.readAlphaIdDiallingNumber(0x20); michael@0: do_check_eq(contact.alphaId, "test"); michael@0: do_check_eq(contact.number, "123456"); michael@0: michael@0: // pin2. michael@0: if (fileId == ICC_EF_ADN) { michael@0: do_check_eq(this.readString(), null); michael@0: } else { michael@0: do_check_eq(this.readString(), "1111"); michael@0: } michael@0: michael@0: if (!ril.v5Legacy) { michael@0: // AID. Ignore because it's from modem. michael@0: this.readInt32(); michael@0: } michael@0: michael@0: if (fileId == ICC_EF_FDN) { michael@0: run_next_test(); michael@0: } michael@0: }; michael@0: michael@0: fileId = ICC_EF_ADN; michael@0: record.updateADNLike(fileId, michael@0: {recordId: 1, alphaId: "test", number: "123456"}); michael@0: michael@0: fileId = ICC_EF_FDN; michael@0: record.updateADNLike(fileId, michael@0: {recordId: 1, alphaId: "test", number: "123456"}, michael@0: "1111"); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCRecordHelper.findFreeRecordId. michael@0: */ michael@0: add_test(function test_find_free_record_id() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let pduHelper = context.GsmPDUHelper; michael@0: let recordHelper = context.ICCRecordHelper; michael@0: let buf = context.Buf; michael@0: let io = context.ICCIOHelper; michael@0: michael@0: function writeRecord (record) { michael@0: // Write data size michael@0: buf.writeInt32(record.length * 2); michael@0: michael@0: for (let i = 0; i < record.length; i++) { michael@0: pduHelper.writeHexOctet(record[i]); michael@0: } michael@0: michael@0: // Write string delimiter michael@0: buf.writeStringDelimiter(record.length * 2); michael@0: } michael@0: michael@0: io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { michael@0: // Some random data. michael@0: let record = [0x12, 0x34, 0x56, 0x78, 0x90]; michael@0: options.p1 = 1; michael@0: options.totalRecords = 2; michael@0: writeRecord(record); michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: }; michael@0: michael@0: io.loadNextRecord = function fakeLoadNextRecord(options) { michael@0: // Unused bytes. michael@0: let record = [0xff, 0xff, 0xff, 0xff, 0xff]; michael@0: options.p1++; michael@0: writeRecord(record); michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: }; michael@0: michael@0: let fileId = 0x0000; // Dummy. michael@0: recordHelper.findFreeRecordId( michael@0: fileId, michael@0: function(recordId) { michael@0: do_check_eq(recordId, 2); michael@0: run_next_test(); michael@0: }.bind(this), michael@0: function(errorMsg) { michael@0: do_print(errorMsg); michael@0: do_check_true(false); michael@0: run_next_test(); michael@0: }.bind(this)); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCContactHelper.readICCContacts michael@0: */ michael@0: add_test(function test_read_icc_contacts() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let record = context.ICCRecordHelper; michael@0: let contactHelper = context.ICCContactHelper; michael@0: let ril = context.RIL; michael@0: michael@0: function do_test(aSimType, aContactType, aExpectedContact, aEnhancedPhoneBook) { michael@0: ril.appType = aSimType; michael@0: ril._isCdma = (aSimType === CARD_APPTYPE_RUIM); michael@0: ril.iccInfoPrivate.cst = (aEnhancedPhoneBook) ? michael@0: [0x0, 0x0C, 0x0, 0x0, 0x0]: michael@0: [0x0, 0x00, 0x0, 0x0, 0x0]; michael@0: michael@0: // Override some functions to test. michael@0: contactHelper.getContactFieldRecordId = function(pbr, contact, field, onsuccess, onerror) { michael@0: onsuccess(1); michael@0: }; michael@0: michael@0: record.readPBR = function readPBR(onsuccess, onerror) { michael@0: onsuccess([{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}]); michael@0: }; michael@0: michael@0: record.readADNLike = function readADNLike(fileId, onsuccess, onerror) { michael@0: onsuccess([{recordId: 1, alphaId: "name", number: "111111"}]) michael@0: }; michael@0: michael@0: record.readEmail = function readEmail(fileId, fileType, recordNumber, onsuccess, onerror) { michael@0: onsuccess("hello@mail.com"); michael@0: }; michael@0: michael@0: record.readANR = function readANR(fileId, fileType, recordNumber, onsuccess, onerror) { michael@0: onsuccess("123456"); michael@0: }; michael@0: michael@0: let onsuccess = function onsuccess(contacts) { michael@0: let contact = contacts[0]; michael@0: for (let key in contact) { michael@0: do_print("check " + key); michael@0: if (Array.isArray(contact[key])) { michael@0: do_check_eq(contact[key][0], aExpectedContact[key]); michael@0: } else { michael@0: do_check_eq(contact[key], aExpectedContact[key]); michael@0: } michael@0: } michael@0: }; michael@0: michael@0: let onerror = function onerror(errorMsg) { michael@0: do_print("readICCContacts failed: " + errorMsg); michael@0: do_check_true(false); michael@0: }; michael@0: michael@0: contactHelper.readICCContacts(aSimType, aContactType, onsuccess, onerror); michael@0: } michael@0: michael@0: let expectedContact1 = { michael@0: pbrIndex: 0, michael@0: recordId: 1, michael@0: alphaId: "name", michael@0: number: "111111" michael@0: }; michael@0: michael@0: let expectedContact2 = { michael@0: pbrIndex: 0, michael@0: recordId: 1, michael@0: alphaId: "name", michael@0: number: "111111", michael@0: email: "hello@mail.com", michael@0: anr: "123456" michael@0: }; michael@0: michael@0: // SIM michael@0: do_print("Test read SIM adn contacts"); michael@0: do_test(CARD_APPTYPE_SIM, "adn", expectedContact1); michael@0: michael@0: do_print("Test read SIM fdn contacts"); michael@0: do_test(CARD_APPTYPE_SIM, "fdn", expectedContact1); michael@0: michael@0: // USIM michael@0: do_print("Test read USIM adn contacts"); michael@0: do_test(CARD_APPTYPE_USIM, "adn", expectedContact2); michael@0: michael@0: do_print("Test read USIM fdn contacts"); michael@0: do_test(CARD_APPTYPE_USIM, "fdn", expectedContact1); michael@0: michael@0: // RUIM michael@0: do_print("Test read RUIM adn contacts"); michael@0: do_test(CARD_APPTYPE_RUIM, "adn", expectedContact1); michael@0: michael@0: do_print("Test read RUIM fdn contacts"); michael@0: do_test(CARD_APPTYPE_RUIM, "fdn", expectedContact1); michael@0: michael@0: // RUIM with enhanced phone book michael@0: do_print("Test read RUIM adn contacts with enhanced phone book"); michael@0: do_test(CARD_APPTYPE_RUIM, "adn", expectedContact2, true); michael@0: michael@0: do_print("Test read RUIM fdn contacts with enhanced phone book"); michael@0: do_test(CARD_APPTYPE_RUIM, "fdn", expectedContact1, true); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCContactHelper.updateICCContact with appType is CARD_APPTYPE_USIM. michael@0: */ michael@0: add_test(function test_update_icc_contact() { michael@0: const ADN_RECORD_ID = 100; michael@0: const ADN_SFI = 1; michael@0: const IAP_FILE_ID = 0x4f17; michael@0: const EMAIL_FILE_ID = 0x4f50; michael@0: const EMAIL_RECORD_ID = 20; michael@0: const ANR0_FILE_ID = 0x4f11; michael@0: const ANR0_RECORD_ID = 30; michael@0: michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let recordHelper = context.ICCRecordHelper; michael@0: let contactHelper = context.ICCContactHelper; michael@0: let ril = context.RIL; michael@0: michael@0: function do_test(aSimType, aContactType, aContact, aPin2, aFileType, aHaveIapIndex, aEnhancedPhoneBook) { michael@0: ril.appType = aSimType; michael@0: ril._isCdma = (aSimType === CARD_APPTYPE_RUIM); michael@0: ril.iccInfoPrivate.cst = (aEnhancedPhoneBook) ? [0x0, 0x0C, 0x0, 0x0, 0x0] michael@0: : [0x0, 0x00, 0x0, 0x0, 0x0]; michael@0: michael@0: recordHelper.readPBR = function(onsuccess, onerror) { michael@0: if (aFileType === ICC_USIM_TYPE1_TAG) { michael@0: onsuccess([{ michael@0: adn: {fileId: ICC_EF_ADN}, michael@0: email: {fileId: EMAIL_FILE_ID, michael@0: fileType: ICC_USIM_TYPE1_TAG}, michael@0: anr0: {fileId: ANR0_FILE_ID, michael@0: fileType: ICC_USIM_TYPE1_TAG} michael@0: }]); michael@0: } else if (aFileType === ICC_USIM_TYPE2_TAG) { michael@0: onsuccess([{ michael@0: adn: {fileId: ICC_EF_ADN, michael@0: sfi: ADN_SFI}, michael@0: iap: {fileId: IAP_FILE_ID}, michael@0: email: {fileId: EMAIL_FILE_ID, michael@0: fileType: ICC_USIM_TYPE2_TAG, michael@0: indexInIAP: 0}, michael@0: anr0: {fileId: ANR0_FILE_ID, michael@0: fileType: ICC_USIM_TYPE2_TAG, michael@0: indexInIAP: 1} michael@0: }]); michael@0: } michael@0: }; michael@0: michael@0: recordHelper.updateADNLike = function(fileId, contact, pin2, onsuccess, onerror) { michael@0: if (aContactType === "fdn") { michael@0: do_check_eq(fileId, ICC_EF_FDN); michael@0: } else if (aContactType === "adn") { michael@0: do_check_eq(fileId, ICC_EF_ADN); michael@0: } michael@0: do_check_eq(pin2, aPin2); michael@0: do_check_eq(contact.alphaId, aContact.alphaId); michael@0: do_check_eq(contact.number, aContact.number); michael@0: onsuccess(); michael@0: }; michael@0: michael@0: recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) { michael@0: do_check_eq(fileId, IAP_FILE_ID); michael@0: do_check_eq(recordNumber, ADN_RECORD_ID); michael@0: onsuccess((aHaveIapIndex) ? [EMAIL_RECORD_ID, ANR0_RECORD_ID] michael@0: : [0xff, 0xff]); michael@0: }; michael@0: michael@0: recordHelper.updateIAP = function(fileId, recordNumber, iap, onsuccess, onerror) { michael@0: do_check_eq(fileId, IAP_FILE_ID); michael@0: do_check_eq(recordNumber, ADN_RECORD_ID); michael@0: onsuccess(); michael@0: }; michael@0: michael@0: recordHelper.updateEmail = function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) { michael@0: do_check_eq(pbr.email.fileId, EMAIL_FILE_ID); michael@0: if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) { michael@0: do_check_eq(recordNumber, ADN_RECORD_ID); michael@0: } else if (pbr.email.fileType === ICC_USIM_TYPE2_TAG) { michael@0: do_check_eq(recordNumber, EMAIL_RECORD_ID); michael@0: } michael@0: do_check_eq(email, aContact.email); michael@0: onsuccess(); michael@0: }; michael@0: michael@0: recordHelper.updateANR = function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) { michael@0: do_check_eq(pbr.anr0.fileId, ANR0_FILE_ID); michael@0: if (pbr.anr0.fileType === ICC_USIM_TYPE1_TAG) { michael@0: do_check_eq(recordNumber, ADN_RECORD_ID); michael@0: } else if (pbr.anr0.fileType === ICC_USIM_TYPE2_TAG) { michael@0: do_check_eq(recordNumber, ANR0_RECORD_ID); michael@0: } michael@0: if (Array.isArray(aContact.anr)) { michael@0: do_check_eq(number, aContact.anr[0]); michael@0: } michael@0: onsuccess(); michael@0: }; michael@0: michael@0: recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { michael@0: let recordId = 0; michael@0: if (fileId === EMAIL_FILE_ID) { michael@0: recordId = EMAIL_RECORD_ID; michael@0: } else if (fileId === ANR0_FILE_ID) { michael@0: recordId = ANR0_RECORD_ID; michael@0: } michael@0: onsuccess(recordId); michael@0: }; michael@0: michael@0: let isSuccess = false; michael@0: let onsuccess = function onsuccess() { michael@0: do_print("updateICCContact success"); michael@0: isSuccess = true; michael@0: }; michael@0: michael@0: let onerror = function onerror(errorMsg) { michael@0: do_print("updateICCContact failed: " + errorMsg); michael@0: }; michael@0: michael@0: contactHelper.updateICCContact(aSimType, aContactType, aContact, aPin2, onsuccess, onerror); michael@0: do_check_true(isSuccess); michael@0: } michael@0: michael@0: let contacts = [ michael@0: { michael@0: pbrIndex: 0, michael@0: recordId: ADN_RECORD_ID, michael@0: alphaId: "test", michael@0: number: "123456", michael@0: email: "test@mail.com", michael@0: anr: ["+654321"] michael@0: }, michael@0: // a contact without email and anr. michael@0: { michael@0: pbrIndex: 0, michael@0: recordId: ADN_RECORD_ID, michael@0: alphaId: "test2", michael@0: number: "123456", michael@0: }, michael@0: // a contact with email but no anr. michael@0: { michael@0: pbrIndex: 0, michael@0: recordId: ADN_RECORD_ID, michael@0: alphaId: "test3", michael@0: number: "123456", michael@0: email: "test@mail.com" michael@0: }, michael@0: // a contact with anr but no email. michael@0: { michael@0: pbrIndex: 0, michael@0: recordId: ADN_RECORD_ID, michael@0: alphaId: "test4", michael@0: number: "123456", michael@0: anr: ["+654321"] michael@0: }]; michael@0: michael@0: for (let i = 0; i < contacts.length; i++) { michael@0: let contact = contacts[i]; michael@0: // SIM michael@0: do_print("Test update SIM adn contacts"); michael@0: do_test(CARD_APPTYPE_SIM, "adn", contact); michael@0: michael@0: do_print("Test update SIM fdn contacts"); michael@0: do_test(CARD_APPTYPE_SIM, "fdn", contact, "1234"); michael@0: michael@0: // USIM michael@0: do_print("Test update USIM adn contacts"); michael@0: do_test(CARD_APPTYPE_USIM, "adn", contact, null, ICC_USIM_TYPE1_TAG); michael@0: do_test(CARD_APPTYPE_USIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, true); michael@0: do_test(CARD_APPTYPE_USIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, false); michael@0: michael@0: do_print("Test update USIM fdn contacts"); michael@0: do_test(CARD_APPTYPE_USIM, "fdn", contact, "1234"); michael@0: michael@0: // RUIM michael@0: do_print("Test update RUIM adn contacts"); michael@0: do_test(CARD_APPTYPE_RUIM, "adn", contact); michael@0: michael@0: do_print("Test update RUIM fdn contacts"); michael@0: do_test(CARD_APPTYPE_RUIM, "fdn", contact, "1234"); michael@0: michael@0: // RUIM with enhanced phone book michael@0: do_print("Test update RUIM adn contacts with enhanced phone book"); michael@0: do_test(CARD_APPTYPE_RUIM, "adn", contact, null, ICC_USIM_TYPE1_TAG, null, true); michael@0: do_test(CARD_APPTYPE_RUIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, true, true); michael@0: do_test(CARD_APPTYPE_RUIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, false, true); michael@0: michael@0: do_print("Test update RUIM fdn contacts with enhanced phone book"); michael@0: do_test(CARD_APPTYPE_RUIM, "fdn", contact, "1234", null, true); michael@0: } michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify updateICCContact with removal of anr and email with File Type 1. michael@0: */ michael@0: add_test(function test_update_icc_contact_with_remove_type1_attr() { michael@0: const ADN_RECORD_ID = 100; michael@0: const IAP_FILE_ID = 0x4f17; michael@0: const EMAIL_FILE_ID = 0x4f50; michael@0: const EMAIL_RECORD_ID = 20; michael@0: const ANR0_FILE_ID = 0x4f11; michael@0: const ANR0_RECORD_ID = 30; michael@0: michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let recordHelper = context.ICCRecordHelper; michael@0: let contactHelper = context.ICCContactHelper; michael@0: michael@0: recordHelper.updateADNLike = function(fileId, contact, pin2, onsuccess, onerror) { michael@0: onsuccess(); michael@0: }; michael@0: michael@0: let contact = { michael@0: pbrIndex: 0, michael@0: recordId: ADN_RECORD_ID, michael@0: alphaId: "test2", michael@0: number: "123456", michael@0: }; michael@0: michael@0: recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) { michael@0: onsuccess([EMAIL_RECORD_ID, ANR0_RECORD_ID]); michael@0: }; michael@0: michael@0: recordHelper.updateEmail = function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) { michael@0: do_check_true(email == null); michael@0: onsuccess(); michael@0: }; michael@0: michael@0: recordHelper.updateANR = function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) { michael@0: do_check_true(number == null); michael@0: onsuccess(); michael@0: }; michael@0: michael@0: function do_test(type) { michael@0: recordHelper.readPBR = function(onsuccess, onerror) { michael@0: if (type == ICC_USIM_TYPE1_TAG) { michael@0: onsuccess([{ michael@0: adn: {fileId: ICC_EF_ADN}, michael@0: email: {fileId: EMAIL_FILE_ID, michael@0: fileType: ICC_USIM_TYPE1_TAG}, michael@0: anr0: {fileId: ANR0_FILE_ID, michael@0: fileType: ICC_USIM_TYPE1_TAG}}]); michael@0: } else { michael@0: onsuccess([{ michael@0: adn: {fileId: ICC_EF_ADN}, michael@0: iap: {fileId: IAP_FILE_ID}, michael@0: email: {fileId: EMAIL_FILE_ID, michael@0: fileType: ICC_USIM_TYPE2_TAG, michael@0: indexInIAP: 0}, michael@0: anr0: {fileId: ANR0_FILE_ID, michael@0: fileType: ICC_USIM_TYPE2_TAG, michael@0: indexInIAP: 1}}]); michael@0: } michael@0: }; michael@0: michael@0: let successCb = function() { michael@0: do_check_true(true); michael@0: }; michael@0: michael@0: let errorCb = function(errorMsg) { michael@0: do_print(errorMsg); michael@0: do_check_true(false); michael@0: }; michael@0: michael@0: contactHelper.updateICCContact(CARD_APPTYPE_USIM, "adn", contact, null, successCb, errorCb); michael@0: } michael@0: michael@0: do_test(ICC_USIM_TYPE1_TAG); michael@0: do_test(ICC_USIM_TYPE2_TAG); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCContactHelper.findFreeICCContact in SIM michael@0: */ michael@0: add_test(function test_find_free_icc_contact_sim() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let recordHelper = context.ICCRecordHelper; michael@0: let contactHelper = context.ICCContactHelper; michael@0: // Correct record Id starts with 1, so put a null element at index 0. michael@0: let records = [null]; michael@0: const MAX_RECORDS = 3; michael@0: const PBR_INDEX = 0; michael@0: michael@0: recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { michael@0: if (records.length > MAX_RECORDS) { michael@0: onerror("No free record found."); michael@0: return; michael@0: } michael@0: michael@0: onsuccess(records.length); michael@0: }; michael@0: michael@0: let successCb = function(pbrIndex, recordId) { michael@0: do_check_eq(pbrIndex, PBR_INDEX); michael@0: records[recordId] = {}; michael@0: }; michael@0: michael@0: let errorCb = function(errorMsg) { michael@0: do_print(errorMsg); michael@0: do_check_true(false); michael@0: }; michael@0: michael@0: for (let i = 0; i < MAX_RECORDS; i++) { michael@0: contactHelper.findFreeICCContact(CARD_APPTYPE_SIM, "adn", successCb, errorCb); michael@0: } michael@0: // The 1st element, records[0], is null. michael@0: do_check_eq(records.length - 1, MAX_RECORDS); michael@0: michael@0: // Now the EF is full, so finding a free one should result failure. michael@0: successCb = function(pbrIndex, recordId) { michael@0: do_check_true(false); michael@0: }; michael@0: michael@0: errorCb = function(errorMsg) { michael@0: do_check_true(errorMsg === "No free record found."); michael@0: }; michael@0: contactHelper.findFreeICCContact(CARD_APPTYPE_SIM, "adn", successCb, errorCb); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify ICCContactHelper.findFreeICCContact in USIM michael@0: */ michael@0: add_test(function test_find_free_icc_contact_usim() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let recordHelper = context.ICCRecordHelper; michael@0: let contactHelper = context.ICCContactHelper; michael@0: const ADN1_FILE_ID = 0x6f3a; michael@0: const ADN2_FILE_ID = 0x6f3b; michael@0: const MAX_RECORDS = 3; michael@0: michael@0: // The adn in the first phonebook set has already two records, which means michael@0: // only 1 free record remained. michael@0: let pbrs = [{adn: {fileId: ADN1_FILE_ID, records: [null, {}, {}]}}, michael@0: {adn: {fileId: ADN2_FILE_ID, records: [null]}}]; michael@0: michael@0: recordHelper.readPBR = function readPBR(onsuccess, onerror) { michael@0: onsuccess(pbrs); michael@0: }; michael@0: michael@0: recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { michael@0: let pbr = (fileId == ADN1_FILE_ID ? pbrs[0]: pbrs[1]); michael@0: if (pbr.adn.records.length > MAX_RECORDS) { michael@0: onerror("No free record found."); michael@0: return; michael@0: } michael@0: michael@0: onsuccess(pbr.adn.records.length); michael@0: }; michael@0: michael@0: let successCb = function(pbrIndex, recordId) { michael@0: do_check_eq(pbrIndex, 0); michael@0: pbrs[pbrIndex].adn.records[recordId] = {}; michael@0: }; michael@0: michael@0: let errorCb = function(errorMsg) { michael@0: do_check_true(false); michael@0: }; michael@0: michael@0: contactHelper.findFreeICCContact(CARD_APPTYPE_USIM, "adn", successCb, errorCb); michael@0: michael@0: // Now the EF_ADN in the 1st phonebook set is full, so the next free contact michael@0: // will come from the 2nd phonebook set. michael@0: successCb = function(pbrIndex, recordId) { michael@0: do_check_eq(pbrIndex, 1); michael@0: do_check_eq(recordId, 1); michael@0: } michael@0: contactHelper.findFreeICCContact(CARD_APPTYPE_USIM, "adn", successCb, errorCb); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Test error message returned in onerror for readICCContacts. michael@0: */ michael@0: add_test(function test_error_message_read_icc_contact () { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ril = context.RIL; michael@0: michael@0: function do_test(options, expectedErrorMsg) { michael@0: ril.sendChromeMessage = function(message) { michael@0: do_check_eq(message.errorMsg, expectedErrorMsg); michael@0: } michael@0: ril.readICCContacts(options); michael@0: } michael@0: michael@0: // Error 1, didn't specify correct contactType. michael@0: do_test({}, CONTACT_ERR_REQUEST_NOT_SUPPORTED); michael@0: michael@0: // Error 2, specifying a non-supported contactType. michael@0: ril.appType = CARD_APPTYPE_USIM; michael@0: do_test({contactType: "sdn"}, CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); michael@0: michael@0: // Error 3, suppose we update the supported PBR fields in USIM_PBR_FIELDS, michael@0: // but forget to add implemenetations for it. michael@0: USIM_PBR_FIELDS.push("pbc"); michael@0: do_test({contactType: "adn"}, CONTACT_ERR_FIELD_NOT_SUPPORTED); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Test error message returned in onerror for updateICCContact. michael@0: */ michael@0: add_test(function test_error_message_update_icc_contact() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ril = context.RIL; michael@0: michael@0: const ICCID = "123456789"; michael@0: ril.iccInfo.iccid = ICCID; michael@0: michael@0: function do_test(options, expectedErrorMsg) { michael@0: ril.sendChromeMessage = function(message) { michael@0: do_check_eq(message.errorMsg, expectedErrorMsg); michael@0: } michael@0: ril.updateICCContact(options); michael@0: } michael@0: michael@0: // Error 1, didn't specify correct contactType. michael@0: do_test({}, CONTACT_ERR_REQUEST_NOT_SUPPORTED); michael@0: michael@0: // Error 2, specifying a correct contactType, but without providing 'contact'. michael@0: do_test({contactType: "adn"}, CONTACT_ERR_REQUEST_NOT_SUPPORTED); michael@0: michael@0: // Error 3, specifying a non-supported contactType. michael@0: ril.appType = CARD_APPTYPE_USIM; michael@0: do_test({contactType: "sdn", contact: {}}, CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); michael@0: michael@0: // Error 4, without supplying pin2. michael@0: do_test({contactType: "fdn", contact: {contactId: ICCID + "1"}}, GECKO_ERROR_SIM_PIN2); michael@0: michael@0: // Error 5, No free record found in EF_ADN. michael@0: let record = context.ICCRecordHelper; michael@0: record.readPBR = function(onsuccess, onerror) { michael@0: onsuccess([{adn: {fileId: 0x4f3a}}]); michael@0: }; michael@0: michael@0: let io = context.ICCIOHelper; michael@0: io.loadLinearFixedEF = function(options) { michael@0: options.totalRecords = 1; michael@0: options.p1 = 1; michael@0: options.callback(options); michael@0: }; michael@0: michael@0: do_test({contactType: "adn", contact: {}}, CONTACT_ERR_NO_FREE_RECORD_FOUND); michael@0: michael@0: // Error 6, ICC IO Error. michael@0: io.loadLinearFixedEF = function(options) { michael@0: ril[REQUEST_SIM_IO](0, {rilRequestError: ERROR_GENERIC_FAILURE}); michael@0: }; michael@0: do_test({contactType: "adn", contact: {contactId: ICCID + "1"}}, michael@0: GECKO_ERROR_GENERIC_FAILURE); michael@0: michael@0: // Error 7, suppose we update the supported PBR fields in USIM_PBR_FIELDS, michael@0: // but forget to add implemenetations for it. michael@0: USIM_PBR_FIELDS.push("pbc"); michael@0: do_test({contactType: "adn", contact: {contactId: ICCID + "1"}}, michael@0: CONTACT_ERR_FIELD_NOT_SUPPORTED); michael@0: michael@0: // Error 8, EF_PBR doesn't exist. michael@0: record.readPBR = function(onsuccess, onerror) { michael@0: onsuccess([]); michael@0: }; michael@0: michael@0: do_test({contactType: "adn", contact: {contactId: ICCID + "1"}}, michael@0: CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function test_process_icc_io_error() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ioHelper = context.ICCIOHelper; michael@0: michael@0: function do_test(errorCode, expectedErrorMsg) { michael@0: let called = false; michael@0: function errorCb(errorMsg) { michael@0: called = true; michael@0: do_check_eq(errorMsg, expectedErrorMsg); michael@0: } michael@0: michael@0: ioHelper.processICCIOError({rilRequestError: errorCode, michael@0: fileId: 0xffff, michael@0: command: 0xff, michael@0: sw1: 0xff, michael@0: sw2: 0xff, michael@0: onerror: errorCb}); michael@0: do_check_true(called); michael@0: } michael@0: michael@0: for (let i = 0; i < ERROR_REJECTED_BY_REMOTE + 1; i++) { michael@0: do_test(i, RIL_ERROR_TO_GECKO_ERROR[i]); michael@0: } michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function test_personalization_state() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ril = context.RIL; michael@0: michael@0: context.ICCRecordHelper.readICCID = function fakeReadICCID() {}; michael@0: michael@0: function testPersonalization(isCdma, cardPersoState, geckoCardState) { michael@0: let iccStatus = { michael@0: cardState: CARD_STATE_PRESENT, michael@0: gsmUmtsSubscriptionAppIndex: (!isCdma) ? 0 : -1, michael@0: cdmaSubscriptionAppIndex: (isCdma) ? 0 : -1, michael@0: apps: [ michael@0: { michael@0: app_state: CARD_APPSTATE_SUBSCRIPTION_PERSO, michael@0: perso_substate: cardPersoState michael@0: }], michael@0: }; michael@0: michael@0: ril._isCdma = isCdma; michael@0: ril._processICCStatus(iccStatus); michael@0: do_check_eq(ril.cardState, geckoCardState); michael@0: } michael@0: michael@0: // Test GSM personalization state. michael@0: testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK, michael@0: GECKO_CARDSTATE_NETWORK_LOCKED); michael@0: testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE, michael@0: GECKO_CARDSTATE_CORPORATE_LOCKED); michael@0: testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER, michael@0: GECKO_CARDSTATE_SERVICE_PROVIDER_LOCKED); michael@0: testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_PUK, michael@0: GECKO_CARDSTATE_NETWORK_PUK_REQUIRED); michael@0: testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK, michael@0: GECKO_CARDSTATE_CORPORATE_PUK_REQUIRED); michael@0: testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK, michael@0: GECKO_CARDSTATE_SERVICE_PROVIDER_PUK_REQUIRED); michael@0: testPersonalization(false, CARD_PERSOSUBSTATE_READY, michael@0: GECKO_CARDSTATE_PERSONALIZATION_READY); michael@0: michael@0: // Test CDMA personalization state. michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1, michael@0: GECKO_CARDSTATE_NETWORK1_LOCKED); michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2, michael@0: GECKO_CARDSTATE_NETWORK2_LOCKED); michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD, michael@0: GECKO_CARDSTATE_HRPD_NETWORK_LOCKED); michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE, michael@0: GECKO_CARDSTATE_RUIM_CORPORATE_LOCKED); michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER, michael@0: GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_LOCKED); michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM, michael@0: GECKO_CARDSTATE_RUIM_LOCKED); michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1_PUK, michael@0: GECKO_CARDSTATE_NETWORK1_PUK_REQUIRED); michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2_PUK, michael@0: GECKO_CARDSTATE_NETWORK2_PUK_REQUIRED); michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD_PUK, michael@0: GECKO_CARDSTATE_HRPD_NETWORK_PUK_REQUIRED); michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE_PUK, michael@0: GECKO_CARDSTATE_RUIM_CORPORATE_PUK_REQUIRED); michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK, michael@0: GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED); michael@0: testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM_PUK, michael@0: GECKO_CARDSTATE_RUIM_PUK_REQUIRED); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify SIM app_state in _processICCStatus michael@0: */ michael@0: add_test(function test_card_app_state() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ril = context.RIL; michael@0: michael@0: context.ICCRecordHelper.readICCID = function fakeReadICCID() {}; michael@0: michael@0: function testCardAppState(cardAppState, geckoCardState) { michael@0: let iccStatus = { michael@0: cardState: CARD_STATE_PRESENT, michael@0: gsmUmtsSubscriptionAppIndex: 0, michael@0: apps: [ michael@0: { michael@0: app_state: cardAppState michael@0: }], michael@0: }; michael@0: michael@0: ril._processICCStatus(iccStatus); michael@0: do_check_eq(ril.cardState, geckoCardState); michael@0: } michael@0: michael@0: testCardAppState(CARD_APPSTATE_ILLEGAL, michael@0: GECKO_CARDSTATE_ILLEGAL); michael@0: testCardAppState(CARD_APPSTATE_PIN, michael@0: GECKO_CARDSTATE_PIN_REQUIRED); michael@0: testCardAppState(CARD_APPSTATE_PUK, michael@0: GECKO_CARDSTATE_PUK_REQUIRED); michael@0: testCardAppState(CARD_APPSTATE_READY, michael@0: GECKO_CARDSTATE_READY); michael@0: testCardAppState(CARD_APPSTATE_UNKNOWN, michael@0: GECKO_CARDSTATE_UNKNOWN); michael@0: testCardAppState(CARD_APPSTATE_DETECTED, michael@0: GECKO_CARDSTATE_UNKNOWN); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify permanent blocked for ICC. michael@0: */ michael@0: add_test(function test_icc_permanent_blocked() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ril = context.RIL; michael@0: michael@0: context.ICCRecordHelper.readICCID = function fakeReadICCID() {}; michael@0: michael@0: function testPermanentBlocked(pin1_replaced, universalPINState, pin1) { michael@0: let iccStatus = { michael@0: cardState: CARD_STATE_PRESENT, michael@0: gsmUmtsSubscriptionAppIndex: 0, michael@0: universalPINState: universalPINState, michael@0: apps: [ michael@0: { michael@0: pin1_replaced: pin1_replaced, michael@0: pin1: pin1 michael@0: }] michael@0: }; michael@0: michael@0: ril._processICCStatus(iccStatus); michael@0: do_check_eq(ril.cardState, GECKO_CARDSTATE_PERMANENT_BLOCKED); michael@0: } michael@0: michael@0: testPermanentBlocked(1, michael@0: CARD_PINSTATE_ENABLED_PERM_BLOCKED, michael@0: CARD_PINSTATE_UNKNOWN); michael@0: testPermanentBlocked(1, michael@0: CARD_PINSTATE_ENABLED_PERM_BLOCKED, michael@0: CARD_PINSTATE_ENABLED_PERM_BLOCKED); michael@0: testPermanentBlocked(0, michael@0: CARD_PINSTATE_UNKNOWN, michael@0: CARD_PINSTATE_ENABLED_PERM_BLOCKED); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify iccSetCardLock - Facility Lock. michael@0: */ michael@0: add_test(function test_set_icc_card_lock_facility_lock() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let aid = "123456789"; michael@0: let ril = context.RIL; michael@0: ril.aid = aid; michael@0: ril.v5Legacy = false; michael@0: let buf = context.Buf; michael@0: michael@0: let GECKO_CARDLOCK_TO_FACILITIY_LOCK = {}; michael@0: GECKO_CARDLOCK_TO_FACILITIY_LOCK[GECKO_CARDLOCK_PIN] = ICC_CB_FACILITY_SIM; michael@0: GECKO_CARDLOCK_TO_FACILITIY_LOCK[GECKO_CARDLOCK_FDN] = ICC_CB_FACILITY_FDN; michael@0: michael@0: let GECKO_CARDLOCK_TO_PASSWORD_TYPE = {}; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_PIN] = "pin"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_FDN] = "pin2"; michael@0: michael@0: const pin = "1234"; michael@0: const pin2 = "4321"; michael@0: let GECKO_CARDLOCK_TO_PASSWORD = {}; michael@0: GECKO_CARDLOCK_TO_PASSWORD[GECKO_CARDLOCK_PIN] = pin; michael@0: GECKO_CARDLOCK_TO_PASSWORD[GECKO_CARDLOCK_FDN] = pin2; michael@0: michael@0: const serviceClass = ICC_SERVICE_CLASS_VOICE | michael@0: ICC_SERVICE_CLASS_DATA | michael@0: ICC_SERVICE_CLASS_FAX; michael@0: michael@0: function do_test(aLock, aPassword, aEnabled) { michael@0: buf.sendParcel = function fakeSendParcel () { michael@0: // Request Type. michael@0: do_check_eq(this.readInt32(), REQUEST_SET_FACILITY_LOCK); michael@0: michael@0: // Token : we don't care michael@0: this.readInt32(); michael@0: michael@0: let parcel = this.readStringList(); michael@0: do_check_eq(parcel.length, 5); michael@0: do_check_eq(parcel[0], GECKO_CARDLOCK_TO_FACILITIY_LOCK[aLock]); michael@0: do_check_eq(parcel[1], aEnabled ? "1" : "0"); michael@0: do_check_eq(parcel[2], GECKO_CARDLOCK_TO_PASSWORD[aLock]); michael@0: do_check_eq(parcel[3], serviceClass.toString()); michael@0: do_check_eq(parcel[4], aid); michael@0: }; michael@0: michael@0: let lock = {lockType: aLock, michael@0: enabled: aEnabled}; michael@0: lock[GECKO_CARDLOCK_TO_PASSWORD_TYPE[aLock]] = aPassword; michael@0: michael@0: ril.iccSetCardLock(lock); michael@0: } michael@0: michael@0: do_test(GECKO_CARDLOCK_PIN, pin, true); michael@0: do_test(GECKO_CARDLOCK_PIN, pin, false); michael@0: do_test(GECKO_CARDLOCK_FDN, pin2, true); michael@0: do_test(GECKO_CARDLOCK_FDN, pin2, false); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify iccUnlockCardLock. michael@0: */ michael@0: add_test(function test_unlock_card_lock_corporateLocked() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let ril = context.RIL; michael@0: let buf = context.Buf; michael@0: const pin = "12345678"; michael@0: const puk = "12345678"; michael@0: michael@0: let GECKO_CARDLOCK_TO_PASSWORD_TYPE = {}; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK] = "pin"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK1] = "pin"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK2] = "pin"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_HNCK] = "pin"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_CCK] = "pin"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_SPCK] = "pin"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RCCK] = "pin"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RSPCK] = "pin"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK_PUK] = "puk"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK1_PUK] = "puk"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK2_PUK] = "puk"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_HNCK_PUK] = "puk"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_CCK_PUK] = "puk"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_SPCK_PUK] = "puk"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RCCK_PUK] = "puk"; michael@0: GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RSPCK_PUK] = "puk"; michael@0: michael@0: function do_test(aLock, aPassword) { michael@0: buf.sendParcel = function fakeSendParcel () { michael@0: // Request Type. michael@0: do_check_eq(this.readInt32(), REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE); michael@0: michael@0: // Token : we don't care michael@0: this.readInt32(); michael@0: michael@0: let lockType = GECKO_PERSO_LOCK_TO_CARD_PERSO_LOCK[aLock]; michael@0: // Lock Type michael@0: do_check_eq(this.readInt32(), lockType); michael@0: michael@0: // Pin/Puk. michael@0: do_check_eq(this.readString(), aPassword); michael@0: }; michael@0: michael@0: let lock = {lockType: aLock}; michael@0: lock[GECKO_CARDLOCK_TO_PASSWORD_TYPE[aLock]] = aPassword; michael@0: ril.iccUnlockCardLock(lock); michael@0: } michael@0: michael@0: do_test(GECKO_CARDLOCK_NCK, pin); michael@0: do_test(GECKO_CARDLOCK_NCK1, pin); michael@0: do_test(GECKO_CARDLOCK_NCK2, pin); michael@0: do_test(GECKO_CARDLOCK_HNCK, pin); michael@0: do_test(GECKO_CARDLOCK_CCK, pin); michael@0: do_test(GECKO_CARDLOCK_SPCK, pin); michael@0: do_test(GECKO_CARDLOCK_RCCK, pin); michael@0: do_test(GECKO_CARDLOCK_RSPCK, pin); michael@0: do_test(GECKO_CARDLOCK_NCK_PUK, puk); michael@0: do_test(GECKO_CARDLOCK_NCK1_PUK, puk); michael@0: do_test(GECKO_CARDLOCK_NCK2_PUK, puk); michael@0: do_test(GECKO_CARDLOCK_HNCK_PUK, puk); michael@0: do_test(GECKO_CARDLOCK_CCK_PUK, puk); michael@0: do_test(GECKO_CARDLOCK_SPCK_PUK, puk); michael@0: do_test(GECKO_CARDLOCK_RCCK_PUK, puk); michael@0: do_test(GECKO_CARDLOCK_RSPCK_PUK, puk); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify MCC and MNC parsing michael@0: */ michael@0: add_test(function test_mcc_mnc_parsing() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.ICCUtilsHelper; michael@0: michael@0: function do_test(imsi, mncLength, expectedMcc, expectedMnc) { michael@0: let result = helper.parseMccMncFromImsi(imsi, mncLength); michael@0: michael@0: if (!imsi) { michael@0: do_check_eq(result, null); michael@0: return; michael@0: } michael@0: michael@0: do_check_eq(result.mcc, expectedMcc); michael@0: do_check_eq(result.mnc, expectedMnc); michael@0: } michael@0: michael@0: // Test the imsi is null. michael@0: do_test(null, null, null, null); michael@0: michael@0: // Test MCC is Taiwan michael@0: do_test("466923202422409", 0x02, "466", "92"); michael@0: do_test("466923202422409", 0x03, "466", "923"); michael@0: do_test("466923202422409", null, "466", "92"); michael@0: michael@0: // Test MCC is US michael@0: do_test("310260542718417", 0x02, "310", "26"); michael@0: do_test("310260542718417", 0x03, "310", "260"); michael@0: do_test("310260542718417", null, "310", "260"); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify reading EF_AD and parsing MCC/MNC michael@0: */ michael@0: add_test(function test_reading_ad_and_parsing_mcc_mnc() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let record = context.SimRecordHelper; michael@0: let helper = context.GsmPDUHelper; michael@0: let ril = context.RIL; michael@0: let buf = context.Buf; michael@0: let io = context.ICCIOHelper; michael@0: michael@0: function do_test(mncLengthInEf, imsi, expectedMcc, expectedMnc) { michael@0: ril.iccInfoPrivate.imsi = imsi; michael@0: michael@0: io.loadTransparentEF = function fakeLoadTransparentEF(options) { michael@0: let ad = [0x00, 0x00, 0x00]; michael@0: if (mncLengthInEf) { michael@0: ad.push(mncLengthInEf); michael@0: } michael@0: michael@0: // Write data size michael@0: buf.writeInt32(ad.length * 2); michael@0: michael@0: // Write data michael@0: for (let i = 0; i < ad.length; i++) { michael@0: helper.writeHexOctet(ad[i]); michael@0: } michael@0: michael@0: // Write string delimiter michael@0: buf.writeStringDelimiter(ad.length * 2); michael@0: michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: }; michael@0: michael@0: record.readAD(); michael@0: michael@0: do_check_eq(ril.iccInfo.mcc, expectedMcc); michael@0: do_check_eq(ril.iccInfo.mnc, expectedMnc); michael@0: } michael@0: michael@0: do_test(undefined, "466923202422409", "466", "92" ); michael@0: do_test(0x03, "466923202422409", "466", "923"); michael@0: do_test(undefined, "310260542718417", "310", "260"); michael@0: do_test(0x02, "310260542718417", "310", "26" ); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function test_reading_optional_efs() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let record = context.SimRecordHelper; michael@0: let gsmPdu = context.GsmPDUHelper; michael@0: let ril = context.RIL; michael@0: let buf = context.Buf; michael@0: let io = context.ICCIOHelper; michael@0: michael@0: function buildSST(supportedEf) { michael@0: let sst = []; michael@0: let len = supportedEf.length; michael@0: for (let i = 0; i < len; i++) { michael@0: let index, bitmask, iccService; michael@0: if (ril.appType === CARD_APPTYPE_SIM) { michael@0: iccService = GECKO_ICC_SERVICES.sim[supportedEf[i]]; michael@0: iccService -= 1; michael@0: index = Math.floor(iccService / 4); michael@0: bitmask = 2 << ((iccService % 4) << 1); michael@0: } else if (ril.appType === CARD_APPTYPE_USIM){ michael@0: iccService = GECKO_ICC_SERVICES.usim[supportedEf[i]]; michael@0: iccService -= 1; michael@0: index = Math.floor(iccService / 8); michael@0: bitmask = 1 << ((iccService % 8) << 0); michael@0: } michael@0: michael@0: if (sst) { michael@0: sst[index] |= bitmask; michael@0: } michael@0: } michael@0: return sst; michael@0: } michael@0: michael@0: ril.updateCellBroadcastConfig = function fakeUpdateCellBroadcastConfig() { michael@0: // Ignore updateCellBroadcastConfig after reading SST michael@0: }; michael@0: michael@0: function do_test(sst, supportedEf) { michael@0: // Clone supportedEf to local array for testing michael@0: let testEf = supportedEf.slice(0); michael@0: michael@0: record.readMSISDN = function fakeReadMSISDN() { michael@0: testEf.splice(testEf.indexOf("MSISDN"), 1); michael@0: }; michael@0: michael@0: record.readMBDN = function fakeReadMBDN() { michael@0: testEf.splice(testEf.indexOf("MDN"), 1); michael@0: }; michael@0: michael@0: record.readMWIS = function fakeReadMWIS() { michael@0: testEf.splice(testEf.indexOf("MWIS"), 1); michael@0: }; michael@0: michael@0: io.loadTransparentEF = function fakeLoadTransparentEF(options) { michael@0: // Write data size michael@0: buf.writeInt32(sst.length * 2); michael@0: michael@0: // Write data michael@0: for (let i = 0; i < sst.length; i++) { michael@0: gsmPdu.writeHexOctet(sst[i] || 0); michael@0: } michael@0: michael@0: // Write string delimiter michael@0: buf.writeStringDelimiter(sst.length * 2); michael@0: michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: michael@0: if (testEf.length !== 0) { michael@0: do_print("Un-handled EF: " + JSON.stringify(testEf)); michael@0: do_check_true(false); michael@0: } michael@0: }; michael@0: michael@0: record.readSST(); michael@0: } michael@0: michael@0: // TODO: Add all necessary optional EFs eventually michael@0: let supportedEf = ["MSISDN", "MDN", "MWIS"]; michael@0: ril.appType = CARD_APPTYPE_SIM; michael@0: do_test(buildSST(supportedEf), supportedEf); michael@0: ril.appType = CARD_APPTYPE_USIM; michael@0: do_test(buildSST(supportedEf), supportedEf); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify fetchSimRecords. michael@0: */ michael@0: add_test(function test_fetch_sim_recodes() { michael@0: let worker = newWorker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let RIL = context.RIL; michael@0: let iccRecord = context.ICCRecordHelper; michael@0: let simRecord = context.SimRecordHelper; michael@0: michael@0: function testFetchSimRecordes(expectCalled) { michael@0: let ifCalled = []; michael@0: michael@0: RIL.getIMSI = function() { michael@0: ifCalled.push("getIMSI"); michael@0: }; michael@0: michael@0: simRecord.readAD = function() { michael@0: ifCalled.push("readAD"); michael@0: }; michael@0: michael@0: simRecord.readSST = function() { michael@0: ifCalled.push("readSST"); michael@0: }; michael@0: michael@0: simRecord.fetchSimRecords(); michael@0: michael@0: for (let i = 0; i < expectCalled.length; i++ ) { michael@0: if (ifCalled[i] != expectCalled[i]) { michael@0: do_print(expectCalled[i] + " is not called."); michael@0: do_check_true(false); michael@0: } michael@0: } michael@0: } michael@0: michael@0: let expectCalled = ["getIMSI", "readAD", "readSST"]; michael@0: testFetchSimRecordes(expectCalled); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function test_fetch_icc_recodes() { michael@0: let worker = newWorker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let RIL = context.RIL; michael@0: let iccRecord = context.ICCRecordHelper; michael@0: let simRecord = context.SimRecordHelper; michael@0: let ruimRecord = context.RuimRecordHelper; michael@0: let fetchTag = 0x00; michael@0: michael@0: simRecord.fetchSimRecords = function() { michael@0: fetchTag = 0x01; michael@0: }; michael@0: michael@0: ruimRecord.fetchRuimRecords = function() { michael@0: fetchTag = 0x02; michael@0: }; michael@0: michael@0: RIL.appType = CARD_APPTYPE_SIM; michael@0: iccRecord.fetchICCRecords(); michael@0: do_check_eq(fetchTag, 0x01); michael@0: michael@0: RIL.appType = CARD_APPTYPE_RUIM; michael@0: iccRecord.fetchICCRecords(); michael@0: do_check_eq(fetchTag, 0x02); michael@0: michael@0: RIL.appType = CARD_APPTYPE_USIM; michael@0: iccRecord.fetchICCRecords(); michael@0: do_check_eq(fetchTag, 0x01); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify SimRecordHelper.readMWIS michael@0: */ michael@0: add_test(function test_read_mwis() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let helper = context.GsmPDUHelper; michael@0: let recordHelper = context.SimRecordHelper; michael@0: let buf = context.Buf; michael@0: let io = context.ICCIOHelper; michael@0: let mwisData; michael@0: let postedMessage; michael@0: michael@0: worker.postMessage = function fakePostMessage(message) { michael@0: postedMessage = message; michael@0: }; michael@0: michael@0: io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { michael@0: if (mwisData) { michael@0: // Write data size michael@0: buf.writeInt32(mwisData.length * 2); michael@0: michael@0: // Write MWIS michael@0: for (let i = 0; i < mwisData.length; i++) { michael@0: helper.writeHexOctet(mwisData[i]); michael@0: } michael@0: michael@0: // Write string delimiter michael@0: buf.writeStringDelimiter(mwisData.length * 2); michael@0: michael@0: options.recordSize = mwisData.length; michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: } else { michael@0: do_print("mwisData[] is not set."); michael@0: } michael@0: }; michael@0: michael@0: function buildMwisData(isActive, msgCount) { michael@0: if (msgCount < 0 || msgCount === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) { michael@0: msgCount = 0; michael@0: } else if (msgCount > 255) { michael@0: msgCount = 255; michael@0: } michael@0: michael@0: mwisData = [ (isActive) ? 0x01 : 0x00, michael@0: msgCount, michael@0: 0xFF, 0xFF, 0xFF ]; michael@0: } michael@0: michael@0: function do_test(isActive, msgCount) { michael@0: buildMwisData(isActive, msgCount); michael@0: recordHelper.readMWIS(); michael@0: michael@0: do_check_eq("iccmwis", postedMessage.rilMessageType); michael@0: do_check_eq(isActive, postedMessage.mwi.active); michael@0: do_check_eq((isActive) ? msgCount : 0, postedMessage.mwi.msgCount); michael@0: } michael@0: michael@0: do_test(true, GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN); michael@0: do_test(true, 1); michael@0: do_test(true, 255); michael@0: michael@0: do_test(false, 0); michael@0: do_test(false, 255); // Test the corner case when mwi is disable with incorrect msgCount. michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify SimRecordHelper.updateMWIS michael@0: */ michael@0: add_test(function test_update_mwis() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let pduHelper = context.GsmPDUHelper; michael@0: let ril = context.RIL; michael@0: ril.appType = CARD_APPTYPE_USIM; michael@0: ril.iccInfoPrivate.mwis = [0x00, 0x00, 0x00, 0x00, 0x00]; michael@0: let recordHelper = context.SimRecordHelper; michael@0: let buf = context.Buf; michael@0: let ioHelper = context.ICCIOHelper; michael@0: let recordSize = ril.iccInfoPrivate.mwis.length; michael@0: let recordNum = 1; michael@0: michael@0: ioHelper.updateLinearFixedEF = function(options) { michael@0: options.pathId = context.ICCFileHelper.getEFPath(options.fileId); michael@0: options.command = ICC_COMMAND_UPDATE_RECORD; michael@0: options.p1 = options.recordNumber; michael@0: options.p2 = READ_RECORD_ABSOLUTE_MODE; michael@0: options.p3 = recordSize; michael@0: ril.iccIO(options); michael@0: }; michael@0: michael@0: function do_test(isActive, count) { michael@0: let mwis = ril.iccInfoPrivate.mwis; michael@0: let isUpdated = false; michael@0: michael@0: function buildMwisData() { michael@0: let result = mwis.slice(0); michael@0: result[0] = isActive? (mwis[0] | 0x01) : (mwis[0] & 0xFE); michael@0: result[1] = (count === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) ? 0 : count; michael@0: michael@0: return result; michael@0: } michael@0: michael@0: buf.sendParcel = function() { michael@0: isUpdated = true; michael@0: michael@0: // Request Type. michael@0: do_check_eq(this.readInt32(), REQUEST_SIM_IO); michael@0: michael@0: // Token : we don't care michael@0: this.readInt32(); michael@0: michael@0: // command. michael@0: do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); michael@0: michael@0: // fileId. michael@0: do_check_eq(this.readInt32(), ICC_EF_MWIS); michael@0: michael@0: // pathId. michael@0: do_check_eq(this.readString(), michael@0: EF_PATH_MF_SIM + ((ril.appType === CARD_APPTYPE_USIM) ? EF_PATH_ADF_USIM : EF_PATH_DF_GSM)); michael@0: michael@0: // p1. michael@0: do_check_eq(this.readInt32(), recordNum); michael@0: michael@0: // p2. michael@0: do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); michael@0: michael@0: // p3. michael@0: do_check_eq(this.readInt32(), recordSize); michael@0: michael@0: // data. michael@0: let strLen = this.readInt32(); michael@0: do_check_eq(recordSize * 2, strLen); michael@0: let expectedMwis = buildMwisData(); michael@0: for (let i = 0; i < recordSize; i++) { michael@0: do_check_eq(expectedMwis[i], pduHelper.readHexOctet()); michael@0: } michael@0: this.readStringDelimiter(strLen); michael@0: michael@0: // pin2. michael@0: do_check_eq(this.readString(), null); michael@0: michael@0: if (!ril.v5Legacy) { michael@0: // AID. Ignore because it's from modem. michael@0: this.readInt32(); michael@0: } michael@0: }; michael@0: michael@0: do_check_false(isUpdated); michael@0: michael@0: recordHelper.updateMWIS({ active: isActive, michael@0: msgCount: count }); michael@0: michael@0: do_check_true((ril.iccInfoPrivate.mwis) ? isUpdated : !isUpdated); michael@0: } michael@0: michael@0: do_test(true, GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN); michael@0: do_test(true, 1); michael@0: do_test(true, 255); michael@0: michael@0: do_test(false, 0); michael@0: michael@0: // Test if Path ID is correct for SIM. michael@0: ril.appType = CARD_APPTYPE_SIM; michael@0: do_test(false, 0); michael@0: michael@0: // Test if loadLinearFixedEF() is not invoked in updateMWIS() when michael@0: // EF_MWIS is not loaded/available. michael@0: delete ril.iccInfoPrivate.mwis; michael@0: do_test(false, 0); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify the call flow of receiving Class 2 SMS stored in SIM: michael@0: * 1. UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM. michael@0: * 2. SimRecordHelper.readSMS(). michael@0: * 3. sendChromeMessage() with rilMessageType == "sms-received". michael@0: */ michael@0: add_test(function test_read_new_sms_on_sim() { michael@0: // Instead of reusing newUint8Worker defined in this file, michael@0: // we define our own worker to fake the methods in WorkerBuffer dynamically. michael@0: function newSmsOnSimWorkerHelper() { michael@0: let _postedMessage; michael@0: let _worker = newWorker({ michael@0: postRILMessage: function(data) { michael@0: }, michael@0: postMessage: function(message) { michael@0: _postedMessage = message; michael@0: } michael@0: }); michael@0: michael@0: _worker.debug = do_print; michael@0: michael@0: return { michael@0: get postedMessage() { michael@0: return _postedMessage; michael@0: }, michael@0: get worker() { michael@0: return _worker; michael@0: }, michael@0: fakeWokerBuffer: function() { michael@0: let context = _worker.ContextPool._contexts[0]; michael@0: let index = 0; // index for read michael@0: let buf = []; michael@0: context.Buf.writeUint8 = function(value) { michael@0: buf.push(value); michael@0: }; michael@0: context.Buf.readUint8 = function() { michael@0: return buf[index++]; michael@0: }; michael@0: context.Buf.seekIncoming = function(offset) { michael@0: index += offset; michael@0: }; michael@0: context.Buf.getReadAvailable = function() { michael@0: return buf.length - index; michael@0: }; michael@0: } michael@0: }; michael@0: } michael@0: michael@0: let workerHelper = newSmsOnSimWorkerHelper(); michael@0: let worker = workerHelper.worker; michael@0: let context = worker.ContextPool._contexts[0]; michael@0: michael@0: context.ICCIOHelper.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { michael@0: // SimStatus: Unread, SMSC:+0123456789, Sender: +9876543210, Text: How are you? michael@0: let SimSmsPduHex = "0306911032547698040A9189674523010000208062917314080CC8F71D14969741F977FD07" michael@0: // In 4.2.25 EF_SMS Short Messages of 3GPP TS 31.102: michael@0: // 1. Record length == 176 bytes. michael@0: // 2. Any bytes in the record following the TPDU shall be filled with 'FF'. michael@0: + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" michael@0: + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" michael@0: + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" michael@0: + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; michael@0: michael@0: workerHelper.fakeWokerBuffer(); michael@0: michael@0: context.Buf.writeString(SimSmsPduHex); michael@0: michael@0: options.recordSize = 176; // Record length is fixed to 176 bytes. michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: }; michael@0: michael@0: function newSmsOnSimParcel() { michael@0: let data = new Uint8Array(4 + 4); // Int32List with 1 element. michael@0: let offset = 0; michael@0: michael@0: function writeInt(value) { michael@0: data[offset++] = value & 0xFF; michael@0: data[offset++] = (value >> 8) & 0xFF; michael@0: data[offset++] = (value >> 16) & 0xFF; michael@0: data[offset++] = (value >> 24) & 0xFF; michael@0: } michael@0: michael@0: writeInt(1); // Length of Int32List michael@0: writeInt(1); // RecordNum = 1. michael@0: michael@0: return newIncomingParcel(-1, michael@0: RESPONSE_TYPE_UNSOLICITED, michael@0: UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM, michael@0: data); michael@0: } michael@0: michael@0: function do_test() { michael@0: worker.onRILMessage(0, newSmsOnSimParcel()); michael@0: michael@0: let postedMessage = workerHelper.postedMessage; michael@0: michael@0: do_check_eq("sms-received", postedMessage.rilMessageType); michael@0: do_check_eq("+0123456789", postedMessage.SMSC); michael@0: do_check_eq("+9876543210", postedMessage.sender); michael@0: do_check_eq("How are you?", postedMessage.body); michael@0: } michael@0: michael@0: do_test(); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: // Test ICC_COMMAND_GET_RESPONSE with FCP template format. michael@0: /** michael@0: * Verify transparent structure with FCP template format. michael@0: */ michael@0: add_test(function test_fcp_template_for_transparent_structure() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let pduHelper = context.GsmPDUHelper; michael@0: let berHelper = context.BerTlvHelper; michael@0: michael@0: let tag_test = [ michael@0: 0x62, michael@0: 0x22, michael@0: 0x82, 0x02, 0x41, 0x21, michael@0: 0x83, 0x02, 0x2F, 0xE2, michael@0: 0xA5, 0x09, 0xC1, 0x04, 0x40, 0x0F, 0xF5, 0x55, 0x92, 0x01, 0x00, michael@0: 0x8A, 0x01, 0x05, michael@0: 0x8B, 0x03, 0x2F, 0x06, 0x0B, michael@0: 0x80, 0x02, 0x00, 0x0A, michael@0: 0x88, 0x01, 0x10]; michael@0: michael@0: for (let i = 0; i < tag_test.length; i++) { michael@0: pduHelper.writeHexOctet(tag_test[i]); michael@0: } michael@0: michael@0: let berTlv = berHelper.decode(tag_test.length); michael@0: let iter = Iterator(berTlv.value); michael@0: let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter); michael@0: do_check_eq(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_TYPE_TRANSPARENT]); michael@0: michael@0: tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter); michael@0: do_check_eq(tlv.value.fileId, 0x2FE2); michael@0: michael@0: tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter); michael@0: do_check_eq(tlv.value.fileSizeData, 0x0A); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify linear fixed structure with FCP template format. michael@0: */ michael@0: add_test(function test_fcp_template_for_linear_fixed_structure() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let pduHelper = context.GsmPDUHelper; michael@0: let berHelper = context.BerTlvHelper; michael@0: michael@0: let tag_test = [ michael@0: 0x62, michael@0: 0x1E, michael@0: 0x82, 0x05, 0x42, 0x21, 0x00, 0x1A, 0x01, michael@0: 0x83, 0x02, 0x6F, 0x40, michael@0: 0xA5, 0x03, 0x92, 0x01, 0x00, michael@0: 0x8A, 0x01, 0x07, michael@0: 0x8B, 0x03, 0x6F, 0x06, 0x02, michael@0: 0x80, 0x02, 0x00, 0x1A, michael@0: 0x88, 0x00]; michael@0: michael@0: for (let i = 0; i < tag_test.length; i++) { michael@0: pduHelper.writeHexOctet(tag_test[i]); michael@0: } michael@0: michael@0: let berTlv = berHelper.decode(tag_test.length); michael@0: let iter = Iterator(berTlv.value); michael@0: let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter); michael@0: do_check_eq(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_TYPE_LINEAR_FIXED]); michael@0: do_check_eq(tlv.value.recordLength, 0x1A); michael@0: do_check_eq(tlv.value.numOfRecords, 0x01); michael@0: michael@0: tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter); michael@0: do_check_eq(tlv.value.fileId, 0x6F40); michael@0: michael@0: tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter); michael@0: do_check_eq(tlv.value.fileSizeData, 0x1A); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function test_icc_io_get_response_for_transparent_structure() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let buf = context.Buf; michael@0: let iccioHelper = context.ICCIOHelper; michael@0: let pduHelper = context.GsmPDUHelper; michael@0: michael@0: let responseArray = [ michael@0: // SIM response. michael@0: [0x00, 0x00, 0x00, 0x0A, 0x2F, 0xE2, 0x04, 0x00, 0x0A, 0xA0, 0xAA, 0x00, michael@0: 0x02, 0x00, 0x00], michael@0: // USIM response. michael@0: [0x62, 0x22, 0x82, 0x02, 0x41, 0x21, 0x83, 0x02, 0x2F, 0xE2, 0xA5, 0x09, michael@0: 0xC1, 0x04, 0x40, 0x0F, 0xF5, 0x55, 0x92, 0x01, 0x00, 0x8A, 0x01, 0x05, michael@0: 0x8B, 0x03, 0x2F, 0x06, 0x0B, 0x80, 0x02, 0x00, 0x0A, 0x88, 0x01, 0x10] michael@0: ]; michael@0: michael@0: for (let i = 0; i < responseArray.length; i++) { michael@0: let strLen = responseArray[i].length * 2; michael@0: buf.writeInt32(strLen); michael@0: for (let j = 0; j < responseArray[i].length; j++) { michael@0: pduHelper.writeHexOctet(responseArray[i][j]); michael@0: } michael@0: buf.writeStringDelimiter(strLen); michael@0: michael@0: let options = {fileId: ICC_EF_ICCID, michael@0: type: EF_TYPE_TRANSPARENT}; michael@0: iccioHelper.processICCIOGetResponse(options); michael@0: michael@0: do_check_eq(options.fileSize, 0x0A); michael@0: } michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function test_icc_io_get_response_for_linear_fixed_structure() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let buf = context.Buf; michael@0: let iccioHelper = context.ICCIOHelper; michael@0: let pduHelper = context.GsmPDUHelper; michael@0: michael@0: let responseArray = [ michael@0: // SIM response. michael@0: [0x00, 0x00, 0x00, 0x1A, 0x6F, 0x40, 0x04, 0x00, 0x11, 0xA0, 0xAA, 0x00, michael@0: 0x02, 0x01, 0x1A], michael@0: // USIM response. michael@0: [0x62, 0x1E, 0x82, 0x05, 0x42, 0x21, 0x00, 0x1A, 0x01, 0x83, 0x02, 0x6F, michael@0: 0x40, 0xA5, 0x03, 0x92, 0x01, 0x00, 0x8A, 0x01, 0x07, 0x8B, 0x03, 0x6F, michael@0: 0x06, 0x02, 0x80, 0x02, 0x00, 0x1A, 0x88, 0x00] michael@0: ]; michael@0: michael@0: for (let i = 0; i < responseArray.length; i++) { michael@0: let strLen = responseArray[i].length * 2; michael@0: buf.writeInt32(strLen); michael@0: for (let j = 0; j < responseArray[i].length; j++) { michael@0: pduHelper.writeHexOctet(responseArray[i][j]); michael@0: } michael@0: buf.writeStringDelimiter(strLen); michael@0: michael@0: let options = {fileId: ICC_EF_MSISDN, michael@0: type: EF_TYPE_LINEAR_FIXED}; michael@0: iccioHelper.processICCIOGetResponse(options); michael@0: michael@0: do_check_eq(options.fileSize, 0x1A); michael@0: do_check_eq(options.recordSize, 0x1A); michael@0: do_check_eq(options.totalRecords, 0x01); michael@0: } michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify reading EF_ICCID. michael@0: */ michael@0: add_test(function test_handling_iccid() { michael@0: let worker = newUint8Worker(); michael@0: let context = worker.ContextPool._contexts[0]; michael@0: let record = context.ICCRecordHelper; michael@0: let helper = context.GsmPDUHelper; michael@0: let ril = context.RIL; michael@0: let buf = context.Buf; michael@0: let io = context.ICCIOHelper; michael@0: michael@0: ril.reportStkServiceIsRunning = function fakeReportStkServiceIsRunning() { michael@0: }; michael@0: michael@0: function do_test(rawICCID, expectedICCID) { michael@0: io.loadTransparentEF = function fakeLoadTransparentEF(options) { michael@0: // Write data size michael@0: buf.writeInt32(rawICCID.length); michael@0: michael@0: // Write data michael@0: for (let i = 0; i < rawICCID.length; i += 2) { michael@0: helper.writeHexOctet(parseInt(rawICCID.substr(i, 2), 16)); michael@0: } michael@0: michael@0: // Write string delimiter michael@0: buf.writeStringDelimiter(rawICCID.length); michael@0: michael@0: if (options.callback) { michael@0: options.callback(options); michael@0: } michael@0: }; michael@0: michael@0: record.readICCID(); michael@0: michael@0: do_check_eq(ril.iccInfo.iccid, expectedICCID); michael@0: } michael@0: michael@0: // Invalid char at high nibbile + low nibbile contains 0xF. michael@0: do_test("9868002E90909F001519", "89860020909"); michael@0: // Invalid char at low nibbile. michael@0: do_test("986800E2909090001519", "8986002090909005191"); michael@0: // Valid ICCID. michael@0: do_test("98101430121181157002", "89014103211118510720"); michael@0: michael@0: run_next_test(); michael@0: });