Skip to content

Commit e3367c7

Browse files
authored
Merge pull request #10410 from eth3lbert/refactor-search-test
Improving the readability of search test cases
2 parents f681b36 + e25d975 commit e3367c7

File tree

1 file changed

+89
-66
lines changed

1 file changed

+89
-66
lines changed

src/tests/routes/crates/list.rs

Lines changed: 89 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::controllers::helpers::pagination::decode_seek;
21
use crate::models::Category;
32
use crate::schema::{crates, users};
43
use crate::tests::builders::{CrateBuilder, VersionBuilder};
@@ -308,7 +307,7 @@ async fn index_sorting() -> anyhow::Result<()> {
308307
.await;
309308

310309
let krate3 = CrateBuilder::new("baz_sort", user.id)
311-
.description("foo_sort bar_sort foo_sort bar_sort foo_sort bar_sort const")
310+
.description("foo_sort bar_sort foo_sort bar_sort bar_sort const")
312311
.downloads(100_000)
313312
.recent_downloads(50)
314313
.expect_build(&mut conn)
@@ -412,76 +411,75 @@ async fn index_sorting() -> anyhow::Result<()> {
412411
assert_eq!(resp[3].meta.total, 4);
413412
assert_eq!(calls, 5);
414413

415-
use std::cmp::Reverse;
416-
417414
// Sort by alpha with query
418-
for query in ["sort=alpha&q=bar_sort", "sort=alpha&q=sort"] {
419-
let (resp, calls) = page_with_seek(&anon, query).await;
420-
assert_eq!(calls, resp[0].meta.total + 1);
421-
let decoded_seeks = resp
422-
.iter()
423-
.filter_map(|cl| {
424-
cl.meta
425-
.next_page
426-
.as_ref()
427-
.map(|next_page| (next_page, cl.crates[0].name.to_owned()))
428-
})
429-
.filter_map(|(q, name)| {
430-
let query = url::form_urlencoded::parse(q.trim_start_matches('?').as_bytes())
431-
.into_owned()
432-
.collect::<indexmap::IndexMap<String, String>>();
433-
query.get("seek").map(|s| {
434-
let d = decode_seek::<(bool, i32)>(s).unwrap();
435-
(d.0, name)
436-
})
437-
})
438-
.collect::<Vec<_>>();
439-
// ordering (exact match desc, name asc)
440-
let mut sorted = decoded_seeks.to_vec();
441-
sorted.sort_by_key(|k| (Reverse(k.0), k.1.to_owned()));
442-
assert_eq!(sorted, decoded_seeks);
443-
for json in search_both(&anon, query).await {
444-
assert_eq!(json.meta.total, resp[0].meta.total);
445-
for (c, r) in json.crates.iter().zip(&resp) {
446-
assert_eq!(c.name, r.crates[0].name);
447-
}
448-
}
415+
// ordering (exact match desc, name asc)
416+
let query = "sort=alpha&q=bar_sort";
417+
let (resp, calls) = page_with_seek(&anon, query).await;
418+
for json in search_both(&anon, query).await {
419+
assert_eq!(json.meta.total, 3);
420+
assert_eq!(resp[0].crates[0].name, "bar_sort");
421+
assert_eq!(resp[1].crates[0].name, "baz_sort");
422+
assert_eq!(resp[2].crates[0].name, "foo_sort");
449423
}
424+
assert_eq!(calls, 4);
425+
426+
let query = "sort=alpha&q=sort";
427+
let (resp, calls) = page_with_seek(&anon, query).await;
428+
for json in search_both(&anon, query).await {
429+
assert_eq!(json.meta.total, 4);
430+
assert_eq!(resp[0].crates[0].name, "bar_sort");
431+
assert_eq!(resp[1].crates[0].name, "baz_sort");
432+
assert_eq!(resp[2].crates[0].name, "foo_sort");
433+
assert_eq!(resp[3].crates[0].name, "other_sort");
434+
}
435+
assert_eq!(calls, 5);
450436

451437
// Sort by relevance
438+
// ordering (exact match desc, rank desc, name asc)
439+
let query = "q=foo_sort";
440+
let (resp, calls) = page_with_seek(&anon, query).await;
441+
for json in search_both(&anon, query).await {
442+
assert_eq!(json.meta.total, 3);
443+
assert_eq!(resp[0].crates[0].name, "foo_sort");
444+
// same rank, by name asc
445+
assert_eq!(resp[1].crates[0].name, "bar_sort");
446+
assert_eq!(resp[2].crates[0].name, "baz_sort");
447+
}
448+
assert_eq!(calls, 4);
449+
let ranks = querystring_rank(&mut conn, "foo_sort").await;
450+
assert_eq!(ranks.get("bar_sort"), ranks.get("baz_sort"));
451+
452452
// Add query containing a space to ensure tsquery works
453-
for query in ["q=foo_sort", "q=sort", "q=foo%20sort"] {
454-
let (resp, calls) = page_with_seek(&anon, query).await;
455-
assert_eq!(calls, resp[0].meta.total + 1);
456-
let decoded_seeks = resp
457-
.iter()
458-
.filter_map(|cl| {
459-
cl.meta
460-
.next_page
461-
.as_ref()
462-
.map(|next_page| (next_page, cl.crates[0].name.to_owned()))
463-
})
464-
.filter_map(|(q, name)| {
465-
let query = url::form_urlencoded::parse(q.trim_start_matches('?').as_bytes())
466-
.into_owned()
467-
.collect::<indexmap::IndexMap<String, String>>();
468-
query.get("seek").map(|s| {
469-
let d = decode_seek::<(bool, f32, i32)>(s).unwrap();
470-
(d.0, (d.1 * 1e12) as i64, name)
471-
})
472-
})
473-
.collect::<Vec<_>>();
474-
// ordering (exact match desc, rank desc, name asc)
475-
let mut sorted = decoded_seeks.clone();
476-
sorted.sort_by_key(|k| (Reverse(k.0), Reverse(k.1), k.2.to_owned()));
477-
assert_eq!(sorted, decoded_seeks);
478-
for json in search_both(&anon, query).await {
479-
assert_eq!(json.meta.total, resp[0].meta.total);
480-
for (c, r) in json.crates.iter().zip(&resp) {
481-
assert_eq!(c.name, r.crates[0].name);
482-
}
483-
}
453+
// "foo_sort" and "foo sort" would generate same tsquery
454+
let query = "q=foo%20sort";
455+
let (resp, calls) = page_with_seek(&anon, query).await;
456+
for json in search_both(&anon, query).await {
457+
assert_eq!(json.meta.total, 3);
458+
assert_eq!(resp[0].crates[0].name, "foo_sort");
459+
// same rank, by name asc
460+
assert_eq!(resp[1].crates[0].name, "bar_sort");
461+
assert_eq!(resp[2].crates[0].name, "baz_sort");
462+
}
463+
assert_eq!(calls, 4);
464+
let ranks = querystring_rank(&mut conn, "foo%20sort").await;
465+
assert_eq!(ranks.get("bar_sort"), ranks.get("baz_sort"));
466+
467+
let query = "q=sort";
468+
let (resp, calls) = page_with_seek(&anon, query).await;
469+
for json in search_both(&anon, query).await {
470+
assert_eq!(json.meta.total, 4);
471+
// by rank desc (items with more "sort" should have a hider rank value)
472+
assert_eq!(resp[0].crates[0].name, "baz_sort");
473+
assert_eq!(resp[1].crates[0].name, "bar_sort");
474+
assert_eq!(resp[2].crates[0].name, "foo_sort");
475+
assert_eq!(resp[3].crates[0].name, "other_sort");
484476
}
477+
assert_eq!(calls, 5);
478+
let ranks = querystring_rank(&mut conn, "sort").await;
479+
assert_eq!(
480+
ranks.keys().collect::<Vec<_>>(),
481+
["baz_sort", "bar_sort", "foo_sort", "other_sort"]
482+
);
485483

486484
// Test for bug with showing null results first when sorting
487485
// by descending downloads
@@ -1286,3 +1284,28 @@ fn default_versions_iter(
12861284
fn yanked_iter(crates: &[crate::tests::EncodableCrate]) -> impl Iterator<Item = &bool> {
12871285
crates.iter().map(|c| &c.yanked)
12881286
}
1287+
1288+
async fn querystring_rank(
1289+
conn: &mut diesel_async::AsyncPgConnection,
1290+
q: &str,
1291+
) -> indexmap::IndexMap<String, f32> {
1292+
use diesel_full_text_search::configuration::TsConfigurationByName;
1293+
use diesel_full_text_search::{plainto_tsquery_with_search_config, ts_rank_cd};
1294+
use futures_util::future::ready;
1295+
use futures_util::TryStreamExt;
1296+
1297+
let tsquery = plainto_tsquery_with_search_config(TsConfigurationByName("english"), q);
1298+
let rank = ts_rank_cd(crates::textsearchable_index_col, tsquery);
1299+
crates::table
1300+
.select((crates::name, rank))
1301+
.order_by(rank.desc())
1302+
.load_stream::<(String, f32)>(conn)
1303+
.await
1304+
.unwrap()
1305+
.try_fold(indexmap::IndexMap::new(), |mut map, (name, id)| {
1306+
map.insert(name, id);
1307+
ready(Ok(map))
1308+
})
1309+
.await
1310+
.unwrap()
1311+
}

0 commit comments

Comments
 (0)