From a1778638c895c6d21fbd41b93bb927f9988ca056 Mon Sep 17 00:00:00 2001
From: Evgenii Startcev <slayer-gurgen@yandex.ru>
Date: Fri, 14 Mar 2025 22:03:00 +0100
Subject: [PATCH 1/7] context: Add exception handling

---
 application/F3DStarter.cxx | 51 +++++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 14 deletions(-)

diff --git a/application/F3DStarter.cxx b/application/F3DStarter.cxx
index 3995f1cd4d..b72c5509e7 100644
--- a/application/F3DStarter.cxx
+++ b/application/F3DStarter.cxx
@@ -936,29 +936,52 @@ int F3DStarter::Start(int argc, char** argv)
     bool offscreen = !this->Internals->AppOptions.Reference.empty() ||
       !this->Internals->AppOptions.Output.empty() || this->Internals->AppOptions.BindingsList;
 
-    if (this->Internals->AppOptions.RenderingBackend == "egl")
+    try
     {
-      this->Internals->Engine = std::make_unique<f3d::engine>(f3d::engine::createEGL());
+      if (this->Internals->AppOptions.RenderingBackend == "egl")
+      {
+        this->Internals->Engine = std::make_unique<f3d::engine>(f3d::engine::createEGL());
+      }
+      else if (this->Internals->AppOptions.RenderingBackend == "osmesa")
+      {
+        this->Internals->Engine = std::make_unique<f3d::engine>(f3d::engine::createOSMesa());
+      }
+      else if (this->Internals->AppOptions.RenderingBackend == "glx")
+      {
+        this->Internals->Engine = std::make_unique<f3d::engine>(f3d::engine::createGLX(offscreen));
+      }
+      else if (this->Internals->AppOptions.RenderingBackend == "wgl")
+      {
+        this->Internals->Engine = std::make_unique<f3d::engine>(f3d::engine::createWGL(offscreen));
+      }
+      else
+      {
+        if (this->Internals->AppOptions.RenderingBackend != "auto")
+        {
+          f3d::log::warn("--rendering-backend value is invalid, falling back to \"auto\"");
+        }
+        this->Internals->Engine = std::make_unique<f3d::engine>(f3d::engine::create(offscreen));
+      }
     }
-    else if (this->Internals->AppOptions.RenderingBackend == "osmesa")
+    catch (const f3d::context::loading_exception& ex)
     {
-      this->Internals->Engine = std::make_unique<f3d::engine>(f3d::engine::createOSMesa());
+      f3d::log::error("Could not load graphic library: ", ex.what());
+      return EXIT_FAILURE;
     }
-    else if (this->Internals->AppOptions.RenderingBackend == "glx")
+    catch (const f3d::context::symbol_exception& ex)
     {
-      this->Internals->Engine = std::make_unique<f3d::engine>(f3d::engine::createGLX(offscreen));
+      f3d::log::error("Could not find needed symbol in graphic library: ", ex.what());
+      return EXIT_FAILURE;
     }
-    else if (this->Internals->AppOptions.RenderingBackend == "wgl")
+    catch (const f3d::engine::no_window_exception& ex)
     {
-      this->Internals->Engine = std::make_unique<f3d::engine>(f3d::engine::createWGL(offscreen));
+      f3d::log::error("Could not create the window: ", ex.what());
+      return EXIT_FAILURE;
     }
-    else
+    catch (const f3d::engine::cache_exception& ex)
     {
-      if (this->Internals->AppOptions.RenderingBackend != "auto")
-      {
-        f3d::log::warn("--rendering-backend value is invalid, falling back to \"auto\"");
-      }
-      this->Internals->Engine = std::make_unique<f3d::engine>(f3d::engine::create(offscreen));
+      f3d::log::error("Could not use default cache directory: ", ex.what());
+      return EXIT_FAILURE;
     }
 
     this->ResetWindowName();

From 58f8310a0f5b9c1b8ce98b21e6cefe6d5e5a4f73 Mon Sep 17 00:00:00 2001
From: Evgenii Startcev <slayer-gurgen@yandex.ru>
Date: Fri, 14 Mar 2025 23:22:17 +0100
Subject: [PATCH 2/7] engine: Fix memory leak

