1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // TODO(team): switch to re2 library
16 #include <regex> // NOLINT
17 #include <string>
18
19 #include "gtest/gtest.h"
20 #include "absl/flags/flag.h"
21 #include "absl/strings/str_cat.h"
22 #include "absl/strings/string_view.h"
23 #include "fcp/base/monitoring.h"
24 #include "fcp/base/platform.h"
25 #include "fcp/testing/testing.h"
26
27 ABSL_FLAG(std::string, codegen_tool_path, "", "Path to codegen tool script");
28
29 namespace fcp {
30 namespace {
31
32 const char* kBaselineDir = "fcp/tracing/tools/testdata";
33
PostProcessOutput(const std::string & input)34 std::string PostProcessOutput(const std::string& input) {
35 std::regex header_guard_simplifier(
36 "(THIRD_PARTY_)?FCP_TRACING_TOOLS_TESTDATA");
37 std::string header_guard_replaced = std::regex_replace(
38 input, header_guard_simplifier, "THIRD_PARTY_FCP_TRACING_TOOLS_TESTDATA");
39 std::regex runfiles_path_simplifier("\".*runfiles.*fcp/tracing");
40 // replaces the runfile directory with {RUNFILE_PATH} for testing purposes
41 std::string runfiles_replaced = std::regex_replace(
42 header_guard_replaced, runfiles_path_simplifier, "\"${RUNFILE_PATH}");
43 std::regex path_simplifier_pattern("( |\")(\\w+/)*fcp/tracing");
44 // replaces the directory of the .fbs for testing purposes
45 std::string directory_replaced = std::regex_replace(
46 runfiles_replaced, path_simplifier_pattern, "$1${DIR}");
47 std::regex fcp_base_path_simplifier("(\\w+/)?fcp/base");
48 return std::regex_replace(directory_replaced, fcp_base_path_simplifier,
49 "${BASE}");
50 }
51
DoTest()52 void DoTest() {
53 std::string source_file = absl::StrCat(TestName(), ".fbs");
54 std::string source_path =
55 GetTestDataPath(ConcatPath(kBaselineDir, source_file));
56
57 // Read fsb source file derived from the test name:
58 StatusOr<std::string> source_s = ReadFileToString(source_path);
59 ASSERT_THAT(source_s, IsOk()) << "Can't read " << source_path;
60 std::string source = source_s.value();
61
62 std::string out_file =
63 ConcatPath(testing::TempDir(), absl::StrCat(TestName(), ".out"));
64 std::string err_file =
65 ConcatPath(testing::TempDir(), absl::StrCat(TestName(), ".err"));
66
67 // Run codegen script, redirecting stdout to out_file and stderr to err_file
68 int exit_code = system(
69 absl::StrCat(GetTestDataPath(absl::GetFlag(FLAGS_codegen_tool_path)), " ",
70 source_path, " ", testing::TempDir(), " ", kBaselineDir,
71 " 1> ", out_file, " 2> ", err_file)
72 .c_str());
73
74 // Reading error and out files
75 std::string out = ReadFileToString(out_file).value();
76 std::string err = ReadFileToString(err_file).value();
77
78 if (exit_code != 0) {
79 // Codegen failed. This might be expected depending on the test.
80 // In the case of failure we're not interested in capturing possible partial
81 // output in baseline file.
82 out.clear();
83 if (err.empty()) {
84 // If error is not empty it already contains relevant diagnostics,
85 // otherwise adding information about exit code.
86 err = absl::StrCat("Exit code ", exit_code);
87 }
88 }
89
90 // Producing report which is expected to precisely match .baseline file.
91 std::ostringstream report;
92 report << "============== " << source_file << " ============" << std::endl;
93 report << PostProcessOutput(source) << std::endl;
94 report << "============== diagnosis ============" << std::endl;
95 report << PostProcessOutput(err) << std::endl;
96 report << "============== result ============" << std::endl;
97 report << PostProcessOutput(out) << std::endl;
98
99 // Compare produced report with baseline.
100 std::string baseline_path =
101 ConcatPath(kBaselineDir, absl::StrCat(TestName(), ".baseline"));
102 auto status_s = VerifyAgainstBaseline(baseline_path, report.str());
103 ASSERT_TRUE(status_s.ok()) << status_s.status();
104 auto& diff = status_s.value();
105 if (!diff.empty()) {
106 FAIL() << diff;
107 }
108 }
109
TEST(Codegen,EmptyTable)110 TEST(Codegen, EmptyTable) { DoTest(); }
TEST(Codegen,FieldsOfDifferentTypes)111 TEST(Codegen, FieldsOfDifferentTypes) { DoTest(); }
TEST(Codegen,DeprecatedField)112 TEST(Codegen, DeprecatedField) { DoTest(); }
TEST(Codegen,NonTableObjectsAreSkipped)113 TEST(Codegen, NonTableObjectsAreSkipped) { DoTest(); }
TEST(Codegen,AllTypes)114 TEST(Codegen, AllTypes) { DoTest(); }
TEST(Codegen,OrderWithIds)115 TEST(Codegen, OrderWithIds) { DoTest(); }
TEST(Codegen,NoTag)116 TEST(Codegen, NoTag) { DoTest(); }
TEST(Codegen,NoAttributes)117 TEST(Codegen, NoAttributes) { DoTest(); }
TEST(Codegen,TagTooLong)118 TEST(Codegen, TagTooLong) { DoTest(); }
TEST(Codegen,DuplicateTags)119 TEST(Codegen, DuplicateTags) { DoTest(); }
TEST(Codegen,UnsupportedType)120 TEST(Codegen, UnsupportedType) { DoTest(); }
TEST(Codegen,TableWithNamespace)121 TEST(Codegen, TableWithNamespace) { DoTest(); }
TEST(Codegen,EnumType)122 TEST(Codegen, EnumType) { DoTest(); }
123
124 } // namespace
125 } // namespace fcp
126