[search] Added SearchParams.m_categorialRequest for *pure* category results.

Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
This commit is contained in:
Viktor Govako 2022-06-12 15:00:33 +03:00
parent 7b38901608
commit 39073aad1b
28 changed files with 174 additions and 118 deletions

View file

@ -290,12 +290,13 @@ extern "C"
}
JNIEXPORT jboolean JNICALL Java_com_mapswithme_maps_search_SearchEngine_nativeRunSearch(
JNIEnv * env, jclass clazz, jbyteArray bytes, jstring lang, jlong timestamp,
jboolean hasPosition, jdouble lat, jdouble lon)
JNIEnv * env, jclass clazz, jbyteArray bytes, jboolean isCategory,
jstring lang, jlong timestamp, jboolean hasPosition, jdouble lat, jdouble lon)
{
search::EverywhereSearchParams params;
params.m_query = jni::ToNativeString(env, bytes);
params.m_inputLocale = jni::ToNativeString(env, lang);
params.m_isCategory = isCategory;
params.m_onResults = bind(&OnResults, _1, _2, timestamp, false, hasPosition, lat, lon);
bool const searchStarted = g_framework->NativeFramework()->GetSearchAPI().SearchEverywhere(params);
if (searchStarted)
@ -304,12 +305,13 @@ extern "C"
}
JNIEXPORT void JNICALL Java_com_mapswithme_maps_search_SearchEngine_nativeRunInteractiveSearch(
JNIEnv * env, jclass clazz, jbyteArray bytes, jstring lang, jlong timestamp,
jboolean isMapAndTable)
JNIEnv * env, jclass clazz, jbyteArray bytes, jboolean isCategory,
jstring lang, jlong timestamp, jboolean isMapAndTable)
{
search::ViewportSearchParams vparams;
vparams.m_query = jni::ToNativeString(env, bytes);
vparams.m_inputLocale = jni::ToNativeString(env, lang);
vparams.m_isCategory = isCategory;
// TODO (@alexzatsepin): set up vparams.m_onCompleted here and use
// HotelsClassifier for hotel queries detection.

View file

@ -280,7 +280,8 @@ class SearchWheel implements View.OnClickListener
{
mCurrentOption = searchOption;
final String query = mFrame.getContext().getString(searchOption.mQueryId);
SearchEngine.INSTANCE.searchInteractive(mFrame.getContext(), query, System.nanoTime(), false /* isMapAndTable */);
// Category request from navigation search wheel.
SearchEngine.INSTANCE.searchInteractive(mFrame.getContext(), query, true, System.nanoTime(), false);
SearchEngine.INSTANCE.setQuery(query);
refreshSearchButtonImage();
toggleSearchLayout();

View file

@ -127,25 +127,26 @@ public enum SearchEngine implements NativeSearchListener,
* @return whether search was actually started.
*/
@MainThread
public boolean search(@NonNull Context context, String query, long timestamp, boolean hasLocation,
double lat, double lon)
public boolean search(@NonNull Context context, String query, boolean isCategory,
long timestamp, boolean hasLocation, double lat, double lon)
{
return nativeRunSearch(query.getBytes(StandardCharsets.UTF_8), Language.getKeyboardLocale(context),
timestamp, hasLocation, lat, lon);
return nativeRunSearch(query.getBytes(StandardCharsets.UTF_8), isCategory,
Language.getKeyboardLocale(context), timestamp, hasLocation, lat, lon);
}
@MainThread
public void searchInteractive(@NonNull String query, @NonNull String locale, long timestamp,
boolean isMapAndTable)
public void searchInteractive(@NonNull String query, boolean isCategory, @NonNull String locale,
long timestamp, boolean isMapAndTable)
{
nativeRunInteractiveSearch(query.getBytes(StandardCharsets.UTF_8), locale, timestamp, isMapAndTable);
nativeRunInteractiveSearch(query.getBytes(StandardCharsets.UTF_8), isCategory,
locale, timestamp, isMapAndTable);
}
@MainThread
public void searchInteractive(@NonNull Context context, @NonNull String query, long timestamp,
boolean isMapAndTable)
public void searchInteractive(@NonNull Context context, @NonNull String query, boolean isCategory,
long timestamp, boolean isMapAndTable)
{
searchInteractive(query, Language.getKeyboardLocale(context), timestamp, isMapAndTable);
searchInteractive(query, isCategory, Language.getKeyboardLocale(context), timestamp, isMapAndTable);
}
@MainThread
@ -223,13 +224,15 @@ public enum SearchEngine implements NativeSearchListener,
/**
* @param bytes utf-8 formatted bytes of query.
*/
private static native boolean nativeRunSearch(byte[] bytes, String language, long timestamp, boolean hasLocation,
private static native boolean nativeRunSearch(byte[] bytes, boolean isCategory,
String language, long timestamp, boolean hasLocation,
double lat, double lon);
/**
* @param bytes utf-8 formatted query bytes
*/
private static native void nativeRunInteractiveSearch(byte[] bytes, String language, long timestamp,
private static native void nativeRunInteractiveSearch(byte[] bytes, boolean isCategory,
String language, long timestamp,
boolean isMapAndTable);
/**

View file

@ -348,15 +348,9 @@ public class SearchFragment extends BaseMwmFragment
super.onDestroy();
}
private String getQuery()
{
return mToolbarController.getQuery();
}
void setQuery(String text)
{
mToolbarController.setQuery(text);
}
private String getQuery() { return mToolbarController.getQuery(); }
private boolean isCategory() { return mToolbarController.isCategory(); }
void setQuery(String text) { mToolbarController.setQuery(text); }
private void readArguments()
{
@ -436,12 +430,12 @@ public class SearchFragment extends BaseMwmFragment
mLastQueryTimestamp = System.nanoTime();
SearchEngine.INSTANCE.searchInteractive(
query, !TextUtils.isEmpty(mInitialLocale)
query, isCategory(), !TextUtils.isEmpty(mInitialLocale)
? mInitialLocale : com.mapswithme.util.Language.getKeyboardLocale(requireContext()),
mLastQueryTimestamp, false /* isMapAndTable */);
SearchEngine.INSTANCE.setQuery(query);
Utils.navigateToParent(getActivity());
}
private void onSearchEnd()
@ -479,12 +473,13 @@ public class SearchFragment extends BaseMwmFragment
mLastQueryTimestamp = System.nanoTime();
if (isTabletSearch())
{
SearchEngine.INSTANCE.searchInteractive(requireContext(), getQuery(), mLastQueryTimestamp, true /* isMapAndTable */);
SearchEngine.INSTANCE.searchInteractive(requireContext(), getQuery(), isCategory(),
mLastQueryTimestamp, true /* isMapAndTable */);
}
else
{
if (!SearchEngine.INSTANCE.search(requireContext(), getQuery(), mLastQueryTimestamp, mLastPosition.valid,
mLastPosition.lat, mLastPosition.lon))
if (!SearchEngine.INSTANCE.search(requireContext(), getQuery(), isCategory(),
mLastQueryTimestamp, mLastPosition.valid, mLastPosition.lat, mLastPosition.lon))
{
return;
}
@ -518,7 +513,7 @@ public class SearchFragment extends BaseMwmFragment
@Override
public void onSearchCategorySelected(@Nullable String category)
{
mToolbarController.setQuery(category);
mToolbarController.setQuery(category, true);
}
private void refreshSearchResults(@NonNull SearchResult[] results)

View file

@ -31,6 +31,7 @@ public class SearchToolbarController extends ToolbarController implements View.O
private final View mBack;
@NonNull
private final EditText mQuery;
private boolean mFromCategory = false;
@NonNull
private final View mProgress;
@NonNull
@ -157,13 +158,16 @@ public class SearchToolbarController extends ToolbarController implements View.O
{
return (UiUtils.isVisible(mSearchContainer) ? mQuery.getText().toString() : "");
}
public boolean isCategory() { return mFromCategory; }
public void setQuery(CharSequence query)
public void setQuery(CharSequence query, boolean fromCategory)
{
mFromCategory = fromCategory;
mQuery.setText(query);
if (!TextUtils.isEmpty(query))
mQuery.setSelection(query.length());
}
public void setQuery(CharSequence query) { setQuery(query, false); }
public void clear()
{

View file

@ -29,7 +29,8 @@ API_AVAILABLE(ios(12.0))
self.inputLocale = inputLocale;
self.lastResults = @[];
self.completionHandler = completionHandler;
[MWMSearch searchQuery:text forInputLocale:inputLocale];
/// @todo Didn't find pure category request in CarPlay.
[MWMSearch searchQuery:text forInputLocale:inputLocale withCategory:NO];
}
- (void)saveLastQuery {

View file

@ -106,7 +106,7 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
return NO;
self.searchManager.state = MWMSearchManagerStateTableSearch;
[self.searchManager searchText:text forInputLocale:locale];
[self.searchManager searchText:text forInputLocale:locale withCategory:NO];
return YES;
}

View file

@ -193,7 +193,8 @@ BOOL defaultOrientation(CGSize const &size) {
[MWMSearch setSearchOnMap:YES];
NSString *query = [kSearchButtonRequest.at(state) stringByAppendingString:@" "];
NSString *locale = [[AppInfo sharedInfo] languageId];
[MWMSearch searchQuery:query forInputLocale:locale];
// Category request from navigation search wheel.
[MWMSearch searchQuery:query forInputLocale:locale withCategory:YES];
[self setSearchState:state animated:YES];
};

View file

@ -14,7 +14,7 @@ struct ProductInfo;
+ (void)removeObserver:(id<MWMSearchObserver>)observer;
+ (void)saveQuery:(NSString *)query forInputLocale:(NSString *)inputLocale;
+ (void)searchQuery:(NSString *)query forInputLocale:(NSString *)inputLocale;
+ (void)searchQuery:(NSString *)query forInputLocale:(NSString *)inputLocale withCategory:(BOOL)isCategory;
+ (void)showResult:(search::Result const &)result;

View file

@ -132,7 +132,7 @@ using Observers = NSHashTable<Observer>;
GetFramework().GetSearchAPI().SaveSearchQuery(make_pair(locale, text));
}
+ (void)searchQuery:(NSString *)query forInputLocale:(NSString *)inputLocale {
+ (void)searchQuery:(NSString *)query forInputLocale:(NSString *)inputLocale withCategory:(BOOL)isCategory {
if (!query)
return;
@ -142,11 +142,15 @@ using Observers = NSHashTable<Observer>;
manager->m_everywhereParams.m_inputLocale = locale;
manager->m_viewportParams.m_inputLocale = locale;
}
manager.lastQuery = query.precomposedStringWithCompatibilityMapping;
std::string const text = manager.lastQuery.UTF8String;
manager->m_everywhereParams.m_query = text;
manager->m_viewportParams.m_query = text;
manager.textChanged = YES;
manager->m_everywhereParams.m_isCategory = manager->m_viewportParams.m_isCategory = (isCategory == YES);
[manager update];
}

View file

@ -22,7 +22,7 @@ typedef NS_ENUM(NSInteger, MWMSearchManagerRoutingTooltipSearch) {
@property(nonnull, nonatomic) IBOutletCollection(UIView) NSArray *topViews;
- (void)searchText:(nonnull NSString *)text forInputLocale:(nullable NSString *)locale;
- (void)searchText:(nonnull NSString *)text forInputLocale:(nullable NSString *)locale withCategory:(BOOL)isCategory;
#pragma mark - Layout

View file

@ -97,7 +97,7 @@ using Observers = NSHashTable<Observer>;
NSString *text = textField.text;
if (text.length > 0) {
[self beginSearch];
[MWMSearch searchQuery:text forInputLocale:textField.textInputMode.primaryLanguage];
[MWMSearch searchQuery:text forInputLocale:textField.textInputMode.primaryLanguage withCategory:NO];
} else {
[self endSearch];
}
@ -135,11 +135,11 @@ using Observers = NSHashTable<Observer>;
#pragma mark - MWMSearchTabbedViewProtocol
- (void)searchText:(NSString *)text forInputLocale:(NSString *)locale {
- (void)searchText:(NSString *)text forInputLocale:(NSString *)locale withCategory:(BOOL)isCategory {
[self beginSearch];
self.searchTextField.text = text;
NSString *inputLocale = locale ?: self.searchTextField.textInputMode.primaryLanguage;
[MWMSearch searchQuery:text forInputLocale:inputLocale];
[MWMSearch searchQuery:text forInputLocale:inputLocale withCategory:isCategory];
}
- (void)dismissKeyboard {
@ -176,7 +176,7 @@ using Observers = NSHashTable<Observer>;
if (self.state == MWMSearchManagerStateTableSearch || self.state == MWMSearchManagerStateMapSearch) {
NSString *text = self.searchTextField.text;
if (text.length != 0)
[MWMSearch searchQuery:text forInputLocale:self.searchTextField.textInputMode.primaryLanguage];
[MWMSearch searchQuery:text forInputLocale:self.searchTextField.textInputMode.primaryLanguage withCategory:NO];
}
}
@ -413,8 +413,11 @@ using Observers = NSHashTable<Observer>;
}
}
- (void)searchTabController:(MWMSearchTabViewController *)viewController didSearch:(NSString *)didSearch {
[self searchText:didSearch forInputLocale:[[AppInfo sharedInfo] languageId]];
- (void)searchTabController:(MWMSearchTabViewController *)viewController
didSearch:(NSString *)didSearch
withCategory:(BOOL)isCategory
{
[self searchText:didSearch forInputLocale:[[AppInfo sharedInfo] languageId] withCategory:isCategory];
}
- (MWMSearchTableViewController *)tableViewController {

View file

@ -129,7 +129,8 @@ NSString *GetLocalizedTypeName(search::Result const &result) {
case MWMSearchItemTypeSuggestion: {
auto const &suggestion = [MWMSearch resultWithContainerIndex:containerIndex];
NSString *suggestionString = @(suggestion.GetSuggestionString().c_str());
[delegate searchText:suggestionString forInputLocale:nil];
/// @todo Pass withCategory:YES if we tap on category suggestion (not street or city)?
[delegate searchText:suggestionString forInputLocale:nil withCategory:NO];
}
}
}

View file

@ -6,7 +6,7 @@
@property(nonatomic) MWMSearchManagerState state;
- (void)searchText:(NSString *)text forInputLocale:(NSString *)locale;
- (void)searchText:(NSString *)text forInputLocale:(NSString *)locale withCategory:(BOOL)isCategory;
- (void)dismissKeyboard;
@end

View file

@ -1,6 +1,7 @@
import CoreFoundation
@objc(MWMSearchTabViewControllerDelegate)
protocol SearchTabViewControllerDelegate: AnyObject {
func searchTabController(_ viewContoller: SearchTabViewController, didSearch: String)
func searchTabController(_ viewContoller: SearchTabViewController, didSearch: String, withCategory: Bool)
}
@objc(MWMSearchTabViewController)
@ -53,13 +54,13 @@ extension SearchTabViewController: SearchCategoriesViewControllerDelegate {
func categoriesViewController(_ viewController: SearchCategoriesViewController,
didSelect category: String) {
let query = L(category) + " "
delegate?.searchTabController(self, didSearch: query)
delegate?.searchTabController(self, didSearch: query, withCategory: true)
}
}
extension SearchTabViewController: SearchHistoryViewControllerDelegate {
func searchHistoryViewController(_ viewController: SearchHistoryViewController,
didSelect query: String) {
delegate?.searchTabController(self, didSearch: query)
delegate?.searchTabController(self, didSearch: query, withCategory: false)
}
}

View file

@ -21,6 +21,7 @@ struct EverywhereSearchParams
std::string m_query;
std::string m_inputLocale;
std::optional<std::chrono::steady_clock::duration> m_timeout;
bool m_isCategory = false;
OnResults m_onResults;
};

View file

@ -184,6 +184,7 @@ bool SearchAPI::SearchEverywhere(EverywhereSearchParams const & params)
p.m_suggestsEnabled = true;
p.m_needAddress = true;
p.m_needHighlighting = true;
p.m_categorialRequest = params.m_isCategory;
if (params.m_timeout)
p.m_timeout = *params.m_timeout;
@ -211,6 +212,7 @@ bool SearchAPI::SearchInViewport(ViewportSearchParams const & params)
p.m_suggestsEnabled = false;
p.m_needAddress = false;
p.m_needHighlighting = false;
p.m_categorialRequest = params.m_isCategory;
if (params.m_timeout)
p.m_timeout = *params.m_timeout;

View file

@ -17,6 +17,7 @@ struct ViewportSearchParams
std::string m_query;
std::string m_inputLocale;
std::optional<std::chrono::steady_clock::duration> m_timeout;
bool m_isCategory = false;
OnStarted m_onStarted;
OnCompleted m_onCompleted;

View file

@ -253,7 +253,7 @@ void Processor::SetInputLocale(string const & locale)
m_inputLocaleCode = CategoriesHolder::MapLocaleToInteger(locale);
}
void Processor::SetQuery(string const & query)
void Processor::SetQuery(string const & query, bool categorialRequest /* = false */)
{
m_query = query;
m_tokens.clear();
@ -319,20 +319,23 @@ void Processor::SetQuery(string const & query)
// Get preferred types to show in results.
m_preferredTypes.clear();
auto const tokenSlice = QuerySliceOnRawStrings<decltype(m_tokens)>(m_tokens, m_prefix);
m_isCategorialRequest = FillCategories(tokenSlice, GetCategoryLocales(), m_categories, m_preferredTypes);
if (!m_isCategorialRequest)
m_isCategorialRequest = categorialRequest;
auto const locales = GetCategoryLocales();
if (!FillCategories(tokenSlice, locales, m_categories, m_preferredTypes))
{
// Try to match query to cuisine categories.
bool const isCuisineRequest = FillCategories(
tokenSlice, GetCategoryLocales(), GetDefaultCuisineCategories(), m_cuisineTypes);
if (isCuisineRequest)
if (FillCategories(tokenSlice, locales, GetDefaultCuisineCategories(), m_cuisineTypes))
{
/// @todo What if I'd like to find "Burger" street? @see "BurgerStreet" test.
m_isCategorialRequest = true;
m_preferredTypes = ftypes::IsEatChecker::Instance().GetTypes();
}
}
if (!m_isCategorialRequest)
{
// Assign tokens and prefix to scorer.
m_keywordsScorer.SetKeywords(m_tokens.data(), m_tokens.size(), m_prefix);
@ -601,7 +604,7 @@ void Processor::Search(SearchParams const & params)
SetInputLocale(params.m_inputLocale);
SetQuery(params.m_query);
SetQuery(params.m_query, params.m_categorialRequest);
SetViewport(viewport);
// Used to store the earliest available cancellation status:
@ -802,12 +805,9 @@ void Processor::InitParams(QueryParams & params) const
else
params.InitWithPrefix(m_tokens.begin(), m_tokens.end(), m_prefix);
// Add names of categories (and synonyms).
Classificator const & c = classif();
auto addCategorySynonyms = [&](size_t i, uint32_t t) {
uint32_t const index = c.GetIndexForType(t);
params.GetTypeIndices(i).push_back(index);
};
// Add names of categories (and synonyms).
auto const tokenSlice = QuerySliceOnRawStrings<decltype(m_tokens)>(m_tokens, m_prefix);
params.SetCategorialRequest(m_isCategorialRequest);
if (m_isCategorialRequest)
@ -822,11 +822,14 @@ void Processor::InitParams(QueryParams & params) const
else
{
// todo(@m, @y). Shall we match prefix tokens for categories?
ForEachCategoryTypeFuzzy(tokenSlice, addCategorySynonyms);
ForEachCategoryTypeFuzzy(tokenSlice, [&c, &params](size_t i, uint32_t t)
{
uint32_t const index = c.GetIndexForType(t);
params.GetTypeIndices(i).push_back(index);
});
}
// Remove all type indices for streets, as they're considired
// individually.
// Remove all type indices for streets, as they're considired individually.
for (size_t i = 0; i < params.GetNumTokens(); ++i)
{
auto & token = params.GetToken(i);
@ -837,8 +840,10 @@ void Processor::InitParams(QueryParams & params) const
for (size_t i = 0; i < params.GetNumTokens(); ++i)
base::SortUnique(params.GetTypeIndices(i));
m_keywordsScorer.ForEachLanguage(
[&](int8_t lang) { params.GetLangs().Insert(static_cast<uint64_t>(lang)); });
m_keywordsScorer.ForEachLanguage([&params](int8_t lang)
{
params.GetLangs().Insert(static_cast<uint64_t>(lang));
});
}
void Processor::InitGeocoder(Geocoder::Params & geocoderParams, SearchParams const & searchParams)

View file

@ -70,7 +70,7 @@ public:
void SetViewport(m2::RectD const & viewport);
void SetPreferredLocale(std::string const & locale);
void SetInputLocale(std::string const & locale);
void SetQuery(std::string const & query);
void SetQuery(std::string const & query, bool categorialRequest = false);
inline std::string const & GetPivotRegion() const { return m_region; }
inline bool IsEmptyQuery() const { return m_prefix.empty() && m_tokens.empty(); }

View file

@ -848,8 +848,8 @@ UNIT_CLASS_TEST(ProcessorTest, TestCategorialSearch)
{
Rules const rules = {ExactMatch(wonderlandId, hotel1), ExactMatch(wonderlandId, hotel2)};
TEST(ResultsMatch("hotel ", rules), ());
TEST(ResultsMatch("hôTeL ", rules), ());
TEST(CategoryMatch("hotel ", rules), ());
TEST(CategoryMatch("hôTeL ", rules), ());
}
{
@ -858,14 +858,13 @@ UNIT_CLASS_TEST(ProcessorTest, TestCategorialSearch)
// A category with a rare name. The word "Entertainment"
// occurs exactly once in the list of categories and starts
// with a capital letter. This is a test for normalization.
TEST(ResultsMatch("entertainment ", rules), ());
TEST(CategoryMatch("entertainment ", rules), ());
}
{
Rules const rules = {ExactMatch(wonderlandId, hotel1), ExactMatch(wonderlandId, hotel2)};
auto request = MakeRequest("гостиница ", "ru");
TEST(ResultsMatch(request->Results(), rules), ());
TEST(CategoryMatch("гостиница ", rules, "ru"), ());
}
{
@ -874,8 +873,8 @@ UNIT_CLASS_TEST(ProcessorTest, TestCategorialSearch)
// Hotel unicode character: both a synonym and and emoji.
uint32_t const hotelEmojiCodepoint = 0x0001F3E8;
strings::UniString const hotelUniString(1, hotelEmojiCodepoint);
auto request = MakeRequest(ToUtf8(hotelUniString));
TEST(ResultsMatch(request->Results(), rules), ());
TEST(CategoryMatch(ToUtf8(hotelUniString), rules), ());
}
{
@ -3027,4 +3026,31 @@ UNIT_CLASS_TEST(ProcessorTest, TestRankingInfo_MultipleOldNames)
checkResult("Ленинград", "Санкт-Петербург (Ленинград)");
checkResult("Петроград", "Санкт-Петербург (Петроград)");
}
/// @todo We are not ready for this test yet.
/*
UNIT_CLASS_TEST(ProcessorTest, BurgerStreet)
{
string const countryName = "Wonderland";
TestPOI burger({1.0, 1.0}, "Dummy", "en");
burger.SetTypes({{"amenity", "fast_food"}, {"cuisine", "burger"}});
TestStreet street({{2.0, 2.0}, {3.0, 3.0}}, "Burger street", "en");
street.SetHighwayType("residential");
auto countryId = BuildCountry(countryName, [&](TestMwmBuilder & builder)
{
builder.Add(burger);
builder.Add(street);
});
SetViewport(m2::RectD(0, 0, 3, 3));
{
Rules rules{ExactMatch(countryId, burger), ExactMatch(countryId, street)};
TEST(ResultsMatch("burger", rules), ());
}
}
*/
} // namespace processor_test

View file

@ -68,8 +68,6 @@ public:
{
SetTypes({{"shop", "alcohol"}});
}
~AlcoShop() override = default;
};
class SubwayStation : public TestPOI
@ -80,8 +78,6 @@ public:
{
SetTypes({{"railway", "station", "subway"}});
}
~SubwayStation() override = default;
};
class SubwayStationMoscow : public TestPOI
@ -92,8 +88,6 @@ public:
{
SetTypes({{"railway", "station", "subway", "moscow"}});
}
~SubwayStationMoscow() override = default;
};
UNIT_CLASS_TEST(SmokeTest, Smoke)
@ -105,7 +99,8 @@ UNIT_CLASS_TEST(SmokeTest, Smoke)
AlcoShop brandyShop(m2::PointD(0, 1), "Brandy shop", "en");
AlcoShop vodkaShop(m2::PointD(1, 1), "Russian vodka shop", "en");
auto id = BuildMwm(kCountryName, DataHeader::MapType::Country, [&](TestMwmBuilder & builder) {
auto id = BuildMwm(kCountryName, DataHeader::MapType::Country, [&](TestMwmBuilder & builder)
{
builder.Add(wineShop);
builder.Add(tequilaShop);
builder.Add(brandyShop);
@ -117,18 +112,16 @@ UNIT_CLASS_TEST(SmokeTest, Smoke)
SetViewport(m2::RectD(m2::PointD(0, 0), m2::PointD(100, 100)));
{
Rules rules = {ExactMatch(id, tequilaShop)};
/// @todo Passing "wine" will interpret request as "categorial" only
/// (see IsCategorialRequest() after adding craft-winery category).
/// Should avoid this strange logic in search core and pass "categorial" request flag via input SearchParams.
TEST(ResultsMatch("tequila ", rules), ());
Rules rules = {ExactMatch(id, wineShop)};
TEST(ResultsMatch("wine ", rules), ());
}
{
Rules rules = {ExactMatch(id, wineShop), ExactMatch(id, tequilaShop),
ExactMatch(id, brandyShop), ExactMatch(id, vodkaShop)};
TEST(ResultsMatch("shop ", rules), ());
}
Rules const allRule = { ExactMatch(id, wineShop), ExactMatch(id, tequilaShop),
ExactMatch(id, brandyShop), ExactMatch(id, vodkaShop) };
TEST(ResultsMatch("shop ", allRule), ());
TEST(ResultsMatch("alcohol ", allRule), ());
TEST(CategoryMatch("алкоголь", allRule, "ru"), ());
}
UNIT_CLASS_TEST(SmokeTest, DeepCategoryTest)
@ -232,6 +225,7 @@ UNIT_CLASS_TEST(SmokeTest, CategoriesTest)
notSupportedTypes.insert(cl.GetTypeByPath(tags));
auto const & holder = GetDefaultCategories();
auto testCategory = [&](uint32_t type, CategoriesHolder::Category const &)
{
if (invisibleTypes.find(type) != invisibleTypes.end())
@ -250,11 +244,10 @@ UNIT_CLASS_TEST(SmokeTest, CategoriesTest)
auto id = BuildMwm(countryName, DataHeader::MapType::Country,
[&](TestMwmBuilder & builder) { builder.AddSafe(poi); });
SetViewport(m2::RectD(m2::PointD(0.0, 0.0), m2::PointD(2.0, 2.0)));
{
Rules rules = {ExactMatch(id, poi)};
auto const query = holder.GetReadableFeatureType(type, CategoriesHolder::kEnglishCode) + " ";
TEST(ResultsMatch(query, categoryIsSearchable ? rules : Rules{}), (query));
auto const query = holder.GetReadableFeatureType(type, CategoriesHolder::kEnglishCode);
TEST(CategoryMatch(query, categoryIsSearchable ? rules : Rules{}), (query));
}
DeregisterMap(countryName);
};

View file

@ -30,7 +30,7 @@ struct SearchParams
static double constexpr kDefaultVillageSearchRadiusM = 2e5;
using TimeDurationT = base::Timer::DurationT;
/// @todo Short timeouts leads to a non-working search on slow devices. Design a better solution.
/// @todo Short timeouts lead to a non-working search on slow devices. Design a better solution.
static TimeDurationT constexpr kDefaultTimeout = std::chrono::seconds(8);
static TimeDurationT constexpr kDefaultDesktopTimeout = std::chrono::seconds(8);
@ -92,6 +92,9 @@ struct SearchParams
// Needed to highlight matching parts of search result names.
bool m_needHighlighting = false;
/// True if you need *pure* category results, without names/addresses/etc matching.
bool m_categorialRequest = false;
bookmarks::GroupId m_bookmarksGroupId = bookmarks::kInvalidGroupId;
// Amount of time after which the search is aborted.

View file

@ -10,6 +10,7 @@
namespace search
{
using namespace std;
using namespace tests_support;
SearchTest::SearchTest()
: m_scopedLog(LDEBUG)
@ -25,24 +26,30 @@ void SearchTest::RegisterCountry(string const & name, m2::RectD const & rect)
infoGetter.AddCountry(storage::CountryDef(name, rect));
}
bool SearchTest::ResultsMatch(string const & query,
vector<shared_ptr<tests_support::MatchingRule>> const & rules)
bool SearchTest::ResultsMatch(string const & query, Rules const & rules)
{
return ResultsMatch(query, "en" /* locale */, rules);
}
bool SearchTest::ResultsMatch(string const & query, string const & locale,
vector<shared_ptr<tests_support::MatchingRule>> const & rules)
bool SearchTest::CategoryMatch(std::string const & query, Rules const & rules, string const & locale)
{
tests_support::TestSearchRequest request(m_engine, query, locale, Mode::Everywhere, m_viewport);
TestSearchRequest request(m_engine, query, locale, Mode::Everywhere, m_viewport);
request.SetCategorial();
request.Run();
return MatchResults(m_dataSource, rules, request.Results());
}
bool SearchTest::ResultsMatch(string const & query, Mode mode,
vector<shared_ptr<tests_support::MatchingRule>> const & rules)
bool SearchTest::ResultsMatch(string const & query, string const & locale, Rules const & rules)
{
tests_support::TestSearchRequest request(m_engine, query, "en", mode, m_viewport);
TestSearchRequest request(m_engine, query, locale, Mode::Everywhere, m_viewport);
request.Run();
return MatchResults(m_dataSource, rules, request.Results());
}
bool SearchTest::ResultsMatch(string const & query, Mode mode, Rules const & rules)
{
TestSearchRequest request(m_engine, query, "en", mode, m_viewport);
request.Run();
return MatchResults(m_dataSource, rules, request.Results());
}
@ -54,7 +61,7 @@ bool SearchTest::ResultsMatch(vector<search::Result> const & results, Rules cons
bool SearchTest::ResultsMatch(SearchParams const & params, Rules const & rules)
{
tests_support::TestSearchRequest request(m_engine, params);
TestSearchRequest request(m_engine, params);
request.Run();
return ResultsMatch(request.Results(), rules);
}
@ -66,26 +73,26 @@ bool SearchTest::ResultMatches(search::Result const & result, Rule const & rule)
bool SearchTest::AlternativeMatch(string const & query, vector<Rules> const & rulesList)
{
tests_support::TestSearchRequest request(m_engine, query, "en", Mode::Everywhere, m_viewport);
TestSearchRequest request(m_engine, query, "en", Mode::Everywhere, m_viewport);
request.Run();
return tests_support::AlternativeMatch(m_dataSource, rulesList, request.Results());
}
size_t SearchTest::GetResultsNumber(string const & query, string const & locale)
{
tests_support::TestSearchRequest request(m_engine, query, locale, Mode::Everywhere, m_viewport);
TestSearchRequest request(m_engine, query, locale, Mode::Everywhere, m_viewport);
request.Run();
return request.Results().size();
}
unique_ptr<tests_support::TestSearchRequest> SearchTest::MakeRequest(SearchParams params)
unique_ptr<TestSearchRequest> SearchTest::MakeRequest(SearchParams params)
{
auto request = make_unique<tests_support::TestSearchRequest>(m_engine, params);
auto request = make_unique<TestSearchRequest>(m_engine, params);
request->Run();
return request;
}
unique_ptr<tests_support::TestSearchRequest> SearchTest::MakeRequest(
unique_ptr<TestSearchRequest> SearchTest::MakeRequest(
string const & query, string const & locale /* = "en" */)
{
SearchParams params;
@ -95,11 +102,10 @@ unique_ptr<tests_support::TestSearchRequest> SearchTest::MakeRequest(
params.m_mode = Mode::Everywhere;
params.m_needAddress = true;
params.m_suggestsEnabled = false;
params.m_streetSearchRadiusM = tests_support::TestSearchRequest::kDefaultTestStreetSearchRadiusM;
params.m_villageSearchRadiusM =
tests_support::TestSearchRequest::kDefaultTestVillageSearchRadiusM;
params.m_streetSearchRadiusM = TestSearchRequest::kDefaultTestStreetSearchRadiusM;
params.m_villageSearchRadiusM = TestSearchRequest::kDefaultTestVillageSearchRadiusM;
auto request = make_unique<tests_support::TestSearchRequest>(m_engine, params);
auto request = make_unique<TestSearchRequest>(m_engine, params);
request->Run();
return request;
}

View file

@ -32,6 +32,7 @@ public:
inline void SetViewport(m2::RectD const & viewport) { m_viewport = viewport; }
bool ResultsMatch(std::string const & query, Rules const & rules);
bool CategoryMatch(std::string const & query, Rules const & rules, std::string const & locale = "en");
bool ResultsMatch(std::string const & query, std::string const & locale, Rules const & rules);

View file

@ -26,7 +26,7 @@ TestSearchEngine::TestSearchEngine(DataSource & dataSource, Engine::Params const
{
}
weak_ptr<::search::ProcessorHandle> TestSearchEngine::Search(::search::SearchParams const & params)
weak_ptr<ProcessorHandle> TestSearchEngine::Search(SearchParams const & params)
{
return m_engine.Search(params);
}

View file

@ -26,13 +26,13 @@ public:
void LoadCitiesBoundaries() { m_engine.LoadCitiesBoundaries(); }
std::weak_ptr<search::ProcessorHandle> Search(search::SearchParams const & params);
std::weak_ptr<ProcessorHandle> Search(SearchParams const & params);
storage::CountryInfoGetter & GetCountryInfoGetter() { return *m_infoGetter; }
private:
std::unique_ptr<storage::CountryInfoGetter> m_infoGetter;
search::Engine m_engine;
Engine m_engine;
};
} // namespace tests_support
} // namespace search

View file

@ -32,6 +32,8 @@ public:
std::string const & locale, Mode mode, m2::RectD const & viewport);
TestSearchRequest(TestSearchEngine & engine, SearchParams const & params);
void SetCategorial() { m_params.m_categorialRequest = true; }
// Initiates the search and waits for it to finish.
void Run();