Essentially changed internals to unique_ptr
---
 library/public/engine.h |  2 +-
 library/src/engine.cxx  | 10 +++-------
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/library/public/engine.h b/library/public/engine.h
index 32760408f9..e9b8313b43 100644
--- a/library/public/engine.h
+++ b/library/public/engine.h
@@ -352,7 +352,7 @@ class F3D_EXPORT engine
 
 private:
   class internals;
-  internals* Internals;
+  std::unique_ptr<internals> Internals;
 
   /**
    * Engine constructor. This is a private method.
diff --git a/library/src/engine.cxx b/library/src/engine.cxx
index 3557b0bc38..0d5ddeb675 100644
--- a/library/src/engine.cxx
+++ b/library/src/engine.cxx
@@ -47,7 +47,7 @@ class engine::internals
 //----------------------------------------------------------------------------
 engine::engine(
   const std::optional<window::Type>& windowType, bool offscreen, const context::function& loader)
-  : Internals(new engine::internals)
+  : Internals(std::make_unique<engine::internals>())
 {
   // Ensure all lib initialization is done (once)
   detail::init::initialize();
@@ -182,22 +182,18 @@ engine engine::createExternalOSMesa()
 //----------------------------------------------------------------------------
 engine::~engine()
 {
-  delete this->Internals;
 }
 
 //----------------------------------------------------------------------------
 engine::engine(engine&& other) noexcept
 {
-  this->Internals = other.Internals;
-  other.Internals = nullptr;
+  this->Internals = std::move(other.Internals);
 }
 
 //----------------------------------------------------------------------------
 engine& engine::operator=(engine&& other) noexcept
 {
-  delete this->Internals;
-  this->Internals = other.Internals;
-  other.Internals = nullptr;
+  this->Internals = std::move(other.Internals);
   return *this;
 }
 

From 6167dbef678a01c016bc84084cf1c35a10b6ac59 Mon Sep 17 00:00:00 2001
From: Evgenii Startcev <slayer-gurgen@yandex.ru>
Date: Fri, 14 Mar 2025 23:28:57 +0100
Subject: [PATCH 3/7] context: Add no cache test case

Also remove symbol loading exception catch as it should not be possible
to happen in this place unless GL wrapper library is faulty somehow
---
 application/F3DStarter.cxx         | 5 -----
 application/testing/CMakeLists.txt | 1 +
 2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/application/F3DStarter.cxx b/application/F3DStarter.cxx
index b72c5509e7..fe30c0ad1d 100644
--- a/application/F3DStarter.cxx
+++ b/application/F3DStarter.cxx
@@ -968,11 +968,6 @@ int F3DStarter::Start(int argc, char** argv)
       f3d::log::error("Could not load graphic library: ", ex.what());
       return EXIT_FAILURE;
     }
-    catch (const f3d::context::symbol_exception& ex)
-    {
-      f3d::log::error("Could not find needed symbol in graphic library: ", ex.what());
-      return EXIT_FAILURE;
-    }
     catch (const f3d::engine::no_window_exception& ex)
     {
       f3d::log::error("Could not create the window: ", ex.what());
diff --git a/application/testing/CMakeLists.txt b/application/testing/CMakeLists.txt
index 55f8fec39a..286c9d041a 100644
--- a/application/testing/CMakeLists.txt
+++ b/application/testing/CMakeLists.txt
@@ -1135,6 +1135,7 @@ f3d_test(NAME TestBindingsList ARGS --list-bindings REGEXP "Any.5        Toggle
 
 # Test rendering backends
 # For some reason the sanitizer detects leaks because of EGL and OSMesa
+f3d_test(NAME TestInvalidCache ENV "HOME=" REGEXP "Could not use default cache directory" NO_BASELINE)
 f3d_test(NAME TestRenderingBackendAuto DATA cow.vtp RENDERING_BACKEND auto)
 if(UNIX AND NOT APPLE AND VTK_VERSION VERSION_GREATER_EQUAL 9.3.20240914 AND F3D_SANITIZER STREQUAL "none")
   if(F3D_TESTING_ENABLE_EGL_TESTS)

From f5929773a55f770f0c2290ebfa26e1ec9278013f Mon Sep 17 00:00:00 2001
From: Evgenii Startcev <slayer-gurgen@yandex.ru>
Date: Fri, 14 Mar 2025 23:43:45 +0100
Subject: [PATCH 4/7] Revert back to raw pointer still fixing the leak

---
 library/public/engine.h |  2 +-
 library/src/engine.cxx  | 11 ++++++++---
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/library/public/engine.h b/library/public/engine.h
index e9b8313b43..32760408f9 100644
--- a/library/public/engine.h
+++ b/library/public/engine.h
@@ -352,7 +352,7 @@ class F3D_EXPORT engine
 
 private:
   class internals;
-  std::unique_ptr<internals> Internals;
+  internals* Internals;
 
   /**
    * Engine constructor. This is a private method.
diff --git a/library/src/engine.cxx b/library/src/engine.cxx
index 0d5ddeb675..8d106273c5 100644
--- a/library/src/engine.cxx
+++ b/library/src/engine.cxx
@@ -47,7 +47,7 @@ class engine::internals
 //----------------------------------------------------------------------------
 engine::engine(
   const std::optional<window::Type>& windowType, bool offscreen, const context::function& loader)
-  : Internals(std::make_unique<engine::internals>())
+  : Internals(new engine::internals)
 {
   // Ensure all lib initialization is done (once)
   detail::init::initialize();
@@ -85,6 +85,7 @@ engine::engine(
 #endif
   if (cachePath.empty())
   {
+    delete Internals;
     throw engine::cache_exception(
       "Could not setup cache, please set the appropriate environment variable");
   }
@@ -182,18 +183,22 @@ engine engine::createExternalOSMesa()
 //----------------------------------------------------------------------------
 engine::~engine()
 {
+  delete this->Internals;
 }
 
 //----------------------------------------------------------------------------
 engine::engine(engine&& other) noexcept
 {
-  this->Internals = std::move(other.Internals);
+  this->Internals = other.Internals;
+  other.Internals = nullptr;
 }
 
 //----------------------------------------------------------------------------
 engine& engine::operator=(engine&& other) noexcept
 {
-  this->Internals = std::move(other.Internals);
+  delete this->Internals;
+  this->Internals = other.Internals;
+  other.Internals = nullptr;
   return *this;
 }
 

From a389f35b2e0b81cb41f453038431121d1b5c2760 Mon Sep 17 00:00:00 2001
From: Evgenii Startcev <slayer-gurgen@yandex.ru>
Date: Sat, 15 Mar 2025 00:15:25 +0100
Subject: [PATCH 5/7] context: Move test to non-Windows

---
 application/testing/CMakeLists.txt | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/application/testing/CMakeLists.txt b/application/testing/CMakeLists.txt
index 286c9d041a..f3fcbb3528 100644
--- a/application/testing/CMakeLists.txt
+++ b/application/testing/CMakeLists.txt
@@ -1135,8 +1135,10 @@ f3d_test(NAME TestBindingsList ARGS --list-bindings REGEXP "Any.5        Toggle
 
 # Test rendering backends
 # For some reason the sanitizer detects leaks because of EGL and OSMesa
-f3d_test(NAME TestInvalidCache ENV "HOME=" REGEXP "Could not use default cache directory" NO_BASELINE)
 f3d_test(NAME TestRenderingBackendAuto DATA cow.vtp RENDERING_BACKEND auto)
+if(NOT WIN32)
+  f3d_test(NAME TestInvalidCache ENV "HOME=" REGEXP "Could not use default cache directory" NO_BASELINE)
+endif()
 if(UNIX AND NOT APPLE AND VTK_VERSION VERSION_GREATER_EQUAL 9.3.20240914 AND F3D_SANITIZER STREQUAL "none")
   if(F3D_TESTING_ENABLE_EGL_TESTS)
     f3d_test(NAME TestRenderingBackendEGL DATA cow.vtp RENDERING_BACKEND egl)

From 74491284e83256f30bef562031804db469183b6a Mon Sep 17 00:00:00 2001
From: Evgenii Startcev <slayer-gurgen@yandex.ru>
Date: Sat, 15 Mar 2025 10:23:20 +0100
Subject: [PATCH 6/7] context: bring back symbol exception handling

Also move test case location
---
 application/F3DStarter.cxx         | 5 +++++
 application/testing/CMakeLists.txt | 4 +---
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/application/F3DStarter.cxx b/application/F3DStarter.cxx
index fe30c0ad1d..b72c5509e7 100644
--- a/application/F3DStarter.cxx
+++ b/application/F3DStarter.cxx
@@ -968,6 +968,11 @@ int F3DStarter::Start(int argc, char** argv)
       f3d::log::error("Could not load graphic library: ", ex.what());
       return EXIT_FAILURE;
     }
+    catch (const f3d::context::symbol_exception& ex)
+    {
+      f3d::log::error("Could not find needed symbol in graphic library: ", ex.what());
+      return EXIT_FAILURE;
+    }
     catch (const f3d::engine::no_window_exception& ex)
     {
       f3d::log::error("Could not create the window: ", ex.what());
diff --git a/application/testing/CMakeLists.txt b/application/testing/CMakeLists.txt
index f3fcbb3528..d1c7ffca7c 100644
--- a/application/testing/CMakeLists.txt
+++ b/application/testing/CMakeLists.txt
@@ -1136,9 +1136,6 @@ f3d_test(NAME TestBindingsList ARGS --list-bindings REGEXP "Any.5        Toggle
 # Test rendering backends
 # For some reason the sanitizer detects leaks because of EGL and OSMesa
 f3d_test(NAME TestRenderingBackendAuto DATA cow.vtp RENDERING_BACKEND auto)
-if(NOT WIN32)
-  f3d_test(NAME TestInvalidCache ENV "HOME=" REGEXP "Could not use default cache directory" NO_BASELINE)
-endif()
 if(UNIX AND NOT APPLE AND VTK_VERSION VERSION_GREATER_EQUAL 9.3.20240914 AND F3D_SANITIZER STREQUAL "none")
   if(F3D_TESTING_ENABLE_EGL_TESTS)
     f3d_test(NAME TestRenderingBackendEGL DATA cow.vtp RENDERING_BACKEND egl)
@@ -1190,6 +1187,7 @@ set_tests_properties(f3d::TestNoFileFileNameTemplate PROPERTIES PASS_REGULAR_EXP
 set_tests_properties(f3d::TestNoFileFileNameTemplate PROPERTIES ENVIRONMENT "CTEST_F3D_NO_DATA_FORCE_RENDER=1")
 
 if(NOT WIN32)
+  f3d_test(NAME TestInvalidCache ENV "HOME=" REGEXP "Could not use default cache directory" NO_BASELINE)
   add_test(NAME f3d::TestHOMEOutput COMMAND $<TARGET_FILE:f3d> ${F3D_SOURCE_DIR}/testing/data/suzanne.stl --output=~/Testing/Temporary/TestHOMEOutput.png --resolution=300,300 --no-config)
   set_tests_properties(f3d::TestHOMEOutput PROPERTIES ENVIRONMENT "HOME=${CMAKE_BINARY_DIR}")
   set_tests_properties(f3d::TestHOMEOutput PROPERTIES FIXTURES_SETUP f3d::TestHOMEOutput_FIXTURE)

From 4f5465b5a842afcb83bc2250965b4959d985180c Mon Sep 17 00:00:00 2001
From: Evgenii Startcev <slayer-gurgen@yandex.ru>
Date: Sat, 15 Mar 2025 10:57:13 +0100
Subject: [PATCH 7/7] context: Clearer test declaration

---
 application/testing/CMakeLists.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/application/testing/CMakeLists.txt b/application/testing/CMakeLists.txt
index d1c7ffca7c..df948e74a2 100644
--- a/application/testing/CMakeLists.txt
+++ b/application/testing/CMakeLists.txt
@@ -1188,6 +1188,7 @@ set_tests_properties(f3d::TestNoFileFileNameTemplate PROPERTIES ENVIRONMENT "CTE
 
 if(NOT WIN32)
   f3d_test(NAME TestInvalidCache ENV "HOME=" REGEXP "Could not use default cache directory" NO_BASELINE)
+
   add_test(NAME f3d::TestHOMEOutput COMMAND $<TARGET_FILE:f3d> ${F3D_SOURCE_DIR}/testing/data/suzanne.stl --output=~/Testing/Temporary/TestHOMEOutput.png --resolution=300,300 --no-config)
   set_tests_properties(f3d::TestHOMEOutput PROPERTIES ENVIRONMENT "HOME=${CMAKE_BINARY_DIR}")
   set_tests_properties(f3d::TestHOMEOutput PROPERTIES FIXTURES_SETUP f3d::TestHOMEOutput_FIXTURE)