[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [dferry] /: Add beginDictEntry() / endDictEntry() and corresponding states.
From: Andreas Hartmetz <ahartmetz () gmail ! com>
Date: 2016-12-04 18:52:11
Message-ID: E1cDbtT-0001fw-6O () code ! kde ! org
[Download RAW message or body]
Git commit 244ba3c620a304e2ade00553744bead9bb444470 by Andreas Hartmetz.
Committed on 03/12/2016 at 21:29.
Pushed by ahartmetz into branch 'master'.
Add beginDictEntry() / endDictEntry() and corresponding states.
...as a compile time option. With only a little testing because
it is mainly for use in QtDBus which already has tests.
That said, the tests pass with and without WITH_DICT_ENTRY
defined.
M +152 -7 serialization/arguments.cpp
M +18 -1 serialization/arguments.h
M +96 -2 tests/serialization/tst_arguments.cpp
M +5 -0 util/error.h
https://commits.kde.org/dferry/244ba3c620a304e2ade00553744bead9bb444470
diff --git a/serialization/arguments.cpp b/serialization/arguments.cpp
index 9da1408..5ad3148 100644
--- a/serialization/arguments.cpp
+++ b/serialization/arguments.cpp
@@ -53,10 +53,10 @@ static byte alignmentLog2(uint32 alignment)
static cstring printableState(Arguments::IoState state)
{
- if (state < Arguments::NotStarted || state > Arguments::UnixFd) {
+ if (state < Arguments::NotStarted || state >= Arguments::LastState) {
return cstring();
}
- static const char *strings[Arguments::UnixFd + 1] = {
+ static const char *strings[Arguments::LastState] = {
"NotStarted",
"Finished",
"NeedMoreData",
@@ -84,6 +84,11 @@ static cstring printableState(Arguments::IoState state)
"ObjectPath",
"Signature",
"UnixFd"
+#ifdef WITH_DICT_ENTRY
+ ,
+ "BeginDictEntry",
+ "EndDictEntry"
+#endif
};
return cstring(strings[state]);
}
@@ -143,6 +148,16 @@ void Arguments::copyOneElement(Arguments::Reader *reader, \
Arguments::Writer *wri reader->endDict();
writer->endDict();
break;
+#ifdef WITH_DICT_ENTRY
+ case Arguments::BeginDictEntry:
+ reader->beginDictEntry();
+ writer->beginDictEntry();
+ break;
+ case Arguments::EndDictEntry:
+ reader->endDictEntry();
+ writer->endDictEntry();
+ break;
+#endif
case Arguments::Byte:
writer->writeByte(reader->readByte());
break;
@@ -356,9 +371,21 @@ public:
MaxFullSignatureLength = MaxSignatureLength + 1
};
+#ifdef WITH_DICT_ENTRY
+ enum DictEntryState : uint32
+ {
+ RequireBeginDictEntry = 0,
+ InDictEntry,
+ RequireEndDictEntry,
+ AfterEndDictEntry
+ };
+#endif
struct ArrayInfo
{
uint32 containedTypeBegin; // to rewind when reading the next element
+#ifdef WITH_DICT_ENTRY
+ DictEntryState dictEntryState;
+#endif
};
struct VariantInfo
@@ -1312,8 +1339,19 @@ void Arguments::Reader::advanceState()
if (likely(!d->m_nilArrayNesting) && d->m_dataPosition < \
arrayInfo.dataEnd) {
d->m_dataPosition = align(d->m_dataPosition, 8); // align to \
dict entry
d->m_signaturePosition = arrayInfo.containedTypeBegin;
+#ifdef WITH_DICT_ENTRY
+ d->m_signaturePosition--;
+ m_state = EndDictEntry;
+ m_u.Uint32 = 0; // meaning: more dict entries follow (state \
after next is BeginDictEntry) + return;
+#endif
break;
}
+#ifdef WITH_DICT_ENTRY
+ m_state = EndDictEntry;
+ m_u.Uint32 = 1; // meaning: array end reached (state after next is \
EndDict) + return;
+#endif
m_state = EndDict;
return;
}
@@ -1661,9 +1699,18 @@ bool Arguments::Reader::beginDict(EmptyArrayOption option)
if (unlikely(d->m_nilArrayNesting && option == SkipIfEmpty)) {
skipArrayOrDictSignature(true);
+#ifdef WITH_DICT_ENTRY
+ const bool ret = !d->m_nilArrayNesting;
+ advanceState();
+ endDictEntry();
+ return ret;
+ }
+ m_state = BeginDictEntry;
+#else
}
advanceState();
+#endif
return !d->m_nilArrayNesting;
}
@@ -1693,6 +1740,24 @@ void Arguments::Reader::endDict()
advanceState();
}
+#ifdef WITH_DICT_ENTRY
+void Arguments::Reader::beginDictEntry()
+{
+ VALID_IF(m_state == BeginDictEntry, Error::ReadWrongType);
+ advanceState();
+}
+
+void Arguments::Reader::endDictEntry()
+{
+ VALID_IF(m_state == EndDictEntry, Error::ReadWrongType);
+ if (m_u.Uint32 == 0) {
+ m_state = BeginDictEntry;
+ } else {
+ m_state = EndDict;
+ }
+}
+#endif
+
void Arguments::Reader::beginStruct()
{
VALID_IF(m_state == BeginStruct, Error::ReadWrongType);
@@ -1816,6 +1881,14 @@ void Arguments::Reader::skipCurrentElement()
case Arguments::BeginDict:
skipDict();
break;
+#ifdef WITH_DICT_ENTRY
+ case Arguments::BeginDictEntry:
+ beginDictEntry();
+ break;
+ case Arguments::EndDictEntry:
+ endDictEntry();
+ break;
+#endif
case Arguments::EndDict:
assert(stateOnEntry == EndDict); // only way this can happen - we \
gracefully "skip" EndDict
// and DON'T decrease nestingLevel b/c \
it would go negative. @@ -2160,9 +2233,8 @@ void \
Arguments::Writer::advanceState(cstring signatureFragment, IoState \
newState
VALID_IF(d->m_signaturePosition + signatureFragment.length <= \
MaxSignatureLength, Error::SignatureTooLong);
}
-
if (!d->m_aggregateStack.empty()) {
- const Private::AggregateInfo &aggregateInfo = d->m_aggregateStack.back();
+ Private::AggregateInfo &aggregateInfo = d->m_aggregateStack.back();
switch (aggregateInfo.aggregateType) {
case BeginVariant:
// arrays and variants may contain just one single complete type; note \
that this will @@ -2183,8 +2255,43 @@ void Arguments::Writer::advanceState(cstring \
signatureFragment, IoState newState break;
case BeginDict:
if (d->m_signaturePosition == aggregateInfo.arr.containedTypeBegin) {
+#ifdef WITH_DICT_ENTRY
+ if (aggregateInfo.arr.dictEntryState == \
Private::RequireBeginDictEntry) { + // This is only reached \
immediately after beginDict() so it's kinda wasteful, oh well. + \
VALID_IF(newState == BeginDictEntry, Error::MissingBeginDictEntry); + \
aggregateInfo.arr.dictEntryState = Private::InDictEntry; + m_state \
= DictKey; + return; // BeginDictEntry writes no data
+ }
+#endif
VALID_IF(isPrimitiveType || isStringType, \
Error::InvalidKeyTypeInDict); }
+#ifdef WITH_DICT_ENTRY
+ // TODO test this part of the state machine
+ if (d->m_signaturePosition >= aggregateInfo.arr.containedTypeBegin + 2) \
{ + if (aggregateInfo.arr.dictEntryState == \
Private::RequireEndDictEntry) { + VALID_IF(newState == \
EndDictEntry, Error::MissingEndDictEntry); + \
aggregateInfo.arr.dictEntryState = Private::AfterEndDictEntry; + \
m_state = BeginDictEntry; + return; // EndDictEntry writes no data
+ } else {
+ // v should've been caught earlier
+ assert(aggregateInfo.arr.dictEntryState == \
Private::AfterEndDictEntry); + VALID_IF(newState == BeginDictEntry \
|| newState == EndDict, Error::MissingBeginDictEntry); + // "fall \
through", the rest (another iteration or finish) is handled below + }
+ } else if (d->m_signaturePosition >= \
aggregateInfo.arr.containedTypeBegin + 1) { + \
assert(aggregateInfo.arr.dictEntryState == Private::InDictEntry); + \
aggregateInfo.arr.dictEntryState = Private::RequireEndDictEntry; + // \
Setting EndDictEntry after writing a primitive type works fine, but setting it after \
+ // ending another aggregate would be somewhat involved and need to \
happen somewhere + // else, so just don't do that. We still produce an \
error when endDictEntry() is not + // used correctly.
+ // m_state = EndDictEntry;
+
+ // continue and write the dict entry's value
+ }
+#endif
// first type has been checked already, second must be present (checked \
in EndDict // state handler). no third type allowed.
if (d->m_signaturePosition >= aggregateInfo.arr.containedTypeBegin + 2
@@ -2196,7 +2303,13 @@ void Arguments::Writer::advanceState(cstring \
signatureFragment, IoState newState
d->m_signaturePosition = aggregateInfo.arr.containedTypeBegin;
isWritingSignature = false;
m_state = DictKey;
+#ifdef WITH_DICT_ENTRY
+ assert(newState == BeginDictEntry);
+ aggregateInfo.arr.dictEntryState = Private::InDictEntry;
+ return; // BeginDictEntry writes no data
+#endif
}
+
break;
default:
break;
@@ -2325,18 +2438,24 @@ void Arguments::Writer::advanceState(cstring \
signatureFragment, IoState newState
// not re-opened before each element: there is no observable difference \
for clients VALID_IF(d->m_nesting.beginParen(), Error::ExcessiveNesting);
}
+
aggregateInfo.aggregateType = newState;
aggregateInfo.arr.containedTypeBegin = d->m_signaturePosition;
- d->m_aggregateStack.reserve(8);
- d->m_aggregateStack.push_back(aggregateInfo);
d->m_elements.push_back(Private::ElementInfo(4, \
Private::ElementInfo::ArrayLengthField)); if (newState == BeginDict) {
d->m_elements.push_back(Private::ElementInfo(structAlignment, 0)); // \
align to dict entry +#ifdef WITH_DICT_ENTRY
+ m_state = BeginDictEntry;
+ aggregateInfo.arr.dictEntryState = Private::RequireBeginDictEntry;
+#else
m_state = DictKey;
+#endif
}
- break; }
+ d->m_aggregateStack.reserve(8);
+ d->m_aggregateStack.push_back(aggregateInfo);
+ break; }
case EndDict:
case EndArray: {
const bool isDict = newState == EndDict;
@@ -2367,6 +2486,11 @@ void Arguments::Writer::advanceState(cstring \
signatureFragment, IoState newState // due to alignment changes from a different \
start address
d->m_elements.push_back(Private::ElementInfo(1, \
Private::ElementInfo::ArrayLengthEndMark)); break; }
+#ifdef WITH_DICT_ENTRY
+ case BeginDictEntry:
+ case EndDictEntry:
+ break;
+#endif
default:
VALID_IF(false, Error::InvalidType);
break;
@@ -2442,6 +2566,27 @@ void Arguments::Writer::endDict()
advanceState(cstring("}", strlen("}")), EndDict);
}
+#ifdef WITH_DICT_ENTRY
+void Arguments::Writer::beginDictEntry()
+{
+ VALID_IF(m_state == BeginDictEntry, Error::MisplacedBeginDictEntry);
+ advanceState(cstring(), BeginDictEntry);
+}
+
+void Arguments::Writer::endDictEntry()
+{
+ if (!d->m_aggregateStack.empty()) {
+ Private::AggregateInfo &aggregateInfo = d->m_aggregateStack.back();
+ if (aggregateInfo.aggregateType == BeginDict
+ && aggregateInfo.arr.dictEntryState == Private::RequireEndDictEntry) {
+ advanceState(cstring(), EndDictEntry);
+ return;
+ }
+ }
+ VALID_IF(false, Error::MisplacedEndDictEntry);
+}
+#endif
+
void Arguments::Writer::beginStruct()
{
advanceState(cstring("(", strlen("(")), BeginStruct);
diff --git a/serialization/arguments.h b/serialization/arguments.h
index 85d3f09..faa8c1e 100644
--- a/serialization/arguments.h
+++ b/serialization/arguments.h
@@ -34,6 +34,8 @@
class Error;
class Message;
+//#define WITH_DICT_ENTRY
+
class DFERRY_EXPORT Arguments
{
public:
@@ -90,7 +92,12 @@ public:
String,
ObjectPath,
Signature,
- UnixFd
+ UnixFd,
+#ifdef WITH_DICT_ENTRY
+ BeginDictEntry,
+ EndDictEntry,
+#endif
+ LastState
};
Arguments(); // constructs an empty argument list
@@ -258,6 +265,11 @@ public:
// instead of the type of primitive.
Arguments::IoState peekPrimitiveArray(EmptyArrayOption option = SkipIfEmpty) \
const;
+#ifdef WITH_DICT_ENTRY
+ void beginDictEntry();
+ void endDictEntry();
+#endif
+
private:
class Private;
friend class Private;
@@ -342,6 +354,11 @@ public:
void writePrimitiveArray(IoState type, chunk data);
+#ifdef WITH_DICT_ENTRY
+ void beginDictEntry();
+ void endDictEntry();
+#endif
+
class Private;
friend class Private;
diff --git a/tests/serialization/tst_arguments.cpp \
b/tests/serialization/tst_arguments.cpp index 9771a2b..340ab09 100644
--- a/tests/serialization/tst_arguments.cpp
+++ b/tests/serialization/tst_arguments.cpp
@@ -64,6 +64,22 @@ static bool stringsEqual(cstring s1, cstring s2)
return chunksEqual(chunk(s1.ptr, s1.length), chunk(s2.ptr, s2.length));
}
+static void maybeBeginDictEntry(Arguments::Writer *writer)
+{
+ (void) writer;
+#ifdef WITH_DICT_ENTRY
+ writer->beginDictEntry();
+#endif
+}
+
+static void maybeEndDictEntry(Arguments::Writer *writer)
+{
+ (void) writer;
+#ifdef WITH_DICT_ENTRY
+ writer->endDictEntry();
+#endif
+}
+
// This class does:
// 1) iterates over the full Arguments with m_reader
// 2) skips whole aggregates at and below nesting level m_skipAggregatesFromLevel \
with m_skippingReader @@ -98,7 +114,24 @@ public:
}
}
}
+#ifdef WITH_DICT_ENTRY
+ void beginDictEntry()
+ {
+ m_reader->beginDictEntry();
+ if (m_nestingLevel < m_skipAggregatesFromLevel && m_nilArrayNesting < \
m_skipNilArraysFromLevel) { + m_skippingReader->beginDictEntry();
+ }
+ }
+
+ void endDictEntry()
+ {
+ m_reader->endDictEntry();
+ if (m_nestingLevel < m_skipAggregatesFromLevel && m_nilArrayNesting < \
m_skipNilArraysFromLevel) { + m_skippingReader->endDictEntry();
+ }
+ }
+#endif
template<typename F, typename G>
void beginAggregate(F beginFunc, G skipFunc)
{
@@ -225,6 +258,14 @@ static void testReadWithSkip(const Arguments &arg, bool \
debugPrint) case Arguments::BeginDict:
checker.beginArrayAggregate(&Arguments::Reader::beginDict, \
&Arguments::Reader::skipDict); break;
+#ifdef WITH_DICT_ENTRY
+ case Arguments::BeginDictEntry:
+ checker.beginDictEntry();
+ break;
+ case Arguments::EndDictEntry:
+ checker.endDictEntry();
+ break;
+#endif
case Arguments::EndDict:
checker.endAggregate(&Arguments::Reader::endDict, true);
break;
@@ -292,6 +333,10 @@ static void defaultReadToWrite(Arguments::Reader *reader, \
Arguments::Writer *wri case Arguments::BeginVariant:
case Arguments::EndVariant:
case Arguments::EndArray:
+#ifdef WITH_DICT_ENTRY
+ case Arguments::BeginDictEntry:
+ case Arguments::EndDictEntry:
+#endif
case Arguments::EndDict:
case Arguments::Byte:
case Arguments::Boolean:
@@ -696,6 +741,7 @@ static void test_nesting()
Arguments::Writer writer;
for (int i = 0; i < 32; i++) {
writer.beginDict();
+ maybeBeginDictEntry(&writer);
writer.writeInt32(i); // key, next nested dict is value
}
TEST(writer.state() != Arguments::InvalidData);
@@ -706,6 +752,7 @@ static void test_nesting()
Arguments::Writer writer;
for (int i = 0; i < 32; i++) {
writer.beginDict();
+ maybeBeginDictEntry(&writer);
writer.writeInt32(i); // key, next nested dict is value
}
TEST(writer.state() != Arguments::InvalidData);
@@ -904,17 +951,22 @@ static void test_writerMisuse()
{
Arguments::Writer writer;
writer.beginDict();
+ maybeBeginDictEntry(&writer);
writer.writeByte(1);
writer.writeByte(2);
+ maybeEndDictEntry(&writer);
writer.endDict();
TEST(writer.state() != Arguments::InvalidData);
}
{
Arguments::Writer writer;
writer.beginDict();
+ maybeBeginDictEntry(&writer);
writer.writeByte(1);
writer.writeByte(2);
+ maybeEndDictEntry(&writer);
// second key-value pair
+ maybeBeginDictEntry(&writer);
TEST(writer.state() != Arguments::InvalidData);
writer.writeUint16(3); // wrong, incompatible with first element
TEST(writer.state() == Arguments::InvalidData);
@@ -922,9 +974,12 @@ static void test_writerMisuse()
{
Arguments::Writer writer;
writer.beginDict();
+ maybeBeginDictEntry(&writer);
writer.writeByte(1);
writer.writeByte(2);
+ maybeEndDictEntry(&writer);
// second key-value pair
+ maybeBeginDictEntry(&writer);
writer.writeByte(3);
TEST(writer.state() != Arguments::InvalidData);
writer.writeUint16(4); // wrong, incompatible with first element
@@ -934,6 +989,7 @@ static void test_writerMisuse()
{
Arguments::Writer writer;
writer.beginDict();
+ maybeBeginDictEntry(&writer);
writer.beginVariant(); // wrong, key type must be basic
TEST(writer.state() == Arguments::InvalidData);
}
@@ -1022,16 +1078,21 @@ static void test_complicated()
writer.writeByte(115);
writer.beginVariant();
writer.beginDict();
+ maybeBeginDictEntry(&writer);
writer.writeByte(23);
writer.beginVariant();
writer.writeString(cstring("twenty-three"));
writer.endVariant();
+ maybeEndDictEntry(&writer);
// key-value pair 2
+ maybeBeginDictEntry(&writer);
writer.writeByte(83);
writer.beginVariant();
writer.writeObjectPath(cstring("/foo/bar/object"));
writer.endVariant();
+ maybeEndDictEntry(&writer);
// key-value pair 3
+ maybeBeginDictEntry(&writer);
writer.writeByte(234);
writer.beginVariant();
writer.beginArray();
@@ -1040,11 +1101,14 @@ static void test_complicated()
writer.writeUint16(234);
writer.endArray();
writer.endVariant();
+ maybeEndDictEntry(&writer);
// key-value pair 4
+ maybeBeginDictEntry(&writer);
writer.writeByte(25);
writer.beginVariant();
addSomeVariantStuff(&writer);
writer.endVariant();
+ maybeEndDictEntry(&writer);
writer.endDict();
writer.endVariant();
writer.writeString("Hello D-Bus!");
@@ -1171,8 +1235,10 @@ static void test_isWritingSignatureBug()
writer.beginArray();
writer.beginStruct();
writer.beginDict();
+ maybeBeginDictEntry(&writer);
writer.writeByte(1);
writer.writeByte(2);
+ maybeEndDictEntry(&writer);
writer.endDict();
// Must add more stuff after the inner dict to ensure that the \
signature position of the
// dict's value is well inside the existing signature in the second \
dict entry. @@ -1182,11 +1248,14 @@ static void test_isWritingSignatureBug()
writer.endStruct();
writer.beginStruct();
writer.beginDict();
+ maybeBeginDictEntry(&writer);
writer.writeByte(1);
writer.writeByte(2);
+ maybeEndDictEntry(&writer);
// In the second pass, we are definitely NOT writing a new part \
of the dict signature,
// which used to go (that was the bug!!) through a different \
code path in // Arguments::Writer::advanceState().
+ maybeBeginDictEntry(&writer);
writer.writeByte(1);
TEST(writer.state() != Arguments::InvalidData);
writer.writeUint16(2);
@@ -1564,7 +1633,8 @@ static void test_emptyArrayAndDict()
// Test RestartEmptyArrayToWriteTypes and writing an empty array inside the \
>1st iteration of another array Arguments::Writer writer;
writer.beginArray((i & 2) ? Arguments::Writer::WriteTypesOfEmptyArray : \
Arguments::Writer::NonEmptyArray);
- writer.beginArray(Arguments::Writer::NonEmptyArray); // don't care, the \
logic error is only in the second iteration + // v don't care, the logic \
error is only in the second iteration + \
writer.beginArray(Arguments::Writer::NonEmptyArray); \
writer.writeString(cstring("a")); writer.endArray();
if (i & 1) {
@@ -1610,8 +1680,10 @@ static void test_emptyArrayAndDict()
{
Arguments::Writer writer;
writer.beginDict(Arguments::Writer::WriteTypesOfEmptyArray);
+ maybeBeginDictEntry(&writer);
writer.writeByte(0);
writer.writeString(cstring("a"));
+ maybeEndDictEntry(&writer);
writer.endDict();
TEST(writer.state() != Arguments::InvalidData);
Arguments arg = writer.finish();
@@ -1621,9 +1693,11 @@ static void test_emptyArrayAndDict()
{
Arguments::Writer writer;
writer.beginDict(Arguments::Writer::WriteTypesOfEmptyArray);
+ maybeBeginDictEntry(&writer);
writer.writeString(cstring("a"));
writer.beginVariant();
writer.endVariant();
+ maybeEndDictEntry(&writer);
writer.endDict();
TEST(writer.state() != Arguments::InvalidData);
Arguments arg = writer.finish();
@@ -1633,12 +1707,16 @@ static void test_emptyArrayAndDict()
{
Arguments::Writer writer;
writer.beginDict(Arguments::Writer::WriteTypesOfEmptyArray);
+ maybeBeginDictEntry(&writer);
writer.writeString(cstring("a"));
writer.beginVariant();
writer.endVariant();
+ maybeEndDictEntry(&writer);
+ maybeBeginDictEntry(&writer);
writer.writeString(cstring("a"));
writer.beginVariant();
writer.endVariant();
+ maybeEndDictEntry(&writer);
writer.endDict();
TEST(writer.state() != Arguments::InvalidData);
Arguments arg = writer.finish();
@@ -1648,6 +1726,7 @@ static void test_emptyArrayAndDict()
{
Arguments::Writer writer;
writer.beginDict(Arguments::Writer::WriteTypesOfEmptyArray);
+ maybeBeginDictEntry(&writer);
writer.writeString(cstring("a"));
writer.beginVariant();
TEST(writer.state() != Arguments::InvalidData);
@@ -1655,6 +1734,7 @@ static void test_emptyArrayAndDict()
// variants in nil arrays may contain data but it will be discarded, i.e. \
there will only be an // empty variant in the output
writer.endVariant();
+ maybeEndDictEntry(&writer);
writer.endDict();
Arguments arg = writer.finish();
TEST(writer.state() == Arguments::Finished);
@@ -1664,21 +1744,31 @@ static void test_emptyArrayAndDict()
// Test RestartEmptyArrayToWriteTypes and writing an empty dict inside the \
>1st iteration of another dict Arguments::Writer writer;
writer.beginDict((i & 2) ? Arguments::Writer::WriteTypesOfEmptyArray : \
Arguments::Writer::NonEmptyArray); + maybeBeginDictEntry(&writer);
writer.writeString(cstring("a"));
- writer.beginDict(Arguments::Writer::NonEmptyArray); // don't care, the \
logic error is only in the second iteration + // v don't care, the logic \
error is only in the second iteration + \
writer.beginDict(Arguments::Writer::NonEmptyArray); + \
maybeBeginDictEntry(&writer); writer.writeString(cstring("a"));
writer.writeInt32(1234);
+ maybeEndDictEntry(&writer);
writer.endDict();
+ maybeEndDictEntry(&writer);
+ maybeBeginDictEntry(&writer);
writer.writeString(cstring("a"));
if (i & 1) {
writer.beginDict(Arguments::Writer::WriteTypesOfEmptyArray);
+ maybeBeginDictEntry(&writer);
} else {
writer.beginDict(Arguments::Writer::NonEmptyArray);
writer.beginDict(Arguments::Writer::RestartEmptyArrayToWriteTypes);
+ maybeBeginDictEntry(&writer);
}
writer.writeString(cstring("a"));
writer.writeInt32(1234);
+ maybeEndDictEntry(&writer);
writer.endDict();
+ maybeEndDictEntry(&writer);
writer.endDict();
TEST(writer.state() != Arguments::InvalidData);
Arguments arg = writer.finish();
@@ -1690,6 +1780,7 @@ static void test_emptyArrayAndDict()
Arguments::Writer writer;
for (int j = 0; j <= i; j++) {
writer.beginDict(Arguments::Writer::WriteTypesOfEmptyArray);
+ maybeBeginDictEntry(&writer);
if (j == 32) {
TEST(writer.state() == Arguments::InvalidData);
}
@@ -1701,6 +1792,7 @@ static void test_emptyArrayAndDict()
}
writer.writeUint16(52345);
for (int j = 0; j <= i; j++) {
+ maybeEndDictEntry(&writer);
writer.endDict();
}
TEST(writer.state() != Arguments::InvalidData);
@@ -1734,6 +1826,8 @@ int main(int, char *[])
test_signatureLengths();
test_emptyArrayAndDict();
+ // TODO (maybe): specific tests for begin/endDictEntry() for both Reader and \
Writer. +
// TODO many more misuse tests for Writer and maybe some for Reader
std::cout << "Passed!\n";
}
diff --git a/util/error.h b/util/error.h
index cba439f..eeed6ae 100644
--- a/util/error.h
+++ b/util/error.h
@@ -75,6 +75,11 @@ public:
InvalidKeyTypeInDict,
GreaterTwoTypesInDict,
ArrayOrDictTooLong,
+
+ MissingBeginDictEntry = 1019,
+ MisplacedBeginDictEntry,
+ MissingEndDictEntry,
+ MisplacedEndDictEntry,
// we have a lot of error codes at our disposal, so reserve some for easy \
classification // by range
MaxArgumentsError = 1023,
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic