mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-07-02 05:35:11 +00:00
555
tests/unit_tests/idl_compiler/compiler_test.cpp
Normal file
555
tests/unit_tests/idl_compiler/compiler_test.cpp
Normal file
@@ -0,0 +1,555 @@
|
||||
#include "includes.h"
|
||||
#include "parser_test.h"
|
||||
#include "../../../sdv_executables/sdv_idl_compiler/parser.h"
|
||||
#include "../../../sdv_executables/sdv_idl_compiler/generator/context.cpp"
|
||||
#include "../../../sdv_executables/sdv_idl_compiler/generator/ps_class_generator_base.cpp"
|
||||
#include "../../../sdv_executables/sdv_idl_compiler/generator/definition_generator.cpp"
|
||||
#include "../../../sdv_executables/sdv_idl_compiler/generator/proxy_generator.cpp"
|
||||
#include "../../../sdv_executables/sdv_idl_compiler/generator/stub_generator.cpp"
|
||||
#include "../../../sdv_executables/sdv_idl_compiler/generator/serdes_generator.cpp"
|
||||
#include "../../../sdv_executables/sdv_idl_compiler/generator/cmake_generator.cpp"
|
||||
|
||||
/**
|
||||
* @brief IDL file management class.
|
||||
*/
|
||||
class CIdlFile
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rssIdlCode Reference to the string containing the code to store in the IDL file.
|
||||
*/
|
||||
CIdlFile(const std::string& rssIdlCode) : m_pathIdl(std::filesystem::current_path() / "test.idl")
|
||||
{
|
||||
// Start clean
|
||||
CleanUp();
|
||||
|
||||
// Create a stream and write the code.
|
||||
std::ofstream fstreamIdlFile(m_pathIdl.c_str());
|
||||
fstreamIdlFile << rssIdlCode;
|
||||
fstreamIdlFile.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~CIdlFile()
|
||||
{
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the full path to the IDL file.
|
||||
* @return The path.
|
||||
*/
|
||||
std::filesystem::path PathIdl() const { return m_pathIdl; }
|
||||
|
||||
/**
|
||||
* @brief Get the header file content (if one was created).
|
||||
* @return The string containing the header file content.
|
||||
*/
|
||||
std::string Header() const
|
||||
{
|
||||
std::filesystem::path pathHdr = m_pathIdl;
|
||||
pathHdr.replace_extension(".h");
|
||||
std::ifstream fstream(pathHdr.c_str());
|
||||
std::stringstream sstreamContent;
|
||||
sstreamContent << fstream.rdbuf();
|
||||
return sstreamContent.str();
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Clean up before and after the compilation.
|
||||
*/
|
||||
void CleanUp()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (std::filesystem::exists(m_pathIdl))
|
||||
std::filesystem::remove(m_pathIdl);
|
||||
} catch (const std::filesystem::filesystem_error&)
|
||||
{}
|
||||
std::filesystem::path pathHdr = m_pathIdl;
|
||||
pathHdr.replace_extension(".h");
|
||||
try
|
||||
{
|
||||
if (std::filesystem::exists(pathHdr))
|
||||
std::filesystem::remove(pathHdr);
|
||||
} catch (const std::filesystem::filesystem_error&)
|
||||
{}
|
||||
std::filesystem::path pathPSDir = m_pathIdl;
|
||||
pathPSDir.remove_filename();
|
||||
pathPSDir /= "ps";
|
||||
if (std::filesystem::exists(pathPSDir))
|
||||
{
|
||||
try
|
||||
{
|
||||
std::filesystem::remove_all(pathPSDir);
|
||||
} catch (const std::filesystem::filesystem_error&)
|
||||
{}
|
||||
}
|
||||
std::filesystem::path pathSerDesDir = m_pathIdl;
|
||||
pathSerDesDir.remove_filename();
|
||||
pathSerDesDir /= "serdes";
|
||||
if (std::filesystem::exists(pathSerDesDir))
|
||||
{
|
||||
try
|
||||
{
|
||||
std::filesystem::remove_all(pathSerDesDir);
|
||||
} catch (const std::filesystem::filesystem_error&)
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path m_pathIdl; ///< Path to the IDL file
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Class managing a test compilation.
|
||||
*/
|
||||
class CTestCompile : public CIdlFile
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor triggering a test compilation using the provided code.
|
||||
* @param[in] rssIdlCode Reference to the IDL code to compile.
|
||||
*/
|
||||
CTestCompile(const std::string& rssIdlCode) : CIdlFile(rssIdlCode)
|
||||
{
|
||||
CIdlCompilerEnvironment environment;
|
||||
try
|
||||
{
|
||||
// Parse file
|
||||
CParser parser(PathIdl(), environment);
|
||||
parser.Parse();
|
||||
|
||||
// Generate definition
|
||||
CDefinitionGenerator defgen(&parser);
|
||||
defgen.Generate();
|
||||
|
||||
// Proxy code
|
||||
CProxyGenerator proxygen(&parser);
|
||||
proxygen.Generate();
|
||||
|
||||
// Stub code
|
||||
CStubGenerator stubgen(&parser);
|
||||
stubgen.Generate();
|
||||
|
||||
// Serdes code
|
||||
CSerdesGenerator serdesgen(&parser);
|
||||
serdesgen.Generate();
|
||||
|
||||
// CMake code generation
|
||||
CIdlCompilerCMakeGenerator cmakegen(&parser);
|
||||
cmakegen.Generate("proxystub");
|
||||
}
|
||||
catch (const CCompileException& rexcept)
|
||||
{
|
||||
std::stringstream sstreamError;
|
||||
if (!rexcept.GetPath().empty())
|
||||
std::cout << rexcept.GetPath() << "(line=" << rexcept.GetLineNo() << ", col=" << rexcept.GetColNo() <<
|
||||
") error: " << rexcept.GetReason() << std::endl;
|
||||
else
|
||||
std::cout << "error: " << rexcept.GetReason() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Compilation was successful
|
||||
m_bResult = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the result.
|
||||
*/
|
||||
operator bool() const
|
||||
{
|
||||
return m_bResult;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_bResult = false; ///< The result value of the test.
|
||||
};
|
||||
|
||||
using CCompilerTest = CParserTest;
|
||||
|
||||
TEST_F(CCompilerTest, EmptyFile)
|
||||
{
|
||||
// Tests bug fix: #380794
|
||||
EXPECT_TRUE(CTestCompile(""));
|
||||
EXPECT_TRUE(CTestCompile("/// @file Empty file without any definitions"));
|
||||
}
|
||||
|
||||
TEST_F(CCompilerTest, SkipCodePreCompiled)
|
||||
{
|
||||
// Partially skip code
|
||||
EXPECT_TRUE(CTestCompile(R"code(/// @file Skip code by using a conditional pre-compile statement
|
||||
|
||||
struct S1
|
||||
{};
|
||||
|
||||
#if 0
|
||||
|
||||
module mod
|
||||
{};
|
||||
|
||||
#endif
|
||||
|
||||
struct S2
|
||||
{};)code"));
|
||||
|
||||
// Tests bug fix: #380794
|
||||
// Completely skip code
|
||||
EXPECT_TRUE(CTestCompile(R"code(/// @file Skip complete file by using a conditional pre-compile statement
|
||||
|
||||
#if 0
|
||||
|
||||
module mod
|
||||
{};
|
||||
|
||||
#endif)code"));
|
||||
}
|
||||
|
||||
TEST_F(CCompilerTest, SkipCodeCommenting)
|
||||
{
|
||||
// Partially skip code
|
||||
EXPECT_TRUE(CTestCompile(R"code(/// @file Skip code by using a commented out code
|
||||
|
||||
struct S1
|
||||
{};
|
||||
|
||||
//module mod
|
||||
//{};
|
||||
|
||||
struct S2
|
||||
{};)code"));
|
||||
|
||||
// Tests bug fix: #380794
|
||||
// Completely skip code
|
||||
EXPECT_TRUE(CTestCompile(R"code(/// @file Skip code by using a commented out code
|
||||
|
||||
//struct S1
|
||||
//{};
|
||||
|
||||
//module mod
|
||||
//{};
|
||||
|
||||
//struct S2
|
||||
//{};)code"));
|
||||
|
||||
// Tests bug fix: #380790
|
||||
// Skip large chunk
|
||||
std::stringstream sstream;
|
||||
sstream << R"code(/// @file Skip code by using a commented out code
|
||||
|
||||
struct S1
|
||||
{};
|
||||
)code";
|
||||
for (size_t n = 0; n < 20000; n++)
|
||||
{
|
||||
sstream << R"code(// struct STest {
|
||||
// this is a test with lots of comments
|
||||
// which should be skipped and not be processed
|
||||
// and should not lead to any unexpected behaviour
|
||||
// like crashes or giant comment blocks for the definition
|
||||
// following...
|
||||
// };
|
||||
)code";
|
||||
}
|
||||
|
||||
sstream << R"code(
|
||||
struct S2
|
||||
{};)code";
|
||||
EXPECT_TRUE(CTestCompile(sstream.str()));
|
||||
}
|
||||
|
||||
TEST_F(CCompilerTest, GeneratedCodeWithTypedefOfArray)
|
||||
{
|
||||
const char szIdl[] = R"code(struct LidarPointField {};
|
||||
const int32 maxLidarPoints = 32;
|
||||
typedef LidarPointField LidarPointsField_t;
|
||||
typedef LidarPointField LidarPointsAry[maxLidarPoints];
|
||||
|
||||
struct LidarPoints
|
||||
{
|
||||
uint32 pointNumber;
|
||||
LidarPointsField_t point;
|
||||
LidarPointsAry lidarPointsList;
|
||||
};)code";
|
||||
|
||||
const char szHdr[] = R"code(struct LidarPointField{};
|
||||
static const int32_t maxLidarPoints = 32;
|
||||
typedef LidarPointField LidarPointsField_t;
|
||||
typedef LidarPointField LidarPointsAry[maxLidarPoints];
|
||||
struct LidarPoints
|
||||
{
|
||||
uint32_t pointNumber;
|
||||
LidarPointsField_t point;
|
||||
LidarPointsAry lidarPointsList;
|
||||
};)code";
|
||||
|
||||
// Tests bug fix: #385982
|
||||
CTestCompile test(szIdl);
|
||||
EXPECT_TRUE(test);
|
||||
EXPECT_CPPEQ(test.Header(), szHdr);
|
||||
}
|
||||
|
||||
TEST_F(CCompilerTest, ExplicitSpecifyModule)
|
||||
{
|
||||
const char szIdl[] = R"code(module MyAPI
|
||||
{
|
||||
struct VehSpd {};
|
||||
module interfaces
|
||||
{
|
||||
struct VehSpd
|
||||
{
|
||||
MyAPI::VehSpd notifyStatus;
|
||||
};
|
||||
};
|
||||
};)code";
|
||||
|
||||
const char szHdr[] = R"code(namespace MyAPI
|
||||
{
|
||||
struct VehSpd
|
||||
{};
|
||||
namespace interfaces
|
||||
{
|
||||
struct VehSpd
|
||||
{
|
||||
MyAPI::VehSpd notifyStatus;
|
||||
};
|
||||
}
|
||||
}
|
||||
)code";
|
||||
|
||||
// Tests bug fix: #384857
|
||||
CTestCompile test(szIdl);
|
||||
EXPECT_TRUE(test);
|
||||
EXPECT_CPPEQ(test.Header(), szHdr);
|
||||
}
|
||||
|
||||
// NOTE 11.04.2025: The C++ comparison function is not working correctly.
|
||||
TEST_F(CCompilerTest, DISABLED_ForwardDeclUnion)
|
||||
{
|
||||
const char szIdlTypeBased[] = R"code(union UTest;
|
||||
/**
|
||||
* @brief Standard union based on a integer.
|
||||
*/
|
||||
union UTest switch (uint32)
|
||||
{
|
||||
case 10: boolean bVal; ///< Bool value
|
||||
case 20: uint64 uiVal; ///< 64-bit int value
|
||||
case 30: float fVal; ///< Float value
|
||||
default: string ssVal; ///< String value
|
||||
};)code";
|
||||
|
||||
const char szHdrTypeBased[] = R"code(struct UTest;
|
||||
struct UTest;
|
||||
|
||||
/**
|
||||
* @brief Standard union based on a integer.
|
||||
*/
|
||||
struct UTest
|
||||
{
|
||||
/** Constructor */
|
||||
UTest()
|
||||
{
|
||||
construct_switch_value();
|
||||
}
|
||||
|
||||
/** Destructor */
|
||||
~UTest()
|
||||
{
|
||||
destruct_switch_value();
|
||||
}
|
||||
|
||||
private:
|
||||
/** Constructor helper function for switch_value */
|
||||
void construct_switch_value(uint32_t val = uint32_t{})
|
||||
{
|
||||
switch_value = val;
|
||||
switch (val)
|
||||
{
|
||||
case 10:
|
||||
new (&bVal) bool;
|
||||
break;
|
||||
case 20:
|
||||
new (&uiVal) uint64_t;
|
||||
break;
|
||||
case 30:
|
||||
new (&fVal) float;
|
||||
break;
|
||||
default:
|
||||
new (&ssVal) sdv::string;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Destructor helper function for switch_value */
|
||||
void destruct_switch_value()
|
||||
{
|
||||
switch (switch_value)
|
||||
{
|
||||
case 10:
|
||||
break;
|
||||
case 20:
|
||||
break;
|
||||
case 30:
|
||||
break;
|
||||
default:
|
||||
ssVal.~string_base();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/** Set the switch type for the union UTest */
|
||||
void switch_to(uint32_t val)
|
||||
{
|
||||
// Anything to do?
|
||||
if (switch_value == val) return;
|
||||
|
||||
// Assign the new value...
|
||||
switch_value = val;
|
||||
|
||||
// Destruct and construct switch_value...
|
||||
destruct_switch_value();
|
||||
construct_switch_value(val);
|
||||
}
|
||||
|
||||
/** Get the switch value */
|
||||
uint32_t get_switch() const
|
||||
{
|
||||
return switch_value;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t switch_value; ///< Union switch variable.
|
||||
|
||||
public:
|
||||
union /*switch(switch_value)*/
|
||||
{
|
||||
// case 10:
|
||||
/// Bool value
|
||||
bool bVal;
|
||||
|
||||
// case 20:
|
||||
/// 64-bit int value
|
||||
uint64_t uiVal;
|
||||
|
||||
// case 30:
|
||||
/// Float value
|
||||
float fVal;
|
||||
|
||||
// default
|
||||
/// String value
|
||||
sdv::string ssVal;
|
||||
};
|
||||
};
|
||||
)code";
|
||||
|
||||
// Tests bug fix: #380792
|
||||
CTestCompile testTypeBased(szIdlTypeBased);
|
||||
EXPECT_TRUE(testTypeBased);
|
||||
EXPECT_CPPEQ(testTypeBased.Header(), szHdrTypeBased);
|
||||
|
||||
const char szIdlVarBased[] = R"code(struct S {
|
||||
// Forward declaration
|
||||
union UTest;
|
||||
|
||||
int32 iVal;
|
||||
|
||||
/**
|
||||
* @brief Standard union based on a integer value.
|
||||
*/
|
||||
union UTest switch (iVal)
|
||||
{
|
||||
case 10: boolean bVal; ///< Bool value
|
||||
case 20: uint64 uiVal; ///< 64-bit int value
|
||||
case 30: float fVal; ///< Float value
|
||||
default: char cVal; ///< Character value
|
||||
};
|
||||
};)code";
|
||||
|
||||
const char szHdrVarBased[] = R"code(struct S {
|
||||
union UTest;
|
||||
int32_t iVal;
|
||||
union UTest
|
||||
{
|
||||
UTest() {}
|
||||
~UTest() {}
|
||||
bool bVal;
|
||||
uint64_t uiVal;
|
||||
float fVal;
|
||||
char cVal;
|
||||
};
|
||||
};
|
||||
)code";
|
||||
|
||||
// Tests bug fix: #380792
|
||||
CTestCompile testVarBased(szIdlVarBased);
|
||||
EXPECT_TRUE(testVarBased);
|
||||
EXPECT_CPPEQ(testVarBased.Header(), szHdrVarBased);
|
||||
}
|
||||
|
||||
// NOTE 11.04.2025: The C++ comparison function is not working correctly.
|
||||
TEST_F(CCompilerTest, DISABLED_UnionWithComplexMembers)
|
||||
{
|
||||
const char szIdlTypeBased[] = R"code(/**
|
||||
* @brief Standard union based on a integer.
|
||||
*/
|
||||
union UTest switch (uint32)
|
||||
{
|
||||
case 10: boolean bVal; ///< Bool value
|
||||
case 20: uint64 uiVal; ///< 64-bit int value
|
||||
case 30: float fVal; ///< Float value
|
||||
default: string ssVal; ///< String value
|
||||
};)code";
|
||||
|
||||
const char szHdrTypeBased[] = R"code(struct UTest
|
||||
{
|
||||
UTest(uint32_t val = 10)
|
||||
{
|
||||
switch_value = val;
|
||||
switch (val)
|
||||
{
|
||||
case 10: new (&bVal) bool; break;
|
||||
case 20: new (&uiVal) uint64_t; break;
|
||||
case 30: new (&fVal) float; break;
|
||||
default: new (&ssVal) sdv::string; break;
|
||||
}
|
||||
}
|
||||
~UTest()
|
||||
{
|
||||
switch (switch_value)
|
||||
{
|
||||
case 10: break;
|
||||
case 20: break;
|
||||
case 30: break;
|
||||
default: ssVal.~string_base(); break;
|
||||
}
|
||||
}
|
||||
void switch_to(uint32_t val)
|
||||
{
|
||||
if (val == switch_value) return;
|
||||
this->~UTest();
|
||||
new (this) UTest(val);
|
||||
}
|
||||
|
||||
uint32_t switch_value;
|
||||
union
|
||||
{
|
||||
bool bVal;
|
||||
uint64_t uiVal;
|
||||
float fVal;
|
||||
sdv::string ssVal;
|
||||
};
|
||||
};
|
||||
)code";
|
||||
|
||||
// Tests bug fix: #380792
|
||||
CTestCompile testTypeBased(szIdlTypeBased);
|
||||
EXPECT_TRUE(testTypeBased);
|
||||
EXPECT_CPPEQ(testTypeBased.Header(), szHdrTypeBased);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user