SmsMessageBodyTestpublic class SmsMessageBodyTest extends android.test.AndroidTestCase Test cases to verify selection of the optimal 7 bit encoding tables
(for all combinations of enabled national language tables) for messages
containing Turkish, Spanish, Portuguese, Greek, and other symbols
present in the GSM default and national language tables defined in
3GPP TS 23.038. Also verifies correct SMS encoding for CDMA, which only
supports the GSM 7 bit default alphabet, ASCII 8 bit, and UCS-2.
Tests both encoding variations: unsupported characters mapped to space,
and unsupported characters force entire message to UCS-2. |
Fields Summary |
---|
private static final String | TAG | private static final String | sAsciiChars | private static final String | sGsmDefaultChars | private static final String | sGsmDefaultAndTurkishTables | private static final String | sGsmDefaultTableOnly | private static final String | sGsmExtendedAsciiChars | private static final String | sGsmExtendedPortugueseLocking | private static final String | sGsmExtendedEuroSymbol | private static final String | sUnicodeChars | private static final String | sTurkishChars | private static final String | sPortugueseAndSpanishChars | private static final String | sNationalLanguageTablesOnly | private static final String | sPortugueseChars | private static final String | sPortugueseLockingShiftChars | private static final String | sGreekLettersNotInPortugueseTables | private static final String | sGreekLettersInPortugueseShiftTable | private static final String[] | sCharacterClasses | private static final int | sNumCharacterClasses | private static final boolean[] | sCharClassPresenceInTables | private static final int | sTestLengthCount | private static final int[] | sSeptetTestLengths | private static final int[] | sUnicodeTestLengths | private static final int[] | sTestMsgCounts | private static final int[] | sSeptetUnitsRemaining | private static final int[] | sUnicodeUnitsRemaining | private static final int[] | sEnabledSingleShiftTables | private static final int[] | sEnabledLockingShiftTables | private static final int[] | sLanguagePairIndexesByEnabledIndex | private static final int | UDH_SEPTET_COST_LENGTHUser data header requires one octet for length. Count as one septet, because
all combinations of header elements below will have at least one free bit
when padding to the nearest septet boundary. | private static final int | UDH_SEPTET_COST_ONE_SHIFT_TABLEUsing a non-default language locking shift table OR single shift table
requires a user data header of 3 octets, or 4 septets, plus UDH length. | private static final int | UDH_SEPTET_COST_TWO_SHIFT_TABLESUsing a non-default language locking shift table AND single shift table
requires a user data header of 6 octets, or 7 septets, plus UDH length. | private static final int | UDH_SEPTET_COST_CONCATENATED_MESSAGEMulti-part messages require a user data header of 5 octets, or 6 septets,
plus UDH length. |
Methods Summary |
---|
private void | callCdmaLengthMethods(java.lang.CharSequence msgBody, boolean use7bitOnly, int[] expectedValues)
int activePhone = TelephonyManager.getDefault().getPhoneType();
if (TelephonyManager.PHONE_TYPE_CDMA == activePhone) {
int[] values = android.telephony.SmsMessage.calculateLength(msgBody, use7bitOnly);
assertEquals("msgCount", expectedValues[0], values[0]);
assertEquals("codeUnitCount", expectedValues[1], values[1]);
assertEquals("codeUnitsRemaining", expectedValues[2], values[2]);
assertEquals("codeUnitSize", expectedValues[3], values[3]);
}
GsmAlphabet.TextEncodingDetails ted =
com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly, true);
assertEquals("msgCount", expectedValues[0], ted.msgCount);
assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount);
assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining);
assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize);
ted = com.android.internal.telephony.cdma.sms.BearerData.calcTextEncodingDetails(msgBody, use7bitOnly, true);
assertEquals("msgCount", expectedValues[0], ted.msgCount);
assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount);
assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining);
assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize);
| private void | callGsmLengthMethods(java.lang.CharSequence msgBody, boolean use7bitOnly, int[] expectedValues)
// deprecated GSM-specific method
int[] values = android.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly);
assertEquals("msgCount", expectedValues[0], values[0]);
assertEquals("codeUnitCount", expectedValues[1], values[1]);
assertEquals("codeUnitsRemaining", expectedValues[2], values[2]);
assertEquals("codeUnitSize", expectedValues[3], values[3]);
int activePhone = TelephonyManager.getDefault().getPhoneType();
if (TelephonyManager.PHONE_TYPE_GSM == activePhone) {
values = android.telephony.SmsMessage.calculateLength(msgBody, use7bitOnly);
assertEquals("msgCount", expectedValues[0], values[0]);
assertEquals("codeUnitCount", expectedValues[1], values[1]);
assertEquals("codeUnitsRemaining", expectedValues[2], values[2]);
assertEquals("codeUnitSize", expectedValues[3], values[3]);
}
GsmAlphabet.TextEncodingDetails ted =
com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly);
assertEquals("msgCount", expectedValues[0], ted.msgCount);
assertEquals("codeUnitCount", expectedValues[1], ted.codeUnitCount);
assertEquals("codeUnitsRemaining", expectedValues[2], ted.codeUnitsRemaining);
assertEquals("codeUnitSize", expectedValues[3], ted.codeUnitSize);
assertEquals("languageTable", expectedValues[4], ted.languageTable);
assertEquals("languageShiftTable", expectedValues[5], ted.languageShiftTable);
| public void | testCalcLengthAscii()
StringBuilder sb = new StringBuilder(320);
int[] values = {0, 0, 0, SmsConstants.ENCODING_7BIT, 0, 0};
int startPos = 0;
int asciiCharsLen = sAsciiChars.length();
for (int i = 0; i < sTestLengthCount; i++) {
int len = sSeptetTestLengths[i];
assertTrue(sb.length() <= len);
while (sb.length() < len) {
int addCount = len - sb.length();
int endPos = (asciiCharsLen - startPos > addCount) ?
(startPos + addCount) : asciiCharsLen;
sb.append(sAsciiChars, startPos, endPos);
startPos = (endPos == asciiCharsLen) ? 0 : endPos;
}
assertEquals(len, sb.length());
String testStr = sb.toString();
values[0] = sTestMsgCounts[i];
values[1] = len;
values[2] = sSeptetUnitsRemaining[i];
callGsmLengthMethods(testStr, false, values);
callGsmLengthMethods(testStr, true, values);
callCdmaLengthMethods(testStr, false, values);
callCdmaLengthMethods(testStr, true, values);
}
| public void | testCalcLengthMixed7bit()
StringBuilder sb = new StringBuilder(320);
CounterHelper ch = new CounterHelper();
Random r = new Random(0x4321); // use the same seed for reproducibility
int[] expectedValues = new int[6];
int[] origLockingShiftTables = GsmAlphabet.getEnabledLockingShiftTables();
int[] origSingleShiftTables = GsmAlphabet.getEnabledSingleShiftTables();
int enabledLanguagesTestCases = sEnabledSingleShiftTables.length;
long startTime = System.currentTimeMillis();
// Repeat for 10 test runs
for (int run = 0; run < 10; run++) {
sb.setLength(0);
ch.clear();
int unicodeOnlyCount = 0;
// Test incrementally from 1 to 320 character random messages
for (int i = 1; i < 320; i++) {
// 1% chance to add from each special character class, else add an ASCII char
int charClass = r.nextInt(100);
if (charClass >= sNumCharacterClasses) {
charClass = sNumCharacterClasses - 1; // last class is ASCII
}
int classLength = sCharacterClasses[charClass].length();
char nextChar = sCharacterClasses[charClass].charAt(r.nextInt(classLength));
sb.append(nextChar);
ch.addChar(charClass);
// if (i % 20 == 0) {
// Rlog.d(TAG, "test string: " + sb);
// }
// Test string against all combinations of enabled languages
boolean unicodeOnly = true;
for (int j = 0; j < enabledLanguagesTestCases; j++) {
GsmAlphabet.setEnabledSingleShiftTables(sEnabledSingleShiftTables[j]);
GsmAlphabet.setEnabledLockingShiftTables(sEnabledLockingShiftTables[j]);
ch.fillData(j, false, expectedValues, i);
if (expectedValues[3] == SmsConstants.ENCODING_7BIT) {
unicodeOnly = false;
}
callGsmLengthMethods(sb, false, expectedValues);
// test 7 bit only mode
ch.fillData(j, true, expectedValues, i);
callGsmLengthMethods(sb, true, expectedValues);
}
// after 10 iterations with a Unicode-only string, skip to next test string
// so we can spend more time testing strings that do encode into 7 bits.
if (unicodeOnly && ++unicodeOnlyCount == 10) {
// Rlog.d(TAG, "Unicode only: skipping to next test string");
break;
}
}
}
ch.printStats();
Rlog.d(TAG, "Completed in " + (System.currentTimeMillis() - startTime) + " ms");
GsmAlphabet.setEnabledLockingShiftTables(origLockingShiftTables);
GsmAlphabet.setEnabledSingleShiftTables(origSingleShiftTables);
| public void | testCalcLengthUnicode()
StringBuilder sb = new StringBuilder(160);
int[] values = {0, 0, 0, SmsConstants.ENCODING_16BIT, 0, 0};
int[] values7bit = {1, 0, 0, SmsConstants.ENCODING_7BIT, 0, 0};
int startPos = 0;
int unicodeCharsLen = sUnicodeChars.length();
// start with length 1: empty string uses ENCODING_7BIT
for (int i = 1; i < sTestLengthCount; i++) {
int len = sUnicodeTestLengths[i];
assertTrue(sb.length() <= len);
while (sb.length() < len) {
int addCount = len - sb.length();
int endPos = (unicodeCharsLen - startPos > addCount) ?
(startPos + addCount) : unicodeCharsLen;
sb.append(sUnicodeChars, startPos, endPos);
startPos = (endPos == unicodeCharsLen) ? 0 : endPos;
}
assertEquals(len, sb.length());
String testStr = sb.toString();
values[0] = sTestMsgCounts[i];
values[1] = len;
values[2] = sUnicodeUnitsRemaining[i];
values7bit[1] = len;
values7bit[2] = SmsConstants.MAX_USER_DATA_SEPTETS - len;
callGsmLengthMethods(testStr, false, values);
callCdmaLengthMethods(testStr, false, values);
callGsmLengthMethods(testStr, true, values7bit);
callCdmaLengthMethods(testStr, true, values7bit);
}
|
|