mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Rewrite JSONSchemaChecker to QT (#128)
* Add files via upload * Update CMakeLists.txt * Add files via upload * Update TestConfigFile.cpp * Update TestConfigFile.cpp * Update TestConfigFile.cpp * Update QJsonFactory.h
This commit is contained in:
parent
b1d9a041d4
commit
230cf9e970
88
include/utils/jsonschema/QJsonFactory.h
Normal file
88
include/utils/jsonschema/QJsonFactory.h
Normal file
@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
// JSON-Schema includes
|
||||
#include <utils/jsonschema/QJsonSchemaChecker.h>
|
||||
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QRegularExpression>
|
||||
|
||||
class QJsonFactory
|
||||
{
|
||||
public:
|
||||
|
||||
static int load(const QString& schema, const QString& config, QJsonObject& json)
|
||||
{
|
||||
// Load the schema and the config trees
|
||||
QJsonObject schemaTree = readJson(schema);
|
||||
QJsonObject configTree = readJson(config);
|
||||
|
||||
// create the validator
|
||||
QJsonSchemaChecker schemaChecker;
|
||||
schemaChecker.setSchema(schemaTree);
|
||||
|
||||
bool valid = schemaChecker.validate(configTree);
|
||||
|
||||
for (std::list<std::string>::const_iterator i = schemaChecker.getMessages().begin(); i != schemaChecker.getMessages().end(); ++i)
|
||||
{
|
||||
std::cout << *i << std::endl;
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
std::cerr << "Validation failed for configuration file: " << config.toStdString() << std::endl;
|
||||
return -3;
|
||||
}
|
||||
|
||||
json = configTree;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QJsonObject readJson(const QString& path)
|
||||
{
|
||||
QFile file(path);
|
||||
QJsonParseError error;
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
std::stringstream sstream;
|
||||
sstream << "Configuration file not found: " << file.errorString().toStdString();
|
||||
throw std::runtime_error(sstream.str());
|
||||
}
|
||||
|
||||
QString config = QString(file.readAll());
|
||||
config.remove(QRegularExpression("([^:]?\\/\\/.*)"));
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(config.toUtf8(), &error);
|
||||
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
{
|
||||
// report to the user the failure and their locations in the document.
|
||||
int errorLine(0), errorColumn(0);
|
||||
|
||||
for( int i=0, count=qMin( error.offset,config.size()); i<count; ++i )
|
||||
{
|
||||
++errorColumn;
|
||||
if(config.at(i) == '\n' )
|
||||
{
|
||||
errorColumn = 0;
|
||||
++errorLine;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream sstream;
|
||||
sstream << "Failed to parse configuration: " << error.errorString().toStdString() << " at Line: " << errorLine << ", Column: " << errorColumn;
|
||||
throw std::runtime_error(sstream.str());
|
||||
}
|
||||
|
||||
file.close();
|
||||
return doc.object();
|
||||
}
|
||||
};
|
190
include/utils/jsonschema/QJsonSchemaChecker.h
Normal file
190
include/utils/jsonschema/QJsonSchemaChecker.h
Normal file
@ -0,0 +1,190 @@
|
||||
#pragma once
|
||||
|
||||
// stl includes
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonArray>
|
||||
#include <QStringList>
|
||||
|
||||
/// JsonSchemaChecker is a very basic implementation of json schema.
|
||||
/// The json schema definition draft can be found at
|
||||
/// http://tools.ietf.org/html/draft-zyp-json-schema-03
|
||||
///
|
||||
/// The following keywords are supported:
|
||||
/// - type
|
||||
/// - required
|
||||
/// - properties
|
||||
/// - items
|
||||
/// - enum
|
||||
/// - minimum
|
||||
/// - maximum
|
||||
/// - addtionalProperties
|
||||
/// - minItems
|
||||
/// - maxItems
|
||||
|
||||
class QJsonSchemaChecker
|
||||
{
|
||||
public:
|
||||
QJsonSchemaChecker();
|
||||
virtual ~QJsonSchemaChecker();
|
||||
|
||||
///
|
||||
/// @param schema The schema to use
|
||||
/// @return true upon succes
|
||||
///
|
||||
bool setSchema(const QJsonObject & schema);
|
||||
|
||||
///
|
||||
/// @brief Validate a JSON structure
|
||||
/// @param value The JSON value to check
|
||||
/// @return true when the arguments is valid according to the schema
|
||||
///
|
||||
bool validate(const QJsonObject & value);
|
||||
|
||||
///
|
||||
/// @return A list of error messages
|
||||
///
|
||||
const std::list<std::string> & getMessages() const;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Validates a json-value against a given schema. Results are stored in the members of this
|
||||
/// class (_error & _messages)
|
||||
///
|
||||
/// @param[in] value The value to validate
|
||||
/// @param[in] schema The schema against which the value is validated
|
||||
///
|
||||
void validate(const QJsonValue &value, const QJsonObject & schema);
|
||||
|
||||
///
|
||||
/// Adds the given message to the message-queue (with reference to current line-number)
|
||||
///
|
||||
/// @param[in] message The message to add to the queue
|
||||
///
|
||||
void setMessage(const std::string & message);
|
||||
|
||||
///
|
||||
/// Retrieves all references from the json-value as specified by the schema
|
||||
///
|
||||
/// @param[in] value The json-value
|
||||
/// @param[in] schema The schema
|
||||
///
|
||||
void collectDependencies(const QJsonValue & value, const QJsonObject &schema);
|
||||
|
||||
private:
|
||||
// attribute check functions
|
||||
///
|
||||
/// Checks if the given value is of the specified type. If the type does not match _error is set
|
||||
/// to true and an error-message is added to the message-queue
|
||||
///
|
||||
/// @param[in] value The given value
|
||||
/// @param[in] schema The specified type (as json-value)
|
||||
///
|
||||
void checkType(const QJsonValue & value, const QJsonValue & schema);
|
||||
|
||||
///
|
||||
/// Checks is required properties of an json-object exist and if all properties are of the
|
||||
/// correct format. If this is not the case _error is set to true and an error-message is added
|
||||
/// to the message-queue.
|
||||
///
|
||||
/// @param[in] value The given json-object
|
||||
/// @param[in] schema The schema of the json-object
|
||||
///
|
||||
void checkProperties(const QJsonObject & value, const QJsonObject & schema);
|
||||
|
||||
///
|
||||
/// Verifies the additional configured properties of an json-object. If this is not the case
|
||||
/// _error is set to true and an error-message is added to the message-queue.
|
||||
///
|
||||
/// @param value The given json-object
|
||||
/// @param schema The schema for the json-object
|
||||
/// @param ignoredProperties The properties that were ignored
|
||||
///
|
||||
void checkAdditionalProperties(const QJsonObject & value, const QJsonValue & schema, const QStringList & ignoredProperties);
|
||||
|
||||
///
|
||||
/// Checks if references are configued and used correctly. If this is not the case _error is set
|
||||
/// to true and an error-message is added to the message-queue.
|
||||
///
|
||||
/// @param value The given json-object
|
||||
/// @param schemaLink The schema of the json-object
|
||||
///
|
||||
void checkDependencies(const QJsonValue & value, const QJsonValue & schemaLink);
|
||||
|
||||
///
|
||||
/// Checks if the given value is larger or equal to the specified value. If this is not the case
|
||||
/// _error is set to true and an error-message is added to the message-queue.
|
||||
///
|
||||
/// @param[in] value The given value
|
||||
/// @param[in] schema The minimum value (as json-value)
|
||||
///
|
||||
void checkMinimum(const QJsonValue & value, const QJsonValue & schema);
|
||||
|
||||
///
|
||||
/// Checks if the given value is smaller or equal to the specified value. If this is not the
|
||||
/// case _error is set to true and an error-message is added to the message-queue.
|
||||
///
|
||||
/// @param[in] value The given value
|
||||
/// @param[in] schema The maximum value (as json-value)
|
||||
///
|
||||
void checkMaximum(const QJsonValue & value, const QJsonValue & schema);
|
||||
|
||||
///
|
||||
/// Validates all the items of an array.
|
||||
///
|
||||
/// @param value The json-array
|
||||
/// @param schema The schema for the items in the array
|
||||
///
|
||||
void checkItems(const QJsonValue & value, const QJsonObject & schema);
|
||||
|
||||
///
|
||||
/// Checks if a given array has at least a minimum number of items. If this is not the case
|
||||
/// _error is set to true and an error-message is added to the message-queue.
|
||||
///
|
||||
/// @param value The json-array
|
||||
/// @param schema The minimum size specification (as json-value)
|
||||
///
|
||||
void checkMinItems(const QJsonValue & value, const QJsonValue & schema);
|
||||
|
||||
///
|
||||
/// Checks if a given array has at most a maximum number of items. If this is not the case
|
||||
/// _error is set to true and an error-message is added to the message-queue.
|
||||
///
|
||||
/// @param value The json-array
|
||||
/// @param schema The maximum size specification (as json-value)
|
||||
///
|
||||
void checkMaxItems(const QJsonValue & value, const QJsonValue & schema);
|
||||
|
||||
///
|
||||
/// Checks if a given array contains only unique items. If this is not the case
|
||||
/// _error is set to true and an error-message is added to the message-queue.
|
||||
///
|
||||
/// @param value The json-array
|
||||
/// @param schema Bool to enable the check (as json-value)
|
||||
///
|
||||
void checkUniqueItems(const QJsonValue & value, const QJsonValue & schema);
|
||||
|
||||
///
|
||||
/// Checks if an enum value is actually a valid value for that enum. If this is not the case
|
||||
/// _error is set to true and an error-message is added to the message-queue.
|
||||
///
|
||||
/// @param value The enum value
|
||||
/// @param schema The enum schema definition
|
||||
///
|
||||
void checkEnum(const QJsonValue & value, const QJsonValue & schema);
|
||||
|
||||
private:
|
||||
/// The schema of the entire json-configuration
|
||||
QJsonObject _qSchema;
|
||||
|
||||
/// The current location into a json-configuration structure being checked
|
||||
std::list<std::string> _currentPath;
|
||||
/// The result messages collected during the schema verification
|
||||
std::list<std::string> _messages;
|
||||
/// Flag indicating an error occured during validation
|
||||
bool _error;
|
||||
};
|
@ -45,6 +45,10 @@ add_library(hyperion-utils
|
||||
${CURRENT_HEADER_DIR}/jsonschema/JsonFactory.h
|
||||
${CURRENT_HEADER_DIR}/jsonschema/JsonSchemaChecker.h
|
||||
${CURRENT_SOURCE_DIR}/jsonschema/JsonSchemaChecker.cpp
|
||||
|
||||
${CURRENT_HEADER_DIR}/jsonschema/QJsonFactory.h
|
||||
${CURRENT_HEADER_DIR}/jsonschema/QJsonSchemaChecker.h
|
||||
${CURRENT_SOURCE_DIR}/jsonschema/QJsonSchemaChecker.cpp
|
||||
)
|
||||
|
||||
qt5_use_modules(hyperion-utils Core)
|
||||
|
375
libsrc/utils/jsonschema/QJsonSchemaChecker.cpp
Normal file
375
libsrc/utils/jsonschema/QJsonSchemaChecker.cpp
Normal file
@ -0,0 +1,375 @@
|
||||
// stdlib includes
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
|
||||
// Utils-Jsonschema includes
|
||||
#include <utils/jsonschema/QJsonSchemaChecker.h>
|
||||
|
||||
QJsonSchemaChecker::QJsonSchemaChecker()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
QJsonSchemaChecker::~QJsonSchemaChecker()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
bool QJsonSchemaChecker::setSchema(const QJsonObject & schema)
|
||||
{
|
||||
_qSchema = schema;
|
||||
|
||||
// TODO: check the schema
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QJsonSchemaChecker::validate(const QJsonObject & value)
|
||||
{
|
||||
// initialize state
|
||||
_error = false;
|
||||
_messages.clear();
|
||||
_currentPath.clear();
|
||||
_currentPath.push_back("[root]");
|
||||
|
||||
// validate
|
||||
validate(value, _qSchema);
|
||||
|
||||
return !_error;
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::validate(const QJsonValue & value, const QJsonObject &schema)
|
||||
{
|
||||
// check the current json value
|
||||
for (QJsonObject::const_iterator i = schema.begin(); i != schema.end(); ++i)
|
||||
{
|
||||
QString attribute = i.key();
|
||||
const QJsonValue & attributeValue = *i;
|
||||
|
||||
if (attribute == "type")
|
||||
checkType(value, attributeValue);
|
||||
else if (attribute == "properties")
|
||||
{
|
||||
if (value.isObject())
|
||||
checkProperties(value.toObject(), attributeValue.toObject());
|
||||
else
|
||||
{
|
||||
_error = true;
|
||||
setMessage("properties attribute is only valid for objects");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (attribute == "additionalProperties")
|
||||
{
|
||||
if (value.isObject())
|
||||
{
|
||||
// ignore the properties which are handled by the properties attribute (if present)
|
||||
QStringList ignoredProperties;
|
||||
if (schema.contains("properties")) {
|
||||
const QJsonObject & props = schema["properties"].toObject();
|
||||
ignoredProperties = props.keys();
|
||||
}
|
||||
|
||||
checkAdditionalProperties(value.toObject(), attributeValue, ignoredProperties);
|
||||
}
|
||||
else
|
||||
{
|
||||
_error = true;
|
||||
setMessage("additional properties attribute is only valid for objects");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (attribute == "minimum")
|
||||
checkMinimum(value, attributeValue);
|
||||
else if (attribute == "maximum")
|
||||
checkMaximum(value, attributeValue);
|
||||
else if (attribute == "items")
|
||||
{
|
||||
if (value.isArray())
|
||||
checkItems(value, attributeValue.toObject());
|
||||
else
|
||||
{
|
||||
_error = true;
|
||||
setMessage("items only valid for arrays");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (attribute == "minItems")
|
||||
checkMinItems(value, attributeValue);
|
||||
else if (attribute == "maxItems")
|
||||
checkMaxItems(value, attributeValue);
|
||||
else if (attribute == "uniqueItems")
|
||||
checkUniqueItems(value, attributeValue);
|
||||
else if (attribute == "enum")
|
||||
checkEnum(value, attributeValue);
|
||||
else if (attribute == "required")
|
||||
; // nothing to do. value is present so always oke
|
||||
else if (attribute == "id")
|
||||
; // references have already been collected
|
||||
else
|
||||
{
|
||||
// no check function defined for this attribute
|
||||
setMessage(std::string("No check function defined for attribute ") + attribute.toStdString());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::setMessage(const std::string & message)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
std::copy(_currentPath.begin(), _currentPath.end(), std::ostream_iterator<std::string>(oss, ""));
|
||||
oss << ": " << message;
|
||||
_messages.push_back(oss.str());
|
||||
}
|
||||
|
||||
const std::list<std::string> & QJsonSchemaChecker::getMessages() const
|
||||
{
|
||||
return _messages;
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::checkType(const QJsonValue & value, const QJsonValue & schema)
|
||||
{
|
||||
QString type = schema.toString();
|
||||
|
||||
bool wrongType = false;
|
||||
if (type == "string")
|
||||
wrongType = !value.isString();
|
||||
else if (type == "number")
|
||||
wrongType = !value.isDouble();
|
||||
else if (type == "integer")
|
||||
wrongType = (rint(value.toDouble()) != value.toDouble());
|
||||
else if (type == "double")
|
||||
wrongType = !value.isDouble();
|
||||
else if (type == "boolean")
|
||||
wrongType = !value.isBool();
|
||||
else if (type == "object")
|
||||
wrongType = !value.isObject();
|
||||
else if (type == "array")
|
||||
wrongType = !value.isArray();
|
||||
else if (type == "null")
|
||||
wrongType = !value.isNull();
|
||||
else if (type == "enum")
|
||||
wrongType = !value.isString();
|
||||
else if (type == "any")
|
||||
wrongType = false;
|
||||
// else
|
||||
// assert(false);
|
||||
|
||||
if (wrongType)
|
||||
{
|
||||
_error = true;
|
||||
setMessage(type.toStdString() + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::checkProperties(const QJsonObject & value, const QJsonObject & schema)
|
||||
{
|
||||
for (QJsonObject::const_iterator i = schema.begin(); i != schema.end(); ++i)
|
||||
{
|
||||
QString property = i.key();
|
||||
|
||||
const QJsonValue & propertyValue = i.value();
|
||||
|
||||
_currentPath.push_back(std::string(".") + property.toStdString());
|
||||
QJsonObject::const_iterator required = propertyValue.toObject().find("required");
|
||||
|
||||
if (value.contains(property))
|
||||
{
|
||||
validate(value[property], propertyValue.toObject());
|
||||
}
|
||||
else if (required != schema.end() && required.value().toBool())
|
||||
{
|
||||
_error = true;
|
||||
setMessage("missing member");
|
||||
}
|
||||
_currentPath.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::checkAdditionalProperties(const QJsonObject & value, const QJsonValue & schema, const QStringList & ignoredProperties)
|
||||
{
|
||||
for (QJsonObject::const_iterator i = value.begin(); i != value.end(); ++i)
|
||||
{
|
||||
QString property = i.key();
|
||||
if (std::find(ignoredProperties.begin(), ignoredProperties.end(), property) == ignoredProperties.end())
|
||||
{
|
||||
// property has no property definition. check against the definition for additional properties
|
||||
_currentPath.push_back(std::string(".") + property.toStdString());
|
||||
if (schema.isBool())
|
||||
{
|
||||
if (schema.toBool() == false)
|
||||
{
|
||||
_error = true;
|
||||
setMessage("no schema definition");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
validate(value[property], schema.toObject());
|
||||
}
|
||||
_currentPath.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::checkMinimum(const QJsonValue & value, const QJsonValue & schema)
|
||||
{
|
||||
if (!value.isDouble())
|
||||
{
|
||||
// only for numeric
|
||||
_error = true;
|
||||
setMessage("minimum check only for numeric fields");
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.toDouble() < schema.toDouble())
|
||||
{
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "value is too small (minimum=" << schema.toDouble() << ")";
|
||||
setMessage(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::checkMaximum(const QJsonValue & value, const QJsonValue & schema)
|
||||
{
|
||||
if (!value.isDouble())
|
||||
{
|
||||
// only for numeric
|
||||
_error = true;
|
||||
setMessage("maximum check only for numeric fields");
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.toDouble() > schema.toDouble())
|
||||
{
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "value is too large (maximum=" << schema.toDouble() << ")";
|
||||
setMessage(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::checkItems(const QJsonValue & value, const QJsonObject & schema)
|
||||
{
|
||||
if (!value.isArray())
|
||||
{
|
||||
// only for arrays
|
||||
_error = true;
|
||||
setMessage("items only valid for arrays");
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonArray jArray = value.toArray();
|
||||
for(int i = 0; i < jArray.size(); ++i)
|
||||
{
|
||||
// validate each item
|
||||
std::ostringstream oss;
|
||||
oss << "[" << i << "]";
|
||||
_currentPath.push_back(oss.str());
|
||||
validate(jArray[i].toObject(), schema);
|
||||
_currentPath.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::checkMinItems(const QJsonValue & value, const QJsonValue & schema)
|
||||
{
|
||||
if (!value.isArray())
|
||||
{
|
||||
// only for arrays
|
||||
_error = true;
|
||||
setMessage("minItems only valid for arrays");
|
||||
return;
|
||||
}
|
||||
|
||||
int minimum = schema.toInt();
|
||||
|
||||
QJsonArray jArray = value.toArray();
|
||||
if (static_cast<int>(jArray.size()) < minimum)
|
||||
{
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "array is too small (minimum=" << minimum << ")";
|
||||
setMessage(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::checkMaxItems(const QJsonValue & value, const QJsonValue & schema)
|
||||
{
|
||||
if (!value.isArray())
|
||||
{
|
||||
// only for arrays
|
||||
_error = true;
|
||||
setMessage("maxItems only valid for arrays");
|
||||
return;
|
||||
}
|
||||
|
||||
int maximum = schema.toInt();
|
||||
|
||||
QJsonArray jArray = value.toArray();
|
||||
if (static_cast<int>(jArray.size()) > maximum)
|
||||
{
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "array is too large (maximum=" << maximum << ")";
|
||||
setMessage(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::checkUniqueItems(const QJsonValue & value, const QJsonValue & schema)
|
||||
{
|
||||
if (!value.isArray())
|
||||
{
|
||||
// only for arrays
|
||||
_error = true;
|
||||
setMessage("uniqueItems only valid for arrays");
|
||||
return;
|
||||
}
|
||||
|
||||
if (schema.toBool() == true)
|
||||
{
|
||||
// make sure no two items are identical
|
||||
|
||||
QJsonArray jArray = value.toArray();
|
||||
for(int i = 0; i < jArray.size(); ++i)
|
||||
{
|
||||
for (int j = i+1; j < jArray.size(); ++j)
|
||||
{
|
||||
if (jArray[i] == jArray[j])
|
||||
{
|
||||
// found a value twice
|
||||
_error = true;
|
||||
setMessage("array must have unique values");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QJsonSchemaChecker::checkEnum(const QJsonValue & value, const QJsonValue & schema)
|
||||
{
|
||||
if (schema.isArray())
|
||||
{
|
||||
QJsonArray jArray = schema.toArray();
|
||||
for(int i = 0; i < jArray.size(); ++i)
|
||||
{
|
||||
if (jArray[i] == value)
|
||||
{
|
||||
// found enum value. done.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nothing found
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "Unknown enum value (allowed values are: " << schema.toString().toStdString();
|
||||
QJsonDocument doc(schema.toArray());
|
||||
QString strJson(doc.toJson(QJsonDocument::Compact));
|
||||
oss << strJson.toStdString() << ")";
|
||||
setMessage(oss.str());
|
||||
}
|
@ -6,36 +6,76 @@
|
||||
#include <QResource>
|
||||
|
||||
// JsonSchema includes
|
||||
#include <utils/jsonschema/JsonFactory.h>
|
||||
#include <utils/jsonschema/QJsonFactory.h>
|
||||
|
||||
// hyperion includes
|
||||
#include <hyperion/LedString.h>
|
||||
|
||||
Json::Value loadConfig(const std::string & configFile)
|
||||
bool loadConfig(const QString & configFile)
|
||||
{
|
||||
// make sure the resources are loaded (they may be left out after static linking)
|
||||
Q_INIT_RESOURCE(resource);
|
||||
|
||||
// read the json schema from the resource
|
||||
QResource schemaData(":/hyperion-schema");
|
||||
if (!schemaData.isValid()) \
|
||||
QJsonParseError error;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// read and set the json schema from the resource
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
QFile schemaData(":/hyperion-schema");
|
||||
|
||||
if (!schemaData.open(QIODevice::ReadOnly))
|
||||
{
|
||||
throw std::runtime_error("Schema not found");
|
||||
std::stringstream error;
|
||||
error << "Schema not found: " << schemaData.errorString().toStdString();
|
||||
throw std::runtime_error(error.str());
|
||||
}
|
||||
|
||||
Json::Reader jsonReader;
|
||||
Json::Value schemaJson;
|
||||
if (!jsonReader.parse(reinterpret_cast<const char *>(schemaData.data()), reinterpret_cast<const char *>(schemaData.data()) + schemaData.size(), schemaJson, false))
|
||||
QByteArray schema = schemaData.readAll();
|
||||
QJsonDocument schemaJson = QJsonDocument::fromJson(schema, &error);
|
||||
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
{
|
||||
throw std::runtime_error("Schema error: " + jsonReader.getFormattedErrorMessages()) ;
|
||||
// report to the user the failure and their locations in the document.
|
||||
int errorLine(0), errorColumn(0);
|
||||
|
||||
for( int i=0, count=qMin( error.offset,schema.size()); i<count; ++i )
|
||||
{
|
||||
++errorColumn;
|
||||
if(schema.at(i) == '\n' )
|
||||
{
|
||||
errorColumn = 0;
|
||||
++errorLine;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream sstream;
|
||||
sstream << "Schema error: " << error.errorString().toStdString() << " at Line: " << errorLine << ", Column: " << errorColumn;
|
||||
|
||||
throw std::runtime_error(sstream.str());
|
||||
}
|
||||
|
||||
QJsonSchemaChecker schemaChecker;
|
||||
schemaChecker.setSchema(schemaJson.object());
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// read and validate the configuration file from the command line
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
const QJsonObject jsonConfig = QJsonFactory::readJson(configFile);
|
||||
|
||||
if (!schemaChecker.validate(jsonConfig))
|
||||
{
|
||||
for (std::list<std::string>::const_iterator i = schemaChecker.getMessages().begin(); i != schemaChecker.getMessages().end(); ++i)
|
||||
{
|
||||
std::cout << *i << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "FAILED" << std::endl;
|
||||
exit(1);
|
||||
return false;
|
||||
}
|
||||
JsonSchemaChecker schemaChecker;
|
||||
schemaChecker.setSchema(schemaJson);
|
||||
|
||||
const Json::Value jsonConfig = JsonFactory::readJson(configFile);
|
||||
schemaChecker.validate(jsonConfig);
|
||||
|
||||
return jsonConfig;
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
@ -47,19 +87,20 @@ int main(int argc, char** argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string configFile(argv[1]);
|
||||
std::cout << "Configuration file selected: " << configFile.c_str() << std::endl;
|
||||
std::cout << "Attemp to load...\t";
|
||||
const QString configFile(argv[1]);
|
||||
std::cout << "Configuration file selected: " << configFile.toStdString() << std::endl;
|
||||
std::cout << "Attemp to load..." << std::endl;
|
||||
try
|
||||
{
|
||||
Json::Value value = loadConfig(configFile);
|
||||
(void)value;
|
||||
std::cout << "PASSED" << std::endl;
|
||||
if (loadConfig(configFile))
|
||||
std::cout << "PASSED" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
catch (std::runtime_error exception)
|
||||
{
|
||||
std::cout << "FAILED" << std::endl;
|
||||
std::cout << exception.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user