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
19210df6
Unverified
Commit
19210df6
authored
Feb 08, 2022
by
Maarten L. Hekkelman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix parsing mmCIF files with an unquoted string ??
parent
15c57307
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
651 additions
and
657 deletions
+651
-657
CMakeLists.txt
+1
-1
changelog
+7
-0
include/cif++/CifParser.hpp
+8
-8
src/CifParser.cpp
+73
-109
test/unit-test.cpp
+562
-539
No files found.
CMakeLists.txt
View file @
19210df6
...
...
@@ -25,7 +25,7 @@
cmake_minimum_required
(
VERSION 3.16
)
# set the project name
project
(
cifpp VERSION 3.0.
2
LANGUAGES CXX
)
project
(
cifpp VERSION 3.0.
4
LANGUAGES CXX
)
list
(
PREPEND CMAKE_MODULE_PATH
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/cmake"
)
...
...
changelog
View file @
19210df6
Version
3.0.4
-
Fix
in
mmCIF
parser
,
now
correctly
handles
the
unquoted
string
??
Version
3.0.3
-
Better
configuration
checks
,
for
atomic
e
.
g
.
-
Fixed
a
problem
introduced
in
refactoring
mmcif
::
Atom
...
...
@@ -17,6 +21,9 @@ Version 3.0.0
-
Upgraded
mmcif
::
Structure
-
various
other
small
fixes
Version
2.0.5
-
Backporting
updated
CMakeLists
.
txt
file
Version
2.0.4
-
Reverted
a
too
strict
test
when
reading
cif
files
.
...
...
include/cif++/CifParser.hpp
View file @
19210df6
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
*
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
...
...
@@ -139,7 +139,7 @@ class SacParser
int
getNextChar
();
void
retract
();
void
restart
(
);
int
restart
(
int
start
);
CIFToken
getNextToken
();
void
match
(
CIFToken
token
);
...
...
@@ -181,8 +181,9 @@ class SacParser
eStateTextField
,
eStateFloat
=
100
,
eStateInt
=
110
,
// eStateNumericSuffix = 200,
eStateValue
=
300
eStateValue
=
300
,
eStateDATA
,
eStateSAVE
};
std
::
istream
&
mData
;
...
...
@@ -191,7 +192,6 @@ class SacParser
bool
mValidate
;
uint32_t
mLineNr
;
bool
mBol
;
int
mState
,
mStart
;
CIFToken
mLookahead
;
std
::
string
mTokenValue
;
CIFValueType
mTokenType
;
...
...
src/CifParser.cpp
View file @
19210df6
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
*
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
...
...
@@ -42,7 +42,7 @@ namespace cif
const
uint32_t
kMaxLineLength
=
132
;
const
uint8_t
kCharTraitsTable
[
128
]
=
{
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
14
,
15
,
14
,
14
,
14
,
15
,
15
,
14
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
// 2
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
10
,
15
,
15
,
15
,
15
,
// 3
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
15
,
// 4
...
...
@@ -151,23 +151,26 @@ void SacParser::retract()
mTokenValue
.
pop_back
();
}
void
SacParser
::
restart
()
int
SacParser
::
restart
(
int
start
)
{
int
result
=
0
;
while
(
not
mTokenValue
.
empty
())
retract
();
switch
(
mS
tart
)
switch
(
s
tart
)
{
case
eStateStart
:
mState
=
mStar
t
=
eStateFloat
;
resul
t
=
eStateFloat
;
break
;
case
eStateFloat
:
mState
=
mStar
t
=
eStateInt
;
resul
t
=
eStateInt
;
break
;
case
eStateInt
:
mState
=
mStar
t
=
eStateValue
;
resul
t
=
eStateValue
;
break
;
default
:
...
...
@@ -175,6 +178,8 @@ void SacParser::restart()
}
mBol
=
false
;
return
result
;
}
void
SacParser
::
match
(
SacParser
::
CIFToken
t
)
...
...
@@ -191,7 +196,7 @@ SacParser::CIFToken SacParser::getNextToken()
CIFToken
result
=
eCIFTokenUnknown
;
int
quoteChar
=
0
;
mState
=
mS
tart
=
eStateStart
;
int
state
=
eStateStart
,
s
tart
=
eStateStart
;
mBol
=
false
;
mTokenValue
.
clear
();
...
...
@@ -201,7 +206,7 @@ SacParser::CIFToken SacParser::getNextToken()
{
auto
ch
=
getNextChar
();
switch
(
mS
tate
)
switch
(
s
tate
)
{
case
eStateStart
:
if
(
ch
==
kEOF
)
...
...
@@ -209,27 +214,23 @@ SacParser::CIFToken SacParser::getNextToken()
else
if
(
ch
==
'\n'
)
{
mBol
=
true
;
mS
tate
=
eStateWhite
;
s
tate
=
eStateWhite
;
}
else
if
(
ch
==
' '
or
ch
==
'\t'
)
mS
tate
=
eStateWhite
;
s
tate
=
eStateWhite
;
else
if
(
ch
==
'#'
)
mState
=
eStateComment
;
else
if
(
ch
==
'.'
)
mState
=
eStateDot
;
state
=
eStateComment
;
else
if
(
ch
==
'_'
)
mS
tate
=
eStateTag
;
s
tate
=
eStateTag
;
else
if
(
ch
==
';'
and
mBol
)
mS
tate
=
eStateTextField
;
s
tate
=
eStateTextField
;
else
if
(
ch
==
'\''
or
ch
==
'"'
)
{
quoteChar
=
ch
;
mS
tate
=
eStateQuotedString
;
s
tate
=
eStateQuotedString
;
}
else
if
(
ch
==
'?'
)
mState
=
eStateQuestionMark
;
else
restart
(
);
state
=
start
=
restart
(
start
);
break
;
case
eStateWhite
:
...
...
@@ -237,7 +238,7 @@ SacParser::CIFToken SacParser::getNextToken()
result
=
eCIFTokenEOF
;
else
if
(
not
isspace
(
ch
))
{
mS
tate
=
eStateStart
;
s
tate
=
eStateStart
;
retract
();
mTokenValue
.
clear
();
}
...
...
@@ -248,7 +249,7 @@ SacParser::CIFToken SacParser::getNextToken()
case
eStateComment
:
if
(
ch
==
'\n'
)
{
mS
tate
=
eStateStart
;
s
tate
=
eStateStart
;
mBol
=
true
;
mTokenValue
.
clear
();
}
...
...
@@ -258,44 +259,19 @@ SacParser::CIFToken SacParser::getNextToken()
error
(
"invalid character in comment"
);
break
;
case
eStateQuestionMark
:
if
(
isNonBlank
(
ch
))
mState
=
eStateValue
;
else
{
retract
();
result
=
eCIFTokenValue
;
mTokenValue
.
clear
();
mTokenType
=
eCIFValueUnknown
;
}
break
;
case
eStateDot
:
if
(
isdigit
(
ch
))
mState
=
eStateFloat
+
2
;
else
if
(
isspace
(
ch
))
{
retract
();
result
=
eCIFTokenValue
;
mTokenType
=
eCIFValueInapplicable
;
}
else
mState
=
eStateValue
;
break
;
case
eStateTextField
:
if
(
ch
==
'\n'
)
mS
tate
=
eStateTextField
+
1
;
s
tate
=
eStateTextField
+
1
;
else
if
(
ch
==
kEOF
)
error
(
"unterminated textfield"
);
else
if
(
not
isAnyPrint
(
ch
)
and
cif
::
VERBOSE
>=
0
)
else
if
(
not
isAnyPrint
(
ch
))
// error("invalid character in text field '" + string({ static_cast<char>(ch) }) + "' (" + to_string((int)ch) + ")");
std
::
cerr
<<
"invalid character in text field '"
<<
std
::
string
({
static_cast
<
char
>
(
ch
)})
<<
"' ("
<<
ch
<<
") line: "
<<
mLineNr
<<
std
::
endl
;
break
;
case
eStateTextField
+
1
:
if
(
isTextLead
(
ch
)
or
ch
==
' '
or
ch
==
'\t'
)
mS
tate
=
eStateTextField
;
s
tate
=
eStateTextField
;
else
if
(
ch
==
';'
)
{
assert
(
mTokenValue
.
length
()
>=
2
);
...
...
@@ -313,7 +289,7 @@ SacParser::CIFToken SacParser::getNextToken()
if
(
ch
==
kEOF
)
error
(
"unterminated quoted string"
);
else
if
(
ch
==
quoteChar
)
mS
tate
=
eStateQuotedStringQuote
;
s
tate
=
eStateQuotedStringQuote
;
else
if
(
not
isAnyPrint
(
ch
))
error
(
"invalid character in quoted string"
);
break
;
...
...
@@ -331,7 +307,7 @@ SacParser::CIFToken SacParser::getNextToken()
else
if
(
ch
==
quoteChar
)
;
else
if
(
isAnyPrint
(
ch
))
mS
tate
=
eStateQuotedString
;
s
tate
=
eStateQuotedString
;
else
if
(
ch
==
kEOF
)
error
(
"unterminated quoted string"
);
else
...
...
@@ -349,12 +325,12 @@ SacParser::CIFToken SacParser::getNextToken()
case
eStateFloat
:
if
(
ch
==
'+'
or
ch
==
'-'
)
{
mS
tate
=
eStateFloat
+
1
;
s
tate
=
eStateFloat
+
1
;
}
else
if
(
isdigit
(
ch
))
mS
tate
=
eStateFloat
+
1
;
s
tate
=
eStateFloat
+
1
;
else
restart
(
);
state
=
start
=
restart
(
start
);
break
;
case
eStateFloat
+
1
:
...
...
@@ -362,9 +338,9 @@ SacParser::CIFToken SacParser::getNextToken()
// mState = eStateNumericSuffix;
// else
if
(
ch
==
'.'
)
mS
tate
=
eStateFloat
+
2
;
s
tate
=
eStateFloat
+
2
;
else
if
(
tolower
(
ch
)
==
'e'
)
mS
tate
=
eStateFloat
+
3
;
s
tate
=
eStateFloat
+
3
;
else
if
(
isWhite
(
ch
)
or
ch
==
kEOF
)
{
retract
();
...
...
@@ -372,16 +348,13 @@ SacParser::CIFToken SacParser::getNextToken()
mTokenType
=
eCIFValueInt
;
}
else
restart
(
);
state
=
start
=
restart
(
start
);
break
;
// parsed '.'
case
eStateFloat
+
2
:
// if (ch == '(') // numeric???
// mState = eStateNumericSuffix;
// else
if
(
tolower
(
ch
)
==
'e'
)
mS
tate
=
eStateFloat
+
3
;
s
tate
=
eStateFloat
+
3
;
else
if
(
isWhite
(
ch
)
or
ch
==
kEOF
)
{
retract
();
...
...
@@ -389,30 +362,27 @@ SacParser::CIFToken SacParser::getNextToken()
mTokenType
=
eCIFValueFloat
;
}
else
restart
(
);
state
=
start
=
restart
(
start
);
break
;
// parsed 'e'
case
eStateFloat
+
3
:
if
(
ch
==
'-'
or
ch
==
'+'
)
mS
tate
=
eStateFloat
+
4
;
s
tate
=
eStateFloat
+
4
;
else
if
(
isdigit
(
ch
))
mS
tate
=
eStateFloat
+
5
;
s
tate
=
eStateFloat
+
5
;
else
restart
(
);
state
=
start
=
restart
(
start
);
break
;
case
eStateFloat
+
4
:
if
(
isdigit
(
ch
))
mS
tate
=
eStateFloat
+
5
;
s
tate
=
eStateFloat
+
5
;
else
restart
(
);
state
=
start
=
restart
(
start
);
break
;
case
eStateFloat
+
5
:
// if (ch == '(')
// mState = eStateNumericSuffix;
// else
if
(
isWhite
(
ch
)
or
ch
==
kEOF
)
{
retract
();
...
...
@@ -420,14 +390,14 @@ SacParser::CIFToken SacParser::getNextToken()
mTokenType
=
eCIFValueFloat
;
}
else
restart
(
);
state
=
start
=
restart
(
start
);
break
;
case
eStateInt
:
if
(
isdigit
(
ch
)
or
ch
==
'+'
or
ch
==
'-'
)
mS
tate
=
eStateInt
+
1
;
s
tate
=
eStateInt
+
1
;
else
restart
(
);
state
=
start
=
restart
(
start
);
break
;
case
eStateInt
+
1
:
...
...
@@ -438,35 +408,11 @@ SacParser::CIFToken SacParser::getNextToken()
mTokenType
=
eCIFValueInt
;
}
else
restart
(
);
state
=
start
=
restart
(
start
);
break
;
// case eStateNumericSuffix:
// if (isdigit(ch))
// mState = eStateNumericSuffix + 1;
// else
// restart();
// break;
//
// case eStateNumericSuffix + 1:
// if (ch == ')')
// {
// result = eCIFTokenValue;
// mTokenType = eCIFValueNumeric;
// }
// else if (not isdigit(ch))
// restart();
// break;
case
eStateValue
:
if
(
isNonBlank
(
ch
))
mState
=
eStateValue
+
1
;
else
error
(
"invalid character at this position"
);
break
;
case
eStateValue
+
1
:
if
(
ch
==
'_'
)
// first _, check for keywords
if
(
ch
==
'_'
)
{
std
::
string
s
=
toLowerCopy
(
mTokenValue
);
...
...
@@ -476,23 +422,40 @@ SacParser::CIFToken SacParser::getNextToken()
result
=
eCIFTokenSTOP
;
else
if
(
s
==
"loop_"
)
result
=
eCIFTokenLOOP
;
else
if
(
s
==
"data_"
or
s
==
"save_"
)
mState
=
eStateValue
+
2
;
else
if
(
s
==
"data_"
)
{
state
=
eStateDATA
;
continue
;
}
else
if
(
s
==
"save_"
)
{
state
=
eStateSAVE
;
continue
;
}
}
else
if
(
not
isNonBlank
(
ch
))
if
(
result
==
eCIFTokenUnknown
and
not
isNonBlank
(
ch
))
{
retract
();
result
=
eCIFTokenValue
;
mTokenType
=
eCIFValueString
;
if
(
mTokenValue
==
"."
)
mTokenType
=
eCIFValueInapplicable
;
else
if
(
mTokenValue
==
"?"
)
{
mTokenType
=
eCIFValueUnknown
;
mTokenValue
.
clear
();
}
}
break
;
case
eStateValue
+
2
:
case
eStateDATA
:
case
eStateSAVE
:
if
(
not
isNonBlank
(
ch
))
{
retract
();
if
(
tolower
(
mTokenValue
[
0
])
==
'd'
)
if
(
state
==
eStateDATA
)
result
=
eCIFTokenDATA
;
else
result
=
eCIFTokenSAVE
;
...
...
@@ -521,6 +484,7 @@ SacParser::CIFToken SacParser::getNextToken()
return
result
;
}
DatablockIndex
SacParser
::
indexDatablocks
()
{
DatablockIndex
index
;
...
...
test/unit-test.cpp
View file @
19210df6
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
*
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
...
...
@@ -31,36 +31,35 @@
#include <stdexcept>
// #include "cif++/DistanceMap.hpp"
#include "cif++/Cif++.hpp"
#include "cif++/BondMap.hpp"
#include "cif++/Cif++.hpp"
#include "cif++/CifValidator.hpp"
namespace
tt
=
boost
::
test_tools
;
std
::
filesystem
::
path
gTestDir
=
std
::
filesystem
::
current_path
();
// filled in first test
std
::
filesystem
::
path
gTestDir
=
std
::
filesystem
::
current_path
();
// filled in first test
// --------------------------------------------------------------------
cif
::
File
operator
""
_cf
(
const
char
*
text
,
size_t
length
)
cif
::
File
operator
""
_cf
(
const
char
*
text
,
size_t
length
)
{
struct
membuf
:
public
std
::
streambuf
{
membuf
(
char
*
text
,
size_t
length
)
{
this
->
setg
(
text
,
text
,
text
+
length
);
}
}
buffer
(
const_cast
<
char
*>
(
text
),
length
);
std
::
istream
is
(
&
buffer
);
return
cif
::
File
(
is
);
struct
membuf
:
public
std
::
streambuf
{
membuf
(
char
*
text
,
size_t
length
)
{
this
->
setg
(
text
,
text
,
text
+
length
);
}
}
buffer
(
const_cast
<
char
*>
(
text
),
length
);
std
::
istream
is
(
&
buffer
);
return
cif
::
File
(
is
);
}
// --------------------------------------------------------------------
bool
init_unit_test
()
{
cif
::
VERBOSE
=
1
;
cif
::
VERBOSE
=
1
;
// not a test, just initialize test dir
if
(
boost
::
unit_test
::
framework
::
master_test_suite
().
argc
==
2
)
...
...
@@ -79,9 +78,9 @@ bool init_unit_test()
BOOST_AUTO_TEST_CASE
(
ut1
)
{
// using namespace mmcif;
// using namespace mmcif;
auto
f
=
R"(data_TEST
auto
f
=
R"(data_TEST
#
loop_
_test.id
...
...
@@ -91,36 +90,36 @@ _test.name
3 mies
)"
_cf
;
auto
&
db
=
f
.
firstDatablock
();
auto
&
db
=
f
.
firstDatablock
();
BOOST_CHECK
(
db
.
getName
()
==
"TEST"
);
auto
&
test
=
db
[
"test"
];
BOOST_CHECK
(
test
.
size
()
==
3
);
BOOST_CHECK
(
db
.
getName
()
==
"TEST"
);
auto
&
test
=
db
[
"test"
];
BOOST_CHECK
(
test
.
size
()
==
3
);
// wrong! the next lines will crash. And that's OK, don't do that
// for (auto r: test)
// test.erase(r);
// wrong! the next lines will crash. And that's OK, don't do that
// for (auto r: test)
// test.erase(r);
// BOOST_CHECK(test.empty());
// BOOST_CHECK(test.empty());
// test.purge();
// test.purge();
auto
n
=
test
.
erase
(
cif
::
Key
(
"id"
)
==
1
,
[](
const
cif
::
Row
&
r
)
{
auto
n
=
test
.
erase
(
cif
::
Key
(
"id"
)
==
1
,
[](
const
cif
::
Row
&
r
)
{
BOOST_CHECK_EQUAL
(
r
[
"id"
].
as
<
int
>
(),
1
);
BOOST_CHECK_EQUAL
(
r
[
"name"
].
as
<
std
::
string
>
(),
"aap"
);
});
BOOST_CHECK_EQUAL
(
r
[
"name"
].
as
<
std
::
string
>
(),
"aap"
);
});
BOOST_CHECK_EQUAL
(
n
,
1
);
BOOST_CHECK_EQUAL
(
n
,
1
);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE
(
ut2
)
{
// using namespace mmcif;
// using namespace mmcif;
auto
f
=
R"(data_TEST
auto
f
=
R"(data_TEST
#
loop_
_test.id
...
...
@@ -131,36 +130,36 @@ _test.value
3 mies 1.2
)"
_cf
;
auto
&
db
=
f
.
firstDatablock
();
BOOST_CHECK
(
db
.
getName
()
==
"TEST"
);
auto
&
test
=
db
[
"test"
];
BOOST_CHECK
(
test
.
size
()
==
3
);
int
n
=
0
;
for
(
auto
r
:
test
.
find
(
cif
::
Key
(
"name"
)
==
"aap"
))
{
BOOST_CHECK
(
++
n
==
1
);
BOOST_CHECK
(
r
[
"id"
].
as
<
int
>
()
==
1
);
BOOST_CHECK
(
r
[
"name"
].
as
<
std
::
string
>
()
==
"aap"
);
BOOST_CHECK
(
r
[
"value"
].
as
<
float
>
()
==
1.0
);
}
auto
t
=
test
.
find
(
cif
::
Key
(
"id"
)
==
1
);
BOOST_CHECK
(
not
t
.
empty
());
BOOST_CHECK
(
t
.
front
()[
"name"
].
as
<
std
::
string
>
()
==
"aap"
);
auto
t2
=
test
.
find
(
cif
::
Key
(
"value"
)
==
1.2
);
BOOST_CHECK
(
not
t2
.
empty
());
BOOST_CHECK
(
t2
.
front
()[
"name"
].
as
<
std
::
string
>
()
==
"mies"
);
auto
&
db
=
f
.
firstDatablock
();
BOOST_CHECK
(
db
.
getName
()
==
"TEST"
);
auto
&
test
=
db
[
"test"
];
BOOST_CHECK
(
test
.
size
()
==
3
);
int
n
=
0
;
for
(
auto
r
:
test
.
find
(
cif
::
Key
(
"name"
)
==
"aap"
))
{
BOOST_CHECK
(
++
n
==
1
);
BOOST_CHECK
(
r
[
"id"
].
as
<
int
>
()
==
1
);
BOOST_CHECK
(
r
[
"name"
].
as
<
std
::
string
>
()
==
"aap"
);
BOOST_CHECK
(
r
[
"value"
].
as
<
float
>
()
==
1.0
);
}
auto
t
=
test
.
find
(
cif
::
Key
(
"id"
)
==
1
);
BOOST_CHECK
(
not
t
.
empty
());
BOOST_CHECK
(
t
.
front
()[
"name"
].
as
<
std
::
string
>
()
==
"aap"
);
auto
t2
=
test
.
find
(
cif
::
Key
(
"value"
)
==
1.2
);
BOOST_CHECK
(
not
t2
.
empty
());
BOOST_CHECK
(
t2
.
front
()[
"name"
].
as
<
std
::
string
>
()
==
"mies"
);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE
(
d1
)
{
const
char
dict
[]
=
R"(
const
char
dict
[]
=
R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
...
...
@@ -253,24 +252,24 @@ save__cat_2.desc
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
);
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
);
std
::
istream
is_dict
(
&
buffer
);
cif
::
Validator
validator
(
"test"
,
is_dict
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
// --------------------------------------------------------------------
// --------------------------------------------------------------------
const
char
data
[]
=
R"(
const
char
data
[]
=
R"(
data_test
loop_
_cat_1.id
...
...
@@ -286,48 +285,47 @@ _cat_2.desc
1 1 'Een dier'
2 1 'Een andere aap'
3 2 'walnoot bijvoorbeeld'
)"
;
)"
;
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
);
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
);
std
::
istream
is_data
(
&
data_buffer
);
f
.
load
(
is_data
);
auto
&
cat1
=
f
.
firstDatablock
()[
"cat_1"
];
auto
&
cat2
=
f
.
firstDatablock
()[
"cat_2"
];
auto
&
cat1
=
f
.
firstDatablock
()[
"cat_1"
];
auto
&
cat2
=
f
.
firstDatablock
()[
"cat_2"
];
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
3
);
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
3
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
1
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
1
);
BOOST_CHECK
(
cat1
.
size
()
==
2
);
BOOST_CHECK
(
cat2
.
size
()
==
1
);
BOOST_CHECK
(
cat1
.
size
()
==
2
);
BOOST_CHECK
(
cat2
.
size
()
==
1
);
// BOOST_CHECK_THROW(cat2.emplace({
// { "id", 4 },
// { "parent_id", 4 },
// { "desc", "moet fout gaan" }
// }), std::exception);
// BOOST_CHECK_THROW(cat2.emplace({
// { "id", 4 },
// { "parent_id", 4 },
// { "desc", "moet fout gaan" }
// }), std::exception);
BOOST_CHECK_THROW
(
cat2
.
emplace
({
{
"id"
,
"vijf"
},
// <- invalid value
{
"parent_id"
,
2
},
{
"desc"
,
"moet fout gaan"
}
}),
std
::
exception
);
BOOST_CHECK_THROW
(
cat2
.
emplace
({{
"id"
,
"vijf"
},
// <- invalid value
{
"parent_id"
,
2
},
{
"desc"
,
"moet fout gaan"
}}),
std
::
exception
);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE
(
d2
)
{
const
char
dict
[]
=
R"(
const
char
dict
[]
=
R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
...
...
@@ -383,24 +381,24 @@ save__cat_1.c
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
);
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
);
std
::
istream
is_dict
(
&
buffer
);
cif
::
Validator
validator
(
"test"
,
is_dict
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
// --------------------------------------------------------------------
// --------------------------------------------------------------------
const
char
data
[]
=
R"(
const
char
data
[]
=
R"(
data_test
loop_
_cat_1.id
...
...
@@ -408,39 +406,37 @@ _cat_1.c
aap Aap
noot Noot
mies Mies
)"
;
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"
];
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
);
BOOST_CHECK
(
cat1
.
size
()
==
3
);
std
::
istream
is_data
(
&
data_buffer
);
f
.
load
(
is_data
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
"AAP"
)
;
auto
&
cat1
=
f
.
firstDatablock
()[
"cat_1"
]
;
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat1
.
size
()
==
3
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
"noot
"
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
"AAP
"
);
BOOST_CHECK
(
cat1
.
size
()
==
2
);
BOOST_CHECK
(
cat1
.
size
()
==
3
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
"noot"
);
BOOST_CHECK
(
cat1
.
size
()
==
2
);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE
(
d3
)
{
const
char
dict
[]
=
R"(
const
char
dict
[]
=
R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
...
...
@@ -533,24 +529,24 @@ save__cat_2.desc
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
);
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
);
std
::
istream
is_dict
(
&
buffer
);
cif
::
Validator
validator
(
"test"
,
is_dict
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
// --------------------------------------------------------------------
// --------------------------------------------------------------------
const
char
data
[]
=
R"(
const
char
data
[]
=
R"(
data_test
loop_
_cat_1.id
...
...
@@ -569,84 +565,79 @@ _cat_2.desc
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
;
}
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
);
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
4
);
std
::
istream
is_data
(
&
data_buffer
);
f
.
load
(
is_data
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
1
).
size
()
==
0
)
;
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
10
).
size
()
==
1
)
;
auto
&
cat1
=
f
.
firstDatablock
()[
"cat_1"
]
;
auto
&
cat2
=
f
.
firstDatablock
()[
"cat_2"
]
;
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
// check a rename in parent and child, this time only one child should be renamed
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
1
))
{
r
[
"id"
]
=
10
;
break
;
}
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
.
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
(
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"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
10
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
2
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
20
).
size
()
==
1
);
// check a rename in parent and child, this time only one child should be renamed
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
);
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
);
// // --------------------------------------------------------------------
// cat1.erase(cif::Key("id") == 10);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
2
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
20
).
size
()
==
1
);
// BOOST_CHECK(cat1.size() == 2);
// BOOST_CHECK(cat2.size() == 2);
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") == 20);
// // --------------------------------------------------------------------
// BOOST_CHECK(cat1.size() == 1);
// BOOST_CHECK(cat2.size() == 1);
// 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"(
const
char
dict
[]
=
R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
...
...
@@ -741,24 +732,24 @@ save__cat_2.parent_id3
)"
;
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
);
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
);
std
::
istream
is_dict
(
&
buffer
);
cif
::
Validator
validator
(
"test"
,
is_dict
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
// --------------------------------------------------------------------
// --------------------------------------------------------------------
const
char
data
[]
=
R"(
const
char
data
[]
=
R"(
data_test
loop_
_cat_1.id
...
...
@@ -787,93 +778,90 @@ _cat_2.parent_id3
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
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
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
1
))
{
r
[
"id"
]
=
10
;
break
;
}
std
::
istream
is_data
(
&
data_buffer
);
f
.
load
(
is_data
);
BOOST_CHECK
(
cat1
.
size
()
==
4
)
;
BOOST_CHECK
(
cat2
.
size
()
==
13
)
;
auto
&
cat1
=
f
.
firstDatablock
()[
"cat_1"
]
;
auto
&
cat2
=
f
.
firstDatablock
()[
"cat_2"
]
;
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
10
).
size
()
==
1
);
// check a rename in parent and child
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"
)
==
1
))
{
r
[
"id"
]
=
10
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
4
);
BOOST_CHECK
(
cat2
.
size
()
==
13
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
))
{
r
[
"id"
]
=
20
;
break
;
}
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
10
).
size
()
==
1
);
BOOST_CHECK
(
cat1
.
size
()
==
4
);
BOOST_CHECK
(
cat2
.
size
()
==
13
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
1
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
10
).
size
()
==
2
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
20
).
size
()
==
1
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
))
{
r
[
"id"
]
=
20
;
break
;
}
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
2
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
20
).
size
()
==
2
);
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
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
3
))
{
r
[
"id"
]
=
30
;
break
;
}
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
2
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
20
).
size
()
==
2
);
BOOST_CHECK
(
cat1
.
size
()
==
4
);
BOOST_CHECK
(
cat2
.
size
()
==
13
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
3
))
{
r
[
"id"
]
=
30
;
break
;
}
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
3
).
size
()
==
0
);
BOOST_CHECK
(
cat1
.
find
(
cif
::
Key
(
"id"
)
==
30
).
size
()
==
1
);
BOOST_CHECK
(
cat1
.
size
()
==
4
);
BOOST_CHECK
(
cat2
.
size
()
==
13
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
3
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_
id"
)
==
30
).
size
()
==
1
);
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
;
}
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
.
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
(
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
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
4
).
size
()
==
3
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
40
).
size
()
==
0
);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE
(
d5
)
{
const
char
dict
[]
=
R"(
const
char
dict
[]
=
R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
...
...
@@ -965,24 +953,24 @@ cat_2 2 cat_2:cat_1:2
cat_2 3 cat_2:cat_1:3
)"
;
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
);
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
);
std
::
istream
is_dict
(
&
buffer
);
cif
::
Validator
validator
(
"test"
,
is_dict
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
// --------------------------------------------------------------------
// --------------------------------------------------------------------
const
char
data
[]
=
R"(
const
char
data
[]
=
R"(
data_test
loop_
_cat_1.id
...
...
@@ -1004,119 +992,120 @@ _cat_2.parent_id3
7 3 3 3
)"
;
// --------------------------------------------------------------------
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 iterate children
auto
PR2set
=
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
);
BOOST_ASSERT
(
PR2set
.
size
()
==
1
);
auto
PR2
=
PR2set
.
front
();
BOOST_CHECK
(
PR2
[
"id"
].
as
<
int
>
()
==
2
);
auto
CR2set
=
cat1
.
getChildren
(
PR2
,
"cat_2"
);
BOOST_ASSERT
(
CR2set
.
size
()
==
3
);
std
::
vector
<
int
>
CRids
;
std
::
transform
(
CR2set
.
begin
(),
CR2set
.
end
(),
std
::
back_inserter
(
CRids
),
[](
cif
::
Row
r
)
{
return
r
[
"id"
].
as
<
int
>
();
});
std
::
sort
(
CRids
.
begin
(),
CRids
.
end
());
BOOST_CHECK
(
CRids
==
std
::
vector
<
int
>
({
4
,
5
,
6
}));
// 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
()
==
7
);
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_id2"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
10
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
10
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
10
).
size
()
==
1
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
))
{
r
[
"id"
]
=
20
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
7
);
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
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
2
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
2
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
20
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
20
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
20
).
size
()
==
2
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
3
))
{
r
[
"id"
]
=
30
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
7
);
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
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
3
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
3
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
30
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
30
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
30
).
size
()
==
1
);
// test delete
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
10
);
BOOST_CHECK
(
cat1
.
size
()
==
2
);
BOOST_CHECK
(
cat2
.
size
()
==
4
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
20
);
BOOST_CHECK
(
cat1
.
size
()
==
1
);
BOOST_CHECK
(
cat2
.
size
()
==
1
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
30
);
BOOST_CHECK
(
cat1
.
size
()
==
0
);
BOOST_CHECK
(
cat2
.
size
()
==
0
);
// --------------------------------------------------------------------
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 iterate children
auto
PR2set
=
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
);
BOOST_ASSERT
(
PR2set
.
size
()
==
1
);
auto
PR2
=
PR2set
.
front
();
BOOST_CHECK
(
PR2
[
"id"
].
as
<
int
>
()
==
2
);
auto
CR2set
=
cat1
.
getChildren
(
PR2
,
"cat_2"
);
BOOST_ASSERT
(
CR2set
.
size
()
==
3
);
std
::
vector
<
int
>
CRids
;
std
::
transform
(
CR2set
.
begin
(),
CR2set
.
end
(),
std
::
back_inserter
(
CRids
),
[](
cif
::
Row
r
)
{
return
r
[
"id"
].
as
<
int
>
();
});
std
::
sort
(
CRids
.
begin
(),
CRids
.
end
());
BOOST_CHECK
(
CRids
==
std
::
vector
<
int
>
({
4
,
5
,
6
}));
// 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
()
==
7
);
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_id2"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
1
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
10
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
10
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
10
).
size
()
==
1
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
2
))
{
r
[
"id"
]
=
20
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
7
);
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
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
2
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
2
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
20
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
20
).
size
()
==
2
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
20
).
size
()
==
2
);
for
(
auto
r
:
cat1
.
find
(
cif
::
Key
(
"id"
)
==
3
))
{
r
[
"id"
]
=
30
;
break
;
}
BOOST_CHECK
(
cat1
.
size
()
==
3
);
BOOST_CHECK
(
cat2
.
size
()
==
7
);
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
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
3
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
3
).
size
()
==
0
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id"
)
==
30
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id2"
)
==
30
).
size
()
==
1
);
BOOST_CHECK
(
cat2
.
find
(
cif
::
Key
(
"parent_id3"
)
==
30
).
size
()
==
1
);
// test delete
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
10
);
BOOST_CHECK
(
cat1
.
size
()
==
2
);
BOOST_CHECK
(
cat2
.
size
()
==
4
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
20
);
BOOST_CHECK
(
cat1
.
size
()
==
1
);
BOOST_CHECK
(
cat2
.
size
()
==
1
);
cat1
.
erase
(
cif
::
Key
(
"id"
)
==
30
);
BOOST_CHECK
(
cat1
.
size
()
==
0
);
BOOST_CHECK
(
cat2
.
size
()
==
0
);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE
(
c1
)
{
cif
::
VERBOSE
=
1
;
cif
::
VERBOSE
=
1
;
auto
f
=
R"(data_TEST
auto
f
=
R"(data_TEST
#
loop_
_test.id
...
...
@@ -1128,52 +1117,52 @@ _test.name
5 ?
)"
_cf
;
auto
&
db
=
f
.
firstDatablock
();
for
(
auto
r
:
db
[
"test"
].
find
(
cif
::
Key
(
"id"
)
==
1
))
{
const
auto
&
[
id
,
name
]
=
r
.
get
<
int
,
std
::
string
>
({
"id"
,
"name"
});
BOOST_CHECK
(
id
==
1
);
BOOST_CHECK
(
name
==
"aap"
);
}
for
(
auto
r
:
db
[
"test"
].
find
(
cif
::
Key
(
"id"
)
==
4
))
{
const
auto
&
[
id
,
name
]
=
r
.
get
<
int
,
std
::
string
>
({
"id"
,
"name"
});
BOOST_CHECK
(
id
==
4
);
BOOST_CHECK
(
name
.
empty
());
}
for
(
auto
r
:
db
[
"test"
].
find
(
cif
::
Key
(
"id"
)
==
5
))
{
const
auto
&
[
id
,
name
]
=
r
.
get
<
int
,
std
::
string
>
({
"id"
,
"name"
});
BOOST_CHECK
(
id
==
5
);
BOOST_CHECK
(
name
.
empty
());
}
// optional
for
(
auto
r
:
db
[
"test"
])
{
const
auto
&
[
id
,
name
]
=
r
.
get
<
int
,
std
::
optional
<
std
::
string
>>
({
"id"
,
"name"
});
switch
(
id
)
{
case
1
:
BOOST_CHECK
(
name
==
"aap"
);
break
;
case
2
:
BOOST_CHECK
(
name
==
"noot"
);
break
;
case
3
:
BOOST_CHECK
(
name
==
"mies"
);
break
;
case
4
:
case
5
:
BOOST_CHECK
(
not
name
);
break
;
default
:
BOOST_CHECK
(
false
);
}
}
auto
&
db
=
f
.
firstDatablock
();
for
(
auto
r
:
db
[
"test"
].
find
(
cif
::
Key
(
"id"
)
==
1
))
{
const
auto
&
[
id
,
name
]
=
r
.
get
<
int
,
std
::
string
>
({
"id"
,
"name"
});
BOOST_CHECK
(
id
==
1
);
BOOST_CHECK
(
name
==
"aap"
);
}
for
(
auto
r
:
db
[
"test"
].
find
(
cif
::
Key
(
"id"
)
==
4
))
{
const
auto
&
[
id
,
name
]
=
r
.
get
<
int
,
std
::
string
>
({
"id"
,
"name"
});
BOOST_CHECK
(
id
==
4
);
BOOST_CHECK
(
name
.
empty
());
}
for
(
auto
r
:
db
[
"test"
].
find
(
cif
::
Key
(
"id"
)
==
5
))
{
const
auto
&
[
id
,
name
]
=
r
.
get
<
int
,
std
::
string
>
({
"id"
,
"name"
});
BOOST_CHECK
(
id
==
5
);
BOOST_CHECK
(
name
.
empty
());
}
// optional
for
(
auto
r
:
db
[
"test"
])
{
const
auto
&
[
id
,
name
]
=
r
.
get
<
int
,
std
::
optional
<
std
::
string
>>
({
"id"
,
"name"
});
switch
(
id
)
{
case
1
:
BOOST_CHECK
(
name
==
"aap"
);
break
;
case
2
:
BOOST_CHECK
(
name
==
"noot"
);
break
;
case
3
:
BOOST_CHECK
(
name
==
"mies"
);
break
;
case
4
:
case
5
:
BOOST_CHECK
(
not
name
);
break
;
default
:
BOOST_CHECK
(
false
);
}
}
}
BOOST_AUTO_TEST_CASE
(
c2
)
{
cif
::
VERBOSE
=
1
;
cif
::
VERBOSE
=
1
;
auto
f
=
R"(data_TEST
auto
f
=
R"(data_TEST
#
loop_
_test.id
...
...
@@ -1185,31 +1174,30 @@ _test.name
5 ?
)"
_cf
;
auto
&
db
=
f
.
firstDatablock
();
// query tests
for
(
const
auto
&
[
id
,
name
]
:
db
[
"test"
].
rows
<
int
,
std
::
optional
<
std
::
string
>>
(
"id"
,
"name"
))
{
switch
(
id
)
{
case
1
:
BOOST_CHECK
(
name
==
"aap"
);
break
;
case
2
:
BOOST_CHECK
(
name
==
"noot"
);
break
;
case
3
:
BOOST_CHECK
(
name
==
"mies"
);
break
;
case
4
:
case
5
:
BOOST_CHECK
(
not
name
);
break
;
default
:
BOOST_CHECK
(
false
);
}
}
}
auto
&
db
=
f
.
firstDatablock
();
// query tests
for
(
const
auto
&
[
id
,
name
]
:
db
[
"test"
].
rows
<
int
,
std
::
optional
<
std
::
string
>>
(
"id"
,
"name"
))
{
switch
(
id
)
{
case
1
:
BOOST_CHECK
(
name
==
"aap"
);
break
;
case
2
:
BOOST_CHECK
(
name
==
"noot"
);
break
;
case
3
:
BOOST_CHECK
(
name
==
"mies"
);
break
;
case
4
:
case
5
:
BOOST_CHECK
(
not
name
);
break
;
default
:
BOOST_CHECK
(
false
);
}
}
}
BOOST_AUTO_TEST_CASE
(
c3
)
{
cif
::
VERBOSE
=
1
;
cif
::
VERBOSE
=
1
;
auto
f
=
R"(data_TEST
auto
f
=
R"(data_TEST
#
loop_
_test.id
...
...
@@ -1221,27 +1209,27 @@ _test.name
5 ?
)"
_cf
;
auto
&
db
=
f
.
firstDatablock
();
// query tests
for
(
const
auto
&
[
id
,
name
]
:
db
[
"test"
].
find
<
int
,
std
::
optional
<
std
::
string
>>
(
cif
::
All
(),
"id"
,
"name"
))
{
switch
(
id
)
{
case
1
:
BOOST_CHECK
(
name
==
"aap"
);
break
;
case
2
:
BOOST_CHECK
(
name
==
"noot"
);
break
;
case
3
:
BOOST_CHECK
(
name
==
"mies"
);
break
;
case
4
:
case
5
:
BOOST_CHECK
(
not
name
);
break
;
default
:
BOOST_CHECK
(
false
);
}
}
const
auto
&
[
id
,
name
]
=
db
[
"test"
].
find1
<
int
,
std
::
string
>
(
cif
::
Key
(
"id"
)
==
1
,
"id"
,
"name"
);
BOOST_CHECK
(
id
==
1
);
BOOST_CHECK
(
name
==
"aap"
);
auto
&
db
=
f
.
firstDatablock
();
// query tests
for
(
const
auto
&
[
id
,
name
]
:
db
[
"test"
].
find
<
int
,
std
::
optional
<
std
::
string
>>
(
cif
::
All
(),
"id"
,
"name"
))
{
switch
(
id
)
{
case
1
:
BOOST_CHECK
(
name
==
"aap"
);
break
;
case
2
:
BOOST_CHECK
(
name
==
"noot"
);
break
;
case
3
:
BOOST_CHECK
(
name
==
"mies"
);
break
;
case
4
:
case
5
:
BOOST_CHECK
(
not
name
);
break
;
default
:
BOOST_CHECK
(
false
);
}
}
const
auto
&
[
id
,
name
]
=
db
[
"test"
].
find1
<
int
,
std
::
string
>
(
cif
::
Key
(
"id"
)
==
1
,
"id"
,
"name"
);
BOOST_CHECK
(
id
==
1
);
BOOST_CHECK
(
name
==
"aap"
);
}
// --------------------------------------------------------------------
...
...
@@ -1250,22 +1238,22 @@ _test.name
BOOST_AUTO_TEST_CASE
(
r1
)
{
/*
Rationale:
The pdbx_mmcif dictionary contains inconsistent child-parent relations. E.g. atom_site is parent
of pdbx_nonpoly_scheme which itself is a parent of pdbx_entity_nonpoly. If I want to rename a residue
I cannot update pdbx_nonpoly_scheme since changing a parent changes children, but not vice versa.
But if I change the comp_id in atom_site, the pdbx_nonpoly_scheme is update, that's good, and then
pdbx_entity_nonpoly is updated and that's bad.
The idea is now that if we update a parent and a child that must change as well, we first check
if there are more parents of this child that will not change. In that case we have to split the
child into two, one with the new value and one with the old. We then of course have to split all
children of this split row that are direct children.
Rationale:
The pdbx_mmcif dictionary contains inconsistent child-parent relations. E.g. atom_site is parent
of pdbx_nonpoly_scheme which itself is a parent of pdbx_entity_nonpoly. If I want to rename a residue
I cannot update pdbx_nonpoly_scheme since changing a parent changes children, but not vice versa.
But if I change the comp_id in atom_site, the pdbx_nonpoly_scheme is update, that's good, and then
pdbx_entity_nonpoly is updated and that's bad.
The idea is now that if we update a parent and a child that must change as well, we first check
if there are more parents of this child that will not change. In that case we have to split the
child into two, one with the new value and one with the old. We then of course have to split all
children of this split row that are direct children.
*/
const
char
dict
[]
=
R"(
const
char
dict
[]
=
R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
...
...
@@ -1394,23 +1382,23 @@ cat_2 1 '_cat_2.num' '_cat_3.num' cat_3
)"
;
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
);
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
);
std
::
istream
is_dict
(
&
buffer
);
cif
::
Validator
validator
(
"test"
,
is_dict
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
cif
::
File
f
;
f
.
setValidator
(
&
validator
);
// --------------------------------------------------------------------
// --------------------------------------------------------------------
const
char
data
[]
=
R"(
const
char
data
[]
=
R"(
data_test
loop_
_cat_1.id
...
...
@@ -1435,29 +1423,29 @@ _cat_3.name
_cat_3.num
1 aap 1
2 aap 2
)"
;
)"
;
using
namespace
cif
::
literals
;
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
);
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
);
std
::
istream
is_data
(
&
data_buffer
);
f
.
load
(
is_data
);
auto
&
cat1
=
f
.
firstDatablock
()[
"cat_1"
];
auto
&
cat2
=
f
.
firstDatablock
()[
"cat_2"
];
auto
&
cat3
=
f
.
firstDatablock
()[
"cat_3"
];
auto
&
cat1
=
f
.
firstDatablock
()[
"cat_1"
];
auto
&
cat2
=
f
.
firstDatablock
()[
"cat_2"
];
auto
&
cat3
=
f
.
firstDatablock
()[
"cat_3"
];
cat3
.
update_value
(
"name"
_key
==
"aap"
and
"num"
_key
==
1
,
"name"
,
"aapje"
);
BOOST_CHECK
(
cat3
.
size
()
==
2
);
{
int
id
,
num
;
std
::
string
name
;
...
...
@@ -1471,9 +1459,9 @@ _cat_3.num
BOOST_CHECK
(
num
==
2
);
BOOST_CHECK
(
name
==
"aap"
);
}
int
i
=
0
;
for
(
const
auto
&
[
id
,
name
,
num
,
desc
]
:
cat2
.
rows
<
int
,
std
::
string
,
int
,
std
::
string
>
(
"id"
,
"name"
,
"num"
,
"desc"
))
int
i
=
0
;
for
(
const
auto
&
[
id
,
name
,
num
,
desc
]
:
cat2
.
rows
<
int
,
std
::
string
,
int
,
std
::
string
>
(
"id"
,
"name"
,
"num"
,
"desc"
))
{
switch
(
++
i
)
{
...
...
@@ -1497,7 +1485,7 @@ _cat_3.num
BOOST_CHECK
(
name
==
"noot"
);
BOOST_CHECK
(
desc
==
"walnoot bijvoorbeeld"
);
break
;
default
:
BOOST_FAIL
(
"Unexpected record"
);
}
...
...
@@ -1505,7 +1493,7 @@ _cat_3.num
BOOST_CHECK
(
cat1
.
size
()
==
4
);
i
=
0
;
for
(
const
auto
&
[
id
,
name
,
desc
]
:
cat1
.
rows
<
int
,
std
::
string
,
std
::
string
>
(
"id"
,
"name"
,
"desc"
))
for
(
const
auto
&
[
id
,
name
,
desc
]
:
cat1
.
rows
<
int
,
std
::
string
,
std
::
string
>
(
"id"
,
"name"
,
"desc"
))
{
switch
(
++
i
)
{
...
...
@@ -1526,13 +1514,13 @@ _cat_3.num
BOOST_CHECK
(
name
==
"mies"
);
BOOST_CHECK
(
desc
==
"Mies"
);
break
;
case
4
:
BOOST_CHECK
(
id
==
4
);
BOOST_CHECK
(
name
==
"aap"
);
BOOST_CHECK
(
desc
==
"Aap"
);
break
;
default
:
BOOST_FAIL
(
"Unexpected record"
);
}
...
...
@@ -1545,7 +1533,7 @@ _cat_3.num
BOOST_AUTO_TEST_CASE
(
bondmap_1
)
{
cif
::
VERBOSE
=
2
;
cif
::
VERBOSE
=
2
;
// sections taken from CCD compounds.cif
auto
components
=
R"(
...
...
@@ -1634,7 +1622,7 @@ PRO CD HD3 SING N N 16
PRO OXT HXT SING N N 17
)"
_cf
;
const
std
::
filesystem
::
path
example
(
gTestDir
/
".."
/
"examples"
/
"1cbs.cif.gz"
);
const
std
::
filesystem
::
path
example
(
gTestDir
/
".."
/
"examples"
/
"1cbs.cif.gz"
);
mmcif
::
File
file
(
example
.
string
());
mmcif
::
Structure
structure
(
file
);
...
...
@@ -1642,11 +1630,11 @@ PRO OXT HXT SING N N 17
mmcif
::
BondMap
bm
(
structure
);
// Test the bonds of the first three residues, that's PRO A 1, ASN A 2, PHE A 3
// Test the bonds of the first three residues, that's PRO A 1, ASN A 2, PHE A 3
for
(
const
auto
&
[
compound
,
seqnr
]
:
std
::
initializer_list
<
std
::
tuple
<
std
::
string
,
int
>>
{
{
"PRO"
,
1
},
{
"ASN"
,
2
},
{
"PHE"
,
3
}
})
for
(
const
auto
&
[
compound
,
seqnr
]
:
std
::
initializer_list
<
std
::
tuple
<
std
::
string
,
int
>>
{{
"PRO"
,
1
},
{
"ASN"
,
2
},
{
"PHE"
,
3
}
})
{
auto
&
res
=
structure
.
getResidue
(
"A"
,
compound
,
seqnr
);
auto
&
res
=
structure
.
getResidue
(
"A"
,
compound
,
seqnr
);
auto
atoms
=
res
.
atoms
();
auto
dc
=
components
.
get
(
compound
);
...
...
@@ -1655,14 +1643,14 @@ PRO OXT HXT SING N N 17
auto
cc
=
dc
->
get
(
"chem_comp_bond"
);
BOOST_ASSERT
(
cc
!=
nullptr
);
std
::
set
<
std
::
tuple
<
std
::
string
,
std
::
string
>>
bonded
;
std
::
set
<
std
::
tuple
<
std
::
string
,
std
::
string
>>
bonded
;
for
(
const
auto
&
[
atom_id_1
,
atom_id_2
]
:
cc
->
rows
<
std
::
string
,
std
::
string
>
(
"atom_id_1"
,
"atom_id_2"
))
for
(
const
auto
&
[
atom_id_1
,
atom_id_2
]
:
cc
->
rows
<
std
::
string
,
std
::
string
>
(
"atom_id_1"
,
"atom_id_2"
))
{
if
(
atom_id_1
>
atom_id_2
)
bonded
.
insert
({
atom_id_2
,
atom_id_1
});
bonded
.
insert
({
atom_id_2
,
atom_id_1
});
else
bonded
.
insert
({
atom_id_1
,
atom_id_2
});
bonded
.
insert
({
atom_id_1
,
atom_id_2
});
}
for
(
size_t
i
=
0
;
i
+
1
<
atoms
.
size
();
++
i
)
...
...
@@ -1677,8 +1665,8 @@ PRO OXT HXT SING N N 17
bool
bonded_1_i
=
bm
(
atoms
[
j
],
atoms
[
i
]);
bool
bonded_t
=
label_i
>
label_j
?
bonded
.
count
({
label_j
,
label_i
})
:
bonded
.
count
({
label_i
,
label_j
});
?
bonded
.
count
({
label_j
,
label_i
})
:
bonded
.
count
({
label_i
,
label_j
});
BOOST_CHECK
(
bonded_1
==
bonded_t
);
BOOST_CHECK
(
bonded_1_i
==
bonded_t
);
...
...
@@ -1718,20 +1706,19 @@ BOOST_AUTO_TEST_CASE(t1)
// q = Normalize(q);
// Quaternion q{ 0.1, 0.2, 0.3, 0.4 };
Quaternion
q
{
0.5
,
0.5
,
0.5
,
0.5
};
Quaternion
q
{
0.5
,
0.5
,
0.5
,
0.5
};
q
=
Normalize
(
q
);
const
auto
&&
[
angle0
,
axis0
]
=
QuaternionToAngleAxis
(
q
);
std
::
vector
<
Point
>
p1
{
{
16.979
,
13.301
,
44.555
},
{
18.150
,
13.525
,
43.680
},
{
18.656
,
14.966
,
43.784
},
{
17.890
,
15.889
,
44.078
},
{
17.678
,
13.270
,
42.255
},
{
16.248
,
13.734
,
42.347
},
{
15.762
,
13.216
,
43.724
}
};
{
16.979
,
13.301
,
44.555
},
{
18.150
,
13.525
,
43.680
},
{
18.656
,
14.966
,
43.784
},
{
17.890
,
15.889
,
44.078
},
{
17.678
,
13.270
,
42.255
},
{
16.248
,
13.734
,
42.347
},
{
15.762
,
13.216
,
43.724
}};
auto
p2
=
p1
;
...
...
@@ -1739,7 +1726,7 @@ BOOST_AUTO_TEST_CASE(t1)
for
(
auto
&
p
:
p2
)
p
.
rotate
(
q
);
CenterPoints
(
p2
);
auto
q2
=
AlignPoints
(
p1
,
p2
);
...
...
@@ -1757,3 +1744,38 @@ BOOST_AUTO_TEST_CASE(t1)
// std::cout << "rmsd: " << RMSd(p1, p2) << std::endl;
}
BOOST_AUTO_TEST_CASE
(
parser_test_1
)
{
auto
data1
=
R"(
data_QM
_test.text ??
)"
_cf
;
auto
&
db1
=
data1
.
firstDatablock
();
auto
&
test1
=
db1
[
"test"
];
BOOST_CHECK_EQUAL
(
test1
.
size
(),
1
);
for
(
auto
r
:
test1
)
{
const
auto
&
[
text
]
=
r
.
get
<
std
::
string
>
({
"text"
});
BOOST_CHECK_EQUAL
(
text
,
"??"
);
}
std
::
stringstream
ss
;
data1
.
save
(
ss
);
auto
data2
=
cif
::
File
(
ss
);
auto
&
db2
=
data2
.
firstDatablock
();
auto
&
test2
=
db2
[
"test"
];
BOOST_CHECK_EQUAL
(
test2
.
size
(),
1
);
for
(
auto
r
:
test2
)
{
const
auto
&
[
text
]
=
r
.
get
<
std
::
string
>
({
"text"
});
BOOST_CHECK_EQUAL
(
text
,
"??"
);
}
}
\ No newline at end of file
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