/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include "../../placemanager_utils/placemanager_utils.h" QT_USE_NAMESPACE class tst_QPlaceManagerNokia : public PlaceManagerUtils { Q_OBJECT public: enum ExpectedResults { AnyResults, //zero or more results expected SomeResults, //at least one result expected NoResults // zero results expected }; tst_QPlaceManagerNokia(); private Q_SLOTS: void initTestCase(); void search(); void search_data(); void searchResultFields(); void recommendations(); void recommendations_data(); void details(); void categories(); void suggestions(); void suggestions_data(); void suggestionsMisc(); void locale(); void content(); void content_data(); void unsupportedFunctions(); private: void commonAreas(QList *dataTags, QList *areas, QList *errors, QList *results); static const QLatin1String ValidKnownPlaceId; static const QLatin1String ProxyEnv; static const QLatin1String AppIdEnv; static const QLatin1String TokenEnv; QGeoServiceProvider *provider; }; Q_DECLARE_METATYPE(tst_QPlaceManagerNokia::ExpectedResults) // ValidKnownPlaceId is the id of a place with a full complement of place content. Editorials, // reviews, images, recommendations. If it disappears these tests will fail. // Currently it is set to an Eiffel Tower tourist office. const QLatin1String tst_QPlaceManagerNokia::ValidKnownPlaceId("250u09tu-4561b8da952f4fd79c4e1998c3fcf032"); const QLatin1String tst_QPlaceManagerNokia::ProxyEnv("NOKIA_PLUGIN_PROXY"); const QLatin1String tst_QPlaceManagerNokia::AppIdEnv("NOKIA_APP_ID"); const QLatin1String tst_QPlaceManagerNokia::TokenEnv("NOKIA_TOKEN"); tst_QPlaceManagerNokia::tst_QPlaceManagerNokia() { } void tst_QPlaceManagerNokia::initTestCase() { QVariantMap params; QStringList providers = QGeoServiceProvider::availableServiceProviders(); QVERIFY(providers.contains("nokia")); #ifndef QT_NO_PROCESS QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); if (!(env.contains(AppIdEnv) && env.contains(TokenEnv))) QSKIP("NOKIA_APP_ID and NOKIA_TOKEN environment variables not set");\ params.insert(QStringLiteral("app_id"), env.value(AppIdEnv)); params.insert(QStringLiteral("token"), env.value(TokenEnv)); if (env.contains(ProxyEnv)) params.insert(QStringLiteral("proxy"), env.value(ProxyEnv)); #else QSKIP("Cannot parse process environment, NOKIA_APP_ID and NOKIA_TOKEN not set"); #endif provider = new QGeoServiceProvider("nokia", params); placeManager = provider->placeManager(); QVERIFY(placeManager); } void tst_QPlaceManagerNokia::search() { QFETCH(QGeoShape, area); QFETCH(QString, searchTerm); QFETCH(QList, categories); QFETCH(QPlaceReply::Error, error); QFETCH(ExpectedResults, expectedResults); QPlaceSearchRequest searchRequest; searchRequest.setSearchArea(area); searchRequest.setSearchTerm(searchTerm); if (categories.count() == 1) searchRequest.setCategory(categories.first()); else searchRequest.setCategories(categories); QList results; QVERIFY(doSearch(searchRequest, &results, error)); if (expectedResults == NoResults) QVERIFY(results.count() == 0); else if (expectedResults == SomeResults) QVERIFY(results.count() > 0); } void tst_QPlaceManagerNokia::search_data() { QTest::addColumn("area"); QTest::addColumn("searchTerm"); QTest::addColumn >("categories"); QTest::addColumn("hint"); QTest::addColumn ("error"); QTest::addColumn("expectedResults"); for (int i = 0; i < 3; i++) { QByteArray suffix; QGeoShape area; if (i==0) { area = QGeoCircle(QGeoCoordinate(-27.5, 153)); suffix = " (Circle - center only)"; } else if (i==1) { area = QGeoCircle(QGeoCoordinate(-27.5, 153), 5000); suffix = " (Circle - with radius specified)"; } else { area = QGeoRectangle(QGeoCoordinate(-26.5, 152), QGeoCoordinate(-28.5, 154)); suffix = " (Rectangle)"; } QByteArray dataTag = QByteArray("coordinate only") + suffix; QTest::newRow(dataTag) << area << QString() << QList() << QPlaceSearchRequest::UnspecifiedHint << QPlaceReply::NoError << SomeResults; dataTag = QByteArray("seach term") + suffix; QTest::newRow(dataTag) << area << "sushi" << QList() << QPlaceSearchRequest::UnspecifiedHint << QPlaceReply::NoError << SomeResults; QPlaceCategory eatDrinkCat; eatDrinkCat.setCategoryId(QStringLiteral("eat-drink")); dataTag = QByteArray("single valid category") + suffix; QTest::newRow(dataTag) << area << QString() << (QList() << eatDrinkCat) << QPlaceSearchRequest::UnspecifiedHint << QPlaceReply::NoError << SomeResults; QPlaceCategory accommodationCat; accommodationCat.setCategoryId(QStringLiteral("accommodation")); dataTag = QByteArray("multiple valid categories") + suffix; QTest::newRow(dataTag) << area << QString() << (QList() << eatDrinkCat << accommodationCat) << QPlaceSearchRequest::UnspecifiedHint << QPlaceReply::NoError << SomeResults; QPlaceCategory nonExistentCat; nonExistentCat.setCategoryId(QStringLiteral("klingon cuisine")); dataTag = QByteArray("non-existent category") + suffix; QTest::newRow(dataTag) << area << QString() << (QList() << nonExistentCat) << QPlaceSearchRequest::UnspecifiedHint << QPlaceReply::NoError << NoResults; dataTag = QByteArray("search term and category") + suffix; QTest::newRow(dataTag) << area << "sushi" << (QList() << eatDrinkCat) << QPlaceSearchRequest::UnspecifiedHint << QPlaceReply::BadArgumentError << NoResults; } //invalid areas and boundary testing QList dataTags; QList areas; QList errors; QList results; commonAreas(&dataTags, &areas, &errors, &results); for (int i = 0; i < dataTags.count(); ++i) { QTest::newRow(dataTags.at(i)) << areas.at(i) << "sushi" << QList() << QPlaceSearchRequest::UnspecifiedHint << errors.at(i) << results.at(i); } //relevancy hints will be ignored by the backend, but should give a valid result QTest::newRow("check using a distance relevancy hint") << static_cast(QGeoCircle(QGeoCoordinate(-27.5, 153))) << QStringLiteral("sushi") << QList() << QPlaceSearchRequest::DistanceHint << QPlaceReply::NoError << AnyResults; QTest::newRow("check using lexical place name hint") << static_cast(QGeoCircle(QGeoCoordinate(-27.5, 153))) << QStringLiteral("sushi") << QList() << QPlaceSearchRequest::LexicalPlaceNameHint << QPlaceReply::NoError << AnyResults; } void tst_QPlaceManagerNokia::searchResultFields() { //check that using a distance relevancy hint will give a valid result //even though it will be ignored by the backend. QPlaceSearchRequest searchRequest; searchRequest.setSearchArea(QGeoCircle(QGeoCoordinate(-27.5, 153))); searchRequest.setSearchTerm(QStringLiteral("sushi")); QPlaceSearchReply *reply = placeManager->search(searchRequest); QSignalSpy spy(reply, SIGNAL(finished())); QTRY_VERIFY_WITH_TIMEOUT(spy.count() == 1, Timeout); QVERIFY(reply->results().count() > 0); //check that search results have basic data filled in QPlaceResult result= reply->results().at(0); QVERIFY(!result.title().isEmpty()); QVERIFY(!result.icon().url().isEmpty()); QVERIFY(!qIsNaN(result.distance())); QVERIFY(!result.place().name().isEmpty()); QVERIFY(result.place().location().coordinate().isValid()); QVERIFY(!result.place().location().address().text().isEmpty()); QVERIFY(!result.place().location().address().isTextGenerated()); QVERIFY(result.place().categories().count() == 1);//only primary category retrieved on //search //sponsored and ratings fields are optional and thus have not been explicitly tested. } void tst_QPlaceManagerNokia::recommendations() { QFETCH(QString, recommendationId); QFETCH(QString, searchTerm); QFETCH(QGeoShape, searchArea); QFETCH(QList, categories); QFETCH(QPlaceReply::Error, error); QPlaceSearchRequest searchRequest; searchRequest.setRecommendationId(recommendationId); searchRequest.setSearchTerm(searchTerm); searchRequest.setSearchArea(searchArea); searchRequest.setCategories(categories); QList results; QVERIFY(doSearch(searchRequest, &results, error)); if (error == QPlaceReply::NoError) QVERIFY(results.count() > 0); } void tst_QPlaceManagerNokia::recommendations_data() { QTest::addColumn("recommendationId"); QTest::addColumn("searchTerm"); QTest::addColumn("searchArea"); QTest::addColumn >("categories"); QTest::addColumn("error"); QPlaceCategory eatDrinkCat; eatDrinkCat.setCategoryId(QStringLiteral("eat-drink")); QTest::newRow("search recommendations with valid id") << QString(ValidKnownPlaceId) << QString() << QGeoShape() << QList() << QPlaceReply::NoError; QTest::newRow("search for recommendations with invalid id") << QStringLiteral("does_not_exist_id") << QString() << QGeoShape() << QList() << QPlaceReply::PlaceDoesNotExistError; QTest::newRow("search for recommendations with id and search term") << QString(ValidKnownPlaceId) << QStringLiteral("sushi") << QGeoShape() << QList() << QPlaceReply::BadArgumentError; QTest::newRow("search for recommendations with an id and category") << QString(ValidKnownPlaceId) << QString() << QGeoShape() << (QList() << eatDrinkCat) << QPlaceReply::BadArgumentError; QTest::newRow("search for recommendations with id, search term and category") << QString(ValidKnownPlaceId) << QStringLiteral("sushi") << QGeoShape() << (QList() << eatDrinkCat) << QPlaceReply::BadArgumentError; QTest::newRow("search for recommendations with an id and search area") << QString(ValidKnownPlaceId) << QString() << static_cast(QGeoCircle(QGeoCoordinate(-27.5, 153))) << QList() << QPlaceReply::BadArgumentError; } void tst_QPlaceManagerNokia::details() { //fetch the details of a valid place QPlace place; QVERIFY(doFetchDetails(ValidKnownPlaceId, &place)); QVERIFY(!place.name().isEmpty()); QVERIFY(!place.icon().url().isEmpty()); QStringList contactTypes = place.contactTypes(); QVERIFY(!contactTypes.isEmpty()); foreach (const QString &contactType, contactTypes) { QList details = place.contactDetails(contactType); QVERIFY(details.count() > 0); foreach (const QPlaceContactDetail &detail, details) { QVERIFY(!detail.label().isEmpty()); QVERIFY(!detail.value().isEmpty()); } } QVERIFY(place.location().coordinate().isValid()); QVERIFY(!place.location().address().isEmpty()); QVERIFY(!place.location().address().text().isEmpty()); QVERIFY(!place.location().address().isTextGenerated()); QVERIFY(place.ratings().average() >= 1 && place.ratings().average() <= 5); QVERIFY(place.ratings().maximum() == 5); QVERIFY(place.ratings().count() > 0); QVERIFY(place.categories().count() > 0); foreach (const QPlaceCategory &category, place.categories()) { QVERIFY(!category.name().isEmpty()); QVERIFY(!category.categoryId().isEmpty()); QVERIFY(!category.icon().url().isEmpty()); } QVERIFY(!place.extendedAttributeTypes().isEmpty()); QVERIFY(place.visibility() == QLocation::PublicVisibility); QVERIFY(place.detailsFetched()); //attributions are optional and thus have not been explicitly tested. //fetch the details of a non-existent place QVERIFY(doFetchDetails(QStringLiteral("does_not_exist"), &place, QPlaceReply::PlaceDoesNotExistError)); } void tst_QPlaceManagerNokia::categories() { QVERIFY(doInitializeCategories()); QList categories = placeManager->childCategories(); QVERIFY(categories.count() > 0); foreach (const QPlaceCategory &category, categories) { //check that we have valid fields QVERIFY(!category.categoryId().isEmpty()); QVERIFY(!category.name().isEmpty()); QVERIFY(!category.icon().url().isEmpty()); //check we can retrieve the very same category by id QCOMPARE(placeManager->category(category.categoryId()), category); //since the nokia plugin only supports a single level category tree //check that there are no parent or children categories QVERIFY(placeManager->parentCategoryId(category.categoryId()).isEmpty()); QVERIFY(placeManager->childCategories(category.categoryId()).isEmpty()); } } void tst_QPlaceManagerNokia::suggestions() { QFETCH(QGeoShape, area); QFETCH(QString, searchTerm); QFETCH(QPlaceReply::Error, error); QFETCH(ExpectedResults, expectedResults); QPlaceSearchRequest searchRequest; searchRequest.setSearchArea(area); searchRequest.setSearchTerm(searchTerm); QStringList results; QVERIFY(doSearchSuggestions(searchRequest, &results, error)); if (expectedResults == NoResults) QVERIFY(results.count() == 0); else if (expectedResults == SomeResults) QVERIFY(results.count() > 0); } void tst_QPlaceManagerNokia::suggestions_data() { QTest::addColumn("area"); QTest::addColumn("searchTerm"); QTest::addColumn ("error"); QTest::addColumn("expectedResults"); for (int i = 0; i < 3; i++) { QByteArray suffix; QGeoShape area; if (i == 0) { area = QGeoCircle(QGeoCoordinate(-27.5, 153)); suffix = " (Circle - center only)"; } else if (i == 1) { area = QGeoCircle(QGeoCoordinate(-27.5, 153), 5000); suffix = " (Circle - with radius specified)"; } else { area = QGeoRectangle(QGeoCoordinate(-26.5, 152), QGeoCoordinate(-28.5, 154)); suffix = " (Rectangle)"; } QByteArray dataTag = QByteArray("valid usage") + suffix; QTest::newRow(dataTag) << area << "sus" << QPlaceReply::NoError << SomeResults; } //invalid areas and boundary testing QList dataTags; QList areas; QList errors; QList results; commonAreas(&dataTags, &areas, &errors, &results); for (int i = 0; i < dataTags.count(); ++i) { QTest::newRow(dataTags.at(i)) << areas.at(i) << "sus" << errors.at(i) << results.at(i); } QTest::newRow("no text") << static_cast(QGeoCircle(QGeoCoordinate(-27.5, 153))) << QString() << QPlaceReply::NoError << NoResults; } void tst_QPlaceManagerNokia::suggestionsMisc() { //check providing a distance relevancy hint (should be ignored) QPlaceSearchRequest searchRequest; QStringList results; searchRequest.setSearchArea(QGeoCircle(QGeoCoordinate(-27.5, 153))); searchRequest.setSearchTerm(QStringLiteral("sus")); searchRequest.setRelevanceHint(QPlaceSearchRequest::DistanceHint); QVERIFY(doSearchSuggestions(searchRequest, &results, QPlaceReply::NoError)); QVERIFY(results.count() > 0); searchRequest.clear(); //check porviding a lexical place name relevancy hint (should be ignored) searchRequest.setSearchArea(QGeoCircle(QGeoCoordinate(-27.5, 153))); searchRequest.setSearchTerm(QStringLiteral("sus")); searchRequest.setRelevanceHint(QPlaceSearchRequest::LexicalPlaceNameHint); QVERIFY(doSearchSuggestions(searchRequest, &results, QPlaceReply::NoError)); QVERIFY(results.count() > 0); searchRequest.clear(); //check providing a category QPlaceCategory eatDrinkCat; eatDrinkCat.setCategoryId(QStringLiteral("eat-drink")); searchRequest.setSearchArea(QGeoCircle(QGeoCoordinate(-27.5, 153))); searchRequest.setSearchTerm(QStringLiteral("sus")); searchRequest.setCategory(eatDrinkCat); QVERIFY(doSearchSuggestions(searchRequest, &results, QPlaceReply::BadArgumentError)); QCOMPARE(results.count(), 0); searchRequest.clear(); //check providing a recommendation id searchRequest.setSearchArea(QGeoCircle(QGeoCoordinate(-27.5, 153))); searchRequest.setSearchTerm(QStringLiteral("sus")); searchRequest.setRecommendationId("id"); QVERIFY(doSearchSuggestions(searchRequest, &results, QPlaceReply::BadArgumentError)); } void tst_QPlaceManagerNokia::locale() { //check that the defualt locale is set QCOMPARE(placeManager->locales().count(), 1); QCOMPARE(placeManager->locales().at(0), QLocale()); //check that we can set different locales for the categories placeManager->setLocale(QLocale("en")); QVERIFY(doInitializeCategories()); QList enCategories = placeManager->childCategories(); QVERIFY(enCategories.count() > 0); placeManager->setLocale(QLocale("fi")); QVERIFY(doInitializeCategories()); QList fiCategories = placeManager->childCategories(); foreach (const QPlaceCategory enCat, enCategories) { foreach (const QPlaceCategory fiCat, fiCategories) { if (enCat.categoryId() == fiCat.categoryId()) { QVERIFY(fiCat.name() != enCat.name()); QVERIFY(fiCat == placeManager->category(fiCat.categoryId())); } } } //check that setting a locale will affect place detail fetches. QPlace place; placeManager->setLocale(QLocale("en")); QVERIFY(doFetchDetails(ValidKnownPlaceId, &place)); QString englishName = place.name(); placeManager->setLocale(QLocale("fr")); QVERIFY(doFetchDetails(ValidKnownPlaceId, &place)); QVERIFY(englishName != place.name()); } void tst_QPlaceManagerNokia::content() { QFETCH(QPlaceContent::Type, type); //check fetching of content QPlaceContentRequest request; request.setContentType(type); request.setPlaceId(ValidKnownPlaceId); QPlaceContent::Collection results; QVERIFY(doFetchContent(request, &results)); QVERIFY(results.count() > 0); QMapIterator iter(results); while (iter.hasNext()) { iter.next(); switch (type) { case (QPlaceContent::ImageType): { QPlaceImage image = iter.value(); QVERIFY(!image.url().isEmpty()); break; } case (QPlaceContent::ReviewType) : { QPlaceReview review = iter.value(); QVERIFY(!review.dateTime().isValid()); QVERIFY(!review.text().isEmpty()); QVERIFY(review.rating() >= 1 && review.rating() <= 5); //title and language fields are optional and thus have not been //explicitly tested break; } case (QPlaceContent::EditorialType): { QPlaceEditorial editorial = iter.value(); QVERIFY(!editorial.text().isEmpty()); //The language field is optional and thus has not been //explicitly tested. break; } default: QFAIL("Unknown content type"); } } //check total count QPlaceContentReply *contentReply = placeManager->getPlaceContent(request); QSignalSpy contentSpy(contentReply, SIGNAL(finished())); QTRY_VERIFY_WITH_TIMEOUT(contentSpy.count() ==1, Timeout); QVERIFY(contentReply->totalCount() > 0); if (contentReply->totalCount() >= 2) { //try testing with a limit request.setLimit(1); QPlaceContent::Collection newResults; QVERIFY(doFetchContent(request, &newResults)); QCOMPARE(newResults.count(), 1); QCOMPARE(newResults.values().first(), results.value(0)); } } void tst_QPlaceManagerNokia::content_data() { QTest::addColumn("type"); QTest::newRow("images") << QPlaceContent::ImageType; QTest::newRow("reviews") << QPlaceContent::ReviewType; QTest::newRow("editorials") << QPlaceContent::EditorialType; } void tst_QPlaceManagerNokia::unsupportedFunctions() { QPlace place; place.setName(QStringLiteral("Brisbane")); QVERIFY(doSavePlace(place, QPlaceReply::UnsupportedError)); QVERIFY(doRemovePlace(place, QPlaceReply::UnsupportedError)); QPlaceCategory category; category.setName(QStringLiteral("Accommodation")); QVERIFY(doSaveCategory(category, QPlaceReply::UnsupportedError)); QVERIFY(doRemoveCategory(category, QPlaceReply::UnsupportedError)); } void tst_QPlaceManagerNokia::commonAreas(QList *dataTags, QList *areas, QList *errors, QList *results) { Q_ASSERT(dataTags); Q_ASSERT(areas); dataTags->append("Unknown shape for search area"); areas->append(QGeoShape()); errors->append(QPlaceReply::BadArgumentError); results->append(NoResults); dataTags->append("NaN coordinate"); areas->append(QGeoCircle(QGeoCoordinate())); errors->append(QPlaceReply::BadArgumentError); results->append(NoResults); dataTags->append("Valid latitude (upper boundary)"); areas->append(QGeoCircle(QGeoCoordinate(90.0, 45))); errors->append(QPlaceReply::NoError); results->append(AnyResults); dataTags->append("Invalid latitude (upper boundary)"); areas->append(QGeoCircle(QGeoCoordinate(90.1, 45))); errors->append(QPlaceReply::BadArgumentError); results->append(NoResults); dataTags->append("Valid latitude (lower boundary)"); areas->append(QGeoCircle(QGeoCoordinate(-90.0, 45))); errors->append(QPlaceReply::NoError); results->append(AnyResults); dataTags->append("Invalid latitude (lower boundary)"); areas->append(QGeoCircle(QGeoCoordinate(-90.1, 45))); errors->append(QPlaceReply::BadArgumentError); results->append(NoResults); dataTags->append("Valid longitude (lower boundary)"); areas->append(QGeoCircle(QGeoCoordinate(-45, -180.0))); errors->append(QPlaceReply::NoError); results->append(AnyResults); dataTags->append("Invalid longitude (lower boundary)"); areas->append(QGeoCircle(QGeoCoordinate(-45, -180.1))); errors->append(QPlaceReply::BadArgumentError); results->append(NoResults); dataTags->append("Valid longitude (upper boundary)"); areas->append(QGeoCircle(QGeoCoordinate(-45, 180.0))); errors->append(QPlaceReply::NoError); results->append(AnyResults); dataTags->append("Invalid longitude (upper boundary)"); areas->append(QGeoCircle(QGeoCoordinate(-45, 180.1))); errors->append(QPlaceReply::BadArgumentError); results->append(NoResults); dataTags->append("Invalid rectangular area"); areas->append(QGeoRectangle(QGeoCoordinate(20,20), QGeoCoordinate(30,10))); errors->append(QPlaceReply::BadArgumentError); results->append(NoResults); } QTEST_GUILESS_MAIN(tst_QPlaceManagerNokia) #include "tst_places.moc"