mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-04 06:15:20 +00:00 
			
		
		
		
	Speed up build
This commit is contained in:
		
							parent
							
								
									c68548a2ca
								
							
						
					
					
						commit
						bee8bacefd
					
				@ -5,6 +5,7 @@
 | 
				
			|||||||
#include "optional.h"
 | 
					#include "optional.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <unordered_map>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct FileContents {
 | 
					struct FileContents {
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,15 @@ void VerifyUnique(const std::vector<T>& values0) {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					void RemoveRange(std::vector<T>* dest, const std::vector<T>& to_remove) {
 | 
				
			||||||
 | 
					  std::unordered_set<T> to_remove_set(to_remove.begin(), to_remove.end());
 | 
				
			||||||
 | 
					  dest->erase(
 | 
				
			||||||
 | 
					      std::remove_if(dest->begin(), dest->end(),
 | 
				
			||||||
 | 
					                     [&](const T& t) { return to_remove_set.count(t) > 0; }),
 | 
				
			||||||
 | 
					      dest->end());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<QueryType::Def> ToQuery(const IdMap& id_map,
 | 
					optional<QueryType::Def> ToQuery(const IdMap& id_map,
 | 
				
			||||||
                                 const IndexType::Def& type) {
 | 
					                                 const IndexType::Def& type) {
 | 
				
			||||||
  if (type.detailed_name.empty())
 | 
					  if (type.detailed_name.empty())
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										204
									
								
								src/test.cc
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								src/test.cc
									
									
									
									
									
								
							@ -5,8 +5,12 @@
 | 
				
			|||||||
#include "serializer.h"
 | 
					#include "serializer.h"
 | 
				
			||||||
#include "utils.h"
 | 
					#include "utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <doctest/doctest.h>
 | 
				
			||||||
 | 
					#include <loguru/loguru.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The 'diff' utility is available and we can use dprintf(3).
 | 
					// The 'diff' utility is available and we can use dprintf(3).
 | 
				
			||||||
@ -33,6 +37,155 @@ std::string ToString(const rapidjson::Document& document) {
 | 
				
			|||||||
  return UpdateToRnNewlines(output);
 | 
					  return UpdateToRnNewlines(output);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ParseTestExpectation(
 | 
				
			||||||
 | 
					    const std::string& filename,
 | 
				
			||||||
 | 
					    const std::vector<std::string>& lines_with_endings,
 | 
				
			||||||
 | 
					    TextReplacer* replacer,
 | 
				
			||||||
 | 
					    std::vector<std::string>* flags,
 | 
				
			||||||
 | 
					    std::unordered_map<std::string, std::string>* output_sections) {
 | 
				
			||||||
 | 
					#if false
 | 
				
			||||||
 | 
					#include "bar.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void foo();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					  // DOCS for TEXT_REPLACE:
 | 
				
			||||||
 | 
					  //  Each line under TEXT_REPLACE is a replacement, ie, the two entries will be
 | 
				
			||||||
 | 
					  //  considered equivalent. This is useful for USRs which vary across files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // DOCS for EXTRA_FLAGS:
 | 
				
			||||||
 | 
					  //  Additional flags to pass to clang.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // DOCS for OUTPUT:
 | 
				
			||||||
 | 
					  //  If no name is given assume to be this file name. If there is not an output
 | 
				
			||||||
 | 
					  //  section for a file it is not checked.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  TEXT_REPLACE:
 | 
				
			||||||
 | 
					  foo <===> bar
 | 
				
			||||||
 | 
					  one <===> two
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXTRA_FLAGS:
 | 
				
			||||||
 | 
					  -std=c++14
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  OUTPUT:
 | 
				
			||||||
 | 
					  {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  OUTPUT: bar.cc
 | 
				
			||||||
 | 
					  {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  OUTPUT: bar.h
 | 
				
			||||||
 | 
					  {}
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Scan for TEXT_REPLACE:
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    bool in_output = false;
 | 
				
			||||||
 | 
					    for (std::string line : lines_with_endings) {
 | 
				
			||||||
 | 
					      TrimInPlace(line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (StartsWith(line, "TEXT_REPLACE:")) {
 | 
				
			||||||
 | 
					        assert(!in_output && "multiple TEXT_REPLACE sections");
 | 
				
			||||||
 | 
					        in_output = true;
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (in_output && line.empty())
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (in_output) {
 | 
				
			||||||
 | 
					        static const std::string kKey = " <===> ";
 | 
				
			||||||
 | 
					        size_t index = line.find(kKey);
 | 
				
			||||||
 | 
					        LOG_IF_S(FATAL, index == std::string::npos)
 | 
				
			||||||
 | 
					            << " No '" << kKey << "' in replacement string '" << line << "'"
 | 
				
			||||||
 | 
					            << ", index=" << index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        TextReplacer::Replacement replacement;
 | 
				
			||||||
 | 
					        replacement.from = line.substr(0, index);
 | 
				
			||||||
 | 
					        replacement.to = line.substr(index + kKey.size());
 | 
				
			||||||
 | 
					        TrimInPlace(replacement.from);
 | 
				
			||||||
 | 
					        TrimInPlace(replacement.to);
 | 
				
			||||||
 | 
					        replacer->replacements.push_back(replacement);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Scan for EXTRA_FLAGS:
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    bool in_output = false;
 | 
				
			||||||
 | 
					    for (std::string line : lines_with_endings) {
 | 
				
			||||||
 | 
					      TrimInPlace(line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (StartsWith(line, "EXTRA_FLAGS:")) {
 | 
				
			||||||
 | 
					        assert(!in_output && "multiple EXTRA_FLAGS sections");
 | 
				
			||||||
 | 
					        in_output = true;
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (in_output && line.empty())
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (in_output)
 | 
				
			||||||
 | 
					        flags->push_back(line);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Scan for OUTPUT:
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    std::string active_output_filename;
 | 
				
			||||||
 | 
					    std::string active_output_contents;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool in_output = false;
 | 
				
			||||||
 | 
					    for (std::string line_with_ending : lines_with_endings) {
 | 
				
			||||||
 | 
					      if (StartsWith(line_with_ending, "*/"))
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (StartsWith(line_with_ending, "OUTPUT:")) {
 | 
				
			||||||
 | 
					        // Terminate the previous output section if we found a new one.
 | 
				
			||||||
 | 
					        if (in_output) {
 | 
				
			||||||
 | 
					          (*output_sections)[active_output_filename] = active_output_contents;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Try to tokenize OUTPUT: based one whitespace. If there is more than
 | 
				
			||||||
 | 
					        // one token assume it is a filename.
 | 
				
			||||||
 | 
					        std::vector<std::string> tokens = SplitString(line_with_ending, " ");
 | 
				
			||||||
 | 
					        if (tokens.size() > 1) {
 | 
				
			||||||
 | 
					          active_output_filename = tokens[1];
 | 
				
			||||||
 | 
					          TrimInPlace(active_output_filename);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          active_output_filename = filename;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        active_output_contents = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        in_output = true;
 | 
				
			||||||
 | 
					      } else if (in_output)
 | 
				
			||||||
 | 
					        active_output_contents += line_with_ending;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (in_output)
 | 
				
			||||||
 | 
					      (*output_sections)[active_output_filename] = active_output_contents;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UpdateTestExpectation(const std::string& filename,
 | 
				
			||||||
 | 
					                           const std::string& expectation,
 | 
				
			||||||
 | 
					                           const std::string& actual) {
 | 
				
			||||||
 | 
					  // Read the entire file into a string.
 | 
				
			||||||
 | 
					  std::ifstream in(filename);
 | 
				
			||||||
 | 
					  std::string str;
 | 
				
			||||||
 | 
					  str.assign(std::istreambuf_iterator<char>(in),
 | 
				
			||||||
 | 
					             std::istreambuf_iterator<char>());
 | 
				
			||||||
 | 
					  in.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Replace expectation
 | 
				
			||||||
 | 
					  auto it = str.find(expectation);
 | 
				
			||||||
 | 
					  assert(it != std::string::npos);
 | 
				
			||||||
 | 
					  str.replace(it, expectation.size(), actual);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Write it back out.
 | 
				
			||||||
 | 
					  WriteToFile(filename, str);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DiffDocuments(std::string path,
 | 
					void DiffDocuments(std::string path,
 | 
				
			||||||
                   std::string path_section,
 | 
					                   std::string path_section,
 | 
				
			||||||
                   rapidjson::Document& expected,
 | 
					                   rapidjson::Document& expected,
 | 
				
			||||||
@ -309,3 +462,54 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
 | 
				
			|||||||
// TODO: ctor/dtor, copy ctor
 | 
					// TODO: ctor/dtor, copy ctor
 | 
				
			||||||
// TODO: Always pass IndexFile by pointer, ie, search and remove all IndexFile&
 | 
					// TODO: Always pass IndexFile by pointer, ie, search and remove all IndexFile&
 | 
				
			||||||
// refs.
 | 
					// refs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_SUITE("ParseTestExpectation") {
 | 
				
			||||||
 | 
					  TEST_CASE("Parse TEXT_REPLACE") {
 | 
				
			||||||
 | 
					    // clang-format off
 | 
				
			||||||
 | 
					    std::vector<std::string> lines_with_endings = {
 | 
				
			||||||
 | 
					        "/*\n",
 | 
				
			||||||
 | 
					        "TEXT_REPLACE:\n",
 | 
				
			||||||
 | 
					        "  foo   <===> \tbar  \n",
 | 
				
			||||||
 | 
					        "01 <===> 2\n",
 | 
				
			||||||
 | 
					        "\n",
 | 
				
			||||||
 | 
					        "*/\n"};
 | 
				
			||||||
 | 
					    // clang-format on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TextReplacer text_replacer;
 | 
				
			||||||
 | 
					    std::vector<std::string> flags;
 | 
				
			||||||
 | 
					    std::unordered_map<std::string, std::string> all_expected_output;
 | 
				
			||||||
 | 
					    ParseTestExpectation("foo.cc", lines_with_endings, &text_replacer, &flags,
 | 
				
			||||||
 | 
					                         &all_expected_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    REQUIRE(text_replacer.replacements.size() == 2);
 | 
				
			||||||
 | 
					    REQUIRE(text_replacer.replacements[0].from == "foo");
 | 
				
			||||||
 | 
					    REQUIRE(text_replacer.replacements[0].to == "bar");
 | 
				
			||||||
 | 
					    REQUIRE(text_replacer.replacements[1].from == "01");
 | 
				
			||||||
 | 
					    REQUIRE(text_replacer.replacements[1].to == "2");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  TEST_CASE("Apply TEXT_REPLACE") {
 | 
				
			||||||
 | 
					    TextReplacer replacer;
 | 
				
			||||||
 | 
					    replacer.replacements.push_back(TextReplacer::Replacement{"foo", "bar"});
 | 
				
			||||||
 | 
					    replacer.replacements.push_back(TextReplacer::Replacement{"01", "2"});
 | 
				
			||||||
 | 
					    replacer.replacements.push_back(TextReplacer::Replacement{"3", "456"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Equal-length.
 | 
				
			||||||
 | 
					    REQUIRE(replacer.Apply("foo") == "bar");
 | 
				
			||||||
 | 
					    REQUIRE(replacer.Apply("bar") == "bar");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Shorter replacement.
 | 
				
			||||||
 | 
					    REQUIRE(replacer.Apply("01") == "2");
 | 
				
			||||||
 | 
					    REQUIRE(replacer.Apply("2") == "2");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Longer replacement.
 | 
				
			||||||
 | 
					    REQUIRE(replacer.Apply("3") == "456");
 | 
				
			||||||
 | 
					    REQUIRE(replacer.Apply("456") == "456");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Content before-after replacement.
 | 
				
			||||||
 | 
					    REQUIRE(replacer.Apply("aaaa01bbbb") == "aaaa2bbbb");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Multiple replacements.
 | 
				
			||||||
 | 
					    REQUIRE(replacer.Apply("foofoobar0123") == "barbarbar22456");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										200
									
								
								src/utils.cc
									
									
									
									
									
								
							
							
						
						
									
										200
									
								
								src/utils.cc
									
									
									
									
									
								
							@ -374,155 +374,6 @@ std::string TextReplacer::Apply(const std::string& content) {
 | 
				
			|||||||
  return result;
 | 
					  return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ParseTestExpectation(
 | 
					 | 
				
			||||||
    const std::string& filename,
 | 
					 | 
				
			||||||
    const std::vector<std::string>& lines_with_endings,
 | 
					 | 
				
			||||||
    TextReplacer* replacer,
 | 
					 | 
				
			||||||
    std::vector<std::string>* flags,
 | 
					 | 
				
			||||||
    std::unordered_map<std::string, std::string>* output_sections) {
 | 
					 | 
				
			||||||
#if false
 | 
					 | 
				
			||||||
#include "bar.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void foo();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /*
 | 
					 | 
				
			||||||
  // DOCS for TEXT_REPLACE:
 | 
					 | 
				
			||||||
  //  Each line under TEXT_REPLACE is a replacement, ie, the two entries will be
 | 
					 | 
				
			||||||
  //  considered equivalent. This is useful for USRs which vary across files.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // DOCS for EXTRA_FLAGS:
 | 
					 | 
				
			||||||
  //  Additional flags to pass to clang.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // DOCS for OUTPUT:
 | 
					 | 
				
			||||||
  //  If no name is given assume to be this file name. If there is not an output
 | 
					 | 
				
			||||||
  //  section for a file it is not checked.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  TEXT_REPLACE:
 | 
					 | 
				
			||||||
  foo <===> bar
 | 
					 | 
				
			||||||
  one <===> two
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  EXTRA_FLAGS:
 | 
					 | 
				
			||||||
  -std=c++14
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  OUTPUT:
 | 
					 | 
				
			||||||
  {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  OUTPUT: bar.cc
 | 
					 | 
				
			||||||
  {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  OUTPUT: bar.h
 | 
					 | 
				
			||||||
  {}
 | 
					 | 
				
			||||||
  */
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Scan for TEXT_REPLACE:
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    bool in_output = false;
 | 
					 | 
				
			||||||
    for (std::string line : lines_with_endings) {
 | 
					 | 
				
			||||||
      TrimInPlace(line);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (StartsWith(line, "TEXT_REPLACE:")) {
 | 
					 | 
				
			||||||
        assert(!in_output && "multiple TEXT_REPLACE sections");
 | 
					 | 
				
			||||||
        in_output = true;
 | 
					 | 
				
			||||||
        continue;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (in_output && line.empty())
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (in_output) {
 | 
					 | 
				
			||||||
        static const std::string kKey = " <===> ";
 | 
					 | 
				
			||||||
        size_t index = line.find(kKey);
 | 
					 | 
				
			||||||
        LOG_IF_S(FATAL, index == std::string::npos)
 | 
					 | 
				
			||||||
            << " No '" << kKey << "' in replacement string '" << line << "'"
 | 
					 | 
				
			||||||
            << ", index=" << index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        TextReplacer::Replacement replacement;
 | 
					 | 
				
			||||||
        replacement.from = line.substr(0, index);
 | 
					 | 
				
			||||||
        replacement.to = line.substr(index + kKey.size());
 | 
					 | 
				
			||||||
        TrimInPlace(replacement.from);
 | 
					 | 
				
			||||||
        TrimInPlace(replacement.to);
 | 
					 | 
				
			||||||
        replacer->replacements.push_back(replacement);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Scan for EXTRA_FLAGS:
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    bool in_output = false;
 | 
					 | 
				
			||||||
    for (std::string line : lines_with_endings) {
 | 
					 | 
				
			||||||
      TrimInPlace(line);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (StartsWith(line, "EXTRA_FLAGS:")) {
 | 
					 | 
				
			||||||
        assert(!in_output && "multiple EXTRA_FLAGS sections");
 | 
					 | 
				
			||||||
        in_output = true;
 | 
					 | 
				
			||||||
        continue;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (in_output && line.empty())
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (in_output)
 | 
					 | 
				
			||||||
        flags->push_back(line);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Scan for OUTPUT:
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    std::string active_output_filename;
 | 
					 | 
				
			||||||
    std::string active_output_contents;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool in_output = false;
 | 
					 | 
				
			||||||
    for (std::string line_with_ending : lines_with_endings) {
 | 
					 | 
				
			||||||
      if (StartsWith(line_with_ending, "*/"))
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (StartsWith(line_with_ending, "OUTPUT:")) {
 | 
					 | 
				
			||||||
        // Terminate the previous output section if we found a new one.
 | 
					 | 
				
			||||||
        if (in_output) {
 | 
					 | 
				
			||||||
          (*output_sections)[active_output_filename] = active_output_contents;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Try to tokenize OUTPUT: based one whitespace. If there is more than
 | 
					 | 
				
			||||||
        // one token assume it is a filename.
 | 
					 | 
				
			||||||
        std::vector<std::string> tokens = SplitString(line_with_ending, " ");
 | 
					 | 
				
			||||||
        if (tokens.size() > 1) {
 | 
					 | 
				
			||||||
          active_output_filename = tokens[1];
 | 
					 | 
				
			||||||
          TrimInPlace(active_output_filename);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          active_output_filename = filename;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        active_output_contents = "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        in_output = true;
 | 
					 | 
				
			||||||
      } else if (in_output)
 | 
					 | 
				
			||||||
        active_output_contents += line_with_ending;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (in_output)
 | 
					 | 
				
			||||||
      (*output_sections)[active_output_filename] = active_output_contents;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void UpdateTestExpectation(const std::string& filename,
 | 
					 | 
				
			||||||
                           const std::string& expectation,
 | 
					 | 
				
			||||||
                           const std::string& actual) {
 | 
					 | 
				
			||||||
  // Read the entire file into a string.
 | 
					 | 
				
			||||||
  std::ifstream in(filename);
 | 
					 | 
				
			||||||
  std::string str;
 | 
					 | 
				
			||||||
  str.assign(std::istreambuf_iterator<char>(in),
 | 
					 | 
				
			||||||
             std::istreambuf_iterator<char>());
 | 
					 | 
				
			||||||
  in.close();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Replace expectation
 | 
					 | 
				
			||||||
  auto it = str.find(expectation);
 | 
					 | 
				
			||||||
  assert(it != std::string::npos);
 | 
					 | 
				
			||||||
  str.replace(it, expectation.size(), actual);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Write it back out.
 | 
					 | 
				
			||||||
  WriteToFile(filename, str);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void WriteToFile(const std::string& filename, const std::string& content) {
 | 
					void WriteToFile(const std::string& filename, const std::string& content) {
 | 
				
			||||||
  std::ofstream file(filename,
 | 
					  std::ofstream file(filename,
 | 
				
			||||||
                     std::ios::out | std::ios::trunc | std::ios::binary);
 | 
					                     std::ios::out | std::ios::trunc | std::ios::binary);
 | 
				
			||||||
@ -601,57 +452,6 @@ std::string UpdateToRnNewlines(std::string output) {
 | 
				
			|||||||
  return output;
 | 
					  return output;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_SUITE("ParseTestExpectation") {
 | 
					 | 
				
			||||||
  TEST_CASE("Parse TEXT_REPLACE") {
 | 
					 | 
				
			||||||
    // clang-format off
 | 
					 | 
				
			||||||
    std::vector<std::string> lines_with_endings = {
 | 
					 | 
				
			||||||
        "/*\n",
 | 
					 | 
				
			||||||
        "TEXT_REPLACE:\n",
 | 
					 | 
				
			||||||
        "  foo   <===> \tbar  \n",
 | 
					 | 
				
			||||||
        "01 <===> 2\n",
 | 
					 | 
				
			||||||
        "\n",
 | 
					 | 
				
			||||||
        "*/\n"};
 | 
					 | 
				
			||||||
    // clang-format on
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    TextReplacer text_replacer;
 | 
					 | 
				
			||||||
    std::vector<std::string> flags;
 | 
					 | 
				
			||||||
    std::unordered_map<std::string, std::string> all_expected_output;
 | 
					 | 
				
			||||||
    ParseTestExpectation("foo.cc", lines_with_endings, &text_replacer, &flags,
 | 
					 | 
				
			||||||
                         &all_expected_output);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    REQUIRE(text_replacer.replacements.size() == 2);
 | 
					 | 
				
			||||||
    REQUIRE(text_replacer.replacements[0].from == "foo");
 | 
					 | 
				
			||||||
    REQUIRE(text_replacer.replacements[0].to == "bar");
 | 
					 | 
				
			||||||
    REQUIRE(text_replacer.replacements[1].from == "01");
 | 
					 | 
				
			||||||
    REQUIRE(text_replacer.replacements[1].to == "2");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  TEST_CASE("Apply TEXT_REPLACE") {
 | 
					 | 
				
			||||||
    TextReplacer replacer;
 | 
					 | 
				
			||||||
    replacer.replacements.push_back(TextReplacer::Replacement{"foo", "bar"});
 | 
					 | 
				
			||||||
    replacer.replacements.push_back(TextReplacer::Replacement{"01", "2"});
 | 
					 | 
				
			||||||
    replacer.replacements.push_back(TextReplacer::Replacement{"3", "456"});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Equal-length.
 | 
					 | 
				
			||||||
    REQUIRE(replacer.Apply("foo") == "bar");
 | 
					 | 
				
			||||||
    REQUIRE(replacer.Apply("bar") == "bar");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Shorter replacement.
 | 
					 | 
				
			||||||
    REQUIRE(replacer.Apply("01") == "2");
 | 
					 | 
				
			||||||
    REQUIRE(replacer.Apply("2") == "2");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Longer replacement.
 | 
					 | 
				
			||||||
    REQUIRE(replacer.Apply("3") == "456");
 | 
					 | 
				
			||||||
    REQUIRE(replacer.Apply("456") == "456");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Content before-after replacement.
 | 
					 | 
				
			||||||
    REQUIRE(replacer.Apply("aaaa01bbbb") == "aaaa2bbbb");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Multiple replacements.
 | 
					 | 
				
			||||||
    REQUIRE(replacer.Apply("foofoobar0123") == "barbarbar22456");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_SUITE("Update \\n to \\r\\n") {
 | 
					TEST_SUITE("Update \\n to \\r\\n") {
 | 
				
			||||||
  TEST_CASE("all") {
 | 
					  TEST_CASE("all") {
 | 
				
			||||||
    REQUIRE(UpdateToRnNewlines("\n") == "\r\n");
 | 
					    REQUIRE(UpdateToRnNewlines("\n") == "\r\n");
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										22
									
								
								src/utils.h
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/utils.h
									
									
									
									
									
								
							@ -7,8 +7,6 @@
 | 
				
			|||||||
#include <iterator>
 | 
					#include <iterator>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <unordered_map>
 | 
					 | 
				
			||||||
#include <unordered_set>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Trim from start (in place)
 | 
					// Trim from start (in place)
 | 
				
			||||||
@ -111,17 +109,6 @@ struct TextReplacer {
 | 
				
			|||||||
  std::string Apply(const std::string& content);
 | 
					  std::string Apply(const std::string& content);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ParseTestExpectation(
 | 
					 | 
				
			||||||
    const std::string& filename,
 | 
					 | 
				
			||||||
    const std::vector<std::string>& lines_with_endings,
 | 
					 | 
				
			||||||
    TextReplacer* text_replacer,
 | 
					 | 
				
			||||||
    std::vector<std::string>* flags,
 | 
					 | 
				
			||||||
    std::unordered_map<std::string, std::string>* output_sections);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void UpdateTestExpectation(const std::string& filename,
 | 
					 | 
				
			||||||
                           const std::string& expectation,
 | 
					 | 
				
			||||||
                           const std::string& actual);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void WriteToFile(const std::string& filename, const std::string& content);
 | 
					void WriteToFile(const std::string& filename, const std::string& content);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// note: this implementation does not disable this overload for array types
 | 
					// note: this implementation does not disable this overload for array types
 | 
				
			||||||
@ -143,15 +130,6 @@ void AddRange(std::vector<T>* dest, std::vector<T>&& to_add) {
 | 
				
			|||||||
               std::make_move_iterator(to_add.end()));
 | 
					               std::make_move_iterator(to_add.end()));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T>
 | 
					 | 
				
			||||||
void RemoveRange(std::vector<T>* dest, const std::vector<T>& to_remove) {
 | 
					 | 
				
			||||||
  std::unordered_set<T> to_remove_set(to_remove.begin(), to_remove.end());
 | 
					 | 
				
			||||||
  dest->erase(
 | 
					 | 
				
			||||||
      std::remove_if(dest->begin(), dest->end(),
 | 
					 | 
				
			||||||
                     [&](const T& t) { return to_remove_set.count(t) > 0; }),
 | 
					 | 
				
			||||||
      dest->end());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// http://stackoverflow.com/a/38140932
 | 
					// http://stackoverflow.com/a/38140932
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//  struct SomeHashKey {
 | 
					//  struct SomeHashKey {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user