1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-09-18 14:27:39 +03:00

Compare commits

..

2 Commits

Author SHA1 Message Date
dkulikov
40c01dedcf Fixed remark 2025-08-29 17:28:59 +01:00
dkulikov
d644a7b47f Stack overflow when meshing(with tbb) shapes from attached step file #688
Fixed stack overflow by introducing StackOfFrames class that allows for iterative approach instead of recursive.
2025-08-29 17:23:16 +01:00
119 changed files with 6423 additions and 4213 deletions

View File

@@ -126,7 +126,7 @@ runs:
-D BUILD_GTEST=ON \
-D BUILD_CPP_STANDARD=C++17 \
-D INSTALL_GTEST=ON \
-D CMAKE_CXX_FLAGS="-Werror -Wall -Wextra -Wno-unknown-warning-option -Wno-error=cast-function-type-mismatch" \
-D CMAKE_CXX_FLAGS="-Werror -Wall -Wextra" \
${{ inputs.additional-cmake-flags }} ..
echo "Configuration completed successfully for macOS"
shell: bash

View File

@@ -56,14 +56,7 @@ runs:
if: runner.os == 'macOS'
run: |
brew update || true
# Install each package separately to continue even if some fail
brew install cmake || true
brew install ninja || true
brew install nasm || true
brew install autoconf || true
brew install automake || true
brew install mono || true
brew install openexr || true
brew install cmake ninja nasm autoconf automake mono openexr || true
brew install --cask xquartz || true
shell: bash

View File

@@ -125,7 +125,7 @@ jobs:
artifact-name: install-macos-clang-no-pch
build-use-pch: 'false'
build-opt-profile: 'Default'
additional-cmake-flags: '-D CMAKE_CXX_FLAGS="-Werror -Wall -Wextra -Wno-error=cast-function-type-mismatch" -D CMAKE_C_FLAGS="-Werror -Wall -Wextra -Wno-error=cast-function-type-mismatch"'
additional-cmake-flags: '-D CMAKE_CXX_FLAGS="-Werror -Wall -Wextra" -D CMAKE_C_FLAGS="-Werror -Wall -Wextra"'
cmake-build-type: 'Debug'
github-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -139,17 +139,3 @@ bool DE_ConfigurationNode::CheckContent(const Handle(NCollection_Buffer)& theBuf
(void)theBuffer;
return false;
}
//=================================================================================================
void DE_ConfigurationNode::Register(const Handle(DE_Wrapper)& theWrapper) const
{
theWrapper->Bind(this);
}
//=================================================================================================
void DE_ConfigurationNode::UnRegister(const Handle(DE_Wrapper)& theWrapper) const
{
theWrapper->UnBind(this);
}

View File

@@ -18,7 +18,6 @@
class DE_ConfigurationContext;
class DE_Provider;
class DE_Wrapper;
class NCollection_Buffer;
//! Base class to work with CAD transfer properties.
@@ -155,16 +154,6 @@ public:
//!< unit is unknown, default 1.0 (MM)
} GlobalParameters;
public:
//! Registers configuration node with the specified wrapper
//! @param[in] theWrapper wrapper to register with
Standard_EXPORT virtual void Register(const Handle(DE_Wrapper)& theWrapper) const;
//! Unregisters configuration node from the specified wrapper
//! @param[in] theWrapper wrapper to unregister from
Standard_EXPORT virtual void UnRegister(const Handle(DE_Wrapper)& theWrapper) const;
private:
Standard_Boolean myIsEnabled; //!< Flag to use a current provider for Read or Write process via DE_Wrapper
// clang-format on

View File

@@ -15,7 +15,6 @@
#define _DE_PluginHolder_HeaderFile
#include <DE_Wrapper.hxx>
#include <tuple>
//! Base class to work with DE_Wrapper global registration of components.
//! Control life-time of current configuration node.
@@ -30,80 +29,17 @@ public:
{
Standard_Mutex::Sentry aLock(DE_Wrapper::GlobalLoadMutex());
myInternalConfiguration = new TheConfType;
myInternalConfiguration->Register(DE_Wrapper::GlobalWrapper());
DE_Wrapper::GlobalWrapper()->Bind(myInternalConfiguration);
}
~DE_PluginHolder()
{
Standard_Mutex::Sentry aLock(DE_Wrapper::GlobalLoadMutex());
myInternalConfiguration->UnRegister(DE_Wrapper::GlobalWrapper());
DE_Wrapper::GlobalWrapper()->UnBind(myInternalConfiguration);
}
private:
Handle(TheConfType) myInternalConfiguration; //!< Wrapped object
};
//! Helper class for variadic plugin registration.
//! Allows registration of multiple configuration node types simultaneously.
template <typename... TheConfTypes>
class DE_MultiPluginHolder
{
public:
DE_MultiPluginHolder()
: myHolders{}
{
}
private:
std::tuple<DE_PluginHolder<TheConfTypes>...> myHolders; //!< Tuple of individual plugin holders
};
//! Macro to define plugin factory function for DE_Wrapper configuration nodes.
//! @param[in] theNodeType - first configuration node class to instantiate
//! @param[in] ... - additional configuration node classes to instantiate (optional)
//! Needs to be called after loading of the library to register configuration nodes.
//!
//! Example of usage:
//! @code
//! // Inside implementation of the configuration node source file:
//! DEPLUGIN(DESTEP_ConfigurationNode)
//!
//! // For multiple node types:
//! DEPLUGIN(DESTEP_ConfigurationNode, DEIGES_ConfigurationNode, DEVRML_ConfigurationNode)
//! @endcode
//!
//! After loading of the library TKDESTEP:
//! @code
//! OSD_SharedLibrary aSharedLibrary("libTKDESTEP.so");
//! if (!aSharedLibrary.DlOpen(OSD_RTLD_LAZY))
//! {
//! // Error handling
//! return;
//! }
//!
//! typedef void (*PluginFactoryFunc)();
//! PluginFactoryFunc aFunc = (PluginFactoryFunc)aSharedLibrary.DlSymb("PLUGINFACTORY");
//! if (aFunc == NULL)
//! {
//! // Error handling
//! return;
//! }
//!
//! aFunc(); // Call factory function to register configuration nodes
//! @endcode
//!
//! Will create instances of all specified configuration nodes and set them to DE_Wrapper global
//! configuration.
//!
//! Note: if OCCT_NO_PLUGINS is defined, macro does nothing.
#ifdef OCCT_NO_PLUGINS
#define DEPLUGIN(theNodeType, ...)
#else
#define DEPLUGIN(theNodeType, ...) \
extern "C" Standard_EXPORT void PLUGINFACTORY() \
{ \
static DE_MultiPluginHolder<theNodeType, ##__VA_ARGS__> aMultiHolder; \
}
#endif
#endif // _DE_PluginHolder_HeaderFile

View File

@@ -14,6 +14,7 @@
#include <DE_ShapeFixConfigurationNode.hxx>
#include <DE_ConfigurationContext.hxx>
#include <DE_PluginHolder.hxx>
#include <DE_Wrapper.hxx>
IMPLEMENT_STANDARD_RTTIEXT(DE_ShapeFixConfigurationNode, DE_ConfigurationNode)

View File

@@ -15,6 +15,7 @@
#include <DEBREP_Provider.hxx>
#include <DE_ConfigurationContext.hxx>
#include <DE_PluginHolder.hxx>
#include <NCollection_Buffer.hxx>
IMPLEMENT_STANDARD_RTTIEXT(DEBREP_ConfigurationNode, DE_ConfigurationNode)
@@ -27,6 +28,8 @@ static const TCollection_AsciiString& THE_CONFIGURATION_SCOPE()
return aScope;
}
// Wrapper to auto-load DE component
DE_PluginHolder<DEBREP_ConfigurationNode> THE_OCCT_BREP_COMPONENT_PLUGIN;
} // namespace
//=================================================================================================

View File

@@ -15,6 +15,7 @@
#include <DEXCAF_Provider.hxx>
#include <DE_ConfigurationContext.hxx>
#include <DE_PluginHolder.hxx>
#include <NCollection_Buffer.hxx>
IMPLEMENT_STANDARD_RTTIEXT(DEXCAF_ConfigurationNode, DE_ConfigurationNode)
@@ -27,6 +28,8 @@ static const TCollection_AsciiString& THE_CONFIGURATION_SCOPE()
return aScope;
}
// Wrapper to auto-load DE component
DE_PluginHolder<DEXCAF_ConfigurationNode> THE_OCCT_XCAF_COMPONENT_PLUGIN;
} // namespace
//=================================================================================================

View File

@@ -4,5 +4,4 @@ set(OCCT_TKDECascade_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKDECascade_FILES
EXTERNLIB
PACKAGES
TKDECascade.cxx
)

View File

@@ -15,6 +15,7 @@
#include <DEGLTF_Provider.hxx>
#include <DE_ConfigurationContext.hxx>
#include <DE_PluginHolder.hxx>
IMPLEMENT_STANDARD_RTTIEXT(DEGLTF_ConfigurationNode, DE_ConfigurationNode)
@@ -26,6 +27,8 @@ static const TCollection_AsciiString& THE_CONFIGURATION_SCOPE()
return aScope;
}
// Wrapper to auto-load DE component
DE_PluginHolder<DEGLTF_ConfigurationNode> THE_OCCT_GLTF_COMPONENT_PLUGIN;
} // namespace
//=================================================================================================

View File

@@ -4,5 +4,4 @@ set(OCCT_TKDEGLTF_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKDEGLTF_FILES
EXTERNLIB
PACKAGES
TKDEGLTF.cxx
)

View File

@@ -15,6 +15,7 @@
#include <DEIGES_Provider.hxx>
#include <DE_ConfigurationContext.hxx>
#include <DE_PluginHolder.hxx>
#include <NCollection_Buffer.hxx>
IMPLEMENT_STANDARD_RTTIEXT(DEIGES_ConfigurationNode, DE_ShapeFixConfigurationNode)
@@ -27,6 +28,8 @@ static const TCollection_AsciiString& THE_CONFIGURATION_SCOPE()
return aScope;
}
// Wrapper to auto-load DE component
DE_PluginHolder<DEIGES_ConfigurationNode> THE_OCCT_IGES_COMPONENT_PLUGIN;
} // namespace
//=================================================================================================

View File

@@ -5,5 +5,4 @@ set(OCCT_TKDEIGES_FILES
EXTERNLIB
PACKAGES
TKDEIGES_pch.hxx
TKDEIGES.cxx
)

View File

@@ -15,6 +15,7 @@
#include <DEOBJ_Provider.hxx>
#include <DE_ConfigurationContext.hxx>
#include <DE_PluginHolder.hxx>
IMPLEMENT_STANDARD_RTTIEXT(DEOBJ_ConfigurationNode, DE_ConfigurationNode)
@@ -26,6 +27,8 @@ static const TCollection_AsciiString& THE_CONFIGURATION_SCOPE()
return aScope;
}
// Wrapper to auto-load DE component
DE_PluginHolder<DEOBJ_ConfigurationNode> THE_OCCT_OBJ_COMPONENT_PLUGIN;
} // namespace
//=================================================================================================

View File

@@ -4,5 +4,4 @@ set(OCCT_TKDEOBJ_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKDEOBJ_FILES
EXTERNLIB
PACKAGES
TKDEOBJ.cxx
)

View File

@@ -15,6 +15,7 @@
#include <DEPLY_Provider.hxx>
#include <DE_ConfigurationContext.hxx>
#include <DE_PluginHolder.hxx>
#include <NCollection_Buffer.hxx>
IMPLEMENT_STANDARD_RTTIEXT(DEPLY_ConfigurationNode, DE_ConfigurationNode)
@@ -27,6 +28,8 @@ static const TCollection_AsciiString& THE_CONFIGURATION_SCOPE()
return aScope;
}
// Wrapper to auto-load DE component
DE_PluginHolder<DEPLY_ConfigurationNode> THE_OCCT_PLY_COMPONENT_PLUGIN;
} // namespace
//=================================================================================================

View File

@@ -4,5 +4,4 @@ set(OCCT_TKDEPLY_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKDEPLY_FILES
EXTERNLIB
PACKAGES
TKDEPLY.cxx
)

View File

@@ -15,6 +15,7 @@
#include <DESTEP_Provider.hxx>
#include <DE_ConfigurationContext.hxx>
#include <DE_PluginHolder.hxx>
#include <NCollection_Buffer.hxx>
IMPLEMENT_STANDARD_RTTIEXT(DESTEP_ConfigurationNode, DE_ShapeFixConfigurationNode)
@@ -27,6 +28,8 @@ static const TCollection_AsciiString& THE_CONFIGURATION_SCOPE()
return aScope;
}
// Wrapper to auto-load DE component
DE_PluginHolder<DESTEP_ConfigurationNode> THE_OCCT_STEP_COMPONENT_PLUGIN;
} // namespace
//=================================================================================================

View File

@@ -5,5 +5,4 @@ set(OCCT_TKDESTEP_FILES
EXTERNLIB
PACKAGES
TKDESTEP_pch.hxx
TKDESTEP.cxx
)

View File

@@ -1,19 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <DESTEP_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
//! Plugin factory function to register DESTEP configuration node.
//! Call PLUGINFACTORY() to register the DESTEP_ConfigurationNode with the global DE_Wrapper.
DEPLUGIN(DESTEP_ConfigurationNode)

View File

@@ -15,6 +15,7 @@
#include <DESTL_Provider.hxx>
#include <DE_ConfigurationContext.hxx>
#include <DE_PluginHolder.hxx>
#include <NCollection_Buffer.hxx>
IMPLEMENT_STANDARD_RTTIEXT(DESTL_ConfigurationNode, DE_ConfigurationNode)
@@ -27,6 +28,8 @@ static const TCollection_AsciiString& THE_CONFIGURATION_SCOPE()
return aScope;
}
// Wrapper to auto-load DE component
DE_PluginHolder<DESTL_ConfigurationNode> THE_OCCT_STL_COMPONENT_PLUGIN;
} // namespace
//=================================================================================================

View File

@@ -4,5 +4,4 @@ set(OCCT_TKDESTL_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKDESTL_FILES
EXTERNLIB
PACKAGES
TKDESTL.cxx
)

View File

@@ -15,6 +15,7 @@
#include <DEVRML_Provider.hxx>
#include <DE_ConfigurationContext.hxx>
#include <DE_PluginHolder.hxx>
IMPLEMENT_STANDARD_RTTIEXT(DEVRML_ConfigurationNode, DE_ConfigurationNode)
@@ -26,6 +27,8 @@ static const TCollection_AsciiString& THE_CONFIGURATION_SCOPE()
return aScope;
}
// Wrapper to auto-load DE component
DE_PluginHolder<DEVRML_ConfigurationNode> THE_OCCT_VRML_COMPONENT_PLUGIN;
} // namespace
//=================================================================================================

View File

@@ -4,5 +4,4 @@ set(OCCT_TKDEVRML_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKDEVRML_FILES
EXTERNLIB
PACKAGES
TKDEVRML.cxx
)

View File

@@ -1,19 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <DEVRML_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
//! Plugin factory function to register DEVRML configuration node.
//! Call PLUGINFACTORY() to register the DEVRML_ConfigurationNode with the global DE_Wrapper.
DEPLUGIN(DEVRML_ConfigurationNode)

View File

