Bug 729876 - Part 2: SMS tests. r=philikon DONTBUILD because NPOTB
authorVicamo Yang <vyang@mozilla.com>
Wed, 07 Mar 2012 14:43:30 -0800
changeset 88433 453d5c733caa6b2cea80273c5713e45ca7f37ca1
parent 88432 a4415019a57ad50b54e1d3865f21e2ee4db6ffa4
child 88434 26342266f30911597ef88d3e65fd3d90c7990352
push id22197
push userpweitershausen@mozilla.com
push dateWed, 07 Mar 2012 22:44:33 +0000
treeherdermozilla-central@453d5c733caa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersphilikon
bugs729876
milestone13.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 729876 - Part 2: SMS tests. r=philikon DONTBUILD because NPOTB
dom/system/b2g/tests/test_ril_worker_sms.js
dom/system/b2g/tests/xpcshell.ini
new file mode 100644
--- /dev/null
+++ b/dom/system/b2g/tests/test_ril_worker_sms.js
@@ -0,0 +1,438 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+const ESCAPE = "\uffff";
+const RESCTL = "\ufffe";
+const LF = "\n";
+const CR = "\r";
+const SP = " ";
+const FF = "\u000c";
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Verify validity of the national language tables
+ */
+add_test(function test_nl_locking_shift_tables_validity() {
+  for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
+    do_print("Verifying PDU_NL_LOCKING_SHIFT_TABLES[" + lst + "]");
+
+    let table = PDU_NL_LOCKING_SHIFT_TABLES[lst];
+
+    // Make sure table length is 128, or it will break table lookup algorithm.
+    do_check_eq(table.length, 128);
+
+    // Make sure special values are preserved.
+    do_check_eq(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE);
+    do_check_eq(table[PDU_NL_LINE_FEED], LF);
+    do_check_eq(table[PDU_NL_CARRIAGE_RETURN], CR);
+    do_check_eq(table[PDU_NL_SPACE], SP);
+  }
+
+  run_next_test();
+});
+
+add_test(function test_nl_single_shift_tables_validity() {
+  for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) {
+    do_print("Verifying PDU_NL_SINGLE_SHIFT_TABLES[" + sst + "]");
+
+    let table = PDU_NL_SINGLE_SHIFT_TABLES[sst];
+
+    // Make sure table length is 128, or it will break table lookup algorithm.
+    do_check_eq(table.length, 128);
+
+    // Make sure special values are preserved.
+    do_check_eq(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE);
+    do_check_eq(table[PDU_NL_PAGE_BREAK], FF);
+    do_check_eq(table[PDU_NL_RESERVED_CONTROL], RESCTL);
+  }
+
+  run_next_test();
+});
+
+/**
+ * Verify GsmPDUHelper#_calculateLangEncodedLength() and
+ * GsmPDUHelper#writeStringAsSeptets() algorithm match each other.
+ */
+add_test(function test_GsmPDUHelper__calculateLangEncodedLength() {
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(data) {
+      // Do nothing
+    },
+    postMessage: function fakePostMessage(message) {
+      // Do nothing
+    }
+  });
+
+  let helper = worker.GsmPDUHelper;
+  helper.resetOctetWritten = function () {
+    helper.octetsWritten = 0;
+  };
+  helper.writeHexOctet = function () {
+    helper.octetsWritten++;
+  };
+
+  function do_check_calc(str, expectedCalcLen, lst, sst) {
+    do_check_eq(expectedCalcLen,
+                helper._calculateLangEncodedLength(str,
+                                                   PDU_NL_LOCKING_SHIFT_TABLES[lst],
+                                                   PDU_NL_SINGLE_SHIFT_TABLES[sst]));
+
+    helper.resetOctetWritten();
+    helper.writeStringAsSeptets(str, 0, lst, sst);
+    do_check_eq(Math.ceil(expectedCalcLen * 7 / 8), helper.octetsWritten);
+  }
+
+  // Test calculation encoded message length using both locking/single shift tables.
+  for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
+    let langTable = PDU_NL_LOCKING_SHIFT_TABLES[lst];
+
+    let str = langTable.substring(0, PDU_NL_EXTENDED_ESCAPE)
+              + langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1);
+
+    for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) {
+      let langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[sst];
+
+      // <escape>, <resctrl> should be ignored.
+      do_check_calc(ESCAPE + RESCTL, 0, lst, sst);
+
+      // Characters defined in locking shift table should be encoded directly.
+      do_check_calc(str, str.length, lst, sst);
+
+      let [str1, str2] = ["", ""];
+      for (let i = 0; i < langShiftTable.length; i++) {
+        if ((i == PDU_NL_EXTENDED_ESCAPE) || (i == PDU_NL_RESERVED_CONTROL)) {
+          continue;
+        }
+
+        let c = langShiftTable[i];
+        if (langTable.indexOf(c) >= 0) {
+          str1 += c;
+        } else {
+          str2 += c;
+        }
+      }
+
+      // Characters found in both locking/single shift tables should be
+      // directly encoded.
+      do_check_calc(str1, str1.length, lst, sst);
+
+      // Characters found only in single shift tables should be encoded as
+      // <escape><code>, therefore doubles its original length.
+      do_check_calc(str2, str2.length * 2, lst, sst);
+    }
+  }
+
+  run_next_test();
+});
+
+/**
+ * Verify GsmPDUHelper#calculateUserDataLength handles national language
+ * selection correctly.
+ */
+add_test(function test_GsmPDUHelper_calculateUserDataLength() {
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(data) {
+      // Do nothing
+    },
+    postMessage: function fakePostMessage(message) {
+      // Do nothing
+    }
+  });
+
+  let helper = worker.GsmPDUHelper;
+  let calc = helper.calculateUserDataLength;
+  function test_calc(str, expected, enabledGsmTableTuples) {
+    helper.enabledGsmTableTuples = enabledGsmTableTuples;
+    let options = {body: str};
+    calc.call(helper, options);
+
+    do_check_eq(expected[0], options.dcs);
+    do_check_eq(expected[1], options.encodedBodyLength);
+    do_check_eq(expected[2], options.userDataHeaderLength);
+    do_check_eq(expected[3], options.langIndex);
+    do_check_eq(expected[4], options.langShiftIndex);
+  }
+
+  // Test UCS fallback
+  // - No any default enabled nl tables
+  test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0, 0, 0], []);
+  // - Character not defined in enabled nl tables
+  test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0, 0, 0], [[2, 2]]);
+
+  // With GSM default nl tables
+  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 0, 0, 0], [[0, 0]]);
+  // - SP is defined in both locking/single shift tables, should be directly
+  //   encoded.
+  test_calc(SP, [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 0, 0, 0], [[0, 0]]);
+  // - '^' is only defined in single shift table, should be encoded as
+  //   <escape>^.
+  test_calc("^", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 0, 0, 0], [[0, 0]]);
+
+  // Test userDataHeaderLength calculation
+  // - Header contains both IEIs
+  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 6, 1, 1], [[1, 1]]);
+  // - Header contains only locking shift table IEI
+  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0]]);
+  // - Header contains only single shift table IEI
+  test_calc("^", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 3, 0, 1], [[0, 1]]);
+
+  // Test minimum cost nl tables selection
+  // - 'A' is defined in locking shift table
+  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0], [2, 0]]);
+  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[2, 0], [1, 0]]);
+  // - 'A' is defined in single shift table
+  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 6, 2, 4], [[2, 0], [2, 4]]);
+  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 6, 2, 4], [[2, 4], [2, 0]]);
+  // - 'A' is defined in locking shift table of one tuple and in single shift
+  //   table of another.
+  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0], [2, 4]]);
+  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[2, 4], [1, 0]]);
+
+  run_next_test();
+});
+
+/**
+ * Verify GsmPDUHelper#writeStringAsSeptets() padding bits handling.
+ */
+add_test(function test_GsmPDUHelper_writeStringAsSeptets() {
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(data) {
+      // Do nothing
+    },
+    postMessage: function fakePostMessage(message) {
+      // Do nothing
+    }
+  });
+
+  let helper = worker.GsmPDUHelper;
+  helper.resetOctetWritten = function () {
+    helper.octetsWritten = 0;
+  };
+  helper.writeHexOctet = function () {
+    helper.octetsWritten++;
+  };
+
+  let base = "AAAAAAAA"; // Base string of 8 characters long
+  for (let len = 0; len < 8; len++) {
+    let str = base.substring(0, len);
+
+    for (let paddingBits = 0; paddingBits < 8; paddingBits++) {
+      do_print("Verifying GsmPDUHelper.writeStringAsSeptets("
+               + str + ", " + paddingBits + ", <default>, <default>)");
+      helper.resetOctetWritten();
+      helper.writeStringAsSeptets(str, paddingBits, PDU_NL_IDENTIFIER_DEFAULT,
+                                  PDU_NL_IDENTIFIER_DEFAULT);
+      do_check_eq(Math.ceil(((len * 7) + paddingBits) / 8),
+                  helper.octetsWritten);
+    }
+  }
+
+  run_next_test();
+});
+
+/**
+ * Verify receiving SMS-DELIVERY messages
+ */
+
+function hexToNibble(nibble) {
+  nibble &= 0x0f;
+  if (nibble < 10) {
+    nibble += 48; // ASCII '0'
+  } else {
+    nibble += 55; // ASCII 'A'
+  }
+  return nibble;
+}
+
+function pduToParcelData(pdu) {
+  let dataLength = 4 + pdu.length * 4 + 4;
+  let data = new Uint8Array(dataLength);
+  let offset = 0;
+
+  // String length
+  data[offset++] = pdu.length & 0xFF;
+  data[offset++] = (pdu.length >> 8) & 0xFF;
+  data[offset++] = (pdu.length >> 16) & 0xFF;
+  data[offset++] = (pdu.length >> 24) & 0xFF;
+
+  // PDU data
+  for (let i = 0; i < pdu.length; i++) {
+    let hi = (pdu[i] >>> 4) & 0x0F;
+    let lo = pdu[i] & 0x0F;
+
+    data[offset++] = hexToNibble(hi);
+    data[offset++] = 0;
+    data[offset++] = hexToNibble(lo);
+    data[offset++] = 0;
+  }
+
+  // String delimitor
+  data[offset++] = 0;
+  data[offset++] = 0;
+  data[offset++] = 0;
+  data[offset++] = 0;
+
+  return data;
+}
+
+function compose7bitPdu(lst, sst, data, septets) {
+  if ((lst == 0) && (sst == 0)) {
+    return [0x00,                              // SMSC
+            PDU_MTI_SMS_DELIVER,               // firstOctet
+            1, 0x00, 0,                        // senderAddress
+            0x00,                              // protocolIdentifier
+            PDU_DCS_MSG_CODING_7BITS_ALPHABET, // dataCodingScheme
+            0, 0, 0, 0, 0, 0, 0,               // y m d h m s tz
+            septets]                           // userDataLength
+           .concat(data);
+  }
+
+  return [0x00,                                            // SMSC
+          PDU_MTI_SMS_DELIVER | PDU_UDHI,                  // firstOctet
+          1, 0x00, 0,                                      // senderAddress
+          0x00,                                            // protocolIdentifier
+          PDU_DCS_MSG_CODING_7BITS_ALPHABET,               // dataCodingScheme
+          0, 0, 0, 0, 0, 0, 0,                             // y m d h m s tz
+          8 + septets,                                     // userDataLength
+          6,                                               // user data header length
+          PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT, 1, lst, // PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT
+          PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT, 1, sst]  // PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT
+         .concat(data);
+}
+
+function composeUcs2Pdu(rawBytes) {
+  return [0x00,                               // SMSC
+          PDU_MTI_SMS_DELIVER,                // firstOctet
+          1, 0x00, 0,                         // senderAddress
+          0x00,                               // protocolIdentifier
+          PDU_DCS_MSG_CODING_16BITS_ALPHABET, // dataCodingScheme
+          0, 0, 0, 0, 0, 0, 0,                // y m d h m s tz
+          rawBytes.length]                    // userDataLength
+         .concat(rawBytes);
+}
+
+function newSmsParcel(pdu) {
+  return newIncomingParcel(-1,
+                           RESPONSE_TYPE_UNSOLICITED,
+                           UNSOLICITED_RESPONSE_NEW_SMS,
+                           pduToParcelData(pdu));
+}
+
+function removeSpecialChar(str, needle) {
+  for (let i = 0; i < needle.length; i++) {
+    let pos;
+    while ((pos = str.indexOf(needle[i])) >= 0) {
+      str = str.substring(0, pos) + str.substring(pos + 1);
+    }
+  }
+  return str;
+}
+
+function newWriteHexOctetAsUint8Worker() {
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(data) {
+      // Do nothing
+    },
+    postMessage: function fakePostMessage(message) {
+      // Do nothing
+    }
+  });
+
+  worker.GsmPDUHelper.writeHexOctet = function (value) {
+    worker.Buf.writeUint8(value);
+  };
+
+  return worker;
+}
+
+function add_test_receiving_sms(expected, pdu) {
+  add_test(function test_receiving_sms() {
+    let worker = newWorker({
+      postRILMessage: function fakePostRILMessage(data) {
+        // Do nothing
+      },
+      postMessage: function fakePostMessage(message) {
+        do_print("body: " + message.body);
+        do_check_eq(expected, message.body)
+      }
+    });
+
+    do_print("expect: " + expected);
+    do_print("pdu: " + pdu);
+    worker.onRILMessage(newSmsParcel(pdu));
+
+    run_next_test();
+  });
+}
+
+function test_receiving_7bit_alphabets(lst, sst) {
+  let worker = newWriteHexOctetAsUint8Worker();
+  let helper = worker.GsmPDUHelper;
+  let buf = worker.Buf;
+
+  function get7bitRawBytes(expected) {
+    buf.outgoingIndex = 0;
+    helper.writeStringAsSeptets(expected, 0, lst, sst);
+
+    let subArray = buf.outgoingBytes.subarray(0, buf.outgoingIndex);
+    return Array.slice(subArray);
+  }
+
+  let langTable = PDU_NL_LOCKING_SHIFT_TABLES[lst];
+  let langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[sst];
+
+  let text = removeSpecialChar(langTable + langShiftTable, ESCAPE + RESCTL);
+  for (let i = 0; i < text.length;) {
+    let len = Math.min(70, text.length - i);
+    let expected = text.substring(i, i + len);
+    let septets = helper._calculateLangEncodedLength(expected, langTable,
+                                                     langShiftTable);
+    let rawBytes = get7bitRawBytes(expected);
+    let pdu = compose7bitPdu(lst, sst, rawBytes, septets);
+    add_test_receiving_sms(expected, pdu);
+
+    i += len;
+  }
+}
+
+function test_receiving_ucs2_alphabets(text) {
+  let worker = newWriteHexOctetAsUint8Worker();
+  let buf = worker.Buf;
+
+  function getUCS2RawBytes(expected) {
+    buf.outgoingIndex = 0;
+    worker.GsmPDUHelper.writeUCS2String(expected);
+
+    let subArray = buf.outgoingBytes.subarray(0, buf.outgoingIndex);
+    return Array.slice(subArray);
+  }
+
+  for (let i = 0; i < text.length;) {
+    let len = Math.min(70, text.length - i);
+    let expected = text.substring(i, i + len);
+    let rawBytes = getUCS2RawBytes(expected);
+    let pdu = composeUcs2Pdu(rawBytes);
+    add_test_receiving_sms(expected, pdu);
+
+    i += len;
+  }
+}
+
+let ucs2str = "";
+for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
+  ucs2str += PDU_NL_LOCKING_SHIFT_TABLES[lst];
+  for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) {
+    test_receiving_7bit_alphabets(lst, sst);
+
+    if (lst == 0) {
+      ucs2str += PDU_NL_SINGLE_SHIFT_TABLES[sst];
+    }
+  }
+}
+test_receiving_ucs2_alphabets(ucs2str);
+
--- a/dom/system/b2g/tests/xpcshell.ini
+++ b/dom/system/b2g/tests/xpcshell.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 head = header_helpers.js
 tail =
 
 [test_ril_worker_buf.js]
+[test_ril_worker_sms.js]