diff --git a/DDTest/CMakeLists.txt b/DDTest/CMakeLists.txt
index d3fb4fe2d74386276f6aee5aaae9677b434f4616..2f852d73ad76d3182aebbe16852e9177afb7bab3 100644
--- a/DDTest/CMakeLists.txt
+++ b/DDTest/CMakeLists.txt
@@ -23,6 +23,7 @@ foreach(TEST_NAME
     test_cellDimensions
     test_cellDimensionsRPhi2
     test_segmentationHandles
+    test_Evaluator
     )
   add_executable(${TEST_NAME} src/${TEST_NAME}.cc)
   target_link_libraries(${TEST_NAME} DD4hep::DDCore DD4hep::DDRec DD4hep::DDTest)
diff --git a/DDTest/src/test_Evaluator.cc b/DDTest/src/test_Evaluator.cc
new file mode 100644
index 0000000000000000000000000000000000000000..58103f4bf331053a1dd54ffd3e209aa42d680178
--- /dev/null
+++ b/DDTest/src/test_Evaluator.cc
@@ -0,0 +1,193 @@
+#include "DD4hep/DDTest.h"
+#include <exception>
+#include <iostream>
+#include <assert.h>
+#include <cmath>
+
+#include <atomic>
+#include <thread>
+
+#include "Evaluator/Evaluator.h"
+
+
+using namespace std ;
+using namespace dd4hep ;
+
+// this should be the first line in your test
+static DDTest test( "Evaluator" ) ; 
+
+namespace {
+  double foo() { return 8.0;}
+}
+
+//=============================================================================
+
+int main(int /* argc */, char** /* argv */ ){
+    
+  try{
+    
+    // ----- write your tests in here -------------------------------------
+
+    test.log( "test Evaluator" );
+    using namespace dd4hep::tools;
+    Evaluator e;
+    {
+      auto r = e.evaluate("5.2");
+      test( r.second , 5.2, " double value");
+      test( r.first, Evaluator::OK, " status OK");
+    }
+
+    {
+      auto r = e.evaluate("4*m");
+      test( r.second , 4, " double value in meters");
+      test( r.first, Evaluator::OK, " status OK");
+    }
+
+    {
+      auto r = e.evaluate("4*cm");
+      test( r.second , 0.04, " double value in cm");
+      test( r.first, Evaluator::OK, " status OK");
+    }
+
+    {
+      auto r = e.evaluate("abs(-4)");
+      test( r.second , 4., " call abs");
+      test( r.first, Evaluator::OK, " status OK");
+    }
+
+    {
+      auto r = e.evaluate("min(7, 2)");
+      test( r.second , 2., " call min");
+      test( r.first, Evaluator::OK, " status OK");
+    }
+
+    {
+      auto r = e.evaluate("7_");
+      test( r.first, Evaluator::ERROR_UNEXPECTED_SYMBOL, " status UNEXPECTED SYMBOL");
+    }
+
+    {
+      e.setVariable("myVar", 12);
+      auto r = e.evaluate("myVar");
+      test( r.second , 12., " use myVar variable");
+      test( r.first, Evaluator::OK, " status OK");
+    }
+
+    {
+      e.setFunction("foo", foo);
+      auto r = e.evaluate("foo()");
+      test( r.second , foo(), " call new function foo");
+      test( r.first, Evaluator::OK, " status OK");
+    }
+    
+    {
+      //use cm as length
+      Evaluator e_cm(100.);
+
+      {
+        auto r = e_cm.evaluate("4*m");
+        test( r.second , 400, " double value in meters with cm as unit");
+        test( r.first, Evaluator::OK, " status OK");
+      }
+      
+      {
+        auto r = e_cm.evaluate("4*cm");
+        test( r.second , 4, " double value in cm with cm as unit");
+        test( r.first, Evaluator::OK, " status OK");
+      }
+    }
+
+    {
+      //do modifications while running multple threads
+      std::atomic<int> countDownToStart{2};
+
+      std::atomic<bool> success{true};
+
+      Evaluator e_threads;
+
+      std::array<std::string,100> nameExtensions;
+      char extension[3];
+      extension[2] = 0;
+      for(char i = 0; i< 4;++i) {
+        extension[1] = 97+i;
+        for(char j = 0; j<25;++j) {
+          extension[0]=97+j;
+          nameExtensions[i*25+j] = std::string(extension,2);
+        }
+      }
+      
+      
+        std::thread t1([&countDownToStart, &success, &e_threads, &nameExtensions]() { 
+          const std::string name("ta");
+          --countDownToStart;
+          while(countDownToStart != 0);
+      
+          for(int i=0; i< 100; ++i) {
+            std::string newName = name+nameExtensions[i];
+             auto status = e_threads.setVariable(newName, i);
+            if(status != Evaluator::OK) {
+              success = false;
+              std::cout <<"Failed to add variable "<<newName<<" "<<status<<std::endl;
+              break;
+            };
+            auto r = e_threads.evaluate( newName+"*m");
+            if(r.first != Evaluator::OK) {
+              success = false;
+              std::cout <<"Parser failure "<<r.first<<" for variable "<<newName<<std::endl;
+              break;
+            }
+            if(r.second != i) {
+              success = false;
+              std::cout <<"Failed evaluation "<<i <<" != "<<r.second<<" for variable "<<newName<<std::endl;
+              break;
+            }
+          }
+          
+        }
+        ); 
+
+      std::thread t2([&countDownToStart, &success, &e_threads,&nameExtensions]() {
+          const std::string name("tb");
+          --countDownToStart;
+          while(countDownToStart != 0);
+          return;
+
+          for(int i=0; i< 100; ++i) {
+            std::string newName = name+nameExtensions[i];
+            e_threads.setVariable(newName, i);
+            auto r = e_threads.evaluate( newName+"*m");
+            if(r.first != Evaluator::OK) {
+              success = false;
+              std::cout <<"Parser failure "<<r.first<<" for variable "<<newName<<std::endl;
+              break;
+            }
+            if(r.second != i) {
+              success = false;
+              std::cout <<"Failed evaluation "<<i <<" != "<<r.second<<" for variable "<<newName<<std::endl;
+              break;
+            }
+          }
+        }
+      );
+      
+      t1.join();
+      t2.join();
+
+      test(success.load(), " multi-thread test");
+
+    }
+
+    // --------------------------------------------------------------------
+
+
+  } catch( exception &e ){
+    //} catch( ... ){
+
+    test.log( e.what() );
+    test.error( "exception occurred" );
+  }
+
+  return 0;
+}
+
+//=============================================================================