@@ -25,6 +25,7 @@
#include <OSD_Chronometer.hxx>
#include <OSD_Environment.hxx>
#include <OSD_Exception_CTRL_BREAK.hxx>
#include <OSD_MAllocHook.hxx>
#include <OSD_MemInfo.hxx>
#include <OSD_Parallel.hxx>
#include <OSD_PerfMeter.hxx>
@@ -676,6 +677,126 @@ static Standard_Integer cpulimit(Draw_Interpretor& di, Standard_Integer n, const
//=================================================================================================
static Standard_Integer mallochook(Draw_Interpretor& di, Standard_Integer n, const char** a)
{
if (n < 2)
{
di << "\
usage: mallochook cmd\n\
where cmd is one of:\n\
set [<op>] - set callback to malloc/free; op is one of the following:\n\
0 - set callback to NULL,\n\
1 - set callback OSD_MAllocHook::CollectBySize (default)\n\
2 - set callback OSD_MAllocHook::LogFileHandler\n\
reset - reset the CollectBySize handler\n\
report1 [<outfile>]\n\
- write report from CollectBySize handler in <outfile>\n\
open [<logfile>]\n\
- open file for writing the log with LogFileHandler\n\
close - close the log file with LogFileHandler\n\
report2 [<flag>] [<logfile>] [<outfile>]\n\
- scan <logfile> written with LogFileHandler\n\
and make synthesized report in <outfile>; <flag> can be:\n\
0 - simple stats by sizes (default),\n\
1 - with alive allocation numbers\n\
By default <logfile> is \"mem-log.txt\", <outfile> is \"mem-stat.txt\""
<< "\n";
return 0;
}
if (strcmp(a[1], "set") == 0)
{
int aType = (n > 2 ? Draw::Atoi(a[2]) : 1);
if (aType < 0 || aType > 2)
{
di << "unknown op of the command set\n";
return 1;
}
else if (aType == 0)
{
OSD_MAllocHook::SetCallback(NULL);
di << "callback is unset\n";
}
else if (aType == 1)
{
OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetCollectBySize());
di << "callback is set to CollectBySize\n";
}
else // if (aType == 2)
{
OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetLogFileHandler());
di << "callback is set to LogFileHandler\n";
}
}
else if (strcmp(a[1], "reset") == 0)
{
OSD_MAllocHook::GetCollectBySize()->Reset();
di << "CollectBySize handler is reset\n";
}
else if (strcmp(a[1], "open") == 0)
{
const char* aFileName = (n > 2 ? a[2] : "mem-log.txt");
if (!OSD_MAllocHook::GetLogFileHandler()->Open(aFileName))
{
di << "cannot create file " << aFileName << " for writing\n";
return 1;
}
di << "log file " << aFileName << " is opened for writing\n";
}
else if (strcmp(a[1], "close") == 0)
{
OSD_MAllocHook::GetLogFileHandler()->Close();
di << "log file is closed\n";
}
else if (strcmp(a[1], "report1") == 0)
{
const char* aOutFile = "mem-stat.txt";
if (n > 2)
aOutFile = a[2];
if (OSD_MAllocHook::GetCollectBySize()->MakeReport(aOutFile))
{
di << "report " << aOutFile << " has been created\n";
}
else
{
di << "cannot create report " << aOutFile << "\n";
return 1;
}
}
else if (strcmp(a[1], "report2") == 0)
{
Standard_Boolean includeAlive = Standard_False;
const char* aLogFile = "mem-log.txt";
const char* aOutFile = "mem-stat.txt";
if (n > 2)
{
includeAlive = (Draw::Atoi(a[2]) != 0);
if (n > 3)
{
aLogFile = a[3];
if (n > 4)
aOutFile = a[4];
}
}
if (OSD_MAllocHook::LogFileHandler::MakeReport(aLogFile, aOutFile, includeAlive))
{
di << "report " << aOutFile << " has been created\n";
}
else
{
di << "cannot create report " << aOutFile << " from the log file " << aLogFile << "\n";
return 1;
}
}
else
{
di << "unrecognized command " << a[1] << "\n";
return 1;
}
return 0;
}
//=================================================================================================
static int dlocale(Draw_Interpretor& di, Standard_Integer n, const char** argv)
{
int category = LC_ALL;
@@ -1198,6 +1319,11 @@ void Draw::BasicCommands(Draw_Interpretor& theCommands)
"\n\t\t: chrono t -stop -show";
theCommands.Add("chrono", aChronoHelp, __FILE__, dchronom, g);
theCommands.Add("dchrono", aChronoHelp, __FILE__, dchronom, g);
theCommands.Add("mallochook",
"debug memory allocation/deallocation, w/o args for help",
__FILE__,
mallochook,
g);
theCommands.Add("meminfo",
"meminfo [virt|v] [heap|h] [wset|w] [wsetpeak] [swap] [swappeak] [private]"
" : memory counters for this process",

View File

@@ -3,4 +3,5 @@ set(OCCT_TKQADraw_LIST_OF_PACKAGES
QABugs
QADNaming
QADraw
QANCollection
)

View File

@@ -2969,12 +2969,96 @@ static Standard_Integer OCC28829(Draw_Interpretor&, Standard_Integer, const char
#include <NCollection_Buffer.hxx>
#include <DDocStd_DrawDocument.hxx>
#include <OSD_FileSystem.hxx>
#include <Standard_ArrayStreamBuffer.hxx>
#include <TDocStd_Application.hxx>
#ifdef max
#undef max
#endif
static Standard_Integer OCC28887(Draw_Interpretor&,
Standard_Integer theNbArgs,
const char** theArgVec)
{
if (theNbArgs < 3)
{
std::cout << "Syntax error: wrong number of arguments!\n";
return 1;
}
const TCollection_AsciiString aFilePath(theArgVec[1]);
const TCollection_AsciiString aName(theArgVec[2]);
Handle(NCollection_Buffer) aBuffer;
{
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::istream> aFile =
aFileSystem->OpenIStream(aFilePath, std::ios::binary | std::ios::in);
if (aFile.get() == NULL)
{
std::cout << "Error: input file '" << aFilePath << "' cannot be read\n";
return 1;
}
aFile->seekg(0, std::ios_base::end);
const int64_t aFileLength = int64_t(aFile->tellg());
if (aFileLength > int64_t(std::numeric_limits<ptrdiff_t>::max()) || aFileLength < 1)
{
std::cout << "Error: input file '" << aFilePath << "' is too large\n";
return 1;
}
aFile->seekg(0, std::ios_base::beg);
aBuffer = new NCollection_Buffer(NCollection_BaseAllocator::CommonBaseAllocator());
if (!aBuffer->Allocate(size_t(aFileLength)))
{
std::cout << "Error: memory allocation (" << aFileLength << ") has failed\n";
return 1;
}
aFile->read((char*)aBuffer->ChangeData(), aBuffer->Size());
if (!aFile->good())
{
std::cout << "Error: input file '" << aFilePath << "' reading failure\n";
return 1;
}
}
Standard_ArrayStreamBuffer aStreamBuffer((const char*)aBuffer->ChangeData(), aBuffer->Size());
std::istream aStream(&aStreamBuffer);
// just play with seeking
aStream.seekg(0, std::ios_base::end);
aStream.seekg(0, std::ios_base::beg);
if (aFilePath.EndsWith(".brep") || aFilePath.EndsWith(".rle"))
{
TopoDS_Shape aShape;
BRep_Builder aBuilder;
BRepTools::Read(aShape, aStream, aBuilder);
DBRep::Set(aName.ToCString(), aShape);
}
else
{
Handle(TDocStd_Document) aDoc;
Handle(TDocStd_Application) anApp = DDocStd::GetApplication();
Standard_CString aNameVar = aName.ToCString();
if (DDocStd::GetDocument(aNameVar, aDoc, Standard_False))
{
std::cout << "Error: document with name " << aName << " already exists\n";
return 1;
}
if (anApp->Open(aStream, aDoc) != PCDM_RS_OK)
{
std::cout << "Error: cannot open XDE document\n";
return 1;
}
Handle(DDocStd_DrawDocument) aDrawDoc = new DDocStd_DrawDocument(aDoc);
TDataStd_Name::Set(aDoc->GetData()->Root(), aName.ToCString());
Draw::Set(aName.ToCString(), aDrawDoc);
}
return 0;
}
static Standard_Integer OCC28131(Draw_Interpretor&,
Standard_Integer theNbArgs,
const char** theArgVec)
@@ -5206,6 +5290,12 @@ void QABugs::Commands_20(Draw_Interpretor& theCommands)
theCommands.Add("OCC28594", "OCC28594", __FILE__, OCC28594, group);
theCommands.Add("OCC28784", "OCC28784 result shape", __FILE__, OCC28784, group);
theCommands.Add("OCC28829", "OCC28829: perform invalid FPE operation", __FILE__, OCC28829, group);
theCommands.Add("OCC28887",
"OCC28887 filePath result"
"\n\t\t: Check interface for reading BRep from memory.",
__FILE__,
OCC28887,
group);
theCommands.Add("OCC28131",
"OCC28131 name: creates face problematic for offset",
__FILE__,

View File

@@ -18,6 +18,7 @@
#include <QABugs.hxx>
#include <QADraw.hxx>
#include <QADNaming.hxx>
#include <QANCollection.hxx>
#include <AIS_InteractiveContext.hxx>
#include <Bnd_Box.hxx>
@@ -174,6 +175,7 @@ void QADraw::Factory(Draw_Interpretor& theCommands)
QABugs::Commands(theCommands);
QADNaming::AllCommands(theCommands);
QANCollection::Commands(theCommands);
}
// Declare entry point PLUGINFACTORY

View File

@@ -0,0 +1,22 @@
# Source files for QANCollection package
set(OCCT_QANCollection_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_QANCollection_FILES
FILES
QANCollection.cxx
QANCollection.hxx
QANCollection_Alloc.cxx
QANCollection_Handle.cxx
QANCollection_Common.cxx
QANCollection_Common.hxx
QANCollection_DataMapIteratorOfDataMapOfRealPnt.hxx
QANCollection_DataMapOfRealPnt.hxx
QANCollection_DoubleMapIteratorOfDoubleMapOfRealInteger.hxx
QANCollection_DoubleMapOfRealInteger.hxx
QANCollection_IndexedDataMapOfRealPnt.hxx
QANCollection_ListIteratorOfListOfPnt.hxx
QANCollection_ListOfPnt.hxx
QANCollection_Perf.cxx
QANCollection_Stl.cxx
QANCollection_Test.cxx
)

View File

@@ -1,4 +1,6 @@
// Copyright (c) 2025 OPEN CASCADE SAS
// Created on: 2004-03-05
// Created by: Mikhail KUZMITCHEV
// Copyright (c) 2004-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
@@ -11,11 +13,14 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <DEBREP_ConfigurationNode.hxx>
#include <DEXCAF_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#include <QANCollection.hxx>
#include <Draw_Interpretor.hxx>
//! Plugin factory function to register TKDECascade configuration nodes.
//! Call PLUGINFACTORY() to register both DEBREP_ConfigurationNode and DEXCAF_ConfigurationNode
//! with the global DE_Wrapper.
DEPLUGIN(DEBREP_ConfigurationNode, DEXCAF_ConfigurationNode)
void QANCollection::Commands(Draw_Interpretor& theCommands)
{
QANCollection::CommandsTest(theCommands);
QANCollection::CommandsPerf(theCommands);
QANCollection::CommandsAlloc(theCommands);
QANCollection::CommandsHandle(theCommands);
QANCollection::CommandsStl(theCommands);
}

View File

@@ -0,0 +1,43 @@
// Created on: 2004-03-05
// Created by: Mikhail KUZMITCHEV
// Copyright (c) 2004-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _QANCollection_HeaderFile
#define _QANCollection_HeaderFile
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
#include <Standard_Handle.hxx>
#include <Draw_Interpretor.hxx>
class QANCollection
{
public:
DEFINE_STANDARD_ALLOC
Standard_EXPORT static void Commands(Draw_Interpretor& DI);
Standard_EXPORT static void CommandsTest(Draw_Interpretor& DI);
Standard_EXPORT static void CommandsPerf(Draw_Interpretor& DI);
Standard_EXPORT static void CommandsAlloc(Draw_Interpretor& DI);
Standard_EXPORT static void CommandsStl(Draw_Interpretor& DI);
Standard_EXPORT static void CommandsHandle(Draw_Interpretor& DI);
};
#endif // _QANCollection_HeaderFile

View File

@@ -0,0 +1,156 @@
// Created on: 2004-03-05
// Created by: Mikhail KUZMITCHEV
// Copyright (c) 2004-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <QANCollection.hxx>
#include <Draw_Interpretor.hxx>
#include <NCollection_OccAllocator.hxx>
#include <NCollection_IncAllocator.hxx>
#include <Standard_Assert.hxx>
#include <list>
#include <vector>
//=================================================================================================
static Standard_Integer QANColStdAllocator1(Draw_Interpretor& di,
Standard_Integer argc,
const char** argv)
{
if (argc != 1)
{
di << "Usage : " << argv[0] << "\n";
return 1;
}
// type definitions
typedef Handle(Standard_Transient) elem_type;
typedef NCollection_OccAllocator<elem_type> allocator_type;
Standard_STATIC_ASSERT(sizeof(allocator_type::value_type) == sizeof(elem_type));
Standard_STATIC_ASSERT(sizeof(allocator_type::pointer) == sizeof(void*));
Standard_STATIC_ASSERT(sizeof(allocator_type::const_pointer) == sizeof(void*));
elem_type aDummy;
allocator_type::reference aRef = aDummy;
(void)aRef; // avoid compiler warning on unused
allocator_type::const_reference aConstRef = aDummy;
(void)aConstRef; // avoid compiler warning on unused
Standard_STATIC_ASSERT(sizeof(allocator_type::size_type) == sizeof(size_t));
Standard_STATIC_ASSERT(sizeof(allocator_type::difference_type) == sizeof(ptrdiff_t));
typedef int other_elem_type;
Standard_STATIC_ASSERT(sizeof(allocator_type::rebind<other_elem_type>::other::value_type)
== sizeof(other_elem_type));
return 0;
}
//=================================================================================================
static Standard_Integer QANColStdAllocator2(Draw_Interpretor& di,
Standard_Integer argc,
const char** argv)
{
if (argc != 1)
{
di << "Usage : " << argv[0] << "\n";
return 1;
}
// create incremental allocator outside the scope of objects it will manage
Handle(NCollection_IncAllocator) anIncAlloc = new NCollection_IncAllocator();
{
// typed allocator
NCollection_OccAllocator<int> aSAlloc(anIncAlloc);
std::list<int, NCollection_OccAllocator<int>> aL(aSAlloc);
aL.push_back(2);
if (aL.size() == size_t(1))
{
di << "Test1 : OK\n";
}
else
{
di << "Test1 : Error\n";
}
// type cast
NCollection_OccAllocator<char> aCAlloc;
std::vector<int, NCollection_OccAllocator<int>> aV(aCAlloc);
aV.push_back(1);
if (aV.size() == size_t(1))
{
di << "Test2 : OK\n";
}
else
{
di << "Test2 : Error\n";
}
// using void-specialization allocator
NCollection_OccAllocator<void*> aVAlloc;
std::vector<int, NCollection_OccAllocator<int>> aV2(aVAlloc);
aV2.resize(10);
aV2.push_back(-1);
if (aV2.size() == size_t(11))
{
di << "Test3 : OK\n";
}
else
{
di << "Test3 : Error\n";
}
// equality of allocators
if (aSAlloc != aCAlloc)
{
di << "Test4 : OK\n";
}
else
{
di << "Test4 : Error\n";
}
NCollection_OccAllocator<int> anIAlloc(anIncAlloc);
if (aSAlloc == anIAlloc)
{
di << "Test5 : OK\n";
}
else
{
di << "Test5 : Error\n";
}
}
return 0;
}
void QANCollection::CommandsAlloc(Draw_Interpretor& theCommands)
{
const char* group = "QANCollection";
theCommands.Add("QANColStdAllocator1",
"QANColStdAllocator1",
__FILE__,
QANColStdAllocator1,
group);
theCommands.Add("QANColStdAllocator2",
"QANColStdAllocator2",
__FILE__,
QANColStdAllocator2,
group);
return;
}

View File

@@ -0,0 +1,55 @@
// Created on: 2002-04-30
// Created by: Alexander KARTOMIN (akm)
// Copyright (c) 2002-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
// Purpose: To test all methods of all NCollection classes
#include <QANCollection_Common.hxx>
#include <stdio.h>
void PrintItem(const gp_Pnt& thePnt)
{
printf(" (%5.1f %5.1f %5.1f)\n", thePnt.X(), thePnt.Y(), thePnt.Z());
}
void PrintItem(const Standard_Real theDbl)
{
printf(" (%5.1f)\n", theDbl);
}
void Random(Standard_Real& theValue)
{
static Standard_Real dfV = 0.14159265358979323846;
dfV *= 37.;
dfV -= Floor(dfV);
theValue = dfV;
// theValue=drand48();
}
void Random(Standard_Integer& theValue, const Standard_Integer theMax)
{
Standard_Real dfR;
Random(dfR);
theValue = RealToInt(theMax * dfR);
}
void Random(gp_Pnt& thePnt)
{
// thePnt.SetCoord(drand48(),drand48(),drand48());
Standard_Real dfX, dfY, dfZ;
Random(dfX);
Random(dfY);
Random(dfZ);
thePnt.SetCoord(dfX, dfY, dfZ);
}

View File

@@ -0,0 +1,34 @@
// Created on: 2002-05-15
// Created by: Alexander KARTOMIN (akm)
// Copyright (c) 2002-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef QANCollection_Common_HeaderFile
#define QANCollection_Common_HeaderFile
#include <gp_Pnt.hxx>
// ===================== Methods for accessing items/keys =====================
// To print other type of items define PrintItem for it
Standard_EXPORT void PrintItem(const gp_Pnt& thePnt);
Standard_EXPORT void PrintItem(const Standard_Real theDbl);
// So do for the pseudo-random generation
Standard_EXPORT void Random(Standard_Real& theValue);
Standard_EXPORT void Random(Standard_Integer& theValue, const Standard_Integer theMax = RAND_MAX);
Standard_EXPORT void Random(gp_Pnt& thePnt);
#endif

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2025 OPEN CASCADE SAS
// Copyright (c) 2015 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
@@ -11,9 +11,9 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <DEPLY_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#ifndef QANCollection_DataMapIteratorOfDataMapOfRealPnt_HeaderFile
#define QANCollection_DataMapIteratorOfDataMapOfRealPnt_HeaderFile
//! Plugin factory function to register DEPLY configuration node.
//! Call PLUGINFACTORY() to register the DEPLY_ConfigurationNode with the global DE_Wrapper.
DEPLUGIN(DEPLY_ConfigurationNode)
#include <QANCollection_DataMapOfRealPnt.hxx>
#endif

View File

@@ -0,0 +1,26 @@
// Created on: 2004-03-05
// Created by: Mikhail KUZMITCHEV
// Copyright (c) 2004-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef QANCollection_DataMapOfRealPnt_HeaderFile
#define QANCollection_DataMapOfRealPnt_HeaderFile
#include <gp_Pnt.hxx>
#include <NCollection_DataMap.hxx>
typedef NCollection_DataMap<Standard_Real, gp_Pnt> QANCollection_DataMapOfRealPnt;
typedef NCollection_DataMap<Standard_Real, gp_Pnt>::Iterator
QANCollection_DataMapIteratorOfDataMapOfRealPnt;
#endif

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2025 OPEN CASCADE SAS
// Copyright (c) 2015 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
@@ -11,9 +11,9 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <DESTL_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#ifndef QANCollection_DoubleMapIteratorOfDoubleMapOfRealInteger_HeaderFile
#define QANCollection_DoubleMapIteratorOfDoubleMapOfRealInteger_HeaderFile
//! Plugin factory function to register DESTL configuration node.
//! Call PLUGINFACTORY() to register the DESTL_ConfigurationNode with the global DE_Wrapper.
DEPLUGIN(DESTL_ConfigurationNode)
#include <QANCollection_DoubleMapOfRealInteger.hxx>
#endif

View File

@@ -0,0 +1,26 @@
// Created on: 2004-03-05
// Created by: Mikhail KUZMITCHEV
// Copyright (c) 2004-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef QANCollection_DoubleMapOfRealInteger_HeaderFile
#define QANCollection_DoubleMapOfRealInteger_HeaderFile
#include <Standard_Integer.hxx>
#include <NCollection_DoubleMap.hxx>
typedef NCollection_DoubleMap<Standard_Real, Standard_Integer> QANCollection_DoubleMapOfRealInteger;
typedef NCollection_DoubleMap<Standard_Real, Standard_Integer>::Iterator
QANCollection_DoubleMapIteratorOfDoubleMapOfRealInteger;
#endif

View File

@@ -0,0 +1,658 @@
// Copyright (c) 2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <QANCollection.hxx>
#include <Draw.hxx>
#include <Draw_Interpretor.hxx>
#include <NCollection_OccAllocator.hxx>
#include <NCollection_IncAllocator.hxx>
#include <NCollection_HeapAllocator.hxx>
#include <OSD_Timer.hxx>
#include <Standard_DefineHandle.hxx>
#include <Standard_Transient.hxx>
#include <TCollection_AsciiString.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Line.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_Surface.hxx>
#include <vector>
#include <memory>
// Auxiliary macro to check and report status.
// Note that if() is used to ensure that condition is
// evaluated before calls to stream output functions, to
// prevent side effects from such calls in cases when condition
// may contain references to freed objects in the stack.
#define CHECK(di, ok, what) \
if (ok) \
di << "Checking " << what << ": OK\n"; \
else \
di << "Checking " << what << ": Error\n"
//=======================================================================
// function : QAHandleOps
// purpose : Test Handle operations (mostly compile-time checks)
//=======================================================================
// set of overloaded functions for checking resolution of arguments
inline void f(const Handle(Geom_Curve)&) {}
inline void func(const Handle(Geom_Curve)&) {}
inline void func(const Handle(Geom_BSplineCurve)&) {}
inline void func(const Handle(Geom_Surface)&) {}
inline void func(const Handle(gp_Pnt)&) {}
inline void func(const Handle(gp_XYZ)&) {}
inline void func(const Handle(gp_Trsf)&) {}
static Standard_Integer QAHandleOps(Draw_Interpretor& theDI,
Standard_Integer /*theArgNb*/,
const char** /*theArgVec*/)
{
// ===============================================================
// Part 1: classes inheriting transient
// ===============================================================
Handle(Geom_Line) aLine = new Geom_Line(gp::Origin(), gp::DZ());
CHECK(theDI, !aLine.IsNull(), "handle for non-null");
const Handle(Geom_Line)& cLine = aLine; // cast to self const ref
const Handle(Geom_Curve)& cCurve = aLine; // cast to base const ref
Geom_Line* pLine = aLine.get();
const Geom_Line* cpLine = aLine.get();
Geom_Line& rLine = *aLine;
const Geom_Line& crLine = *cLine;
Handle(Geom_Curve) aCurve = aLine; // copy from handle to derived type
aCurve = cLine; // assignment to handle of derived type
Handle(Geom_Line) dLine(cpLine); // copy from handle to derived type
aLine = Handle(Geom_Line)::DownCast(cCurve);
CHECK(theDI, !aLine.IsNull(), "down cast");
// comparison operators
CHECK(theDI, aLine == aLine, "equality of handle to itself");
CHECK(theDI, cLine == cLine, "equality of const handle to itself");
CHECK(theDI, aLine == cLine, "equality of const and non-const handle");
CHECK(theDI, aLine == cCurve, "equality of handle and base handle");
CHECK(theDI, aLine == pLine, "equality of handle and pointer");
CHECK(theDI, pLine == aLine, "equality of pointer and handle");
CHECK(theDI, aLine == cpLine, "equality of handle and const pointer");
CHECK(theDI, cpLine == aLine, "equality of const pointer and handle");
CHECK(theDI, &rLine == aLine, "equality of reference and handle");
CHECK(theDI, &crLine == aLine, "equality of reference and handle");
CHECK(theDI, aLine, "cast to bool");
Handle(Geom_Line) aLin2;
CHECK(theDI, aLine != aLin2, "inequality of handle to the same type handle");
CHECK(theDI, aLin2 != cLine, "inequality of const and non-const handle");
CHECK(theDI, aLin2 != cCurve, "inequality of handle and base handle");
CHECK(theDI, aLin2 != pLine, "inequality of handle and pointer");
CHECK(theDI, pLine != aLin2, "inequality of pointer and handle");
CHECK(theDI, aLin2 != cpLine, "inequality of handle and const pointer");
CHECK(theDI, cpLine != aLin2, "inequality of const pointer and handle");
Handle(Geom_Curve) aCur2;
CHECK(theDI, aLine != aCur2, "inequality of handles of different types");
CHECK(theDI, aCur2 != cLine, "inequality of const and non-const handle");
CHECK(theDI, aCur2 != cCurve, "inequality of handle and base handle");
CHECK(theDI, aCur2 != pLine, "inequality of handle and pointer");
CHECK(theDI, pLine != aCur2, "inequality of pointer and handle");
CHECK(theDI, aCur2 != cpLine, "inequality of handle and const pointer");
CHECK(theDI, cpLine != aCur2, "inequality of const pointer and handle");
// passing handle as reference to base class
f(aLine);
// passing handle to overloaded function accepting handle to another type
// will fail on VC below 12 and GCC below 4.3 due to ambiguity of overloads
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) \
|| (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3)
func(aLine);
func(cLine);
#endif
const Handle(Geom_Curve)& aCurve2 = aLine; // cast to base const ref
CHECK(theDI, !aCurve2.IsNull(), "cast to base class const reference");
Handle(Geom_Line) qLine = cpLine; // constructor from const pointer -- could be made explicit...
// check that compiler keeps temporary object referenced by local variable
const Handle(Geom_Line)& aTmpRef(Handle(Geom_Line)::DownCast(aCurve2));
// note that here and in similar checks below we use comparison of pointers instead
// of checking handle for Null, since such check may fail if temporary object is
// destroyed prematurely and its location is used for other object.
CHECK(theDI, aTmpRef.get() == aCurve2.get(), "local reference of to temporary handle object");
// check undesired but logical situation:
// compiler does not keep temporary object referenced by local variable of base type;
// here compiler does not recognize that it should keep the temporary object because handle
// classes do not inherit each other and they use hard cast for references to simulate inheritance
#if defined(__GNUC__) && (__GNUC__ > 12)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdangling-reference"
#endif
const Handle(Geom_Curve)& aTmpRefBase(Handle(Geom_Line)::DownCast(aCurve2));
CHECK(theDI,
aTmpRefBase.get() != aCurve2.get(),
"local reference to temporary handle object (base type)");
#if defined(__GNUC__) && (__GNUC__ > 12)
#pragma GCC diagnostic pop
#endif
// check operations with Handle_* classes
Handle(Geom_Line) hLine = aLine;
CHECK(theDI, !hLine.IsNull(), "hhandle for non-null");
#include <Standard_WarningsDisable.hxx>
const Handle_Geom_Line& chLine = aLine; // cast to self const ref
const Handle_Geom_Curve& chCurve = aLine; // cast to base const ref
const Handle_Geom_Line& hhLine = hLine; // cast to self const ref
const Handle_Geom_Curve& hhCurve = hLine; // cast to base const ref
Handle_Geom_Curve hCurve = aLine; // copy from handle to derived type
Handle_Geom_Line phLine(aLine.get()); // construct from pointer
hLine = Handle_Geom_Line::DownCast(cCurve); // inheritance of downcast
CHECK(theDI, !hLine.IsNull(), "down cast");
// comparison operators
CHECK(theDI, hLine == hLine, "equality of hhandle to itself");
CHECK(theDI, hLine == aLine, "equality of hhandle to handle");
CHECK(theDI, hhLine == hLine, "equality of hhandle to const");
CHECK(theDI, chLine == hLine, "equality of hhandle to const");
CHECK(theDI, hhCurve == hLine, "equality of hhandle to const");
CHECK(theDI, chCurve == hLine, "equality of hhandle to const");
CHECK(theDI, hLine, "cast to bool");
// passing hhandle as reference to base class
f(hLine);
// passing handle to overloaded function accepting handle to another type
// will fail on VC below 12 and GCC below 4.3 due to ambiguity of overloads
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) \
|| (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3)
func(hLine);
func(chLine);
#endif
Handle_Geom_Line qhLine = cpLine; // constructor from const pointer -- could be made explicit...
// check that compiler keeps temporary object referenced by local variable
#if defined(__GNUC__) && (__GNUC__ > 12)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdangling-reference"
#endif
const Handle_Geom_Line& hTmpRef(Handle(Geom_Line)::DownCast(aCurve2));
CHECK(theDI, hTmpRef.get() == aCurve2.get(), "local reference to temporary object (Handle_)");
// check lifetime of temporary object referenced by local variable (base type)
const Handle_Geom_Curve& hTmpRefBase(Handle(Geom_Line)::DownCast(aCurve2));
#if defined(__GNUC__) && (__GNUC__ > 11)
#pragma GCC diagnostic pop
#endif
// here we have different behavior for MSVC 2013+ where Handle_ is a class
// (compiler creates temporary object of approprtiate type and keeps it living
// until the reference is valid) and other compilers where Handle_ is
// typedef to handle<> (compiler does not know that the reference that is being
// assigned is pointing to temporary object, due to involved type cast operation)
#if (defined(_MSC_VER) && _MSC_VER >= 1800)
CHECK(theDI,
hTmpRefBase.get() == aCurve2.get(),
"local reference to temporary handle object (Handle_ to base type)");
#else
CHECK(theDI,
hTmpRefBase.get() != aCurve2.get(),
"local reference to temporary handle object (Handle_ to base type)");
#endif
#include <Standard_WarningsRestore.hxx>
Handle(Geom_Surface) aSurf;
(void)aSurf;
#if 0
// each test in this section must cause compiler error
gunc (cLine); // passing const handle as non-const reference to base type
pLine = cLine.get(); // getting non-const pointer to contained object from const handle
Handle(Geom_Line) xLine = cCurve; // copy from handle to base type
// clang-format off
Handle(Geom_BSplineCurve) aBSpl (new Geom_Line (gp::Origin(), gp::DX())); // construction from pointer to incompatible type
// clang-format on
CHECK(theDI, aLine == aSurf, "equality of handles of incompatible types");
CHECK(theDI, aSurf == cLine, "equality of const and non-const handle");
CHECK(theDI, aSurf == cCurve, "equality of handle and base handle");
CHECK(theDI, aSurf == pLine, "equality of handle and pointer");
CHECK(theDI, pLine == aSurf, "equality of pointer and handle");
CHECK(theDI, aSurf == cpLine, "equality of handle and const pointer");
CHECK(theDI, cpLine != aSurf, "equality of const pointer and handle");
CHECK(theDI, aLine != aSurf, "inequality of handles of incompatible types");
CHECK(theDI, aSurf != cLine, "inequality of const and non-const handle");
CHECK(theDI, aSurf != cCurve, "inequality of handle and base handle");
CHECK(theDI, aSurf != pLine, "inequality of handle and pointer");
CHECK(theDI, pLine != aSurf, "inequality of pointer and handle");
CHECK(theDI, aSurf != cpLine, "inequality of handle and const pointer");
CHECK(theDI, cpLine != aSurf, "inequality of const pointer and handle");
#endif
// ===============================================================
// Part 2: classes not inheriting transient
// ===============================================================
/*
Handle(gp_Pnt) aPnt = new gp_Pnt (gp::Origin());
CHECK(theDI, ! aPnt.IsNull(), "handle for non-null");
const Handle(gp_Pnt)& cPnt = aPnt; // cast to self const ref
// const Handle(gp_XYZ)& cXYZ = aPnt; // cast to base const ref
gp_Pnt* pPnt = aPnt.get();
const gp_Pnt* cpPnt = aPnt.get();
gp_Pnt& rPnt = *aPnt;
const gp_Pnt& crPnt = *cPnt;
// Handle(gp_XYZ) aXYZ = aPnt; // copy from handle to derived type
// aXYZ = cPnt; // assignment to handle of derived type
// aPnt = Handle(gp_Pnt)::DownCast (cXYZ);
// CHECK(theDI, ! aPnt.IsNull(), "down cast");
// comparison operators
CHECK(theDI, aPnt == aPnt, "equality of handle to itself");
CHECK(theDI, cPnt == cPnt, "equality of const handle to itself");
CHECK(theDI, aPnt == cPnt, "equality of const and non-const handle");
// CHECK(theDI, aPnt == cXYZ, "equality of handle and base handle");
CHECK(theDI, aPnt == pPnt, "equality of handle and pointer");
CHECK(theDI, pPnt == aPnt, "equality of pointer and handle");
CHECK(theDI, aPnt == cpPnt, "equality of handle and const pointer");
CHECK(theDI, cpPnt == aPnt, "equality of const pointer and handle");
CHECK(theDI, &rPnt == aPnt, "equality of reference and handle");
CHECK(theDI, &crPnt == aPnt, "equality of reference and handle");
Handle(gp_Pnt) aPnt2;
CHECK(theDI, aPnt != aPnt2, "inequality of handle to the same type handle");
CHECK(theDI, aPnt2 != cPnt, "inequality of const and non-const handle");
// CHECK(theDI, aPnt2 != cXYZ, "inequality of handle and base handle");
CHECK(theDI, aPnt2 != pPnt, "inequality of handle and pointer");
CHECK(theDI, pPnt != aPnt2, "inequality of pointer and handle");
CHECK(theDI, aPnt2 != cpPnt, "inequality of handle and const pointer");
CHECK(theDI, cpPnt != aPnt2, "inequality of const pointer and handle");
Handle(gp_XYZ) aXYZ2;
CHECK(theDI, aLine != aPnt2, "inequality of handles of different types");
CHECK(theDI, aXYZ2 != cPnt, "inequality of const and non-const handle");
// CHECK(theDI, aXYZ2 != cXYZ, "inequality of handle and base handle");
// CHECK(theDI, aXYZ2 != pPnt, "inequality of handle and pointer");
// CHECK(theDI, pPnt != aXYZ2, "inequality of pointer and handle");
// CHECK(theDI, aXYZ2 != cpPnt, "inequality of handle and const pointer");
// CHECK(theDI, cpPnt != aXYZ2, "inequality of const pointer and handle");
// passing handle as reference to base class
func (aPnt);
func (cPnt);
*/
return 0;
}
//=======================================================================
// function : QAHandleBool
// purpose : Test Handle -> bool conversion
//=======================================================================
static Standard_Integer QAHandleBool(Draw_Interpretor& theDI,
Standard_Integer /*theArgNb*/,
const char** /*theArgVec*/)
{
Handle(NCollection_BaseAllocator) aPtr = new NCollection_IncAllocator();
Handle(NCollection_IncAllocator) anInc = Handle(NCollection_IncAllocator)::DownCast(aPtr);
CHECK(theDI, !anInc.IsNull(), "cast to NCollection_IncAllocator");
Handle(NCollection_BaseAllocator) anAlloc = aPtr;
CHECK(theDI, !anAlloc.IsNull(), "cast to NCollection_BaseAllocator");
Handle(NCollection_HeapAllocator) aHAlloc = Handle(NCollection_HeapAllocator)::DownCast(aPtr);
CHECK(theDI, aHAlloc.IsNull(), "cast to NCollection_HeapAllocator");
return 0;
}
// Auxiliary class to define new virtual methods
class Transient_Root : public Standard_Transient
{
public:
virtual const char* Name() const { return "Transient_Root"; }
virtual Standard_Transient* CreateParent() const { return new Standard_Transient; }
virtual Standard_Transient* Clone() const { return new Transient_Root; }
DEFINE_STANDARD_RTTI_INLINE(Transient_Root, Standard_Transient)
};
DEFINE_STANDARD_HANDLE(Transient_Root, Standard_Transient)
// Auxiliary macros to create hierarchy of 50 classes
#define QA_DEFINECLASS(theClass, theParent) \
class theClass : public theParent \
{ \
public: \
virtual const char* Name() const Standard_OVERRIDE \
{ \
return #theClass; \
} \
virtual Standard_Transient* CreateParent() const Standard_OVERRIDE \
{ \
return new theParent(); \
} \
virtual Standard_Transient* Clone() const Standard_OVERRIDE \
{ \
return new theClass(); \
} \
DEFINE_STANDARD_RTTI_INLINE(theClass, theParent) \
}; \
DEFINE_STANDARD_HANDLE(theClass, theParent)
#define QA_NAME(theNum) qaclass##theNum##_##50
#define QA_HANDLE_NAME(theNum) Handle(qaclass##theNum##_##50)
#define QA_DEFINECLASS10(theParent, theTens) \
QA_DEFINECLASS(QA_NAME(theTens##0), theParent) \
QA_DEFINECLASS(QA_NAME(theTens##1), QA_NAME(theTens##0)) \
QA_DEFINECLASS(QA_NAME(theTens##2), QA_NAME(theTens##1)) \
QA_DEFINECLASS(QA_NAME(theTens##3), QA_NAME(theTens##2)) \
QA_DEFINECLASS(QA_NAME(theTens##4), QA_NAME(theTens##3)) \
QA_DEFINECLASS(QA_NAME(theTens##5), QA_NAME(theTens##4)) \
QA_DEFINECLASS(QA_NAME(theTens##6), QA_NAME(theTens##5)) \
QA_DEFINECLASS(QA_NAME(theTens##7), QA_NAME(theTens##6)) \
QA_DEFINECLASS(QA_NAME(theTens##8), QA_NAME(theTens##7)) \
QA_DEFINECLASS(QA_NAME(theTens##9), QA_NAME(theTens##8))
QA_DEFINECLASS10(Transient_Root, 0)
QA_DEFINECLASS10(qaclass09_50, 1)
QA_DEFINECLASS10(qaclass19_50, 2)
QA_DEFINECLASS10(qaclass29_50, 3)
QA_DEFINECLASS10(qaclass39_50, 4)
QA_DEFINECLASS(qaclass50_50, qaclass49_50)
namespace
{
class qaclass50_50ANON : public qaclass49_50
{
};
} // namespace
namespace QaNamespace
{
class qaclass50_50 : public qaclass49_50
{
public:
qaclass50_50() {}
};
} // namespace QaNamespace
namespace
{
//! Timer sentry. Prints elapsed time information at destruction time.
class QATimer : public OSD_Timer
{
public:
enum TimeFormat
{
Seconds,
Milliseconds,
Microseconds,
Nanoseconds,
s = Seconds,
ms = Milliseconds,
ns = Nanoseconds,
};
public:
//! Main constructor - automatically starts the timer.
QATimer(Draw_Interpretor& theDI,
Standard_CString theTitle,
const TimeFormat theFormat,
const Standard_Integer theNbIters = 1,
const Standard_Boolean theToPrintFormat = Standard_False)
: myDI(&theDI),
myTitle(theTitle),
myFormat(theFormat),
myNbIters(theNbIters),
myToPrintFormat(theToPrintFormat)
{
Start();
}
//! Destructor - stops the timer and prints statistics.
~QATimer()
{
Stop();
if (myTitle != NULL)
{
(*myDI) << myTitle;
}
switch (myFormat)
{
case Seconds:
(*myDI) << ElapsedTime() / Standard_Real(myNbIters);
if (myToPrintFormat)
{
(*myDI) << " s";
}
break;
case Milliseconds:
(*myDI) << (ElapsedTime() / Standard_Real(myNbIters)) * 1000.0;
if (myToPrintFormat)
{
(*myDI) << " ms";
}
break;
case Microseconds:
(*myDI) << (ElapsedTime() / Standard_Real(myNbIters)) * 1000000.0;
if (myToPrintFormat)
{
(*myDI) << " microseconds";
}
break;
case Nanoseconds:
(*myDI) << (ElapsedTime() / Standard_Real(myNbIters)) * 1000000000.0;
if (myToPrintFormat)
{
(*myDI) << " ns";
}
break;
}
}
private:
Draw_Interpretor* myDI;
Standard_CString myTitle; //!< timer description
TimeFormat myFormat; //!< time format
Standard_Integer myNbIters; //!< iterations number
Standard_Boolean myToPrintFormat; //!< add time format
};
} // anonymous namespace
//=======================================================================
// function : QAHandleInc
// purpose : Estimate the smart-pointer counter incrementing time
//=======================================================================
static Standard_Integer QAHandleInc(Draw_Interpretor& theDI,
Standard_Integer theArgNb,
const char** theArgVec)
{
if (theArgNb > 2)
{
std::cout << "Error: wrong syntax! See usage:\n";
theDI.PrintHelp(theArgVec[0]);
return 1;
}
const Standard_Integer aNbIters = (theArgNb > 1) ? Draw::Atoi(theArgVec[1]) : 10000000;
if (aNbIters < 1)
{
std::cout << "Error: number of iterations should be positive!\n";
return 1;
}
Handle(Standard_Transient) aHandle = new Standard_Transient();
std::shared_ptr<Standard_Transient> aSharePtr(new Standard_Transient());
theDI << "Time of creating and destroying " << aNbIters
<< " smart pointers to the same object, per item, ns:";
{
{
QATimer aTimer(theDI, "\nOCCT Handle: ", QATimer::ns, aNbIters);
{
std::vector<Handle(Standard_Transient)> aHandles(aNbIters);
for (Standard_Integer anIter = 0; anIter < aNbIters; ++anIter)
{
aHandles[anIter] = aHandle;
}
}
}
{
QATimer aTimer(theDI, "\nC++ shared_ptr: ", QATimer::ns, aNbIters);
{
std::vector<std::shared_ptr<Standard_Transient>> aSharePointers(aNbIters);
for (Standard_Integer anIter = 0; anIter < aNbIters; ++anIter)
{
aSharePointers[anIter] = aSharePtr;
}
}
}
}
return 0;
}
//=================================================================================================
static Standard_Integer QAHandleKind(Draw_Interpretor& /*theDI*/,
Standard_Integer /*theArgNb*/,
const char** /*theArgVec*/)
{
Handle(Standard_Type) aType00 = STANDARD_TYPE(qaclass00_50);
Handle(Standard_Type) aType10 = STANDARD_TYPE(qaclass10_50);
Handle(Standard_Type) aType20 = STANDARD_TYPE(qaclass20_50);
Handle(Standard_Type) aType30 = STANDARD_TYPE(qaclass30_50);
Handle(Standard_Type) aType40 = STANDARD_TYPE(qaclass40_50);
Handle(Standard_Type) aType50 = STANDARD_TYPE(qaclass50_50);
Handle(qaclass00_50) aHandle = new qaclass40_50();
#define QA_CHECK(theDesc, theExpr, theValue) \
{ \
const bool isTrue = !!(theExpr); \
std::cout << theDesc << (isTrue ? " TRUE " : " FALSE ") \
<< (isTrue == theValue ? " is OK\n" : " is Error\n"); \
}
std::cout << "Check instance of " << aHandle->DynamicType()->Name() << "\n";
for (Handle(Standard_Type) aType = aHandle->DynamicType(); !aType.IsNull();
aType = aType->Parent())
{
std::cout << " - " << aType->Name() << "\n";
}
QA_CHECK("Name == qaclass40_50 : ",
TCollection_AsciiString("qaclass40_50") == aHandle->DynamicType()->Name(),
true);
QA_CHECK("IsKind (aType00) : ", aHandle->IsKind(aType00), true);
QA_CHECK("IsKind (aType10) : ", aHandle->IsKind(aType10), true);
QA_CHECK("IsKind (aType20) : ", aHandle->IsKind(aType20), true);
QA_CHECK("IsKind (aType30) : ", aHandle->IsKind(aType30), true);
QA_CHECK("IsKind (aType40) : ", aHandle->IsKind(aType40), true);
QA_CHECK("IsKind (aType50) : ", aHandle->IsKind(aType50), false);
QA_CHECK("IsKind (\"qaclass00_50\"): ", aHandle->IsKind("qaclass00_50"), true);
QA_CHECK("IsKind (\"qaclass10_50\"): ", aHandle->IsKind("qaclass10_50"), true);
QA_CHECK("IsKind (\"qaclass20_50\"): ", aHandle->IsKind("qaclass20_50"), true);
QA_CHECK("IsKind (\"qaclass30_50\"): ", aHandle->IsKind("qaclass30_50"), true);
QA_CHECK("IsKind (\"qaclass40_50\"): ", aHandle->IsKind("qaclass40_50"), true);
QA_CHECK("IsKind (\"qaclass50_50\"): ", aHandle->IsKind("qaclass50_50"), false);
QA_CHECK("IsInstance (aType00) : ", aHandle->IsInstance(aType00), false);
QA_CHECK("IsInstance (aType10) : ", aHandle->IsInstance(aType10), false);
QA_CHECK("IsInstance (aType20) : ", aHandle->IsInstance(aType20), false);
QA_CHECK("IsInstance (aType30) : ", aHandle->IsInstance(aType30), false);
QA_CHECK("IsInstance (aType40) : ", aHandle->IsInstance(aType40), true);
QA_CHECK("IsInstance (aType50) : ", aHandle->IsInstance(aType50), false);
#ifdef HAVE_CPP11
std::cout << "\nC++11:\n";
std::type_index aCppType = typeid(*aHandle.operator->());
std::cout << "typeid().name() = '" << typeid(*aHandle.operator->()).name() << "'\n";
#ifdef _MSC_VER
std::cout << "typeid().raw_name()= '" << typeid(*aHandle.operator->()).raw_name() << "'\n";
#endif
std::cout << "[ANON]typeid().name() = '" << typeid(qaclass50_50ANON).name() << "'\n";
#ifdef _MSC_VER
std::cout << "[ANON]typeid().raw_name()= '" << typeid(qaclass50_50ANON).raw_name() << "'\n";
#endif
std::cout << "[NS]typeid().name() = '" << typeid(QaNamespace::qaclass50_50).name() << "'\n";
#ifdef _MSC_VER
std::cout << "[NS]typeid().raw_name()= '" << typeid(QaNamespace::qaclass50_50).raw_name()
<< "'\n";
#endif
QA_CHECK("is typeid (aType00) : ",
typeid(*aHandle.operator->()) == typeid(qaclass00_50),
false);
QA_CHECK("is typeid (aType10) : ",
typeid(*aHandle.operator->()) == typeid(qaclass10_50),
false);
QA_CHECK("is typeid (aType20) : ",
typeid(*aHandle.operator->()) == typeid(qaclass20_50),
false);
QA_CHECK("is typeid (aType30) : ",
typeid(*aHandle.operator->()) == typeid(qaclass30_50),
false);
QA_CHECK("is typeid (aType40) : ",
typeid(*aHandle.operator->()) == typeid(qaclass40_50),
true);
QA_CHECK("is typeid (aType50) : ",
typeid(*aHandle.operator->()) == typeid(qaclass50_50),
false);
QA_CHECK("is type_index (aType00) : ", aCppType == typeid(qaclass00_50), false);
QA_CHECK("is type_index (aType40) : ", aCppType == typeid(qaclass40_50), true);
QA_CHECK("IsClass(Standard_Transient): ",
std::is_class<Standard_Transient>::value
== !!STANDARD_TYPE(Standard_Transient)->IsClass(),
true);
// QA_CHECK ("IsEnum (Message_Status) : ", std::is_enum<Message_Status>::value ==
// !!STANDARD_TYPE(Message_Status)->IsEnumeration(), true);
#endif
return 0;
}
void QANCollection::CommandsHandle(Draw_Interpretor& theCommands)
{
const char* THE_GROUP = "QANCollection";
theCommands.Add("QAHandleBool",
"Test handle boolean operator",
__FILE__,
QAHandleBool,
THE_GROUP);
theCommands.Add("QAHandleInc",
"QAHandleInc nbIter=1000000"
"\n\t\t: Test handle increment performance",
__FILE__,
QAHandleInc,
THE_GROUP);
theCommands.Add("QAHandleKind", "Test handle IsKind", __FILE__, QAHandleKind, THE_GROUP);
theCommands.Add("QAHandleOps", "Test handle operations", __FILE__, QAHandleOps, THE_GROUP);
return;
}

View File

@@ -1,4 +1,6 @@
// Copyright (c) 2025 OPEN CASCADE SAS
// Created on: 2004-03-05
// Created by: Mikhail KUZMITCHEV
// Copyright (c) 2004-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
@@ -11,9 +13,12 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <DEGLTF_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#ifndef QANCollection_IndexedDataMapOfRealPnt_HeaderFile
#define QANCollection_IndexedDataMapOfRealPnt_HeaderFile
//! Plugin factory function to register DEGLTF configuration node.
//! Call PLUGINFACTORY() to register the DEGLTF_ConfigurationNode with the global DE_Wrapper.
DEPLUGIN(DEGLTF_ConfigurationNode)
#include <gp_Pnt.hxx>
#include <NCollection_IndexedDataMap.hxx>
typedef NCollection_IndexedDataMap<Standard_Real, gp_Pnt> QANCollection_IndexedDataMapOfRealPnt;
#endif

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2025 OPEN CASCADE SAS
// Copyright (c) 2015 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
@@ -11,9 +11,9 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <DEOBJ_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#ifndef QANCollection_ListIteratorOfListOfPnt_HeaderFile
#define QANCollection_ListIteratorOfListOfPnt_HeaderFile
//! Plugin factory function to register DEOBJ configuration node.
//! Call PLUGINFACTORY() to register the DEOBJ_ConfigurationNode with the global DE_Wrapper.
DEPLUGIN(DEOBJ_ConfigurationNode)
#include <QANCollection_ListOfPnt.hxx>
#endif

View File

@@ -1,4 +1,6 @@
// Copyright (c) 2025 OPEN CASCADE SAS
// Created on: 2004-03-05
// Created by: Mikhail KUZMITCHEV
// Copyright (c) 2004-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
@@ -11,9 +13,13 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <DEIGES_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#ifndef QANCollection_ListOfPnt_HeaderFile
#define QANCollection_ListOfPnt_HeaderFile
//! Plugin factory function to register DEIGES configuration node.
//! Call PLUGINFACTORY() to register the DEIGES_ConfigurationNode with the global DE_Wrapper.
DEPLUGIN(DEIGES_ConfigurationNode)
#include <gp_Pnt.hxx>
#include <NCollection_List.hxx>
typedef NCollection_List<gp_Pnt> QANCollection_ListOfPnt;
typedef NCollection_List<gp_Pnt>::Iterator QANCollection_ListIteratorOfListOfPnt;
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6375,106 +6375,6 @@ static Standard_Integer VMoveTo(Draw_Interpretor& theDI,
return 0;
}
//=======================================================================
//function : VMouseButton
//purpose : Emulates mouse button event
//=======================================================================
static Standard_Integer VMouseButton(Draw_Interpretor& /*theDI*/,
Standard_Integer theNbArgs,
const char** theArgVec)
{
const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
const Handle(V3d_View)& aView = ViewerTest::CurrentView();
if (aContext.IsNull())
{
Message::SendFail("Error: no active viewer");
return 1;
}
if (theNbArgs < 6)
{
Message::SendFail("Syntax error: wrong number arguments");
return 1;
}
Aspect_VKeyMouse aButton = Aspect_VKeyMouse_LeftButton;
Standard_Boolean isPressButton = false;
Graphic3d_Vec2i aMousePos(IntegerLast(), IntegerLast());
for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
{
TCollection_AsciiString anArgStr(theArgVec[anArgIter]);
anArgStr.LowerCase();
if (anArgStr == "-button")
{
if (anArgIter + 1 < theNbArgs)
{
++anArgIter;
TCollection_AsciiString aButtonStr(theArgVec[anArgIter]);
if (aButtonStr == "left")
{
aButton = Aspect_VKeyMouse_LeftButton;
}
else if (aButtonStr == "right")
{
aButton = Aspect_VKeyMouse_RightButton;
}
else if (aButtonStr == "middle")
{
aButton = Aspect_VKeyMouse_MiddleButton;
}
}
}
else if (anArgStr == "-up")
{
isPressButton = false;
}
else if (anArgStr == "-down")
{
isPressButton = true;
}
else if (aMousePos.x() == IntegerLast()
&& anArgStr.IsIntegerValue())
{
aMousePos.x() = anArgStr.IntegerValue();
}
else if (aMousePos.y() == IntegerLast()
&& anArgStr.IsIntegerValue())
{
aMousePos.y() = anArgStr.IntegerValue();
}
else
{
Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
return 1;
}
}
if (aMousePos.x() == IntegerLast()
|| aMousePos.y() == IntegerLast())
{
Message::SendFail("Syntax error: wrong number of arguments");
return 1;
}
if (isPressButton)
{
ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
ViewerTest::CurrentEventManager()->PressMouseButton(aMousePos, aButton, Aspect_VKeyFlags_NONE, false);
ViewerTest::CurrentEventManager()->UpdateMousePosition(aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
ViewerTest::CurrentEventManager()->FlushViewEvents(ViewerTest::GetAISContext(), aView, true);
}
else
{
ViewerTest::CurrentEventManager()->UpdateMousePosition(aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
ViewerTest::CurrentEventManager()->FlushViewEvents(ViewerTest::GetAISContext(), aView, true);
ViewerTest::CurrentEventManager()->ReleaseMouseButton(aMousePos, aButton, Aspect_VKeyFlags_NONE, false);
ViewerTest::CurrentEventManager()->FlushViewEvents(ViewerTest::GetAISContext(), aView, true);
}
return 0;
}
//=================================================================================================
static Standard_Integer VSelectByAxis(Draw_Interpretor& theDI,
@@ -14181,14 +14081,6 @@ Emulate cursor movement to pixel position (x,y).
-reset resets current highlighting.
)" /* [vmoveto] */);
addCmd("vmousebutton", VMouseButton, /* [vmousebutton] */ R"(
vmousebutton x y -button right|left|middle -up|-down
Emulate mouse button events.
-button choose button;
-down press button;
-up release button.
)" /* [vmousebutton] */);
addCmd("vselaxis", VSelectByAxis, /* [vselaxis] */ R"(
vselaxis x y z dx dy dz [-onlyTop 0|1] [-display Name] [-showNormal 0|1]"
Provides intersection by given axis and print result intersection points.

View File

@@ -20,8 +20,6 @@
#include <DE_Provider.hxx>
#include <DE_Wrapper.hxx>
#include <DEBREP_ConfigurationNode.hxx>
#include <DEXCAF_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#include <Draw.hxx>
#include <Draw_Interpretor.hxx>
#include <Draw_PluginMacro.hxx>
@@ -33,16 +31,6 @@
#include <XSControl_WorkSession.hxx>
#include <XSDRAW.hxx>
namespace
{
// Singleton to ensure DEBREP and DEXCAF plugins are registered only once
void DECascadeSingleton()
{
static DE_MultiPluginHolder<DEBREP_ConfigurationNode, DEXCAF_ConfigurationNode> aHolder;
(void)aHolder;
}
} // namespace
//=================================================================================================
static Standard_Integer DumpConfiguration(Draw_Interpretor& theDI,
@@ -376,9 +364,6 @@ void XSDRAWDE::Factory(Draw_Interpretor& theDI)
}
aIsActivated = Standard_True;
//! Ensure DEBREP and DEXCAF plugins are registered
DECascadeSingleton();
Standard_CString aGroup = "XDE translation commands";
theDI.Add("DumpConfiguration",
"DumpConfiguration [-path <path>] [-recursive {on|off}] [-format fmt1 fmt2 ...] "
@@ -443,6 +428,10 @@ void XSDRAWDE::Factory(Draw_Interpretor& theDI)
// Load XSDRAW session for pilot activation
XSDRAW::LoadDraw(theDI);
// Workaround to force load TKDECascade lib
DEBREP_ConfigurationNode aTmpObj;
(void)aTmpObj;
}
// Declare entry point PLUGINFACTORY

View File

@@ -16,8 +16,6 @@
#include <DBRep.hxx>
#include <DDocStd.hxx>
#include <DDocStd_DrawDocument.hxx>
#include <DEGLTF_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#include <Draw.hxx>
#include <Draw_Interpretor.hxx>
#include <Draw_PluginMacro.hxx>
@@ -32,16 +30,6 @@
#include <XSControl_WorkSession.hxx>
#include <XSDRAW.hxx>
namespace
{
// Singleton to ensure DEGLTF plugin is registered only once
void DEGLTFSingleton()
{
static DE_PluginHolder<DEGLTF_ConfigurationNode> aHolder;
(void)aHolder;
}
} // namespace
//=============================================================================
// function : parseNameFormat
// purpose : Parse RWMesh_NameFormat enumeration
@@ -521,9 +509,6 @@ void XSDRAWGLTF::Factory(Draw_Interpretor& theDI)
}
aIsActivated = Standard_True;
//! Ensure DEGLTF plugin is registered
DEGLTFSingleton();
const char* aGroup = "XSTEP-STL/VRML"; // Step transfer file commands
theDI.Add("ReadGltf",
"ReadGltf Doc file [-parallel {on|off}] [-listExternalFiles] [-noCreateDoc] "

View File

@@ -17,8 +17,6 @@
#include <DBRep.hxx>
#include <DDocStd.hxx>
#include <DDocStd_DrawDocument.hxx>
#include <DEIGES_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#include <Draw.hxx>
#include <DrawTrSurf.hxx>
#include <Draw_Interpretor.hxx>
@@ -1110,16 +1108,6 @@ static Standard_Integer WriteIges(Draw_Interpretor& theDI,
return 0;
}
namespace
{
// Singleton to ensure DEIGES plugin is registered only once
void DEIGESSingleton()
{
static DE_PluginHolder<DEIGES_ConfigurationNode> aHolder;
(void)aHolder;
}
} // namespace
//=================================================================================================
void XSDRAWIGES::Factory(Draw_Interpretor& theDI)
@@ -1133,9 +1121,6 @@ void XSDRAWIGES::Factory(Draw_Interpretor& theDI)
IGESControl_Controller::Init();
//! Ensure DEIGES plugin is registered
DEIGESSingleton();
const char* aGroup = "DE: IGES";
theDI.Add("tplosttrim",

View File

@@ -17,8 +17,6 @@
#include <DBRep.hxx>
#include <DDocStd.hxx>
#include <DDocStd_DrawDocument.hxx>
#include <DEOBJ_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#include <Draw.hxx>
#include <Draw_Interpretor.hxx>
#include <Draw_PluginMacro.hxx>
@@ -337,16 +335,6 @@ static Standard_Integer WriteObj(Draw_Interpretor& theDI,
return 0;
}
namespace
{
// Singleton to ensure DEOBJ plugin is registered only once
void DEOBJSingleton()
{
static DE_PluginHolder<DEOBJ_ConfigurationNode> aHolder;
(void)aHolder;
}
} // namespace
//=================================================================================================
void XSDRAWOBJ::Factory(Draw_Interpretor& theDI)
@@ -358,9 +346,6 @@ void XSDRAWOBJ::Factory(Draw_Interpretor& theDI)
}
aIsActivated = Standard_True;
//! Ensure DEOBJ plugin is registered
DEOBJSingleton();
const char* aGroup = "XSTEP-STL/VRML"; // Step transfer file commands
theDI.Add(
"ReadObj",

View File

@@ -18,8 +18,6 @@
#include <DBRep.hxx>
#include <DDocStd.hxx>
#include <DDocStd_DrawDocument.hxx>
#include <DEPLY_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#include <Draw.hxx>
#include <Draw_Interpretor.hxx>
#include <Draw_PluginMacro.hxx>
@@ -297,16 +295,6 @@ static Standard_Integer WritePly(Draw_Interpretor& theDI,
return 0;
}
namespace
{
// Singleton to ensure DEPLY plugin is registered only once
void DEPLYSingleton()
{
static DE_PluginHolder<DEPLY_ConfigurationNode> aHolder;
(void)aHolder;
}
} // namespace
//=================================================================================================
void XSDRAWPLY::Factory(Draw_Interpretor& theDI)
@@ -318,9 +306,6 @@ void XSDRAWPLY::Factory(Draw_Interpretor& theDI)
}
aIsActivated = Standard_True;
//! Ensure DEPLY plugin is registered
DEPLYSingleton();
const char* aGroup = "XSTEP-STL/VRML"; // Step transfer file commands
// XSDRAW::LoadDraw(theCommands);
theDI.Add("WritePly",

View File

@@ -17,8 +17,6 @@
#include <DDF.hxx>
#include <DDocStd.hxx>
#include <DDocStd_DrawDocument.hxx>
#include <DESTEP_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#include <Draw.hxx>
#include <Draw_Interpretor.hxx>
#include <Draw_PluginMacro.hxx>
@@ -1094,16 +1092,6 @@ static Standard_Integer WriteStep(Draw_Interpretor& theDI,
return 0;
}
namespace
{
// Singleton to ensure DESTEP plugin is registered only once
void DESTEPSingleton()
{
static DE_PluginHolder<DESTEP_ConfigurationNode> aHolder;
(void)aHolder;
}
} // namespace
//=================================================================================================
void XSDRAWSTEP::Factory(Draw_Interpretor& theDI)
@@ -1116,9 +1104,6 @@ void XSDRAWSTEP::Factory(Draw_Interpretor& theDI)
STEPCAFControl_Controller::Init();
aIsActivated = Standard_True;
//! Ensure DESTEP plugin is registered
DESTEPSingleton();
const char* aGroup = "DE: STEP"; // Step transfer file commands
theDI.Add("stepwrite", "stepwrite mode[0-4 afsmw] shape", __FILE__, stepwrite, aGroup);
theDI.Add("testwritestep",

View File

@@ -18,8 +18,6 @@
#include <DBRep.hxx>
#include <DDocStd.hxx>
#include <DDocStd_DrawDocument.hxx>
#include <DESTL_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#include <Draw.hxx>
#include <Draw_Interpretor.hxx>
#include <Draw_PluginMacro.hxx>
@@ -1235,16 +1233,6 @@ static Standard_Integer meshinfo(Draw_Interpretor& theDI,
return 0;
}
namespace
{
// Singleton to ensure DESTL plugin is registered only once
void DESTLSingleton()
{
static DE_PluginHolder<DESTL_ConfigurationNode> aHolder;
(void)aHolder;
}
} // namespace
//=================================================================================================
void XSDRAWSTL::Factory(Draw_Interpretor& theDI)
@@ -1256,9 +1244,6 @@ void XSDRAWSTL::Factory(Draw_Interpretor& theDI)
}
aIsActivated = Standard_True;
//! Ensure DESTL plugin is registered
DESTLSingleton();
const char* aGroup = "XSTEP-STL/VRML"; // Step transfer file commands
theDI.Add("writestl",

View File

@@ -16,8 +16,6 @@
#include <DBRep.hxx>
#include <DDocStd.hxx>
#include <DDocStd_DrawDocument.hxx>
#include <DEVRML_ConfigurationNode.hxx>
#include <DE_PluginHolder.hxx>
#include <Draw.hxx>
#include <Draw_Interpretor.hxx>
#include <Draw_PluginMacro.hxx>
@@ -410,16 +408,6 @@ static Standard_Integer writevrml(Draw_Interpretor& di, Standard_Integer argc, c
return 0;
}
namespace
{
// Singleton to ensure DEVRML plugin is registered only once
void DEVRMLSingleton()
{
static DE_PluginHolder<DEVRML_ConfigurationNode> aHolder;
(void)aHolder;
}
} // namespace
//=================================================================================================
void XSDRAWVRML::Factory(Draw_Interpretor& theDI)
@@ -431,9 +419,6 @@ void XSDRAWVRML::Factory(Draw_Interpretor& theDI)
}
anInitActor = Standard_True;
//! Ensure DEVRML plugin is registered
DEVRMLSingleton();
Standard_CString aGroup = "XDE translation commands";
theDI.Add(
"ReadVrml",

View File

@@ -34,8 +34,4 @@ set(OCCT_TKMath_GTests_FILES
math_TrigonometricFunctionRoots_Test.cxx
math_Uzawa_Test.cxx
math_Vector_Test.cxx
PLib_Test.cxx
PLib_JacobiPolynomial_Test.cxx
PLib_HermitJacobi_Test.cxx
PLib_DoubleJacobiPolynomial_Test.cxx
)

View File

@@ -1,402 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <PLib_DoubleJacobiPolynomial.hxx>
#include <PLib_JacobiPolynomial.hxx>
#include <gtest/gtest.h>
#include <Standard_Real.hxx>
#include <Standard_Integer.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_HArray1OfReal.hxx>
#include <GeomAbs_Shape.hxx>
#include <Precision.hxx>
// Test fixture for PLib_DoubleJacobiPolynomial tests
class PLibDoubleJacobiPolynomialTest : public ::testing::Test
{
protected:
void SetUp() override
{
// Create Jacobi polynomials for testing
myJacobiU = new PLib_JacobiPolynomial(10, GeomAbs_C0);
myJacobiV = new PLib_JacobiPolynomial(8, GeomAbs_C1);
}
void TearDown() override
{
myJacobiU.Nullify();
myJacobiV.Nullify();
}
Handle(PLib_JacobiPolynomial) myJacobiU;
Handle(PLib_JacobiPolynomial) myJacobiV;
// Helper to create test coefficients
void createTestCoefficients(TColStd_Array1OfReal& theCoeffs,
Standard_Integer theDimension,
Standard_Integer theDegreeU,
Standard_Integer theDegreeV)
{
Standard_Integer anIndex = theCoeffs.Lower(); // Start from array lower bound
for (Standard_Integer j = 0; j <= theDegreeV; j++)
{
for (Standard_Integer i = 0; i <= theDegreeU; i++)
{
for (Standard_Integer d = 1; d <= theDimension; d++)
{
theCoeffs(anIndex) = Sin(anIndex * 0.1 + i * 0.2 + j * 0.3);
anIndex++;
}
}
}
}
};
// Test default constructor
TEST_F(PLibDoubleJacobiPolynomialTest, DefaultConstructor)
{
PLib_DoubleJacobiPolynomial aDoubleJac;
// After default construction, accessors should return null handles
EXPECT_TRUE(aDoubleJac.U().IsNull()) << "U polynomial should be null after default construction";
EXPECT_TRUE(aDoubleJac.V().IsNull()) << "V polynomial should be null after default construction";
EXPECT_TRUE(aDoubleJac.TabMaxU().IsNull()) << "TabMaxU should be null after default construction";
EXPECT_TRUE(aDoubleJac.TabMaxV().IsNull()) << "TabMaxV should be null after default construction";
}
// Test parameterized constructor
TEST_F(PLibDoubleJacobiPolynomialTest, ParameterizedConstructor)
{
ASSERT_FALSE(myJacobiU.IsNull()) << "JacobiU should not be null";
ASSERT_FALSE(myJacobiV.IsNull()) << "JacobiV should not be null";
PLib_DoubleJacobiPolynomial aDoubleJac(myJacobiU, myJacobiV);
// After construction with parameters, accessors should return valid handles
EXPECT_FALSE(aDoubleJac.U().IsNull()) << "U polynomial should not be null";
EXPECT_FALSE(aDoubleJac.V().IsNull()) << "V polynomial should not be null";
EXPECT_FALSE(aDoubleJac.TabMaxU().IsNull()) << "TabMaxU should not be null";
EXPECT_FALSE(aDoubleJac.TabMaxV().IsNull()) << "TabMaxV should not be null";
// Test that the returned handles are correct
EXPECT_EQ(aDoubleJac.U().get(), myJacobiU.get()) << "U polynomial handle should match";
EXPECT_EQ(aDoubleJac.V().get(), myJacobiV.get()) << "V polynomial handle should match";
}
// Test MaxErrorU calculation
TEST_F(PLibDoubleJacobiPolynomialTest, MaxErrorU)
{
PLib_DoubleJacobiPolynomial aDoubleJac(myJacobiU, myJacobiV);
const Standard_Integer aDimension = 2;
const Standard_Integer aDegreeU = 6;
const Standard_Integer aDegreeV = 5;
const Standard_Integer aDJacCoeff = (aDegreeU + 1) * aDimension;
// JacCoeff array must be sized based on WorkDegrees
const Standard_Integer aWorkDegreeU = myJacobiU->WorkDegree();
const Standard_Integer aWorkDegreeV = myJacobiV->WorkDegree();
const Standard_Integer aCoeffCount = (aWorkDegreeU + 1) * (aWorkDegreeV + 1) * aDimension;
TColStd_Array1OfReal aJacCoeff(0, aCoeffCount - 1);
for (Standard_Integer i = aJacCoeff.Lower(); i <= aJacCoeff.Upper(); i++)
{
aJacCoeff(i) = Sin(i * 0.1);
}
EXPECT_NO_THROW({
Standard_Real aMaxErrU =
aDoubleJac.MaxErrorU(aDimension, aDegreeU, aDegreeV, aDJacCoeff, aJacCoeff);
EXPECT_GE(aMaxErrU, 0.0) << "MaxErrorU should be non-negative";
EXPECT_FALSE(Precision::IsInfinite(aMaxErrU)) << "MaxErrorU should be finite";
}) << "MaxErrorU calculation failed";
}
// Test MaxErrorV calculation
TEST_F(PLibDoubleJacobiPolynomialTest, MaxErrorV)
{
PLib_DoubleJacobiPolynomial aDoubleJac(myJacobiU, myJacobiV);
const Standard_Integer aDimension = 2;
const Standard_Integer aDegreeU = 6;
const Standard_Integer aDegreeV = 5;
const Standard_Integer aDJacCoeff = (aDegreeU + 1) * aDimension;
// JacCoeff array must be sized based on WorkDegrees
const Standard_Integer aWorkDegreeU = myJacobiU->WorkDegree();
const Standard_Integer aWorkDegreeV = myJacobiV->WorkDegree();
const Standard_Integer aCoeffCount = (aWorkDegreeU + 1) * (aWorkDegreeV + 1) * aDimension;
TColStd_Array1OfReal aJacCoeff(0, aCoeffCount - 1);
for (Standard_Integer i = aJacCoeff.Lower(); i <= aJacCoeff.Upper(); i++)
{
aJacCoeff(i) = Sin(i * 0.1);
}
EXPECT_NO_THROW({
Standard_Real aMaxErrV =
aDoubleJac.MaxErrorV(aDimension, aDegreeU, aDegreeV, aDJacCoeff, aJacCoeff);
EXPECT_GE(aMaxErrV, 0.0) << "MaxErrorV should be non-negative";
EXPECT_FALSE(Precision::IsInfinite(aMaxErrV)) << "MaxErrorV should be finite";
}) << "MaxErrorV calculation failed";
}
// Test general MaxError calculation
TEST_F(PLibDoubleJacobiPolynomialTest, MaxError)
{
PLib_DoubleJacobiPolynomial aDoubleJac(myJacobiU, myJacobiV);
const Standard_Integer aDimension = 1;
const Standard_Integer aMinDegreeU = 2, aMaxDegreeU = 5;
const Standard_Integer aMinDegreeV = 4, aMaxDegreeV = 7; // MinDegreeV must be >= MinV=4
const Standard_Integer aDJacCoeff = (aMaxDegreeU + 1) * aDimension;
const Standard_Real anError = 1e-6;
// JacCoeff array must be sized based on WorkDegrees
const Standard_Integer aWorkDegreeU = myJacobiU->WorkDegree();
const Standard_Integer aWorkDegreeV = myJacobiV->WorkDegree();
const Standard_Integer aCoeffCount = (aWorkDegreeU + 1) * (aWorkDegreeV + 1) * aDimension;
TColStd_Array1OfReal aJacCoeff(0, aCoeffCount - 1);
for (Standard_Integer i = aJacCoeff.Lower(); i <= aJacCoeff.Upper(); i++)
{
aJacCoeff(i) = Sin(i * 0.1);
}
EXPECT_NO_THROW({
Standard_Real aMaxErr = aDoubleJac.MaxError(aDimension,
aMinDegreeU,
aMaxDegreeU,
aMinDegreeV,
aMaxDegreeV,
aDJacCoeff,
aJacCoeff,
anError);
EXPECT_GE(aMaxErr, 0.0) << "MaxError should be non-negative";
EXPECT_FALSE(Precision::IsInfinite(aMaxErr)) << "MaxError should be finite";
}) << "MaxError calculation failed";
}
// Test degree reduction
TEST_F(PLibDoubleJacobiPolynomialTest, ReduceDegree)
{
PLib_DoubleJacobiPolynomial aDoubleJac(myJacobiU, myJacobiV);
const Standard_Integer aDimension = 1;
const Standard_Integer aMinDegreeU = 2, aMaxDegreeU = 6; // Must be >= MinU=2
const Standard_Integer aMinDegreeV = 4, aMaxDegreeV = 7; // Must be >= MinV=4
const Standard_Integer aDJacCoeff = (aMaxDegreeU + 1) * aDimension;
const Standard_Real anEpmsCut = 1e-8;
// JacCoeff array must be sized based on WorkDegrees and use 0-based indexing
const Standard_Integer aWorkDegreeU = myJacobiU->WorkDegree();
const Standard_Integer aWorkDegreeV = myJacobiV->WorkDegree();
const Standard_Integer aCoeffCount = (aWorkDegreeU + 1) * (aWorkDegreeV + 1) * aDimension;
TColStd_Array1OfReal aJacCoeff(0, aCoeffCount - 1);
for (Standard_Integer i = aJacCoeff.Lower(); i <= aJacCoeff.Upper(); i++)
{
aJacCoeff(i) = 1.0 / (i + 10); // Small decreasing values
}
Standard_Real aMaxError = -1.0;
Standard_Integer aNewDegreeU = -1, aNewDegreeV = -1;
EXPECT_NO_THROW({
aDoubleJac.ReduceDegree(aDimension,
aMinDegreeU,
aMaxDegreeU,
aMinDegreeV,
aMaxDegreeV,
aDJacCoeff,
aJacCoeff,
anEpmsCut,
aMaxError,
aNewDegreeU,
aNewDegreeV);
}) << "ReduceDegree failed";
// Verify results are reasonable
EXPECT_LE(aNewDegreeU, aMaxDegreeU) << "New U degree should not exceed max";
EXPECT_GE(aNewDegreeU, aMinDegreeU) << "New U degree should be at least min";
EXPECT_LE(aNewDegreeV, aMaxDegreeV) << "New V degree should not exceed max";
EXPECT_GE(aNewDegreeV, aMinDegreeV) << "New V degree should be at least min";
EXPECT_GE(aMaxError, 0.0) << "Max error should be non-negative";
EXPECT_FALSE(Precision::IsInfinite(aMaxError)) << "Max error should be finite";
}
// Test average error calculation
TEST_F(PLibDoubleJacobiPolynomialTest, AverageError)
{
PLib_DoubleJacobiPolynomial aDoubleJac(myJacobiU, myJacobiV);
const Standard_Integer aDimension = 2;
const Standard_Integer aDegreeU = 4;
const Standard_Integer aDegreeV = 3;
const Standard_Integer aDJacCoeff = 0; // For 0-based arrays, start offset should be 0
// JacCoeff array must be sized based on WorkDegrees and use 0-based indexing
const Standard_Integer aWorkDegreeU = myJacobiU->WorkDegree();
const Standard_Integer aWorkDegreeV = myJacobiV->WorkDegree();
const Standard_Integer aCoeffCount = (aWorkDegreeU + 1) * (aWorkDegreeV + 1) * aDimension;
TColStd_Array1OfReal aJacCoeff(0, aCoeffCount - 1);
for (Standard_Integer i = aJacCoeff.Lower(); i <= aJacCoeff.Upper(); i++)
{
aJacCoeff(i) = Sin(i * 0.1);
}
EXPECT_NO_THROW({
Standard_Real aAvgErr =
aDoubleJac.AverageError(aDimension, aDegreeU, aDegreeV, aDJacCoeff, aJacCoeff);
EXPECT_GE(aAvgErr, 0.0) << "Average error should be non-negative";
EXPECT_FALSE(Precision::IsInfinite(aAvgErr)) << "Average error should be finite";
}) << "AverageError calculation failed";
}
// Test coefficient conversion to canonical base
TEST_F(PLibDoubleJacobiPolynomialTest, CoefficientConversion)
{
PLib_DoubleJacobiPolynomial aDoubleJac(myJacobiU, myJacobiV);
const Standard_Integer aDimension = 3;
const Standard_Integer aDegreeU = 3;
const Standard_Integer aDegreeV = 2;
// JacCoeff array must be sized based on WorkDegrees, not input degrees
const Standard_Integer aWorkDegreeU = myJacobiU->WorkDegree();
const Standard_Integer aWorkDegreeV = myJacobiV->WorkDegree();
const Standard_Integer aJacCoeffSize = (aWorkDegreeU + 1) * (aWorkDegreeV + 1) * aDimension;
// JacCoeff uses 0-based indexing as per the implementation
TColStd_Array1OfReal aJacCoeff(0, aJacCoeffSize - 1);
// Initialize with test data - use simple pattern for valid coefficients
for (Standard_Integer i = aJacCoeff.Lower(); i <= aJacCoeff.Upper(); i++)
{
aJacCoeff(i) = Sin(i * 0.1);
}
// Output coefficients array is sized based on actual degrees
const Standard_Integer aCoeffCount = (aDegreeU + 1) * (aDegreeV + 1) * aDimension;
TColStd_Array1OfReal aCoefficients(0, aCoeffCount - 1);
EXPECT_NO_THROW({
aDoubleJac.WDoubleJacobiToCoefficients(aDimension,
aDegreeU,
aDegreeV,
aJacCoeff,
aCoefficients);
}) << "Coefficient conversion failed";
// Verify output coefficients are finite
for (Standard_Integer i = aCoefficients.Lower(); i <= aCoefficients.Upper(); i++)
{
EXPECT_FALSE(Precision::IsInfinite(aCoefficients(i)))
<< "Converted coefficient should be finite at index " << i;
}
}
// Test with mismatched degrees
TEST_F(PLibDoubleJacobiPolynomialTest, MismatchedDegrees)
{
Handle(PLib_JacobiPolynomial) aJacU_Low = new PLib_JacobiPolynomial(5, GeomAbs_C0);
Handle(PLib_JacobiPolynomial) aJacV_High = new PLib_JacobiPolynomial(20, GeomAbs_C1);
EXPECT_NO_THROW({
PLib_DoubleJacobiPolynomial aDoubleJac(aJacU_Low, aJacV_High);
// Should handle mismatched degrees gracefully
EXPECT_FALSE(aDoubleJac.U().IsNull());
EXPECT_FALSE(aDoubleJac.V().IsNull());
}) << "Constructor should handle mismatched degrees";
}
// Test accessor consistency
TEST_F(PLibDoubleJacobiPolynomialTest, AccessorConsistency)
{
PLib_DoubleJacobiPolynomial aDoubleJac(myJacobiU, myJacobiV);
// Test that accessors return consistent results
Handle(PLib_JacobiPolynomial) aReturnedU = aDoubleJac.U();
Handle(PLib_JacobiPolynomial) aReturnedV = aDoubleJac.V();
Handle(TColStd_HArray1OfReal) aTabMaxU = aDoubleJac.TabMaxU();
Handle(TColStd_HArray1OfReal) aTabMaxV = aDoubleJac.TabMaxV();
// Multiple calls should return same handles
EXPECT_EQ(aReturnedU.get(), aDoubleJac.U().get()) << "U accessor should be consistent";
EXPECT_EQ(aReturnedV.get(), aDoubleJac.V().get()) << "V accessor should be consistent";
EXPECT_EQ(aTabMaxU.get(), aDoubleJac.TabMaxU().get()) << "TabMaxU accessor should be consistent";
EXPECT_EQ(aTabMaxV.get(), aDoubleJac.TabMaxV().get()) << "TabMaxV accessor should be consistent";
// Verify TabMax arrays are properly sized and contain valid data
if (!aTabMaxU.IsNull())
{
const TColStd_Array1OfReal& anArrU = aTabMaxU->Array1();
for (Standard_Integer i = anArrU.Lower(); i <= anArrU.Upper(); i++)
{
EXPECT_GT(anArrU(i), 0.0) << "TabMaxU values should be positive";
EXPECT_FALSE(Precision::IsInfinite(anArrU(i))) << "TabMaxU values should be finite";
}
}
if (!aTabMaxV.IsNull())
{
const TColStd_Array1OfReal& anArrV = aTabMaxV->Array1();
for (Standard_Integer i = anArrV.Lower(); i <= anArrV.Upper(); i++)
{
EXPECT_GT(anArrV(i), 0.0) << "TabMaxV values should be positive";
EXPECT_FALSE(Precision::IsInfinite(anArrV(i))) << "TabMaxV values should be finite";
}
}
}
// Stress test with large degrees
TEST_F(PLibDoubleJacobiPolynomialTest, StressTest)
{
Handle(PLib_JacobiPolynomial) aJacU_Large = new PLib_JacobiPolynomial(25, GeomAbs_C1);
Handle(PLib_JacobiPolynomial) aJacV_Large = new PLib_JacobiPolynomial(20, GeomAbs_C2);
EXPECT_NO_THROW({
PLib_DoubleJacobiPolynomial aDoubleJac(aJacU_Large, aJacV_Large);
// Test basic operations don't crash with large degrees
const Standard_Integer aDimension = 1;
const Standard_Integer aDegreeU = 15;
const Standard_Integer aDegreeV = 12;
// Array must be sized based on WorkDegrees for proper method operation
const Standard_Integer aWorkDegreeU = aJacU_Large->WorkDegree();
const Standard_Integer aWorkDegreeV = aJacV_Large->WorkDegree();
const Standard_Integer aCoeffCount = (aWorkDegreeU + 1) * (aWorkDegreeV + 1) * aDimension;
const Standard_Integer aDJacCoeff = 0; // For 0-based arrays
TColStd_Array1OfReal aJacCoeff(0, aCoeffCount - 1);
for (Standard_Integer i = aJacCoeff.Lower(); i <= aJacCoeff.Upper(); i++)
{
aJacCoeff(i) = Sin(i * 0.1);
}
Standard_Real aMaxErrU =
aDoubleJac.MaxErrorU(aDimension, aDegreeU, aDegreeV, aDJacCoeff, aJacCoeff);
Standard_Real aMaxErrV =
aDoubleJac.MaxErrorV(aDimension, aDegreeU, aDegreeV, aDJacCoeff, aJacCoeff);
Standard_Real aAvgErr =
aDoubleJac.AverageError(aDimension, aDegreeU, aDegreeV, aDJacCoeff, aJacCoeff);
EXPECT_GE(aMaxErrU, 0.0) << "MaxErrorU should be non-negative";
EXPECT_GE(aMaxErrV, 0.0) << "MaxErrorV should be non-negative";
EXPECT_GE(aAvgErr, 0.0) << "AverageError should be non-negative";
}) << "Large degree operations should complete without crashing";
}

View File

@@ -1,310 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <PLib_HermitJacobi.hxx>
#include <PLib_JacobiPolynomial.hxx>
#include <gtest/gtest.h>
#include <Standard_Real.hxx>
#include <Standard_Integer.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <GeomAbs_Shape.hxx>
#include <Precision.hxx>
// Test fixture for PLib_HermitJacobi tests
class PLibHermitJacobiTest : public ::testing::Test
{
protected:
void SetUp() override
{
// Common test setup
}
void TearDown() override
{
// Cleanup
}
// Helper to create valid HermitJacobi polynomial instances
Handle(PLib_HermitJacobi) createHermitJacobi(Standard_Integer theDegree,
GeomAbs_Shape theConstraint)
{
// Ensure degree is within valid range
EXPECT_LE(theDegree, 30) << "Degree too high for HermitJacobi polynomial";
EXPECT_GE(theDegree, 0) << "Degree must be non-negative";
return new PLib_HermitJacobi(theDegree, theConstraint);
}
};
// Test constructor and basic properties
TEST_F(PLibHermitJacobiTest, ConstructorAndBasicProperties)
{
// Test with different constraint orders
Handle(PLib_HermitJacobi) aHermC0 = createHermitJacobi(10, GeomAbs_C0);
Handle(PLib_HermitJacobi) aHermC1 = createHermitJacobi(15, GeomAbs_C1);
Handle(PLib_HermitJacobi) aHermC2 = createHermitJacobi(20, GeomAbs_C2);
ASSERT_FALSE(aHermC0.IsNull()) << "Failed to create C0 HermitJacobi polynomial";
ASSERT_FALSE(aHermC1.IsNull()) << "Failed to create C1 HermitJacobi polynomial";
ASSERT_FALSE(aHermC2.IsNull()) << "Failed to create C2 HermitJacobi polynomial";
// Test WorkDegree property
EXPECT_EQ(aHermC0->WorkDegree(), 10);
EXPECT_EQ(aHermC1->WorkDegree(), 15);
EXPECT_EQ(aHermC2->WorkDegree(), 20);
// Test NivConstr property
EXPECT_EQ(aHermC0->NivConstr(), 0);
EXPECT_EQ(aHermC1->NivConstr(), 1);
EXPECT_EQ(aHermC2->NivConstr(), 2);
}
// Test basis function evaluation D0
TEST_F(PLibHermitJacobiTest, BasisFunctionD0)
{
Handle(PLib_HermitJacobi) aHerm = createHermitJacobi(6, GeomAbs_C0);
TColStd_Array1OfReal aBasisValue(0, aHerm->WorkDegree());
// Test at various parameter values
std::vector<Standard_Real> aTestParams = {-1.0, -0.5, 0.0, 0.5, 1.0};
for (Standard_Real aU : aTestParams)
{
EXPECT_NO_THROW({ aHerm->D0(aU, aBasisValue); }) << "D0 evaluation failed at U=" << aU;
// Basic sanity checks
for (Standard_Integer i = aBasisValue.Lower(); i <= aBasisValue.Upper(); i++)
{
EXPECT_FALSE(Precision::IsInfinite(aBasisValue(i)))
<< "Basis value should be finite at index " << i << ", U=" << aU;
}
}
}
// Test basis function evaluation with derivatives
TEST_F(PLibHermitJacobiTest, BasisFunctionDerivatives)
{
Handle(PLib_HermitJacobi) aHerm = createHermitJacobi(8, GeomAbs_C1);
TColStd_Array1OfReal aBasisValue(0, aHerm->WorkDegree());
TColStd_Array1OfReal aBasisD1(0, aHerm->WorkDegree());
TColStd_Array1OfReal aBasisD2(0, aHerm->WorkDegree());
TColStd_Array1OfReal aBasisD3(0, aHerm->WorkDegree());
Standard_Real aU = 0.5; // Test at middle point
// Test D1
EXPECT_NO_THROW({ aHerm->D1(aU, aBasisValue, aBasisD1); }) << "D1 evaluation failed";
// Test D2
EXPECT_NO_THROW({ aHerm->D2(aU, aBasisValue, aBasisD1, aBasisD2); }) << "D2 evaluation failed";
// Test D3
EXPECT_NO_THROW({ aHerm->D3(aU, aBasisValue, aBasisD1, aBasisD2, aBasisD3); })
<< "D3 evaluation failed";
// Verify all values are finite
for (Standard_Integer i = aBasisValue.Lower(); i <= aBasisValue.Upper(); i++)
{
EXPECT_FALSE(Precision::IsInfinite(aBasisValue(i))) << "Basis value should be finite at " << i;
EXPECT_FALSE(Precision::IsInfinite(aBasisD1(i)))
<< "First derivative should be finite at " << i;
EXPECT_FALSE(Precision::IsInfinite(aBasisD2(i)))
<< "Second derivative should be finite at " << i;
EXPECT_FALSE(Precision::IsInfinite(aBasisD3(i)))
<< "Third derivative should be finite at " << i;
}
}
// Test coefficient conversion
TEST_F(PLibHermitJacobiTest, CoefficientConversion)
{
const Standard_Integer aWorkDegree = 6; // Use smaller degree that works well with ToCoefficients
Handle(PLib_HermitJacobi) aHerm = createHermitJacobi(aWorkDegree, GeomAbs_C0);
const Standard_Integer aDimension = 1;
const Standard_Integer aDegree =
aHerm->WorkDegree() - 2 * (aHerm->NivConstr() + 1); // Use computational degree
// Create test HermitJacobi coefficients with proper size
// ToCoefficients expects arrays sized based on the degree and dimension
Standard_Integer aHermJacSize = (aDegree + 1) * aDimension;
Standard_Integer aCoeffSize = (aDegree + 1) * aDimension;
// Use 0-based arrays to match the ToCoefficients indexing expectations
TColStd_Array1OfReal aHermJacCoeff(0, aHermJacSize - 1);
for (Standard_Integer i = aHermJacCoeff.Lower(); i <= aHermJacCoeff.Upper(); i++)
{
aHermJacCoeff(i) = Sin(i * 0.3); // Some test values
}
TColStd_Array1OfReal aCoefficients(0, aCoeffSize - 1);
EXPECT_NO_THROW({ aHerm->ToCoefficients(aDimension, aDegree, aHermJacCoeff, aCoefficients); })
<< "Coefficient conversion failed";
// Verify output is finite
for (Standard_Integer i = aCoefficients.Lower(); i <= aCoefficients.Upper(); i++)
{
EXPECT_FALSE(Precision::IsInfinite(aCoefficients(i)))
<< "Converted coefficient should be finite at index " << i;
}
}
// Test degree reduction
TEST_F(PLibHermitJacobiTest, DegreeReduction)
{
Handle(PLib_HermitJacobi) aHerm = createHermitJacobi(10, GeomAbs_C0);
const Standard_Integer aDimension = 1;
const Standard_Integer aMaxDegree = 8;
const Standard_Real aTol = 1e-6;
// Create test coefficients - must be sized for full WorkDegree
const Standard_Integer aWorkDegree = aHerm->WorkDegree();
TColStd_Array1OfReal aCoeff(1, (aWorkDegree + 1) * aDimension);
for (Standard_Integer i = aCoeff.Lower(); i <= aCoeff.Upper(); i++)
{
aCoeff(i) = 1.0 / (i + 1); // Decreasing coefficients to allow reduction
}
Standard_Integer aNewDegree = -1;
Standard_Real aMaxError = -1.0;
EXPECT_NO_THROW({
aHerm->ReduceDegree(aDimension, aMaxDegree, aTol, aCoeff.ChangeValue(1), aNewDegree, aMaxError);
}) << "Degree reduction failed";
// Verify results are reasonable
EXPECT_LE(aNewDegree, aMaxDegree) << "New degree should not exceed max degree";
EXPECT_GE(aNewDegree, 0) << "New degree should be non-negative";
EXPECT_GE(aMaxError, 0.0) << "Max error should be non-negative";
EXPECT_FALSE(Precision::IsInfinite(aMaxError)) << "Max error should be finite";
}
// Test error estimation
TEST_F(PLibHermitJacobiTest, ErrorEstimation)
{
Handle(PLib_HermitJacobi) aHerm = createHermitJacobi(8, GeomAbs_C1);
const Standard_Integer aDimension = 1;
// Create test coefficients
TColStd_Array1OfReal aCoeff(1, 10 * aDimension);
for (Standard_Integer i = aCoeff.Lower(); i <= aCoeff.Upper(); i++)
{
aCoeff(i) = 1.0 / (i + 1);
}
Standard_Integer aNewDegree = 6; // Reduced from original
// Test MaxError
Standard_Real aMaxErr = -1.0;
EXPECT_NO_THROW({ aMaxErr = aHerm->MaxError(aDimension, aCoeff.ChangeValue(1), aNewDegree); })
<< "MaxError calculation failed";
EXPECT_GE(aMaxErr, 0.0) << "Max error should be non-negative";
EXPECT_FALSE(Precision::IsInfinite(aMaxErr)) << "Max error should be finite";
// Test AverageError
Standard_Real aAvgErr = -1.0;
EXPECT_NO_THROW({ aAvgErr = aHerm->AverageError(aDimension, aCoeff.ChangeValue(1), aNewDegree); })
<< "AverageError calculation failed";
EXPECT_GE(aAvgErr, 0.0) << "Average error should be non-negative";
EXPECT_FALSE(Precision::IsInfinite(aAvgErr)) << "Average error should be finite";
// Average error should typically be <= max error
EXPECT_LE(aAvgErr, aMaxErr + Precision::Confusion())
<< "Average error should not exceed max error significantly";
}
// Test extreme parameter values
TEST_F(PLibHermitJacobiTest, ExtremeParameterValues)
{
Handle(PLib_HermitJacobi) aHerm = createHermitJacobi(10, GeomAbs_C2);
TColStd_Array1OfReal aBasisValue(0, aHerm->WorkDegree());
// Test with boundary values
std::vector<Standard_Real> aExtremeParams = {-0.99999, -1e-12, 1e-12, 0.99999};
for (Standard_Real aU : aExtremeParams)
{
EXPECT_NO_THROW({ aHerm->D0(aU, aBasisValue); })
<< "Extreme parameter U=" << aU << " should not crash";
// Check that results are finite
for (Standard_Integer i = aBasisValue.Lower(); i <= aBasisValue.Upper(); i++)
{
EXPECT_FALSE(Precision::IsInfinite(aBasisValue(i)))
<< "Basis value should be finite at extreme parameter U=" << aU;
}
}
}
// Test consistency between different derivative orders
TEST_F(PLibHermitJacobiTest, DerivativeConsistency)
{
Handle(PLib_HermitJacobi) aHerm = createHermitJacobi(6, GeomAbs_C2);
TColStd_Array1OfReal aBasisValue1(0, aHerm->WorkDegree());
TColStd_Array1OfReal aBasisD1_1(0, aHerm->WorkDegree());
TColStd_Array1OfReal aBasisValue2(0, aHerm->WorkDegree());
TColStd_Array1OfReal aBasisD1_2(0, aHerm->WorkDegree());
TColStd_Array1OfReal aBasisD2_2(0, aHerm->WorkDegree());
Standard_Real aU = 0.3;
// Get values from D1 and D2 calls
aHerm->D1(aU, aBasisValue1, aBasisD1_1);
aHerm->D2(aU, aBasisValue2, aBasisD1_2, aBasisD2_2);
// Values and first derivatives should be consistent
for (Standard_Integer i = aBasisValue1.Lower(); i <= aBasisValue1.Upper(); i++)
{
EXPECT_NEAR(aBasisValue1(i), aBasisValue2(i), Precision::Confusion())
<< "Function values should be consistent between D1 and D2 calls at index " << i;
EXPECT_NEAR(aBasisD1_1(i), aBasisD1_2(i), Precision::Confusion())
<< "First derivatives should be consistent between D1 and D2 calls at index " << i;
}
}
// Performance test with maximum degree
TEST_F(PLibHermitJacobiTest, PerformanceTest)
{
Handle(PLib_HermitJacobi) aHermMax = createHermitJacobi(30, GeomAbs_C2);
TColStd_Array1OfReal aBasisValue(0, aHermMax->WorkDegree());
TColStd_Array1OfReal aBasisD1(0, aHermMax->WorkDegree());
TColStd_Array1OfReal aBasisD2(0, aHermMax->WorkDegree());
TColStd_Array1OfReal aBasisD3(0, aHermMax->WorkDegree());
// Test that operations complete in reasonable time
std::vector<Standard_Real> aTestParams = {-0.8, -0.5, 0.0, 0.5, 0.8};
for (Standard_Real aU : aTestParams)
{
EXPECT_NO_THROW({
aHermMax->D0(aU, aBasisValue);
aHermMax->D1(aU, aBasisValue, aBasisD1);
aHermMax->D2(aU, aBasisValue, aBasisD1, aBasisD2);
aHermMax->D3(aU, aBasisValue, aBasisD1, aBasisD2, aBasisD3);
}) << "High degree operations should complete without crashing at U="
<< aU;
}
}

View File

@@ -1,366 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <PLib_JacobiPolynomial.hxx>
#include <gtest/gtest.h>
#include <Standard_Real.hxx>
#include <Standard_Integer.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array2OfReal.hxx>
#include <GeomAbs_Shape.hxx>
#include <Precision.hxx>
namespace
{
} // namespace
// Test fixture for PLib_JacobiPolynomial tests
class PLibJacobiPolynomialTest : public ::testing::Test
{
protected:
void SetUp() override
{
// Common test setup
}
void TearDown() override
{
// Cleanup
}
// Helper to create valid Jacobi polynomial instances
Handle(PLib_JacobiPolynomial) createJacobiPolynomial(Standard_Integer theDegree,
GeomAbs_Shape theConstraint)
{
// Ensure degree is within valid range (typically <= 30)
EXPECT_LE(theDegree, 30) << "Degree too high for Jacobi polynomial";
EXPECT_GE(theDegree, 0) << "Degree must be non-negative";
return new PLib_JacobiPolynomial(theDegree, theConstraint);
}
};
// Test constructor and basic properties
TEST_F(PLibJacobiPolynomialTest, ConstructorAndBasicProperties)
{
// Test with different constraint orders
Handle(PLib_JacobiPolynomial) aJacC0 = createJacobiPolynomial(10, GeomAbs_C0);
Handle(PLib_JacobiPolynomial) aJacC1 = createJacobiPolynomial(15, GeomAbs_C1);
Handle(PLib_JacobiPolynomial) aJacC2 = createJacobiPolynomial(20, GeomAbs_C2);
ASSERT_FALSE(aJacC0.IsNull()) << "Failed to create C0 Jacobi polynomial";
ASSERT_FALSE(aJacC1.IsNull()) << "Failed to create C1 Jacobi polynomial";
ASSERT_FALSE(aJacC2.IsNull()) << "Failed to create C2 Jacobi polynomial";
// Test WorkDegree property
EXPECT_EQ(aJacC0->WorkDegree(), 10);
EXPECT_EQ(aJacC1->WorkDegree(), 15);
EXPECT_EQ(aJacC2->WorkDegree(), 20);
// Test NivConstr property
EXPECT_EQ(aJacC0->NivConstr(), 0);
EXPECT_EQ(aJacC1->NivConstr(), 1);
EXPECT_EQ(aJacC2->NivConstr(), 2);
}
// Test constructor with edge cases
TEST_F(PLibJacobiPolynomialTest, ConstructorEdgeCases)
{
// Test minimum degree
Handle(PLib_JacobiPolynomial) aJacMin = createJacobiPolynomial(0, GeomAbs_C0);
EXPECT_FALSE(aJacMin.IsNull());
EXPECT_EQ(aJacMin->WorkDegree(), 0);
// Test maximum recommended degree
Handle(PLib_JacobiPolynomial) aJacMax = createJacobiPolynomial(30, GeomAbs_C2);
EXPECT_FALSE(aJacMax.IsNull());
EXPECT_EQ(aJacMax->WorkDegree(), 30);
// Test reasonable high degrees
Handle(PLib_JacobiPolynomial) aJacHigh = createJacobiPolynomial(25, GeomAbs_C0);
EXPECT_GT(aJacHigh->WorkDegree(), 20) << "High degree should be supported";
}
// Test Gauss integration points
TEST_F(PLibJacobiPolynomialTest, GaussIntegrationPoints)
{
Handle(PLib_JacobiPolynomial) aJac = createJacobiPolynomial(10, GeomAbs_C0);
// Test various numbers of Gauss points (only valid values supported by OCCT)
std::vector<Standard_Integer> aGaussNumbers = {8, 10, 15, 20, 25, 30, 40, 50, 61};
for (Standard_Integer aNbGauss : aGaussNumbers)
{
if (aNbGauss > aJac->WorkDegree())
{
TColStd_Array1OfReal aPoints(0, aNbGauss / 2);
EXPECT_NO_THROW({ aJac->Points(aNbGauss, aPoints); })
<< "Points calculation failed for " << aNbGauss << " Gauss points";
// Verify points are in valid range and ordered
for (Standard_Integer i = aPoints.Lower(); i <= aPoints.Upper(); i++)
{
if (i == 0 && aNbGauss % 2 == 0)
{
// For even number of Gauss points, TabPoints(0) is set to UNDEFINED (-999)
EXPECT_EQ(aPoints(i), -999) << "TabPoints(0) should be UNDEFINED for even NbGaussPoints";
}
else if (i == 0 && aNbGauss % 2 == 1)
{
// For odd number of Gauss points, TabPoints(0) should be 0
EXPECT_EQ(aPoints(i), 0.0) << "TabPoints(0) should be 0 for odd NbGaussPoints";
}
else
{
// Other points should be positive and <= 1
EXPECT_GT(aPoints(i), 0.0) << "Gauss point should be positive";
EXPECT_LE(aPoints(i), 1.0) << "Gauss point should be <= 1";
if (i > aPoints.Lower() && i > 0)
{
EXPECT_GE(aPoints(i), aPoints(i - 1)) << "Gauss points should be ordered";
}
}
}
}
}
}
// Test Gauss integration weights
TEST_F(PLibJacobiPolynomialTest, GaussIntegrationWeights)
{
Handle(PLib_JacobiPolynomial) aJac = createJacobiPolynomial(8, GeomAbs_C1);
Standard_Integer aNbGauss = 15; // Must be > degree for valid computation
TColStd_Array2OfReal aWeights(0, aNbGauss / 2, 0, aJac->WorkDegree());
aJac->Weights(aNbGauss, aWeights);
// Basic sanity checks on weights - the array is 2D with specific bounds
EXPECT_EQ(aWeights.LowerRow(), 0) << "Lower row should be 0";
EXPECT_EQ(aWeights.UpperRow(), aNbGauss / 2) << "Upper row mismatch";
EXPECT_EQ(aWeights.LowerCol(), 0) << "Lower col should be 0";
EXPECT_EQ(aWeights.UpperCol(), aJac->WorkDegree()) << "Upper col should match work degree";
for (Standard_Integer i = aWeights.LowerRow(); i <= aWeights.UpperRow(); i++)
{
for (Standard_Integer j = aWeights.LowerCol(); j <= aWeights.UpperCol(); j++)
{
EXPECT_FALSE(Precision::IsInfinite(aWeights(i, j)))
<< "Weight should be finite at (" << i << "," << j << ")";
}
}
}
// Test MaxValue computation
TEST_F(PLibJacobiPolynomialTest, MaxValue)
{
Handle(PLib_JacobiPolynomial) aJac = createJacobiPolynomial(10, GeomAbs_C0);
Standard_Integer aTabSize = aJac->WorkDegree() - 2 * (aJac->NivConstr() + 1);
if (aTabSize > 0)
{
TColStd_Array1OfReal aTabMax(0, aTabSize);
aJac->MaxValue(aTabMax);
// Verify all max values are positive (they represent maximum absolute values)
for (Standard_Integer i = aTabMax.Lower(); i <= aTabMax.Upper(); i++)
{
EXPECT_GT(aTabMax(i), 0.0) << "Max value should be positive at index " << i;
EXPECT_FALSE(Precision::IsInfinite(aTabMax(i)))
<< "Max value should be finite at index " << i;
}
}
}
// Test basis function evaluation D0
TEST_F(PLibJacobiPolynomialTest, BasisFunctionD0)
{
Handle(PLib_JacobiPolynomial) aJac = createJacobiPolynomial(6, GeomAbs_C0);
TColStd_Array1OfReal aBasisValue(0, aJac->WorkDegree());
// Test at various parameter values
std::vector<Standard_Real> aTestParams = {-1.0, -0.5, 0.0, 0.5, 1.0};
for (Standard_Real aU : aTestParams)
{
aJac->D0(aU, aBasisValue);
// Basic sanity checks
for (Standard_Integer i = aBasisValue.Lower(); i <= aBasisValue.Upper(); i++)
{
EXPECT_FALSE(Precision::IsInfinite(aBasisValue(i)))
<< "Basis value should be finite at index " << i << ", U=" << aU;
}
}
}
// Test basis function evaluation with derivatives
TEST_F(PLibJacobiPolynomialTest, BasisFunctionDerivatives)
{
Handle(PLib_JacobiPolynomial) aJac = createJacobiPolynomial(8, GeomAbs_C1);
TColStd_Array1OfReal aBasisValue(0, aJac->WorkDegree());
TColStd_Array1OfReal aBasisD1(0, aJac->WorkDegree());
TColStd_Array1OfReal aBasisD2(0, aJac->WorkDegree());
TColStd_Array1OfReal aBasisD3(0, aJac->WorkDegree());
Standard_Real aU = 0.5; // Test at middle point
// Test D1, D2, D3 evaluations
aJac->D1(aU, aBasisValue, aBasisD1);
aJac->D2(aU, aBasisValue, aBasisD1, aBasisD2);
aJac->D3(aU, aBasisValue, aBasisD1, aBasisD2, aBasisD3);
// Verify all values are finite
for (Standard_Integer i = aBasisValue.Lower(); i <= aBasisValue.Upper(); i++)
{
EXPECT_FALSE(Precision::IsInfinite(aBasisValue(i))) << "Basis value should be finite at " << i;
EXPECT_FALSE(Precision::IsInfinite(aBasisD1(i)))
<< "First derivative should be finite at " << i;
EXPECT_FALSE(Precision::IsInfinite(aBasisD2(i)))
<< "Second derivative should be finite at " << i;
EXPECT_FALSE(Precision::IsInfinite(aBasisD3(i)))
<< "Third derivative should be finite at " << i;
}
}
// Test coefficient conversion
TEST_F(PLibJacobiPolynomialTest, CoefficientConversion)
{
const Standard_Integer aWorkDegree = 6; // Use smaller degree that works well with ToCoefficients
Handle(PLib_JacobiPolynomial) aJac = createJacobiPolynomial(aWorkDegree, GeomAbs_C0);
const Standard_Integer aDimension = 1;
const Standard_Integer aDegree =
aJac->WorkDegree() - 2 * (aJac->NivConstr() + 1); // Use computational degree
// Create test Jacobi coefficients with proper size
// ToCoefficients expects arrays sized based on the degree and dimension
// Analysis shows we need arrays that can handle the indexing patterns in the method
Standard_Integer aJacSize = (aDegree + 1) * aDimension;
Standard_Integer aCoeffSize = (aDegree + 1) * aDimension;
// Use 0-based arrays to match the ToCoefficients indexing expectations
TColStd_Array1OfReal aJacCoeff(0, aJacSize - 1);
for (Standard_Integer i = aJacCoeff.Lower(); i <= aJacCoeff.Upper(); i++)
{
aJacCoeff(i) = Sin(i * 0.1); // Some test values
}
TColStd_Array1OfReal aCoefficients(0, aCoeffSize - 1);
aJac->ToCoefficients(aDimension, aDegree, aJacCoeff, aCoefficients);
// Verify output is finite
for (Standard_Integer i = aCoefficients.Lower(); i <= aCoefficients.Upper(); i++)
{
EXPECT_FALSE(Precision::IsInfinite(aCoefficients(i)))
<< "Converted coefficient should be finite at index " << i;
}
}
// Test degree reduction
TEST_F(PLibJacobiPolynomialTest, DegreeReduction)
{
Handle(PLib_JacobiPolynomial) aJac = createJacobiPolynomial(10, GeomAbs_C0);
const Standard_Integer aDimension = 1;
const Standard_Integer aMaxDegree = 8;
const Standard_Real aTol = 1e-6;
// Create test coefficients - must be sized for full WorkDegree
const Standard_Integer aWorkDegree = aJac->WorkDegree();
TColStd_Array1OfReal aCoeff(1, (aWorkDegree + 1) * aDimension);
for (Standard_Integer i = aCoeff.Lower(); i <= aCoeff.Upper(); i++)
{
aCoeff(i) = 1.0 / (i + 1); // Decreasing coefficients to allow reduction
}
Standard_Integer aNewDegree = -1;
Standard_Real aMaxError = -1.0;
aJac->ReduceDegree(aDimension, aMaxDegree, aTol, aCoeff.ChangeValue(1), aNewDegree, aMaxError);
// Verify results are reasonable
EXPECT_LE(aNewDegree, aMaxDegree) << "New degree should not exceed max degree";
EXPECT_GE(aNewDegree, 0) << "New degree should be non-negative";
EXPECT_GE(aMaxError, 0.0) << "Max error should be non-negative";
EXPECT_FALSE(Precision::IsInfinite(aMaxError)) << "Max error should be finite";
}
// Test error estimation
TEST_F(PLibJacobiPolynomialTest, ErrorEstimation)
{
Handle(PLib_JacobiPolynomial) aJac = createJacobiPolynomial(8, GeomAbs_C1);
const Standard_Integer aDimension = 1;
// Create test coefficients
TColStd_Array1OfReal aCoeff(1, 10 * aDimension);
for (Standard_Integer i = aCoeff.Lower(); i <= aCoeff.Upper(); i++)
{
aCoeff(i) = 1.0 / (i + 1);
}
Standard_Integer aNewDegree = 6; // Reduced from original
// Test MaxError
Standard_Real aMaxErr = aJac->MaxError(aDimension, aCoeff.ChangeValue(1), aNewDegree);
EXPECT_GE(aMaxErr, 0.0) << "Max error should be non-negative";
EXPECT_FALSE(Precision::IsInfinite(aMaxErr)) << "Max error should be finite";
// Test AverageError
Standard_Real aAvgErr = aJac->AverageError(aDimension, aCoeff.ChangeValue(1), aNewDegree);
EXPECT_GE(aAvgErr, 0.0) << "Average error should be non-negative";
EXPECT_FALSE(Precision::IsInfinite(aAvgErr)) << "Average error should be finite";
// Average error should typically be <= max error
EXPECT_LE(aAvgErr, aMaxErr + Precision::Confusion())
<< "Average error should not exceed max error significantly";
}
// Performance and stress tests
TEST_F(PLibJacobiPolynomialTest, StressTests)
{
// Test with maximum degree
Handle(PLib_JacobiPolynomial) aJacMax = createJacobiPolynomial(30, GeomAbs_C2);
// Test that basic operations work with high degrees
TColStd_Array1OfReal aBasisValue(0, aJacMax->WorkDegree());
aJacMax->D0(0.0, aBasisValue);
aJacMax->D0(0.5, aBasisValue);
aJacMax->D0(1.0, aBasisValue);
// Test with extreme parameter values
std::vector<Standard_Real> aExtremeParams = {-0.99999, -1e-10, 1e-10, 0.99999};
for (Standard_Real aU : aExtremeParams)
{
aJacMax->D0(aU, aBasisValue);
// Verify basis values are finite
for (Standard_Integer i = aBasisValue.Lower(); i <= aBasisValue.Upper(); i++)
{
EXPECT_FALSE(Precision::IsInfinite(aBasisValue(i))) << "Basis value should be finite";
}
}
}

View File

@@ -1,418 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <PLib.hxx>
#include <gtest/gtest.h>
#include <Standard_Real.hxx>
#include <Standard_Integer.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array2OfReal.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColgp_Array2OfPnt.hxx>
#include <GeomAbs_Shape.hxx>
#include <Precision.hxx>
namespace
{
// Helper function for comparing points with tolerance
void checkPointsEqual(const gp_Pnt& thePnt1,
const gp_Pnt& thePnt2,
const Standard_Real theTolerance = Precision::Confusion())
{
EXPECT_NEAR(thePnt1.X(), thePnt2.X(), theTolerance) << "X coordinates differ";
EXPECT_NEAR(thePnt1.Y(), thePnt2.Y(), theTolerance) << "Y coordinates differ";
EXPECT_NEAR(thePnt1.Z(), thePnt2.Z(), theTolerance) << "Z coordinates differ";
}
// Helper function for comparing 2D points with tolerance
void checkPoint2dEqual(const gp_Pnt2d& thePnt1,
const gp_Pnt2d& thePnt2,
const Standard_Real theTolerance = Precision::Confusion())
{
EXPECT_NEAR(thePnt1.X(), thePnt2.X(), theTolerance) << "X coordinates differ";
EXPECT_NEAR(thePnt1.Y(), thePnt2.Y(), theTolerance) << "Y coordinates differ";
}
} // namespace
// Test class for PLib tests
class PLibTest : public ::testing::Test
{
protected:
void SetUp() override
{
// Setup common test data
}
void TearDown() override
{
// Cleanup
}
};
// Tests for basic utility functions
TEST_F(PLibTest, NoWeightsPointers)
{
// Test that NoWeights() returns NULL as expected
EXPECT_EQ(PLib::NoWeights(), static_cast<TColStd_Array1OfReal*>(nullptr));
EXPECT_EQ(PLib::NoWeights2(), static_cast<TColStd_Array2OfReal*>(nullptr));
}
// Tests for 3D pole conversion functions
TEST_F(PLibTest, SetGetPoles3D)
{
// Create test data
TColgp_Array1OfPnt aPoles(1, 3);
aPoles(1) = gp_Pnt(1.0, 2.0, 3.0);
aPoles(2) = gp_Pnt(4.0, 5.0, 6.0);
aPoles(3) = gp_Pnt(7.0, 8.0, 9.0);
// Test SetPoles and GetPoles without weights
TColStd_Array1OfReal aFP(1, 9); // 3 poles * 3 coordinates
PLib::SetPoles(aPoles, aFP);
TColgp_Array1OfPnt aResultPoles(1, 3);
PLib::GetPoles(aFP, aResultPoles);
// Verify results
for (Standard_Integer i = 1; i <= 3; i++)
{
checkPointsEqual(aPoles(i), aResultPoles(i));
}
}
TEST_F(PLibTest, SetGetPoles3DWithWeights)
{
// Create test data
TColgp_Array1OfPnt aPoles(1, 2);
aPoles(1) = gp_Pnt(1.0, 2.0, 3.0);
aPoles(2) = gp_Pnt(4.0, 5.0, 6.0);
TColStd_Array1OfReal aWeights(1, 2);
aWeights(1) = 0.5;
aWeights(2) = 2.0;
// Test SetPoles and GetPoles with weights
TColStd_Array1OfReal aFP(1, 8); // 2 poles * (3 coords + 1 weight)
PLib::SetPoles(aPoles, aWeights, aFP);
TColgp_Array1OfPnt aResultPoles(1, 2);
TColStd_Array1OfReal aResultWeights(1, 2);
PLib::GetPoles(aFP, aResultPoles, aResultWeights);
// Verify results
for (Standard_Integer i = 1; i <= 2; i++)
{
checkPointsEqual(aPoles(i), aResultPoles(i));
EXPECT_NEAR(aWeights(i), aResultWeights(i), Precision::Confusion());
}
}
// Tests for 2D pole conversion functions
TEST_F(PLibTest, SetGetPoles2D)
{
// Create test data
TColgp_Array1OfPnt2d aPoles(1, 3);
aPoles(1) = gp_Pnt2d(1.0, 2.0);
aPoles(2) = gp_Pnt2d(3.0, 4.0);
aPoles(3) = gp_Pnt2d(5.0, 6.0);
// Test SetPoles and GetPoles without weights
TColStd_Array1OfReal aFP(1, 6); // 3 poles * 2 coordinates
PLib::SetPoles(aPoles, aFP);
TColgp_Array1OfPnt2d aResultPoles(1, 3);
PLib::GetPoles(aFP, aResultPoles);
// Verify results
for (Standard_Integer i = 1; i <= 3; i++)
{
checkPoint2dEqual(aPoles(i), aResultPoles(i));
}
}
TEST_F(PLibTest, SetGetPoles2DWithWeights)
{
// Create test data
TColgp_Array1OfPnt2d aPoles(1, 2);
aPoles(1) = gp_Pnt2d(1.0, 2.0);
aPoles(2) = gp_Pnt2d(3.0, 4.0);
TColStd_Array1OfReal aWeights(1, 2);
aWeights(1) = 0.8;
aWeights(2) = 1.5;
// Test SetPoles and GetPoles with weights
TColStd_Array1OfReal aFP(1, 6); // 2 poles * (2 coords + 1 weight)
PLib::SetPoles(aPoles, aWeights, aFP);
TColgp_Array1OfPnt2d aResultPoles(1, 2);
TColStd_Array1OfReal aResultWeights(1, 2);
PLib::GetPoles(aFP, aResultPoles, aResultWeights);
// Verify results
for (Standard_Integer i = 1; i <= 2; i++)
{
checkPoint2dEqual(aPoles(i), aResultPoles(i));
EXPECT_NEAR(aWeights(i), aResultWeights(i), Precision::Confusion());
}
}
// Test for zero weights handling (safety test)
TEST_F(PLibTest, ZeroWeightsHandling)
{
// Create test data with zero weight - this should not crash
TColgp_Array1OfPnt2d aPoles(1, 2);
aPoles(1) = gp_Pnt2d(1.0, 2.0);
aPoles(2) = gp_Pnt2d(3.0, 4.0);
TColStd_Array1OfReal aWeights(1, 2);
aWeights(1) = 1.0;
aWeights(2) = 0.0; // Zero weight - potential division by zero
TColStd_Array1OfReal aFP(1, 6);
PLib::SetPoles(aPoles, aWeights, aFP);
// This test should complete without crashing
// The behavior with zero weights may vary, but it shouldn't crash
EXPECT_TRUE(true); // We mainly test that no crash occurs
}
// Tests for Binomial coefficient function
TEST_F(PLibTest, BinomialCoefficient)
{
// Test known binomial coefficients
EXPECT_NEAR(PLib::Bin(0, 0), 1.0, Precision::Confusion());
EXPECT_NEAR(PLib::Bin(5, 0), 1.0, Precision::Confusion());
EXPECT_NEAR(PLib::Bin(5, 5), 1.0, Precision::Confusion());
EXPECT_NEAR(PLib::Bin(5, 1), 5.0, Precision::Confusion());
EXPECT_NEAR(PLib::Bin(5, 2), 10.0, Precision::Confusion());
EXPECT_NEAR(PLib::Bin(5, 3), 10.0, Precision::Confusion());
EXPECT_NEAR(PLib::Bin(10, 3), 120.0, Precision::Confusion());
// Test symmetry property: C(n,k) = C(n,n-k)
for (Standard_Integer n = 1; n <= 10; n++)
{
for (Standard_Integer k = 0; k <= n; k++)
{
EXPECT_NEAR(PLib::Bin(n, k), PLib::Bin(n, n - k), Precision::Confusion())
<< "Binomial coefficient symmetry failed for C(" << n << "," << k << ")";
}
}
}
// Tests for polynomial evaluation
TEST_F(PLibTest, EvalPolynomial)
{
// Test simple polynomial evaluation: f(x) = 1 + 2x + 3x^2
const Standard_Integer aDegree = 2;
const Standard_Integer aDimension = 1;
const Standard_Integer aDerivOrder = 0;
TColStd_Array1OfReal aCoeffs(1, 3);
aCoeffs(1) = 1.0; // constant term
aCoeffs(2) = 2.0; // linear term
aCoeffs(3) = 3.0; // quadratic term
TColStd_Array1OfReal aResults(1, 1);
// Test at x = 0: f(0) = 1
PLib::EvalPolynomial(0.0,
aDerivOrder,
aDegree,
aDimension,
aCoeffs.ChangeValue(1),
aResults.ChangeValue(1));
EXPECT_NEAR(aResults(1), 1.0, Precision::Confusion());
// Test at x = 1: f(1) = 1 + 2 + 3 = 6
PLib::EvalPolynomial(1.0,
aDerivOrder,
aDegree,
aDimension,
aCoeffs.ChangeValue(1),
aResults.ChangeValue(1));
EXPECT_NEAR(aResults(1), 6.0, Precision::Confusion());
// Test at x = 2: f(2) = 1 + 4 + 12 = 17
PLib::EvalPolynomial(2.0,
aDerivOrder,
aDegree,
aDimension,
aCoeffs.ChangeValue(1),
aResults.ChangeValue(1));
EXPECT_NEAR(aResults(1), 17.0, Precision::Confusion());
}
// Tests for polynomial evaluation with derivatives
TEST_F(PLibTest, EvalPolynomialWithDerivatives)
{
// Test polynomial f(x) = 1 + 2x + 3x^2
// f'(x) = 2 + 6x
// f''(x) = 6
const Standard_Integer aDegree = 2;
const Standard_Integer aDimension = 1;
const Standard_Integer aDerivOrder = 2;
TColStd_Array1OfReal aCoeffs(1, 3);
aCoeffs(1) = 1.0;
aCoeffs(2) = 2.0;
aCoeffs(3) = 3.0;
TColStd_Array1OfReal aResults(1, 3); // value + 1st + 2nd derivative
// Test at x = 1
PLib::EvalPolynomial(1.0,
aDerivOrder,
aDegree,
aDimension,
aCoeffs.ChangeValue(1),
aResults.ChangeValue(1));
EXPECT_NEAR(aResults(1), 6.0, Precision::Confusion()); // f(1) = 6
EXPECT_NEAR(aResults(2), 8.0, Precision::Confusion()); // f'(1) = 2 + 6 = 8
EXPECT_NEAR(aResults(3), 6.0, Precision::Confusion()); // f''(1) = 6
}
// Tests for constraint order conversion functions
TEST_F(PLibTest, ConstraintOrderConversion)
{
// Test NivConstr function
EXPECT_EQ(PLib::NivConstr(GeomAbs_C0), 0);
EXPECT_EQ(PLib::NivConstr(GeomAbs_C1), 1);
EXPECT_EQ(PLib::NivConstr(GeomAbs_C2), 2);
// Test ConstraintOrder function
EXPECT_EQ(PLib::ConstraintOrder(0), GeomAbs_C0);
EXPECT_EQ(PLib::ConstraintOrder(1), GeomAbs_C1);
EXPECT_EQ(PLib::ConstraintOrder(2), GeomAbs_C2);
// Test round-trip consistency
for (Standard_Integer i = 0; i <= 2; i++)
{
GeomAbs_Shape aShape = PLib::ConstraintOrder(i);
Standard_Integer aLevel = PLib::NivConstr(aShape);
EXPECT_EQ(aLevel, i) << "Round-trip conversion failed for level " << i;
}
}
// Test for Hermite interpolation
TEST_F(PLibTest, HermiteInterpolate)
{
const Standard_Integer aDimension = 1;
const Standard_Real aFirstParam = 0.0;
const Standard_Real aLastParam = 1.0;
const Standard_Integer aFirstOrder = 1; // value + 1st derivative
const Standard_Integer aLastOrder = 1; // value + 1st derivative
// Define constraints: f(0) = 0, f'(0) = 1, f(1) = 1, f'(1) = 0
TColStd_Array2OfReal aFirstConstr(1, aDimension, 0, aFirstOrder);
aFirstConstr(1, 0) = 0.0; // f(0) = 0
aFirstConstr(1, 1) = 1.0; // f'(0) = 1
TColStd_Array2OfReal aLastConstr(1, aDimension, 0, aLastOrder);
aLastConstr(1, 0) = 1.0; // f(1) = 1
aLastConstr(1, 1) = 0.0; // f'(1) = 0
const Standard_Integer aCoeffCount = aFirstOrder + aLastOrder + 2;
TColStd_Array1OfReal aCoeffs(0,
aCoeffCount
- 1); // 0-based indexing as expected by HermiteInterpolate
// Perform Hermite interpolation
Standard_Boolean aResult = PLib::HermiteInterpolate(aDimension,
aFirstParam,
aLastParam,
aFirstOrder,
aLastOrder,
aFirstConstr,
aLastConstr,
aCoeffs);
EXPECT_TRUE(aResult) << "Hermite interpolation failed";
if (aResult)
{
// Verify that the resulting polynomial satisfies the constraints
TColStd_Array1OfReal aResults(1, 2); // value + 1st derivative
// Check at first parameter
PLib::EvalPolynomial(aFirstParam,
1,
aCoeffCount - 1,
aDimension,
aCoeffs.ChangeValue(0),
aResults.ChangeValue(1));
EXPECT_NEAR(aResults(1), 0.0, Precision::Confusion()) << "f(0) constraint not satisfied";
EXPECT_NEAR(aResults(2), 1.0, Precision::Confusion()) << "f'(0) constraint not satisfied";
// Check at last parameter
PLib::EvalPolynomial(aLastParam,
1,
aCoeffCount - 1,
aDimension,
aCoeffs.ChangeValue(0),
aResults.ChangeValue(1));
EXPECT_NEAR(aResults(1), 1.0, Precision::Confusion()) << "f(1) constraint not satisfied";
EXPECT_NEAR(aResults(2), 0.0, Precision::Confusion()) << "f'(1) constraint not satisfied";
}
}
// Edge case tests
TEST_F(PLibTest, EdgeCases)
{
// Test with very small coefficients
TColStd_Array1OfReal aSmallCoeffs(1, 3);
aSmallCoeffs(1) = 1.0e-12;
aSmallCoeffs(2) = 1.0e-12;
aSmallCoeffs(3) = 1.0e-12;
TColStd_Array1OfReal aResults(1, 1);
// This should not crash even with very small coefficients
EXPECT_NO_THROW(
{ PLib::EvalPolynomial(1.0, 0, 2, 1, aSmallCoeffs.ChangeValue(1), aResults.ChangeValue(1)); });
// Test with large coefficients
TColStd_Array1OfReal aLargeCoeffs(1, 3);
aLargeCoeffs(1) = 1.0e10;
aLargeCoeffs(2) = 1.0e10;
aLargeCoeffs(3) = 1.0e10;
EXPECT_NO_THROW(
{ PLib::EvalPolynomial(1.0, 0, 2, 1, aLargeCoeffs.ChangeValue(1), aResults.ChangeValue(1)); });
}
// Test for Jacobi parameter calculation
TEST_F(PLibTest, JacobiParameters)
{
Standard_Integer aNbGaussPoints, aWorkDegree;
// Test various constraint orders and codes
PLib::JacobiParameters(GeomAbs_C0, 10, 1, aNbGaussPoints, aWorkDegree);
EXPECT_GT(aNbGaussPoints, 0) << "Number of Gauss points should be positive";
EXPECT_GT(aWorkDegree, 0) << "Work degree should be positive";
PLib::JacobiParameters(GeomAbs_C1, 15, 2, aNbGaussPoints, aWorkDegree);
EXPECT_GT(aNbGaussPoints, 0);
EXPECT_GT(aWorkDegree, 0);
PLib::JacobiParameters(GeomAbs_C2, 20, 3, aNbGaussPoints, aWorkDegree);
EXPECT_GT(aNbGaussPoints, 0);
EXPECT_GT(aWorkDegree, 0);
}

View File

@@ -371,27 +371,24 @@ TEST(MathBFGSTest, MaxIterationsLimit)
TEST(MathBFGSTest, NotDoneState)
{
QuadraticFunction2D aFunc;
math_BFGS anOptimizer(2, 1.0e-12, 3); // Reasonable tolerance, few iterations
math_BFGS anOptimizer(2, 1.0e-15, 1); // Very tight tolerance, one iteration
math_Vector aStartPoint(1, 2);
aStartPoint(1) = 50.0; // Far from minimum but not extreme
aStartPoint(2) = 50.0;
aStartPoint(1) = 100.0; // Very far from minimum
aStartPoint(2) = 100.0;
// Wrap in try-catch to handle potential exceptions in debug mode
EXPECT_NO_THROW({
anOptimizer.Perform(aFunc, aStartPoint);
anOptimizer.Perform(aFunc, aStartPoint);
if (!anOptimizer.IsDone())
{
EXPECT_GE(anOptimizer.NbIterations(), 0)
<< "Iteration count should be non-negative even on failure";
}
else
{
EXPECT_GT(anOptimizer.NbIterations(), 0)
<< "Successful optimization should require at least one iteration";
}
}) << "BFGS optimization should not throw exceptions";
if (!anOptimizer.IsDone())
{
EXPECT_GE(anOptimizer.NbIterations(), 0)
<< "Iteration count should be non-negative even on failure";
}
else
{
EXPECT_GT(anOptimizer.NbIterations(), 0)
<< "Successful optimization should require at least one iteration";
}
}
TEST(MathBFGSTest, DimensionCompatibility)

View File

@@ -251,27 +251,24 @@ TEST(MathFunctionRootTest, HighPrecisionTolerance)
TEST(MathFunctionRootTest, MaxIterationsLimit)
{
QuadraticFunction aFunc;
Standard_Real aTolerance = 1.0e-10; // Reasonable tolerance for debug mode
Standard_Real aTolerance = 1.0e-15; // Very tight tolerance
Standard_Real anInitialGuess = 2.1;
Standard_Integer aMaxIterations = 5; // Few but reasonable iterations
Standard_Integer aMaxIterations = 3; // Very few iterations
// Wrap in try-catch to handle potential exceptions in debug mode
EXPECT_NO_THROW({
math_FunctionRoot aRootFinder(aFunc, anInitialGuess, aTolerance, aMaxIterations);
math_FunctionRoot aRootFinder(aFunc, anInitialGuess, aTolerance, aMaxIterations);
// Should either succeed within iterations or fail gracefully
if (aRootFinder.IsDone())
{
EXPECT_LE(aRootFinder.NbIterations(), aMaxIterations) << "Should not exceed max iterations";
EXPECT_NEAR(aRootFinder.Root(), 2.0, 1.0e-3)
<< "Root should be reasonably close even with few iterations";
}
else
{
// It's acceptable to fail if too few iterations are allowed
EXPECT_LE(aMaxIterations, 10) << "Failure is acceptable with very few iterations";
}
}) << "Function root finding should not throw exceptions";
// Should either succeed within 3 iterations or fail
if (aRootFinder.IsDone())
{
EXPECT_LE(aRootFinder.NbIterations(), aMaxIterations) << "Should not exceed max iterations";
EXPECT_NEAR(aRootFinder.Root(), 2.0, 1.0e-3)
<< "Root should be reasonably close even with few iterations";
}
else
{
// It's acceptable to fail if too few iterations are allowed
EXPECT_LE(aMaxIterations, 10) << "Failure is acceptable with very few iterations";
}
}
TEST(MathFunctionRootTest, OutOfBoundsGuess)
@@ -331,30 +328,27 @@ TEST(MathFunctionRootTest, ZeroDerivativeHandling)
TEST(MathFunctionRootTest, ConstrainedConvergenceState)
{
QuadraticFunction aFunc;
Standard_Real aTolerance = 1.0e-10; // Reasonable tolerance for debug mode
Standard_Real anInitialGuess = 50.0; // Far from roots but not extreme
Standard_Integer aMaxIterations = 3; // Few but reasonable iterations
Standard_Real aTolerance = 1.0e-15; // Very tight tolerance
Standard_Real anInitialGuess = 100.0; // Very far from roots
Standard_Integer aMaxIterations = 1; // Very few iterations
// Wrap in try-catch to handle potential exceptions in debug mode
EXPECT_NO_THROW({
math_FunctionRoot aRootFinder(aFunc, anInitialGuess, aTolerance, aMaxIterations);
math_FunctionRoot aRootFinder(aFunc, anInitialGuess, aTolerance, aMaxIterations);
// Test state handling for constrained convergence conditions
if (!aRootFinder.IsDone())
{
// Verify consistent state reporting
EXPECT_FALSE(aRootFinder.IsDone()) << "Root finder should consistently report failure";
EXPECT_GE(aRootFinder.NbIterations(), 0)
<< "Iteration count should be non-negative even on failure";
}
else
{
// If it succeeds, verify the results are reasonable
EXPECT_GT(aRootFinder.NbIterations(), 0) << "Should have done at least one iteration";
EXPECT_TRUE(Abs(aRootFinder.Root() - 2.0) < 0.5 || Abs(aRootFinder.Root() - (-2.0)) < 0.5)
<< "Root should be reasonably close to one of the expected roots";
}
}) << "Function root finding should not throw exceptions";
// Test state handling for constrained convergence conditions
if (!aRootFinder.IsDone())
{
// In release builds, verify consistent state reporting
EXPECT_FALSE(aRootFinder.IsDone()) << "Root finder should consistently report failure";
EXPECT_GE(aRootFinder.NbIterations(), 0)
<< "Iteration count should be non-negative even on failure";
}
else
{
// If it surprisingly succeeds, verify the results are reasonable
EXPECT_GT(aRootFinder.NbIterations(), 0) << "Should have done at least one iteration";
EXPECT_TRUE(Abs(aRootFinder.Root() - 2.0) < 0.1 || Abs(aRootFinder.Root() - (-2.0)) < 0.1)
<< "Root should be close to one of the expected roots";
}
}
// Tests for convergence behavior

View File

@@ -21,7 +21,6 @@
#include <StdFail_NotDone.hxx>
#include <Standard_RangeError.hxx>
#include <algorithm>
#include <cmath>
namespace

View File

@@ -173,8 +173,6 @@ void PLib_DoubleJacobiPolynomial::ReduceDegree(const Standard_Integer Dimen
NewV = MaxDegreeV;
math_Vector MaxErr2(1, 2);
MaxError = 0.0; // Initialize MaxError
//**********************************************************************
//-------------------- Coupure des coefficients ------------------------
//**********************************************************************

View File

@@ -29,7 +29,7 @@
class math_DoubleTab
{
static const Standard_Integer THE_BUFFER_SIZE = 64;
static const Standard_Integer THE_BUFFER_SIZE = 16;
public:
DEFINE_STANDARD_ALLOC;

View File

@@ -22,9 +22,10 @@
template <typename TheItemType>
math_VectorBase<TheItemType>::math_VectorBase(const Standard_Integer theLower,
const Standard_Integer theUpper)
: Array(theUpper - theLower + 1 <= math_VectorBase::THE_BUFFER_SIZE
? NCollection_Array1<TheItemType>(*myBuffer.data(), theLower, theUpper)
: NCollection_Array1<TheItemType>(theLower, theUpper))
: Array(*myBuffer.data(),
theLower,
theUpper,
(theUpper - theLower + 1 <= math_VectorBase::THE_BUFFER_SIZE))
{
}
@@ -32,9 +33,10 @@ template <typename TheItemType>
math_VectorBase<TheItemType>::math_VectorBase(const Standard_Integer theLower,
const Standard_Integer theUpper,
const TheItemType theInitialValue)
: Array(theUpper - theLower + 1 <= math_VectorBase::THE_BUFFER_SIZE
? NCollection_Array1<TheItemType>(*myBuffer.data(), theLower, theUpper)
: NCollection_Array1<TheItemType>(theLower, theUpper))
: Array(*myBuffer.data(),
theLower,
theUpper,
(theUpper - theLower + 1 <= math_VectorBase::THE_BUFFER_SIZE))
{
Array.Init(theInitialValue);
}

View File

@@ -2,8 +2,6 @@
set(OCCT_TKernel_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKernel_GTests_FILES
Handle_Advanced_Test.cxx
Handle_Operations_Test.cxx
NCollection_Array1_Test.cxx
NCollection_Array2_Test.cxx
NCollection_BaseAllocator_Test.cxx
@@ -14,14 +12,10 @@ set(OCCT_TKernel_GTests_FILES
NCollection_List_Test.cxx
NCollection_LocalArray_Test.cxx
NCollection_Map_Test.cxx
NCollection_OccAllocator_Test.cxx
NCollection_Sequence_Test.cxx
NCollection_SparseArray_Test.cxx
NCollection_Vec4_Test.cxx
NCollection_Vector_Test.cxx
OSD_Path_Test.cxx
OSD_PerfMeter_Test.cxx
Standard_ArrayStreamBuffer_Test.cxx
TCollection_AsciiString_Test.cxx
TCollection_ExtendedString_Test.cxx
)

View File

@@ -1,413 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Standard_Handle.hxx>
#include <Standard_Transient.hxx>
#include <Standard_Type.hxx>
#include <Standard_Assert.hxx>
#include <NCollection_BaseAllocator.hxx>
#include <NCollection_IncAllocator.hxx>
#include <NCollection_HeapAllocator.hxx>
#include <OSD_Timer.hxx>
#include <gtest/gtest.h>
#include <vector>
#include <memory>
#include <typeinfo>
#include <type_traits>
// Auxiliary macro to check and report status with EXPECT
#define CHECK_HANDLE(ok, what) EXPECT_TRUE(ok) << "Checking " << what << " failed"
// Test root class for hierarchy
class TransientRoot : public Standard_Transient
{
public:
virtual const char* Name() const { return "TransientRoot"; }
virtual Standard_Transient* CreateParent() const { return new Standard_Transient; }
virtual Standard_Transient* Clone() const { return new TransientRoot; }
DEFINE_STANDARD_RTTI_INLINE(TransientRoot, Standard_Transient)
};
DEFINE_STANDARD_HANDLE(TransientRoot, Standard_Transient)
// Auxiliary macros to create hierarchy of classes
#define QA_DEFINECLASS(theClass, theParent) \
class theClass : public theParent \
{ \
public: \
virtual const char* Name() const override \
{ \
return #theClass; \
} \
virtual Standard_Transient* CreateParent() const override \
{ \
return new theParent(); \
} \
virtual Standard_Transient* Clone() const override \
{ \
return new theClass(); \
} \
DEFINE_STANDARD_RTTI_INLINE(theClass, theParent) \
}; \
DEFINE_STANDARD_HANDLE(theClass, theParent)
#define QA_NAME(theNum) QaClass##theNum##_50
#define QA_HANDLE_NAME(theNum) Handle(QaClass##theNum##_50)
#define QA_DEFINECLASS10(theParent, theTens) \
QA_DEFINECLASS(QA_NAME(theTens##0), theParent) \
QA_DEFINECLASS(QA_NAME(theTens##1), QA_NAME(theTens##0)) \
QA_DEFINECLASS(QA_NAME(theTens##2), QA_NAME(theTens##1)) \
QA_DEFINECLASS(QA_NAME(theTens##3), QA_NAME(theTens##2)) \
QA_DEFINECLASS(QA_NAME(theTens##4), QA_NAME(theTens##3)) \
QA_DEFINECLASS(QA_NAME(theTens##5), QA_NAME(theTens##4)) \
QA_DEFINECLASS(QA_NAME(theTens##6), QA_NAME(theTens##5)) \
QA_DEFINECLASS(QA_NAME(theTens##7), QA_NAME(theTens##6)) \
QA_DEFINECLASS(QA_NAME(theTens##8), QA_NAME(theTens##7)) \
QA_DEFINECLASS(QA_NAME(theTens##9), QA_NAME(theTens##8))
// Create the hierarchy: 50 classes in inheritance chain
QA_DEFINECLASS10(TransientRoot, 0)
QA_DEFINECLASS10(QaClass09_50, 1)
QA_DEFINECLASS10(QaClass19_50, 2)
QA_DEFINECLASS10(QaClass29_50, 3)
QA_DEFINECLASS10(QaClass39_50, 4)
QA_DEFINECLASS(QaClass50_50, QaClass49_50)
// Anonymous namespace class for testing
namespace
{
class QaClass50_50Anon : public QaClass49_50
{
public:
QaClass50_50Anon() {}
};
} // namespace
// Named namespace class for testing
namespace QaNamespace
{
class QaClass50_50 : public QaClass49_50
{
public:
QaClass50_50() {}
};
} // namespace QaNamespace
// Timer class for performance testing
namespace
{
class QATimer : public OSD_Timer
{
public:
enum TimeFormat
{
Seconds,
Milliseconds,
Microseconds
};
QATimer(const char* theOperationName, TimeFormat theFormat = Milliseconds)
: myOperationName(theOperationName),
myFormat(theFormat)
{
Start();
}
~QATimer()
{
Stop();
Standard_Real aTime = 0.0;
switch (myFormat)
{
case Seconds:
aTime = ElapsedTime();
break;
case Milliseconds:
aTime = ElapsedTime() * 1000.0;
break;
case Microseconds:
aTime = ElapsedTime() * 1000000.0;
break;
}
// Note: In tests we don't print timing info but could store it for verification
(void)aTime; // Avoid unused variable warning
(void)myOperationName; // Avoid unused field warning
}
private:
const char* myOperationName;
TimeFormat myFormat;
};
} // namespace
// Test fixture for advanced Handle operations tests
class HandleAdvancedTest : public testing::Test
{
protected:
void SetUp() override {}
void TearDown() override {}
};
TEST_F(HandleAdvancedTest, CompilerSpecificBehavior)
{
Handle(TransientRoot) aRoot = new TransientRoot();
EXPECT_FALSE(aRoot.IsNull());
const Handle(TransientRoot)& aConstRoot = aRoot;
(void)aConstRoot; // Avoid unused variable warning
Handle(Standard_Transient) aTransient = aRoot;
// Test passing handle as reference to base class
// This tests template argument deduction and inheritance
auto testFunction = [](const Handle(Standard_Transient)& theObj) -> bool {
return !theObj.IsNull();
};
EXPECT_TRUE(testFunction(aRoot));
// Test overloaded function compatibility (compiler version specific)
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) \
|| (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3)
// Test overload resolution with handles
auto testOverload1 = [](const Handle(Standard_Transient)&) -> int { return 1; };
auto testOverload2 = [](const Handle(TransientRoot)&) -> int { return 2; };
// More specific overload should be chosen
EXPECT_EQ(2, testOverload2(aRoot));
EXPECT_EQ(1, testOverload1(aTransient));
#endif
const Handle(Standard_Transient)& aTransient2 = aRoot; // cast to base const ref
CHECK_HANDLE(!aTransient2.IsNull(), "cast to base class const reference");
}
TEST_F(HandleAdvancedTest, DeepHierarchyRTTI)
{
// Test RTTI with deep inheritance hierarchy
Handle(Standard_Type) aType00 = STANDARD_TYPE(QaClass00_50);
Handle(Standard_Type) aType10 = STANDARD_TYPE(QaClass10_50);
Handle(Standard_Type) aType20 = STANDARD_TYPE(QaClass20_50);
Handle(Standard_Type) aType30 = STANDARD_TYPE(QaClass30_50);
Handle(Standard_Type) aType40 = STANDARD_TYPE(QaClass40_50);
Handle(Standard_Type) aType50 = STANDARD_TYPE(QaClass50_50);
Handle(QaClass00_50) aHandle = new QaClass40_50();
// Test type name
EXPECT_STREQ("QaClass40_50", aHandle->DynamicType()->Name());
// Test IsKind() - should be true for all parent types
EXPECT_TRUE(aHandle->IsKind(aType00)) << "IsKind failed for root type";
EXPECT_TRUE(aHandle->IsKind(aType10)) << "IsKind failed for parent type 10";
EXPECT_TRUE(aHandle->IsKind(aType20)) << "IsKind failed for parent type 20";
EXPECT_TRUE(aHandle->IsKind(aType30)) << "IsKind failed for parent type 30";
EXPECT_TRUE(aHandle->IsKind(aType40)) << "IsKind failed for exact type 40";
EXPECT_FALSE(aHandle->IsKind(aType50)) << "IsKind should be false for child type 50";
// Test IsKind() with string names
EXPECT_TRUE(aHandle->IsKind("QaClass00_50"));
EXPECT_TRUE(aHandle->IsKind("QaClass10_50"));
EXPECT_TRUE(aHandle->IsKind("QaClass20_50"));
EXPECT_TRUE(aHandle->IsKind("QaClass30_50"));
EXPECT_TRUE(aHandle->IsKind("QaClass40_50"));
EXPECT_FALSE(aHandle->IsKind("QaClass50_50"));
// Test IsInstance() - should be true only for exact type
EXPECT_FALSE(aHandle->IsInstance(aType00));
EXPECT_FALSE(aHandle->IsInstance(aType10));
EXPECT_FALSE(aHandle->IsInstance(aType20));
EXPECT_FALSE(aHandle->IsInstance(aType30));
EXPECT_TRUE(aHandle->IsInstance(aType40));
EXPECT_FALSE(aHandle->IsInstance(aType50));
}
TEST_F(HandleAdvancedTest, TypeInfoCompatibility)
{
Handle(QaClass40_50) aHandle = new QaClass40_50();
#ifdef __cpp_rtti
// Test C++ RTTI compatibility
// Use OCCT standard warning suppression for RTTI operations
#include <Standard_WarningsDisable.hxx>
const std::type_info& aTypeInfo = typeid(*aHandle.get());
// Test type_info comparisons
EXPECT_FALSE(aTypeInfo == typeid(QaClass00_50));
EXPECT_FALSE(aTypeInfo == typeid(QaClass10_50));
EXPECT_FALSE(aTypeInfo == typeid(QaClass20_50));
EXPECT_FALSE(aTypeInfo == typeid(QaClass30_50));
EXPECT_TRUE(aTypeInfo == typeid(QaClass40_50));
EXPECT_FALSE(aTypeInfo == typeid(QaClass50_50));
// Test type_index if available
#if __cplusplus >= 201103L
std::type_index aCppType = typeid(*aHandle.get());
EXPECT_FALSE(aCppType == typeid(QaClass00_50));
EXPECT_TRUE(aCppType == typeid(QaClass40_50));
#endif
// Test anonymous and namespaced classes
QaClass50_50Anon anAnon;
QaNamespace::QaClass50_50 aNamed;
// These should have different type_info
EXPECT_FALSE(typeid(anAnon) == typeid(aNamed));
EXPECT_FALSE(typeid(anAnon) == typeid(QaClass50_50));
EXPECT_FALSE(typeid(aNamed) == typeid(QaClass50_50));
#include <Standard_WarningsRestore.hxx>
#endif // __cpp_rtti
// Test Standard_Transient type traits
EXPECT_TRUE(std::is_class<Standard_Transient>::value);
// Note: IsClass() method is not available in all OCCT versions
// EXPECT_TRUE(STANDARD_TYPE(Standard_Transient)->IsClass());
}
TEST_F(HandleAdvancedTest, AllocatorHandlePerformance)
{
// Test performance aspects of handle operations with different allocators
Handle(NCollection_BaseAllocator) aBasePtr = new NCollection_IncAllocator();
EXPECT_FALSE(aBasePtr.IsNull());
// Test casting performance with allocator hierarchy
{
QATimer aTimer("IncAllocator DownCast", QATimer::Microseconds);
for (int i = 0; i < 1000; ++i)
{
Handle(NCollection_IncAllocator) anIncAlloc =
Handle(NCollection_IncAllocator)::DownCast(aBasePtr);
EXPECT_FALSE(anIncAlloc.IsNull());
}
}
// Test failed downcast performance
{
QATimer aTimer("Failed HeapAllocator DownCast", QATimer::Microseconds);
for (int i = 0; i < 1000; ++i)
{
Handle(NCollection_HeapAllocator) aHeapAlloc =
Handle(NCollection_HeapAllocator)::DownCast(aBasePtr);
EXPECT_TRUE(aHeapAlloc.IsNull());
}
}
}
TEST_F(HandleAdvancedTest, HandleArrayOperations)
{
// Test handle operations with arrays and containers
std::vector<Handle(QaClass00_50)> aHandleVector;
// Fill with different types in the hierarchy
aHandleVector.push_back(new QaClass00_50());
aHandleVector.push_back(new QaClass10_50());
aHandleVector.push_back(new QaClass20_50());
aHandleVector.push_back(new QaClass30_50());
aHandleVector.push_back(new QaClass40_50());
EXPECT_EQ(5, aHandleVector.size());
// Test that all handles are valid and point to correct types
for (size_t i = 0; i < aHandleVector.size(); ++i)
{
EXPECT_FALSE(aHandleVector[i].IsNull());
// Test polymorphic behavior
EXPECT_TRUE(aHandleVector[i]->IsKind("QaClass00_50"));
// Test dynamic casting
Handle(QaClass00_50) aCast = aHandleVector[i];
EXPECT_FALSE(aCast.IsNull());
EXPECT_EQ(aHandleVector[i].get(), aCast.get());
}
// Test specific type casting
Handle(QaClass40_50) aSpecific = Handle(QaClass40_50)::DownCast(aHandleVector[4]);
EXPECT_FALSE(aSpecific.IsNull());
// This should fail - trying to cast parent to child
Handle(QaClass40_50) aFailedCast = Handle(QaClass40_50)::DownCast(aHandleVector[0]);
EXPECT_TRUE(aFailedCast.IsNull());
}
TEST_F(HandleAdvancedTest, ConstHandleOperations)
{
Handle(QaClass30_50) aNonConstHandle = new QaClass30_50();
const Handle(QaClass30_50)& aConstHandle = aNonConstHandle;
// Test const correctness
EXPECT_EQ(aNonConstHandle.get(), aConstHandle.get());
// Test const pointer access
const QaClass30_50* aConstPtr = aConstHandle.get();
QaClass30_50* aNonConstPtr = aNonConstHandle.get();
EXPECT_EQ(aConstPtr, aNonConstPtr);
// Test const casting to base types
const Handle(QaClass00_50)& aConstBase = aConstHandle;
Handle(QaClass00_50) aNonConstBase = aNonConstHandle;
EXPECT_EQ(aConstBase.get(), aNonConstBase.get());
// Test const handle comparisons
EXPECT_TRUE(aConstHandle == aNonConstHandle);
EXPECT_TRUE(aConstBase == aNonConstBase);
EXPECT_FALSE(aConstHandle != aNonConstHandle);
}
TEST_F(HandleAdvancedTest, WeakReferenceSimulation)
{
// Simulate weak reference-like behavior using raw pointers
QaClass20_50* aRawPtr = nullptr;
{
Handle(QaClass20_50) aHandle = new QaClass20_50();
aRawPtr = aHandle.get();
EXPECT_NE(nullptr, aRawPtr);
// Handle should keep the object alive
EXPECT_FALSE(aHandle.IsNull());
EXPECT_EQ(aRawPtr, aHandle.get());
}
// After handle destruction, raw pointer becomes invalid
// Note: We can't safely test this without risking segfaults,
// but the pattern demonstrates handle lifetime management
// Create multiple new handles to ensure we get different objects
// (Memory allocator might reuse the same location, so we create several)
std::vector<Handle(QaClass20_50)> aHandles;
bool aFoundDifferent = false;
for (int i = 0; i < 10 && !aFoundDifferent; ++i)
{
aHandles.push_back(new QaClass20_50());
if (aHandles.back().get() != aRawPtr)
{
aFoundDifferent = true;
}
}
// We expect to find at least one different address (though allocator might reuse)
// The test demonstrates handle independence regardless
EXPECT_TRUE(aFoundDifferent || !aFoundDifferent); // Either outcome is acceptable
}

View File

@@ -1,236 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Standard_Handle.hxx>
#include <Standard_Transient.hxx>
#include <NCollection_BaseAllocator.hxx>
#include <NCollection_IncAllocator.hxx>
#include <NCollection_HeapAllocator.hxx>
#include <gtest/gtest.h>
// Test classes for Handle operations
class TestBase : public Standard_Transient
{
public:
TestBase() {}
virtual ~TestBase() {}
DEFINE_STANDARD_RTTI_INLINE(TestBase, Standard_Transient)
};
DEFINE_STANDARD_HANDLE(TestBase, Standard_Transient)
class TestDerived : public TestBase
{
public:
TestDerived() {}
virtual ~TestDerived() {}
DEFINE_STANDARD_RTTI_INLINE(TestDerived, TestBase)
};
DEFINE_STANDARD_HANDLE(TestDerived, TestBase)
class TestOther : public Standard_Transient
{
public:
TestOther() {}
virtual ~TestOther() {}
DEFINE_STANDARD_RTTI_INLINE(TestOther, Standard_Transient)
};
DEFINE_STANDARD_HANDLE(TestOther, Standard_Transient)
// Test fixture for Handle operations tests
class HandleOperationsTest : public testing::Test
{
protected:
void SetUp() override {}
void TearDown() override {}
};
TEST_F(HandleOperationsTest, BasicHandleOperations)
{
// Test basic handle creation and null checking
Handle(TestDerived) aDerived = new TestDerived();
EXPECT_FALSE(aDerived.IsNull());
// Test various casting operations
const Handle(TestDerived)& aConstDerived = aDerived;
const Handle(TestBase)& aConstBase = aDerived;
(void)aConstBase; // Avoid unused variable warning
TestDerived* aDerivedPtr = aDerived.get();
const TestDerived* aConstDerivedPtr = aDerived.get();
EXPECT_NE(nullptr, aDerivedPtr);
EXPECT_NE(nullptr, aConstDerivedPtr);
EXPECT_EQ(aDerivedPtr, aConstDerivedPtr);
// Test reference access
TestDerived& aDerivedRef = *aDerived;
const TestDerived& aConstDerivedRef = *aConstDerived;
EXPECT_EQ(&aDerivedRef, aDerivedPtr);
EXPECT_EQ(&aConstDerivedRef, aConstDerivedPtr);
// Test handle assignment to base type
Handle(TestBase) aBase = aDerived;
EXPECT_FALSE(aBase.IsNull());
EXPECT_EQ(aBase.get(), aDerived.get());
}
TEST_F(HandleOperationsTest, HandleDownCast)
{
// Test DownCast functionality
Handle(TestDerived) aDerived = new TestDerived();
Handle(TestBase) aBase = aDerived;
Handle(TestDerived) aDownCastDerived = Handle(TestDerived)::DownCast(aBase);
EXPECT_FALSE(aDownCastDerived.IsNull());
EXPECT_EQ(aDownCastDerived.get(), aDerived.get());
// Test failed downcast (different type)
Handle(TestOther) anOther = new TestOther();
Handle(Standard_Transient) aTransient = anOther;
Handle(TestDerived) aFailedDownCast = Handle(TestDerived)::DownCast(aTransient);
EXPECT_TRUE(aFailedDownCast.IsNull());
}
TEST_F(HandleOperationsTest, HandleComparisons)
{
Handle(TestDerived) aDerived = new TestDerived();
Handle(TestDerived) aDerived2 = aDerived; // Same object
Handle(TestDerived) aDerived3 = new TestDerived(); // Different object
Handle(TestBase) aBase = aDerived;
// Test equality operators
EXPECT_TRUE(aDerived == aDerived); // Self equality
EXPECT_TRUE(aDerived == aDerived2); // Same object through different handles
EXPECT_TRUE(aDerived == aBase); // Handle to base type
EXPECT_FALSE(aDerived == aDerived3); // Different objects
// Test with pointers
TestDerived* aDerivedPtr = aDerived.get();
const TestDerived* aConstDerivedPtr = aDerived.get();
EXPECT_TRUE(aDerived == aDerivedPtr);
EXPECT_TRUE(aDerivedPtr == aDerived);
EXPECT_TRUE(aDerived == aConstDerivedPtr);
EXPECT_TRUE(aConstDerivedPtr == aDerived);
// Test inequality
EXPECT_FALSE(aDerived != aDerived2); // Should be equal
EXPECT_TRUE(aDerived != aDerived3); // Should be different
// Test boolean conversion
EXPECT_TRUE(static_cast<bool>(aDerived));
Handle(TestDerived) aNullDerived;
EXPECT_FALSE(static_cast<bool>(aNullDerived));
}
TEST_F(HandleOperationsTest, AllocatorHandleCasting)
{
// Test Handle casting with allocator hierarchy
Handle(NCollection_BaseAllocator) aBasePtr = new NCollection_IncAllocator();
EXPECT_FALSE(aBasePtr.IsNull());
// Test successful downcast to IncAllocator
Handle(NCollection_IncAllocator) anIncAlloc =
Handle(NCollection_IncAllocator)::DownCast(aBasePtr);
EXPECT_FALSE(anIncAlloc.IsNull());
// Test upcast back to BaseAllocator
Handle(NCollection_BaseAllocator) aBaseAlloc = anIncAlloc;
EXPECT_FALSE(aBaseAlloc.IsNull());
EXPECT_EQ(aBaseAlloc.get(), aBasePtr.get());
// Test failed downcast to HeapAllocator
Handle(NCollection_HeapAllocator) aHeapAlloc =
Handle(NCollection_HeapAllocator)::DownCast(aBasePtr);
EXPECT_TRUE(aHeapAlloc.IsNull());
}
TEST_F(HandleOperationsTest, HandleCopyAndAssignment)
{
Handle(TestDerived) aDerived1 = new TestDerived();
// Test copy constructor
Handle(TestDerived) aDerived2(aDerived1);
EXPECT_FALSE(aDerived2.IsNull());
EXPECT_EQ(aDerived1.get(), aDerived2.get());
// Test assignment operator
Handle(TestDerived) aDerived3;
EXPECT_TRUE(aDerived3.IsNull());
aDerived3 = aDerived1;
EXPECT_FALSE(aDerived3.IsNull());
EXPECT_EQ(aDerived1.get(), aDerived3.get());
// Test self-assignment (suppress warning)
#include <Standard_WarningsDisable.hxx>
aDerived1 = aDerived1;
#include <Standard_WarningsRestore.hxx>
EXPECT_FALSE(aDerived1.IsNull());
// Test assignment to null
aDerived3 = Handle(TestDerived)();
EXPECT_TRUE(aDerived3.IsNull());
}
TEST_F(HandleOperationsTest, HandleWithDifferentTypes)
{
Handle(TestDerived) aDerived = new TestDerived();
Handle(TestOther) anOther = new TestOther();
// Note: Direct comparison between handles of different types is not allowed by the type system
// This is actually a good thing as it prevents type errors at compile time
// Test casting both to common base type
Handle(Standard_Transient) aDerivedTransient = aDerived;
Handle(Standard_Transient) anOtherTransient = anOther;
// These should be different objects even when cast to base type
EXPECT_FALSE(aDerivedTransient == anOtherTransient);
EXPECT_TRUE(aDerivedTransient != anOtherTransient);
// But each should equal itself when cast
EXPECT_TRUE(aDerivedTransient == aDerived);
EXPECT_TRUE(anOtherTransient == anOther);
// Test that each maintains its identity through base type casting
EXPECT_EQ(aDerivedTransient.get(), aDerived.get());
EXPECT_EQ(anOtherTransient.get(), anOther.get());
}
TEST_F(HandleOperationsTest, HandleNullOperations)
{
Handle(TestDerived) aNullHandle;
Handle(TestDerived) anotherNullHandle;
Handle(TestDerived) aValidHandle = new TestDerived();
// Test null handle properties
EXPECT_TRUE(aNullHandle.IsNull());
EXPECT_EQ(nullptr, aNullHandle.get());
// Test null handle comparisons
EXPECT_TRUE(aNullHandle == anotherNullHandle); // Both null
EXPECT_FALSE(aNullHandle == aValidHandle); // Null vs valid
EXPECT_FALSE(aValidHandle == aNullHandle); // Valid vs null
EXPECT_FALSE(aNullHandle != anotherNullHandle); // Both null
EXPECT_TRUE(aNullHandle != aValidHandle); // Null vs valid
EXPECT_TRUE(aValidHandle != aNullHandle); // Valid vs null
// Test boolean conversion
EXPECT_FALSE(static_cast<bool>(aNullHandle));
EXPECT_TRUE(static_cast<bool>(aValidHandle));
}

View File

@@ -15,9 +15,6 @@
#include <Standard_Integer.hxx>
#include <gtest/gtest.h>
#include <algorithm>
#include <random>
#include <vector>
TEST(NCollection_Array1Test, DefaultConstructor)
{
@@ -343,73 +340,3 @@ TEST(NCollection_Array1Test, IteratorAccess)
index++;
}
}
TEST(NCollection_Array1Test, STLAlgorithmCompatibility_MinMax)
{
const Standard_Integer size = 100;
NCollection_Array1<Standard_Integer> anArray(1, size);
std::vector<Standard_Integer> aVector;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 1; anIdx <= size; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
anArray(anIdx) = aVal;
aVector.push_back(aVal);
}
auto aMinOCCT = std::min_element(anArray.begin(), anArray.end());
auto aMinStd = std::min_element(aVector.begin(), aVector.end());
auto aMaxOCCT = std::max_element(anArray.begin(), anArray.end());
auto aMaxStd = std::max_element(aVector.begin(), aVector.end());
EXPECT_EQ(*aMinOCCT, *aMinStd);
EXPECT_EQ(*aMaxOCCT, *aMaxStd);
}
TEST(NCollection_Array1Test, STLAlgorithmCompatibility_Replace)
{
const Standard_Integer size = 100;
NCollection_Array1<Standard_Integer> anArray(1, size);
std::vector<Standard_Integer> aVector;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 1; anIdx <= size; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
anArray(anIdx) = aVal;
aVector.push_back(aVal);
}
Standard_Integer aTargetValue = aVector.back();
Standard_Integer aNewValue = -1;
std::replace(anArray.begin(), anArray.end(), aTargetValue, aNewValue);
std::replace(aVector.begin(), aVector.end(), aTargetValue, aNewValue);
EXPECT_TRUE(std::equal(anArray.begin(), anArray.end(), aVector.begin()));
}
TEST(NCollection_Array1Test, STLAlgorithmCompatibility_Sort)
{
const Standard_Integer size = 100;
NCollection_Array1<Standard_Integer> anArray(1, size);
std::vector<Standard_Integer> aVector;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 1; anIdx <= size; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
anArray(anIdx) = aVal;
aVector.push_back(aVal);
}
std::sort(anArray.begin(), anArray.end());
std::sort(aVector.begin(), aVector.end());
EXPECT_TRUE(std::equal(anArray.begin(), anArray.end(), aVector.begin()));
}

View File

@@ -16,9 +16,6 @@
#include <TCollection_AsciiString.hxx>
#include <gtest/gtest.h>
#include <algorithm>
#include <vector>
#include <set>
// Test fixture for NCollection_DataMap tests
class NCollection_DataMapTest : public testing::Test
@@ -235,43 +232,3 @@ TEST_F(NCollection_DataMapTest, ExhaustiveIterator)
EXPECT_EQ(NUM_ELEMENTS, count);
}
TEST_F(NCollection_DataMapTest, STLAlgorithmCompatibility_MinMax)
{
NCollection_DataMap<Standard_Integer, Standard_Integer> aMap;
// Add some sequential values to make results predictable
for (Standard_Integer anIdx = 10; anIdx <= 50; anIdx += 5)
{
aMap.Bind(anIdx, anIdx * 2);
}
EXPECT_FALSE(aMap.IsEmpty());
// Test that STL algorithms work with OCCT iterators
auto aMinElement = std::min_element(aMap.cbegin(), aMap.cend());
auto aMaxElement = std::max_element(aMap.cbegin(), aMap.cend());
EXPECT_TRUE(aMinElement != aMap.cend());
EXPECT_TRUE(aMaxElement != aMap.cend());
EXPECT_LE(*aMinElement, *aMaxElement);
}
TEST_F(NCollection_DataMapTest, STLAlgorithmCompatibility_Find)
{
NCollection_DataMap<Standard_Integer, Standard_Integer> aMap;
// Add known values
aMap.Bind(100, 200);
aMap.Bind(200, 400);
aMap.Bind(300, 600);
// Test std::find compatibility
auto aFound = std::find(aMap.cbegin(), aMap.cend(), 200);
EXPECT_TRUE(aFound != aMap.cend());
EXPECT_EQ(*aFound, 200);
// Test finding non-existent value
auto aNotFound = std::find(aMap.cbegin(), aMap.cend(), 999);
EXPECT_TRUE(aNotFound == aMap.cend());
}

View File

@@ -15,8 +15,6 @@
#include <TCollection_AsciiString.hxx>
#include <gtest/gtest.h>
#include <algorithm>
#include <vector>
// Basic test types for the IndexedDataMap
typedef Standard_Integer KeyType;
@@ -705,43 +703,3 @@ TEST(NCollection_IndexedDataMapTest, ReSize)
EXPECT_DOUBLE_EQ(aMap.FindFromKey(i), static_cast<Standard_Real>(i) / 10.0);
}
}
TEST(NCollection_IndexedDataMapTest, STLAlgorithmCompatibility_MinMax)
{
NCollection_IndexedDataMap<Standard_Integer, Standard_Integer> aMap;
// Add some sequential values to make results predictable
for (Standard_Integer anIdx = 10; anIdx <= 50; anIdx += 5)
{
aMap.Add(anIdx, anIdx * 2);
}
EXPECT_FALSE(aMap.IsEmpty());
// Test that STL algorithms work with OCCT iterators
auto aMinElement = std::min_element(aMap.cbegin(), aMap.cend());
auto aMaxElement = std::max_element(aMap.cbegin(), aMap.cend());
EXPECT_TRUE(aMinElement != aMap.cend());
EXPECT_TRUE(aMaxElement != aMap.cend());
EXPECT_LE(*aMinElement, *aMaxElement);
}
TEST(NCollection_IndexedDataMapTest, STLAlgorithmCompatibility_Find)
{
NCollection_IndexedDataMap<Standard_Integer, Standard_Integer> aMap;
// Add known values
aMap.Add(100, 200);
aMap.Add(200, 400);
aMap.Add(300, 600);
// Test std::find compatibility
auto aFound = std::find(aMap.cbegin(), aMap.cend(), 200);
EXPECT_TRUE(aFound != aMap.cend());
EXPECT_EQ(*aFound, 200);
// Test finding non-existent value
auto aNotFound = std::find(aMap.cbegin(), aMap.cend(), 999);
EXPECT_TRUE(aNotFound == aMap.cend());
}

View File

@@ -15,9 +15,6 @@
#include <TCollection_AsciiString.hxx>
#include <gtest/gtest.h>
#include <algorithm>
#include <random>
#include <vector>
// Basic test type for the IndexedMap
typedef Standard_Integer KeyType;
@@ -514,52 +511,4 @@ TEST(NCollection_IndexedMapTest, ReSize)
EXPECT_EQ(aMap.FindIndex(i), i);
EXPECT_EQ(aMap.FindKey(i), i);
}
}
TEST(NCollection_IndexedMapTest, STLAlgorithmCompatibility_MinMax)
{
NCollection_IndexedMap<Standard_Integer> aMap;
std::vector<Standard_Integer> aVector;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 0; anIdx < 100; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
aMap.Add(aVal);
aVector.push_back(aVal);
}
auto aMinOCCT = std::min_element(aMap.cbegin(), aMap.cend());
auto aMinStd = std::min_element(aVector.begin(), aVector.end());
auto aMaxOCCT = std::max_element(aMap.cbegin(), aMap.cend());
auto aMaxStd = std::max_element(aVector.begin(), aVector.end());
EXPECT_EQ(*aMinOCCT, *aMinStd);
EXPECT_EQ(*aMaxOCCT, *aMaxStd);
}
TEST(NCollection_IndexedMapTest, STLAlgorithmCompatibility_Find)
{
NCollection_IndexedMap<Standard_Integer> aMap;
std::vector<Standard_Integer> aVector;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 0; anIdx < 100; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
aMap.Add(aVal);
aVector.push_back(aVal);
}
// Test std::find compatibility
Standard_Integer aSearchValue = aVector[10];
auto aFoundOCCT = std::find(aMap.cbegin(), aMap.cend(), aSearchValue);
auto aFoundStd = std::find(aVector.begin(), aVector.end(), aSearchValue);
EXPECT_TRUE(aFoundOCCT != aMap.cend());
EXPECT_TRUE(aFoundStd != aVector.end());
EXPECT_EQ(*aFoundOCCT, *aFoundStd);
}

View File

@@ -15,9 +15,6 @@
#include <Standard_Integer.hxx>
#include <gtest/gtest.h>
#include <algorithm>
#include <list>
#include <random>
// Test fixture for NCollection_List tests
class NCollection_ListTest : public testing::Test
@@ -402,51 +399,4 @@ TEST_F(NCollection_ListTest, Reverse)
EXPECT_EQ(20, it.Value());
it.Next();
EXPECT_EQ(10, it.Value());
}
TEST_F(NCollection_ListTest, STLAlgorithmCompatibility_MinMax)
{
NCollection_List<Standard_Integer> aList;
std::list<Standard_Integer> aStdList;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 0; anIdx < 100; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
aList.Append(aVal);
aStdList.push_back(aVal);
}
auto aMinOCCT = std::min_element(aList.begin(), aList.end());
auto aMinStd = std::min_element(aStdList.begin(), aStdList.end());
auto aMaxOCCT = std::max_element(aList.begin(), aList.end());
auto aMaxStd = std::max_element(aStdList.begin(), aStdList.end());
EXPECT_EQ(*aMinOCCT, *aMinStd);
EXPECT_EQ(*aMaxOCCT, *aMaxStd);
}
TEST_F(NCollection_ListTest, STLAlgorithmCompatibility_Replace)
{
NCollection_List<Standard_Integer> aList;
std::list<Standard_Integer> aStdList;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 0; anIdx < 100; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
aList.Append(aVal);
aStdList.push_back(aVal);
}
Standard_Integer aTargetValue = aStdList.back();
Standard_Integer aNewValue = -1;
std::replace(aList.begin(), aList.end(), aTargetValue, aNewValue);
std::replace(aStdList.begin(), aStdList.end(), aTargetValue, aNewValue);
EXPECT_TRUE(std::equal(aList.begin(), aList.end(), aStdList.begin()));
}

View File

@@ -1,164 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <NCollection_OccAllocator.hxx>
#include <NCollection_IncAllocator.hxx>
#include <Standard_Transient.hxx>
#include <Standard_Assert.hxx>
#include <gtest/gtest.h>
#include <list>
#include <vector>
// Test fixture for NCollection_OccAllocator tests
class NCollection_OccAllocatorTest : public testing::Test
{
protected:
void SetUp() override {}
void TearDown() override {}
};
TEST_F(NCollection_OccAllocatorTest, AllocatorTypeTraits)
{
// Test type definitions and static assertions (compile-time checks)
typedef Handle(Standard_Transient) anElemType;
typedef NCollection_OccAllocator<anElemType> anAllocatorType;
// These would fail to compile if the types were wrong
EXPECT_EQ(sizeof(anAllocatorType::value_type), sizeof(anElemType));
EXPECT_EQ(sizeof(anAllocatorType::pointer), sizeof(void*));
EXPECT_EQ(sizeof(anAllocatorType::const_pointer), sizeof(void*));
EXPECT_EQ(sizeof(anAllocatorType::size_type), sizeof(size_t));
EXPECT_EQ(sizeof(anAllocatorType::difference_type), sizeof(ptrdiff_t));
// Test reference types
anElemType aDummy;
anAllocatorType::reference aRef = aDummy;
anAllocatorType::const_reference aConstRef = aDummy;
// Basic checks that references work
EXPECT_EQ(&aRef, &aDummy);
EXPECT_EQ(&aConstRef, &aDummy);
// Test rebind functionality
typedef int anOtherElemType;
typedef anAllocatorType::rebind<anOtherElemType>::other anOtherAllocatorType;
EXPECT_EQ(sizeof(anOtherAllocatorType::value_type), sizeof(anOtherElemType));
}
TEST_F(NCollection_OccAllocatorTest, STLContainerIntegration)
{
// Create incremental allocator outside the scope of objects it will manage
Handle(NCollection_IncAllocator) anIncAlloc = new NCollection_IncAllocator();
{
// Test with std::list using typed allocator
NCollection_OccAllocator<int> anSAlloc(anIncAlloc);
std::list<int, NCollection_OccAllocator<int>> aList(anSAlloc);
aList.push_back(2);
EXPECT_EQ(1, aList.size());
EXPECT_EQ(2, aList.front());
// Test with std::vector using type cast
NCollection_OccAllocator<char> aCAlloc;
std::vector<int, NCollection_OccAllocator<int>> aVector(aCAlloc);
aVector.push_back(1);
EXPECT_EQ(1, aVector.size());
EXPECT_EQ(1, aVector[0]);
// Test using void-specialization allocator
NCollection_OccAllocator<void*> aVAlloc;
std::vector<int, NCollection_OccAllocator<int>> aVector2(aVAlloc);
aVector2.resize(10);
aVector2.push_back(-1);
EXPECT_EQ(11, aVector2.size());
EXPECT_EQ(-1, aVector2.back());
// Test equality of allocators
EXPECT_NE(anSAlloc, aCAlloc); // Different underlying allocators
NCollection_OccAllocator<int> anIAlloc(anIncAlloc);
EXPECT_EQ(anSAlloc, anIAlloc); // Same underlying allocator
}
}
TEST_F(NCollection_OccAllocatorTest, DefaultAllocator)
{
// Test default allocator behavior
NCollection_OccAllocator<int> aDefaultAlloc;
std::vector<int, NCollection_OccAllocator<int>> aVector(aDefaultAlloc);
// Fill with some data
for (int i = 0; i < 100; ++i)
{
aVector.push_back(i);
}
EXPECT_EQ(100, aVector.size());
// Verify data integrity
for (size_t i = 0; i < aVector.size(); ++i)
{
EXPECT_EQ(static_cast<int>(i), aVector[i]);
}
}
TEST_F(NCollection_OccAllocatorTest, AllocatorComparison)
{
Handle(NCollection_IncAllocator) anIncAlloc1 = new NCollection_IncAllocator();
Handle(NCollection_IncAllocator) anIncAlloc2 = new NCollection_IncAllocator();
NCollection_OccAllocator<int> aAlloc1(anIncAlloc1);
NCollection_OccAllocator<int> aAlloc2(anIncAlloc1); // Same underlying allocator
NCollection_OccAllocator<int> aAlloc3(anIncAlloc2); // Different underlying allocator
NCollection_OccAllocator<int> aAlloc4; // Default allocator
// Test equality
EXPECT_EQ(aAlloc1, aAlloc2); // Same underlying allocator
EXPECT_NE(aAlloc1, aAlloc3); // Different underlying allocator
EXPECT_NE(aAlloc1, aAlloc4); // One uses IncAllocator, one uses default
// Test inequality
EXPECT_FALSE(aAlloc1 != aAlloc2); // Should be equal
EXPECT_TRUE(aAlloc1 != aAlloc3); // Should be different
}
TEST_F(NCollection_OccAllocatorTest, CrossTypeCompatibility)
{
Handle(NCollection_IncAllocator) anIncAlloc = new NCollection_IncAllocator();
// Test allocators for different types but same underlying allocator
NCollection_OccAllocator<int> anIntAlloc(anIncAlloc);
NCollection_OccAllocator<double> aDoubleAlloc(anIncAlloc);
NCollection_OccAllocator<char> aCharAlloc(anIncAlloc);
// They should be considered equal despite different value types
// (This tests the allocator's rebind and comparison logic)
EXPECT_EQ(anIntAlloc, NCollection_OccAllocator<int>(anIncAlloc));
// Create containers with different allocators pointing to same IncAllocator
std::vector<int, NCollection_OccAllocator<int>> anIntVector(anIntAlloc);
std::vector<double, NCollection_OccAllocator<double>> aDoubleVector(aDoubleAlloc);
anIntVector.push_back(42);
aDoubleVector.push_back(3.14);
EXPECT_EQ(1, anIntVector.size());
EXPECT_EQ(1, aDoubleVector.size());
EXPECT_EQ(42, anIntVector[0]);
EXPECT_DOUBLE_EQ(3.14, aDoubleVector[0]);
}

View File

@@ -16,9 +16,6 @@
#include <NCollection_BaseAllocator.hxx>
#include <gtest/gtest.h>
#include <algorithm>
#include <list>
#include <random>
// Basic test type for the Sequence
typedef Standard_Integer ItemType;
@@ -375,68 +372,4 @@ TEST(NCollection_SequenceTest, MoveOperations)
EXPECT_TRUE(aSeq3.IsEmpty()); // Original sequence should be empty after move
EXPECT_EQ(aSeq4.Size(), 1);
EXPECT_EQ(aSeq4(1), 40);
}
TEST(NCollection_SequenceTest, STLAlgorithmCompatibility_MinMax)
{
NCollection_Sequence<Standard_Integer> aSequence;
std::list<Standard_Integer> aStdList;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 0; anIdx < 100; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
aSequence.Append(aVal);
aStdList.push_back(aVal);
}
auto aMinOCCT = std::min_element(aSequence.begin(), aSequence.end());
auto aMinStd = std::min_element(aStdList.begin(), aStdList.end());
auto aMaxOCCT = std::max_element(aSequence.begin(), aSequence.end());
auto aMaxStd = std::max_element(aStdList.begin(), aStdList.end());
EXPECT_EQ(*aMinOCCT, *aMinStd);
EXPECT_EQ(*aMaxOCCT, *aMaxStd);
}
TEST(NCollection_SequenceTest, STLAlgorithmCompatibility_Replace)
{
NCollection_Sequence<Standard_Integer> aSequence;
std::list<Standard_Integer> aStdList;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 0; anIdx < 100; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
aSequence.Append(aVal);
aStdList.push_back(aVal);
}
Standard_Integer aTargetValue = aStdList.back();
Standard_Integer aNewValue = -1;
std::replace(aSequence.begin(), aSequence.end(), aTargetValue, aNewValue);
std::replace(aStdList.begin(), aStdList.end(), aTargetValue, aNewValue);
EXPECT_TRUE(std::equal(aSequence.begin(), aSequence.end(), aStdList.begin()));
}
TEST(NCollection_SequenceTest, STLAlgorithmCompatibility_Reverse)
{
NCollection_Sequence<Standard_Integer> aSequence;
std::list<Standard_Integer> aStdList;
for (Standard_Integer anIdx = 0; anIdx < 100; ++anIdx)
{
aSequence.Append(anIdx);
aStdList.push_back(anIdx);
}
std::reverse(aSequence.begin(), aSequence.end());
std::reverse(aStdList.begin(), aStdList.end());
EXPECT_TRUE(std::equal(aSequence.begin(), aSequence.end(), aStdList.begin()));
}

View File

@@ -1,131 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <NCollection_Vec4.hxx>
#include <NCollection_Vec3.hxx>
#include <NCollection_Mat4.hxx>
#include <gtest/gtest.h>
#include <cmath>
// Test fixture for NCollection_Vec4 tests
class NCollection_Vec4Test : public testing::Test
{
protected:
void SetUp() override {}
void TearDown() override {}
};
TEST_F(NCollection_Vec4Test, BasicConstruction)
{
// Test default constructor
NCollection_Vec4<float> aVec1;
EXPECT_EQ(0.0f, aVec1.x());
EXPECT_EQ(0.0f, aVec1.y());
EXPECT_EQ(0.0f, aVec1.z());
EXPECT_EQ(0.0f, aVec1.w());
// Test parameterized constructor
NCollection_Vec4<float> aVec2(1.0f, 2.0f, 3.0f, 4.0f);
EXPECT_EQ(1.0f, aVec2.x());
EXPECT_EQ(2.0f, aVec2.y());
EXPECT_EQ(3.0f, aVec2.z());
EXPECT_EQ(4.0f, aVec2.w());
}
TEST_F(NCollection_Vec4Test, XyzMethod)
{
NCollection_Vec4<float> aVec(2.0f, 3.0f, 4.0f, 5.0f);
NCollection_Vec3<float> aVec3 = aVec.xyz();
EXPECT_EQ(2.0f, aVec3.x());
EXPECT_EQ(3.0f, aVec3.y());
EXPECT_EQ(4.0f, aVec3.z());
}
TEST_F(NCollection_Vec4Test, MatrixMultiplicationAndTransformation)
{
// Test matrix multiplication and xyz() method with translation
NCollection_Mat4<float> aMatrix;
aMatrix.Translate(NCollection_Vec3<float>(4.0f, 3.0f, 1.0f));
// Create a cube of points (-1,-1,-1) to (1,1,1)
NCollection_Vec4<float> aPoints1[8];
for (int aX = 0; aX < 2; ++aX)
{
for (int aY = 0; aY < 2; ++aY)
{
for (int aZ = 0; aZ < 2; ++aZ)
{
aPoints1[aX * 2 * 2 + aY * 2 + aZ] = NCollection_Vec4<float>(-1.0f + 2.0f * float(aX),
-1.0f + 2.0f * float(aY),
-1.0f + 2.0f * float(aZ),
1.0f);
}
}
}
// Apply transformation and convert to Vec3
NCollection_Vec3<float> aPoints2[8];
for (int aPntIdx = 0; aPntIdx < 8; ++aPntIdx)
{
aPoints1[aPntIdx] = aMatrix * aPoints1[aPntIdx];
aPoints2[aPntIdx] = aPoints1[aPntIdx].xyz() / aPoints1[aPntIdx].w();
}
// Check that the transformation worked correctly
// The last point should be (1,1,1) transformed by translation (4,3,1) -> (5,4,2)
// SquareModulus of (5,4,2) = 25 + 16 + 4 = 45
float aSquareModulus = aPoints2[7].SquareModulus();
EXPECT_NEAR(45.0f, aSquareModulus, 0.001f);
// Check that all points were translated correctly
// Point (0,0,0) -> translate by (4,3,1) -> (4,3,1)
// Point index 0 corresponds to (-1,-1,-1) -> (3,2,0)
float aExpectedSquareMod0 = 3.0f * 3.0f + 2.0f * 2.0f + 0.0f * 0.0f; // 9 + 4 + 0 = 13
EXPECT_NEAR(aExpectedSquareMod0, aPoints2[0].SquareModulus(), 0.001f);
}
TEST_F(NCollection_Vec4Test, ComponentAccess)
{
NCollection_Vec4<float> aVec(1.5f, 2.5f, 3.5f, 4.5f);
// Test read access
EXPECT_EQ(1.5f, aVec.x());
EXPECT_EQ(2.5f, aVec.y());
EXPECT_EQ(3.5f, aVec.z());
EXPECT_EQ(4.5f, aVec.w());
// Test write access
aVec.x() = 10.0f;
aVec.y() = 20.0f;
aVec.z() = 30.0f;
aVec.w() = 40.0f;
EXPECT_EQ(10.0f, aVec.x());
EXPECT_EQ(20.0f, aVec.y());
EXPECT_EQ(30.0f, aVec.z());
EXPECT_EQ(40.0f, aVec.w());
}
TEST_F(NCollection_Vec4Test, HomogeneousCoordinateDivision)
{
// Test perspective division using w component
NCollection_Vec4<float> aVec(8.0f, 12.0f, 16.0f, 4.0f);
NCollection_Vec3<float> aResult = aVec.xyz() / aVec.w();
EXPECT_EQ(2.0f, aResult.x()); // 8/4 = 2
EXPECT_EQ(3.0f, aResult.y()); // 12/4 = 3
EXPECT_EQ(4.0f, aResult.z()); // 16/4 = 4
}

View File

@@ -16,9 +16,6 @@
#include <Standard_Integer.hxx>
#include <gtest/gtest.h>
#include <algorithm>
#include <random>
#include <vector>
TEST(NCollection_VectorTest, DefaultConstructor)
{
@@ -382,88 +379,4 @@ TEST(NCollection_VectorTest, SetIncrement)
{
EXPECT_EQ(i, aVector(i));
}
}
TEST(NCollection_VectorTest, STLAlgorithmCompatibility_MinMax)
{
NCollection_Vector<Standard_Integer> aVector;
std::vector<Standard_Integer> aStdVector;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 0; anIdx < 100; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
aVector.Append(aVal);
aStdVector.push_back(aVal);
}
auto aMinOCCT = std::min_element(aVector.begin(), aVector.end());
auto aMinStd = std::min_element(aStdVector.begin(), aStdVector.end());
auto aMaxOCCT = std::max_element(aVector.begin(), aVector.end());
auto aMaxStd = std::max_element(aStdVector.begin(), aStdVector.end());
EXPECT_EQ(*aMinOCCT, *aMinStd);
EXPECT_EQ(*aMaxOCCT, *aMaxStd);
}
TEST(NCollection_VectorTest, STLAlgorithmCompatibility_Replace)
{
NCollection_Vector<Standard_Integer> aVector;
std::vector<Standard_Integer> aStdVector;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 0; anIdx < 100; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
aVector.Append(aVal);
aStdVector.push_back(aVal);
}
Standard_Integer aTargetValue = aStdVector.back();
Standard_Integer aNewValue = -1;
std::replace(aVector.begin(), aVector.end(), aTargetValue, aNewValue);
std::replace(aStdVector.begin(), aStdVector.end(), aTargetValue, aNewValue);
EXPECT_TRUE(std::equal(aVector.begin(), aVector.end(), aStdVector.begin()));
}
TEST(NCollection_VectorTest, STLAlgorithmCompatibility_Reverse)
{
NCollection_Vector<Standard_Integer> aVector;
std::vector<Standard_Integer> aStdVector;
for (Standard_Integer anIdx = 0; anIdx < 100; ++anIdx)
{
aVector.Append(anIdx);
aStdVector.push_back(anIdx);
}
std::reverse(aVector.begin(), aVector.end());
std::reverse(aStdVector.begin(), aStdVector.end());
EXPECT_TRUE(std::equal(aVector.begin(), aVector.end(), aStdVector.begin()));
}
TEST(NCollection_VectorTest, STLAlgorithmCompatibility_Sort)
{
NCollection_Vector<Standard_Integer> aVector;
std::vector<Standard_Integer> aStdVector;
std::mt19937 aGenerator(1); // Fixed seed for reproducible tests
std::uniform_int_distribution<Standard_Integer> aDistribution(0, RAND_MAX);
for (Standard_Integer anIdx = 0; anIdx < 100; ++anIdx)
{
Standard_Integer aVal = aDistribution(aGenerator);
aVector.Append(aVal);
aStdVector.push_back(aVal);
}
std::sort(aVector.begin(), aVector.end());
std::sort(aStdVector.begin(), aStdVector.end());
EXPECT_TRUE(std::equal(aVector.begin(), aVector.end(), aStdVector.begin()));
}

View File

@@ -1,246 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <OSD_Path.hxx>
#include <TCollection_AsciiString.hxx>
#include <gtest/gtest.h>
// Test fixture for OSD_Path tests
class OSD_PathTest : public testing::Test
{
protected:
void SetUp() override {}
void TearDown() override {}
};
TEST_F(OSD_PathTest, DosAbsolutePaths)
{
// Test DOS absolute paths
EXPECT_TRUE(OSD_Path::IsAbsolutePath("c:\\folder\\file.png"));
EXPECT_TRUE(OSD_Path::IsDosPath("c:\\folder\\file.png"));
EXPECT_FALSE(OSD_Path::IsRelativePath("c:\\folder\\file.png"));
EXPECT_FALSE(OSD_Path::IsUnixPath("c:\\folder\\file.png"));
EXPECT_FALSE(OSD_Path::IsUncPath("c:\\folder\\file.png"));
// Test DOS root
EXPECT_TRUE(OSD_Path::IsAbsolutePath("D:\\"));
EXPECT_TRUE(OSD_Path::IsDosPath("D:\\"));
// Test single file on DOS drive
EXPECT_TRUE(OSD_Path::IsAbsolutePath("c:\\file.png"));
EXPECT_TRUE(OSD_Path::IsDosPath("c:\\file.png"));
}
TEST_F(OSD_PathTest, UncPaths)
{
// Test UNC paths
EXPECT_TRUE(OSD_Path::IsAbsolutePath("\\\\share\\file.pdf"));
EXPECT_TRUE(OSD_Path::IsUncPath("\\\\share\\file.pdf"));
EXPECT_FALSE(OSD_Path::IsDosPath("\\\\share\\file.pdf"));
EXPECT_FALSE(OSD_Path::IsUnixPath("\\\\share\\file.pdf"));
}
TEST_F(OSD_PathTest, NtExtendedPaths)
{
// Test NT Extended paths
EXPECT_TRUE(OSD_Path::IsAbsolutePath("\\\\?\\C:\\documents\\file.docx"));
EXPECT_TRUE(OSD_Path::IsNtExtendedPath("\\\\?\\C:\\documents\\file.docx"));
EXPECT_FALSE(OSD_Path::IsUncPath("\\\\?\\C:\\documents\\file.docx"));
}
TEST_F(OSD_PathTest, UncExtendedPaths)
{
// Test UNC Extended paths
EXPECT_TRUE(OSD_Path::IsAbsolutePath("\\\\?\\UNC\\server\\share\\file.zip"));
EXPECT_TRUE(OSD_Path::IsUncPath("\\\\?\\UNC\\server\\share\\file.zip"));
EXPECT_TRUE(OSD_Path::IsNtExtendedPath("\\\\?\\UNC\\server\\share\\file.zip"));
EXPECT_TRUE(OSD_Path::IsUncExtendedPath("\\\\?\\UNC\\server\\share\\file.zip"));
}
TEST_F(OSD_PathTest, RemoteProtocolPaths)
{
// Test remote protocol paths
EXPECT_TRUE(OSD_Path::IsAbsolutePath("https://www.server.org/file.gif"));
EXPECT_TRUE(OSD_Path::IsRemoteProtocolPath("https://www.server.org/file.gif"));
EXPECT_FALSE(OSD_Path::IsUnixPath("https://www.server.org/file.gif"));
EXPECT_FALSE(OSD_Path::IsDosPath("https://www.server.org/file.gif"));
// Test other protocols
EXPECT_TRUE(OSD_Path::IsAbsolutePath("ftp://ftp.server.com/file.dat"));
EXPECT_TRUE(OSD_Path::IsRemoteProtocolPath("ftp://ftp.server.com/file.dat"));
EXPECT_TRUE(OSD_Path::IsAbsolutePath("http://example.com/path"));
EXPECT_TRUE(OSD_Path::IsRemoteProtocolPath("http://example.com/path"));
}
TEST_F(OSD_PathTest, ContentProtocolPaths)
{
// Test content protocol paths
EXPECT_TRUE(OSD_Path::IsAbsolutePath("content://file.jpg"));
EXPECT_TRUE(OSD_Path::IsRemoteProtocolPath("content://file.jpg"));
EXPECT_TRUE(OSD_Path::IsContentProtocolPath("content://file.jpg"));
}
TEST_F(OSD_PathTest, UnixAbsolutePaths)
{
// Test Unix absolute paths
EXPECT_TRUE(OSD_Path::IsAbsolutePath("/home/username/file.txt"));
EXPECT_TRUE(OSD_Path::IsUnixPath("/home/username/file.txt"));
EXPECT_FALSE(OSD_Path::IsRelativePath("/home/username/file.txt"));
EXPECT_FALSE(OSD_Path::IsDosPath("/home/username/file.txt"));
// Test Unix root
EXPECT_TRUE(OSD_Path::IsAbsolutePath("/"));
EXPECT_TRUE(OSD_Path::IsUnixPath("/"));
// Test single file on Unix
EXPECT_TRUE(OSD_Path::IsAbsolutePath("/boot.bin"));
EXPECT_TRUE(OSD_Path::IsUnixPath("/boot.bin"));
}
TEST_F(OSD_PathTest, RelativePaths)
{
// Test relative paths with navigation
EXPECT_TRUE(OSD_Path::IsRelativePath("./subfolder/../file.txt"));
EXPECT_FALSE(OSD_Path::IsAbsolutePath("./subfolder/../file.txt"));
EXPECT_TRUE(OSD_Path::IsRelativePath("../file.txt"));
EXPECT_FALSE(OSD_Path::IsAbsolutePath("../file.txt"));
// Test current directory
EXPECT_TRUE(OSD_Path::IsRelativePath("."));
EXPECT_FALSE(OSD_Path::IsAbsolutePath("."));
// Test parent directory
EXPECT_TRUE(OSD_Path::IsRelativePath(".."));
EXPECT_FALSE(OSD_Path::IsAbsolutePath(".."));
// Test simple relative path
EXPECT_TRUE(OSD_Path::IsRelativePath("folder/file.txt"));
EXPECT_FALSE(OSD_Path::IsAbsolutePath("folder/file.txt"));
// Test simple filename
EXPECT_TRUE(OSD_Path::IsRelativePath("file.txt"));
EXPECT_FALSE(OSD_Path::IsAbsolutePath("file.txt"));
}
TEST_F(OSD_PathTest, FolderAndFileFromPath_UnixPaths)
{
TCollection_AsciiString aFolder, aFileName;
// Test Unix absolute path
OSD_Path::FolderAndFileFromPath("/home/username/file.txt", aFolder, aFileName);
EXPECT_STREQ("/home/username/", aFolder.ToCString());
EXPECT_STREQ("file.txt", aFileName.ToCString());
// Test Unix root file
OSD_Path::FolderAndFileFromPath("/file.txt", aFolder, aFileName);
EXPECT_STREQ("/", aFolder.ToCString());
EXPECT_STREQ("file.txt", aFileName.ToCString());
// Test Unix folder only (trailing slash)
OSD_Path::FolderAndFileFromPath("/home/username/", aFolder, aFileName);
EXPECT_STREQ("/home/username/", aFolder.ToCString());
EXPECT_STREQ("", aFileName.ToCString());
}
TEST_F(OSD_PathTest, FolderAndFileFromPath_DosPaths)
{
TCollection_AsciiString aFolder, aFileName;
// Test DOS absolute path
OSD_Path::FolderAndFileFromPath("C:\\Users\\John\\document.txt", aFolder, aFileName);
EXPECT_STREQ("C:\\Users\\John\\", aFolder.ToCString());
EXPECT_STREQ("document.txt", aFileName.ToCString());
// Test DOS root file
OSD_Path::FolderAndFileFromPath("C:\\file.txt", aFolder, aFileName);
EXPECT_STREQ("C:\\", aFolder.ToCString());
EXPECT_STREQ("file.txt", aFileName.ToCString());
// Test DOS folder only (trailing backslash)
OSD_Path::FolderAndFileFromPath("C:\\Program Files\\", aFolder, aFileName);
EXPECT_STREQ("C:\\Program Files\\", aFolder.ToCString());
EXPECT_STREQ("", aFileName.ToCString());
}
TEST_F(OSD_PathTest, FolderAndFileFromPath_RelativePaths)
{
TCollection_AsciiString aFolder, aFileName;
// Test relative path
OSD_Path::FolderAndFileFromPath("folder/subfolder/file.txt", aFolder, aFileName);
EXPECT_STREQ("folder/subfolder/", aFolder.ToCString());
EXPECT_STREQ("file.txt", aFileName.ToCString());
// Test relative with navigation
OSD_Path::FolderAndFileFromPath("../folder/file.txt", aFolder, aFileName);
EXPECT_STREQ("../folder/", aFolder.ToCString());
EXPECT_STREQ("file.txt", aFileName.ToCString());
// Test just filename
OSD_Path::FolderAndFileFromPath("file.txt", aFolder, aFileName);
EXPECT_STREQ("", aFolder.ToCString());
EXPECT_STREQ("file.txt", aFileName.ToCString());
}
TEST_F(OSD_PathTest, FolderAndFileFromPath_ProtocolPaths)
{
TCollection_AsciiString aFolder, aFileName;
// Test HTTPS path
OSD_Path::FolderAndFileFromPath("https://www.server.org/folder/file.gif", aFolder, aFileName);
EXPECT_STREQ("https://www.server.org/folder/", aFolder.ToCString());
EXPECT_STREQ("file.gif", aFileName.ToCString());
// Test content protocol
OSD_Path::FolderAndFileFromPath("content://path/file.jpg", aFolder, aFileName);
EXPECT_STREQ("content://path/", aFolder.ToCString());
EXPECT_STREQ("file.jpg", aFileName.ToCString());
}
TEST_F(OSD_PathTest, EdgeCases)
{
TCollection_AsciiString aFolder, aFileName;
// Test empty path
OSD_Path::FolderAndFileFromPath("", aFolder, aFileName);
EXPECT_STREQ("", aFolder.ToCString());
EXPECT_STREQ("", aFileName.ToCString());
// Test just separator
OSD_Path::FolderAndFileFromPath("/", aFolder, aFileName);
EXPECT_STREQ("/", aFolder.ToCString());
EXPECT_STREQ("", aFileName.ToCString());
OSD_Path::FolderAndFileFromPath("\\", aFolder, aFileName);
EXPECT_STREQ("\\", aFolder.ToCString());
EXPECT_STREQ("", aFileName.ToCString());
// Test path with no file extension
OSD_Path::FolderAndFileFromPath("/home/username/foldername", aFolder, aFileName);
EXPECT_STREQ("/home/username/", aFolder.ToCString());
EXPECT_STREQ("foldername", aFileName.ToCString());
}
TEST_F(OSD_PathTest, MixedSeparators)
{
TCollection_AsciiString aFolder, aFileName;
// Test mixed separators (this might happen in cross-platform scenarios)
OSD_Path::FolderAndFileFromPath("C:/Users/John\\Documents/file.txt", aFolder, aFileName);
// The exact behavior might depend on implementation, but it should handle this gracefully
EXPECT_FALSE(aFolder.IsEmpty() || aFileName.IsEmpty());
}

View File

@@ -1,354 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Standard_ArrayStreamBuffer.hxx>
#include <gtest/gtest.h>
#include <sstream>
#include <string>
TEST(Standard_ArrayStreamBufferTest, ConstructorAndBasicUsage)
{
const char* aTestData = "Hello, World!";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
std::string aResult;
aStream >> aResult;
EXPECT_EQ("Hello,", aResult);
}
TEST(Standard_ArrayStreamBufferTest, InitMethod)
{
const char* aTestData1 = "First data";
const char* aTestData2 = "Second data";
const size_t aDataSize1 = strlen(aTestData1);
const size_t aDataSize2 = strlen(aTestData2);
Standard_ArrayStreamBuffer aBuffer(aTestData1, aDataSize1);
std::istream aStream(&aBuffer);
std::string aResult1;
aStream >> aResult1;
EXPECT_EQ("First", aResult1);
aBuffer.Init(aTestData2, aDataSize2);
aStream.clear();
aStream.seekg(0);
std::string aResult2;
aStream >> aResult2;
EXPECT_EQ("Second", aResult2);
}
TEST(Standard_ArrayStreamBufferTest, ReadFullContent)
{
const char* aTestData = "Hello World";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
std::string aResult;
std::getline(aStream, aResult);
EXPECT_EQ("Hello World", aResult);
}
TEST(Standard_ArrayStreamBufferTest, CharacterByCharacterRead)
{
const char* aTestData = "ABC";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
char aCh1, aCh2, aCh3, aCh4;
aStream >> aCh1 >> aCh2 >> aCh3;
EXPECT_EQ('A', aCh1);
EXPECT_EQ('B', aCh2);
EXPECT_EQ('C', aCh3);
EXPECT_TRUE(aStream.good());
aStream >> aCh4;
EXPECT_TRUE(aStream.eof());
}
TEST(Standard_ArrayStreamBufferTest, SeekFromBeginning)
{
const char* aTestData = "0123456789";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
aStream.seekg(5, std::ios::beg);
char aCh;
aStream >> aCh;
EXPECT_EQ('5', aCh);
}
TEST(Standard_ArrayStreamBufferTest, SeekFromEnd)
{
const char* aTestData = "0123456789";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
// Position to 3 characters before the end
// String: "0123456789" (length 10)
// Position 7 should give us character '7'
aStream.seekg(7, std::ios::beg);
char aCh;
aStream >> aCh;
EXPECT_EQ('7', aCh);
}
TEST(Standard_ArrayStreamBufferTest, SeekFromCurrent)
{
const char* aTestData = "0123456789";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
aStream.seekg(2, std::ios::beg);
aStream.seekg(3, std::ios::cur);
char aCh;
aStream >> aCh;
EXPECT_EQ('5', aCh);
}
TEST(Standard_ArrayStreamBufferTest, TellPosition)
{
const char* aTestData = "0123456789";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
EXPECT_EQ(0, aStream.tellg());
aStream.seekg(5);
EXPECT_EQ(5, aStream.tellg());
char aCh;
aStream >> aCh;
EXPECT_EQ(6, aStream.tellg());
}
TEST(Standard_ArrayStreamBufferTest, ReadBeyondBuffer)
{
const char* aTestData = "ABC";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
aStream.seekg(10);
char aCh;
aStream >> aCh;
EXPECT_TRUE(aStream.eof());
}
TEST(Standard_ArrayStreamBufferTest, EmptyBuffer)
{
const char* aTestData = "";
const size_t aDataSize = 0;
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
char aCh;
aStream >> aCh;
EXPECT_TRUE(aStream.eof());
}
TEST(Standard_ArrayStreamBufferTest, NullPointerBuffer)
{
Standard_ArrayStreamBuffer aBuffer(nullptr, 0);
std::istream aStream(&aBuffer);
char aCh;
aStream >> aCh;
EXPECT_TRUE(aStream.eof());
}
TEST(Standard_ArrayStreamBufferTest, BinaryData)
{
const char aBinaryData[] = {0x01, 0x02, 0x03, 0x00, 0x04, 0x05};
const size_t aDataSize = sizeof(aBinaryData);
Standard_ArrayStreamBuffer aBuffer(aBinaryData, aDataSize);
std::istream aStream(&aBuffer);
char aByte1, aByte2, aByte3, aByte4, aByte5, aByte6;
aStream.read(&aByte1, 1);
aStream.read(&aByte2, 1);
aStream.read(&aByte3, 1);
aStream.read(&aByte4, 1);
aStream.read(&aByte5, 1);
aStream.read(&aByte6, 1);
EXPECT_EQ(0x01, static_cast<unsigned char>(aByte1));
EXPECT_EQ(0x02, static_cast<unsigned char>(aByte2));
EXPECT_EQ(0x03, static_cast<unsigned char>(aByte3));
EXPECT_EQ(0x00, static_cast<unsigned char>(aByte4));
EXPECT_EQ(0x04, static_cast<unsigned char>(aByte5));
EXPECT_EQ(0x05, static_cast<unsigned char>(aByte6));
}
TEST(Standard_ArrayStreamBufferTest, LargeBuffer)
{
const size_t aLargeSize = 10000;
std::string aLargeData(aLargeSize, 'X');
Standard_ArrayStreamBuffer aBuffer(aLargeData.c_str(), aLargeData.size());
std::istream aStream(&aBuffer);
aStream.seekg(aLargeSize / 2);
char aCh;
aStream >> aCh;
EXPECT_EQ('X', aCh);
EXPECT_EQ((aLargeSize / 2) + 1, static_cast<size_t>(aStream.tellg()));
}
TEST(Standard_ArrayStreamBufferTest, MultipleReads)
{
const char* aTestData = "Line1\nLine2\nLine3";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
std::string aLine1, aLine2, aLine3;
std::getline(aStream, aLine1);
std::getline(aStream, aLine2);
std::getline(aStream, aLine3);
EXPECT_EQ("Line1", aLine1);
EXPECT_EQ("Line2", aLine2);
EXPECT_EQ("Line3", aLine3);
}
TEST(Standard_ArrayStreamBufferTest, SeekToSpecificPosition)
{
const char* aTestData = "0123456789";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
aStream.seekg(7);
char aCh;
aStream >> aCh;
EXPECT_EQ('7', aCh);
EXPECT_EQ(8, aStream.tellg());
}
TEST(Standard_ArrayStreamBufferTest, ReadAfterSeekToEnd)
{
const char* aTestData = "Hello";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
aStream.seekg(0, std::ios::end);
char aCh;
aStream >> aCh;
EXPECT_TRUE(aStream.eof());
}
TEST(Standard_ArrayStreamBufferTest, BackwardSeek)
{
const char* aTestData = "0123456789";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
aStream.seekg(0, std::ios::end);
aStream.seekg(-5, std::ios::cur);
char aCh;
aStream >> aCh;
EXPECT_EQ('5', aCh);
}
TEST(Standard_ArrayStreamBufferTest, MultilineContent)
{
const char* aTestData = "First line\nSecond line\nThird line";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
std::string aContent;
std::getline(aStream, aContent, '\0');
EXPECT_EQ("First line\nSecond line\nThird line", aContent);
}
TEST(Standard_ArrayStreamBufferTest, ReadBlock)
{
const char* aTestData = "ABCDEFGHIJ";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
char aBlock[5];
aStream.read(aBlock, 4);
aBlock[4] = '\0';
EXPECT_EQ(std::string("ABCD"), std::string(aBlock));
EXPECT_EQ(4, aStream.gcount());
}
TEST(Standard_ArrayStreamBufferTest, AvailableCharacters)
{
const char* aTestData = "Testing";
const size_t aDataSize = strlen(aTestData);
Standard_ArrayStreamBuffer aBuffer(aTestData, aDataSize);
std::istream aStream(&aBuffer);
std::streamsize anAvailable = aBuffer.in_avail();
EXPECT_EQ(static_cast<std::streamsize>(aDataSize), anAvailable);
char aCh;
aStream >> aCh;
anAvailable = aBuffer.in_avail();
EXPECT_EQ(static_cast<std::streamsize>(aDataSize - 1), anAvailable);
}

View File

@@ -50,6 +50,8 @@ set(OCCT_OSD_FILES
OSD_LocalFileSystem.cxx
OSD_LocalFileSystem.hxx
OSD_LockType.hxx
OSD_MAllocHook.cxx
OSD_MAllocHook.hxx
OSD_MemInfo.cxx
OSD_MemInfo.hxx
OSD_OEMType.hxx

View File

@@ -0,0 +1,545 @@
// Created on: 2011-02-04
// Created by: Mikhail SAZONOV
// Copyright (c) 2011-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <OSD_MAllocHook.hxx>
#ifndef _MSC_VER
#if !defined __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include <stdint.h>
#endif
#include <set>
#include <map>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#ifndef SIZE_MAX
#define SIZE_MAX UINT_MAX
#endif
#define MAX_STR 80
static OSD_MAllocHook::Callback* MypCurrentCallback = NULL;
namespace
{
// dummy function to call at place where break point might be needed
static unsigned debug_counter = 0;
inline void place_for_breakpoint()
{
// this statement is just to have any instruction in object code,
// otherwise compiler does not leave a place for break point
debug_counter++;
}
} // namespace
//=================================================================================================
OSD_MAllocHook::Callback* OSD_MAllocHook::GetCallback()
{
return MypCurrentCallback;
}
//=================================================================================================
OSD_MAllocHook::LogFileHandler* OSD_MAllocHook::GetLogFileHandler()
{
static LogFileHandler MyHandler;
return &MyHandler;
}
//=================================================================================================
OSD_MAllocHook::CollectBySize* OSD_MAllocHook::GetCollectBySize()
{
static CollectBySize MyHandler;
return &MyHandler;
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Platform-dependent methods
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#ifdef _MSC_VER
#include <crtdbg.h>
#if _MSC_VER >= 1500 /* VS 2008 */
static long getRequestNum(void* pvData, long lRequest, size_t& theSize)
{
#ifdef _DEBUG /* protect against invalid pointer; in Release, _CrtIsValidHeapPointer is always \
1 */
if (!_CrtIsValidHeapPointer(pvData))
return lRequest;
#else
(void)lRequest; // avoid compiler warning on unused arg
#endif
#define nNoMansLandSize 4
// the header struct is taken from crt/src/dbgint.h
struct _CrtMemBlockHeader
{
#ifdef _WIN64
int nBlockUse;
size_t nDataSize;
#else
size_t nDataSize;
int nBlockUse;
#endif
long lRequest;
unsigned char gap[nNoMansLandSize];
};
_CrtMemBlockHeader* aHeader = ((_CrtMemBlockHeader*)pvData) - 1;
theSize = aHeader->nDataSize;
return aHeader->lRequest;
}
#else /* _MSC_VER < 1500 */
static long getRequestNum(void* /*pvData*/, long lRequest, size_t& /*theSize*/)
{
return lRequest;
}
#endif /* _MSC_VER == 1500 */
int __cdecl MyAllocHook(int nAllocType,
void* pvData,
size_t nSize,
int nBlockUse,
long lRequest,
const unsigned char* /*szFileName*/,
int /*nLine*/)
{
if (nBlockUse == _CRT_BLOCK || // Ignore internal C runtime library allocations
MypCurrentCallback == NULL)
return (1);
if (nAllocType == _HOOK_ALLOC)
MypCurrentCallback->AllocEvent(nSize, lRequest);
else if (nAllocType == _HOOK_FREE)
{
// for free hook, lRequest is not defined,
// but we can take it from the CRT mem block header
size_t aSize = 0;
lRequest = getRequestNum(pvData, lRequest, aSize);
MypCurrentCallback->FreeEvent(pvData, aSize, lRequest);
}
else // _HOOK_REALLOC
{
// for realloc hook, lRequest shows the new request,
// and we should get request number for old block
size_t anOldSize = 0;
long anOldRequest = getRequestNum(pvData, 0, anOldSize);
MypCurrentCallback->FreeEvent(pvData, anOldSize, anOldRequest);
MypCurrentCallback->AllocEvent(nSize, lRequest);
}
return (1); // Allow the memory operation to proceed
}
//=================================================================================================
void OSD_MAllocHook::SetCallback(Callback* theCB)
{
MypCurrentCallback = theCB;
if (theCB == NULL)
_CrtSetAllocHook(NULL);
else
_CrtSetAllocHook(MyAllocHook);
}
#else // ! _MSC_VER
// Not yet implemented for non-WNT platform
void OSD_MAllocHook::SetCallback(Callback* theCB)
{
MypCurrentCallback = theCB;
}
#endif // _MSC_VER
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// LogFileHandler handler methods
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//=================================================================================================
OSD_MAllocHook::LogFileHandler::LogFileHandler()
: myBreakSize(0)
{
myLogFile.imbue(std::locale("C"));
}
//=================================================================================================
OSD_MAllocHook::LogFileHandler::~LogFileHandler()
{
Close();
}
//=================================================================================================
Standard_Boolean OSD_MAllocHook::LogFileHandler::Open(const char* theFileName)
{
Close();
myLogFile.open(theFileName);
if (!myLogFile.is_open())
{
return Standard_False;
}
myLogFile << "Operation type; Request Number; Block Size\n"
"------------------------------------------\n";
return Standard_True;
}
//=================================================================================================
void OSD_MAllocHook::LogFileHandler::Close()
{
if (myLogFile.is_open())
{
myLogFile.close();
}
}
//=================================================================================================
namespace
{
struct StorageInfo
{
Standard_Size size;
Standard_Integer nbAlloc;
Standard_Integer nbFree;
Standard_Integer nbLeftPeak;
std::set<unsigned long> alive;
StorageInfo(Standard_Size theSize = 0)
: size(theSize),
nbAlloc(0),
nbFree(0),
nbLeftPeak(0),
alive()
{
}
bool operator<(const StorageInfo& theOther) const { return size < theOther.size; }
};
} // namespace
Standard_Boolean OSD_MAllocHook::LogFileHandler::MakeReport(const char* theLogFile,
const char* theOutFile,
const Standard_Boolean theIncludeAlive)
{
// open log file
FILE* aLogFile = fopen(theLogFile, "r");
if (aLogFile == NULL)
return Standard_False;
// skip 2 header lines
char aStr[MAX_STR];
if (fgets(aStr, MAX_STR - 1, aLogFile) == NULL)
{
fclose(aLogFile);
return Standard_False;
}
if (fgets(aStr, MAX_STR - 1, aLogFile) == NULL)
{
fclose(aLogFile);
return Standard_False;
}
// scan the log file
size_t aTotalLeftSize = 0;
size_t aTotalPeakSize = 0;
std::set<StorageInfo> aStMap;
while (fgets(aStr, MAX_STR - 1, aLogFile) != NULL)
{
// detect operation type, request number and block size
unsigned long aReqNum, aSize;
char* aType = aStr;
char* pStr = aStr;
// sscanf(aStr, "%5s %lu %lu", aType, &aReqNum, &aSize);
while (*pStr != ' ' && *pStr)
pStr++;
*pStr++ = '\0';
while (*pStr == ' ' && *pStr)
pStr++;
aReqNum = atol(pStr);
while (*pStr != ' ' && *pStr)
pStr++;
while (*pStr == ' ' && *pStr)
pStr++;
aSize = atol(pStr);
Standard_Boolean isAlloc = Standard_False;
if (strcmp(aType, "alloc") == 0)
{
isAlloc = Standard_True;
}
else if (strcmp(aType, "free") != 0)
continue;
// collect statistics by storage size
StorageInfo aSuchInfo(aSize);
std::set<StorageInfo>::iterator aFound = aStMap.find(aSuchInfo);
if (aFound == aStMap.end())
aFound = aStMap.insert(aSuchInfo).first;
StorageInfo& aInfo = const_cast<StorageInfo&>(*aFound);
if (isAlloc)
{
if (aInfo.nbAlloc + 1 > 0)
aInfo.nbAlloc++;
aTotalLeftSize += aSize;
if (aTotalLeftSize > aTotalPeakSize)
aTotalPeakSize = aTotalLeftSize;
int nbLeft = aInfo.nbAlloc - aInfo.nbFree;
if (nbLeft > aInfo.nbLeftPeak)
aInfo.nbLeftPeak = nbLeft;
aInfo.alive.insert(aReqNum);
}
else
{
std::set<unsigned long>::iterator aFoundReqNum = aInfo.alive.find(aReqNum);
if (aFoundReqNum == aInfo.alive.end())
// freeing non-registered block, skip it
continue;
aTotalLeftSize -= aSize;
aInfo.alive.erase(aFoundReqNum);
if (aInfo.nbAlloc + 1 > 0)
aInfo.nbFree++;
}
}
fclose(aLogFile);
// print the report
std::ofstream aRepFile(theOutFile);
if (!aRepFile.is_open())
{
return Standard_False;
}
aRepFile.imbue(std::locale("C"));
aRepFile << std::setw(20) << "BlockSize " << std::setw(10) << "NbAlloc " << std::setw(10)
<< "NbLeft " << std::setw(10) << "NbLeftPeak " << std::setw(20) << "AllocSize "
<< std::setw(20) << "LeftSize " << std::setw(20) << "PeakSize " << std::endl;
Standard_Size aTotAlloc = 0;
for (std::set<StorageInfo>::const_iterator it = aStMap.begin(); it != aStMap.end(); ++it)
{
const StorageInfo& aInfo = *it;
Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree;
Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.size;
Standard_Size aSizeLeft = nbLeft * aInfo.size;
Standard_Size aSizePeak = aInfo.nbLeftPeak * aInfo.size;
aRepFile << std::setw(20) << aInfo.size << ' ' << std::setw(10) << aInfo.nbAlloc << ' '
<< std::setw(10) << nbLeft << ' ' << std::setw(10) << aInfo.nbLeftPeak << ' '
<< std::setw(20) << aSizeAlloc << ' ' << std::setw(20) << aSizeLeft << ' '
<< std::setw(20) << aSizePeak << std::endl;
if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
aTotAlloc = SIZE_MAX;
else
aTotAlloc += aSizeAlloc;
if (theIncludeAlive && !aInfo.alive.empty())
{
for (std::set<unsigned long>::const_iterator it1 = aInfo.alive.begin();
it1 != aInfo.alive.end();
++it1)
aRepFile << std::setw(10) << *it1;
}
}
aRepFile << std::setw(20) << "Total:" << std::setw(10) << "" << ' ' << std::setw(10) << "" << ' '
<< std::setw(10) << "" << ' ' << (aTotAlloc == SIZE_MAX ? '>' : ' ') << std::setw(20)
<< aTotAlloc << ' ' << std::setw(20) << aTotalLeftSize << ' ' << std::setw(20)
<< aTotalPeakSize << std::endl;
aRepFile.close();
return Standard_True;
}
//=================================================================================================
void OSD_MAllocHook::LogFileHandler::AllocEvent(size_t theSize, long theRequestNum)
{
if (myLogFile.is_open())
{
myMutex.Lock();
myLogFile << "alloc " << std::setw(10) << theRequestNum << std::setw(20) << theSize
<< std::endl;
if (myBreakSize == theSize)
place_for_breakpoint();
myMutex.Unlock();
}
}
//=================================================================================================
void OSD_MAllocHook::LogFileHandler::FreeEvent(void* /*theData*/,
size_t theSize,
long theRequestNum)
{
if (myLogFile.is_open())
{
myMutex.Lock();
myLogFile << "free " << std::setw(20) << theRequestNum << std::setw(20) << theSize << std::endl;
myMutex.Unlock();
}
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CollectBySize handler methods
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//=================================================================================================
OSD_MAllocHook::CollectBySize::CollectBySize()
: myArray(NULL),
myTotalLeftSize(0),
myTotalPeakSize(0),
myBreakSize(0),
myBreakPeak(0)
{
Reset();
}
//=================================================================================================
OSD_MAllocHook::CollectBySize::~CollectBySize()
{
if (myArray != NULL)
delete[] myArray;
}
//=================================================================================================
#define MAX_ALLOC_SIZE 2000000
const size_t OSD_MAllocHook::CollectBySize::myMaxAllocSize = MAX_ALLOC_SIZE;
void OSD_MAllocHook::CollectBySize::Reset()
{
myMutex.Lock();
if (myArray == NULL)
myArray = new Numbers[MAX_ALLOC_SIZE];
else
{
for (int i = 0; i < MAX_ALLOC_SIZE; i++)
myArray[i] = Numbers();
}
myTotalLeftSize = 0;
myTotalPeakSize = 0;
myMutex.Unlock();
}
//=================================================================================================
Standard_Boolean OSD_MAllocHook::CollectBySize::MakeReport(const char* theOutFile)
{
// print the report
std::ofstream aRepFile(theOutFile);
if (!aRepFile.is_open())
return Standard_False;
std::locale aCLoc("C");
aRepFile.imbue(aCLoc);
aRepFile << std::setw(10) << "BlockSize " << std::setw(10) << "NbAlloc " << std::setw(10)
<< "NbLeft " << std::setw(10) << "NbLeftPeak " << std::setw(20) << "AllocSize "
<< std::setw(20) << "LeftSize " << std::setw(20) << "PeakSize " << std::endl;
Standard_Size aTotAlloc = 0;
for (int i = 0; i < MAX_ALLOC_SIZE; i++)
{
if (myArray[i].nbAlloc > 0 || myArray[i].nbFree > 0)
{
Standard_Integer nbLeft = myArray[i].nbAlloc - myArray[i].nbFree;
int aSize = i + 1;
Standard_Size aSizeAlloc = myArray[i].nbAlloc * aSize;
ptrdiff_t aSizeLeft = nbLeft * aSize;
Standard_Size aSizePeak = myArray[i].nbLeftPeak * aSize;
aRepFile << std::setw(10) << aSize << ' ' << std::setw(10) << myArray[i].nbAlloc << ' '
<< std::setw(10) << nbLeft << ' ' << std::setw(10) << myArray[i].nbLeftPeak << ' '
<< std::setw(20) << aSizeAlloc << ' ' << std::setw(20) << aSizeLeft << ' '
<< std::setw(20) << aSizePeak << std::endl;
if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
aTotAlloc = SIZE_MAX;
else
aTotAlloc += aSizeAlloc;
}
}
aRepFile << std::setw(10) << "Total:" << ' ' << std::setw(10) << "" << ' ' << std::setw(10) << ""
<< ' ' << std::setw(10) << "" << ' ' << (aTotAlloc == SIZE_MAX ? '>' : ' ')
<< std::setw(20) << aTotAlloc << ' ' << std::setw(20) << myTotalLeftSize << ' '
<< std::setw(20) << myTotalPeakSize << std::endl;
aRepFile.close();
return Standard_True;
}
//=================================================================================================
void OSD_MAllocHook::CollectBySize::AllocEvent(size_t theSize, long /*theRequestNum*/)
{
if (myBreakSize == theSize)
place_for_breakpoint();
if (theSize > 0)
{
myMutex.Lock();
int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE - 1 : (int)(theSize - 1));
myArray[ind].nbAlloc++;
myTotalLeftSize += theSize;
int nbLeft = myArray[ind].nbAlloc - myArray[ind].nbFree;
if (nbLeft > myArray[ind].nbLeftPeak)
{
myArray[ind].nbLeftPeak = nbLeft;
if (myBreakPeak != 0 && (myBreakSize == theSize || myBreakSize == 0))
{
const Standard_Size aSizePeak = myArray[ind].nbLeftPeak * theSize;
if (aSizePeak > myBreakPeak)
{
place_for_breakpoint();
}
}
}
if (myTotalLeftSize > (ptrdiff_t)myTotalPeakSize)
myTotalPeakSize = myTotalLeftSize;
myMutex.Unlock();
}
}
//=================================================================================================
void OSD_MAllocHook::CollectBySize::FreeEvent(void* /*theData*/,
size_t theSize,
long /*theRequestNum*/)
{
if (theSize > 0)
{
myMutex.Lock();
int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE - 1 : (int)(theSize - 1));
myArray[ind].nbFree++;
myTotalLeftSize -= theSize;
myMutex.Unlock();
}
}

View File

@@ -0,0 +1,170 @@
// Created on: 2011-02-03
// Created by: Mikhail SAZONOV
// Copyright (c) 2011-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _OSD_MAllocHook_HeaderFile
#define _OSD_MAllocHook_HeaderFile
#include <Standard_Mutex.hxx>
#include <fstream>
/**
* This class provides the possibility to set callback for memory
* allocation/deallocation.
* On MS Windows, it works only in Debug builds. It relies on the
* debug CRT function _CrtSetAllocHook (see MSDN for help).
*/
class OSD_MAllocHook
{
public:
/**
* Interface of a class that should handle allocation/deallocation events
*/
class Callback
{
public:
//! Allocation event handler
/**
* It is called when allocation is done
* @param theSize
* the size of the memory block in bytes
* @param theRequestNum
* the allocation order number of the memory block
*/
virtual void AllocEvent(size_t theSize, long theRequestNum) = 0;
//! Freeing event handler
/**
* It is called when the block is freed
* @param theData
* the pointer to the user data section of the memory block
* @param theSize
* the size of the memory block in bytes
* @param theRequestNum
* the allocation order number of the memory block
*/
virtual void FreeEvent(void* theData, size_t theSize, long theRequestNum) = 0;
};
/**
* Implementation of the handler that collects all events
* to the log file. It contains the method to generate the report
* from the log file.
*/
class LogFileHandler : public Callback
{
public:
//! Constructor
Standard_EXPORT LogFileHandler();
//! Destructor
Standard_EXPORT ~LogFileHandler();
//! Create the file and start collecting events.
//! Return false if the file with the given name cannot be created.
Standard_EXPORT Standard_Boolean Open(const char* theFileName);
//! Close the file and stop collecting events
Standard_EXPORT void Close();
//! Make synthesized report on the given log file.
/**
* Generate an easy to use report in the
* new file with the given name, taking the given log file as input.
* If theIncludeAlive is true then
* include into the report the alive allocation numbers.
*/
Standard_EXPORT static Standard_Boolean MakeReport(
const char* theLogFile,
const char* theOutFile,
const Standard_Boolean theIncludeAlive = Standard_False);
Standard_EXPORT virtual void AllocEvent(size_t, long);
Standard_EXPORT virtual void FreeEvent(void*, size_t, long);
private:
std::ofstream myLogFile;
Standard_Mutex myMutex;
size_t myBreakSize;
};
/**
* Implementation of the handler that collects numbers of
* allocations/deallocations for each block size directly in the memory.
*/
class CollectBySize : public Callback
{
public:
//! Constructor
Standard_EXPORT CollectBySize();
//! Destructor
Standard_EXPORT ~CollectBySize();
//! Reset the buffer and start collecting events.
Standard_EXPORT void Reset();
//! Write report in the given file.
Standard_EXPORT Standard_Boolean MakeReport(const char* theOutFile);
Standard_EXPORT virtual void AllocEvent(size_t, long);
Standard_EXPORT virtual void FreeEvent(void*, size_t, long);
public:
struct Numbers
{
int nbAlloc;
int nbFree;
int nbLeftPeak;
Numbers()
: nbAlloc(0),
nbFree(0),
nbLeftPeak(0)
{
}
};
static const size_t myMaxAllocSize; //!< maximum tracked size
Standard_Mutex myMutex; //!< used for thread-safe access
Numbers* myArray; //!< indexed from 0 to myMaxAllocSize-1
ptrdiff_t myTotalLeftSize; //!< currently remained allocated size
size_t myTotalPeakSize; //!< maximum cumulative allocated size
// clang-format off
size_t myBreakSize; //!< user defined allocation size to debug (see place_for_breakpoint())
// clang-format on
size_t myBreakPeak; //!< user defined peak size limit to debug
};
//! Set handler of allocation/deallocation events
/**
* You can pass here any implementation. For easy start, you can try
* with the predefined handler LogFileHandler, which static instance
* is returned by GetLogFileHandler().
* To clear the handler, pass NULL here.
*/
Standard_EXPORT static void SetCallback(Callback* theCB);
//! Get current handler of allocation/deallocation events
Standard_EXPORT static Callback* GetCallback();
//! Get static instance of LogFileHandler handler
Standard_EXPORT static LogFileHandler* GetLogFileHandler();
//! Get static instance of CollectBySize handler
Standard_EXPORT static CollectBySize* GetCollectBySize();
};
#endif /* _OSD_MAllocHook_HeaderFile */

View File

@@ -1687,12 +1687,6 @@ Standard_Boolean ShapeFix_Face::FixMissingSeam()
Handle(Geom_ToroidalSurface) aTorSurf = Handle(Geom_ToroidalSurface)::DownCast(mySurf->Surface());
Standard_Boolean anIsDegeneratedTor =
(aTorSurf.IsNull() ? Standard_False : aTorSurf->MajorRadius() < aTorSurf->MinorRadius());
// if the second wire is not null, we don't need mark the torus as degenerated
// and should process it as a regular one.
if (anIsDegeneratedTor && !w2.IsNull())
{
anIsDegeneratedTor = Standard_False;
}
if (w1.IsNull())
return Standard_False;

View File

@@ -2,5 +2,4 @@
set(OCCT_TKGeomBase_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
set(OCCT_TKGeomBase_GTests_FILES
IntAna_IntQuadQuad_Test.cxx
)

View File

@@ -1,206 +0,0 @@
// Copyright (c) 2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <IntAna_IntQuadQuad.hxx>
#include <IntAna_Quadric.hxx>
#include <gp_Sphere.hxx>
#include <gp_Cylinder.hxx>
#include <gp_Cone.hxx>
#include <gp_Pln.hxx>
#include <gp_Ax3.hxx>
#include <gtest/gtest.h>
class IntAna_IntQuadQuad_Test : public ::testing::Test
{
protected:
void SetUp() override
{
// Set up common geometric objects for tests
gp_Pnt anOrigin(0, 0, 0);
gp_Dir aZDir(0, 0, 1);
gp_Dir anXDir(1, 0, 0);
gp_Ax3 anAxis(anOrigin, aZDir, anXDir);
// Create sphere at origin with radius 5
mySphere1 = gp_Sphere(anAxis, 5.0);
// Create cylinder with axis along Z, radius 3
myCylinder1 = gp_Cylinder(anAxis, 3.0);
// Create cone with semi-angle 30 degrees
myCone1 = gp_Cone(anAxis, M_PI / 6, 2.0);
// Create plane at Z = 2
gp_Pnt aPlaneOrigin(0, 0, 2);
myPlane1 = gp_Pln(aPlaneOrigin, aZDir);
}
gp_Sphere mySphere1;
gp_Cylinder myCylinder1;
gp_Cone myCone1;
gp_Pln myPlane1;
};
// Test basic intersection functionality - Cylinder vs Quadric (sphere)
TEST_F(IntAna_IntQuadQuad_Test, CylinderVsSphereIntersection)
{
IntAna_Quadric aSphereQuad(mySphere1);
IntAna_IntQuadQuad anIntersector(myCylinder1, aSphereQuad, 1e-7);
// Should have intersection curves
EXPECT_TRUE(anIntersector.IsDone());
EXPECT_FALSE(anIntersector.IdenticalElements());
// Should have intersection curves for cylinder-sphere case
EXPECT_GT(anIntersector.NbCurve(), 0);
// Test that we can access all curves without exceptions
for (Standard_Integer i = 1; i <= anIntersector.NbCurve(); i++)
{
// This should not throw any exceptions - just verify we can access the curve
EXPECT_NO_THROW(anIntersector.Curve(i));
}
}
// Test NextCurve functionality - the main test for our bug fix
TEST_F(IntAna_IntQuadQuad_Test, NextCurveMethodCorrectness)
{
IntAna_Quadric aSphereQuad(mySphere1);
IntAna_IntQuadQuad anIntersector(myCylinder1, aSphereQuad, 1e-7);
EXPECT_TRUE(anIntersector.IsDone());
// Test HasNextCurve and NextCurve for valid indices
for (Standard_Integer i = 1; i <= anIntersector.NbCurve(); i++)
{
// These methods should not crash and should return consistent results
Standard_Boolean aHasNext = anIntersector.HasNextCurve(i);
if (aHasNext) // Only test NextCurve when HasNextCurve is true
{
Standard_Boolean anOpposite;
Standard_Integer aNextIdx = anIntersector.NextCurve(i, anOpposite);
// Next curve index should be valid
EXPECT_GT(aNextIdx, 0);
EXPECT_LE(aNextIdx, anIntersector.NbCurve());
EXPECT_NE(aNextIdx, i); // Should not point to itself
}
}
}
// Test edge cases and boundary conditions
TEST_F(IntAna_IntQuadQuad_Test, NextCurveBoundaryConditions)
{
IntAna_Quadric aSphereQuad(mySphere1);
IntAna_IntQuadQuad anIntersector(myCylinder1, aSphereQuad, 1e-7);
EXPECT_TRUE(anIntersector.IsDone());
// Test with invalid indices (should throw exceptions)
EXPECT_THROW(anIntersector.HasNextCurve(0), Standard_OutOfRange);
EXPECT_THROW(anIntersector.HasNextCurve(anIntersector.NbCurve() + 1), Standard_OutOfRange);
// Test NextCurve on curves that don't have next curves
for (Standard_Integer i = 1; i <= anIntersector.NbCurve(); i++)
{
if (!anIntersector.HasNextCurve(i)) // Only test exception when HasNextCurve is false
{
Standard_Boolean anOpposite;
EXPECT_THROW(anIntersector.NextCurve(i, anOpposite), Standard_DomainError);
}
}
}
// Test specific geometric configuration that creates connected curves
TEST_F(IntAna_IntQuadQuad_Test, ConnectedCurvesScenario)
{
// Create two spheres that intersect in a circle
gp_Pnt aCenter1(0, 0, 0);
gp_Pnt aCenter2(3, 0, 0); // Overlapping spheres
gp_Dir aZDir(0, 0, 1);
gp_Dir anXDir(1, 0, 0);
gp_Ax3 anAxis1(aCenter1, aZDir, anXDir);
gp_Ax3 anAxis2(aCenter2, aZDir, anXDir);
gp_Sphere aSphere1(anAxis1, 2.0);
gp_Sphere aSphere2(anAxis2, 2.0);
IntAna_Quadric aSphere2Quad(aSphere2);
IntAna_IntQuadQuad anIntersector;
anIntersector.Perform(gp_Cylinder(anAxis1, 2.0), aSphere2Quad, 1e-7);
EXPECT_TRUE(anIntersector.IsDone());
EXPECT_FALSE(anIntersector.IdenticalElements());
// Verify that NextCurve method works correctly for each curve
for (Standard_Integer i = 1; i <= anIntersector.NbCurve(); i++)
{
if (anIntersector.HasNextCurve(i)) // Only test NextCurve when HasNextCurve is true
{
Standard_Boolean anOpposite;
Standard_Integer aNextIdx = anIntersector.NextCurve(i, anOpposite);
// Validate the result
EXPECT_GT(aNextIdx, 0);
EXPECT_LE(aNextIdx, anIntersector.NbCurve());
// Test consistency: if curve i connects to j, then j should connect back
// (though possibly with different opposite flag)
if (anIntersector.HasNextCurve(aNextIdx))
{
Standard_Boolean aReverseOpposite;
Standard_Integer aReverseNext = anIntersector.NextCurve(aNextIdx, aReverseOpposite);
// This creates a circular reference which is geometrically possible
EXPECT_GT(aReverseNext, 0);
EXPECT_LE(aReverseNext, anIntersector.NbCurve());
}
}
}
}
// Test the fix specifically - ensure we don't access out-of-bounds memory
TEST_F(IntAna_IntQuadQuad_Test, IndexingConsistencyTest)
{
// This test specifically validates that HasNextCurve and NextCurve
// use consistent indexing (both should use I-1 for 0-based arrays)
IntAna_Quadric aSphereQuad(mySphere1); // Cylinder vs sphere intersection
IntAna_IntQuadQuad anIntersector(myCylinder1, aSphereQuad, 1e-7);
EXPECT_TRUE(anIntersector.IsDone());
// Test all valid curve indices
for (Standard_Integer i = 1; i <= anIntersector.NbCurve(); i++)
{
// These calls should be consistent and not crash
Standard_Boolean aHasNext = anIntersector.HasNextCurve(i);
if (aHasNext) // Only test NextCurve when HasNextCurve is true
{
Standard_Boolean anOpposite;
// This should not crash or return invalid values
Standard_Integer aNextIdx = anIntersector.NextCurve(i, anOpposite);
EXPECT_GT(aNextIdx, 0);
EXPECT_LE(aNextIdx, anIntersector.NbCurve());
}
}
}

View File

@@ -1576,8 +1576,16 @@ Standard_Integer IntAna_IntQuadQuad::NextCurve(const Standard_Integer I,
{
if (HasNextCurve(I))
{
theOpposite = nextcurve[I - 1] < 0;
return Abs(nextcurve[I - 1]);
if (nextcurve[I] > 0)
{
theOpposite = Standard_False;
return (nextcurve[I - 1]);
}
else
{
theOpposite = Standard_True;
return (-nextcurve[I - 1]);
}
}
else
{

View File

@@ -44,6 +44,7 @@
#include <Message.hxx>
#include <Message_Messenger.hxx>
#include <NCollection_Array1.hxx>
#include <Standard_ArrayStreamBuffer.hxx>
#include <TCollection_AsciiString.hxx>
#include <TCollection_ExtendedString.hxx>
#include <OSD_OpenFile.hxx>

View File

@@ -1788,17 +1788,8 @@ void AIS_ViewController::handleViewRotation(const Handle(V3d_View)& theView,
}
if (myGL.ViewRotation.ToStart)
{
gp_Dir aCamDirection = aCam->Direction();
if (aCam->OrthogonalizedUp().IsParallel (gp::DY(), Precision::Angular()))
{
aCamDirection = aCamDirection.Dot (gp::DZ()) > 0
? gp::DZ()
: gp::DZ().Reversed();
}
gp_Trsf aTrsf;
aTrsf.SetTransformation(gp_Ax3(gp::Origin(), aCam->OrthogonalizedUp(), aCamDirection),
aTrsf.SetTransformation(gp_Ax3(gp::Origin(), aCam->OrthogonalizedUp(), aCam->Direction()),
gp_Ax3(gp::Origin(), gp::DZ(), gp::DX()));
const gp_Quaternion aRot = aTrsf.GetRotation();
double aRollDummy = 0.0;
@@ -1806,12 +1797,6 @@ void AIS_ViewController::handleViewRotation(const Handle(V3d_View)& theView,
myRotateStartYawPitchRoll[0],
myRotateStartYawPitchRoll[1],
aRollDummy);
if (aCamDirection.IsParallel (gp::DZ(), Precision::Angular()))
{
myRotateStartYawPitchRoll[0] = aCamDirection.IsEqual (gp::DZ(), Precision::Angular())
? aRollDummy
: -aRollDummy;
}
}
if (toRotateAnyway)
{

View File

@@ -993,7 +993,7 @@ public:
const Graphic3d_BufferType& theBufferType = Graphic3d_BT_RGB,
const Standard_Boolean theToAdjustAspect = Standard_True,
const Graphic3d_ZLayerId theTargetZLayerId = Graphic3d_ZLayerId_BotOSD,
const Standard_Boolean theIsSingleLayer = Standard_False,
const Standard_Integer theIsSingleLayer = Standard_False,
const V3d_StereoDumpOptions theStereoOptions = V3d_SDO_MONO,
const Standard_CString theLightName = "")
{

11
tests/bugs/fclasses/bug23569_1 Executable file
View File

@@ -0,0 +1,11 @@
puts "======="
puts "OCC23569"
puts "======="
puts ""
###########################################################################
## Adding NCollection_StdAllocator
###########################################################################
pload QAcommands
QANColStdAllocator1

11
tests/bugs/fclasses/bug23569_2 Executable file
View File

@@ -0,0 +1,11 @@
puts "======="
puts "OCC23569"
puts "======="
puts ""
###########################################################################
## Adding NCollection_StdAllocator
###########################################################################
pload QAcommands
QANColStdAllocator2

View File

@@ -0,0 +1,5 @@
puts "TODO ?CR33225 Windows: Failed class "
pload QAcommands
QANTestStlIterators

View File

@@ -1,8 +0,0 @@
puts "================================================"
puts "Revolved shape in STEP file is imported inverted"
puts "================================================"
puts ""
stepread [locate_data_file gh_bug378.stp] a *
checkprops a_1 -v 10504.9

15
tests/bugs/xde/bug28887_1 Normal file
View File

@@ -0,0 +1,15 @@
puts "=========="
puts "OCC28887 Test case for Standard_ArrayStreamBuffer class - streaming interface for reading from allocated memory block"
puts "=========="
puts ""
pload QAcommands VISUALIZATION
OCC28887 [locate_data_file face.brep] f
vclear
vclose ALL
vinit View1
vaxo
vdisplay -dispMode 1 f
vfit
vdump $::imagedir/${::casename}.png

16
tests/bugs/xde/bug28887_2 Normal file
View File

@@ -0,0 +1,16 @@
puts "=========="
puts "OCC28887 Test case for Standard_ArrayStreamBuffer class - streaming interface for reading from allocated memory block"
puts "=========="
puts ""
pload QAcommands VISUALIZATION DCAF
Close Doc -silent
OCC28887 [locate_data_file bug23384-doc_subshapes.xbf] doc
vclear
vclose ALL
XShow doc
vaxo
vfit
vsetdispmode 1
vdump $::imagedir/${::casename}.png

1
tests/collections/grids.list Executable file
View File

@@ -0,0 +1 @@
001 n

View File

@@ -0,0 +1,3 @@
puts "Check NCollection_Array1 functionality"
QANColTestArray1 1 10

View File

@@ -0,0 +1,3 @@
puts "Check NCollection_Array2 functionality"
QANColTestArray2 1 5 1 3

Some files were not shown because too many files have changed in this diff Show More