diff --git a/tests/trikKernelTests/configurerTest.cpp b/tests/trikKernelTests/configurerTest.cpp new file mode 100644 index 000000000..3926f0311 --- /dev/null +++ b/tests/trikKernelTests/configurerTest.cpp @@ -0,0 +1,33 @@ +/* Copyright 2015 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "configurerTest.h" + +TEST_F(ConfigurerTest, deviceClassParseTest) +{ + ASSERT_TRUE(mConfigurer->attributeByDevice("servoMotor", "controlMax") == "90"); + ASSERT_TRUE(mConfigurer->attributeByPort("S1", "period") == "20000000"); +} + +TEST_F(ConfigurerTest, deviceTypeParseTest) +{ + ASSERT_TRUE(mConfigurer->attributeByPort("S1", "min") == "700000"); +} + +TEST_F(ConfigurerTest, changeAttributeTest) +{ + ASSERT_TRUE(mConfigurer->attributeByPort("S1", "min") == "700000"); + mConfigurer->changeAttributeByPort("S1", "min", "7"); + ASSERT_TRUE(mConfigurer->attributeByPort("S1", "min") == "7"); +} diff --git a/tests/trikKernelTests/configurerTest.h b/tests/trikKernelTests/configurerTest.h new file mode 100644 index 000000000..0a0975af5 --- /dev/null +++ b/tests/trikKernelTests/configurerTest.h @@ -0,0 +1,41 @@ +/* Copyright 2015 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include + +#include + +using namespace trikKernel; + +/// Test fixture for Configurer class. +class ConfigurerTest : public testing::Test +{ +protected: + void SetUp() + { + mConfigurer = new Configurer(QString("./test-system-config.xml"), QString("./test-model-config.xml")); + } + + void TearDown() + { + delete mConfigurer; + } + + /// Has ownership + Configurer *mConfigurer; +}; + + diff --git a/tests/trikKernelTests/trikKernelTests.pro b/tests/trikKernelTests/trikKernelTests.pro index fc920bc21..116fd7094 100644 --- a/tests/trikKernelTests/trikKernelTests.pro +++ b/tests/trikKernelTests/trikKernelTests.pro @@ -18,10 +18,12 @@ include(../common.pri) HEADERS += \ $$PWD/synchronizedVarTest.h \ + configurerTest.h SOURCES += \ $$PWD/synchronizedVarTest.cpp \ $$PWD/differentOwnedPointerTest.cpp \ + configurerTest.cpp implementationIncludes(trikKernel) links(trikKernel) diff --git a/trikKernel/include/trikKernel/configurer.h b/trikKernel/include/trikKernel/configurer.h index 8a5fbe43c..a2c55ba6d 100644 --- a/trikKernel/include/trikKernel/configurer.h +++ b/trikKernel/include/trikKernel/configurer.h @@ -60,6 +60,12 @@ class Configurer /// Returns version of the config file which shall correspond to casing model. QString version() const; + /// Creates new model-config file + void generateConfigFile(const QString &fileName, const QString &dirPath) const; + + /// Changes value of given attribute of a device on given port + void changeAttributeByPort(const QString &port, const QString &attributeName, const QString &newAttributeValue); + private: struct Device { QString name; @@ -81,7 +87,7 @@ class Configurer }; struct AdditionalModelConfigurationElement { - QString deviceClass; + QString deviceType; QHash attributes; }; diff --git a/trikKernel/src/configurer.cpp b/trikKernel/src/configurer.cpp index d7b5c252b..3ba7f4517 100644 --- a/trikKernel/src/configurer.cpp +++ b/trikKernel/src/configurer.cpp @@ -195,6 +195,121 @@ QString Configurer::version() const return mVersion; } +void Configurer::generateConfigFile(const QString &fileName, const QString &dirPath) const +{ + QString content = "" + '\n'; + const QString indent = " "; + QStringList sortedPorts = ports(); + sortedPorts.sort(); + + for (const QString &port : sortedPorts) { + ModelConfigurationElement currentElement = mModelConfiguration[port]; + content += indent + "<" + port + ">" + '\n'; + content += indent + indent + "<" + currentElement.deviceType; + + QStringList sortedAttributes = currentElement.attributes.keys(); + sortedAttributes.sort(); + if (sortedAttributes.length() != 0) { + content += '\n'; + } + + for (const QString &name : sortedAttributes) { + if (mDeviceTypes[currentElement.deviceType].attributes[name] != currentElement.attributes[name]) { + content += indent + indent + indent + name + "=\"" + currentElement.attributes[name] + "\"" + '\n'; + } + } + + if (sortedAttributes.length() != 0) { + content += indent + indent + "/>" + '\n'; + } + else { + content += QString(" ") + "/>" + '\n'; + } + + content += indent + "" + '\n'; + } + + QStringList sortedDeviceClasses = mAdditionalModelConfiguration.keys(); + sortedDeviceClasses.sort(); + for (const QString &deviceClassName : sortedDeviceClasses) { + AdditionalModelConfigurationElement currentElement = mAdditionalModelConfiguration[deviceClassName]; + content += indent + "<" + deviceClassName; + + QStringList sortedAttributes = currentElement.attributes.keys(); + sortedAttributes.sort(); + if (sortedAttributes.length() != 0) { + content += '\n'; + } + + for (const QString &name : sortedAttributes) { + if (mDevices[deviceClassName].attributes[name] != currentElement.attributes[name]) { + content += indent + indent + name + "=\"" + currentElement.attributes[name] + "\"" + '\n'; + } + } + + if (sortedAttributes.length() != 0) { + content += indent + "/>" + '\n'; + } + else { + content += " />" + '\n'; + } + } + + content += ""; + FileUtils::writeToFile(fileName, content, dirPath); +} + +void Configurer::changeAttributeByPort(const QString &port, const QString &attributeName, + const QString &newAttributeValue) +{ + if (!mModelConfiguration.contains(port)) { + throw MalformedConfigException(QString("Port '%1' is not configured").arg(port)); + } + + if (mModelConfiguration[port].attributes.contains(attributeName)) + { + mModelConfiguration[port].attributes[attributeName] = newAttributeValue; + return; + } + + const QString &deviceType = mModelConfiguration.value(port).deviceType; + if (mDeviceTypes.contains(deviceType)) { + if (mDeviceTypes[deviceType].attributes.contains(attributeName)) { + mModelConfiguration[port].attributes.insert(attributeName, newAttributeValue); + return; + } + + const QString deviceClass = mDeviceTypes[deviceType].deviceClass; + if (mDevices.contains(deviceClass)) { + const Device &device = mDevices[deviceClass]; + + if (device.attributes.contains(attributeName)) { + if (!mAdditionalModelConfiguration.contains(device.name)){ + AdditionalModelConfigurationElement element; + element.deviceType = device.name; + mAdditionalModelConfiguration.insert(device.name, element); + } + + if (!mAdditionalModelConfiguration[device.name].attributes.contains(attributeName)) { + mAdditionalModelConfiguration[device.name].attributes.insert(attributeName, newAttributeValue); + } + else { + mAdditionalModelConfiguration[device.name].attributes[attributeName] = newAttributeValue; + } + return; + } + } + else { + throw MalformedConfigException( + QString("Device type '%1' has device class '%2' which is not listed in 'deviceClasses' section.") + .arg(deviceType).arg(deviceClass)); + } + } + + throw MalformedConfigException(QString("Unknown attribute '%1' of device '%2' on port '%3'") + .arg(attributeName).arg(deviceType).arg(port)); +} + void Configurer::parseDeviceClasses(const QDomElement &element) { const QDomNodeList deviceClasses = element.childNodes(); @@ -329,8 +444,8 @@ void Configurer::parseModelConfig(const QDomElement &element) } } else { AdditionalModelConfigurationElement element; - element.deviceClass = tag.tagName(); - if (!mDevices.contains(element.deviceClass)) { + element.deviceType = tag.tagName(); + if (!mDevices.contains(element.deviceType)) { throw MalformedConfigException( "Device shall be listed in 'deviceClasses' section in system config", tag); } @@ -342,7 +457,7 @@ void Configurer::parseModelConfig(const QDomElement &element) element.attributes.insert(attribute.name(), attribute.value()); } - mAdditionalModelConfiguration.insert(element.deviceClass, element); + mAdditionalModelConfiguration.insert(element.deviceType, element); } } }