mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-02-05 15:18:45 +00:00
556 lines
13 KiB
C++
556 lines
13 KiB
C++
#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);
|
|
|
|
}
|