Skip to content

Commit e25d975

Browse files
committed
src/tests/routes/crates/list: Assert with explicit value for relevance sorting
Refactor the existing relevance sorting test cases to be more explicit and easier to follow for better readability.
1 parent 5cd07f6 commit e25d975

File tree

1 file changed

+68
-34
lines changed

1 file changed

+68
-34
lines changed

src/tests/routes/crates/list.rs

Lines changed: 68 additions & 34 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};
@@ -412,8 +411,6 @@ 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
418415
// ordering (exact match desc, name asc)
419416
let query = "sort=alpha&q=bar_sort";
@@ -438,39 +435,51 @@ async fn index_sorting() -> anyhow::Result<()> {
438435
assert_eq!(calls, 5);
439436

440437
// 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+
441452
// Add query containing a space to ensure tsquery works
442-
for query in ["q=foo_sort", "q=sort", "q=foo%20sort"] {
443-
let (resp, calls) = page_with_seek(&anon, query).await;
444-
assert_eq!(calls, resp[0].meta.total + 1);
445-
let decoded_seeks = resp
446-
.iter()
447-
.filter_map(|cl| {
448-
cl.meta
449-
.next_page
450-
.as_ref()
451-
.map(|next_page| (next_page, cl.crates[0].name.to_owned()))
452-
})
453-
.filter_map(|(q, name)| {
454-
let query = url::form_urlencoded::parse(q.trim_start_matches('?').as_bytes())
455-
.into_owned()
456-
.collect::<indexmap::IndexMap<String, String>>();
457-
query.get("seek").map(|s| {
458-
let d = decode_seek::<(bool, f32, i32)>(s).unwrap();
459-
(d.0, (d.1 * 1e12) as i64, name)
460-
})
461-
})
462-
.collect::<Vec<_>>();
463-
// ordering (exact match desc, rank desc, name asc)
464-
let mut sorted = decoded_seeks.clone();
465-
sorted.sort_by_key(|k| (Reverse(k.0), Reverse(k.1), k.2.to_owned()));
466-
assert_eq!(sorted, decoded_seeks);
467-
for json in search_both(&anon, query).await {
468-
assert_eq!(json.meta.total, resp[0].meta.total);
469-
for (c, r) in json.crates.iter().zip(&resp) {
470-
assert_eq!(c.name, r.crates[0].name);
471-
}
472-
}
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");
473476
}
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+
);
474483

475484
// Test for bug with showing null results first when sorting
476485
// by descending downloads
@@ -1275,3 +1284,28 @@ fn default_versions_iter(
12751284
fn yanked_iter(crates: &[crate::tests::EncodableCrate]) -> impl Iterator<Item = &bool> {
12761285
crates.iter().map(|c| &c.yanked)
12771286
}
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)