xref: /aosp_15_r20/external/cronet/testing/data_driven_testing/data_driven_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "testing/data_driven_testing/data_driven_test.h"
6 
7 #include "base/files/file_enumerator.h"
8 #include "base/files/file_util.h"
9 #include "base/strings/string_util.h"
10 #include "base/threading/thread_restrictions.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "third_party/re2/src/re2/re2.h"
13 
14 namespace testing {
15 namespace {
16 
17 // Reads |file| into |content|, and converts Windows line-endings to Unix ones.
18 // Returns true on success.
ReadFile(const base::FilePath & file,std::string * content)19 bool ReadFile(const base::FilePath& file, std::string* content) {
20   if (!base::ReadFileToString(file, content))
21     return false;
22 
23   base::ReplaceSubstringsAfterOffset(content, 0, "\r\n", "\n");
24   return true;
25 }
26 
27 // Write |content| to |file|. Returns true on success.
WriteFile(const base::FilePath & file,const std::string & content)28 bool WriteFile(const base::FilePath& file, const std::string& content) {
29   return base::WriteFile(file, content);
30 }
31 
32 // Removes lines starting with (optional) whitespace and a #.
StripComments(std::string * content)33 void StripComments(std::string* content) {
34   RE2::GlobalReplace(
35       content,
36       // Enable multi-line mode, ^ and $ match begin/end line in addition to
37       // begin/end text.
38       "(?m)"
39       // Search for start of lines (^), ignore spaces (\\s*), and then look for
40       // '#'.
41       "^\\s*#"
42       // Consume all characters (.*) until end of line ($).
43       ".*$"
44       // Consume the line wrapping so that the entire line is gone.
45       "[\\r\\n]*",
46       // Replace entire line with empty string.
47       "");
48 }
49 
50 }  // namespace
51 
RunDataDrivenTest(const base::FilePath & input_directory,const base::FilePath & output_directory,const base::FilePath::StringType & file_name_pattern)52 void DataDrivenTest::RunDataDrivenTest(
53     const base::FilePath& input_directory,
54     const base::FilePath& output_directory,
55     const base::FilePath::StringType& file_name_pattern) {
56   base::ScopedAllowBlockingForTesting allow_blocking;
57   ASSERT_TRUE(base::DirectoryExists(input_directory));
58   ASSERT_TRUE(base::DirectoryExists(output_directory));
59   base::FileEnumerator input_files(
60       input_directory, false, base::FileEnumerator::FILES, file_name_pattern);
61   const bool kIsExpectedToPass = true;
62   for (base::FilePath input_file = input_files.Next(); !input_file.empty();
63        input_file = input_files.Next()) {
64     RunOneDataDrivenTest(input_file, output_directory, kIsExpectedToPass);
65   }
66 }
67 
RunOneDataDrivenTest(const base::FilePath & test_file_name,const base::FilePath & output_directory,bool is_expected_to_pass)68 void DataDrivenTest::RunOneDataDrivenTest(
69     const base::FilePath& test_file_name,
70     const base::FilePath& output_directory,
71     bool is_expected_to_pass) {
72   base::ScopedAllowBlockingForTesting allow_blocking;
73   // iOS doesn't get rid of removed test files. TODO(estade): remove this after
74   // all iOS bots are clobbered.
75   if (test_file_name.BaseName().value() == FILE_PATH_LITERAL("multimerge.in"))
76     return;
77 
78   ASSERT_TRUE(base::DirectoryExists(output_directory));
79   SCOPED_TRACE(test_file_name.BaseName().value());
80 
81   std::string input;
82   ReadFile(test_file_name, &input);
83 
84   std::string output;
85   {
86     base::ScopedDisallowBlocking disallow_blocking;
87     GenerateResults(input, &output);
88   }
89 
90   base::FilePath output_file = output_directory.Append(
91       test_file_name.BaseName().StripTrailingSeparators().ReplaceExtension(
92           FILE_PATH_LITERAL(".out")));
93 
94   std::string output_file_contents;
95   if (!ReadFile(output_file, &output_file_contents)) {
96     ASSERT_TRUE(WriteFile(output_file, output));
97     return;
98   }
99   // Remove comment lines (lead by '#' character).
100   StripComments(&output_file_contents);
101 
102   if (is_expected_to_pass) {
103     EXPECT_EQ(output_file_contents, output);
104   } else {
105     EXPECT_NE(output_file_contents, output);
106   }
107 }
108 
GetInputDirectory()109 base::FilePath DataDrivenTest::GetInputDirectory() {
110   return test_data_directory_.Append(feature_directory_)
111       .Append(test_name_)
112       .AppendASCII("input");
113 }
114 
GetOutputDirectory()115 base::FilePath DataDrivenTest::GetOutputDirectory() {
116   return test_data_directory_.Append(feature_directory_)
117       .Append(test_name_)
118       .AppendASCII("output");
119 }
120 
DataDrivenTest(const base::FilePath & test_data_directory,const base::FilePath::StringType & feature_directory,const base::FilePath::StringType & test_name)121 DataDrivenTest::DataDrivenTest(
122     const base::FilePath& test_data_directory,
123     const base::FilePath::StringType& feature_directory,
124     const base::FilePath::StringType& test_name)
125     : test_data_directory_(test_data_directory),
126       feature_directory_(feature_directory),
127       test_name_(test_name) {}
128 
~DataDrivenTest()129 DataDrivenTest::~DataDrivenTest() {}
130 
131 }  // namespace testing
132