Match contacts with many phone numbers
Also adds testing for some back-end of the SMS app
This commit is contained in:
parent
bc978309ef
commit
a5a0c16b61
6 changed files with 416 additions and 23 deletions
|
@ -2,15 +2,42 @@ qt5_add_resources(KCSMS_SRCS resources.qrc)
|
||||||
|
|
||||||
find_package(KF5People)
|
find_package(KF5People)
|
||||||
|
|
||||||
add_executable(kdeconnect-sms
|
add_library(kdeconnectsms
|
||||||
main.cpp
|
|
||||||
conversationmodel.cpp
|
conversationmodel.cpp
|
||||||
conversationlistmodel.cpp
|
conversationlistmodel.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(kdeconnectsms PROPERTIES
|
||||||
|
VERSION ${KDECONNECT_VERSION}
|
||||||
|
SOVERSION ${KDECONNECT_VERSION_MAJOR}
|
||||||
|
)
|
||||||
|
|
||||||
|
generate_export_header(kdeconnectsms EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/kdeconnectsms_export.h BASE_NAME KDEConnectSmsAppLib)
|
||||||
|
target_include_directories(kdeconnectsms PUBLIC ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
# If ever this library is actually used by someone else, we should export these headers
|
||||||
|
target_link_libraries(kdeconnectsms
|
||||||
|
LINK_PRIVATE
|
||||||
|
Qt5::Quick
|
||||||
|
Qt5::Widgets
|
||||||
|
KF5::People
|
||||||
|
kdeconnectinterfaces
|
||||||
|
)
|
||||||
|
|
||||||
|
set(libkdeconnectsms_HEADERS
|
||||||
|
conversationmodel.h
|
||||||
|
conversationlistmodel.h
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/kdeconnectsms_export.h
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(kdeconnect-sms
|
||||||
|
main.cpp
|
||||||
${KCSMS_SRCS})
|
${KCSMS_SRCS})
|
||||||
|
|
||||||
target_include_directories(kdeconnect-sms PUBLIC ${CMAKE_BINARY_DIR})
|
target_include_directories(kdeconnect-sms PUBLIC ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
target_link_libraries(kdeconnect-sms
|
target_link_libraries(kdeconnect-sms
|
||||||
|
kdeconnectsms
|
||||||
kdeconnectinterfaces
|
kdeconnectinterfaces
|
||||||
Qt5::Quick
|
Qt5::Quick
|
||||||
Qt5::Widgets
|
Qt5::Widgets
|
||||||
|
@ -21,4 +48,5 @@ target_link_libraries(kdeconnect-sms
|
||||||
)
|
)
|
||||||
|
|
||||||
install(TARGETS kdeconnect-sms ${INSTALL_TARGETS_DEFAULT_ARGS})
|
install(TARGETS kdeconnect-sms ${INSTALL_TARGETS_DEFAULT_ARGS})
|
||||||
|
install(TARGETS kdeconnectsms ${INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP)
|
||||||
install(PROGRAMS org.kde.kdeconnect.sms.desktop DESTINATION ${KDE_INSTALL_APPDIR})
|
install(PROGRAMS org.kde.kdeconnect.sms.desktop DESTINATION ${KDE_INSTALL_APPDIR})
|
||||||
|
|
|
@ -21,12 +21,16 @@
|
||||||
|
|
||||||
#include "conversationlistmodel.h"
|
#include "conversationlistmodel.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include "interfaces/conversationmessage.h"
|
#include "interfaces/conversationmessage.h"
|
||||||
#include "interfaces/dbusinterfaces.h"
|
#include "interfaces/dbusinterfaces.h"
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(KDECONNECT_SMS_CONVERSATIONS_LIST_MODEL, "kdeconnect.sms.conversations_list")
|
Q_LOGGING_CATEGORY(KDECONNECT_SMS_CONVERSATIONS_LIST_MODEL, "kdeconnect.sms.conversations_list")
|
||||||
|
|
||||||
|
OurSortFilterProxyModel::OurSortFilterProxyModel(){}
|
||||||
|
OurSortFilterProxyModel::~OurSortFilterProxyModel(){}
|
||||||
|
|
||||||
ConversationListModel::ConversationListModel(QObject* parent)
|
ConversationListModel::ConversationListModel(QObject* parent)
|
||||||
: QStandardItemModel(parent)
|
: QStandardItemModel(parent)
|
||||||
, m_conversationsInterface(nullptr)
|
, m_conversationsInterface(nullptr)
|
||||||
|
@ -179,21 +183,24 @@ KPeople::PersonData* ConversationListModel::lookupPersonByAddress(const QString&
|
||||||
const QString& uri = m_people.get(rowIndex, KPeople::PersonsModel::PersonUriRole).toString();
|
const QString& uri = m_people.get(rowIndex, KPeople::PersonsModel::PersonUriRole).toString();
|
||||||
KPeople::PersonData* person = new KPeople::PersonData(uri);
|
KPeople::PersonData* person = new KPeople::PersonData(uri);
|
||||||
|
|
||||||
const QString& email = person->email();
|
const QStringList& allEmails = person->allEmails();
|
||||||
const QString& phoneNumber = canonicalizePhoneNumber(person->contactCustomProperty("phoneNumber").toString());
|
for (const QString& email : allEmails) {
|
||||||
|
// Although we are nominally an SMS messaging app, it is possible to send messages to phone numbers using email -> sms bridges
|
||||||
|
if (address == email) {
|
||||||
|
return person;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// To decide if a phone number matches:
|
// TODO: Either upgrade KPeople with an allPhoneNumbers method
|
||||||
// 1. Are they similar lengths? If two numbers are very different, probably one is junk data and should be ignored
|
const QVariantList allPhoneNumbers = person->contactCustomProperty(QStringLiteral("all-phoneNumber")).toList();
|
||||||
// 2. Is one a superset of the other? Phone number digits get more specific the further towards the end of the string,
|
for (const QVariant& rawPhoneNumber : allPhoneNumbers) {
|
||||||
// so if one phone number ends with the other, it is probably just a more-complete version of the same thing
|
const QString& phoneNumber = canonicalizePhoneNumber(rawPhoneNumber.toString());
|
||||||
const QString& longerNumber = canonicalAddress.length() >= phoneNumber.length() ? canonicalAddress : phoneNumber;
|
bool matchingPhoneNumber = isPhoneNumberMatchCanonicalized(canonicalAddress, phoneNumber);
|
||||||
const QString& shorterNumber = canonicalAddress.length() < phoneNumber.length() ? canonicalAddress : phoneNumber;
|
|
||||||
|
|
||||||
bool matchingPhoneNumber = longerNumber.endsWith(shorterNumber) && shorterNumber.length() * 2 >= longerNumber.length();
|
if (matchingPhoneNumber) {
|
||||||
|
//qCDebug(KDECONNECT_SMS_CONVERSATIONS_LIST_MODEL) << "Matched" << address << "to" << person->name();
|
||||||
if (address == email || matchingPhoneNumber) {
|
return person;
|
||||||
//qCDebug(KDECONNECT_SMS_CONVERSATIONS_LIST_MODEL) << "Matched" << address << "to" << person->name();
|
}
|
||||||
return person;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete person;
|
delete person;
|
||||||
|
@ -202,6 +209,73 @@ KPeople::PersonData* ConversationListModel::lookupPersonByAddress(const QString&
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ConversationListModel::isPhoneNumberMatchCanonicalized(const QString& canonicalPhone1, const QString& canonicalPhone2)
|
||||||
|
{
|
||||||
|
// To decide if a phone number matches:
|
||||||
|
// 1. Are they similar lengths? If two numbers are very different, probably one is junk data and should be ignored
|
||||||
|
// 2. Is one a superset of the other? Phone number digits get more specific the further towards the end of the string,
|
||||||
|
// so if one phone number ends with the other, it is probably just a more-complete version of the same thing
|
||||||
|
const QString& longerNumber = canonicalPhone1.length() >= canonicalPhone2.length() ? canonicalPhone1 : canonicalPhone2;
|
||||||
|
const QString& shorterNumber = canonicalPhone1.length() < canonicalPhone2.length() ? canonicalPhone1 : canonicalPhone2;
|
||||||
|
|
||||||
|
const CountryCode& country = determineCountryCode(longerNumber);
|
||||||
|
|
||||||
|
const bool shorterNumberIsShortCode = isShortCode(shorterNumber, country);
|
||||||
|
const bool longerNumberIsShortCode = isShortCode(longerNumber, country);
|
||||||
|
|
||||||
|
if ((shorterNumberIsShortCode && !longerNumberIsShortCode) || (!shorterNumberIsShortCode && longerNumberIsShortCode)) {
|
||||||
|
// If only one of the numbers is a short code, they clearly do not match
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matchingPhoneNumber = longerNumber.endsWith(shorterNumber);
|
||||||
|
|
||||||
|
return matchingPhoneNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConversationListModel::isPhoneNumberMatch(const QString& phone1, const QString& phone2)
|
||||||
|
{
|
||||||
|
const QString& canonicalPhone1 = canonicalizePhoneNumber(phone1);
|
||||||
|
const QString& canonicalPhone2 = canonicalizePhoneNumber(phone2);
|
||||||
|
|
||||||
|
return ConversationListModel::isPhoneNumberMatchCanonicalized(canonicalPhone1, canonicalPhone2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConversationListModel::isShortCode(const QString& phoneNumber, const ConversationListModel::CountryCode& country)
|
||||||
|
{
|
||||||
|
// Regardless of which country this number belongs to, a number of length less than 6 is a "short code"
|
||||||
|
if (phoneNumber.length() <= 6) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (country == CountryCode::Australia && phoneNumber.length() == 8 && phoneNumber.startsWith("19")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (country == CountryCode::CzechRepublic && phoneNumber.length() <= 9) {
|
||||||
|
// This entry of the Wikipedia article is fairly poorly written, so it is not clear whether a
|
||||||
|
// short code with length 7 should start with a 9. Leave it like this for now, upgrade as
|
||||||
|
// we get more information
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConversationListModel::CountryCode ConversationListModel::determineCountryCode(const QString& canonicalNumber)
|
||||||
|
{
|
||||||
|
// This is going to fall apart if someone has not entered a country code into their contact book
|
||||||
|
// or if Android decides it can't be bothered to report the country code, but probably we will
|
||||||
|
// be fine anyway
|
||||||
|
if (canonicalNumber.startsWith("41")) {
|
||||||
|
return CountryCode::Australia;
|
||||||
|
}
|
||||||
|
if (canonicalNumber.startsWith("420")) {
|
||||||
|
return CountryCode::CzechRepublic;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The only countries I care about for the current implementation are Australia and CzechRepublic
|
||||||
|
// If we need to deal with further countries, we should probably find a library
|
||||||
|
return CountryCode::Other;
|
||||||
|
}
|
||||||
|
|
||||||
QString ConversationListModel::canonicalizePhoneNumber(const QString& phoneNumber)
|
QString ConversationListModel::canonicalizePhoneNumber(const QString& phoneNumber)
|
||||||
{
|
{
|
||||||
QString toReturn(phoneNumber);
|
QString toReturn(phoneNumber);
|
||||||
|
|
|
@ -31,10 +31,12 @@
|
||||||
#include "interfaces/conversationmessage.h"
|
#include "interfaces/conversationmessage.h"
|
||||||
#include "interfaces/dbusinterfaces.h"
|
#include "interfaces/dbusinterfaces.h"
|
||||||
|
|
||||||
|
#include "kdeconnectsms_export.h"
|
||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_SMS_CONVERSATIONS_LIST_MODEL)
|
Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_SMS_CONVERSATIONS_LIST_MODEL)
|
||||||
|
|
||||||
|
|
||||||
class OurSortFilterProxyModel : public QSortFilterProxyModel, public QQmlParserStatus
|
class KDECONNECTSMSAPPLIB_EXPORT OurSortFilterProxyModel : public QSortFilterProxyModel, public QQmlParserStatus
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_INTERFACES(QQmlParserStatus)
|
Q_INTERFACES(QQmlParserStatus)
|
||||||
|
@ -54,6 +56,9 @@ public:
|
||||||
sortNow();
|
sortNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OurSortFilterProxyModel();
|
||||||
|
~OurSortFilterProxyModel();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void sortNow() {
|
void sortNow() {
|
||||||
if (m_completed && dynamicSortFilter())
|
if (m_completed && dynamicSortFilter())
|
||||||
|
@ -64,7 +69,7 @@ private:
|
||||||
Qt::SortOrder m_sortOrder = Qt::AscendingOrder;
|
Qt::SortOrder m_sortOrder = Qt::AscendingOrder;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConversationListModel
|
class KDECONNECTSMSAPPLIB_EXPORT ConversationListModel
|
||||||
: public QStandardItemModel
|
: public QStandardItemModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -83,9 +88,42 @@ public:
|
||||||
};
|
};
|
||||||
Q_ENUM(Roles)
|
Q_ENUM(Roles)
|
||||||
|
|
||||||
|
enum CountryCode {
|
||||||
|
Australia,
|
||||||
|
CzechRepublic,
|
||||||
|
Other, // I only care about a few country codes
|
||||||
|
};
|
||||||
|
|
||||||
QString deviceId() const { return m_deviceId; }
|
QString deviceId() const { return m_deviceId; }
|
||||||
void setDeviceId(const QString &/*deviceId*/);
|
void setDeviceId(const QString &/*deviceId*/);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true to indicate the two phone numbers should be considered the same, false otherwise
|
||||||
|
*/
|
||||||
|
static bool isPhoneNumberMatch(const QString& phone1, const QString& phone2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true to indicate the two phone numbers should be considered the same, false otherwise
|
||||||
|
* Requires canonicalized phone numbers as inputs
|
||||||
|
*/
|
||||||
|
static bool isPhoneNumberMatchCanonicalized(const QString& canonicalPhone1, const QString& canonicalPhone2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See inline comments for how short codes are determined
|
||||||
|
* All information from https://en.wikipedia.org/wiki/Short_code
|
||||||
|
*/
|
||||||
|
static bool isShortCode(const QString& canonicalNumber, const CountryCode& country);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to guess the country code from the passed number
|
||||||
|
*/
|
||||||
|
static CountryCode determineCountryCode(const QString& canonicalNumber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simplify a phone number to a known form
|
||||||
|
*/
|
||||||
|
static QString canonicalizePhoneNumber(const QString& phoneNumber);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void handleCreatedConversation(const QVariantMap& msg);
|
void handleCreatedConversation(const QVariantMap& msg);
|
||||||
void handleConversationUpdated(const QVariantMap& msg);
|
void handleConversationUpdated(const QVariantMap& msg);
|
||||||
|
@ -106,11 +144,6 @@ private:
|
||||||
*/
|
*/
|
||||||
KPeople::PersonData* lookupPersonByAddress(const QString& address);
|
KPeople::PersonData* lookupPersonByAddress(const QString& address);
|
||||||
|
|
||||||
/**
|
|
||||||
* Simplify a phone number to a known form
|
|
||||||
*/
|
|
||||||
QString canonicalizePhoneNumber(const QString& phoneNumber);
|
|
||||||
|
|
||||||
QStandardItem* conversationForThreadId(qint32 threadId);
|
QStandardItem* conversationForThreadId(qint32 threadId);
|
||||||
|
|
||||||
DeviceConversationsDbusInterface* m_conversationsInterface;
|
DeviceConversationsDbusInterface* m_conversationsInterface;
|
||||||
|
|
|
@ -28,11 +28,13 @@
|
||||||
|
|
||||||
#include "interfaces/dbusinterfaces.h"
|
#include "interfaces/dbusinterfaces.h"
|
||||||
|
|
||||||
|
#include "kdeconnectsms_export.h"
|
||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_SMS_CONVERSATION_MODEL)
|
Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_SMS_CONVERSATION_MODEL)
|
||||||
|
|
||||||
#define INVALID_THREAD_ID -1
|
#define INVALID_THREAD_ID -1
|
||||||
|
|
||||||
class ConversationModel
|
class KDECONNECTSMSAPPLIB_EXPORT ConversationModel
|
||||||
: public QStandardItemModel
|
: public QStandardItemModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
|
@ -5,6 +5,7 @@ include_directories(
|
||||||
${CMAKE_SOURCE_DIR}
|
${CMAKE_SOURCE_DIR}
|
||||||
${CMAKE_BINARY_DIR}
|
${CMAKE_BINARY_DIR}
|
||||||
${CMAKE_BINARY_DIR}/plugins/sendnotifications/
|
${CMAKE_BINARY_DIR}/plugins/sendnotifications/
|
||||||
|
${CMAKE_BINARY_DIR}/smsapp/
|
||||||
)
|
)
|
||||||
|
|
||||||
set(kdeconnect_libraries
|
set(kdeconnect_libraries
|
||||||
|
@ -17,6 +18,14 @@ set(kdeconnect_libraries
|
||||||
qca-qt5
|
qca-qt5
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(kdeconnect_sms_libraries
|
||||||
|
${kdeconnect_libraries}
|
||||||
|
kdeconnectinterfaces
|
||||||
|
kdeconnectsms
|
||||||
|
Qt5::Quick
|
||||||
|
KF5::People
|
||||||
|
)
|
||||||
|
|
||||||
ecm_add_test(pluginloadtest.cpp LINK_LIBRARIES ${kdeconnect_libraries})
|
ecm_add_test(pluginloadtest.cpp LINK_LIBRARIES ${kdeconnect_libraries})
|
||||||
ecm_add_test(sendfiletest.cpp LINK_LIBRARIES ${kdeconnect_libraries})
|
ecm_add_test(sendfiletest.cpp LINK_LIBRARIES ${kdeconnect_libraries})
|
||||||
ecm_add_test(networkpackettests.cpp LINK_LIBRARIES ${kdeconnect_libraries})
|
ecm_add_test(networkpackettests.cpp LINK_LIBRARIES ${kdeconnect_libraries})
|
||||||
|
@ -31,3 +40,4 @@ ecm_add_test(testnotificationlistener.cpp
|
||||||
../plugins/sendnotifications/notifyingapplication.cpp
|
../plugins/sendnotifications/notifyingapplication.cpp
|
||||||
TEST_NAME testnotificationlistener
|
TEST_NAME testnotificationlistener
|
||||||
LINK_LIBRARIES ${kdeconnect_libraries} Qt5::DBus KF5::Notifications KF5::IconThemes)
|
LINK_LIBRARIES ${kdeconnect_libraries} Qt5::DBus KF5::Notifications KF5::IconThemes)
|
||||||
|
ecm_add_test(testconversationlistmodel.cpp LINK_LIBRARIES ${kdeconnect_sms_libraries})
|
||||||
|
|
246
tests/testconversationlistmodel.cpp
Normal file
246
tests/testconversationlistmodel.cpp
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2019 Simon Redman <simon@ergotech.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "conversationlistmodel.h"
|
||||||
|
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class tests the working of device class
|
||||||
|
*/
|
||||||
|
class ConversationListModelTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
|
||||||
|
void testSimplePhoneMatch();
|
||||||
|
void testMessyPhoneMatch();
|
||||||
|
void testMissingCountryCode();
|
||||||
|
void testLeadingZeros();
|
||||||
|
void testLongDistancePhoneNumber();
|
||||||
|
void testShortCodePhoneNumberNonMatch();
|
||||||
|
void testShortCodeMatch();
|
||||||
|
void testShortCodeNonMatch();
|
||||||
|
void testAustralianShortCodeNumberNonMatch();
|
||||||
|
void testAustralianShortCodeMatch();
|
||||||
|
void testAustralianShortCodeNonMatch();
|
||||||
|
void testCzechRepublicShortCodeNumberNonMatch();
|
||||||
|
void testCzechRepublicShortCodeMatch();
|
||||||
|
void testCzechRepublicShortCodeNonMatch();
|
||||||
|
void testDifferentPhoneNumbers1();
|
||||||
|
void testDifferentPhoneNumbers2();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two phone numbers which are exactly the same should match
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testSimplePhoneMatch()
|
||||||
|
{
|
||||||
|
const QString& phoneNumber = QLatin1String("+1 (222) 333-4444");
|
||||||
|
|
||||||
|
QVERIFY2(ConversationListModel::isPhoneNumberMatch(phoneNumber, phoneNumber),
|
||||||
|
"Failed to match a phone number with itself");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two phone numbers which have been entered with different formatting should match
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testMessyPhoneMatch()
|
||||||
|
{
|
||||||
|
const QString& phoneNumber = QLatin1String("12223334444");
|
||||||
|
const QString& messyPhoneNumber = QLatin1String("+1 (222) 333-4444");
|
||||||
|
|
||||||
|
QVERIFY2(ConversationListModel::isPhoneNumberMatch(phoneNumber, messyPhoneNumber),
|
||||||
|
"Failed to match same number with different formatting characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I don't think most people in the US even know what a country code *is*, and I know lots of people
|
||||||
|
* who don't enter it into their contacts book here. Make sure that kind of match works.
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testMissingCountryCode()
|
||||||
|
{
|
||||||
|
const QString& shortForm = QLatin1String("(222) 333-4444");
|
||||||
|
const QString& longForm = QLatin1String("+1 (222) 333-4444");
|
||||||
|
|
||||||
|
QVERIFY2(ConversationListModel::isPhoneNumberMatch(shortForm, longForm),
|
||||||
|
"Failed to match two same numbers with missing country code");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I don't quite understand which cases this applies, but sometimes you see a message where the
|
||||||
|
* country code has been prefixed with a few zeros. Make sure that works too.
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testLeadingZeros()
|
||||||
|
{
|
||||||
|
const QString& shortForm = QLatin1String("+1 (222) 333-4444");
|
||||||
|
const QString& zeroForm = QLatin1String("001 (222) 333-4444");
|
||||||
|
|
||||||
|
QVERIFY2(ConversationListModel::isPhoneNumberMatch(shortForm, zeroForm),
|
||||||
|
"Failed to match two same numbers with padded zeros");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* At least on my phone, it is possible to leave the area code and country code off but still have
|
||||||
|
* the phone call or text message go through. Some people's contacts books might be this way, so make
|
||||||
|
* sure we support matching that too
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testLongDistancePhoneNumber()
|
||||||
|
{
|
||||||
|
const QString& shortForm = QLatin1String("333-4444");
|
||||||
|
const QString& longForm = QLatin1String("+1 (222) 333-4444");
|
||||||
|
|
||||||
|
QVERIFY2(ConversationListModel::isPhoneNumberMatch(shortForm, longForm),
|
||||||
|
"Failed to suffix match two phone numbers");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Phone operators define short codes for a variety of reasons. Even if they have the same suffix,
|
||||||
|
* they should not match a regular phone number
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testShortCodePhoneNumberNonMatch()
|
||||||
|
{
|
||||||
|
const QString& shortCode = QLatin1String("44455");
|
||||||
|
const QString& normalNumber = QLatin1String("222-334-4455");
|
||||||
|
|
||||||
|
QVERIFY2(!ConversationListModel::isPhoneNumberMatch(shortCode, normalNumber),
|
||||||
|
"Short code matched with normal number");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two of the same short code should be able to match
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testShortCodeMatch()
|
||||||
|
{
|
||||||
|
const QString& shortCode = QLatin1String("44455");
|
||||||
|
QVERIFY2(ConversationListModel::isPhoneNumberMatch(shortCode, shortCode),
|
||||||
|
"Did not match two of the same short code");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two different short codes should not match
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testShortCodeNonMatch()
|
||||||
|
{
|
||||||
|
const QString& shortCode1 = QLatin1String("44455");
|
||||||
|
const QString& shortCode2 = QLatin1String("66677");
|
||||||
|
QVERIFY2(!ConversationListModel::isPhoneNumberMatch(shortCode1, shortCode2),
|
||||||
|
"Incorrectly matched two different short codes");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Even in the land down under, a short code phone number should not match a regular phone number
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testAustralianShortCodeNumberNonMatch()
|
||||||
|
{
|
||||||
|
const QString& australianShortCode = QLatin1String("19333444");
|
||||||
|
// I'm not sure if this is even a valid Australian phone number, but whatever...
|
||||||
|
const QString& australianPhoneNumber = QLatin1String("+41 02 1233 3444");
|
||||||
|
|
||||||
|
QVERIFY2(!ConversationListModel::isPhoneNumberMatch(australianShortCode, australianPhoneNumber),
|
||||||
|
"Matched Australian short code with regular phone number");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two of the same Australian short code numbers should be able to match
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testAustralianShortCodeMatch()
|
||||||
|
{
|
||||||
|
const QString& australianShortCode = QLatin1String("12333444");
|
||||||
|
|
||||||
|
QVERIFY2(ConversationListModel::isPhoneNumberMatch(australianShortCode, australianShortCode),
|
||||||
|
"Failed to match Australian short code number");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two different Australian short code numbers should be able to match
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testAustralianShortCodeNonMatch()
|
||||||
|
{
|
||||||
|
const QString& australianShortCode1 = QLatin1String("12333444");
|
||||||
|
const QString& australianShortCode2 = QLatin1String("12555666");
|
||||||
|
|
||||||
|
QVERIFY2(!ConversationListModel::isPhoneNumberMatch(australianShortCode1, australianShortCode2),
|
||||||
|
"Matched two different Australian short code numbers");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Czech Republic short code phone number should not match a regular phone number
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testCzechRepublicShortCodeNumberNonMatch()
|
||||||
|
{
|
||||||
|
const QString& czechRepShortCode = QLatin1String("9090930");
|
||||||
|
// I'm not sure if this is even a valid Czech Republic phone number, but whatever...
|
||||||
|
const QString& czechRepPhoneNumber = QLatin1String("+420 809 090 930");
|
||||||
|
|
||||||
|
QVERIFY2(!ConversationListModel::isPhoneNumberMatch(czechRepShortCode, czechRepPhoneNumber),
|
||||||
|
"Matched Czech Republic short code with regular phone number");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two of the same Czech Republic short code numbers should be able to match
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testCzechRepublicShortCodeMatch()
|
||||||
|
{
|
||||||
|
const QString& czechRepShortCode = QLatin1String("9090930");
|
||||||
|
|
||||||
|
QVERIFY2(ConversationListModel::isPhoneNumberMatch(czechRepShortCode, czechRepShortCode),
|
||||||
|
"Failed to match Czech Republic short code number");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two different Czech Republic short code numbers should be able to match
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testCzechRepublicShortCodeNonMatch()
|
||||||
|
{
|
||||||
|
const QString& czechRepShortCode1 = QLatin1String("9090930");
|
||||||
|
const QString& czechRepShortCode2 = QLatin1String("9080990");
|
||||||
|
|
||||||
|
QVERIFY2(!ConversationListModel::isPhoneNumberMatch(czechRepShortCode1, czechRepShortCode2),
|
||||||
|
"Matched two different Czech Republic short code numbers");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two phone numbers which are different should not be reported as the same
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testDifferentPhoneNumbers1()
|
||||||
|
{
|
||||||
|
const QString& phone1 = QLatin1String("+1 (222) 333-4444");
|
||||||
|
const QString& phone2 = QLatin1String("+1 (333) 222-4444");
|
||||||
|
|
||||||
|
QVERIFY2(!ConversationListModel::isPhoneNumberMatch(phone1, phone2),
|
||||||
|
"Incorrectly marked two different numbers as same");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two phone numbers which are different should not be reported as the same
|
||||||
|
*/
|
||||||
|
void ConversationListModelTest::testDifferentPhoneNumbers2()
|
||||||
|
{
|
||||||
|
const QString& phone1 = QLatin1String("+1 (222) 333-4444");
|
||||||
|
const QString& phone2 = QLatin1String("122-2333");
|
||||||
|
|
||||||
|
QVERIFY2(!ConversationListModel::isPhoneNumberMatch(phone1, phone2),
|
||||||
|
"Incorrectly *prefix* matched two phone numbers");
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_MAIN(ConversationListModelTest);
|
||||||
|
#include "testconversationlistmodel.moc"
|
Loading…
Reference in a new issue