32 #define INVALIDATE_IF(cond) do{ if (cond) { invalidate(); return; } }while(0)
34 int size = keys.
size();
35 bool is_full_path = !keys[0][0];
37 depth = is_full_path ? INT_MAX : size;
39 int implEntry =
int(is_full_path);
47 quark[size-implEntry] = 0;
59 while (quark[offset]) ++
offset;
70 #if defined(ASSERTION_USED)
75 currently_called_back = &*
cb;
77 currently_called_back->
spec(
cb->gbd, allowedTypes);
78 currently_called_back =
NULp;
87 inside_callback_main =
this;
92 inside_callback_main =
NULp;
95 inline void GB_MAIN_TYPE::callback_group::forget_hcbs() {
101 changeCBs.forget_hcbs();
102 deleteCBs.forget_hcbs();
106 DatabaseCallback TypedDatabaseCallback::MARKED_DELETED = makeDatabaseCallback(
dummy_db_cb);
121 if (currently_called_back->
gbd == of_gbd) {
170 if (!currently_called_back) {
171 GB_export_error(
"You cannot call GB_read_old_value outside a ARBDB callback");
174 if (!currently_called_back->
old) {
179 if (!data)
return NULp;
185 if (!currently_called_back) {
186 GB_export_error(
"You cannot call GB_read_old_size outside a ARBDB callback");
189 if (!currently_called_back->
old) {
199 #define appendcbtype(cbt) do { \
201 type = GB_CB_TYPE(type-cbt); \
219 readable_fun, readable_cbtype, (
void*)dbcb.inspect_CD1());
221 free(readable_cbtype);
233 char *cb_info =
cb->spec.get_info();
250 #if defined(ASSERTION_USED)
251 template<
typename CB>
254 if (
cb->spec.is_equal_to(like.spec) &&
255 !
cb->spec.is_marked_for_removal())
265 if (
cb->spec.is_equal_to(like.
spec) &&
266 !
cb->spec.is_marked_for_removal() &&
276 template <
typename PRED>
278 #if defined(ASSERTION_USED)
280 printf(
"Warning: gb_remove_callback called inside delete-callback of gbd (gbd may already be freed)\n");
343 printf(
"Warning: add_priority_callback called inside delete-callback of gbd (gbd may already be freed)\n");
344 #if defined(DEVEL_RALF)
378 #define CHECK_HIER_CB_CONDITION() \
379 if (get_transaction_level()<0) return "no hierarchy callbacks allowed in NO_TRANSACTION_MODE"; \
380 if (!loc.is_valid()) return "invalid hierarchy location"
408 #undef CHECK_HIER_CB_CONDITION
410 #if defined(UNIT_TESTS)
450 if (
cb->spec.is_equal_to(newcb) && !
cb->spec.is_marked_for_removal()) {
484 fprintf(stderr,
"test_count_cb: var.add=%p old.val=%i ", counter, *counter);
486 fprintf(stderr,
"new.val=%i\n", *counter);
494 static void re_add_self_cb(
GBDATA *gbe,
int *calledCounter,
GB_CB_TYPE cbtype) {
497 DatabaseCallback dbcb = makeDatabaseCallback(re_add_self_cb, calledCounter);
503 void TEST_db_callbacks_ta_nota() {
510 BOTH_TA_MODES = (NO_TA|WITH_TA)
513 for (TAmode ta_mode = NO_TA; ta_mode <= WITH_TA; ta_mode = TAmode(ta_mode+1)) {
517 TEST_ANNOTATE(ta_mode == NO_TA ?
"NO_TA" :
"WITH_TA");
518 if (ta_mode == NO_TA) {
539 int c_son_created = 0;
546 #define CHCB_COUNTERS_EXPECTATION(e1c,e2c,cc,csc) \
547 that(e1_changed).is_equal_to(e1c), \
548 that(e2_changed).is_equal_to(e2c), \
549 that(c_changed).is_equal_to(cc), \
550 that(c_son_created).is_equal_to(csc)
552 #define DLCB_COUNTERS_EXPECTATION(e1d,e2d,e3d,cd) \
553 that(e1_deleted).is_equal_to(e1d), \
554 that(e2_deleted).is_equal_to(e2d), \
555 that(e3_deleted).is_equal_to(e3d), \
556 that(c_deleted).is_equal_to(cd)
558 #define TEST_EXPECT_CHCB_COUNTERS(e1c,e2c,cc,csc,tam) do{ if (ta_mode & (tam)) TEST_EXPECTATION(all().of(CHCB_COUNTERS_EXPECTATION(e1c,e2c,cc,csc))); }while(0)
559 #define TEST_EXPECT_CHCB___WANTED(e1c,e2c,cc,csc,tam) do{ if (ta_mode & (tam)) TEST_EXPECTATION__WANTED(all().of(CHCB_COUNTERS_EXPECTATION(e1c,e2c,cc,csc))); }while(0)
561 #define TEST_EXPECT_DLCB_COUNTERS(e1d,e2d,e3d,cd,tam) do{ if (ta_mode & (tam)) TEST_EXPECTATION(all().of(DLCB_COUNTERS_EXPECTATION(e1d,e2d,e3d,cd))); }while(0)
562 #define TEST_EXPECT_DLCB___WANTED(e1d,e2d,e3d,cd,tam) do{ if (ta_mode & (tam)) TEST_EXPECTATION__WANTED(all().of(DLCB_COUNTERS_EXPECTATION(e1d,e2d,e3d,cd))); }while(0)
564 #define TEST_EXPECT_COUNTER(tam,cnt,expected) do{ if (ta_mode & (tam)) TEST_EXPECT_EQUAL(cnt, expected); }while(0)
565 #define TEST_EXPECT_COUNTER__BROKEN(tam,cnt,expected,got) do{ if (ta_mode & (tam)) TEST_EXPECT_EQUAL__BROKEN(cnt, expected, got); }while(0)
567 #define RESET_CHCB_COUNTERS() do{ e1_changed = e2_changed = c_changed = c_son_created = 0; }while(0)
568 #define RESET_DLCB_COUNTERS() do{ e1_deleted = e2_deleted = e3_deleted = c_deleted = 0; }while(0)
569 #define RESET_ALL_CB_COUNTERS() do{ RESET_CHCB_COUNTERS(); RESET_DLCB_COUNTERS(); }while(0)
581 TEST_EXPECT_CHCB_COUNTERS(0, 0, 0, 0, BOTH_TA_MODES);
590 TEST_EXPECT_CHCB_COUNTERS(1, 1, 1, 0, NO_TA);
591 TEST_EXPECT_CHCB_COUNTERS(0, 0, 0, 0, WITH_TA);
596 TEST_EXPECT_CHCB_COUNTERS(1, 1, 1, 0, NO_TA);
597 TEST_EXPECT_CHCB_COUNTERS(1, 1, 1, 0, WITH_TA);
600 RESET_CHCB_COUNTERS();
605 TEST_EXPECT_CHCB_COUNTERS(0, 0, 0, 0, NO_TA);
606 TEST_EXPECT_CHCB___WANTED(0, 0, 1, 1, NO_TA);
607 TEST_EXPECT_CHCB_COUNTERS(0, 0, 1, 1, WITH_TA);
610 RESET_CHCB_COUNTERS();
615 TEST_EXPECT_CHCB_COUNTERS(0, 0, 1, 0, BOTH_TA_MODES);
619 RESET_CHCB_COUNTERS();
628 TEST_EXPECT_CHCB_COUNTERS(0, 0, 0, 0, BOTH_TA_MODES);
635 TEST_EXPECT_DLCB_COUNTERS(0, 1, 1, 0, NO_TA);
636 TEST_EXPECT_DLCB_COUNTERS(0, 0, 0, 0, WITH_TA);
639 TEST_EXPECT_CHCB_COUNTERS(0, 0, 1, 0, WITH_TA);
640 TEST_EXPECT_CHCB_COUNTERS(0, 0, 0, 0, NO_TA);
641 TEST_EXPECT_CHCB___WANTED(0, 0, 1, 1, NO_TA);
643 TEST_EXPECT_DLCB_COUNTERS(0, 1, 1, 0, BOTH_TA_MODES);
645 RESET_ALL_CB_COUNTERS();
650 TEST_EXPECT_CHCB_COUNTERS(0, 0, 0, 0, BOTH_TA_MODES);
651 TEST_EXPECT_DLCB_COUNTERS(1, 0, 0, 1, BOTH_TA_MODES);
681 TEST_EXPECT_COUNTER(NO_TA, counter1, 0);
682 TEST_EXPECT_COUNTER(WITH_TA, counter1, 1);
683 TEST_EXPECT_COUNTER(BOTH_TA_MODES, counter2, 0);
685 counter1 = 0; counter2 = 0;
692 TEST_EXPECT_COUNTER(BOTH_TA_MODES, counter1, 0);
693 TEST_EXPECT_COUNTER(BOTH_TA_MODES, counter2, 0);
696 TEST_EXPECT_COUNTER(BOTH_TA_MODES, counter1, 1);
697 TEST_EXPECT_COUNTER(BOTH_TA_MODES, counter2, 0);
700 TEST_EXPECT_COUNTER(BOTH_TA_MODES, counter1, 1);
701 TEST_EXPECT_COUNTER(BOTH_TA_MODES, counter2, 1);
704 TEST_EXPECT_COUNTER(BOTH_TA_MODES, counter1, 1);
705 TEST_EXPECT_COUNTER(BOTH_TA_MODES, counter2, 1);
719 calledWith(
GBDATA *gbd_,
GB_CB_TYPE type_) : gbd(gbd_), type(type_), time_called(++timer) {}
725 class callback_trace;
728 static ct_registry *SINGLETON;
730 typedef list<callback_trace*> ctl;
744 static ct_registry *instance() {
gb_assert(SINGLETON);
return SINGLETON; }
746 void add(callback_trace *ct) { traces.push_back(ct); }
747 void remove(callback_trace *ct) { traces.remove(ct); }
751 ct_registry *ct_registry::SINGLETON =
NULp;
753 int calledWith::timer = 0;
755 class callback_trace {
756 typedef list<calledWith> calledList;
757 typedef calledList::iterator calledIter;
762 calledIter find(
GBDATA *gbd) {
763 calledIter c = called.begin();
764 while (c != called.end()) {
765 if (c->gbd == gbd)
break;
771 calledIter c = called.begin();
772 while (c != called.end()) {
773 if (c->type&exp_type)
break;
779 calledIter c = called.begin();
780 while (c != called.end()) {
781 if (c->gbd == gbd && (c->type&exp_type))
break;
787 bool removed(calledIter c) {
788 if (c == called.end())
return false;
794 callback_trace(
const char *name_)
798 ct_registry::instance()->add(
this);
802 ct_registry::instance()->remove(
this);
805 const string& get_name()
const {
return name; }
807 void set_called_by(
GBDATA *gbd,
GB_CB_TYPE type) { called.push_back(calledWith(gbd, type)); }
809 bool was_called_by(
GBDATA *gbd) {
return removed(find(gbd)); }
810 bool was_called_by(
GB_CB_TYPE exp_type) {
return removed(find(exp_type)); }
811 bool was_called_by(
GBDATA *gbd,
GB_CB_TYPE exp_type) {
return removed(find(gbd, exp_type)); }
814 calledIter found = find(gbd, exp_type);
815 if (found == called.end())
return -1;
817 int t = found->time_called;
822 bool was_not_called()
const {
return called.empty(); }
823 bool was_called()
const {
return !was_not_called(); }
831 for (ctl::iterator t = traces.begin(); t != traces.end(); ++t) {
832 callback_trace *ct = *t;
833 if (ct->was_called()) {
837 const char *failing_trace = ct->get_name().c_str();
840 expected.
add(
all().ofgroup(bad_trace));
844 return all().ofgroup(expected);
848 static void some_cb(
GBDATA *gbd, callback_trace *trace,
GB_CB_TYPE cbtype) {
849 trace->set_called_by(gbd, cbtype);
852 #define TRACESTRUCT(ELEM,FLAVOR) trace_##ELEM##_##FLAVOR
853 #define HIERARCHY_TRACESTRUCT(ELEM,FLAVOR) traceHier_##ELEM##_##FLAVOR
855 #define CONSTRUCT(name) name(#name) // pass instance-name to callback_trace-ctor as char*
856 #define TRACECONSTRUCT(ELEM,FLAVOR) CONSTRUCT(TRACESTRUCT(ELEM,FLAVOR))
857 #define HIERARCHY_TRACECONSTRUCT(ELEM,FLAVOR) CONSTRUCT(HIERARCHY_TRACESTRUCT(ELEM,FLAVOR))
859 #define ADD_CHANGED_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_add_callback(elem, GB_CB_CHANGED, makeDatabaseCallback(some_cb, &TRACESTRUCT(elem,changed))))
860 #define ADD_DELETED_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_add_callback(elem, GB_CB_DELETE, makeDatabaseCallback(some_cb, &TRACESTRUCT(elem,deleted))))
861 #define ADD_NWCHILD_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_add_callback(elem, GB_CB_SON_CREATED, makeDatabaseCallback(some_cb, &TRACESTRUCT(elem,newchild))))
863 #define ADD_CHANGED_HIERARCHY_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_add_hierarchy_callback(elem, GB_CB_CHANGED, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(elem,changed))))
864 #define ADD_DELETED_HIERARCHY_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_add_hierarchy_callback(elem, GB_CB_DELETE, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(elem,deleted))))
865 #define ADD_NWCHILD_HIERARCHY_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_add_hierarchy_callback(elem, GB_CB_SON_CREATED, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(elem,newchild))))
867 #define ADD_CHANGED_HIERARCHY_CALLBACK2(gbm,path,id) TEST_EXPECT_NO_ERROR(GB_add_hierarchy_callback(gbm, path, GB_CB_CHANGED, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(id,changed))))
868 #define ADD_DELETED_HIERARCHY_CALLBACK2(gbm,path,id) TEST_EXPECT_NO_ERROR(GB_add_hierarchy_callback(gbm, path, GB_CB_DELETE, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(id,deleted))))
869 #define ADD_NWCHILD_HIERARCHY_CALLBACK2(gbm,path,id) TEST_EXPECT_NO_ERROR(GB_add_hierarchy_callback(gbm, path, GB_CB_SON_CREATED, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(id,newchild))))
871 #define ENSURE_CHANGED_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_ensure_callback(elem, GB_CB_CHANGED, makeDatabaseCallback(some_cb, &TRACESTRUCT(elem,changed))))
872 #define ENSURE_DELETED_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_ensure_callback(elem, GB_CB_DELETE, makeDatabaseCallback(some_cb, &TRACESTRUCT(elem,deleted))))
873 #define ENSURE_NWCHILD_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_ensure_callback(elem, GB_CB_SON_CREATED, makeDatabaseCallback(some_cb, &TRACESTRUCT(elem,newchild))))
875 #define REMOVE_CHANGED_CALLBACK(elem) GB_remove_callback(elem, GB_CB_CHANGED, makeDatabaseCallback(some_cb, &TRACESTRUCT(elem,changed)))
876 #define REMOVE_DELETED_CALLBACK(elem) GB_remove_callback(elem, GB_CB_DELETE, makeDatabaseCallback(some_cb, &TRACESTRUCT(elem,deleted)))
877 #define REMOVE_NWCHILD_CALLBACK(elem) GB_remove_callback(elem, GB_CB_SON_CREATED, makeDatabaseCallback(some_cb, &TRACESTRUCT(elem,newchild)))
879 #define REMOVE_CHANGED_HIERARCHY_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_remove_hierarchy_callback(elem, GB_CB_CHANGED, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(elem,changed))))
880 #define REMOVE_DELETED_HIERARCHY_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_remove_hierarchy_callback(elem, GB_CB_DELETE, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(elem,deleted))))
881 #define REMOVE_NWCHILD_HIERARCHY_CALLBACK(elem) TEST_EXPECT_NO_ERROR(GB_remove_hierarchy_callback(elem, GB_CB_SON_CREATED, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(elem,newchild))))
883 #define REMOVE_CHANGED_HIERARCHY_CALLBACK2(gbm,path,id) TEST_EXPECT_NO_ERROR(GB_remove_hierarchy_callback(gbm, path, GB_CB_CHANGED, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(id, changed))))
884 #define REMOVE_DELETED_HIERARCHY_CALLBACK2(gbm,path,id) TEST_EXPECT_NO_ERROR(GB_remove_hierarchy_callback(gbm, path, GB_CB_DELETE, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(id, deleted))))
885 #define REMOVE_NWCHILD_HIERARCHY_CALLBACK2(gbm,path,id) TEST_EXPECT_NO_ERROR(GB_remove_hierarchy_callback(gbm, path, GB_CB_SON_CREATED, makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(id, newchild))))
887 #define INIT_CHANGED_CALLBACK(elem) callback_trace TRACECONSTRUCT(elem,changed); ADD_CHANGED_CALLBACK(elem)
888 #define INIT_DELETED_CALLBACK(elem) callback_trace TRACECONSTRUCT(elem,deleted); ADD_DELETED_CALLBACK(elem)
889 #define INIT_NWCHILD_CALLBACK(elem) callback_trace TRACECONSTRUCT(elem,newchild); ADD_NWCHILD_CALLBACK(elem)
891 #define INIT_CHANGED_HIERARCHY_CALLBACK(elem) callback_trace HIERARCHY_TRACECONSTRUCT(elem,changed); ADD_CHANGED_HIERARCHY_CALLBACK(elem)
892 #define INIT_DELETED_HIERARCHY_CALLBACK(elem) callback_trace HIERARCHY_TRACECONSTRUCT(elem,deleted); ADD_DELETED_HIERARCHY_CALLBACK(elem)
893 #define INIT_NWCHILD_HIERARCHY_CALLBACK(elem) callback_trace HIERARCHY_TRACECONSTRUCT(elem,newchild); ADD_NWCHILD_HIERARCHY_CALLBACK(elem)
895 #define INIT_CHANGED_HIERARCHY_CALLBACK2(gbm,path,id) callback_trace HIERARCHY_TRACECONSTRUCT(id,changed); ADD_CHANGED_HIERARCHY_CALLBACK2(gbm,path,id)
896 #define INIT_DELETED_HIERARCHY_CALLBACK2(gbm,path,id) callback_trace HIERARCHY_TRACECONSTRUCT(id,deleted); ADD_DELETED_HIERARCHY_CALLBACK2(gbm,path,id)
897 #define INIT_NWCHILD_HIERARCHY_CALLBACK2(gbm,path,id) callback_trace HIERARCHY_TRACECONSTRUCT(id,newchild); ADD_NWCHILD_HIERARCHY_CALLBACK2(gbm,path,id)
899 #define ENSURE_ENTRY_CALLBACKS(entry) ENSURE_CHANGED_CALLBACK(entry); ENSURE_DELETED_CALLBACK(entry)
900 #define ENSURE_CONTAINER_CALLBACKS(cont) ENSURE_CHANGED_CALLBACK(cont); ENSURE_NWCHILD_CALLBACK(cont); ENSURE_DELETED_CALLBACK(cont)
902 #define REMOVE_ENTRY_CALLBACKS(entry) REMOVE_CHANGED_CALLBACK(entry); REMOVE_DELETED_CALLBACK(entry)
903 #define REMOVE_CONTAINER_CALLBACKS(cont) REMOVE_CHANGED_CALLBACK(cont); REMOVE_NWCHILD_CALLBACK(cont); REMOVE_DELETED_CALLBACK(cont)
905 #define INIT_ENTRY_CALLBACKS(entry) INIT_CHANGED_CALLBACK(entry); INIT_DELETED_CALLBACK(entry)
906 #define INIT_CONTAINER_CALLBACKS(cont) INIT_CHANGED_CALLBACK(cont); INIT_NWCHILD_CALLBACK(cont); INIT_DELETED_CALLBACK(cont)
908 #define TRIGGER_CHANGE(gbd) do { \
909 GB_initial_transaction ta(gb_main); \
910 if (ta.ok()) GB_touch(gbd); \
911 TEST_EXPECT_NO_ERROR(ta.close(NULp)); \
914 #define TRIGGER_2_CHANGES(gbd1, gbd2) do { \
915 GB_initial_transaction ta(gb_main); \
920 TEST_EXPECT_NO_ERROR(ta.close(NULp)); \
923 #define TRIGGER_DELETE(gbd) do { \
924 GB_initial_transaction ta(gb_main); \
925 GB_ERROR error = NULp; \
926 if (ta.ok()) error = GB_delete(gbd); \
927 TEST_EXPECT_NO_ERROR(ta.close(error)); \
930 #define TEST_EXPECT_CB_TRIGGERED(TRACE,GBD,TYPE) TEST_EXPECT(TRACE.was_called_by(GBD, TYPE))
931 #define TEST_EXPECT_CB_TRIGGERED_AT(TRACE,GBD,TYPE,TIME) TEST_EXPECT_EQUAL(TRACE.call_time(GBD, TYPE), TIME)
933 #define TEST_EXPECT_CHANGE_TRIGGERED(GBD) TEST_EXPECT_CB_TRIGGERED(TRACESTRUCT(GBD, changed), GBD, GB_CB_CHANGED)
934 #define TEST_EXPECT_DELETE_TRIGGERED(GBD) TEST_EXPECT_CB_TRIGGERED(TRACESTRUCT(GBD, deleted), GBD, GB_CB_DELETE)
935 #define TEST_EXPECT_NCHILD_TRIGGERED(GBD) TEST_EXPECT_CB_TRIGGERED(TRACESTRUCT(GBD, newchild), GBD, GB_CB_SON_CREATED)
937 #define TEST_EXPECT_CHANGE_HIER_TRIGGERED(NAME,GBD) TEST_EXPECT_CB_TRIGGERED(HIERARCHY_TRACESTRUCT(NAME, changed), GBD, GB_CB_CHANGED)
938 #define TEST_EXPECT_DELETE_HIER_TRIGGERED(NAME,GBD) TEST_EXPECT_CB_TRIGGERED(HIERARCHY_TRACESTRUCT(NAME, deleted), GBD, GB_CB_DELETE)
939 #define TEST_EXPECT_NCHILD_HIER_TRIGGERED(NAME,GBD) TEST_EXPECT_CB_TRIGGERED(HIERARCHY_TRACESTRUCT(NAME, newchild), GBD, GB_CB_SON_CREATED)
942 #define TEST_EXPECT_CHANGE_TRIGGERED_AT(TRACE,GBD,TIME) TEST_EXPECT_CB_TRIGGERED_AT(TRACE, GBD, GB_CB_CHANGED, TIME)
943 #define TEST_EXPECT_DELETE_TRIGGERED_AT(TRACE,GBD,TIME) TEST_EXPECT_CB_TRIGGERED_AT(TRACE, GBD, GB_CB_DELETE, TIME)
945 #define TEST_EXPECT_TRIGGERS_CHECKED() TEST_EXPECTATION(trace_registry.expect_all_calls_checked())
947 void TEST_db_callbacks() {
967 ct_registry trace_registry;
968 INIT_CONTAINER_CALLBACKS(cont_top);
969 INIT_CONTAINER_CALLBACKS(cont_son);
970 INIT_ENTRY_CALLBACKS(top);
971 INIT_ENTRY_CALLBACKS(son);
972 INIT_ENTRY_CALLBACKS(grandson);
973 INIT_ENTRY_CALLBACKS(ograndson);
977 TEST_EXPECT_TRIGGERS_CHECKED();
983 TEST_EXPECT_CHANGE_TRIGGERED(top);
984 TEST_EXPECT_TRIGGERS_CHECKED();
989 TEST_EXPECT_TRIGGERS_CHECKED();
996 TEST_EXPECT_CHANGE_TRIGGERED(son);
997 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
998 TEST_EXPECT_TRIGGER__UNWANTED(trace_cont_top_newchild);
999 TEST_EXPECT_TRIGGERS_CHECKED();
1007 TEST_EXPECT_CHANGE_TRIGGERED(grandson);
1008 TEST_EXPECT_CHANGE_TRIGGERED(cont_son);
1009 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
1010 TEST_EXPECT_TRIGGERS_CHECKED();
1017 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
1018 TEST_EXPECT_NCHILD_TRIGGERED(cont_top);
1019 TEST_EXPECT_TRIGGERS_CHECKED();
1024 TEST_EXPECT_CHANGE_TRIGGERED(cont_son);
1025 TEST_EXPECT_NCHILD_TRIGGERED(cont_son);
1026 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
1027 TEST_EXPECT_TRIGGERS_CHECKED();
1031 TRIGGER_DELETE(son2);
1032 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
1033 TEST_EXPECT_TRIGGERS_CHECKED();
1035 TRIGGER_DELETE(grandson2);
1036 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
1037 TEST_EXPECT_CHANGE_TRIGGERED(cont_son);
1038 TEST_EXPECT_TRIGGERS_CHECKED();
1042 TRIGGER_DELETE(top);
1043 TEST_EXPECT_DELETE_TRIGGERED(top);
1044 TEST_EXPECT_TRIGGERS_CHECKED();
1046 TRIGGER_DELETE(grandson);
1047 TEST_EXPECT_DELETE_TRIGGERED(grandson);
1048 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
1049 TEST_EXPECT_CHANGE_TRIGGERED(cont_son);
1050 TEST_EXPECT_TRIGGERS_CHECKED();
1052 TRIGGER_DELETE(cont_son);
1053 TEST_EXPECT_DELETE_TRIGGERED(ograndson);
1054 TEST_EXPECT_DELETE_TRIGGERED(cont_son);
1055 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
1056 TEST_EXPECT_TRIGGERS_CHECKED();
1061 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
1062 TEST_EXPECT_NCHILD_TRIGGERED(cont_top);
1063 TEST_EXPECT_TRIGGERS_CHECKED();
1067 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
1068 TEST_EXPECT_TRIGGERS_CHECKED();
1071 TEST_EXPECT_TRIGGERS_CHECKED();
1076 ENSURE_CONTAINER_CALLBACKS(cont_top);
1077 ENSURE_CONTAINER_CALLBACKS(cont_son);
1078 ENSURE_ENTRY_CALLBACKS(top);
1079 ENSURE_ENTRY_CALLBACKS(son);
1080 ENSURE_ENTRY_CALLBACKS(grandson);
1082 TEST_EXPECT_TRIGGERS_CHECKED();
1086 TRIGGER_CHANGE(son);
1087 TEST_EXPECT_CHANGE_TRIGGERED(son);
1088 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
1089 TEST_EXPECT_TRIGGERS_CHECKED();
1094 TEST_EXPECT_CHANGE_TRIGGERED(cont_top);
1095 TEST_EXPECT_NCHILD_TRIGGERED(cont_top);
1096 TEST_EXPECT_TRIGGERS_CHECKED();
1101 REMOVE_ENTRY_CALLBACKS(son);
1102 REMOVE_CONTAINER_CALLBACKS(cont_top);
1104 TEST_EXPECT_TRIGGERS_CHECKED();
1108 TRIGGER_CHANGE(son);
1109 TEST_EXPECT_TRIGGERS_CHECKED();
1114 TEST_EXPECT_TRIGGERS_CHECKED();
1118 REMOVE_ENTRY_CALLBACKS(grandson);
1119 REMOVE_ENTRY_CALLBACKS(top);
1120 REMOVE_CONTAINER_CALLBACKS(cont_son);
1127 const char *DBNAME =
"tmp_hier_cb.arb";
1129 for (
int pass = 1; pass<=2; ++pass) {
1130 bool creating = pass == 1;
1131 TEST_ANNOTATE(
GBS_global_string(
"%s database", creating ?
"created" :
"reloaded"));
1224 char *path_grandson = loc_grandson.get_db_path(gb_main);
1231 char *path_grandson2 = loc_grandson2.get_db_path(gb_main);
1234 free(path_grandson2);
1235 free(path_grandson);
1261 TEST_EXPECT_EQUAL(&*SmartCharPtr(loc_submatch.get_db_path(gb_main)),
"cont_son/grandson");
1279 GBDATA *anySonContainer = cont_son11;
1280 GBDATA *anotherSonContainer = cont_son22;
1282 GBDATA *anyGrandson = grandson221;
1283 GBDATA *anotherGrandson = grandson112;
1284 GBDATA *elimGrandson = grandson222;
1285 GBDATA *elimGrandson2 = grandson111;
1288 ct_registry trace_registry;
1289 callback_trace HIERARCHY_TRACECONSTRUCT(anyElem,changed);
1290 INIT_CHANGED_HIERARCHY_CALLBACK(anyGrandson);
1291 INIT_DELETED_HIERARCHY_CALLBACK(anyGrandson);
1292 INIT_DELETED_HIERARCHY_CALLBACK(anySonContainer);
1293 INIT_NWCHILD_HIERARCHY_CALLBACK(anySonContainer);
1296 INIT_CHANGED_HIERARCHY_CALLBACK2(gb_main,
"son", sub_any_son);
1297 INIT_DELETED_HIERARCHY_CALLBACK2(gb_main,
"cont_son/grandson", sub_son_grandson);
1298 INIT_DELETED_HIERARCHY_CALLBACK2(gb_main,
"cont_son", sub_any_sonCont);
1299 INIT_NWCHILD_HIERARCHY_CALLBACK2(gb_main,
"cont_son", sub_contson);
1302 TEST_EXPECT_TRIGGERS_CHECKED();
1305 TRIGGER_CHANGE(anyGrandson);
1306 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyGrandson, anyGrandson);
1307 TEST_EXPECT_TRIGGERS_CHECKED();
1310 TRIGGER_CHANGE(anotherGrandson);
1311 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyGrandson, anotherGrandson);
1312 TEST_EXPECT_TRIGGERS_CHECKED();
1315 TRIGGER_CHANGE(anySon);
1316 TEST_EXPECT_CHANGE_HIER_TRIGGERED(sub_any_son, anySon);
1317 TEST_EXPECT_TRIGGERS_CHECKED();
1320 TRIGGER_CHANGE(anyGrandson);
1321 TRIGGER_CHANGE(anotherGrandson);
1322 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyGrandson, anyGrandson);
1323 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyGrandson, anotherGrandson);
1324 TEST_EXPECT_TRIGGERS_CHECKED();
1327 TRIGGER_2_CHANGES(anyGrandson, anotherGrandson);
1328 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyGrandson, anyGrandson);
1329 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyGrandson, anotherGrandson);
1330 TEST_EXPECT_TRIGGERS_CHECKED();
1340 TEST_EXPECT_NCHILD_HIER_TRIGGERED(anySonContainer, anySonContainer);
1341 TEST_EXPECT_NCHILD_HIER_TRIGGERED(sub_contson, anySonContainer);
1342 TEST_EXPECT_TRIGGERS_CHECKED();
1353 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyGrandson, newGrandson);
1354 TEST_EXPECT_NCHILD_HIER_TRIGGERED(anySonContainer, anotherSonContainer);
1355 TEST_EXPECT_NCHILD_HIER_TRIGGERED(anySonContainer, anySonContainer);
1356 TEST_EXPECT_NCHILD_HIER_TRIGGERED(sub_contson, anotherSonContainer);
1357 TEST_EXPECT_NCHILD_HIER_TRIGGERED(sub_contson, anySonContainer);
1358 TEST_EXPECT_TRIGGERS_CHECKED();
1366 TEST_EXPECT_DELETE_HIER_TRIGGERED(anyGrandson, elimGrandson);
1367 TEST_EXPECT_DELETE_HIER_TRIGGERED(sub_son_grandson, elimGrandson);
1368 TEST_EXPECT_TRIGGERS_CHECKED();
1371 calledWith::timer = 0;
1374 INIT_CHANGED_CALLBACK(anotherGrandson);
1375 INIT_DELETED_CALLBACK(elimGrandson2);
1379 TEST_EXPECT_TRIGGERS_CHECKED();
1391 TEST_EXPECT_DELETE_TRIGGERED_AT(traceHier_anyGrandson_deleted, elimGrandson2, 1);
1392 TEST_EXPECT_DELETE_TRIGGERED_AT(traceHier_sub_son_grandson_deleted, elimGrandson2, 2);
1393 TEST_EXPECT_DELETE_TRIGGERED_AT(trace_elimGrandson2_deleted, elimGrandson2, 3);
1394 TEST_EXPECT_CHANGE_TRIGGERED_AT(traceHier_anyGrandson_changed, anotherGrandson, 4);
1395 TEST_EXPECT_CHANGE_TRIGGERED_AT(trace_anotherGrandson_changed, anotherGrandson, 5);
1397 TEST_EXPECT_TRIGGERS_CHECKED();
1400 REMOVE_CHANGED_HIERARCHY_CALLBACK(anyGrandson);
1401 REMOVE_DELETED_HIERARCHY_CALLBACK(anyGrandson);
1403 REMOVE_DELETED_HIERARCHY_CALLBACK2(gb_main,
"cont_son/grandson", sub_son_grandson);
1405 TRIGGER_CHANGE(anyGrandson);
1410 TEST_EXPECT_TRIGGERS_CHECKED();
1415 anyElem = top1; ADD_CHANGED_HIERARCHY_CALLBACK(anyElem);
1416 anyElem = son11; ADD_CHANGED_HIERARCHY_CALLBACK(anyElem);
1419 TRIGGER_CHANGE(top1);
1420 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyElem, top1);
1421 TEST_EXPECT_TRIGGERS_CHECKED();
1423 TRIGGER_CHANGE(son11);
1424 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyElem, son11);
1425 TEST_EXPECT_CHANGE_HIER_TRIGGERED(sub_any_son, son11);
1426 TEST_EXPECT_TRIGGERS_CHECKED();
1428 TRIGGER_2_CHANGES(top1, son11);
1429 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyElem, top1);
1430 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyElem, son11);
1431 TEST_EXPECT_CHANGE_HIER_TRIGGERED(sub_any_son, son11);
1432 TEST_EXPECT_TRIGGERS_CHECKED();
1435 anyElem = son11; REMOVE_CHANGED_HIERARCHY_CALLBACK(anyElem);
1437 TRIGGER_2_CHANGES(top1, son11);
1439 TEST_EXPECT_CHANGE_HIER_TRIGGERED(sub_any_son, son11);
1440 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyElem, top1);
1441 TEST_EXPECT_TRIGGERS_CHECKED();
1446 const char *locpath =
"/cont_top/son";
1447 DatabaseCallback dbcb = makeDatabaseCallback(some_cb, &HIERARCHY_TRACESTRUCT(anyElem,changed));
1455 TRIGGER_2_CHANGES(top1, son11);
1456 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyElem, top1);
1457 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyElem, son11);
1458 TEST_EXPECT_CHANGE_HIER_TRIGGERED(sub_any_son, son11);
1459 TEST_EXPECT_TRIGGERS_CHECKED();
1466 TRIGGER_2_CHANGES(top1, son11);
1468 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyElem, top1);
1469 TEST_EXPECT_CHANGE_HIER_TRIGGERED(sub_any_son, son11);
1470 TEST_EXPECT_TRIGGERS_CHECKED();
1473 const char *invalidPath =
"//such";
1482 const char *unknownPath =
"/unknownPath/unknownEntry";
1487 TEST_EXPECT_TRIGGERS_CHECKED();
1492 TEST_EXPECT_RESULT__NOERROREXPORTED(gb_unknown =
GB_search(gb_main, unknownPath,
GB_STRING));
1494 TEST_EXPECT_TRIGGERS_CHECKED();
1496 TRIGGER_CHANGE(gb_unknown);
1497 TEST_EXPECT_CHANGE_HIER_TRIGGERED(anyElem, gb_unknown);
1498 TEST_EXPECT_TRIGGERS_CHECKED();
1502 GBDATA *emptySonContainer = cont_son12;
1504 TRIGGER_DELETE(emptySonContainer);
1505 TEST_EXPECT_DELETE_HIER_TRIGGERED(anySonContainer, emptySonContainer);
1506 TEST_EXPECT_DELETE_HIER_TRIGGERED(sub_any_sonCont, emptySonContainer);
1507 TEST_EXPECT_TRIGGERS_CHECKED();
1509 TRIGGER_DELETE(cont_top1);
1510 TEST_EXPECT_DELETE_HIER_TRIGGERED(anySonContainer, cont_son11);
1511 TEST_EXPECT_DELETE_HIER_TRIGGERED(sub_any_sonCont, cont_son11);
1512 TEST_EXPECT_DELETE_HIER_TRIGGERED(sub_any_sonCont, cson_deep);
1513 TEST_EXPECT_TRIGGERS_CHECKED();
1515 TRIGGER_DELETE(cson);
1516 TEST_EXPECT_DELETE_HIER_TRIGGERED(sub_any_sonCont, cson);
1517 TEST_EXPECT_TRIGGERS_CHECKED();
1526 #endif // UNIT_TESTS
GB_ERROR GB_begin_transaction(GBDATA *gbd)
GB_MAIN_TYPE * gb_get_main_during_cb()
void gb_remove_callbacks_marked_for_deletion(GBDATA *gbd)
#define appendcbtype(cbt)
GBDATA * GB_open(const char *path, const char *opent)
void GB_remove_all_callbacks_to(GBDATA *gbd, GB_CB_TYPE type, GB_CB func)
const char * get_db_path(const AW_awar *awar)
GB_TYPES GB_TYPE_TS(gb_transaction_save *ts)
GB_CBUFFER gb_uncompress_data(GBDATA *gbd, GB_CBUFFER source, size_t size)
bool operator()(const gb_callback &cb) const
void cut_tail(size_t byte_count)
GB_ERROR GB_commit_transaction(GBDATA *gbd)
const char * GBS_funptr2readable(void *funptr, bool stripARBHOME)
void add_to_callback_chain(gb_callback_list *&head, const TypedDatabaseCallback &cbs)
listtype::iterator itertype
GB_ERROR GB_add_hierarchy_callback(GBDATA *gb_main, const char *db_path, GB_CB_TYPE type, const DatabaseCallback &dbcb)
const gb_triggered_callback * get_tail() const
return string(buffer, length)
void GB_atclose_callback(GBDATA *gbd, const DatabaseCallback &atClose)
void gb_remove_callbacks_that(GBDATA *gbd, PRED shallRemove)
GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
const char * quark2key(GB_MAIN_TYPE *Main, GBQUARK key_quark)
GB_ERROR GB_add_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
#define INVALIDATE_IF(cond)
#define ASSERT_NO_ERROR(errorExpr)
GB_ERROR gb_add_callback(GBDATA *gbd, const TypedDatabaseCallback &cbs)
GB_MAIN_TYPE * GB_MAIN(GBDATA *gbd)
#define CHECK_HIER_CB_CONDITION()
long GB_GETSIZE_TS(gb_transaction_save *ts)
bool contains_unremoved_callback(const CB &like) const
GBDATA * GB_nextEntry(GBDATA *entry)
const gb_hierarchy_location & get_location() const
bool is_marked_for_removal() const
NOT4PERL const void * GB_read_old_value()
char * get_db_path(GBDATA *gb_main) const
const char * GBS_global_string(const char *templat,...)
bool has_pending_change_callback() const
void(* GB_CB)(GBDATA *, int *clientdata, GB_CB_TYPE gbtype)
void cat(const char *from)
GBQUARK gb_find_or_create_quark(GB_MAIN_TYPE *Main, const char *key)
int GB_unlink(const char *path)
bool is_equal_to(const TypedDatabaseCallback &other) const
void forget_hierarchy_cbs()
gb_transaction_save * old
bool operator()(const gb_callback &cb) const
GB_ERROR GB_delete(GBDATA *&source)
GB_ERROR GB_export_error(const char *error)
TypedDatabaseCallback spec
static GB_MAIN_TYPE * inside_callback_main
GBDATA * GB_create_container(GBDATA *father, const char *key)
#define TEST_EXPECT(cond)
#define does_differ_from(val)
GBDATA * GB_create(GBDATA *father, const char *key, GB_TYPES type)
char * GB_get_callback_info(GBDATA *gbd)
char * GB_GETDATA_TS(gb_transaction_save *ts)
int gb_convert_type_2_appendix_size[]
GB_ERROR GB_save_as(GBDATA *gbd, const char *path, const char *savetype)
IsSpecificHierarchyCallback(const gb_hierarchy_location &loc_, const TypedDatabaseCallback &cb)
bool operator()(const gb_callback &cb) const
#define TEST_REJECT(cond)
#define TEST_REJECT_NULL(n)
static void dummy_db_cb(GBDATA *, GB_CB_TYPE)
static void error(const char *msg)
GB_ERROR add_hierarchy_cb(const gb_hierarchy_location &loc, const TypedDatabaseCallback &dbcb)
bool sig_is_equal_to(const TypedDatabaseCallback &other) const
void call_and_forget(GB_CB_TYPE allowedTypes)
expectation_group & add(const expectation &e)
void remove_callbacks_that(PRED shallRemove)
bool has_pending_delete_callback() const
GB_CB_TYPE get_type() const
char * cbtype2readable(GB_CB_TYPE type)
GB_ERROR GB_write_int(GBDATA *gbd, long i)
bool operator()(const gb_callback &cb) const
TypedDatabaseCallback with_type_changed_to(GB_CB_TYPE type_) const
gb_hierarchy_location loc
#define __ATTR__REDUCED_OPTIMIZE
static GB_CSTR gb_read_pntr_ts(GBDATA *gbd, gb_transaction_save *ts)
void GB_test_transaction(GB_MAIN_TYPE *Main)
GB_ERROR GB_undo(GBDATA *gb_main, GB_UNDO_TYPE type) __ATTR__USERESULT
char * GBT_join_strings(const CharPtrArray &strings, char separator)
gb_callback_list * callback
GB_ERROR GB_remove_hierarchy_callback(GBDATA *gb_main, const char *db_path, GB_CB_TYPE type, const DatabaseCallback &dbcb)
static gb_triggered_callback * currently_called_back
GB_ERROR close(GB_ERROR error)
void GB_write_flag(GBDATA *gbd, long flag)
gb_callback_list * close_callbacks
void GB_touch(GBDATA *gbd)
void GB_remove_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
#define TEST_EXPECT_NO_ERROR(call)
listtype::const_iterator const_itertype
IsSpecificCallback(const TypedDatabaseCallback &cb)
#define TEST_EXPECT_ERROR_CONTAINS(call, part)
IsCallback(GB_CB func_, GB_CB_TYPE type_)
void GBT_split_string(ConstStrArray &dest, const char *namelist, const char *separator, SplitMode mode)
GB_ERROR GB_ensure_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
GB_ERROR remove_hierarchy_cb(const gb_hierarchy_location &loc, const TypedDatabaseCallback &dbcb)
GB_ERROR GB_no_transaction(GBDATA *gbd) __ATTR__USERESULT
GB_ERROR GB_request_undo_type(GBDATA *gb_main, GB_UNDO_TYPE type) __ATTR__USERESULT_TODO
GB_transaction ta(gb_var)
gb_hierarchy_location(GBDATA *gbd)
GBDATA * GB_get_gb_main_during_cb()
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
NOT4PERL bool GB_inside_callback(GBDATA *of_gbd, GB_CB_TYPE cbtype)
int gb_convert_type_2_sizeof[]
void call_pending_callbacks()
#define TEST_EXPECT_EQUAL(expr, want)
TypedDatabaseCallback spec
GBDATA * GB_entry(GBDATA *father, const char *key)
unsigned int compressed_data
gb_callback_list * get_callbacks() const
char * GBS_global_string_copy(const char *templat,...)
void GB_close(GBDATA *gbd)
void add(const CB &newcb)