diff --git a/CMakeLists.txt b/CMakeLists.txt
index b774fa87..b519e8aa 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -632,6 +632,10 @@ if($ENV{ROS_VERSION} STREQUAL "1")
target_include_directories(onto_feature_multi_test PRIVATE ${catkin_INCLUDE_DIRS})
target_link_libraries(onto_feature_multi_test ontologenius_lib ${catkin_LIBRARIES})
+ add_rostest_gtest(onto_feature_subscription_test test/feature_subscription.test src/tests/CI/feature_subscription_test.cpp)
+ target_include_directories(onto_feature_subscription_test PRIVATE ${catkin_INCLUDE_DIRS})
+ target_link_libraries(onto_feature_subscription_test ontologenius_lib ${catkin_LIBRARIES})
+
add_rostest_gtest(onto_reasoning_anonymous_class_test test/reasoning_anonymous_class.test src/tests/CI/reasoning_anonymous_class_test.cpp)
set_target_properties(onto_reasoning_anonymous_class_test PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED ON)
target_include_directories(onto_reasoning_anonymous_class_test PRIVATE ${catkin_INCLUDE_DIRS})
diff --git a/files/test_individuals.owl b/files/test_individuals.owl
index de2d8f6d..955402bb 100644
--- a/files/test_individuals.owl
+++ b/files/test_individuals.owl
@@ -91,6 +91,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/tests/CI/feature_subscription_test.cpp b/src/tests/CI/feature_subscription_test.cpp
new file mode 100644
index 00000000..fcabb3c7
--- /dev/null
+++ b/src/tests/CI/feature_subscription_test.cpp
@@ -0,0 +1,183 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "ontologenius/API/ontologenius/OntologyManipulator.h"
+
+onto::OntologyManipulator* onto_ptr;
+std::atomic done_add;
+std::atomic done_del;
+std::atomic done_any;
+
+#define NB_TIME 20 // 2s
+
+void callbackAdd(const std::string& fact)
+{
+ done_add++;
+}
+
+void callbackDel(const std::string& fact)
+{
+ done_del++;
+}
+
+void callbackAny(const std::string& fact)
+{
+ done_any++;
+}
+
+TEST(feature_subscription, exact_one_pattern)
+{
+ done_add = 0;
+ done_del = 0;
+ onto_ptr->subscriber.subscribe("[add]cube1|isOn|table1", &callbackAdd, 1);
+
+ usleep(1000);
+
+ for(size_t i = 0; i < 2; i++)
+ {
+ onto_ptr->feeder.addProperty("cube1", "isOn", "table1");
+ onto_ptr->feeder.addProperty("cube2", "isOn", "table1");
+ }
+
+ usleep(1000);
+
+ EXPECT_EQ(done_add, 1);
+ EXPECT_EQ(done_del, 0);
+}
+
+TEST(feature_subscription, exact_invert_pattern)
+{
+ done_add = 0;
+ done_del = 0;
+ onto_ptr->subscriber.subscribe("[add]table1|isUnder|cube1", &callbackAdd, 2);
+
+ usleep(1000);
+
+ for(size_t i = 0; i < 2; i++)
+ {
+ onto_ptr->feeder.addProperty("cube1", "isOn", "table1");
+ onto_ptr->feeder.addProperty("cube2", "isOn", "table1");
+ }
+
+ usleep(1000);
+
+ EXPECT_EQ(done_add, 2);
+ EXPECT_EQ(done_del, 0);
+}
+
+TEST(feature_subscription, exact_two_pattern)
+{
+ done_add = 0;
+ done_del = 0;
+ onto_ptr->subscriber.subscribe("[add]cube1|isOn|table1", &callbackAdd, 1);
+ onto_ptr->subscriber.subscribe("[del]cube1|isOn|table1", &callbackDel, 1);
+
+ usleep(1000);
+
+ for(size_t i = 0; i < 2; i++)
+ {
+ onto_ptr->feeder.addProperty("cube1", "isOn", "table1");
+ onto_ptr->feeder.addProperty("cube2", "isOn", "table1");
+ }
+ onto_ptr->feeder.waitUpdate(500);
+ for(size_t i = 0; i < 2; i++)
+ {
+ onto_ptr->feeder.removeProperty("cube1", "isOn", "table1");
+ onto_ptr->feeder.removeProperty("cube2", "isOn", "table1");
+ }
+
+ usleep(1000);
+
+ EXPECT_EQ(done_add, 1);
+ EXPECT_EQ(done_del, 1);
+}
+
+TEST(feature_subscription, abstract_pattern)
+{
+ done_add = 0;
+ done_del = 0;
+ onto_ptr->subscriber.subscribe("[add]Cube|isOn|table1", &callbackAdd, 2);
+
+ usleep(1000);
+
+ onto_ptr->feeder.addProperty("cube1", "isOn", "table1");
+ onto_ptr->feeder.addProperty("cube2", "isOn", "table1");
+
+ usleep(1000);
+
+ EXPECT_EQ(done_add, 2);
+ EXPECT_EQ(done_del, 0);
+}
+
+TEST(feature_subscription, variable_pattern)
+{
+ done_add = 0;
+ done_del = 0;
+ onto_ptr->subscriber.subscribe("[add]?|isOn|table1", &callbackAdd, 3);
+
+ usleep(1000);
+
+ onto_ptr->feeder.addProperty("cube1", "isOn", "table1");
+ onto_ptr->feeder.addProperty("cube2", "isOn", "table1");
+ onto_ptr->feeder.addProperty("cube2", "isOn", "table2");
+
+ usleep(1000);
+
+ EXPECT_EQ(done_add, 2);
+ EXPECT_EQ(done_del, 0);
+}
+
+TEST(feature_subscription, variable_abstract_pattern)
+{
+ done_add = 0;
+ done_del = 0;
+ onto_ptr->subscriber.subscribe("[add]?|isOn|Table", &callbackAdd, 3);
+
+ usleep(1000);
+
+ onto_ptr->feeder.addProperty("cube1", "isOn", "table1");
+ onto_ptr->feeder.addProperty("cube2", "isOn", "table1");
+ onto_ptr->feeder.addProperty("cube2", "isOn", "table2");
+
+ usleep(1000);
+
+ EXPECT_EQ(done_add, 3);
+ EXPECT_EQ(done_del, 0);
+}
+
+TEST(feature_subscription, any_pattern)
+{
+ done_any = 0;
+
+ onto_ptr->subscriber.subscribe("[?]cube1|isOn|table1", &callbackAny, 1);
+
+ usleep(1000);
+
+ onto_ptr->feeder.addProperty("cube1", "isOn", "table1");
+
+ onto_ptr->feeder.waitUpdate(500);
+
+ onto_ptr->feeder.removeProperty("cube1", "isOn", "table1");
+
+ usleep(1000);
+
+ EXPECT_EQ(done_any, 1);
+}
+
+int main(int argc, char** argv)
+{
+ ros::init(argc, argv, "ontologenius_feature_subscription_test");
+
+ onto::OntologyManipulator onto;
+ onto_ptr = &onto;
+
+ onto.close();
+
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/src/tests/CI/subscription.cpp b/src/tests/CI/subscription.cpp
deleted file mode 100644
index e69de29b..00000000
diff --git a/test/feature_subscription.test b/test/feature_subscription.test
new file mode 100644
index 00000000..b66a8933
--- /dev/null
+++ b/test/feature_subscription.test
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+