P4C
The P4 Compiler
Loading...
Searching...
No Matches
test_framework.h
1/*
2 * SPDX-FileCopyrightText: 2023 Google LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#ifndef BACKENDS_P4TOOLS_MODULES_TESTGEN_LIB_TEST_FRAMEWORK_H_
8#define BACKENDS_P4TOOLS_MODULES_TESTGEN_LIB_TEST_FRAMEWORK_H_
9
10#include <cstddef>
11#include <filesystem>
12#include <functional>
13#include <iosfwd>
14#include <map>
15#include <optional>
16#include <string>
17#include <utility>
18
19#include <inja/inja.hpp>
20
21#include "backends/p4tools/common/lib/format_int.h"
22#include "backends/p4tools/common/lib/trace_event.h"
23#include "lib/castable.h"
24#include "lib/cstring.h"
25
26#include "backends/p4tools/modules/testgen/lib/test_backend_configuration.h"
27#include "backends/p4tools/modules/testgen/lib/test_object.h"
28#include "backends/p4tools/modules/testgen/lib/test_spec.h"
29
30namespace P4::P4Tools::P4Testgen {
31
32using namespace P4::literals;
33
38using AbstractTestReference = const AbstractTest *;
39using AbstractTestReferenceOrError = std::optional<AbstractTestReference>;
40using AbstractTestList = std::vector<AbstractTestReference>;
41
44template <class ConcreteTest,
45 typename = std::enable_if_t<std::is_base_of_v<AbstractTest, ConcreteTest>>>
46std::vector<const ConcreteTest *> convertAbstractTestsToConcreteTests(
47 const P4Tools::P4Testgen::AbstractTestList &testList) {
48 std::vector<const ConcreteTest *> result;
49 std::transform(testList.begin(), testList.end(), std::back_inserter(result),
50 [](AbstractTestReference test) { return test->checkedTo<ConcreteTest>(); });
51 return result;
52}
53
56using OptionalFilePath = std::optional<std::filesystem::path>;
57
61 private:
63 std::reference_wrapper<const TestBackendConfiguration> testBackendConfiguration;
64
65 protected:
67 explicit TestFramework(const TestBackendConfiguration &testBackendConfiguration);
68
72 static inja::json getTrace(const TestSpec *testSpec, bool stripNewline = true) {
73 inja::json traceList = inja::json::array();
74 const auto *traces = testSpec->getTraces();
75 if (traces != nullptr) {
76 for (const auto &trace : *traces) {
77 std::stringstream ss;
78 ss << trace;
79 std::string traceStr = ss.str();
80 if (stripNewline) {
81 traceStr.erase(std::remove(traceStr.begin(), traceStr.end(), '\n'),
82 traceStr.cend());
83 }
84 traceList.push_back(traceStr);
85 }
86 }
87 return traceList;
88 }
89
92 template <class ProfileType, class SelectorType>
93 static void checkForTableActionProfile(inja::json &tblJson, std::map<cstring, cstring> &apAsMap,
94 const TableConfig *tblConfig) {
95 const auto *apObject = tblConfig->getProperty("action_profile"_cs, false);
96 if (apObject != nullptr) {
97 const auto *actionProfile = apObject->checkedTo<ProfileType>();
98 tblJson["has_ap"] = true;
99 tblJson["action_profile"] = actionProfile->getProfileDecl()->controlPlaneName();
100 // Check if we have an Action Selector too.
101 // TODO: Change this to check in ActionSelector with table
102 // property "action_selectors".
103 const auto *asObject = tblConfig->getProperty("action_selector"_cs, false);
104 if (asObject != nullptr) {
105 const auto *actionSelector = asObject->checkedTo<SelectorType>();
106 apAsMap[actionProfile->getProfileDecl()->controlPlaneName()] =
107 actionSelector->getSelectorDecl()->controlPlaneName();
108 tblJson["has_as"] = true;
109 tblJson["action_selector"] = actionSelector->getSelectorDecl()->controlPlaneName();
110 }
111 }
112 }
113
116 static void checkForDefaultActionOverride(inja::json &tblJson, const TableConfig *tblConfig) {
117 const auto *defaultOverrideObj =
118 tblConfig->getProperty("overriden_default_action"_cs, false);
119 if (defaultOverrideObj != nullptr) {
120 const auto *defaultAction = defaultOverrideObj->checkedTo<ActionCall>();
121 inja::json a;
122 a["action_name"] = defaultAction->getActionName();
123 auto const *actionArgs = defaultAction->getArgs();
124 inja::json b = inja::json::array();
125 for (const auto &actArg : *actionArgs) {
126 inja::json j;
127 j["param"] = actArg.getActionParamName().c_str();
128 j["value"] = formatHexExpr(actArg.getEvaluatedValue());
129 b.push_back(j);
130 }
131 a["act_args"] = b;
132 tblJson["default_override"] = a;
133 }
134 }
135
137 template <class ProfileType>
138 static void collectActionProfileDeclarations(const TestSpec *testSpec,
139 inja::json &controlPlaneJson,
140 const std::map<cstring, cstring> &apAsMap) {
141 auto actionProfiles = testSpec->getTestObjectCategory("action_profiles"_cs);
142 if (!actionProfiles.empty()) {
143 controlPlaneJson["action_profiles"] = inja::json::array();
144 }
145 for (auto const &testObject : actionProfiles) {
146 const auto *const actionProfile = testObject.second->checkedTo<ProfileType>();
147 const auto *actions = actionProfile->getActions();
148 inja::json j;
149 j["profile"] = actionProfile->getProfileDecl()->controlPlaneName();
150 j["actions"] = inja::json::array();
151 for (size_t idx = 0; idx < actions->size(); ++idx) {
152 const auto &action = actions->at(idx);
153 auto actionName = action.first;
154 auto actionArgs = action.second;
155 inja::json a;
156 a["action_name"] = actionName;
157 a["action_idx"] = std::to_string(idx);
158 inja::json b = inja::json::array();
159 for (const auto &actArg : actionArgs) {
160 inja::json c;
161 c["param"] = actArg.getActionParamName().c_str();
162 c["value"] = formatHexExpr(actArg.getEvaluatedValue()).c_str();
163 b.push_back(c);
164 }
165 a["act_args"] = b;
166 j["actions"].push_back(a);
167 }
168 // Look up the selectors associated with the profile.
169 if (apAsMap.find(actionProfile->getProfileDecl()->controlPlaneName()) !=
170 apAsMap.end()) {
171 j["selector"] = apAsMap.at(actionProfile->getProfileDecl()->controlPlaneName());
172 }
173 controlPlaneJson["action_profiles"].push_back(j);
174 }
175 }
176
178 [[nodiscard]] const TestBackendConfiguration &getTestBackendConfiguration() const;
179
180 public:
181 virtual ~TestFramework() = default;
182
191 virtual void writeTestToFile(const TestSpec *spec, cstring selectedBranches, size_t testIdx,
192 float currentCoverage) = 0;
193
199 virtual AbstractTestReferenceOrError produceTest(const TestSpec *spec, cstring selectedBranches,
200 size_t testIdx, float currentCoverage);
201
203 [[nodiscard]] bool isInFileMode() const;
204};
205
206} // namespace P4::P4Tools::P4Testgen
207
208#endif /* BACKENDS_P4TOOLS_MODULES_TESTGEN_LIB_TEST_FRAMEWORK_H_ */
Definition castable.h:27
Definition lib/test_spec.h:100
cstring getActionName() const
Definition lib/test_spec.cpp:96
Definition lib/test_spec.h:260
const TestObject * getProperty(cstring propertyName, bool checked) const
Definition lib/test_spec.cpp:234
Definition test_framework.h:60
static void checkForTableActionProfile(inja::json &tblJson, std::map< cstring, cstring > &apAsMap, const TableConfig *tblConfig)
Definition test_framework.h:93
virtual AbstractTestReferenceOrError produceTest(const TestSpec *spec, cstring selectedBranches, size_t testIdx, float currentCoverage)
Definition test_framework.cpp:22
static void collectActionProfileDeclarations(const TestSpec *testSpec, inja::json &controlPlaneJson, const std::map< cstring, cstring > &apAsMap)
Collect all the action profile objects. These will have to be declared in the test.
Definition test_framework.h:138
virtual void writeTestToFile(const TestSpec *spec, cstring selectedBranches, size_t testIdx, float currentCoverage)=0
static void checkForDefaultActionOverride(inja::json &tblJson, const TableConfig *tblConfig)
Definition test_framework.h:116
TestFramework(const TestBackendConfiguration &testBackendConfiguration)
Creates a generic test framework.
Definition test_framework.cpp:11
bool isInFileMode() const
@Returns true if the test framework is configured to write to a file.
Definition test_framework.cpp:18
const TestBackendConfiguration & getTestBackendConfiguration() const
Returns the configuration options for the test back end.
Definition test_framework.cpp:14
static inja::json getTrace(const TestSpec *testSpec, bool stripNewline=true)
Definition test_framework.h:72
Definition lib/test_spec.h:303
const std::vector< std::reference_wrapper< const TraceEvent > > * getTraces() const
Definition lib/test_spec.cpp:285
TestObjectMap getTestObjectCategory(cstring category) const
Definition lib/test_spec.cpp:307
Definition cstring.h:85
std::string formatHexExpr(const IR::Expression *expr, const FormatOptions &formatOptions)
Definition common/lib/format_int.cpp:189
Type definitions for abstract tests.
Definition test_framework.h:35
Definition test_backend_configuration.h:22