LLZK 0.1.0
Veridise's ZK Language IR
Loading...
Searching...
No Matches
EnumCAPITestGen.cpp
Go to the documentation of this file.
1//===- EnumCAPITestGen.cpp - C API test generator for enums ---------------===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2025 Veridise Inc.
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
9//
10// EnumCAPITestGen generates unit tests for the C API enums generated by
11// EnumCAPIGen. These are link-time tests that ensure all generated enum
12// declarations and wrap/unwrap functions compile and link properly.
13//
14// Test Strategy:
15// - Tests verify enum values can be assigned and compared
16// - Tests verify wrap/unwrap functions compile and link (though the C++ type
17// doesn't exist in test context, the functions still need to link)
18// - This ensures all enum cases are properly declared and wrap/unwrap functions
19// have correct signatures
20//
21//===----------------------------------------------------------------------===//
22
23#include <mlir/TableGen/Attribute.h>
24#include <mlir/TableGen/GenInfo.h>
25
26#include <llvm/ADT/StringExtras.h>
27#include <llvm/Support/CommandLine.h>
28#include <llvm/Support/FormatVariadic.h>
29#include <llvm/TableGen/Record.h>
30#include <llvm/TableGen/TableGenBackend.h>
31
32#include "CommonCAPIGen.h"
33
34using namespace mlir;
35using namespace mlir::tblgen;
36
37namespace {
38
43struct EnumTestGenerator : public TestGenerator {
46 EnumTestGenerator(llvm::raw_ostream &outputStream) : TestGenerator("Enum", outputStream) {}
47
48 virtual void genExtraMethod(const ExtraMethod &method) const override {
49 llvm_unreachable("Enums cannot have extra methods");
50 }
51
55 void genEnumUsageTest(StringRef cEnumName, StringRef firstCaseValue) const {
56 static constexpr char fmt[] = R"(
57// This test ensures the {1} enum compiles and links properly.
58TEST_F({0}EnumLinkTests, Enum_{1}_Usage) {{
59 // We create a variable and check that enum values can be assigned.
60 {1} enumValue = {2};
61 (void)enumValue;
62
63 // Verify we can compare enum values
64 EXPECT_EQ(enumValue, {2});
65}
66)";
67 os << llvm::formatv(fmt, dialectNameCapitalized, cEnumName, firstCaseValue);
68 }
69
73 void genWrapUnwrapTest(StringRef cEnumName, StringRef firstCaseValue) const {
74 static constexpr char fmt[] = R"(
75// This test ensures wrap/unwrap functions for {1} compile and link.
76TEST_F({0}EnumLinkTests, Enum_{1}_WrapUnwrap) {{
77 // We use the first enum case value for testing.
78 {1} cValue = {2};
79
80 // Test that wrap and unwrap are inverses (at compile/link time)
81 // The actual C++ type doesn't exist in test context, so we just
82 // verify the functions exist and link.
83 {1} roundTrip = wrap(unwrap(cValue));
84 EXPECT_EQ(cValue, roundTrip);
85}
86)";
87 os << llvm::formatv(fmt, dialectNameCapitalized, cEnumName, firstCaseValue);
88 }
89
92 void genCompleteRecord(const EnumAttr &enumInfo) {
93 // EnumAttr does not contain a Dialect reference, so filter by C++ namespace instead.
94 if (!DialectName.empty() && !enumInfo.getCppNamespace().contains_insensitive(DialectName)) {
95 return;
96 }
97
98 std::vector<EnumAttrCase> enumCases = enumInfo.getAllCases();
99 if (enumCases.empty()) {
100 return;
101 }
102
103 // Get enum name
104 std::string cEnumName = toPascalCase(FunctionPrefix) + toPascalCase(DialectName) +
105 toPascalCase(enumInfo.getEnumClassName());
106
107 // Get first enum case for testing
108 std::string firstCase = enumCases[0].getSymbol().upper();
109 std::string firstCaseValue = llvm::formatv("{0}_{1}", cEnumName, firstCase).str();
110
111 // Generate enum usage test
112 this->genEnumUsageTest(cEnumName, firstCaseValue);
113
114 // Generate wrap/unwrap test
115 this->genWrapUnwrapTest(cEnumName, firstCaseValue);
116 }
117};
118
119} // namespace
120
122static bool emitEnumCAPITests(const llvm::RecordKeeper &records, raw_ostream &os) {
123 // Generate file header
124 emitSourceFileHeader("Enum C API Tests", os, records);
125
126 // Create generator
127 EnumTestGenerator generator(os);
128
129 // Generate test class prologue
130 generator.genTestClassPrologue();
131
132 // Generate tests for each enum
133 for (const auto *def : records.getAllDerivedDefinitionsIfDefined("EnumAttrInfo")) {
134 EnumAttr enumInfo(def);
135 generator.genCompleteRecord(enumInfo);
136 }
137
138 return false;
139}
140
141static mlir::GenRegistration
142 genEnumCAPITests("gen-enum-capi-tests", "Generate enum C API unit tests", &emitEnumCAPITests);
llvm::cl::opt< std::string > DialectName
llvm::cl::opt< std::string > FunctionPrefix
std::string toPascalCase(mlir::StringRef str)
Convert names separated by underscore or colon to PascalCase.
Generator for common test implementation file elements.