Advertisement
kutuzzzov

Урок 7. Юнит-тестирование поисковой системы

Nov 29th, 2021
1,661
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.29 KB | None | 0 0
  1. // для прохождения проверки удалить всё что не тесты!!!!!
  2.  
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <cassert>
  6. #include <cmath>
  7. #include <map>
  8. #include <set>
  9. #include <string>
  10. #include <utility>
  11. #include <vector>
  12.  
  13. using namespace std;
  14.  
  15. /* Подставьте вашу реализацию класса SearchServer сюда */
  16.  
  17. struct Document {
  18.     int id;
  19.     double relevance;
  20.     int rating;
  21. };
  22.  
  23. enum class DocumentStatus {
  24.     ACTUAL,
  25.     IRRELEVANT,
  26.     BANNED,
  27.     REMOVED,
  28. };
  29.  
  30. class SearchServer {
  31. public:
  32.     void SetStopWords(const string& text) {
  33.         for (const string& word : SplitIntoWords(text)) {
  34.             stop_words_.insert(word);
  35.         }
  36.     }    
  37.    
  38.     void AddDocument(int document_id, const string& document, DocumentStatus status, const vector<int>& ratings) {
  39.         const vector<string> words = SplitIntoWordsNoStop(document);
  40.         const double inv_word_count = 1.0 / words.size();
  41.         for (const string& word : words) {
  42.             word_to_document_freqs_[word][document_id] += inv_word_count;
  43.         }
  44.         documents_.emplace(document_id,
  45.             DocumentData{
  46.                 ComputeAverageRating(ratings),
  47.                 status
  48.             });
  49.     }
  50.    
  51.     template <typename DocumentPredicate>
  52.     vector<Document> FindTopDocuments(const string& raw_query, DocumentPredicate document_predicate) const {            
  53.         const Query query = ParseQuery(raw_query);
  54.         auto matched_documents = FindAllDocuments(query, document_predicate);
  55.         sort(matched_documents.begin(), matched_documents.end(),
  56.              [](const Document& lhs, const Document& rhs) {
  57.                 if (abs(lhs.relevance - rhs.relevance) < 1e-6) {
  58.                     return lhs.rating > rhs.rating;
  59.                 } else {
  60.                     return lhs.relevance > rhs.relevance;
  61.                 }
  62.              });
  63.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  64.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  65.         }
  66.         return matched_documents;
  67.     }
  68.    
  69.     vector<Document> FindTopDocuments(const string& raw_query, DocumentStatus status) const {
  70.         return FindTopDocuments(raw_query, [&status](int document_id, DocumentStatus status_new, int rating) {return status_new == status;});
  71.     }
  72.    
  73.     vector<Document> FindTopDocuments(const string& raw_query) const {
  74.         return FindTopDocuments(raw_query,
  75.              [](int document_id, const DocumentStatus& status, int rating) {return status == DocumentStatus::ACTUAL;;});
  76.     }  
  77.    
  78.     int GetDocumentCount() const {
  79.         return documents_.size();
  80.     }
  81.    
  82.     tuple<vector<string>, DocumentStatus> MatchDocument(const string& raw_query, int document_id) const {
  83.         const Query query = ParseQuery(raw_query);
  84.         vector<string> matched_words;
  85.         for (const string& word : query.plus_words) {
  86.             if (word_to_document_freqs_.count(word) == 0) {
  87.                 continue;
  88.             }
  89.             if (word_to_document_freqs_.at(word).count(document_id)) {
  90.                 matched_words.push_back(word);
  91.             }
  92.         }
  93.         for (const string& word : query.minus_words) {
  94.             if (word_to_document_freqs_.count(word) == 0) {
  95.                 continue;
  96.             }
  97.             if (word_to_document_freqs_.at(word).count(document_id)) {
  98.                 matched_words.clear();
  99.                 break;
  100.             }
  101.         }
  102.         return {matched_words, documents_.at(document_id).status};
  103.     }
  104.  
  105. private:
  106.     struct DocumentData {
  107.         int rating;
  108.         DocumentStatus status;
  109.     };
  110.  
  111.     set<string> stop_words_;
  112.     map<string, map<int, double>> word_to_document_freqs_;
  113.     map<int, DocumentData> documents_;  
  114.    
  115.     bool IsStopWord(const string& word) const {
  116.         return stop_words_.count(word) > 0;
  117.     }
  118.    
  119.     vector<string> SplitIntoWordsNoStop(const string& text) const {
  120.         vector<string> words;
  121.         for (const string& word : SplitIntoWords(text)) {
  122.             if (!IsStopWord(word)) {
  123.                 words.push_back(word);
  124.             }
  125.         }
  126.         return words;
  127.     }
  128.    
  129.     static int ComputeAverageRating(const vector<int>& ratings) {
  130.         if (ratings.empty()) {
  131.             return 0;
  132.         }
  133.         int rating_sum = 0;
  134.         for (const int rating : ratings) {
  135.             rating_sum += rating;
  136.         }
  137.         return rating_sum / static_cast<int>(ratings.size());
  138.     }
  139.    
  140.     struct QueryWord {
  141.         string data;
  142.         bool is_minus;
  143.         bool is_stop;
  144.     };
  145.    
  146.     QueryWord ParseQueryWord(string text) const {
  147.         bool is_minus = false;
  148.         // Word shouldn't be empty
  149.         if (text[0] == '-') {
  150.             is_minus = true;
  151.             text = text.substr(1);
  152.         }
  153.         return {
  154.             text,
  155.             is_minus,
  156.             IsStopWord(text)
  157.         };
  158.     }
  159.    
  160.     struct Query {
  161.         set<string> plus_words;
  162.         set<string> minus_words;
  163.     };
  164.    
  165.     Query ParseQuery(const string& text) const {
  166.         Query query;
  167.         for (const string& word : SplitIntoWords(text)) {
  168.             const QueryWord query_word = ParseQueryWord(word);
  169.             if (!query_word.is_stop) {
  170.                 if (query_word.is_minus) {
  171.                     query.minus_words.insert(query_word.data);
  172.                 } else {
  173.                     query.plus_words.insert(query_word.data);
  174.                 }
  175.             }
  176.         }
  177.         return query;
  178.     }
  179.    
  180.     double ComputeWordInverseDocumentFreq(const string& word) const {
  181.         return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  182.     }
  183.  
  184.     template <typename DocumentPredicate>
  185.     vector<Document> FindAllDocuments(const Query& query, DocumentPredicate document_predicate) const {
  186.     map<int, double> document_to_relevance;
  187.         for (const string& word : query.plus_words) {
  188.             if (word_to_document_freqs_.count(word) == 0) {
  189.                 continue;
  190.             }
  191.             const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  192.             for (const auto [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  193.                 DocumentData documents_data = documents_.at(document_id);
  194.                 if (document_predicate(document_id, documents_data.status, documents_data.rating)) {
  195.                     document_to_relevance[document_id] += term_freq * inverse_document_freq;
  196.                 }
  197.             }
  198.         }
  199.        
  200.         for (const string& word : query.minus_words) {
  201.             if (word_to_document_freqs_.count(word) == 0) {
  202.                 continue;
  203.             }
  204.             for (const auto [document_id, _] : word_to_document_freqs_.at(word)) {
  205.                 document_to_relevance.erase(document_id);
  206.             }
  207.         }
  208.  
  209.         vector<Document> matched_documents;
  210.         for (const auto [document_id, relevance] : document_to_relevance) {
  211.             matched_documents.push_back({
  212.                 document_id,
  213.                 relevance,
  214.                 documents_.at(document_id).rating
  215.             });
  216.         }
  217.         return matched_documents;
  218.     }
  219. };
  220.  
  221. // -------- Начало модульных тестов поисковой системы ----------
  222.  
  223. // Тест проверяет, что поисковая система исключает стоп-слова при добавлении документов
  224. void TestExcludeStopWordsFromAddedDocumentContent() {
  225.     const int doc_id = 42;
  226.     const string content = "cat in the city"s;
  227.     const vector<int> ratings = {1, 2, 3};
  228.     // Сначала убеждаемся, что поиск слова, не входящего в список стоп-слов,
  229.     // находит нужный документ
  230.     {
  231.         SearchServer server;
  232.         server.AddDocument(doc_id, content, DocumentStatus::ACTUAL, ratings);
  233.         const auto found_docs = server.FindTopDocuments("in"s);
  234.         assert(found_docs.size() == 1);
  235.         const Document& doc0 = found_docs[0];
  236.         assert(doc0.id == doc_id);
  237.     }
  238.  
  239.     // Затем убеждаемся, что поиск этого же слова, входящего в список стоп-слов,
  240.     // возвращает пустой результат
  241.     {
  242.         SearchServer server;
  243.         server.SetStopWords("in the"s);
  244.         server.AddDocument(doc_id, content, DocumentStatus::ACTUAL, ratings);
  245.         assert(server.FindTopDocuments("in"s).empty());
  246.     }
  247. }
  248.  
  249.     // Разместите код остальных тестов здесь
  250. void TestSearchServerMatched(){
  251.     {
  252.         SearchServer server;
  253.         server.AddDocument(0, "белый кот и модный ошейник"s, DocumentStatus::ACTUAL, {8, -3});
  254.         const int document_count = server.GetDocumentCount();
  255.         for (int document_id = 0; document_id < document_count; ++document_id) {
  256.             const auto [words, status] = server.MatchDocument("пушистый кот"s, document_id);
  257.         assert(words.size() == 1);
  258.         assert(document_id == 0);
  259.         assert(status == DocumentStatus::ACTUAL);
  260.         }
  261.     }
  262.     {
  263.         SearchServer server;
  264.         server.SetStopWords("кот"s);
  265.         server.AddDocument(0, "белый кот и модный ошейник"s, DocumentStatus::ACTUAL, {8, -3});
  266.  
  267.         const int document_count = server.GetDocumentCount();
  268.         for (int document_id = 0; document_id < document_count; ++document_id) {
  269.             const auto [words, status] = server.MatchDocument("пушистый кот"s, document_id);
  270.         assert(words.size() == 0);
  271.         assert(document_id == 0);
  272.         assert(status == DocumentStatus::ACTUAL);
  273.  
  274.         }
  275.     }
  276. }
  277.  
  278. void TestSearchServerRelevanse(){
  279.     SearchServer server;
  280. //    server.SetStopWords("и в на"s);
  281.     server.AddDocument(0, "белый кот и модный ошейник"s,        DocumentStatus::ACTUAL, {8, -3});
  282.     server.AddDocument(1, "пушистый кот пушистый хвост"s,       DocumentStatus::ACTUAL, {7, 2, 7});
  283.     server.AddDocument(2, "ухоженный пёс выразительные глаза"s, DocumentStatus::ACTUAL, {5, -12, 2, 1});
  284.     server.AddDocument(3, "ухоженный скворец евгений"s,         DocumentStatus::BANNED, {9});
  285.  
  286.     const auto& documents = server.FindTopDocuments("пушистый ухоженный кот"s);
  287.  
  288.     int doc_size = documents.size();
  289.     for(int i =0; i < doc_size; ++i){
  290.     assert(documents[i].relevance > documents[i + 1].relevance);
  291.     }
  292. }
  293.  
  294. // Функция TestSearchServer является точкой входа для запуска тестов
  295. void TestSearchServer() {
  296.     TestExcludeStopWordsFromAddedDocumentContent();
  297.     // Не забудьте вызывать остальные тесты здесь
  298.     TestSearchServerMatched();
  299.     TestSearchServerRelevanse();
  300. }
  301.  
  302. // --------- Окончание модульных тестов поисковой системы -----------
  303. int main() {
  304.     TestSearchServer();
  305.     // Если вы видите эту строку, значит все тесты прошли успешно
  306.     cout << "Search server testing finished"s << endl;
  307. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement