fix(ConfigurationView): ConfigurationView and JSON is broken for array access #3635

This commit is contained in:
Alex Fabijanic 2022-06-20 20:59:10 +02:00
parent 41f11b02bc
commit 37cb890e58
6 changed files with 70 additions and 24 deletions

View File

@ -32,7 +32,7 @@ class JSON_API Query
{
public:
Query(const Dynamic::Var& source);
/// Creates a Query/
/// Creates a Query.
///
/// Source must be JSON Object, Array, Object::Ptr,
/// Array::Ptr or empty Var. Any other type will trigger throwing of

View File

@ -101,6 +101,8 @@ Array& Query::findArray(const std::string& path, Array& arr) const
Var Query::find(const std::string& path) const
{
Var result = _source;
if (path.empty()) return result;
bool found = false;
StringTokenizer tokenizer(path, ".");
for (const auto& token: tokenizer)
{
@ -134,14 +136,15 @@ Var Query::find(const std::string& path) const
{
Object::Ptr o = result.extract<Object::Ptr>();
result = o->get(name);
found = true;
}
else if (result.type() == typeid(Object))
{
Object o = result.extract<Object>();
result = o.get(name);
found = true;
}
else
result.empty();
else result.empty();
}
@ -165,6 +168,7 @@ Var Query::find(const std::string& path) const
}
}
}
if (!found) result.empty();
return result;
}

View File

@ -1141,6 +1141,10 @@ void JSONTest::testQuery()
std::string firstChild = query.findValue("children[0]", "");
assertTrue (firstChild.compare("Jonas") == 0);
std::string secondChild = query.findValue("children[1]", "");
assertTrue (secondChild.compare("Ellen") == 0);
std::string thirdChild = query.findValue("children[2]", "");
assertTrue (thirdChild.empty());
Poco::DynamicStruct ds = *result.extract<Object::Ptr>();
assertTrue (ds["name"] == "Franky");
@ -1195,6 +1199,22 @@ void JSONTest::testQuery()
fail ("must throw");
}
catch (Poco::InvalidArgumentException&) { }
json = R"json({"foo":["bar"]})json";
try { result = parser.parse(json); }
catch(JSONException& jsone)
{
fail (jsone.message());
}
Query queryFoo(result);
result = queryFoo.find("foo[0]");
assertTrue (!result.isEmpty());
result = queryFoo.find("foo[1]");
assertTrue (result.isEmpty());
result = queryFoo.find("[1]");
assertTrue (result.isEmpty());
result = queryFoo.find("");
assertTrue (result.convert<std::string>() == json);
}

View File

@ -70,7 +70,7 @@ void JSONConfiguration::load(std::istream& istr)
JSON::Parser parser;
parser.parse(istr);
DynamicAny result = parser.result();
if ( result.type() == typeid(JSON::Object::Ptr) )
if (result.type() == typeid(JSON::Object::Ptr))
{
_object = result.extract<JSON::Object::Ptr>();
}
@ -89,7 +89,7 @@ bool JSONConfiguration::getRaw(const std::string & key, std::string & value) con
{
JSON::Query query(_object);
Poco::DynamicAny result = query.find(key);
if ( ! result.isEmpty() )
if (!result.isEmpty())
{
value = result.convert<std::string>();
return true;
@ -106,9 +106,9 @@ void JSONConfiguration::getIndexes(std::string& name, std::vector<int>& indexes)
int firstOffset = -1;
int offset = 0;
RegularExpression regex("\\[([0-9]+)\\]");
while(regex.match(name, offset, matches) > 0 )
while(regex.match(name, offset, matches) > 0)
{
if ( firstOffset == -1 )
if (firstOffset == -1)
{
firstOffset = static_cast<int>(matches[0].offset);
}
@ -117,7 +117,7 @@ void JSONConfiguration::getIndexes(std::string& name, std::vector<int>& indexes)
offset = static_cast<int>(matches[0].offset + matches[0].length);
}
if ( firstOffset != -1 )
if (firstOffset != -1)
{
name = name.substr(0, firstOffset);
}
@ -139,9 +139,9 @@ JSON::Object::Ptr JSONConfiguration::findStart(const std::string& key, std::stri
DynamicAny result = currentObject->get(name);
if ( result.isEmpty() ) // Not found
if (result.isEmpty()) // Not found
{
if ( indexes.empty() ) // We want an object, create it
if (indexes.empty()) // We want an object, create it
{
JSON::Object::Ptr newObject = new JSON::Object();
currentObject->set(name, newObject);
@ -155,12 +155,12 @@ JSON::Object::Ptr JSONConfiguration::findStart(const std::string& key, std::stri
for(std::vector<int>::iterator it = indexes.begin(); it != indexes.end(); ++it)
{
newArray = new JSON::Array();
if ( topArray.isNull() )
if (topArray.isNull())
{
topArray = newArray;
}
if ( ! parentArray.isNull() )
if (! parentArray.isNull())
{
parentArray->add(newArray);
}
@ -181,9 +181,9 @@ JSON::Object::Ptr JSONConfiguration::findStart(const std::string& key, std::stri
}
else // We have a value
{
if ( indexes.empty() ) // We want an object
if (indexes.empty()) // We want an object
{
if ( result.type() == typeid(JSON::Object::Ptr) )
if (result.type() == typeid(JSON::Object::Ptr))
{
currentObject = result.extract<JSON::Object::Ptr>();
}
@ -194,7 +194,7 @@ JSON::Object::Ptr JSONConfiguration::findStart(const std::string& key, std::stri
}
else
{
if ( result.type() == typeid(JSON::Array::Ptr) )
if (result.type() == typeid(JSON::Array::Ptr))
{
JSON::Array::Ptr arr = result.extract<JSON::Array::Ptr>();
@ -202,7 +202,7 @@ JSON::Object::Ptr JSONConfiguration::findStart(const std::string& key, std::stri
{
JSON::Array::Ptr currentArray = arr;
arr = arr->getArray(*it);
if ( arr.isNull() )
if (arr.isNull())
{
arr = new JSON::Array();
currentArray->add(arr);
@ -210,7 +210,7 @@ JSON::Object::Ptr JSONConfiguration::findStart(const std::string& key, std::stri
}
result = arr->get(*indexes.rbegin());
if ( result.isEmpty() ) // Index doesn't exist
if (result.isEmpty()) // Index doesn't exist
{
JSON::Object::Ptr newObject = new JSON::Object();
arr->add(newObject);
@ -218,7 +218,7 @@ JSON::Object::Ptr JSONConfiguration::findStart(const std::string& key, std::stri
}
else // Index is available
{
if ( result.type() == typeid(JSON::Object::Ptr) )
if (result.type() == typeid(JSON::Object::Ptr))
{
currentObject = result.extract<JSON::Object::Ptr>();
}
@ -258,19 +258,19 @@ void JSONConfiguration::setValue(const std::string& key, const Poco::DynamicAny&
std::vector<int> indexes;
getIndexes(lastPart, indexes);
if ( indexes.empty() ) // No Array
if (indexes.empty()) // No Array
{
parentObject->set(lastPart, value);
}
else
{
DynamicAny result = parentObject->get(lastPart);
if ( result.isEmpty() )
if (result.isEmpty())
{
result = JSON::Array::Ptr(new JSON::Array());
parentObject->set(lastPart, result);
}
else if ( result.type() != typeid(JSON::Array::Ptr) )
else if (result.type() != typeid(JSON::Array::Ptr))
{
throw SyntaxException("Expected a JSON array");
}
@ -279,7 +279,7 @@ void JSONConfiguration::setValue(const std::string& key, const Poco::DynamicAny&
for(std::vector<int>::iterator it = indexes.begin(); it != indexes.end() - 1; ++it)
{
JSON::Array::Ptr nextArray = arr->getArray(*it);
if ( nextArray.isNull() )
if (nextArray.isNull())
{
for(int i = static_cast<int>(arr->size()); i <= *it; ++i)
{
@ -335,7 +335,7 @@ void JSONConfiguration::enumerate(const std::string& key, Keys& range) const
{
JSON::Query query(_object);
Poco::DynamicAny result = query.find(key);
if ( result.type() == typeid(JSON::Object::Ptr) )
if (result.type() == typeid(JSON::Object::Ptr))
{
JSON::Object::Ptr object = result.extract<JSON::Object::Ptr>();
object->getNames(range);
@ -358,7 +358,7 @@ void JSONConfiguration::removeRaw(const std::string& key)
std::vector<int> indexes;
getIndexes(lastPart, indexes);
if ( indexes.empty() ) // No Array
if (indexes.empty()) // No Array
{
parentObject->remove(lastPart);
}

View File

@ -113,6 +113,26 @@ void JSONConfigurationTest::testSetArrayElement()
}
void JSONConfigurationTest::testConfigurationView()
{
std::string json = R"json({ "foo" : [ "bar" ] })json";
Poco::Util::JSONConfiguration config;
std::istringstream stream(json);
config.load(stream);
Poco::Util::AbstractConfiguration::Ptr pView = config.createView("foo");
assertTrue (pView->getString("[0]") == "bar");
try
{
pView->getString("[1]");
fail ("must throw on index out of bounds");
}
catch(Poco::NotFoundException&){}
}
AbstractConfiguration::Ptr JSONConfigurationTest::allocConfiguration() const
{
return new JSONConfiguration;
@ -136,6 +156,7 @@ CppUnit::Test* JSONConfigurationTest::suite()
AbstractConfigurationTest_addTests(pSuite, JSONConfigurationTest);
CppUnit_addTest(pSuite, JSONConfigurationTest, testLoad);
CppUnit_addTest(pSuite, JSONConfigurationTest, testSetArrayElement);
CppUnit_addTest(pSuite, JSONConfigurationTest, testConfigurationView);
return pSuite;
}

View File

@ -26,6 +26,7 @@ public:
void testLoad();
void testSetArrayElement();
void testConfigurationView();
void setUp();
void tearDown();