test search by using examples in doc.
This commit is contained in:
		| @ -10,26 +10,26 @@ pub struct Query { | |||||||
|  |  | ||||||
| impl Query { | impl Query { | ||||||
|     pub fn search(&self, input: &mut Iterator<Item = &Texture>) -> Vec<Texture> { |     pub fn search(&self, input: &mut Iterator<Item = &Texture>) -> Vec<Texture> { | ||||||
|         let mut results: Vec<(u64, &Texture)> = Vec::new(); |         let mut results: Vec<(i64, &Texture)> = Vec::new(); | ||||||
|  |  | ||||||
|         // We use pseudo decimal fixed point numbers here. |         // We use pseudo decimal fixed point numbers here. | ||||||
|         // 1.000_000 = 1_000_000; |         // 1.000_000 = 1_000_000; | ||||||
|  |  | ||||||
|         // This is done, since algorithms like quicksort can fail on floats. |         // This is done, since algorithms like quicksort can fail on floats. | ||||||
|         let required_score = self.required_score() * 1_000_000u64; |         let required_score = self.required_score() * 1_000_000i64; | ||||||
|  |  | ||||||
|         for texture in input { |         'texture_loop: for texture in input { | ||||||
|             let mut score = 0u64; |             let mut score = 0i64; | ||||||
|  |  | ||||||
|             for (pos, filter) in self.filters.iter().enumerate() { |             for (pos, filter) in self.filters.iter().enumerate() { | ||||||
|                 match filter.score(texture) { |                 match filter.score(texture) { | ||||||
|                     Score::RequiredMatch(true) => (), |                     Score::RequiredMatch(true) => (), | ||||||
|                     Score::RequiredMatch(false) => { |                     Score::RequiredMatch(false) => { | ||||||
|                         // skip this texture |                         // skip this texture | ||||||
|                         continue; |                         continue 'texture_loop; | ||||||
|                     } |                     } | ||||||
|                     Score::Match(true) => { |                     Score::Match(true) => { | ||||||
|                         score += 1_000_000u64 * (1 + (0.1 / f64::sqrt(pos as f64 + 1.0)) as u64); |                         score += 1_000_000i64 + ((100_000.0 / f64::sqrt(pos as f64 + 1.0)) as i64); | ||||||
|                     } |                     } | ||||||
|                     Score::Match(false) => (), |                     Score::Match(false) => (), | ||||||
|                 } |                 } | ||||||
| @ -40,7 +40,7 @@ impl Query { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         results.sort_by_key(|(score, _)| *score); |         results.sort_by_key(|(score, _)| score * -1); | ||||||
|  |  | ||||||
|         results |         results | ||||||
|             .iter() |             .iter() | ||||||
| @ -48,8 +48,8 @@ impl Query { | |||||||
|             .collect::<Vec<Texture>>() |             .collect::<Vec<Texture>>() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn required_score(&self) -> u64 { |     fn required_score(&self) -> i64 { | ||||||
|         let non_special = self.filters.iter().filter(|f| !f.is_special()).count() as u64; |         let non_special = self.filters.iter().filter(|f| !f.is_special()).count() as i64; | ||||||
|  |  | ||||||
|         // ceil(non_special / 2) |         // ceil(non_special / 2) | ||||||
|         (non_special + 1) / 2 |         (non_special + 1) / 2 | ||||||
| @ -66,3 +66,100 @@ impl Query { | |||||||
|         Ok(result) |         Ok(result) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | /// These tests check against the example section in the search design document. | ||||||
|  | mod test { | ||||||
|  |     use super::*; | ||||||
|  |     use std::str::FromStr; | ||||||
|  |  | ||||||
|  |     /// just a shorthand | ||||||
|  |     fn tex(id: i32, name: &str, tags: &str, added_on: &str, resolution: u64) -> Texture { | ||||||
|  |         Texture { | ||||||
|  |             id: format!("{}", id), // Id should actaly be a uuid, but for testing this is fine. | ||||||
|  |             name: name.to_string(), | ||||||
|  |             tags: tags.split(",").map(|s| s.trim().to_string()).collect(), | ||||||
|  |             added_on: Date::from_str(added_on).unwrap(), | ||||||
|  |             resolution: (resolution, resolution), | ||||||
|  |             format: TextureFormat::JPEG, | ||||||
|  |             texture_hash: Sha256::from_data(b"Some Hash"), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // data of example section of search document. | ||||||
|  |     fn test_data() -> Vec<Texture> { | ||||||
|  |         vec![ | ||||||
|  |             tex( | ||||||
|  |                 1, | ||||||
|  |                 "wood_185841", | ||||||
|  |                 "Holz, Dunkel, Rot, Edel", | ||||||
|  |                 "2019-05-15", | ||||||
|  |                 4 * 1024, | ||||||
|  |             ), | ||||||
|  |             tex(2, "wood_84846", "Holz, Hell", "2019-05-13", 2 * 1024), | ||||||
|  |             tex(3, "silk_large", "Stoff, Rot, Edel", "2018-01-01", 8 * 1024), | ||||||
|  |             tex(4, "cotton_xxx", "Stoff, Rot, Rau", "2018-02-01", 2048), | ||||||
|  |             tex(5, "green_frabric", "Grün, Stoff", "2018-03-01", 1024), | ||||||
|  |             tex(6, "tin54_45", "Metall, Hell", "2018-03-01", 4 * 1024), | ||||||
|  |             tex(7, "copper4_1k", "Rot, Metall", "2016-03-01", 1024), | ||||||
|  |             tex( | ||||||
|  |                 8, | ||||||
|  |                 "rusty_metall", | ||||||
|  |                 "Rot, Metall, Rost, Dunkel", | ||||||
|  |                 "2015-03-01", | ||||||
|  |                 8 * 1024, | ||||||
|  |             ), | ||||||
|  |         ] | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn assert_query(query: &str, expected: Vec<u8>) { | ||||||
|  |         let q = Query::parse( | ||||||
|  |             &query | ||||||
|  |                 .split_whitespace() | ||||||
|  |                 .map(|s| s.to_string()) | ||||||
|  |                 .collect::<Vec<String>>(), | ||||||
|  |         ) | ||||||
|  |         .unwrap(); | ||||||
|  |  | ||||||
|  |         let data = test_data(); | ||||||
|  |  | ||||||
|  |         let result = q.search(&mut data.iter()); | ||||||
|  |  | ||||||
|  |         let only_ids = result | ||||||
|  |             .into_iter() | ||||||
|  |             .map(|tex| tex.id.parse::<u8>().unwrap()) | ||||||
|  |             .collect::<Vec<u8>>(); | ||||||
|  |  | ||||||
|  |         assert_eq!(only_ids, expected) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn test_examples_from_doc_1() { | ||||||
|  |         assert_query("Holz Dunkel", vec![1, 2, 8]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn test_examples_from_doc_2() { | ||||||
|  |         assert_query("n:wood_", vec![1, 2]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn test_examples_from_doc_3() { | ||||||
|  |         assert_query("before:2019-05-31 after:2019-04-30", vec![1, 2]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn test_examples_from_doc_4() { | ||||||
|  |         assert_query("Stoff Rot Edel", vec![3, 4, 1]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn test_examples_from_doc_5() { | ||||||
|  |         assert_query("Stoff Rot !Edel", vec![4, 3, 5, 7, 8]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn test_examples_from_doc_6() { | ||||||
|  |         assert_query("Metall Dunkel res:4k", vec![8, 6, 1]); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user