File indexing completed on 2024-04-21 14:54:24

0001 /*
0002     SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
0003     SPDX-License-Identifier: LGPL-2.0-or-later
0004 */
0005 
0006 #include "addressformat.h"
0007 #include "addressformatparser.cpp"
0008 #include "addressformatscript.cpp"
0009 #include "addressformatter.cpp"
0010 
0011 #include <KConfig>
0012 #include <KConfigGroup>
0013 #include <KCountry>
0014 
0015 #include <QObject>
0016 #include <QRegularExpression>
0017 #include <QTest>
0018 
0019 using namespace KContacts;
0020 
0021 void initLocale()
0022 {
0023     qputenv("LANGUAGE", "en_US");
0024     QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates));
0025 }
0026 
0027 Q_CONSTRUCTOR_FUNCTION(initLocale)
0028 
0029 class AddressFormatTest : public QObject
0030 {
0031     Q_OBJECT
0032 private:
0033     AddressFormat parseFormat(QStringView f, QStringView u, QStringView country)
0034     {
0035         AddressFormat format;
0036         auto fmt = AddressFormatPrivate::get(format);
0037         fmt->upper = AddressFormatParser::parseFields(u);
0038         fmt->elements = AddressFormatParser::parseElements(f);
0039         fmt->country = country.toString();
0040         return format;
0041     }
0042 
0043 private Q_SLOTS:
0044     void testRepostory()
0045     {
0046         auto fmt = AddressFormatRepository::formatForCountry(QStringLiteral("CA"), AddressFormatScriptPreference::Local);
0047         QCOMPARE(fmt.requiredFields(),
0048                  AddressFormatField::StreetAddress | AddressFormatField::Locality | AddressFormatField::PostalCode | AddressFormatField::Region);
0049         QCOMPARE(fmt.upperCaseFields(),
0050                  AddressFormatField::StreetAddress | AddressFormatField::Locality | AddressFormatField::PostalCode | AddressFormatField::Region
0051                      | AddressFormatField::Name | AddressFormatField::Organization | AddressFormatField::Country);
0052         QCOMPARE(fmt.usedFields(),
0053                  AddressFormatField::StreetAddress | AddressFormatField::Locality | AddressFormatField::PostalCode | AddressFormatField::Region
0054                      | AddressFormatField::Name | AddressFormatField::Organization | AddressFormatField::PostOfficeBox);
0055         const auto &elems = fmt.elements();
0056         QCOMPARE(elems.size(), 14);
0057 
0058         QCOMPARE(elems[0].isField(), true);
0059         QCOMPARE(elems[0].field(), AddressFormatField::Name);
0060         QCOMPARE(elems[1].isSeparator(), true);
0061         QCOMPARE(elems[2].isField(), true);
0062         QCOMPARE(elems[2].field(), AddressFormatField::Organization);
0063         QCOMPARE(elems[3].isSeparator(), true);
0064         QCOMPARE(elems[6].isLiteral(), true);
0065         QCOMPARE(elems[6].literal(), QLatin1String("PO BOX "));
0066         QCOMPARE(elems[9].isField(), true);
0067         QCOMPARE(elems[9].field(), AddressFormatField::Locality);
0068         QCOMPARE(elems[10].isLiteral(), true);
0069         QCOMPARE(elems[10].literal(), QLatin1String(" "));
0070         QCOMPARE(elems[11].isField(), true);
0071         QCOMPARE(elems[11].field(), AddressFormatField::Region);
0072         QCOMPARE(elems[12].isLiteral(), true);
0073         QCOMPARE(elems[12].literal(), QLatin1String(" "));
0074         QCOMPARE(elems[13].isField(), true);
0075         QCOMPARE(elems[13].field(), AddressFormatField::PostalCode);
0076 
0077         QVERIFY(!fmt.postalCodeRegularExpression().isEmpty());
0078         QCOMPARE(fmt.country(), QLatin1String("CA"));
0079     }
0080 
0081     void testFormatStyles()
0082     {
0083         Address addr;
0084         addr.setCountry(QStringLiteral("DE"));
0085         addr.setRegion(QStringLiteral("BE"));
0086         addr.setLocality(QStringLiteral("Berlin"));
0087         addr.setPostalCode(QStringLiteral("10969"));
0088         addr.setStreet(QStringLiteral("Prinzenstraße 85 F"));
0089         addr.setExtended(QStringLiteral("East wing"));
0090 
0091         auto fmt = parseFormat(u"%O%n%N%nPostfach %P%n%A%n%Z %C", u"R", u"DE");
0092         auto s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::Postal);
0093         QCOMPARE(s, QStringLiteral("KDE e.V.\nDr. Konqi\nEast wing\nPrinzenstraße 85 F\n10969 Berlin\n\nGERMANY"));
0094         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::MultiLineInternational);
0095         QCOMPARE(s, QStringLiteral("KDE e.V.\nDr. Konqi\nEast wing\nPrinzenstraße 85 F\n10969 Berlin\nGermany"));
0096         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::MultiLineDomestic);
0097         QCOMPARE(s, QStringLiteral("KDE e.V.\nDr. Konqi\nEast wing\nPrinzenstraße 85 F\n10969 Berlin"));
0098         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::SingleLineInternational);
0099         QCOMPARE(s, QStringLiteral("KDE e.V., Dr. Konqi, East wing, Prinzenstraße 85 F, 10969 Berlin, Germany"));
0100         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::SingleLineDomestic);
0101         QCOMPARE(s, QStringLiteral("KDE e.V., Dr. Konqi, East wing, Prinzenstraße 85 F, 10969 Berlin"));
0102         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::GeoUriQuery);
0103         QCOMPARE(s, QStringLiteral("Prinzenstraße 85 F,10969 Berlin,DE"));
0104 
0105         addr.setExtended(QString());
0106         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::Postal);
0107         QCOMPARE(s, QStringLiteral("KDE e.V.\nDr. Konqi\nPrinzenstraße 85 F\n10969 Berlin\n\nGERMANY"));
0108         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::MultiLineInternational);
0109         QCOMPARE(s, QStringLiteral("KDE e.V.\nDr. Konqi\nPrinzenstraße 85 F\n10969 Berlin\nGermany"));
0110         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::MultiLineDomestic);
0111         QCOMPARE(s, QStringLiteral("KDE e.V.\nDr. Konqi\nPrinzenstraße 85 F\n10969 Berlin"));
0112         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::SingleLineInternational);
0113         QCOMPARE(s, QStringLiteral("KDE e.V., Dr. Konqi, Prinzenstraße 85 F, 10969 Berlin, Germany"));
0114         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::SingleLineDomestic);
0115         QCOMPARE(s, QStringLiteral("KDE e.V., Dr. Konqi, Prinzenstraße 85 F, 10969 Berlin"));
0116         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::GeoUriQuery);
0117         QCOMPARE(s, QStringLiteral("Prinzenstraße 85 F,10969 Berlin,DE"));
0118 
0119         addr.setPostOfficeBox(QStringLiteral("42"));
0120         addr.setStreet(QString());
0121         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::Postal);
0122         QCOMPARE(s, QStringLiteral("KDE e.V.\nDr. Konqi\nPostfach 42\n10969 Berlin\n\nGERMANY"));
0123         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::MultiLineInternational);
0124         QCOMPARE(s, QStringLiteral("KDE e.V.\nDr. Konqi\nPostfach 42\n10969 Berlin\nGermany"));
0125         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::MultiLineDomestic);
0126         QCOMPARE(s, QStringLiteral("KDE e.V.\nDr. Konqi\nPostfach 42\n10969 Berlin"));
0127         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::SingleLineInternational);
0128         QCOMPARE(s, QStringLiteral("KDE e.V., Dr. Konqi, Postfach 42, 10969 Berlin, Germany"));
0129         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::SingleLineDomestic);
0130         QCOMPARE(s, QStringLiteral("KDE e.V., Dr. Konqi, Postfach 42, 10969 Berlin"));
0131         s = AddressFormatter::format(addr, QStringLiteral("Dr. Konqi"), QStringLiteral("KDE e.V."), fmt, AddressFormatStyle::GeoUriQuery);
0132         QCOMPARE(s, QStringLiteral("10969 Berlin,DE"));
0133     }
0134 
0135     void testFormatScript()
0136     {
0137         KContacts::Address address;
0138         address.setCountry(QStringLiteral("JP"));
0139         address.setRegion(QStringLiteral("東京"));
0140         address.setLocality(QStringLiteral("都港区"));
0141         address.setPostalCode(QStringLiteral("106-0047"));
0142         address.setStreet(QStringLiteral("南麻布 4-6-28"));
0143         auto fmt = parseFormat(u"〒%Z%n%S%C%A%n%O%n%N", u"SR", u"JP");
0144         auto s = AddressFormatter::format(address, QString(), QString(), fmt, AddressFormatStyle::SingleLineDomestic);
0145         QCOMPARE(s, QStringLiteral("〒106-0047東京都港区南麻布 4-6-28"));
0146 
0147         address = {};
0148         address.setCountry(QStringLiteral("EG"));
0149         address.setLocality(QStringLiteral("القاهرة"));
0150         address.setStreet(QStringLiteral("2005ج كورنيش النيل، رملة بولاق"));
0151         fmt = parseFormat(u"%N%n%O%n%A%n%C%n%S%n%Z", u"", u"EG");
0152         s = AddressFormatter::format(address, QString(), QString(), fmt, AddressFormatStyle::SingleLineDomestic);
0153         QCOMPARE(s, QStringLiteral("2005ج كورنيش النيل، رملة بولاق، القاهرة"));
0154 
0155         address = {};
0156         address.setCountry(QStringLiteral("KR"));
0157         address.setRegion(QStringLiteral("서울특별시"));
0158         address.setLocality(QStringLiteral("중구"));
0159         address.setPostalCode(QStringLiteral("04637"));
0160         address.setStreet(QStringLiteral("한강대로 416"));
0161         fmt = parseFormat(u"%R%n%S %C%D%n%A%n%O%n%N%n%Z", u"Z", u"KR");
0162         s = AddressFormatter::format(address, QString(), QString(), fmt, AddressFormatStyle::SingleLineDomestic);
0163         QCOMPARE(s, QStringLiteral("서울특별시 중구 한강대로 416 04637"));
0164         s = AddressFormatter::format(address, QString(), QString(), fmt, AddressFormatStyle::MultiLineDomestic);
0165         QCOMPARE(s, QStringLiteral("서울특별시 중구\n한강대로 416\n04637"));
0166         // the weird language mix is because we are in the wrong locale for KR here,
0167         // the important part is that the country is in the front when using Hangul
0168         s = AddressFormatter::format(address, QString(), QString(), fmt, AddressFormatStyle::SingleLineInternational);
0169         QCOMPARE(s, QStringLiteral("Korea, Republic of 서울특별시 중구 한강대로 416 04637"));
0170         s = AddressFormatter::format(address, QString(), QString(), fmt, AddressFormatStyle::MultiLineInternational);
0171         QCOMPARE(s, QStringLiteral("Korea, Republic of\n서울특별시 중구\n한강대로 416\n04637"));
0172 
0173         // reverse order address lines
0174         address.setExtended(QStringLiteral("서울스퀘어 11층"));
0175         s = AddressFormatter::format(address, QString(), QString(), fmt, AddressFormatStyle::SingleLineDomestic);
0176         QCOMPARE(s, QStringLiteral("서울특별시 중구 한강대로 416 서울스퀘어 11층 04637"));
0177         s = AddressFormatter::format(address, QString(), QString(), fmt, AddressFormatStyle::MultiLineDomestic);
0178         QCOMPARE(s, QStringLiteral("서울특별시 중구\n한강대로 416\n서울스퀘어 11층\n04637"));
0179     }
0180 
0181     void testIncompleteAddress()
0182     {
0183         KContacts::Address address;
0184         address.setLocality(QStringLiteral("City"));
0185         address.setPostalCode(QStringLiteral("XX 12345")); // region wrongly part of postal code field
0186 
0187         auto fmt = parseFormat(u"%C, %S %Z", u"", u"US");
0188         auto s = AddressFormatter::format(address, QString(), QString(), fmt, AddressFormatStyle::MultiLineDomestic);
0189         QCOMPARE(s, QLatin1String("City XX 12345"));
0190     }
0191 
0192     void validateRepository()
0193     {
0194         KConfig config(QStringLiteral(":/org.kde.kcontacts/addressformatrc"), KConfig::SimpleConfig);
0195         const auto groups = config.groupList();
0196 
0197         for (const auto &countryCode : groups) {
0198             // qDebug() << countryCode;
0199             QVERIFY(KCountry::fromAlpha2(countryCode).isValid());
0200             const auto group = config.group(countryCode);
0201 
0202             QVERIFY(group.hasKey("AddressFormat"));
0203             const auto upper = AddressFormatParser::parseFields(group.readEntry("Upper"));
0204             const auto required = AddressFormatParser::parseFields(group.readEntry("Required"));
0205 
0206             // TODO can we check all language variants as well?
0207             for (const auto &key : {"AddressFormat", "BusinessAddressFormat", "LatinAddressFormat", "LatinBusinessAddressFormat"}) {
0208                 if (!group.hasKey(key)) {
0209                     continue;
0210                 }
0211                 const auto elems = AddressFormatParser::parseElements(group.readEntry(key, QString()));
0212 
0213                 AddressFormatFields seen = AddressFormatField::NoField;
0214                 for (const auto &elem : elems) {
0215                     if (!elem.isField()) {
0216                         continue;
0217                     }
0218                     QCOMPARE(seen & elem.field() & ~(int)AddressFormatField::SortingCode, 0);
0219                     seen |= elem.field();
0220                 }
0221 
0222                 QCOMPARE(seen & required, required);
0223                 QCOMPARE(seen & upper & ~(int)AddressFormatField::Country, upper & ~(int)AddressFormatField::Country);
0224             }
0225 
0226             const auto zipRegEx = group.readEntry("PostalCodeFormat", QString());
0227             if (!zipRegEx.isEmpty()) {
0228                 QVERIFY(QRegularExpression(zipRegEx).isValid());
0229             }
0230         }
0231     }
0232 };
0233 
0234 QTEST_GUILESS_MAIN(AddressFormatTest)
0235 
0236 #include "addressformattest.moc"