diff options
author | Jean-Baptiste Queru <jbq@google.com> | 2012-07-02 14:48:44 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-07-02 14:48:44 -0700 |
commit | 5709f43dd80ed9e3264eaca098f05d9e59c8b937 (patch) | |
tree | c61c0419156f2dce4fdfd469f7cff140cc7138c1 /telephony | |
parent | 3cd92d8faa9fd345d5bfc0d794e28449d4f6c810 (diff) | |
parent | a02bce1d5b3aafe359465eceaf3fd2a5b5b3918e (diff) | |
download | frameworks_base-5709f43dd80ed9e3264eaca098f05d9e59c8b937.zip frameworks_base-5709f43dd80ed9e3264eaca098f05d9e59c8b937.tar.gz frameworks_base-5709f43dd80ed9e3264eaca098f05d9e59c8b937.tar.bz2 |
Merge "Revert "DO NOT MERGE: Remove SMS shortcode warning feature."" into jb-dev-plus-aosp
Diffstat (limited to 'telephony')
3 files changed, 839 insertions, 9 deletions
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java index 07d733e..c5af396 100644 --- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -906,18 +906,61 @@ public abstract class SMSDispatcher extends Handler { SmsTracker tracker = new SmsTracker(map, sentIntent, deliveryIntent, appPackage, PhoneNumberUtils.extractNetworkPortion(destAddr)); - // check for excessive outgoing SMS usage by this app - if (!mUsageMonitor.check(appPackage, SINGLE_PART_SMS)) { - sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker)); - return; - } + // checkDestination() returns true if the destination is not a premium short code or the + // sending app is approved to send to short codes. Otherwise, a message is sent to our + // handler with the SmsTracker to request user confirmation before sending. + if (checkDestination(tracker)) { + // check for excessive outgoing SMS usage by this app + if (!mUsageMonitor.check(appPackage, SINGLE_PART_SMS)) { + sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker)); + return; + } - int ss = mPhone.getServiceState().getState(); + int ss = mPhone.getServiceState().getState(); - if (ss != ServiceState.STATE_IN_SERVICE) { - handleNotInService(ss, tracker.mSentIntent); + if (ss != ServiceState.STATE_IN_SERVICE) { + handleNotInService(ss, tracker.mSentIntent); + } else { + sendSms(tracker); + } + } + } + + /** + * Check if destination is a potential premium short code and sender is not pre-approved to + * send to short codes. + * + * @param tracker the tracker for the SMS to send + * @return true if the destination is approved; false if user confirmation event was sent + */ + boolean checkDestination(SmsTracker tracker) { + if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION_PERMISSION) + == PackageManager.PERMISSION_GRANTED) { + return true; // app is pre-approved to send to short codes } else { - sendSms(tracker); + String countryIso = mTelephonyManager.getSimCountryIso(); + if (countryIso == null || countryIso.length() != 2) { + Log.e(TAG, "Can't get SIM country code: trying network country code"); + countryIso = mTelephonyManager.getNetworkCountryIso(); + } + + switch (mUsageMonitor.checkDestination(tracker.mDestAddress, countryIso)) { + case SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE: + sendMessage(obtainMessage(EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE, + tracker)); + return false; // wait for user confirmation before sending + + case SmsUsageMonitor.CATEGORY_PREMIUM_SHORT_CODE: + sendMessage(obtainMessage(EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE, + tracker)); + return false; // wait for user confirmation before sending + + case SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE: + case SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE: + case SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE: + default: + return true; // destination is not a premium short code + } } } diff --git a/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java b/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java index 4a4485d..1804d97 100644 --- a/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java +++ b/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java @@ -60,17 +60,177 @@ public class SmsUsageMonitor { /** Default number of SMS sent in checking period without user permission. */ private static final int DEFAULT_SMS_MAX_COUNT = 30; + /** Return value from {@link #checkDestination} for regular phone numbers. */ + static final int CATEGORY_NOT_SHORT_CODE = 0; + + /** Return value from {@link #checkDestination} for free (no cost) short codes. */ + static final int CATEGORY_FREE_SHORT_CODE = 1; + + /** Return value from {@link #checkDestination} for standard rate (non-premium) short codes. */ + static final int CATEGORY_STANDARD_SHORT_CODE = 2; + + /** Return value from {@link #checkDestination} for possible premium short codes. */ + static final int CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE = 3; + + /** Return value from {@link #checkDestination} for premium short codes. */ + static final int CATEGORY_PREMIUM_SHORT_CODE = 4; + private final int mCheckPeriod; private final int mMaxAllowed; private final HashMap<String, ArrayList<Long>> mSmsStamp = new HashMap<String, ArrayList<Long>>(); + /** Context for retrieving regexes from XML resource. */ + private final Context mContext; + + /** Country code for the cached short code pattern matcher. */ + private String mCurrentCountry; + + /** Cached short code pattern matcher for {@link #mCurrentCountry}. */ + private ShortCodePatternMatcher mCurrentPatternMatcher; + + /** Cached short code regex patterns from secure settings for {@link #mCurrentCountry}. */ + private String mSettingsShortCodePatterns; + + /** Handler for responding to content observer updates. */ + private final SettingsObserverHandler mSettingsObserverHandler; + + /** XML tag for root element. */ + private static final String TAG_SHORTCODES = "shortcodes"; + + /** XML tag for short code patterns for a specific country. */ + private static final String TAG_SHORTCODE = "shortcode"; + + /** XML attribute for the country code. */ + private static final String ATTR_COUNTRY = "country"; + + /** XML attribute for the short code regex pattern. */ + private static final String ATTR_PATTERN = "pattern"; + + /** XML attribute for the premium short code regex pattern. */ + private static final String ATTR_PREMIUM = "premium"; + + /** XML attribute for the free short code regex pattern. */ + private static final String ATTR_FREE = "free"; + + /** XML attribute for the standard rate short code regex pattern. */ + private static final String ATTR_STANDARD = "standard"; + + /** + * SMS short code regex pattern matcher for a specific country. + */ + private static final class ShortCodePatternMatcher { + private final Pattern mShortCodePattern; + private final Pattern mPremiumShortCodePattern; + private final Pattern mFreeShortCodePattern; + private final Pattern mStandardShortCodePattern; + + ShortCodePatternMatcher(String shortCodeRegex, String premiumShortCodeRegex, + String freeShortCodeRegex, String standardShortCodeRegex) { + mShortCodePattern = (shortCodeRegex != null ? Pattern.compile(shortCodeRegex) : null); + mPremiumShortCodePattern = (premiumShortCodeRegex != null ? + Pattern.compile(premiumShortCodeRegex) : null); + mFreeShortCodePattern = (freeShortCodeRegex != null ? + Pattern.compile(freeShortCodeRegex) : null); + mStandardShortCodePattern = (standardShortCodeRegex != null ? + Pattern.compile(standardShortCodeRegex) : null); + } + + int getNumberCategory(String phoneNumber) { + if (mFreeShortCodePattern != null && mFreeShortCodePattern.matcher(phoneNumber) + .matches()) { + return CATEGORY_FREE_SHORT_CODE; + } + if (mStandardShortCodePattern != null && mStandardShortCodePattern.matcher(phoneNumber) + .matches()) { + return CATEGORY_STANDARD_SHORT_CODE; + } + if (mPremiumShortCodePattern != null && mPremiumShortCodePattern.matcher(phoneNumber) + .matches()) { + return CATEGORY_PREMIUM_SHORT_CODE; + } + if (mShortCodePattern != null && mShortCodePattern.matcher(phoneNumber).matches()) { + return CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE; + } + return CATEGORY_NOT_SHORT_CODE; + } + } + + /** + * Observe the secure setting for updated regex patterns. + */ + private static class SettingsObserver extends ContentObserver { + private final int mWhat; + private final Handler mHandler; + + SettingsObserver(Handler handler, int what) { + super(handler); + mHandler = handler; + mWhat = what; + } + + @Override + public void onChange(boolean selfChange) { + mHandler.obtainMessage(mWhat).sendToTarget(); + } + } + + /** + * Handler to update regex patterns when secure setting for the current country is updated. + */ + private class SettingsObserverHandler extends Handler { + /** Current content observer, or null. */ + SettingsObserver mSettingsObserver; + + /** Current country code to watch for settings updates. */ + private String mCountryIso; + + /** Request to start observing a secure setting. */ + static final int OBSERVE_SETTING = 1; + + /** Handler event for updated secure settings. */ + static final int SECURE_SETTINGS_CHANGED = 2; + + /** Send a message to this handler requesting to observe the setting for a new country. */ + void observeSettingForCountry(String countryIso) { + obtainMessage(OBSERVE_SETTING, countryIso).sendToTarget(); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case OBSERVE_SETTING: + if (msg.obj != null && msg.obj instanceof String) { + mCountryIso = (String) msg.obj; + String settingName = getSettingNameForCountry(mCountryIso); + ContentResolver resolver = mContext.getContentResolver(); + + if (mSettingsObserver != null) { + if (VDBG) log("Unregistering old content observer"); + resolver.unregisterContentObserver(mSettingsObserver); + } + + mSettingsObserver = new SettingsObserver(this, SECURE_SETTINGS_CHANGED); + resolver.registerContentObserver( + Settings.Secure.getUriFor(settingName), false, mSettingsObserver); + if (VDBG) log("Registered content observer for " + settingName); + } + break; + + case SECURE_SETTINGS_CHANGED: + loadPatternsFromSettings(mCountryIso); + break; + } + } + } + /** * Create SMS usage monitor. * @param context the context to use to load resources and get TelephonyManager service */ public SmsUsageMonitor(Context context) { + mContext = context; ContentResolver resolver = context.getContentResolver(); mMaxAllowed = Settings.Secure.getInt(resolver, @@ -80,6 +240,83 @@ public class SmsUsageMonitor { mCheckPeriod = Settings.Secure.getInt(resolver, Settings.Secure.SMS_OUTGOING_CHECK_INTERVAL_MS, DEFAULT_SMS_CHECK_PERIOD); + + mSettingsObserverHandler = new SettingsObserverHandler(); + } + + /** + * Return a pattern matcher object for the specified country. + * @param country the country to search for + * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found + */ + private ShortCodePatternMatcher getPatternMatcher(String country) { + int id = com.android.internal.R.xml.sms_short_codes; + XmlResourceParser parser = mContext.getResources().getXml(id); + + try { + return getPatternMatcher(country, parser); + } catch (XmlPullParserException e) { + Log.e(TAG, "XML parser exception reading short code pattern resource", e); + } catch (IOException e) { + Log.e(TAG, "I/O exception reading short code pattern resource", e); + } finally { + parser.close(); + } + return null; // country not found + } + + /** + * Return a pattern matcher object for the specified country from a secure settings string. + * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found + */ + private static ShortCodePatternMatcher getPatternMatcher(String country, String settingsPattern) { + // embed pattern tag into an XML document. + String document = "<shortcodes>" + settingsPattern + "</shortcodes>"; + if (VDBG) log("loading updated patterns from: " + document); + + try { + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + XmlPullParser parser = factory.newPullParser(); + parser.setInput(new StringReader(document)); + return getPatternMatcher(country, parser); + } catch (XmlPullParserException e) { + Log.e(TAG, "XML parser exception reading short code pattern from settings", e); + } catch (IOException e) { + Log.e(TAG, "I/O exception reading short code pattern from settings", e); + } + return null; // country not found + } + + /** + * Return a pattern matcher object for the specified country and pattern XML parser. + * @param country the country to search for + * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found + */ + private static ShortCodePatternMatcher getPatternMatcher(String country, XmlPullParser parser) + throws XmlPullParserException, IOException + { + XmlUtils.beginDocument(parser, TAG_SHORTCODES); + + while (true) { + XmlUtils.nextElement(parser); + + String element = parser.getName(); + if (element == null) break; + + if (element.equals(TAG_SHORTCODE)) { + String currentCountry = parser.getAttributeValue(null, ATTR_COUNTRY); + if (country.equals(currentCountry)) { + String pattern = parser.getAttributeValue(null, ATTR_PATTERN); + String premium = parser.getAttributeValue(null, ATTR_PREMIUM); + String free = parser.getAttributeValue(null, ATTR_FREE); + String standard = parser.getAttributeValue(null, ATTR_STANDARD); + return new ShortCodePatternMatcher(pattern, premium, free, standard); + } + } else { + Log.e(TAG, "Error: skipping unknown XML tag " + element); + } + } + return null; // country not found } /** Clear the SMS application list for disposal. */ @@ -112,6 +349,90 @@ public class SmsUsageMonitor { } /** + * Check if the destination is a possible premium short code. + * NOTE: the caller is expected to strip non-digits from the destination number with + * {@link PhoneNumberUtils#extractNetworkPortion} before calling this method. + * This happens in {@link SMSDispatcher#sendRawPdu} so that we use the same phone number + * for testing and in the user confirmation dialog if the user needs to confirm the number. + * This makes it difficult for malware to fool the user or the short code pattern matcher + * by using non-ASCII characters to make the number appear to be different from the real + * destination phone number. + * + * @param destAddress the destination address to test for possible short code + * @return {@link #CATEGORY_NOT_SHORT_CODE}, {@link #CATEGORY_FREE_SHORT_CODE}, + * {@link #CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE}, or {@link #CATEGORY_PREMIUM_SHORT_CODE}. + */ + public int checkDestination(String destAddress, String countryIso) { + synchronized (mSettingsObserverHandler) { + // always allow emergency numbers + if (PhoneNumberUtils.isEmergencyNumber(destAddress, countryIso)) { + return CATEGORY_NOT_SHORT_CODE; + } + + ShortCodePatternMatcher patternMatcher = null; + + if (countryIso != null) { + // query secure settings and initialize content observer for updated regex patterns + if (mCurrentCountry == null || !countryIso.equals(mCurrentCountry)) { + loadPatternsFromSettings(countryIso); + mSettingsObserverHandler.observeSettingForCountry(countryIso); + } + + if (countryIso.equals(mCurrentCountry)) { + patternMatcher = mCurrentPatternMatcher; + } else { + patternMatcher = getPatternMatcher(countryIso); + mCurrentCountry = countryIso; + mCurrentPatternMatcher = patternMatcher; // may be null if not found + } + } + + if (patternMatcher != null) { + return patternMatcher.getNumberCategory(destAddress); + } else { + // Generic rule: numbers of 5 digits or less are considered potential short codes + Log.e(TAG, "No patterns for \"" + countryIso + "\": using generic short code rule"); + if (destAddress.length() <= 5) { + return CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE; + } else { + return CATEGORY_NOT_SHORT_CODE; + } + } + } + } + + private static String getSettingNameForCountry(String countryIso) { + return Settings.Secure.SMS_SHORT_CODES_PREFIX + countryIso; + } + + /** + * Load regex patterns from secure settings if present. + * @param countryIso the country to search for + */ + void loadPatternsFromSettings(String countryIso) { + synchronized (mSettingsObserverHandler) { + if (VDBG) log("loadPatternsFromSettings(" + countryIso + ") called"); + String settingsPatterns = Settings.Secure.getString( + mContext.getContentResolver(), getSettingNameForCountry(countryIso)); + if (settingsPatterns != null && !settingsPatterns.equals( + mSettingsShortCodePatterns)) { + // settings pattern string has changed: update the pattern matcher + mSettingsShortCodePatterns = settingsPatterns; + ShortCodePatternMatcher matcher = getPatternMatcher(countryIso, settingsPatterns); + if (matcher != null) { + mCurrentCountry = countryIso; + mCurrentPatternMatcher = matcher; + } + } else if (settingsPatterns == null && mSettingsShortCodePatterns != null) { + // pattern string was removed: caller will load default patterns from XML resource + mCurrentCountry = null; + mCurrentPatternMatcher = null; + mSettingsShortCodePatterns = null; + } + } + } + + /** * Remove keys containing only old timestamps. This can happen if an SMS app is used * to send messages and then uninstalled. */ diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/SmsUsageMonitorShortCodeTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SmsUsageMonitorShortCodeTest.java new file mode 100644 index 0000000..3bb7c06 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/SmsUsageMonitorShortCodeTest.java @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE; +import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE; +import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE; +import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_PREMIUM_SHORT_CODE; +import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE; + +/** + * Test cases for SMS short code pattern matching in SmsUsageMonitor. + */ +public class SmsUsageMonitorShortCodeTest extends AndroidTestCase { + + private static final class ShortCodeTest { + final String countryIso; + final String address; + final int category; + + ShortCodeTest(String countryIso, String destAddress, int category) { + this.countryIso = countryIso; + this.address = destAddress; + this.category = category; + } + } + + /** + * List of short code test cases. + */ + private static final ShortCodeTest[] sShortCodeTests = new ShortCodeTest[] { + new ShortCodeTest("al", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("al", "4321", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("al", "54321", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("al", "15191", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("al", "55500", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("al", "55600", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("al", "654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("am", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("am", "101", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("am", "102", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("am", "103", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("am", "222", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("am", "1111", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("am", "9999", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("am", "1121", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("am", "1141", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("am", "1161", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("am", "3024", CATEGORY_PREMIUM_SHORT_CODE), + + new ShortCodeTest("at", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("at", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("at", "0901234", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("at", "0900666266", CATEGORY_PREMIUM_SHORT_CODE), + + new ShortCodeTest("au", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("au", "180000", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("au", "190000", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("au", "1900000", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("au", "19000000", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("au", "19998882", CATEGORY_PREMIUM_SHORT_CODE), + + new ShortCodeTest("az", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("az", "1234", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("az", "12345", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("az", "87744", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("az", "3301", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("az", "3302", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("az", "9012", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("az", "9014", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("az", "9394", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("az", "87744", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("az", "93101", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("az", "123456", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("be", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("be", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("be", "567890", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("be", "8000", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("be", "6566", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("be", "7777", CATEGORY_PREMIUM_SHORT_CODE), + + new ShortCodeTest("bg", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("bg", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("bg", "1234", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("bg", "12345", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("bg", "1816", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("bg", "1915", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("bg", "1916", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("bg", "1935", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("bg", "18423", CATEGORY_PREMIUM_SHORT_CODE), + + new ShortCodeTest("by", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("by", "1234", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("by", "3336", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("by", "5013", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("by", "5014", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("by", "7781", CATEGORY_PREMIUM_SHORT_CODE), + + new ShortCodeTest("ca", "911", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ca", "+18005551234", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ca", "8005551234", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ca", "20000", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ca", "200000", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ca", "2000000", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ca", "60999", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ca", "88188", CATEGORY_PREMIUM_SHORT_CODE), + + new ShortCodeTest("ch", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ch", "123", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ch", "234", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ch", "3456", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ch", "98765", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ch", "543", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ch", "83111", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ch", "234567", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ch", "87654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("cn", "120", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("cn", "1062503000", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("cn", "1065123456", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("cn", "1066335588", CATEGORY_PREMIUM_SHORT_CODE), + + new ShortCodeTest("cy", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("cy", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("cy", "4321", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("cy", "54321", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("cy", "654321", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("cy", "7510", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("cy", "987654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("cz", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("cz", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("cz", "9090150", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("cz", "90901599", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("cz", "987654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("de", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("de", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("de", "1234", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "12345", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "8888", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "11111", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "11886", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "22022", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "23300", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "3434", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "34567", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "41414", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "55655", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "66766", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "66777", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "77677", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "80888", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "1232286", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("de", "987654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("dk", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("dk", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("dk", "1259", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("dk", "16123", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("dk", "987654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("ee", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ee", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("ee", "123", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ee", "1259", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ee", "15330", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ee", "17999", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ee", "17010", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ee", "17013", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ee", "9034567", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ee", "34567890", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("es", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("es", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("es", "25165", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("es", "27333", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("es", "995399", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("es", "87654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("fi", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("fi", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("fi", "12345", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("fi", "123456", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("fi", "17159", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("fi", "17163", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("fi", "0600123", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("fi", "070012345", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("fi", "987654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("fr", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("fr", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("fr", "34567", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("fr", "45678", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("fr", "81185", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("fr", "87654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("gb", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("gb", "999", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("gb", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("gb", "4567", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("gb", "45678", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("gb", "56789", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("gb", "79067", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("gb", "80079", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("gb", "654321", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("gb", "7654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("ge", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ge", "8765", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ge", "2345", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ge", "8012", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ge", "8013", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ge", "8014", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ge", "8889", CATEGORY_PREMIUM_SHORT_CODE), + + new ShortCodeTest("gr", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("gr", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("gr", "54321", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("gr", "19567", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("gr", "19678", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("gr", "87654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("hu", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("hu", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("hu", "012", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("hu", "0123", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("hu", "1234", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("hu", "1784", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("hu", "2345", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("hu", "01234", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("hu", "012345678", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("hu", "0123456789", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("hu", "1234567890", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("hu", "0691227910", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("hu", "2345678901", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("hu", "01234567890", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("ie", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ie", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("ie", "50123", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("ie", "51234", CATEGORY_STANDARD_SHORT_CODE), + new ShortCodeTest("ie", "52345", CATEGORY_STANDARD_SHORT_CODE), + new ShortCodeTest("ie", "57890", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ie", "67890", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ie", "87654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("il", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("il", "5432", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("il", "4422", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("il", "4545", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("il", "98765", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("it", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("it", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("it", "4567", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("it", "48000", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("it", "45678", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("it", "56789", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("it", "456789", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("kg", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("kg", "5432", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("kg", "4152", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("kg", "4157", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("kg", "4449", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("kg", "98765", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("kz", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("kz", "5432", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("kz", "9194", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("kz", "7790", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("kz", "98765", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("lt", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("lt", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("lt", "123", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("lt", "1234", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("lt", "1381", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("lt", "1394", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("lt", "1645", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("lt", "12345", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("lt", "123456", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("lu", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("lu", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("lu", "1234", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("lu", "12345", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("lu", "64747", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("lu", "678901", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("lv", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("lv", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("lv", "5432", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("lv", "1819", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("lv", "1863", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("lv", "1874", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("lv", "98765", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("mx", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("mx", "2345", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("mx", "7766", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("mx", "23456", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("mx", "53035", CATEGORY_PREMIUM_SHORT_CODE), + + new ShortCodeTest("my", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("my", "1234", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("my", "23456", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("my", "32298", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("my", "33776", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("my", "345678", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("nl", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("nl", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("nl", "1234", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("nl", "4466", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("nl", "5040", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("nl", "23456", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("no", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("no", "1234", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("no", "2201", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("no", "2226", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("no", "2227", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("no", "23456", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("no", "234567", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("nz", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("nz", "123", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("nz", "2345", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("nz", "3903", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("nz", "8995", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("nz", "23456", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("pl", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("pl", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("pl", "7890", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("pl", "34567", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("pl", "7910", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("pl", "74240", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("pl", "79866", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("pl", "92525", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("pl", "87654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("pt", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("pt", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("pt", "61000", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("pt", "62345", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("pt", "68304", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("pt", "69876", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("pt", "87654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("ro", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ro", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("ro", "1234", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ro", "1263", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ro", "1288", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ro", "1314", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ro", "1380", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ro", "7890", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ro", "12345", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("ru", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ru", "5432", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ru", "1161", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ru", "2097", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ru", "3933", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ru", "7781", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ru", "98765", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("se", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("se", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("se", "1234", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("se", "72345", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("se", "72999", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("se", "123456", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("se", "87654321", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("sg", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("sg", "1234", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("sg", "70000", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("sg", "79999", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("sg", "73800", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("sg", "74688", CATEGORY_STANDARD_SHORT_CODE), + new ShortCodeTest("sg", "987654", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("si", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("si", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("si", "1234", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("si", "3838", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("si", "72999", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("sk", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("sk", "116117", CATEGORY_FREE_SHORT_CODE), + new ShortCodeTest("sk", "1234", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("sk", "6674", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("sk", "7604", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("sk", "72999", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("tj", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("tj", "5432", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("tj", "1161", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("tj", "1171", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("tj", "4161", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("tj", "4449", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("tj", "98765", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("ua", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("ua", "5432", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("ua", "4448", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ua", "7094", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ua", "7540", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("ua", "98765", CATEGORY_NOT_SHORT_CODE), + + new ShortCodeTest("us", "911", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("us", "+18005551234", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("us", "8005551234", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("us", "20000", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("us", "200000", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("us", "2000000", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("us", "20433", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("us", "21472", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("us", "23333", CATEGORY_PREMIUM_SHORT_CODE), + new ShortCodeTest("us", "99807", CATEGORY_PREMIUM_SHORT_CODE), + + // generic rules for other countries: 5 digits or less considered potential short code + new ShortCodeTest("zz", "2000000", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest("zz", "54321", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("zz", "4321", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("zz", "321", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest("zz", "112", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest(null, "2000000", CATEGORY_NOT_SHORT_CODE), + new ShortCodeTest(null, "54321", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest(null, "4321", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest(null, "321", CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE), + new ShortCodeTest(null, "112", CATEGORY_NOT_SHORT_CODE), + }; + + @SmallTest + public void testSmsUsageMonitor() { + SmsUsageMonitor monitor = new SmsUsageMonitor(getContext()); + for (ShortCodeTest test : sShortCodeTests) { + assertEquals("country: " + test.countryIso + " number: " + test.address, + test.category, monitor.checkDestination(test.address, test.countryIso)); + } + } +} |