P4C
The P4 Compiler
Loading...
Searching...
No Matches
test_framework.h
1#ifndef BACKENDS_P4TOOLS_MODULES_TESTGEN_LIB_TEST_FRAMEWORK_H_
2#define BACKENDS_P4TOOLS_MODULES_TESTGEN_LIB_TEST_FRAMEWORK_H_
3
4#include <cstddef>
5#include <filesystem>
6#include <functional>
7#include <iosfwd>
8#include <map>
9#include <optional>
10#include <string>
11#include <utility>
12
13#include <inja/inja.hpp>
14
15#include "backends/p4tools/common/lib/format_int.h"
16#include "backends/p4tools/common/lib/trace_event.h"
17#include "lib/castable.h"
18#include "lib/cstring.h"
19
20#include "backends/p4tools/modules/testgen/lib/test_backend_configuration.h"
21#include "backends/p4tools/modules/testgen/lib/test_object.h"
22#include "backends/p4tools/modules/testgen/lib/test_spec.h"
23
24namespace P4::P4Tools::P4Testgen {
25
26using namespace P4::literals;
27
33using AbstractTestReferenceOrError = std::optional<AbstractTestReference>;
34using AbstractTestList = std::vector<AbstractTestReference>;
35
38template <class ConcreteTest,
39 typename = std::enable_if_t<std::is_base_of_v<AbstractTest, ConcreteTest>>>
40std::vector<const ConcreteTest *> convertAbstractTestsToConcreteTests(
41 const P4Tools::P4Testgen::AbstractTestList &testList) {
42 std::vector<const ConcreteTest *> result;
43 std::transform(testList.begin(), testList.end(), std::back_inserter(result),
44 [](AbstractTestReference test) { return test->checkedTo<ConcreteTest>(); });
45 return result;
46}
47
50using OptionalFilePath = std::optional<std::filesystem::path>;
51
55 private:
57 std::reference_wrapper<const TestBackendConfiguration> testBackendConfiguration;
58
59 protected:
61 explicit TestFramework(const TestBackendConfiguration &testBackendConfiguration);
62
64 static inja::json getTrace(const TestSpec *testSpec) {
65 inja::json traceList = inja::json::array();
66 const auto *traces = testSpec->getTraces();
67 if (traces != nullptr) {
68 for (const auto &trace : *traces) {
69 std::stringstream ss;
70 ss << trace;
71 traceList.push_back(ss.str());
72 }
73 }
74 return traceList;
75 }
76
79 template <class ProfileType, class SelectorType>
80 static void checkForTableActionProfile(inja::json &tblJson, std::map<cstring, cstring> &apAsMap,
81 const TableConfig *tblConfig) {
82 const auto *apObject = tblConfig->getProperty("action_profile"_cs, false);
83 if (apObject != nullptr) {
84 const auto *actionProfile = apObject->checkedTo<ProfileType>();
85 tblJson["has_ap"] = true;
86 // Check if we have an Action Selector too.
87 // TODO: Change this to check in ActionSelector with table
88 // property "action_selectors".
89 const auto *asObject = tblConfig->getProperty("action_selector"_cs, false);
90 if (asObject != nullptr) {
91 const auto *actionSelector = asObject->checkedTo<SelectorType>();
92 apAsMap[actionProfile->getProfileDecl()->controlPlaneName()] =
93 actionSelector->getSelectorDecl()->controlPlaneName();
94 tblJson["has_as"] = true;
95 }
96 }
97 }
98
101 static void checkForDefaultActionOverride(inja::json &tblJson, const TableConfig *tblConfig) {
102 const auto *defaultOverrideObj =
103 tblConfig->getProperty("overriden_default_action"_cs, false);
104 if (defaultOverrideObj != nullptr) {
105 const auto *defaultAction = defaultOverrideObj->checkedTo<ActionCall>();
106 inja::json a;
107 a["action_name"] = defaultAction->getActionName();
108 auto const *actionArgs = defaultAction->getArgs();
109 inja::json b = inja::json::array();
110 for (const auto &actArg : *actionArgs) {
111 inja::json j;
112 j["param"] = actArg.getActionParamName().c_str();
113 j["value"] = formatHexExpr(actArg.getEvaluatedValue());
114 b.push_back(j);
115 }
116 a["act_args"] = b;
117 tblJson["default_override"] = a;
118 }
119 }
120
122 template <class ProfileType>
123 static void collectActionProfileDeclarations(const TestSpec *testSpec,
124 inja::json &controlPlaneJson,
125 const std::map<cstring, cstring> &apAsMap) {
126 auto actionProfiles = testSpec->getTestObjectCategory("action_profiles"_cs);
127 if (!actionProfiles.empty()) {
128 controlPlaneJson["action_profiles"] = inja::json::array();
129 }
130 for (auto const &testObject : actionProfiles) {
131 const auto *const actionProfile = testObject.second->checkedTo<ProfileType>();
132 const auto *actions = actionProfile->getActions();
133 inja::json j;
134 j["profile"] = actionProfile->getProfileDecl()->controlPlaneName();
135 j["actions"] = inja::json::array();
136 for (size_t idx = 0; idx < actions->size(); ++idx) {
137 const auto &action = actions->at(idx);
138 auto actionName = action.first;
139 auto actionArgs = action.second;
140 inja::json a;
141 a["action_name"] = actionName;
142 a["action_idx"] = std::to_string(idx);
143 inja::json b = inja::json::array();
144 for (const auto &actArg : actionArgs) {
145 inja::json c;
146 c["param"] = actArg.getActionParamName().c_str();
147 c["value"] = formatHexExpr(actArg.getEvaluatedValue()).c_str();
148 b.push_back(c);
149 }
150 a["act_args"] = b;
151 j["actions"].push_back(a);
152 }
153 // Look up the selectors associated with the profile.
154 if (apAsMap.find(actionProfile->getProfileDecl()->controlPlaneName()) !=
155 apAsMap.end()) {
156 j["selector"] = apAsMap.at(actionProfile->getProfileDecl()->controlPlaneName());
157 }
158 controlPlaneJson["action_profiles"].push_back(j);
159 }
160 }
161
163 [[nodiscard]] const TestBackendConfiguration &getTestBackendConfiguration() const;
164
165 public:
166 virtual ~TestFramework() = default;
167
176 virtual void writeTestToFile(const TestSpec *spec, cstring selectedBranches, size_t testIdx,
177 float currentCoverage) = 0;
178
184 virtual AbstractTestReferenceOrError produceTest(const TestSpec *spec, cstring selectedBranches,
185 size_t testIdx, float currentCoverage);
186
188 [[nodiscard]] bool isInFileMode() const;
189};
190
191} // namespace P4::P4Tools::P4Testgen
192
193#endif /* BACKENDS_P4TOOLS_MODULES_TESTGEN_LIB_TEST_FRAMEWORK_H_ */
Definition castable.h:36
Definition lib/test_spec.h:93
cstring getActionName() const
Definition lib/test_spec.cpp:92
Definition lib/test_spec.h:253
const TestObject * getProperty(cstring propertyName, bool checked) const
Definition lib/test_spec.cpp:230
Definition test_framework.h:54
static void checkForTableActionProfile(inja::json &tblJson, std::map< cstring, cstring > &apAsMap, const TableConfig *tblConfig)
Definition test_framework.h:80
virtual AbstractTestReferenceOrError produceTest(const TestSpec *spec, cstring selectedBranches, size_t testIdx, float currentCoverage)
Definition test_framework.cpp:18
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:123
virtual void writeTestToFile(const TestSpec *spec, cstring selectedBranches, size_t testIdx, float currentCoverage)=0
static inja::json getTrace(const TestSpec *testSpec)
Converts the traces of this test into a string representation and Inja object.
Definition test_framework.h:64
static void checkForDefaultActionOverride(inja::json &tblJson, const TableConfig *tblConfig)
Definition test_framework.h:101
TestFramework(const TestBackendConfiguration &testBackendConfiguration)
Creates a generic test framework.
Definition test_framework.cpp:7
bool isInFileMode() const
@Returns true if the test framework is configured to write to a file.
Definition test_framework.cpp:14
const TestBackendConfiguration & getTestBackendConfiguration() const
Returns the configuration options for the test back end.
Definition test_framework.cpp:10
Definition lib/test_spec.h:296
const std::vector< std::reference_wrapper< const TraceEvent > > * getTraces() const
Definition lib/test_spec.cpp:281
TestObjectMap getTestObjectCategory(cstring category) const
Definition lib/test_spec.cpp:303
Definition cstring.h:85
std::string formatHexExpr(const IR::Expression *expr, const FormatOptions &formatOptions)
Definition common/lib/format_int.cpp:185
Definition cstring.h:80
Type definitions for abstract tests.
Definition test_framework.h:29
Definition test_backend_configuration.h:16