Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
libcifpp
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
libcifpp
Commits
c3963bc4
Commit
c3963bc4
authored
Oct 06, 2020
by
Maarten L. Hekkelman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixed linked update (regression)
parent
23bd51ac
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
624 additions
and
84 deletions
+624
-84
include/cif++/Cif++.hpp
+90
-10
src/Cif++.cpp
+10
-7
src/CifParser.cpp
+89
-65
test/unit-test.cpp
+435
-2
No files found.
include/cif++/Cif++.hpp
View file @
c3963bc4
...
...
@@ -718,11 +718,13 @@ struct ConditionImpl
virtual
void
prepare
(
const
Category
&
c
)
{}
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
=
0
;
virtual
void
str
(
std
::
ostream
&
os
)
const
=
0
;
};
struct
AllConditionImpl
:
public
ConditionImpl
{
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
return
true
;
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
"*"
;
}
};
struct
orConditionImpl
;
...
...
@@ -789,11 +791,20 @@ class Condition
std
::
swap
(
mPrepared
,
rhs
.
mPrepared
);
}
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Condition
&
cond
);
private
:
detail
::
ConditionImpl
*
mImpl
;
bool
mPrepared
=
false
;
};
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Condition
&
cond
)
{
if
(
cond
.
mImpl
)
cond
.
mImpl
->
str
(
os
);
return
os
;
}
namespace
detail
{
...
...
@@ -808,7 +819,12 @@ struct KeyIsEmptyConditionImpl : public ConditionImpl
{
return
r
[
mItemIx
].
empty
();
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
mItemTag
<<
" IS NULL"
;
}
std
::
string
mItemTag
;
size_t
mItemIx
;
};
...
...
@@ -816,8 +832,8 @@ struct KeyIsEmptyConditionImpl : public ConditionImpl
struct
KeyCompareConditionImpl
:
public
ConditionImpl
{
template
<
typename
COMP
>
KeyCompareConditionImpl
(
const
std
::
string
&
ItemTag
,
COMP
&&
comp
)
:
mItemTag
(
ItemTag
),
mComp
(
std
::
move
(
comp
))
{}
KeyCompareConditionImpl
(
const
std
::
string
&
ItemTag
,
COMP
&&
comp
,
const
std
::
string
&
s
)
:
mItemTag
(
ItemTag
),
mComp
(
std
::
move
(
comp
))
,
mStr
(
s
)
{}
virtual
void
prepare
(
const
Category
&
c
);
...
...
@@ -826,10 +842,16 @@ struct KeyCompareConditionImpl : public ConditionImpl
return
mComp
(
c
,
r
,
mCaseInsensitive
);
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
mItemTag
<<
(
mCaseInsensitive
?
"^ "
:
" "
)
<<
mStr
;
}
std
::
string
mItemTag
;
size_t
mItemIx
;
bool
mCaseInsensitive
=
false
;
std
::
function
<
bool
(
const
Category
&
,
const
Row
&
,
bool
)
>
mComp
;
std
::
string
mStr
;
};
struct
KeyMatchesConditionImpl
:
public
ConditionImpl
...
...
@@ -843,6 +865,11 @@ struct KeyMatchesConditionImpl : public ConditionImpl
{
return
std
::
regex_match
(
r
[
mItemIx
].
as
<
std
::
string
>
(),
mRx
);
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
mItemTag
<<
" =~ expression"
;
}
std
::
string
mItemTag
;
size_t
mItemIx
;
...
...
@@ -858,6 +885,10 @@ struct anyIsConditionImpl : public ConditionImpl
:
mValue
(
value
)
{}
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
;
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
"<any> == "
<<
mValue
;
}
valueType
mValue
;
};
...
...
@@ -868,6 +899,10 @@ struct anyMatchesConditionImpl : public ConditionImpl
:
mRx
(
rx
)
{}
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
;
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
"<any> =~ expression"
;
}
std
::
regex
mRx
;
};
...
...
@@ -880,6 +915,11 @@ struct allConditionImpl : public ConditionImpl
{
return
true
;
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
"*"
;
}
};
struct
andConditionImpl
:
public
ConditionImpl
...
...
@@ -908,6 +948,15 @@ struct andConditionImpl : public ConditionImpl
return
mA
->
test
(
c
,
r
)
and
mB
->
test
(
c
,
r
);
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
'('
;
mA
->
str
(
os
);
os
<<
") AND ("
;
mB
->
str
(
os
);
os
<<
')'
;
}
ConditionImpl
*
mA
;
ConditionImpl
*
mB
;
};
...
...
@@ -937,7 +986,16 @@ struct orConditionImpl : public ConditionImpl
{
return
mA
->
test
(
c
,
r
)
or
mB
->
test
(
c
,
r
);
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
'('
;
mA
->
str
(
os
);
os
<<
") OR ("
;
mB
->
str
(
os
);
os
<<
')'
;
}
ConditionImpl
*
mA
;
ConditionImpl
*
mB
;
};
...
...
@@ -964,7 +1022,14 @@ struct notConditionImpl : public ConditionImpl
{
return
not
mA
->
test
(
c
,
r
);
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
"NOT ("
;
mA
->
str
(
os
);
os
<<
')'
;
}
ConditionImpl
*
mA
;
};
...
...
@@ -1004,8 +1069,11 @@ struct Key
template
<
typename
T
>
Condition
operator
==
(
const
Key
&
key
,
const
T
&
v
)
{
std
::
ostringstream
s
;
s
<<
"== "
<<
v
;
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
==
0
;
}));
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
==
0
;
}
,
s
.
str
()
));
}
// inline Condition operator==(const Key& key, const detail::ItemReference& v)
...
...
@@ -1037,29 +1105,41 @@ inline Condition operator!=(const Key& key, const char* v)
template
<
typename
T
>
Condition
operator
>
(
const
Key
&
key
,
const
T
&
v
)
{
std
::
ostringstream
s
;
s
<<
">"
<<
v
;
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>
0
;
}));
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>
0
;
}
,
s
.
str
()
));
}
template
<
typename
T
>
Condition
operator
>=
(
const
Key
&
key
,
const
T
&
v
)
{
std
::
ostringstream
s
;
s
<<
">="
<<
v
;
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>=
0
;
}));
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>=
0
;
}
,
s
.
str
()
));
}
template
<
typename
T
>
Condition
operator
<
(
const
Key
&
key
,
const
T
&
v
)
{
std
::
ostringstream
s
;
s
<<
"<"
<<
v
;
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<
0
;
}));
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<
0
;
}
,
s
.
str
()
));
}
template
<
typename
T
>
Condition
operator
<=
(
const
Key
&
key
,
const
T
&
v
)
{
std
::
ostringstream
s
;
s
<<
"<="
<<
v
;
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<=
0
;
}));
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<=
0
;
}
,
s
.
str
()
));
}
template
<>
...
...
src/Cif++.cpp
View file @
c3963bc4
...
...
@@ -2519,7 +2519,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
std
::
string
ck
=
linked
->
mChildKeys
[
ix
];
// TODO add code to *NOT* test mandatory fiels for Empty
// TODO add code to *NOT* test mandatory fiel
d
s for Empty
if
(
pk
==
iv
->
mTag
)
{
...
...
@@ -2529,16 +2529,19 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
else
{
const
char
*
value
=
(
*
this
)[
pk
].
c_str
();
cond
=
std
::
move
(
cond
)
&&
((
Key
(
ck
)
==
value
)
or
Key
(
ck
)
==
Empty
());
if
(
*
value
==
0
)
cond
=
std
::
move
(
cond
)
&&
Key
(
ck
)
==
Empty
();
else
cond
=
std
::
move
(
cond
)
&&
((
Key
(
ck
)
==
value
)
or
Key
(
ck
)
==
Empty
());
}
}
// if (cif::VERBOSE >
2)
//
{
// std::std::cerr << "Parent: " << linked->mParentCategory << " Child: " << linked->mChildCategory << std::
std::endl
// << cond << std::
std::endl;
//
}
if
(
cif
::
VERBOSE
>=
2
)
{
std
::
cerr
<<
"Parent: "
<<
linked
->
mParentCategory
<<
" Child: "
<<
linked
->
mChildCategory
<<
std
::
endl
<<
cond
<<
std
::
endl
;
}
auto
rows
=
childCat
->
find
(
std
::
move
(
cond
));
for
(
auto
&
cr
:
rows
)
...
...
src/CifParser.cpp
View file @
c3963bc4
...
...
@@ -894,86 +894,110 @@ void DictParser::linkItems()
std
::
map
<
std
::
tuple
<
std
::
string
,
std
::
string
>
,
size_t
>
linkIndex
;
std
::
map
<
std
::
tuple
<
std
::
string
,
std
::
string
>
,
int
>
linkGroupIds
;
std
::
vector
<
std
::
tuple
<
std
::
vector
<
std
::
string
>
,
std
::
vector
<
std
::
string
>>>
linkKeys
;
for
(
auto
gl
:
dict
[
"pdbx_item_linked_group_list"
]
)
auto
addLink
=
[
&
](
size_t
ix
,
const
std
::
string
&
pk
,
const
std
::
string
&
ck
)
{
std
::
string
child
,
parent
;
int
link_group_id
;
cif
::
tie
(
child
,
parent
,
link_group_id
)
=
gl
.
get
(
"child_name"
,
"parent_name"
,
"link_group_id"
);
auto
civ
=
mValidator
.
getValidatorForItem
(
child
);
if
(
civ
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
child
+
"' is not specified"
);
auto
piv
=
mValidator
.
getValidatorForItem
(
parent
);
if
(
piv
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
parent
+
"' is not specified"
);
auto
key
=
std
::
make_tuple
(
piv
->
mCategory
->
mName
,
civ
->
mCategory
->
mName
);
if
(
not
linkIndex
.
count
(
key
))
auto
&&
[
pkeys
,
ckeys
]
=
linkKeys
.
at
(
ix
);
bool
found
=
false
;
for
(
size_t
i
=
0
;
i
<
pkeys
.
size
();
++
i
)
{
linkIndex
[
key
]
=
linkKeys
.
size
();
linkKeys
.
push_back
({});
if
(
pkeys
[
i
]
==
pk
and
ckeys
[
i
]
==
ck
)
{
found
=
true
;
break
;
}
}
linkGroupIds
[
key
]
=
link_group_id
;
if
(
not
found
)
{
pkeys
.
push_back
(
pk
);
ckeys
.
push_back
(
ck
);
}
size_t
ix
=
linkIndex
.
at
(
key
);
std
::
get
<
0
>
(
linkKeys
.
at
(
ix
)).
push_back
(
piv
->
mTag
);
std
::
get
<
1
>
(
linkKeys
.
at
(
ix
)).
push_back
(
civ
->
mTag
);
}
};
// for links recorded in categories but not in pdbx_item_linked_group_list
for
(
auto
li
:
mImpl
->
mLinkedItems
)
{
std
::
string
child
,
parent
;
std
::
tie
(
child
,
parent
)
=
li
;
auto
civ
=
mValidator
.
getValidatorForItem
(
child
);
if
(
civ
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
child
+
"' is not specified"
);
auto
piv
=
mValidator
.
getValidatorForItem
(
parent
);
if
(
piv
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
parent
+
"' is not specified"
);
auto
&
linkedGroupList
=
dict
[
"pdbx_item_linked_group_list"
];
auto
key
=
std
::
make_tuple
(
piv
->
mCategory
->
mName
,
civ
->
mCategory
->
mName
);
if
(
not
linkIndex
.
count
(
key
))
if
(
linkedGroupList
.
empty
())
{
// for links recorded in categories but not in pdbx_item_linked_group_list
for
(
auto
li
:
mImpl
->
mLinkedItems
)
{
linkIndex
[
key
]
=
linkKeys
.
size
();
linkKeys
.
push_back
({});
std
::
string
child
,
parent
;
std
::
tie
(
child
,
parent
)
=
li
;
auto
civ
=
mValidator
.
getValidatorForItem
(
child
);
if
(
civ
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
child
+
"' is not specified"
);
auto
piv
=
mValidator
.
getValidatorForItem
(
parent
);
if
(
piv
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
parent
+
"' is not specified"
);
auto
key
=
std
::
make_tuple
(
piv
->
mCategory
->
mName
,
civ
->
mCategory
->
mName
);
if
(
linkIndex
.
count
(
key
))
{
linkIndex
[
key
]
=
linkKeys
.
size
();
linkKeys
.
push_back
({});
}
size_t
ix
=
linkIndex
.
at
(
key
);
addLink
(
ix
,
piv
->
mTag
,
civ
->
mTag
);
}
size_t
ix
=
linkIndex
.
at
(
key
);
std
::
get
<
0
>
(
linkKeys
.
at
(
ix
)).
push_back
(
piv
->
mTag
);
std
::
get
<
1
>
(
linkKeys
.
at
(
ix
)).
push_back
(
civ
->
mTag
);
}
auto
&
linkedGroup
=
dict
[
"pdbx_item_linked_group"
];
// now store the links in the validator
for
(
auto
&
kv
:
linkIndex
)
else
{
ValidateLink
link
=
{};
std
::
tie
(
link
.
mParentCategory
,
link
.
mChildCategory
)
=
kv
.
first
;
for
(
auto
gl
:
linkedGroupList
)
{
std
::
string
child
,
parent
;
int
link_group_id
;
cif
::
tie
(
child
,
parent
,
link_group_id
)
=
gl
.
get
(
"child_name"
,
"parent_name"
,
"link_group_id"
);
auto
civ
=
mValidator
.
getValidatorForItem
(
child
);
if
(
civ
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
child
+
"' is not specified"
);
auto
piv
=
mValidator
.
getValidatorForItem
(
parent
);
if
(
piv
==
nullptr
)
error
(
"in pdbx_item_linked_group_list, item '"
+
parent
+
"' is not specified"
);
auto
key
=
std
::
make_tuple
(
piv
->
mCategory
->
mName
,
civ
->
mCategory
->
mName
);
if
(
not
linkIndex
.
count
(
key
))
{
linkIndex
[
key
]
=
linkKeys
.
size
();
linkKeys
.
push_back
({});
if
(
linkGroupIds
.
count
(
kv
.
first
))
link
.
mLinkGroupID
=
linkGroupIds
[
kv
.
first
];
std
::
tie
(
link
.
mParentKeys
,
link
.
mChildKeys
)
=
linkKeys
[
kv
.
second
];
linkGroupIds
[
key
]
=
link_group_id
;
}
size_t
ix
=
linkIndex
.
at
(
key
);
addLink
(
ix
,
piv
->
mTag
,
civ
->
mTag
);
}
// look up the label
for
(
auto
r
:
linkedGroup
.
find
(
cif
::
Key
(
"category_id"
)
==
link
.
mChildCategory
and
cif
::
Key
(
"link_group_id"
)
==
link
.
mLinkGroupID
))
auto
&
linkedGroup
=
dict
[
"pdbx_item_linked_group"
];
// now store the links in the validator
for
(
auto
&
kv
:
linkIndex
)
{
link
.
mLinkGroupLabel
=
r
[
"label"
].
as
<
std
::
string
>
();
break
;
}
ValidateLink
link
=
{};
std
::
tie
(
link
.
mParentCategory
,
link
.
mChildCategory
)
=
kv
.
first
;
if
(
linkGroupIds
.
count
(
kv
.
first
))
link
.
mLinkGroupID
=
linkGroupIds
[
kv
.
first
];
std
::
tie
(
link
.
mParentKeys
,
link
.
mChildKeys
)
=
linkKeys
[
kv
.
second
];
// look up the label
for
(
auto
r
:
linkedGroup
.
find
(
cif
::
Key
(
"category_id"
)
==
link
.
mChildCategory
and
cif
::
Key
(
"link_group_id"
)
==
link
.
mLinkGroupID
))
{
link
.
mLinkGroupLabel
=
r
[
"label"
].
as
<
std
::
string
>
();
break
;
}
mValidator
.
addLinkValidator
(
std
::
move
(
link
));
mValidator
.
addLinkValidator
(
std
::
move
(
link
));
}
}
// now make sure the itemType is specified for all itemValidators
for
(
auto
&
cv
:
mValidator
.
mCategoryValidators
)
...
...
test/unit-test.cpp
View file @
c3963bc4
...
...
@@ -52,6 +52,8 @@ cif::File operator""_cf(const char* text, size_t length)
BOOST_AUTO_TEST_CASE
(
ut1
)
{
cif
::
VERBOSE
=
1
;
// using namespace mmcif;
auto
f
=
R"(data_TEST
...
...
@@ -403,4 +405,436 @@ mies Mies
BOOST_CHECK
(
cat1
.
size
()
==
2
);
}
\ No newline at end of file
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE
(
d3
)
{
const
char
dict
[]
=
R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
;
A test dictionary
;
_dictionary.title test_dict.dic
_dictionary.datablock_id test_dict.dic
_dictionary.version 1.0
loop_
_item_type_list.code
_item_type_list.primitive_code
_item_type_list.construct
code char
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
text char
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
int numb
'[+-]?[0-9]+'
save_cat_1
_category.description 'A simple test category'
_category.id cat_1
_category.mandatory_code no
_category_key.name '_cat_1.id'
save_
save__cat_1.id
_item.name '_cat_1.id'
_item.category_id cat_1
_item.mandatory_code yes
_item_linked.child_name '_cat_2.parent_id'
_item_linked.parent_name '_cat_1.id'
_item_type.code code
save_
save__cat_1.name1
_item.name '_cat_1.name1'
_item.category_id cat_1
_item.mandatory_code yes
_item_type.code text
save_
save__cat_1.name2
_item.name '_cat_1.name2'
_item.category_id cat_1
_item.mandatory_code no
_item_linked.child_name '_cat_2.name2'
_item_linked.parent_name '_cat_1.name2'
_item_type.code text
save_
save_cat_2
_category.description 'A second simple test category'
_category.id cat_2
_category.mandatory_code no
_category_key.name '_cat_2.id'
save_
save__cat_2.id
_item.name '_cat_2.id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
save__cat_2.parent_id
_item.name '_cat_2.parent_id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code code
save_
save__cat_2.name2
_item.name '_cat_2.name2'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code text
save_
save__cat_2.desc
_item.name '_cat_2.desc'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code text
save_
)"
;
struct
membuf
:
public
std
::
streambuf
{
membuf
(
char
*
text
,
size_t
length
)
{
this
->
setg
(
text
,
text
,
text
+
length
);
}
}
buffer
(
const_cast
<
char
*>
(
dict
),
sizeof
(
dict
)
-
1
);
std
::
istream
is_dict
(
&
buffer
);
cif
::
File
f
;
f
.
loadDictionary
(
is_dict
);
// --------------------------------------------------------------------
const
char
data
[]
=
R"(
data_test
loop_
_cat_1.id
_cat_1.name1
_cat_1.name2
1 Aap aap
2 Noot noot
3 Mies mies
loop_
_cat_2.id
_cat_2.parent_id
_cat_2.name2
_cat_2.desc
1 1 aap 'Een dier'
2 1 . 'Een andere aap'
3 2 noot 'walnoot bijvoorbeeld'
4 2 n2 hazelnoot
)"
;
struct
data_membuf
:
public
std
::
streambuf
{
data_membuf
(
char
*
text
,
size_t
length
)
{
this
->
setg
(
text
,
text
,
text
+
length
);
}
}
data_buffer
(
const_cast
<
char
*>
(
data
),
sizeof
(
data
)
-
1
);
std
::
istream
is_data
(
&
data_buffer
);
f
.
load
(
is_data
);
auto
&
cat1
=
f
.
firstDatablock
()[
"cat_1"
];
auto
&
cat2
=
f
.
firstDatablock
()[
"cat_2"
];
// check a rename in parent and child
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
1
))
{
r
[
"id"
]
=
10
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
4
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
10
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
10
).
size
()
==
2
);
// check a rename in parent and child, this time only one child should be renamed
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
))
{
r
[
"id"
]
=
20
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
4
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
20
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
2
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
20
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
2
and
cif
::
Key
(
"name2"
)
==
"noot"
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
2
and
cif
::
Key
(
"name2"
)
==
"n2"
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
20
and
cif
::
Key
(
"name2"
)
==
"noot"
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
20
and
cif
::
Key
(
"name2"
)
==
"n2"
).
size
()
==
0
);
// // --------------------------------------------------------------------
// cat1.erase(cif::Key("id") == 10);
// BOOST_CHECK(cat1.size() == 2);
// BOOST_CHECK(cat2.size() == 2);
// cat1.erase(cif::Key("id") == 20);
// BOOST_CHECK(cat1.size() == 1);
// BOOST_CHECK(cat2.size() == 1);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE
(
d4
)
{
const
char
dict
[]
=
R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
;
A test dictionary
;
_dictionary.title test_dict.dic
_dictionary.datablock_id test_dict.dic
_dictionary.version 1.0
loop_
_item_type_list.code
_item_type_list.primitive_code
_item_type_list.construct
code char
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
text char
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
int numb
'[+-]?[0-9]+'
save_cat_1
_category.description 'A simple test category'
_category.id cat_1
_category.mandatory_code no
_category_key.name '_cat_1.id'
save_
save__cat_1.id
_item.name '_cat_1.id'
_item.category_id cat_1
_item.mandatory_code yes
_item_linked.child_name '_cat_2.parent_id'
_item_linked.parent_name '_cat_1.id'
_item_type.code int
save_
save__cat_1.id2
_item.name '_cat_1.id2'
_item.category_id cat_1
_item.mandatory_code no
_item_linked.child_name '_cat_2.parent_id2'
_item_linked.parent_name '_cat_1.id2'
_item_type.code code
save_
save__cat_1.id3
_item.name '_cat_1.id3'
_item.category_id cat_1
_item.mandatory_code no
_item_linked.child_name '_cat_2.parent_id3'
_item_linked.parent_name '_cat_1.id3'
_item_type.code text
save_
save_cat_2
_category.description 'A second simple test category'
_category.id cat_2
_category.mandatory_code no
_category_key.name '_cat_2.id'
save_
save__cat_2.id
_item.name '_cat_2.id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
save__cat_2.parent_id
_item.name '_cat_2.parent_id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
save__cat_2.parent_id2
_item.name '_cat_2.parent_id2'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code code
save_
save__cat_2.parent_id3
_item.name '_cat_2.parent_id3'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code code
save_
)"
;
struct
membuf
:
public
std
::
streambuf
{
membuf
(
char
*
text
,
size_t
length
)
{
this
->
setg
(
text
,
text
,
text
+
length
);
}
}
buffer
(
const_cast
<
char
*>
(
dict
),
sizeof
(
dict
)
-
1
);
std
::
istream
is_dict
(
&
buffer
);
cif
::
File
f
;
f
.
loadDictionary
(
is_dict
);
// --------------------------------------------------------------------
const
char
data
[]
=
R"(
data_test
loop_
_cat_1.id
_cat_1.id2
_cat_1.id3
1 aap aap
2 . noot
3 mies .
4 . .
loop_
_cat_2.id
_cat_2.parent_id
_cat_2.parent_id2
_cat_2.parent_id3
1 1 aap aap
2 1 . x
3 1 aap .
4 2 noot noot
5 2 . noot
6 2 noot .
7 2 . .
8 3 mies mies
9 3 . mies
10 3 mies .
11 4 roos roos
12 4 . roos
13 4 roos .
)"
;
struct
data_membuf
:
public
std
::
streambuf
{
data_membuf
(
char
*
text
,
size_t
length
)
{
this
->
setg
(
text
,
text
,
text
+
length
);
}
}
data_buffer
(
const_cast
<
char
*>
(
data
),
sizeof
(
data
)
-
1
);
std
::
istream
is_data
(
&
data_buffer
);
f
.
load
(
is_data
);
auto
&
cat1
=
f
.
firstDatablock
()[
"cat_1"
];
auto
&
cat2
=
f
.
firstDatablock
()[
"cat_2"
];
// check a rename in parent and child
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
1
))
{
r
[
"id"
]
=
10
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
4
);
BOOST_CHECK
(
cat2
.
size
()
==
13
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
10
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
1
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
10
).
size
()
==
2
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
))
{
r
[
"id"
]
=
20
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
4
);
BOOST_CHECK
(
cat2
.
size
()
==
13
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
20
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
2
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
20
).
size
()
==
2
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
3
))
{
r
[
"id"
]
=
30
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
4
);
BOOST_CHECK
(
cat2
.
size
()
==
13
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
3
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
30
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
3
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
30
).
size
()
==
1
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
4
))
{
r
[
"id"
]
=
40
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
4
);
BOOST_CHECK
(
cat2
.
size
()
==
13
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
4
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
10
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
4
).
size
()
==
3
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
40
).
size
()
==
0
);
f
.
write
(
std
::
cout
,
{});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment