diff --git a/meilisearch/tests/search/mod.rs b/meilisearch/tests/search/mod.rs index 045cfde2c..6a55c7569 100644 --- a/meilisearch/tests/search/mod.rs +++ b/meilisearch/tests/search/mod.rs @@ -5,6 +5,7 @@ mod errors; mod formatted; mod multi; mod pagination; +mod restrict_searchable; use once_cell::sync::Lazy; use serde_json::{json, Value}; diff --git a/meilisearch/tests/search/restrict_searchable.rs b/meilisearch/tests/search/restrict_searchable.rs new file mode 100644 index 000000000..dda38560a --- /dev/null +++ b/meilisearch/tests/search/restrict_searchable.rs @@ -0,0 +1,297 @@ +use once_cell::sync::Lazy; +use serde_json::{json, Value}; + +use crate::common::index::Index; +use crate::common::Server; + +async fn index_with_documents<'a>(server: &'a Server, documents: &Value) -> Index<'a> { + let index = server.index("test"); + + index.add_documents(documents.clone(), None).await; + index.wait_task(0).await; + index +} + +static SIMPLE_SEARCH_DOCUMENTS: Lazy = Lazy::new(|| { + json!([ + { + "title": "Shazam!", + "desc": "a Captain Marvel ersatz", + "id": "1", + }, + { + "title": "Captain Planet", + "desc": "He's not part of the Marvel Cinematic Universe", + "id": "2", + }, + { + "title": "Captain Marvel", + "desc": "a Shazam ersatz", + "id": "3", + }]) +}); + +#[actix_rt::test] +async fn simple_search_on_title() { + let server = Server::new().await; + let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + + // simple search should return 2 documents (ids: 2 and 3). + index + .search( + json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["title"]}), + |response, code| { + assert_eq!(code, 200, "{}", response); + assert_eq!(response["hits"].as_array().unwrap().len(), 2); + }, + ) + .await; +} + +#[actix_rt::test] +async fn simple_prefix_search_on_title() { + let server = Server::new().await; + let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + + // simple search should return 2 documents (ids: 2 and 3). + index + .search( + json!({"q": "Captain Mar", "restrictSearchableAttributes": ["title"]}), + |response, code| { + assert_eq!(code, 200, "{}", response); + assert_eq!(response["hits"].as_array().unwrap().len(), 2); + }, + ) + .await; +} + +#[actix_rt::test] +async fn simple_search_on_title_matching_strategy_all() { + let server = Server::new().await; + let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + // simple search matching strategy all should only return 1 document (ids: 2). + index + .search(json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["title"], "matchingStrategy": "all"}), |response, code| { + assert_eq!(code, 200, "{}", response); + assert_eq!(response["hits"].as_array().unwrap().len(), 1); + }) + .await; +} + +#[actix_rt::test] +async fn simple_search_on_unknown_field() { + let server = Server::new().await; + let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + // simple search on unknown field shouldn't return any document. + index + .search( + json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["unknown"]}), + |response, code| { + assert_eq!(code, 200, "{}", response); + assert_eq!(response["hits"].as_array().unwrap().len(), 0); + }, + ) + .await; +} + +#[actix_rt::test] +async fn simple_search_on_no_field() { + let server = Server::new().await; + let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + // simple search on no field shouldn't return any document. + index + .search( + json!({"q": "Captain Marvel", "restrictSearchableAttributes": []}), + |response, code| { + assert_eq!(code, 200, "{}", response); + assert_eq!(response["hits"].as_array().unwrap().len(), 0); + }, + ) + .await; +} + +#[actix_rt::test] +async fn word_ranking_rule_order() { + let server = Server::new().await; + let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + + // Document 3 should appear before document 2. + index + .search( + json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["title"], "attributesToRetrieve": ["id"]}), + |response, code| { + assert_eq!(code, 200, "{}", response); + assert_eq!( + response["hits"], + json!([ + {"id": "3"}, + {"id": "2"}, + ]) + ); + }, + ) + .await; +} + +#[actix_rt::test] +async fn word_ranking_rule_order_exact_words() { + let server = Server::new().await; + let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + index.update_settings_typo_tolerance(json!({"disableOnWords": ["Captain", "Marvel"]})).await; + index.wait_task(1).await; + + // simple search should return 2 documents (ids: 2 and 3). + index + .search( + json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["title"], "attributesToRetrieve": ["id"]}), + |response, code| { + assert_eq!(code, 200, "{}", response); + assert_eq!( + response["hits"], + json!([ + {"id": "3"}, + {"id": "2"}, + ]) + ); + }, + ) + .await; +} + +#[actix_rt::test] +async fn typo_ranking_rule_order() { + let server = Server::new().await; + let index = index_with_documents( + &server, + &json!([ + { + "title": "Capitain Marivel", + "desc": "Captain Marvel", + "id": "1", + }, + { + "title": "Captain Marivel", + "desc": "a Shazam ersatz", + "id": "2", + }]), + ) + .await; + + // Document 2 should appear before document 1. + index + .search(json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["title"], "attributesToRetrieve": ["id"]}), |response, code| { + assert_eq!(code, 200, "{}", response); + assert_eq!( + response["hits"], + json!([ + {"id": "2"}, + {"id": "1"}, + ]) + ); + }) + .await; +} + +#[actix_rt::test] +async fn proximity_ranking_rule_order() { + let server = Server::new().await; + let index = index_with_documents( + &server, + &json!([ + { + "title": "Captain super mega cool. A Marvel story", + "desc": "Captain Marvel", + "id": "1", + }, + { + "title": "Captain America from Marvel", + "desc": "a Shazam ersatz", + "id": "2", + }]), + ) + .await; + + // Document 2 should appear before document 1. + index + .search(json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["title"], "attributesToRetrieve": ["id"]}), |response, code| { + assert_eq!(code, 200, "{}", response); + assert_eq!( + response["hits"], + json!([ + {"id": "2"}, + {"id": "1"}, + ]) + ); + }) + .await; +} + +#[actix_rt::test] +async fn attributes_ranking_rule_order() { + let server = Server::new().await; + let index = index_with_documents( + &server, + &json!([ + { + "title": "Captain Marvel", + "desc": "a Shazam ersatz", + "footer": "The story of Captain Marvel", + "id": "1", + }, + { + "title": "The Avengers", + "desc": "Captain Marvel is far from the earth", + "footer": "A super hero team", + "id": "2", + }]), + ) + .await; + + // Document 2 should appear before document 1. + index + .search(json!({"q": "Captain Marvel", "restrictSearchableAttributes": ["desc", "footer"], "attributesToRetrieve": ["id"]}), |response, code| { + assert_eq!(code, 200, "{}", response); + assert_eq!( + response["hits"], + json!([ + {"id": "2"}, + {"id": "1"}, + ]) + ); + }) + .await; +} + +#[actix_rt::test] +async fn exactness_ranking_rule_order() { + let server = Server::new().await; + let index = index_with_documents( + &server, + &json!([ + { + "title": "Captain Marvel", + "desc": "Captain Marivel", + "id": "1", + }, + { + "title": "Captain Marvel", + "desc": "CaptainMarvel", + "id": "2", + }]), + ) + .await; + + // Document 2 should appear before document 1. + index + .search(json!({"q": "Captain Marvel", "attributesToRetrieve": ["id"], "restrictSearchableAttributes": ["desc"]}), |response, code| { + assert_eq!(code, 200, "{}", response); + assert_eq!( + response["hits"], + json!([ + {"id": "2"}, + {"id": "1"}, + ]) + ); + }) + .await; +}