diff --git a/.gitignore b/.gitignore index 60170d9..0abcd13 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ tmp/* .wsjcpp-cache/* .wsjcpp-logs/* .wsjcpp/* +unit-tests.wsjcpp/data-tests/read-write-file/docker-compose.output.yml # Prerequisites *.d diff --git a/README.md b/README.md index 96d0762..1496141 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ # wsjcpp-yaml -[![Build Status](https://api.travis-ci.com/wsjcpp/wsjcpp-yaml.svg?branch=master)](https://travis-ci.com/wsjcpp/wsjcpp-yaml) [![Github Stars](https://img.shields.io/github/stars/wsjcpp/wsjcpp-yaml.svg?label=github%20%E2%98%85)](https://github.com/wsjcpp/wsjcpp-yaml) [![Github Stars](https://img.shields.io/github/contributors/wsjcpp/wsjcpp-yaml.svg)](https://github.com/wsjcpp/wsjcpp-yaml) [![Github Forks](https://img.shields.io/github/forks/wsjcpp/wsjcpp-yaml.svg?label=github%20forks)](https://github.com/wsjcpp/wsjcpp-yaml/network/members) [![Total alerts](https://img.shields.io/lgtm/alerts/g/wsjcpp/wsjcpp-yaml.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/wsjcpp/wsjcpp-yaml/alerts/) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/wsjcpp/wsjcpp-yaml.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/wsjcpp/wsjcpp-yaml/context:cpp) - -C++ Write/Reader yaml files +[![Build Status](https://api.travis-ci.com/wsjcpp/wsjcpp-yaml.svg?branch=master)](https://travis-ci.com/wsjcpp/wsjcpp-yaml) [![Github Stars](https://img.shields.io/github/stars/wsjcpp/wsjcpp-yaml.svg?label=github%20%E2%98%85)](https://github.com/wsjcpp/wsjcpp-yaml) [![Github Stars](https://img.shields.io/github/contributors/wsjcpp/wsjcpp-yaml.svg)](https://github.com/wsjcpp/wsjcpp-yaml) [![Github Forks](https://img.shields.io/github/forks/wsjcpp/wsjcpp-yaml.svg?label=github%20forks)](https://github.com/wsjcpp/wsjcpp-yaml/network/members) [![Total alerts](https://img.shields.io/lgtm/alerts/g/wsjcpp/wsjcpp-yaml.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/wsjcpp/wsjcpp-yaml/alerts/) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/wsjcpp/wsjcpp-yaml.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/wsjcpp/wsjcpp-yaml/context:cpp) [![deepcode](https://www.deepcode.ai/api/gh/badge?key=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGF0Zm9ybTEiOiJnaCIsIm93bmVyMSI6IndzamNwcCIsInJlcG8xIjoid3NqY3BwLXlhbWwiLCJpbmNsdWRlTGludCI6ZmFsc2UsImF1dGhvcklkIjoxNTY0MSwiaWF0IjoxNjAxMTQxMDc2fQ.Ueb89NfeP0aM8Bn9xpHiqQ8u5q_VF65O6PeO8aLPQ_E)](https://www.deepcode.ai/app/gh/wsjcpp/wsjcpp-yaml/_/dashboard?utm_content=gh%2Fwsjcpp%2Fwsjcpp-yaml) +C++ YAML parser/reader and writer of *.yaml/*.yml files with keeping user formatting ## Integrate to your c++ project @@ -54,19 +53,19 @@ int main(int argc, char* argv[]) { return -1; } - std::cout << "yaml is " << yaml["yaml1"].getValue() << std::endl; - std::cout << "some-map is " << yaml["some-map"].getValue() << std::endl; - std::cout << "some-map2 is " << yaml["some-map2"].getValue() << std::endl; - std::cout << "some-array has " << std::to_string(yaml["some-array"].getLength()) << std::endl; - std::cout << "some-array element 0 is " << yaml["some-array"][0].getValue() << std::endl; - std::cout << "some-array element 1 is " << yaml["some-array"][1].getValue() << std::endl; - std::cout << "some-am has " << std::to_string(yaml["some-am"].getLength()) << std::endl; + std::cout << "yaml is " << yaml["yaml1"].valStr() << std::endl; + std::cout << "some-map is " << yaml["some-map"].valStr() << std::endl; + std::cout << "some-map2 is " << yaml["some-map2"].valStr() << std::endl; + std::cout << "some-array has " << std::to_string(yaml["some-array"].valStr()) << std::endl; + std::cout << "some-array element 0 is " << yaml["some-array"][0].valStr() << std::endl; + std::cout << "some-array element 1 is " << yaml["some-array"][1].valStr() << std::endl; + std::cout << "some-am has " << std::to_string(yaml["some-am"].size()) << std::endl; std::cout << "some-am is array: " << (yaml["some-am"].isArray() ? "yes" : "no") << std::endl; - std::cout << "some-am has comment " << yaml["some-am"].getComment() << std::endl; - std::cout << "some-am element 0 : p1 is " << yaml["some-am"][0]["p1"].getValue() << std::endl; - std::cout << "some-am element 0 : p2 is " << yaml["some-am"][0]["p2"].getValue() << std::endl; - std::cout << "some-am element 1 : p1 is " << yaml["some-am"][1]["p1"].getValue() << std::endl; - std::cout << "some-am element 1 : p2 is " << yaml["some-am"][1]["p2"].getValue() << std::endl; + std::cout << "some-am has comment " << yaml["some-am"].comment() << std::endl; + std::cout << "some-am element 0 : p1 is " << yaml["some-am"][0]["p1"].valStr() << std::endl; + std::cout << "some-am element 0 : p2 is " << yaml["some-am"][0]["p2"].valStr() << std::endl; + std::cout << "some-am element 1 : p1 is " << yaml["some-am"][1]["p1"].valStr() << std::endl; + std::cout << "some-am element 1 : p2 is " << yaml["some-am"][1]["p2"].valStr() << std::endl; return 0; } diff --git a/src.wsjcpp/CMakeLists.txt b/src.wsjcpp/CMakeLists.txt index c168c43..ec5b1de 100644 --- a/src.wsjcpp/CMakeLists.txt +++ b/src.wsjcpp/CMakeLists.txt @@ -1,4 +1,4 @@ -# Automaticly generated by wsjcpp@v0.1.7 +# Automaticly generated by wsjcpp@v0.2.0 cmake_minimum_required(VERSION 3.0) add_definitions(-DWSJCPP_APP_VERSION="v0.1.3") @@ -22,7 +22,4 @@ list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_core/") list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp") list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_core/wsjcpp_core.h") -# required-libraries -list (APPEND WSJCPP_LIBRARIES "-lpthread") - diff --git a/src/main.cpp b/src/main.cpp index 8af3f86..3be199b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,12 +15,14 @@ int main(int argc, char* argv[]) { WsjcppCore::makeDir(appLogPath); } WsjcppYaml yaml; - if (!yaml.loadFromFile("./wsjcpp.yml")) { - WsjcppLog::err(TAG, "Could not read data from file"); + std::string sError; + std::string sFilePath = "./unit-tests.wsjcpp/data-tests/read-file/example-voiting-app/docker-compose.yml"; + if (!yaml.loadFromFile(sFilePath, sError)) { + WsjcppLog::err(TAG, "Could not read data from file: " + sError); return -1; } - if (!yaml.saveToFile("./wsjcpp.yml")) { + if (!yaml.saveToFile(sFilePath)) { WsjcppLog::err(TAG, "Could not save data to file"); return -1; } diff --git a/src/wsjcpp_yaml.cpp b/src/wsjcpp_yaml.cpp index 7b03a21..2b00c59 100644 --- a/src/wsjcpp_yaml.cpp +++ b/src/wsjcpp_yaml.cpp @@ -1,6 +1,7 @@ #include "wsjcpp_yaml.h" #include +#include // --------------------------------------------------------------------- // WsjcppYamlPlaceInFile @@ -62,44 +63,56 @@ std::string WsjcppYamlPlaceInFile::getForLogFormat() { } // --------------------------------------------------------------------- -// WsjcppYamlItem +// WsjcppYamlNode -WsjcppYamlItem::WsjcppYamlItem( - WsjcppYamlItem *pParent, +WsjcppYamlNode::WsjcppYamlNode( + WsjcppYamlNode *pParent, const WsjcppYamlPlaceInFile &placeInFile, - WsjcppYamlItemType nItemType + WsjcppYamlNodeType nItemType ) { m_pParent = pParent; m_placeInFile.setFilename(placeInFile.getFilename()); m_placeInFile.setLine(placeInFile.getLine()); m_placeInFile.setNumberOfLine(placeInFile.getNumberOfLine()); m_nItemType = nItemType; - m_bValueHasDoubleQuotes = false; - m_bNameHasDoubleQuotes = false; + m_nValueQuotes = WSJCPP_YAML_QUOTES_NONE; + m_nNameQuotes = WSJCPP_YAML_QUOTES_NONE; + // TODO get child intent + if (m_pParent != nullptr && m_pParent->getParent() != nullptr) { + m_nNodeDiffIntent = 2; + m_sNodeDiffIntent = " "; + } else { + m_nNodeDiffIntent = 0; + m_sNodeDiffIntent = ""; + } + TAG = "WsjcppYamlNode"; } // --------------------------------------------------------------------- -WsjcppYamlItem::~WsjcppYamlItem() { +WsjcppYamlNode::~WsjcppYamlNode() { + for (int i = 0; i < m_vObjects.size(); i++) { + delete m_vObjects[i]; + } m_vObjects.clear(); } // --------------------------------------------------------------------- -WsjcppYamlItem *WsjcppYamlItem::getParent() { +WsjcppYamlNode *WsjcppYamlNode::getParent() { return m_pParent; } // --------------------------------------------------------------------- -WsjcppYamlPlaceInFile WsjcppYamlItem::getPlaceInFile() { +WsjcppYamlPlaceInFile WsjcppYamlNode::getPlaceInFile() { return m_placeInFile; } // --------------------------------------------------------------------- -void WsjcppYamlItem::setPlaceInFile(const WsjcppYamlPlaceInFile &placeInFile) { +void WsjcppYamlNode::setPlaceInFile(const WsjcppYamlPlaceInFile &placeInFile) { m_placeInFile.setFilename(placeInFile.getFilename()); m_placeInFile.setLine(placeInFile.getLine()); m_placeInFile.setNumberOfLine(placeInFile.getNumberOfLine()); @@ -107,98 +120,98 @@ void WsjcppYamlItem::setPlaceInFile(const WsjcppYamlPlaceInFile &placeInFile) { // --------------------------------------------------------------------- -void WsjcppYamlItem::setComment(const std::string &sComment) { +void WsjcppYamlNode::setComment(const std::string &sComment) { m_sComment = sComment; } // --------------------------------------------------------------------- -std::string WsjcppYamlItem::getComment() { +std::string WsjcppYamlNode::getComment() { return m_sComment; } // --------------------------------------------------------------------- -void WsjcppYamlItem::setName(const std::string &sName, bool bHasQuotes) { +void WsjcppYamlNode::setName(const std::string &sName, WsjcppYamlQuotes nNameQuotes) { m_sName = sName; - m_bNameHasDoubleQuotes = bHasQuotes; + m_nNameQuotes = nNameQuotes; } // --------------------------------------------------------------------- -std::string WsjcppYamlItem::getName() { +std::string WsjcppYamlNode::getName() { return m_sName; } // --------------------------------------------------------------------- -bool WsjcppYamlItem::hasNameDoubleQuotes() { - return m_bNameHasDoubleQuotes; +WsjcppYamlQuotes WsjcppYamlNode::getNameQuotes() { + return m_nNameQuotes; } // --------------------------------------------------------------------- -bool WsjcppYamlItem::isEmpty() { - return m_nItemType == WSJCPP_YAML_ITEM_EMPTY; +bool WsjcppYamlNode::isEmpty() { + return m_nItemType == WSJCPP_YAML_NODE_EMPTY; } // --------------------------------------------------------------------- -void WsjcppYamlItem::doEmpty() { - if (m_nItemType == WSJCPP_YAML_ITEM_UNDEFINED) { - m_nItemType = WSJCPP_YAML_ITEM_EMPTY; +void WsjcppYamlNode::doEmpty() { + if (m_nItemType == WSJCPP_YAML_NODE_UNDEFINED) { + m_nItemType = WSJCPP_YAML_NODE_EMPTY; } else { - WsjcppLog::throw_err(TAG, "Element already defined as '" + this->getItemTypeAsString() + "'"); + throw std::runtime_error(TAG + ": Element already defined as '" + this->getItemTypeAsString() + "'"); } } // --------------------------------------------------------------------- -bool WsjcppYamlItem::isUndefined() { - return m_nItemType == WSJCPP_YAML_ITEM_UNDEFINED; +bool WsjcppYamlNode::isUndefined() { + return m_nItemType == WSJCPP_YAML_NODE_UNDEFINED; } // --------------------------------------------------------------------- -void WsjcppYamlItem::doArray() { - if (m_nItemType == WSJCPP_YAML_ITEM_UNDEFINED) { - m_nItemType = WSJCPP_YAML_ITEM_ARRAY; +void WsjcppYamlNode::doArray() { + if (m_nItemType == WSJCPP_YAML_NODE_UNDEFINED) { + m_nItemType = WSJCPP_YAML_NODE_ARRAY; } else { - WsjcppLog::throw_err(TAG, "Element already defined as '" + this->getItemTypeAsString() + "'"); + throw std::runtime_error(TAG + ": Element already defined as '" + this->getItemTypeAsString() + "'"); } } // --------------------------------------------------------------------- -void WsjcppYamlItem::doMap() { - if (m_nItemType == WSJCPP_YAML_ITEM_UNDEFINED) { - m_nItemType = WSJCPP_YAML_ITEM_MAP; +void WsjcppYamlNode::doMap() { + if (m_nItemType == WSJCPP_YAML_NODE_UNDEFINED) { + m_nItemType = WSJCPP_YAML_NODE_MAP; } else { - WsjcppLog::throw_err(TAG, "Element already defined as '" + this->getItemTypeAsString() + "'"); + throw std::runtime_error(TAG + ": Element already defined as '" + this->getItemTypeAsString() + "'"); } } // --------------------------------------------------------------------- -void WsjcppYamlItem::doValue() { - if (m_nItemType == WSJCPP_YAML_ITEM_UNDEFINED) { - m_nItemType = WSJCPP_YAML_ITEM_VALUE; +void WsjcppYamlNode::doValue() { + if (m_nItemType == WSJCPP_YAML_NODE_UNDEFINED) { + m_nItemType = WSJCPP_YAML_NODE_VALUE; } else { - WsjcppLog::throw_err(TAG, "Element already defined as '" + this->getItemTypeAsString() + "'"); + throw std::runtime_error(TAG + ": Element already defined as '" + this->getItemTypeAsString() + "'"); } } // --------------------------------------------------------------------- -bool WsjcppYamlItem::isMap() { - return m_nItemType == WSJCPP_YAML_ITEM_MAP; +bool WsjcppYamlNode::isMap() { + return m_nItemType == WSJCPP_YAML_NODE_MAP; } // --------------------------------------------------------------------- -bool WsjcppYamlItem::hasElement(const std::string &sName) { - if (m_nItemType != WSJCPP_YAML_ITEM_MAP) { - WsjcppLog::throw_err(TAG, "hasElement('" + sName + "'): Element must be map"); +bool WsjcppYamlNode::hasElement(const std::string &sName) { + if (m_nItemType != WSJCPP_YAML_NODE_MAP) { + throw std::runtime_error(TAG + ": hasElement('" + sName + "'): Element must be map"); } for (int i = 0; i < m_vObjects.size(); i++) { if (m_vObjects[i]->getName() == sName) { @@ -210,9 +223,9 @@ bool WsjcppYamlItem::hasElement(const std::string &sName) { // --------------------------------------------------------------------- -WsjcppYamlItem *WsjcppYamlItem::getElement(const std::string &sName) { - if (m_nItemType != WSJCPP_YAML_ITEM_MAP) { - WsjcppLog::throw_err(TAG, "getElement: Element must be map"); +WsjcppYamlNode *WsjcppYamlNode::getElement(const std::string &sName) { + if (m_nItemType != WSJCPP_YAML_NODE_MAP) { + throw std::runtime_error(TAG + ": getElement: Element must be map"); } for (int i = 0; i < m_vObjects.size(); i++) { @@ -221,23 +234,25 @@ WsjcppYamlItem *WsjcppYamlItem::getElement(const std::string &sName) { return m_vObjects[i]; } } - WsjcppLog::throw_err(TAG, "Element '" + sName + "' not found for " + this->getForLogFormat()); + throw_error(TAG + "Element '" + sName + "' not found for " + this->getForLogFormat()); return nullptr; } // --------------------------------------------------------------------- -bool WsjcppYamlItem::setElement(const std::string &sName, WsjcppYamlItem *pItem) { - if (m_nItemType == WSJCPP_YAML_ITEM_UNDEFINED) { - m_nItemType = WSJCPP_YAML_ITEM_MAP; // change item type to map on first element +bool WsjcppYamlNode::setElement(const std::string &sName, WsjcppYamlNode *pItem) { + if (m_nItemType == WSJCPP_YAML_NODE_UNDEFINED) { + m_nItemType = WSJCPP_YAML_NODE_MAP; // change item type to map on first element } - if (m_nItemType != WSJCPP_YAML_ITEM_MAP) { - WsjcppLog::throw_err(TAG, "setElement, Element must be 'map' for " + pItem->getPlaceInFile().getForLogFormat()); + if (m_nItemType != WSJCPP_YAML_NODE_MAP) { + throw std::runtime_error(TAG + ": setElement, Element must be 'map' for " + pItem->getPlaceInFile().getForLogFormat()); } if (this->hasElement(sName)) { // TODO remove previous element - WsjcppLog::throw_err(TAG, "setElement: Map already has element with this name: '" + sName + "'"); + throw std::runtime_error(TAG + ": setElement: Current map '" + this->getName() + "' " + "(" + m_placeInFile.getFilename() + ":" + std::to_string(m_placeInFile.getNumberOfLine()) + ") " + "already has element with this name: '" + sName + "'"); } m_vObjects.push_back(pItem); // TODO create clone return true; @@ -245,24 +260,32 @@ bool WsjcppYamlItem::setElement(const std::string &sName, WsjcppYamlItem *pItem) // --------------------------------------------------------------------- -bool WsjcppYamlItem::removeElement(const std::string &sName) { - if (m_nItemType != WSJCPP_YAML_ITEM_MAP) { - WsjcppLog::throw_err(TAG, "removeElement: Element must be map"); +bool WsjcppYamlNode::removeElement(const std::string &sName) { + if (m_nItemType != WSJCPP_YAML_NODE_MAP) { + throw std::runtime_error(TAG + ": removeElement: Element must be map"); + } + std::vector::iterator it; + for (it = m_vObjects.begin(); it != m_vObjects.end(); ++it) { + WsjcppYamlNode *pItem = *it; + if (pItem->getName() == sName) { + m_vObjects.erase(it); + delete pItem; + return true; + } } - // TODO erase return false; } // --------------------------------------------------------------------- -std::vector WsjcppYamlItem::getKeys() { - if (m_nItemType != WSJCPP_YAML_ITEM_MAP) { - WsjcppLog::throw_err(TAG, "getKeys: Element must be map"); +std::vector WsjcppYamlNode::getKeys() { + if (m_nItemType != WSJCPP_YAML_NODE_MAP) { + throw std::runtime_error(TAG + ": getKeys: Element must be map"); } std::vector vKeys; for (int i = 0; i < m_vObjects.size(); i++) { - WsjcppYamlItem *pItem = m_vObjects[i]; - if (pItem->isValue() || pItem->isMap() || pItem->isArray()) { + WsjcppYamlNode *pItem = m_vObjects[i]; + if (pItem->isValue() || pItem->isMap() || pItem->isArray() || pItem->isUndefined()) { std::string sName = pItem->getName(); vKeys.push_back(sName); } @@ -272,23 +295,28 @@ std::vector WsjcppYamlItem::getKeys() { // --------------------------------------------------------------------- -bool WsjcppYamlItem::setElementValue(const std::string &sName, bool bHasNameQuotes, const std::string &sValue, bool bHasValueQuotes) { - if (m_nItemType == WSJCPP_YAML_ITEM_UNDEFINED) { - m_nItemType = WSJCPP_YAML_ITEM_MAP; // change item type to map on first element +bool WsjcppYamlNode::setElementValue( + const std::string &sName, + const std::string &sValue, + WsjcppYamlQuotes nNameQuotes, + WsjcppYamlQuotes nValueQuotes +) { + if (m_nItemType == WSJCPP_YAML_NODE_UNDEFINED) { + m_nItemType = WSJCPP_YAML_NODE_MAP; // change item type to map on first element } - if (m_nItemType != WSJCPP_YAML_ITEM_MAP) { - WsjcppLog::throw_err(TAG, "setElement, Element must be 'map' for " + this->getPlaceInFile().getForLogFormat()); + if (m_nItemType != WSJCPP_YAML_NODE_MAP) { + throw std::runtime_error(TAG + ": setElement, Element must be 'map' for " + this->getPlaceInFile().getForLogFormat()); } if (this->hasElement(sName)) { - WsjcppYamlItem *pItem = this->getElement(sName); - pItem->setValue(sValue, bHasValueQuotes); + WsjcppYamlNode *pItem = this->getElement(sName); + pItem->setValue(sValue, nValueQuotes); } else { WsjcppYamlPlaceInFile pl; - WsjcppYamlItem *pNewItem = new WsjcppYamlItem(this, pl, WsjcppYamlItemType::WSJCPP_YAML_ITEM_VALUE); - pNewItem->setName(sName, bHasNameQuotes); - pNewItem->setValue(sValue, bHasValueQuotes); + WsjcppYamlNode *pNewItem = new WsjcppYamlNode(this, pl, WSJCPP_YAML_NODE_VALUE); + pNewItem->setName(sName, nNameQuotes); + pNewItem->setValue(sValue, nValueQuotes); this->setElement(sName, pNewItem); } return true; @@ -296,59 +324,60 @@ bool WsjcppYamlItem::setElementValue(const std::string &sName, bool bHasNameQuot // --------------------------------------------------------------------- -bool WsjcppYamlItem::createElementMap(const std::string &sName, bool bHasNameQuotes) { - if (m_nItemType != WSJCPP_YAML_ITEM_MAP ) { - WsjcppLog::throw_err(TAG, "createElementMap, Element must be 'map' for " + this->getPlaceInFile().getForLogFormat()); +bool WsjcppYamlNode::createElementMap(const std::string &sName, WsjcppYamlQuotes nNameQuotes) { + if (m_nItemType != WSJCPP_YAML_NODE_MAP ) { + throw std::runtime_error(TAG + ": createElementMap, Element must be 'map' for " + this->getPlaceInFile().getForLogFormat()); } if (this->hasElement(sName)) { return false; // already exists } WsjcppYamlPlaceInFile pl; - WsjcppYamlItem *pNewItem = new WsjcppYamlItem(this, pl, WsjcppYamlItemType::WSJCPP_YAML_ITEM_MAP); - pNewItem->setName(sName, bHasNameQuotes); + WsjcppYamlNode *pNewItem = new WsjcppYamlNode(this, pl, WSJCPP_YAML_NODE_MAP); + pNewItem->setName(sName, nNameQuotes); + // pNewItem->setNodeIntents({2}); this->setElement(sName, pNewItem); return true; } // --------------------------------------------------------------------- -WsjcppYamlItem *WsjcppYamlItem::createElementMap() { - if (m_nItemType != WSJCPP_YAML_ITEM_ARRAY ) { - WsjcppLog::throw_err(TAG, "createElementMap, Element must be 'array' for " + this->getPlaceInFile().getForLogFormat()); +WsjcppYamlNode *WsjcppYamlNode::createElementMap() { + if (m_nItemType != WSJCPP_YAML_NODE_ARRAY ) { + throw std::runtime_error(TAG + ": createElementMap, Element must be 'array' for " + this->getPlaceInFile().getForLogFormat()); } WsjcppYamlPlaceInFile pl; - WsjcppYamlItem *pNewItem = new WsjcppYamlItem(this, pl, WsjcppYamlItemType::WSJCPP_YAML_ITEM_MAP); + WsjcppYamlNode *pNewItem = new WsjcppYamlNode(this, pl, WSJCPP_YAML_NODE_MAP); this->appendElement(pNewItem); return pNewItem; } // --------------------------------------------------------------------- -bool WsjcppYamlItem::createElementArray(const std::string &sName, bool bHasNameQuotes) { - if (m_nItemType != WSJCPP_YAML_ITEM_MAP ) { - WsjcppLog::throw_err(TAG, "createElementArray, Element must be 'map' for " + this->getPlaceInFile().getForLogFormat()); +bool WsjcppYamlNode::createElementArray(const std::string &sName, WsjcppYamlQuotes nNameQuotes) { + if (m_nItemType != WSJCPP_YAML_NODE_MAP ) { + throw std::runtime_error(TAG + ": createElementArray, Element must be 'map' for " + this->getPlaceInFile().getForLogFormat()); } if (this->hasElement(sName)) { return false; } WsjcppYamlPlaceInFile pl; - WsjcppYamlItem *pNewItem = new WsjcppYamlItem(this, pl, WsjcppYamlItemType::WSJCPP_YAML_ITEM_ARRAY); - pNewItem->setName(sName, bHasNameQuotes); + WsjcppYamlNode *pNewItem = new WsjcppYamlNode(this, pl, WSJCPP_YAML_NODE_ARRAY); + pNewItem->setName(sName, nNameQuotes); this->setElement(sName, pNewItem); return true; } // --------------------------------------------------------------------- -bool WsjcppYamlItem::isArray() { - return m_nItemType == WSJCPP_YAML_ITEM_ARRAY; +bool WsjcppYamlNode::isArray() { + return m_nItemType == WSJCPP_YAML_NODE_ARRAY; } // --------------------------------------------------------------------- -int WsjcppYamlItem::getLength() { - if (m_nItemType != WSJCPP_YAML_ITEM_ARRAY) { - WsjcppLog::throw_err(TAG, "getLength, Element must be array for " + this->getForLogFormat()); +int WsjcppYamlNode::getLength() { + if (m_nItemType != WSJCPP_YAML_NODE_ARRAY) { + throw std::runtime_error(TAG + ": getLength, Element must be array for " + this->getForLogFormat()); } int nCount = 0; for (int i = 0; i < m_vObjects.size(); i++) { @@ -361,12 +390,12 @@ int WsjcppYamlItem::getLength() { // --------------------------------------------------------------------- -WsjcppYamlItem *WsjcppYamlItem::getElement(int i) { - if (m_nItemType != WSJCPP_YAML_ITEM_ARRAY) { - WsjcppLog::throw_err(TAG, "getElement, Element must be array"); +WsjcppYamlNode *WsjcppYamlNode::getElement(int i) { + if (m_nItemType != WSJCPP_YAML_NODE_ARRAY) { + throw std::runtime_error(TAG + ": getElement, Element must be array"); } int nCounter = -1; - WsjcppYamlItem *pItem = nullptr; + WsjcppYamlNode *pItem = nullptr; for (int n = 0; n < m_vObjects.size(); n++) { if (!m_vObjects[n]->isEmpty()) { nCounter++; @@ -377,20 +406,20 @@ WsjcppYamlItem *WsjcppYamlItem::getElement(int i) { } } if (pItem == nullptr) { - WsjcppLog::throw_err(TAG, "getElement(" + std::to_string(i) + "), Out of range in array for '" + this->getPlaceInFile().getLine() + "'"); + throw std::runtime_error(TAG + ": getElement(" + std::to_string(i) + "), Out of range in array for '" + this->getPlaceInFile().getLine() + "'"); } return pItem; } // --------------------------------------------------------------------- -bool WsjcppYamlItem::appendElement(WsjcppYamlItem *pItem) { +bool WsjcppYamlNode::appendElement(WsjcppYamlNode *pItem) { if (pItem->isEmpty()) { m_vObjects.push_back(pItem); // TODO clone object return true; } - if (m_nItemType != WSJCPP_YAML_ITEM_ARRAY) { - WsjcppLog::throw_err(TAG, "appendElement, Element must be array for " + this->getForLogFormat()); + if (m_nItemType != WSJCPP_YAML_NODE_ARRAY) { + throw std::runtime_error(TAG + ": appendElement, Element must be array for " + this->getForLogFormat()); } m_vObjects.push_back(pItem); // TODO clone object return true; @@ -398,24 +427,24 @@ bool WsjcppYamlItem::appendElement(WsjcppYamlItem *pItem) { // --------------------------------------------------------------------- -bool WsjcppYamlItem::appendElementValue(const std::string &sValue, bool bHasValueQuotes) { - if (m_nItemType != WSJCPP_YAML_ITEM_ARRAY) { - WsjcppLog::throw_err(TAG, "appendElementValue, Element must be array for " + this->getForLogFormat()); +bool WsjcppYamlNode::appendElementValue(const std::string &sValue, WsjcppYamlQuotes nValueQuotes) { + if (m_nItemType != WSJCPP_YAML_NODE_ARRAY) { + throw std::runtime_error(TAG + ": appendElementValue, Element must be array for " + this->getForLogFormat()); } WsjcppYamlPlaceInFile pl; - WsjcppYamlItem *pNewItem = new WsjcppYamlItem(this, pl, WsjcppYamlItemType::WSJCPP_YAML_ITEM_VALUE); - pNewItem->setValue(sValue, bHasValueQuotes); + WsjcppYamlNode *pNewItem = new WsjcppYamlNode(this, pl, WSJCPP_YAML_NODE_VALUE); + pNewItem->setValue(sValue, nValueQuotes); return this->appendElement(pNewItem); } // --------------------------------------------------------------------- -bool WsjcppYamlItem::removeElement(int i) { - if (m_nItemType != WSJCPP_YAML_ITEM_ARRAY) { - WsjcppLog::throw_err(TAG, "appendElement, Element must be array for " + this->getForLogFormat()); +bool WsjcppYamlNode::removeElement(int i) { + if (m_nItemType != WSJCPP_YAML_NODE_ARRAY) { + throw std::runtime_error(TAG + ": appendElement, Element must be array for " + this->getForLogFormat()); } int nCounter = -1; - WsjcppYamlItem *pItem = nullptr; + WsjcppYamlNode *pItem = nullptr; for (int n = 0; n < m_vObjects.size(); n++) { if (!m_vObjects[n]->isEmpty()) { nCounter++; @@ -426,11 +455,12 @@ bool WsjcppYamlItem::removeElement(int i) { } } if (pItem == nullptr) { - WsjcppLog::throw_err(TAG, "getElement(" + std::to_string(i) + "), Out of range in array for '" + this->getPlaceInFile().getLine() + "'"); + throw std::runtime_error(TAG + ": getElement(" + std::to_string(i) + "), Out of range in array for '" + this->getPlaceInFile().getLine() + "'"); } - std::vector::iterator it; + std::vector::iterator it; for (it = m_vObjects.begin(); it != m_vObjects.end(); ++it) { if (*it == pItem) { + delete pItem; m_vObjects.erase(it); return true; } @@ -440,42 +470,59 @@ bool WsjcppYamlItem::removeElement(int i) { // --------------------------------------------------------------------- -bool WsjcppYamlItem::isValue() { - return m_nItemType == WSJCPP_YAML_ITEM_VALUE; +bool WsjcppYamlNode::isValue() { + return m_nItemType == WSJCPP_YAML_NODE_VALUE; } // --------------------------------------------------------------------- -std::string WsjcppYamlItem::getValue() { - if (m_nItemType != WSJCPP_YAML_ITEM_VALUE) { - WsjcppLog::throw_err(TAG, "getValue, Element must be value for " + this->getForLogFormat()); +std::string WsjcppYamlNode::getValue() { + if (m_nItemType != WSJCPP_YAML_NODE_VALUE) { + throw std::runtime_error(TAG + ": getValue, Element must be value for " + this->getForLogFormat()); } return m_sValue; } // --------------------------------------------------------------------- -void WsjcppYamlItem::setValue(const std::string &sValue, bool bHasQuotes) { - if (m_nItemType != WSJCPP_YAML_ITEM_VALUE) { - WsjcppLog::throw_err(TAG, "setValue, Element must be value for " + this->getForLogFormat()); +void WsjcppYamlNode::setValue(const std::string &sValue, WsjcppYamlQuotes nQuotes) { + if (m_nItemType != WSJCPP_YAML_NODE_VALUE) { + throw std::runtime_error(TAG + ": setValue, Element must be value for " + this->getForLogFormat()); } - m_bValueHasDoubleQuotes = bHasQuotes; + m_nValueQuotes = nQuotes; m_sValue = sValue; } // --------------------------------------------------------------------- -bool WsjcppYamlItem::hasValueDoubleQuotes() { - return m_bValueHasDoubleQuotes; +WsjcppYamlQuotes WsjcppYamlNode::getValueQuotes() { + return m_nValueQuotes; +} + +// --------------------------------------------------------------------- + +std::string WsjcppYamlNode::getSerializedName() { + std::string sRet = ""; + // TODO escape quotes + if (this->getNameQuotes() == WSJCPP_YAML_QUOTES_DOUBLE) { + sRet += "\"" + this->getName() + "\""; + } else if (this->getNameQuotes() == WSJCPP_YAML_QUOTES_SINGLE) { + sRet += "\'" + this->getName() + "\'"; + } else { + sRet += this->getName(); + } + return sRet; } // --------------------------------------------------------------------- -std::string WsjcppYamlItem::toString(std::string sIntent) { +std::string WsjcppYamlNode::toString(std::string sIntent) { std::string sRet = ""; if (this->isValue()) { - if (m_bValueHasDoubleQuotes) { + if (m_nValueQuotes == WSJCPP_YAML_QUOTES_DOUBLE) { sRet = "\"" + m_sValue + "\""; + } else if (m_nValueQuotes == WSJCPP_YAML_QUOTES_SINGLE) { + sRet = "\'" + m_sValue + "\'"; } else { sRet = m_sValue; } @@ -485,69 +532,95 @@ std::string WsjcppYamlItem::toString(std::string sIntent) { } sRet += "# " + m_sComment; } + } else if (this->isUndefined()) { + for (int i = 0; i < m_vObjects.size(); i++) { + if (m_vObjects[i]->isEmpty()) { + sRet += "\n"; + } else { + WsjcppLog::warn(TAG, "Undefined element contains something else"); + } + // sRet += std::to_string(m_vObjects.size()); + } + return sRet; } else if (this->isEmpty()) { if (m_sComment.length() > 0) { - sRet += sIntent + "# " + m_sComment; + sRet += sIntent + m_sNodeDiffIntent + "# " + m_sComment; } + return sRet; } else if (this->isArray()) { for (int i = 0; i < m_vObjects.size(); i++) { - WsjcppYamlItem *pItem = m_vObjects[i]; - if (pItem->isEmpty()) { - sRet += sIntent + pItem->toString(); - } else if (pItem->isMap()) { - std::string s = pItem->toString(sIntent + " "); + WsjcppYamlNode *pNode = m_vObjects[i]; + if (pNode->isEmpty()) { + std::string sVal = pNode->toString(); + sVal = WsjcppCore::trim(sVal); + if (sVal.length() > 0) { // empty string have content + sRet += sIntent + pNode->getStringNodeLastIntent(); + } + sRet += sVal; + } else if (pNode->isMap()) { + sRet += sIntent + pNode->getStringNodeLastIntent(); + std::string s = pNode->toString(sIntent + pNode->getStringNodeLastIntent()); WsjcppCore::trim(s); - sRet += sIntent + "- " + s; + sRet += "- " + s; } else { - sRet += sIntent + "- " + pItem->toString(); + sRet += sIntent + pNode->getStringNodeLastIntent(); + sRet += "- " + pNode->toString(); } sRet += "\n"; } } else if (this->isMap()) { for (int i = 0; i < m_vObjects.size(); i++) { - WsjcppYamlItem *pItem = m_vObjects[i]; - if (pItem->isEmpty() ) { - sRet += sIntent + pItem->toString(); + WsjcppYamlNode *pNode = m_vObjects[i]; + if (pNode->isEmpty() ) { + // sRet += " * " + pNode->toString(sIntent); + sRet += pNode->toString(sIntent); sRet += "\n"; - } else if (pItem->isArray() || pItem->isMap()) { - if (pItem->hasNameDoubleQuotes()) { - sRet += sIntent + "\"" + pItem->getName() + "\":"; - } else { - sRet += sIntent + pItem->getName() + ":"; - } - if (pItem->getComment().length() > 0) { - sRet += " # " + pItem->getComment(); + } else if (pNode->isUndefined()) { + sRet += sIntent + pNode->getStringNodeLastIntent() + + pNode->getSerializedName() + ":\n" + pNode->toString(); + } else if (pNode->isArray() || pNode->isMap()) { + sRet += sIntent + pNode->getStringNodeLastIntent() + + pNode->getSerializedName() + ":"; + if (pNode->getComment().length() > 0) { + sRet += " # " + pNode->getComment(); } sRet += "\n"; - sRet += pItem->toString(sIntent + " "); + sRet += pNode->toString(sIntent + pNode->getStringNodeLastIntent()); } else { - if (pItem->hasNameDoubleQuotes()) { - sRet += sIntent + "\"" + pItem->getName() + "\": " + pItem->toString(); - } else { - sRet += sIntent + pItem->getName() + ": " + pItem->toString(); + std::string sVal = pNode->toString(); + std::string sVal_ = sVal; + sVal_ = WsjcppCore::trim(sVal_); + if (sVal_.length() > 0) { + sVal = " " + sVal; } + sRet += sIntent + pNode->getStringNodeLastIntent() + + pNode->getSerializedName() + ":" + sVal; sRet += "\n"; } } } else { - sRet = "TODO: undefined"; + sRet = ""; // undefined element must be empty } - if (sIntent == "") { - WsjcppCore::trim(sRet); + + if (m_pParent == nullptr) { + int nLen = sRet.length(); + if (nLen > 0 && sRet[nLen - 1] == '\n') { + sRet = sRet.substr(0, nLen - 1); + } } return sRet; } // --------------------------------------------------------------------- -std::string WsjcppYamlItem::getItemTypeAsString() { - if (m_nItemType == WSJCPP_YAML_ITEM_UNDEFINED) { +std::string WsjcppYamlNode::getItemTypeAsString() { + if (m_nItemType == WSJCPP_YAML_NODE_UNDEFINED) { return "undefined"; - } else if (m_nItemType == WSJCPP_YAML_ITEM_ARRAY) { + } else if (m_nItemType == WSJCPP_YAML_NODE_ARRAY) { return "array"; - } else if (m_nItemType == WSJCPP_YAML_ITEM_MAP) { + } else if (m_nItemType == WSJCPP_YAML_NODE_MAP) { return "map"; - } else if (m_nItemType == WSJCPP_YAML_ITEM_VALUE) { + } else if (m_nItemType == WSJCPP_YAML_NODE_VALUE) { return "value"; } return "unknown"; @@ -555,15 +628,63 @@ std::string WsjcppYamlItem::getItemTypeAsString() { // --------------------------------------------------------------------- -std::string WsjcppYamlItem::getForLogFormat() { +std::string WsjcppYamlNode::getForLogFormat() { return m_placeInFile.getForLogFormat(); } // --------------------------------------------------------------------- +int WsjcppYamlNode::getNodeLastIntent() { + return m_nNodeDiffIntent; +} + +// --------------------------------------------------------------------- + +std::string WsjcppYamlNode::getStringNodeLastIntent() { + return m_sNodeDiffIntent; +} + +// --------------------------------------------------------------------- + +void WsjcppYamlNode::setNodeIntents(const std::vector & vNodeIntents) { + m_nNodeDiffIntent = vNodeIntents.back(); + m_sNodeDiffIntent = ""; + for (int i = 0; i < m_nNodeDiffIntent; i++) { + m_sNodeDiffIntent += " "; + } + m_nNodeIntent = 0; + for (int i = 0; i < vNodeIntents.size(); i++) { + m_nNodeIntent += vNodeIntents[i]; + } +} + +// --------------------------------------------------------------------- + +int WsjcppYamlNode::getNodeIntent() { + return m_nNodeIntent; +} + +// --------------------------------------------------------------------- + +void WsjcppYamlNode::throw_error(const std::string &sError) { + throw std::runtime_error(sError.c_str()); +} + +// --------------------------------------------------------------------- +// WsjcppYamlParsebleLine + WsjcppYamlParsebleLine::WsjcppYamlParsebleLine(int nLine) { TAG = "WsjcppYamlParsebleLine(line:" + std::to_string(nLine) + ")"; - m_nLine = nLine; + m_nLineNumber = nLine; + m_sPrefix = ""; + m_bArrayItem = false; + m_sComment = ""; + m_sTagName = ""; + m_sValue = ""; + m_nNameQuotes = WSJCPP_YAML_QUOTES_NONE; + m_nValueQuotes = WSJCPP_YAML_QUOTES_NONE; + m_bHasComment = false; + m_bEmptyLine = false; } // --------------------------------------------------------------------- @@ -576,7 +697,7 @@ WsjcppYamlParsebleLine::WsjcppYamlParsebleLine() // --------------------------------------------------------------------- int WsjcppYamlParsebleLine::getLineNumber() { - return m_nLine; + return m_nLineNumber; } // --------------------------------------------------------------------- @@ -605,20 +726,26 @@ std::string WsjcppYamlParsebleLine::getComment() { // --------------------------------------------------------------------- +bool WsjcppYamlParsebleLine::hasComment() { + return m_bHasComment; +} + +// --------------------------------------------------------------------- + std::string WsjcppYamlParsebleLine::getName() { - return m_sName; + return m_sTagName; } // --------------------------------------------------------------------- -bool WsjcppYamlParsebleLine::hasNameDoubleQuotes() { - return m_bNameHasQuotes; +WsjcppYamlQuotes WsjcppYamlParsebleLine::getNameQuotes() { + return m_nNameQuotes; } // --------------------------------------------------------------------- bool WsjcppYamlParsebleLine::isEmptyName() { - return m_sName.length() == 0; + return m_sTagName.length() == 0; } // --------------------------------------------------------------------- @@ -629,8 +756,8 @@ std::string WsjcppYamlParsebleLine::getValue() { // --------------------------------------------------------------------- -bool WsjcppYamlParsebleLine::hasValueDoubleQuotes() { - return m_bValueHasQuotes; +WsjcppYamlQuotes WsjcppYamlParsebleLine::getValueQuotes() { + return m_nValueQuotes; } // --------------------------------------------------------------------- @@ -641,68 +768,115 @@ bool WsjcppYamlParsebleLine::isEmptyValue() { // --------------------------------------------------------------------- -void WsjcppYamlParsebleLine::parseLine(const std::string &sLine) { +bool WsjcppYamlParsebleLine::isEmptyLine() { + return m_bEmptyLine; +} + +// --------------------------------------------------------------------- + +enum WsjcppYamlParserLineStates { + WSJCPP_YAML_PARSER_LINE_STATE_NO, + WSJCPP_YAML_PARSER_LINE_STATE_VALUE, + WSJCPP_YAML_PARSER_LINE_STATE_COMMENT, + WSJCPP_YAML_PARSER_LINE_STATE_STRING_DOUBLE_QUOTES, + WSJCPP_YAML_PARSER_LINE_STATE_STRING_SINGLE_QUOTES, + WSJCPP_YAML_PARSER_LINE_STATE_ESCAPING_DOUBLE_QUOTES, + WSJCPP_YAML_PARSER_LINE_STATE_ESCAPING_SINGLE_QUOTES +}; + +bool WsjcppYamlParsebleLine::parseLine(const std::string &sLine, std::string &sError) { // reset variables m_bArrayItem = false; m_sPrefix = ""; m_sComment = ""; - m_sName = ""; + m_sTagName = ""; m_sValue = ""; - m_bNameHasQuotes = false; - m_bValueHasQuotes = false; + m_bHasComment = false; + m_nNameQuotes = WSJCPP_YAML_QUOTES_NONE; + m_nValueQuotes = WSJCPP_YAML_QUOTES_NONE; + m_bEmptyLine = false; + std::string sLineTrim = sLine; + sLineTrim = WsjcppCore::trim(sLineTrim); + if (sLineTrim.length() == 0) { + m_bEmptyLine = true; + return true; + } - WsjcppYamlParserLineStates state = WsjcppYamlParserLineStates::NO; + WsjcppYamlParserLineStates state = WSJCPP_YAML_PARSER_LINE_STATE_NO; for (int i = 0; i < sLine.length(); i++) { char c = sLine[i]; - if ((c == ' ' || c == '\t') && state == WsjcppYamlParserLineStates::NO) { + if ((c == ' ' || c == '\t') && state == WSJCPP_YAML_PARSER_LINE_STATE_NO) { m_sPrefix += c; - } else if (c == '#' && (state == WsjcppYamlParserLineStates::NO || state == WsjcppYamlParserLineStates::VALUE)) { - state = WsjcppYamlParserLineStates::COMMENT; - } else if (state == WsjcppYamlParserLineStates::COMMENT) { + } else if (c == '#' && (state == WSJCPP_YAML_PARSER_LINE_STATE_NO || state == WSJCPP_YAML_PARSER_LINE_STATE_VALUE)) { + state = WSJCPP_YAML_PARSER_LINE_STATE_COMMENT; + m_bHasComment = true; + } else if (state == WSJCPP_YAML_PARSER_LINE_STATE_COMMENT) { if (c != '\r') { m_sComment += c; } - } else if (c == '-' && state == WsjcppYamlParserLineStates::NO) { + } else if (c == '-' && state == WSJCPP_YAML_PARSER_LINE_STATE_NO) { m_bArrayItem = true; - state = WsjcppYamlParserLineStates::VALUE; - } else if ((c != ' ' && c != '\t') && state == WsjcppYamlParserLineStates::NO) { - state = WsjcppYamlParserLineStates::VALUE; + state = WSJCPP_YAML_PARSER_LINE_STATE_VALUE; + } else if ((c != ' ' && c != '\t') && state == WSJCPP_YAML_PARSER_LINE_STATE_NO) { + state = WSJCPP_YAML_PARSER_LINE_STATE_VALUE; m_sValue += c; if (c == '"') { - state = WsjcppYamlParserLineStates::STRING; + state = WSJCPP_YAML_PARSER_LINE_STATE_STRING_DOUBLE_QUOTES; + } + if (c == '\'') { + state = WSJCPP_YAML_PARSER_LINE_STATE_STRING_SINGLE_QUOTES; } - } else if (c == '"' && state == WsjcppYamlParserLineStates::VALUE) { - state = WsjcppYamlParserLineStates::STRING; + } else if (c == '"' && state == WSJCPP_YAML_PARSER_LINE_STATE_VALUE) { + state = WSJCPP_YAML_PARSER_LINE_STATE_STRING_DOUBLE_QUOTES; m_sValue += c; - } else if (c == '\\' && state == WsjcppYamlParserLineStates::STRING) { - state = WsjcppYamlParserLineStates::ESCAPING; + } else if (c == '\'' && state == WSJCPP_YAML_PARSER_LINE_STATE_VALUE) { + state = WSJCPP_YAML_PARSER_LINE_STATE_STRING_SINGLE_QUOTES; m_sValue += c; - } else if (state == WsjcppYamlParserLineStates::ESCAPING) { - state = WsjcppYamlParserLineStates::STRING; + } else if (c == '\\' && state == WSJCPP_YAML_PARSER_LINE_STATE_STRING_DOUBLE_QUOTES) { + state = WSJCPP_YAML_PARSER_LINE_STATE_ESCAPING_DOUBLE_QUOTES; m_sValue += c; - } else if (c == '"' && state == WsjcppYamlParserLineStates::STRING) { - state = WsjcppYamlParserLineStates::VALUE; + } else if (c == '\\' && state == WSJCPP_YAML_PARSER_LINE_STATE_STRING_SINGLE_QUOTES) { + state = WSJCPP_YAML_PARSER_LINE_STATE_ESCAPING_SINGLE_QUOTES; m_sValue += c; - } else if (c == ':' && state == WsjcppYamlParserLineStates::VALUE) { - if (m_sName.length() == 0) { - m_sName = m_sValue; + } else if (state == WSJCPP_YAML_PARSER_LINE_STATE_ESCAPING_DOUBLE_QUOTES) { + state = WSJCPP_YAML_PARSER_LINE_STATE_STRING_DOUBLE_QUOTES; + m_sValue += c; + } else if (state == WSJCPP_YAML_PARSER_LINE_STATE_ESCAPING_SINGLE_QUOTES) { + state = WSJCPP_YAML_PARSER_LINE_STATE_STRING_SINGLE_QUOTES; + m_sValue += c; + } else if (c == '"' && state == WSJCPP_YAML_PARSER_LINE_STATE_STRING_DOUBLE_QUOTES) { + state = WSJCPP_YAML_PARSER_LINE_STATE_VALUE; + m_sValue += c; + } else if (c == '\'' && state == WSJCPP_YAML_PARSER_LINE_STATE_STRING_SINGLE_QUOTES) { + state = WSJCPP_YAML_PARSER_LINE_STATE_VALUE; + m_sValue += c; + } else if (c == ':' && state == WSJCPP_YAML_PARSER_LINE_STATE_VALUE) { + if (m_sTagName.length() == 0 && this->canTagName(m_sValue)) { + m_sTagName = m_sValue; m_sValue = ""; // reset value it was param name } else { m_sValue += c; } - } else if (state == WsjcppYamlParserLineStates::STRING) { + } else if ( + state == WSJCPP_YAML_PARSER_LINE_STATE_STRING_DOUBLE_QUOTES + || state == WSJCPP_YAML_PARSER_LINE_STATE_STRING_SINGLE_QUOTES + ) { m_sValue += c; - } else if (state == WsjcppYamlParserLineStates::VALUE) { + } else if (state == WSJCPP_YAML_PARSER_LINE_STATE_VALUE) { m_sValue += c; } else { // skip } } - if (state == WsjcppYamlParserLineStates::STRING - || state == WsjcppYamlParserLineStates::ESCAPING + if ( + state == WSJCPP_YAML_PARSER_LINE_STATE_STRING_DOUBLE_QUOTES + || state == WSJCPP_YAML_PARSER_LINE_STATE_STRING_SINGLE_QUOTES + || state == WSJCPP_YAML_PARSER_LINE_STATE_ESCAPING_DOUBLE_QUOTES + || state == WSJCPP_YAML_PARSER_LINE_STATE_ESCAPING_SINGLE_QUOTES ) { - WsjcppLog::throw_err(TAG, "wrong format"); + sError = "Line has wrong format."; + return false; } // split name and value @@ -716,19 +890,63 @@ void WsjcppYamlParsebleLine::parseLine(const std::string &sLine) { } }*/ - WsjcppCore::trim(m_sName); - if (m_sName.length() > 0 && m_sName[0] == '"') { - m_bNameHasQuotes = true; - m_sName = removeStringDoubleQuotes(m_sName); + m_sTagName = WsjcppCore::trim(m_sTagName); + if (m_sTagName.length() > 0 && m_sTagName[0] == '"') { + m_nNameQuotes = WSJCPP_YAML_QUOTES_DOUBLE; + m_sTagName = removeStringDoubleQuotes(m_sTagName); + } + if (m_sTagName.length() > 0 && m_sTagName[0] == '\'') { + m_nNameQuotes = WSJCPP_YAML_QUOTES_SINGLE; + m_sTagName = removeStringSingleQuotes(m_sTagName); } - WsjcppCore::trim(m_sValue); + m_sValue = WsjcppCore::trim(m_sValue); if (m_sValue.length() > 0 && m_sValue[0] == '"') { - m_bValueHasQuotes = true; + m_nValueQuotes = WSJCPP_YAML_QUOTES_DOUBLE; m_sValue = removeStringDoubleQuotes(m_sValue); } + if (m_sValue.length() > 0 && m_sValue[0] == '\'') { + m_nValueQuotes = WSJCPP_YAML_QUOTES_SINGLE; + m_sValue = removeStringSingleQuotes(m_sValue); + } - WsjcppCore::trim(m_sComment); + m_sComment = WsjcppCore::trim(m_sComment); + + if (m_bArrayItem == false && m_sTagName.length() == 0 && m_sValue.length() > 0 ) { + sError = "Value of name can be empty only for array-item (line: " + sLine + ")"; + return false; + } + return true; +} + +// --------------------------------------------------------------------- + +bool WsjcppYamlParsebleLine::canTagName(const std::string &sVal) { + std::string sTrim = sVal; + sTrim = WsjcppCore::trim(sTrim); + int nLen = sTrim.length(); + if (nLen == 0) { + return false; + } + if (sTrim.length() > 0 && sTrim[0] == '"' && sTrim[nLen-1] == '"') { + return true; + } + if (sTrim.length() > 0 && sTrim[0] == '\'' && sTrim[nLen-1] == '\'') { + return true; + } + // check illegal char + for (int i = 0; i < nLen; i++) { + char c = sTrim[i]; + if ( + c != '-' && c != '_' + && (c < '0' || c > '9') + && (c < 'a' || c > 'z') + && (c < 'A' || c > 'Z') + ) { + return false; + } + } + return true; } // --------------------------------------------------------------------- @@ -760,22 +978,241 @@ std::string WsjcppYamlParsebleLine::removeStringDoubleQuotes(const std::string & return sRet; } + // --------------------------------------------------------------------- -// WsjcppYamlParserStatus -void WsjcppYamlParserStatus::logUnknownLine(const std::string &sPrefix) { - WsjcppLog::warn(sPrefix, "Unknown line (" + std::to_string(placeInFile.getNumberOfLine()) + "): '" + placeInFile.getLine() + "' \n" - + "Current Intent: " + std::to_string(nIntent) + "\n" - + "Current Item(line: " + std::to_string(pCurItem->getPlaceInFile().getNumberOfLine()) + "): '" + pCurItem->getPlaceInFile().getLine() + "'" - + "Current Item(filename: " + pCurItem->getPlaceInFile().getFilename() + "'" - ); +std::string WsjcppYamlParsebleLine::removeStringSingleQuotes(const std::string &sValue) { + if (sValue.size() > 0 && sValue[0] != '\'') { + return sValue; + } + int nStartPos = 1; + int nEndPos = sValue.size()-1; + std::string sRet = ""; + bool bEscape = false; + for (int i = nStartPos; i < nEndPos; i++) { + char c = sValue[i]; + if (bEscape) { + if (c == 'n') { + sRet += '\n'; + } else if (c == 'r') { + sRet += '\r'; + } else { + sRet += c; + } + } else if (c == '\\') { + bEscape = true; + } else { + sRet += c; + } + } + return sRet; +} + +// --------------------------------------------------------------------- +// WsjcppYamlCursor + +WsjcppYamlCursor::WsjcppYamlCursor(WsjcppYamlNode *pCurrentNode) { + m_pCurrentNode = pCurrentNode; + TAG = "WsjcppYamlCursor"; +} + +// --------------------------------------------------------------------- + +WsjcppYamlCursor::WsjcppYamlCursor() +: WsjcppYamlCursor(nullptr) { + // nothing +} + +// --------------------------------------------------------------------- + +WsjcppYamlCursor::~WsjcppYamlCursor() { + // do nothing +} + +// --------------------------------------------------------------------- + +bool WsjcppYamlCursor::isNull() const { + return m_pCurrentNode == nullptr; +} + +// --------------------------------------------------------------------- + +bool WsjcppYamlCursor::isUndefined() const { + return m_pCurrentNode != nullptr && m_pCurrentNode->isUndefined(); +} + +// --------------------------------------------------------------------- + +bool WsjcppYamlCursor::isValue() const { + return m_pCurrentNode != nullptr && m_pCurrentNode->isValue(); +} + +// --------------------------------------------------------------------- + +bool WsjcppYamlCursor::isArray() const { + return m_pCurrentNode != nullptr && m_pCurrentNode->isArray(); +} + +// --------------------------------------------------------------------- + +size_t WsjcppYamlCursor::size() const { + return m_pCurrentNode != nullptr && m_pCurrentNode->isArray() ? m_pCurrentNode->getLength() : -1; +} + +// --------------------------------------------------------------------- + +bool WsjcppYamlCursor::isMap() const { + return m_pCurrentNode != nullptr && m_pCurrentNode->isMap(); +} + +// --------------------------------------------------------------------- + +std::vector WsjcppYamlCursor::keys() const { + return m_pCurrentNode != nullptr && m_pCurrentNode->isMap() ? m_pCurrentNode->getKeys() : std::vector(); +} + +// --------------------------------------------------------------------- + +bool WsjcppYamlCursor::hasKey(const std::string &sKey) const { + return m_pCurrentNode != nullptr && m_pCurrentNode->isMap() && m_pCurrentNode->hasElement(sKey); +} + +// --------------------------------------------------------------------- + +// WsjcppYamlCursor &WsjcppYamlCursor::set(const std::string &sName, const std::string &sValue) { +// return *this; +// } +// +// // --------------------------------------------------------------------- +// +// WsjcppYamlCursor &WsjcppYamlCursor::set(const std::string &sName, int nValue) { +// return *this; +// } +// +// // --------------------------------------------------------------------- +// +// WsjcppYamlCursor &WsjcppYamlCursor::set(const std::string &sName, bool bValue) { +// return *this; +// } +// +// // --------------------------------------------------------------------- +// +// WsjcppYamlCursor &WsjcppYamlCursor::remove(const std::string &sKey) { +// return *this; +// } + +// --------------------------------------------------------------------- + +std::string WsjcppYamlCursor::comment() { + return m_pCurrentNode != nullptr ? m_pCurrentNode->getComment() : ""; +} + +// --------------------------------------------------------------------- + +WsjcppYamlCursor &WsjcppYamlCursor::comment(const std::string& sComment) { + if (m_pCurrentNode != nullptr) { + m_pCurrentNode->setComment(sComment); + } + return *this; +} + +// --------------------------------------------------------------------- + +std::string WsjcppYamlCursor::valStr() { + return m_pCurrentNode != nullptr ? m_pCurrentNode->getValue() : ""; +} + +// --------------------------------------------------------------------- + +WsjcppYamlCursor &WsjcppYamlCursor::val(const std::string &sValue) { + if (m_pCurrentNode != nullptr) { + m_pCurrentNode->setValue(sValue); // TODO reserch need or not add quotes + } + return *this; +} + +// --------------------------------------------------------------------- + +WsjcppYamlCursor &WsjcppYamlCursor::val(const char *sValue) { + this->val(std::string(sValue)); + return *this; +} + +// --------------------------------------------------------------------- + +int WsjcppYamlCursor::valInt() { + if (m_pCurrentNode != nullptr) { + std::string sValue = m_pCurrentNode->getValue(); + sValue = WsjcppCore::toLower(sValue); + int nValue = std::strtol(sValue.c_str(), nullptr, 10); + if (std::to_string(nValue) != sValue) { + throw std::runtime_error(TAG + ": valInt, Element must be int but have a string" + m_pCurrentNode->getForLogFormat()); + } + return nValue; + } + return 0; +} + +// --------------------------------------------------------------------- + +WsjcppYamlCursor &WsjcppYamlCursor::val(int nValue) { + if (m_pCurrentNode != nullptr) { + m_pCurrentNode->setValue(std::to_string(nValue)); + } + return *this; +} + +// --------------------------------------------------------------------- + +bool WsjcppYamlCursor::valBool() { + if (m_pCurrentNode != nullptr) { + std::string sValue = m_pCurrentNode->getValue(); + sValue = WsjcppCore::toLower(sValue); + if (sValue == "yes" || sValue == "true") { + return true; + } else if (sValue == "no" || sValue == "false") { + return false; + } else { + throw std::runtime_error(TAG + ": valBool, Element must be bool expected with ignore case like" + " 'yes', 'no', 'true', 'false' for " + m_pCurrentNode->getForLogFormat()); + } + } + return false; +} + +// --------------------------------------------------------------------- + +WsjcppYamlCursor &WsjcppYamlCursor::val(bool bValue) { + if (m_pCurrentNode != nullptr) { + m_pCurrentNode->setValue((bValue ? "yes" : "no")); + } + return *this; +} + +// --------------------------------------------------------------------- + +WsjcppYamlCursor WsjcppYamlCursor::operator[](int idx) const { + if (m_pCurrentNode != nullptr && m_pCurrentNode->isArray() && idx < m_pCurrentNode->getLength() && idx >= 0) { + return WsjcppYamlCursor(m_pCurrentNode->getElement(idx)); + } + return WsjcppYamlCursor(); +} + +// --------------------------------------------------------------------- + +WsjcppYamlCursor WsjcppYamlCursor::operator[](const std::string &sName) const { + if (m_pCurrentNode != nullptr && m_pCurrentNode->isMap() && m_pCurrentNode->hasElement(sName)) { + return WsjcppYamlCursor(m_pCurrentNode->getElement(sName)); + } + return WsjcppYamlCursor(); } // --------------------------------------------------------------------- // WsjcppYaml WsjcppYaml::WsjcppYaml() { - m_pRoot = new WsjcppYamlItem(nullptr, WsjcppYamlPlaceInFile(), WSJCPP_YAML_ITEM_MAP); + m_pRoot = new WsjcppYamlNode(nullptr, WsjcppYamlPlaceInFile(), WSJCPP_YAML_NODE_MAP); + TAG = "WsjcppYaml"; } // --------------------------------------------------------------------- @@ -786,12 +1223,19 @@ WsjcppYaml::~WsjcppYaml() { // --------------------------------------------------------------------- -bool WsjcppYaml::loadFromFile(const std::string &sFileName) { +void WsjcppYaml::clear() { + delete m_pRoot; + m_pRoot = nullptr; +} + +// --------------------------------------------------------------------- + +bool WsjcppYaml::loadFromFile(const std::string &sFileName, std::string &sError) { std::string sTextContent; if (!WsjcppCore::readTextFile(sFileName, sTextContent)) { return false; } - return parse(sFileName, sTextContent); + return parse(sFileName, sTextContent, sError); } // --------------------------------------------------------------------- @@ -806,27 +1250,39 @@ bool WsjcppYaml::saveToFile(const std::string &sFileName) { // --------------------------------------------------------------------- -bool WsjcppYaml::loadFromString(const std::string &sBuffer) { - return false; +bool WsjcppYaml::loadFromString(const std::string &sBufferName, const std::string &sBuffer, std::string &sError) { + return parse(sBufferName, sBuffer, sError); } // --------------------------------------------------------------------- -bool WsjcppYaml::loadFromString(std::string &sBuffer) { - return parse("", sBuffer); +bool WsjcppYaml::saveToString(std::string &sBuffer) { + sBuffer = m_pRoot->toString(); + return true; } // --------------------------------------------------------------------- -bool WsjcppYaml::saveToString(std::string &sBuffer) { // TODO move to WsjcppCore - sBuffer = m_pRoot->toString(); - return true; +WsjcppYamlNode *WsjcppYaml::getRoot() { + return m_pRoot; } // --------------------------------------------------------------------- -WsjcppYamlItem *WsjcppYaml::getRoot() { - return m_pRoot; +WsjcppYamlCursor WsjcppYaml::getCursor() const { + return WsjcppYamlCursor(m_pRoot); +} + +// --------------------------------------------------------------------- + +WsjcppYamlCursor WsjcppYaml::operator[](int idx) const { + return this->getCursor()[idx]; +} + +// --------------------------------------------------------------------- + +WsjcppYamlCursor WsjcppYaml::operator[](const std::string &sName) const { + return this->getCursor()[sName]; } // --------------------------------------------------------------------- @@ -852,71 +1308,123 @@ std::vector WsjcppYaml::splitToLines(const std::string &sBuffer) { // --------------------------------------------------------------------- -bool WsjcppYaml::parse(const std::string &sFileName, const std::string &sBuffer) { +bool WsjcppYaml::parse(const std::string &sFileName, const std::string &sBuffer, std::string &sError) { + this->clear(); + if (m_pRoot == nullptr) { + m_pRoot = new WsjcppYamlNode(nullptr, WsjcppYamlPlaceInFile(), WSJCPP_YAML_NODE_MAP); + } + std::vector vLines = this->splitToLines(sBuffer); - WsjcppYamlParserStatus st; - st.pCurItem = m_pRoot; // TODO recreate again new root element - st.placeInFile.setFilename(sFileName); - st.nIntent = 0; - m_pRoot->setPlaceInFile(st.placeInFile); + m_pParseCurrentParentNode = m_pRoot; + m_parsePlaceInFile.setFilename(sFileName); + m_vStackDiffNodeIntents.clear(); + m_vStackDiffNodeIntents.push_back(0); + m_nParseCurrentIntent = 0; + m_pRoot->setPlaceInFile(m_parsePlaceInFile); for (int nLine = 0; nLine < vLines.size(); nLine++) { - st.placeInFile.setLine(vLines[nLine]); - // WsjcppLog::info(TAG, "Line(" + std::to_string(nLine) + ") '" + st.sLine + "'"); - st.placeInFile.setNumberOfLine(nLine); - st.line = WsjcppYamlParsebleLine(nLine); - st.line.parseLine(st.placeInFile.getLine()); + m_parsePlaceInFile.setLine(vLines[nLine]); + m_parsePlaceInFile.setNumberOfLine(nLine); + m_parseLine = WsjcppYamlParsebleLine(nLine); + if (!m_parseLine.parseLine(m_parsePlaceInFile.getLine(), sError)) { + return false; + } - bool isEmptyName = st.line.isEmptyName(); - bool isEmptyValue = st.line.isEmptyValue(); - bool isArrayItem = st.line.isArrayItem(); - int nLineIntent = st.line.getIntent(); - int nDiffIntent = nLineIntent - st.nIntent; - - // TODO check comment - /*if (isEmptyName && isEmptyValue && isArrayItem) { - continue; - }*/ - - while (nDiffIntent < 0) { - st.pCurItem = st.pCurItem->getParent(); - st.nIntent = st.nIntent - 2; - nDiffIntent = nLineIntent - st.nIntent; - if (st.pCurItem == nullptr) { - WsjcppLog::throw_err(TAG, "cur item is nullptr"); - } + bool isEmptyName = m_parseLine.isEmptyName(); + bool isEmptyValue = m_parseLine.isEmptyValue(); + bool isArrayItem = m_parseLine.isArrayItem(); + int nLineIntent = m_parseLine.getIntent(); + int nDiffIntent = nLineIntent - m_nParseCurrentIntent; + + if (nDiffIntent > 0) { + m_vStackDiffNodeIntents.push_back(nDiffIntent); + m_nParseCurrentIntent = m_parseLine.getIntent(); } - if (nDiffIntent == 0) { - if (st.line.isEmptyName()) { - if ( ! isEmptyValue && isArrayItem) { - process_sameIntent_emptyName_hasValue_arrayItem(st); - } else if (! isEmptyValue && ! isArrayItem) { - process_sameIntent_emptyName_hasValue_noArrayItem(st); - } else if (isEmptyValue && isArrayItem) { - process_sameIntent_emptyName_emptyValue_arrayItem(st); - } else if (isEmptyValue && ! isArrayItem) { - process_sameIntent_emptyName_emptyValue_noArrayItem(st); + if (m_parseLine.isEmptyLine()) { + if (m_pParseCurrentParentNode != nullptr) { + if (m_pParseCurrentParentNode->isArray() || m_pParseCurrentParentNode->isMap() || m_pParseCurrentParentNode->isUndefined()) { + WsjcppYamlNode *pNode = new WsjcppYamlNode( + m_pParseCurrentParentNode, m_parsePlaceInFile, + WSJCPP_YAML_NODE_EMPTY + ); + pNode->setNodeIntents(m_vStackDiffNodeIntents); + m_pParseCurrentParentNode->appendElement(pNode); + } else if (m_pParseCurrentParentNode->getParent() != nullptr && (m_pParseCurrentParentNode->getParent()->isArray() || m_pParseCurrentParentNode->getParent()->isMap())) { + WsjcppYamlNode *pNode = new WsjcppYamlNode( + m_pParseCurrentParentNode->getParent(), m_parsePlaceInFile, + WSJCPP_YAML_NODE_EMPTY + ); + pNode->setNodeIntents(m_vStackDiffNodeIntents); + m_pParseCurrentParentNode->getParent()->appendElement(pNode); } else { - st.logUnknownLine(TAG); - } - } else if ( ! st.line.isEmptyName()) { - if ( ! isEmptyValue && isArrayItem) { - process_sameIntent_hasName_hasValue_arrayItem(st); - } else if ( ! isEmptyValue && ! isArrayItem) { - process_sameIntent_hasName_hasValue_noArrayItem(st); - } else if (isEmptyValue && isArrayItem) { - process_sameIntent_hasName_emptyValue_arrayItem(st); - } else if (isEmptyValue && ! isArrayItem) { - process_sameIntent_hasName_emptyValue_noArrayItem(st); - } else { - st.logUnknownLine(TAG); + throw std::runtime_error(TAG + ": Empty element can be added only to map or to array"); } + } + continue; + } + + // fast switch to root + if (nDiffIntent < 0 && m_parseLine.getIntent() == 0) { + nDiffIntent = 0; + m_nParseCurrentIntent = m_parseLine.getIntent(); + m_pParseCurrentParentNode = m_pRoot; + m_vStackDiffNodeIntents.clear(); + m_vStackDiffNodeIntents.push_back(0); + } + + // switch to parent + while (nDiffIntent < 0 && m_nParseCurrentIntent != m_parseLine.getIntent()) { + if (m_pParseCurrentParentNode == nullptr) { + sError = "Current node is nullptr, line: " + std::to_string(nLine); + return false; + } + if (m_pParseCurrentParentNode->getParent() == nullptr) { + sError = "Parent of current node is nullptr, line: " + std::to_string(nLine); + return false; + } + m_nParseCurrentIntent = m_nParseCurrentIntent - m_vStackDiffNodeIntents.back(); + m_vStackDiffNodeIntents.pop_back(); + m_pParseCurrentParentNode = m_pParseCurrentParentNode->getParent(); + if (m_nParseCurrentIntent < m_parseLine.getIntent()) { + sError = "Wrong intent, expected " + "'" + std::to_string(m_parseLine.getIntent()) + "'," + " but got '" + + " in line: (" + sFileName + ":" + std::to_string(nLine) + ")"; + return false; + } + + if (m_nParseCurrentIntent == m_parseLine.getIntent()) { + break; + } + } + + if (m_parseLine.isEmptyName()) { + if ( ! isEmptyValue && isArrayItem) { + process_emptyName_hasValue_arrayItem(); + } else if (! isEmptyValue && ! isArrayItem) { + process_emptyName_hasValue_noArrayItem(); + } else if (isEmptyValue && isArrayItem) { + process_emptyName_emptyValue_arrayItem(); + } else if (isEmptyValue && ! isArrayItem) { + process_emptyName_emptyValue_noArrayItem(); + } else { + logUnknownParseLine(); + } + } else if ( ! m_parseLine.isEmptyName()) { + if ( ! isEmptyValue && isArrayItem) { + process_hasName_hasValue_arrayItem(); + } else if ( ! isEmptyValue && ! isArrayItem) { + process_hasName_hasValue_noArrayItem(); + } else if (isEmptyValue && isArrayItem) { + process_hasName_emptyValue_arrayItem(); + } else if (isEmptyValue && ! isArrayItem) { + process_hasName_emptyValue_noArrayItem(); } else { - st.logUnknownLine(TAG); + logUnknownParseLine(); } } else { - st.logUnknownLine(TAG); + logUnknownParseLine(); } } return true; @@ -924,119 +1432,159 @@ bool WsjcppYaml::parse(const std::string &sFileName, const std::string &sBuffer) // --------------------------------------------------------------------- -void WsjcppYaml::process_sameIntent_hasName_emptyValue_arrayItem(WsjcppYamlParserStatus &st) { - st.logUnknownLine("process_sameIntent_hasName_emptyValue_arrayItem"); +void WsjcppYaml::process_hasName_emptyValue_arrayItem() { + WsjcppLog::warn(TAG, "process_hasName_emptyValue_arrayItem"); + this->logUnknownParseLine(); } // --------------------------------------------------------------------- -void WsjcppYaml::process_sameIntent_hasName_emptyValue_noArrayItem(WsjcppYamlParserStatus &st) { - WsjcppYamlItem *pItem = new WsjcppYamlItem( - st.pCurItem, st.placeInFile, - WsjcppYamlItemType::WSJCPP_YAML_ITEM_UNDEFINED +void WsjcppYaml::process_hasName_emptyValue_noArrayItem() { + if (m_parseLine.getIntent() == m_pParseCurrentParentNode->getNodeIntent()) { + if (m_pParseCurrentParentNode->getParent() != nullptr) { + m_pParseCurrentParentNode = m_pParseCurrentParentNode->getParent(); + } + } + // std::cout << "process_hasName_emptyValue_noArrayItem " << std::endl; + WsjcppYamlNode *pNode = new WsjcppYamlNode( + m_pParseCurrentParentNode, m_parsePlaceInFile, + WSJCPP_YAML_NODE_UNDEFINED ); - if (st.line.hasValueDoubleQuotes()) { - pItem->doValue(); - pItem->setValue(st.line.getValue(), st.line.hasValueDoubleQuotes()); + if (m_parseLine.getValueQuotes() != WSJCPP_YAML_QUOTES_NONE) { + pNode->doValue(); + pNode->setValue(m_parseLine.getValue(), m_parseLine.getValueQuotes()); + } + int nDiffIntent = m_parseLine.getIntent() - m_nParseCurrentIntent; + pNode->setName(m_parseLine.getName(), m_parseLine.getNameQuotes()); + pNode->setComment(m_parseLine.getComment()); + pNode->setNodeIntents(m_vStackDiffNodeIntents); + // std::cout << "current node [" << m_vStackDiffNodeIntents.back() << "]" << std::endl; + +/* if (nDiffIntent == 0 && m_pParseCurrentParentNode->isUndefined()) { + std::cout << "shit nDiffIntent = " << nDiffIntent << std::endl; + std::cout << "shit m_pParseCurrentParentNode->getName() = " << m_pParseCurrentParentNode->getName() << std::endl; + if (m_pParseCurrentParentNode->getParent() != nullptr) { + std::cout << "shit " + << " {" << m_pParseCurrentParentNode->getPlaceInFile().getLine() << "} " + << " {" << m_parsePlaceInFile.getLine() << "} " << std::endl; + } } - pItem->setName(st.line.getName(), st.line.hasNameDoubleQuotes()); - pItem->setComment(st.line.getComment()); - st.pCurItem->setElement(st.line.getName(), pItem); - st.pCurItem = pItem; - st.nIntent = st.nIntent + 2; +*/ + m_pParseCurrentParentNode->setElement(m_parseLine.getName(), pNode); + m_pParseCurrentParentNode = pNode; } // --------------------------------------------------------------------- -void WsjcppYaml::process_sameIntent_hasName_hasValue_arrayItem(WsjcppYamlParserStatus &st) { - if (st.pCurItem->isUndefined()) { - st.pCurItem->doArray(); +void WsjcppYaml::process_hasName_hasValue_arrayItem() { + // std::cout << "process_hasName_hasValue_arrayItem " << std::endl; + if (m_pParseCurrentParentNode->isUndefined()) { + m_pParseCurrentParentNode->doArray(); } - WsjcppYamlItem *pMapItem = new WsjcppYamlItem( - st.pCurItem, st.placeInFile, - WsjcppYamlItemType::WSJCPP_YAML_ITEM_MAP + WsjcppYamlNode *pMapItem = new WsjcppYamlNode( + m_pParseCurrentParentNode, m_parsePlaceInFile, + WSJCPP_YAML_NODE_MAP ); - st.pCurItem->appendElement(pMapItem); - st.pCurItem = pMapItem; - st.nIntent = st.nIntent + 2; + m_pParseCurrentParentNode->appendElement(pMapItem); + m_pParseCurrentParentNode = pMapItem; + pMapItem->setNodeIntents(m_vStackDiffNodeIntents); - WsjcppYamlItem *pItem = new WsjcppYamlItem( - st.pCurItem, st.placeInFile, - WsjcppYamlItemType::WSJCPP_YAML_ITEM_VALUE + WsjcppYamlNode *pNode = new WsjcppYamlNode( + m_pParseCurrentParentNode, m_parsePlaceInFile, + WSJCPP_YAML_NODE_VALUE ); - pItem->setComment(st.line.getComment()); - pItem->setValue(st.line.getValue(), st.line.hasValueDoubleQuotes()); - pItem->setName(st.line.getName(), st.line.hasNameDoubleQuotes()); - pMapItem->setElement(st.line.getName(), pItem); - st.pCurItem = pItem; - st.nIntent = st.nIntent + 2; + pNode->setComment(m_parseLine.getComment()); + pNode->setValue(m_parseLine.getValue(), m_parseLine.getValueQuotes()); + pNode->setName(m_parseLine.getName(), m_parseLine.getNameQuotes()); + pMapItem->setElement(m_parseLine.getName(), pNode); + + // next intents must be for map + m_vStackDiffNodeIntents.push_back(2); + m_nParseCurrentIntent += 2; } // --------------------------------------------------------------------- -void WsjcppYaml::process_sameIntent_hasName_hasValue_noArrayItem(WsjcppYamlParserStatus &st) { - WsjcppYamlItem *pItem = new WsjcppYamlItem( - st.pCurItem, st.placeInFile, - WsjcppYamlItemType::WSJCPP_YAML_ITEM_VALUE +void WsjcppYaml::process_hasName_hasValue_noArrayItem() { + WsjcppYamlNode *pNode = new WsjcppYamlNode( + m_pParseCurrentParentNode, m_parsePlaceInFile, + WSJCPP_YAML_NODE_VALUE ); - pItem->setComment(st.line.getComment()); - pItem->setValue(st.line.getValue(), st.line.hasValueDoubleQuotes()); - pItem->setName(st.line.getName(), st.line.hasNameDoubleQuotes()); - st.pCurItem->setElement(st.line.getName(), pItem); - st.pCurItem = pItem; - st.nIntent = st.nIntent + 2; + // std::cout << "m_parseLine.getName(): " << m_parseLine.getName() << std::endl; + // std::cout << "m_pParseCurrentParentNode: " << m_pParseCurrentParentNode->getPlaceInFile().getLine() << std::endl; + pNode->setComment(m_parseLine.getComment()); + pNode->setValue(m_parseLine.getValue(), m_parseLine.getValueQuotes()); + pNode->setName(m_parseLine.getName(), m_parseLine.getNameQuotes()); + pNode->setNodeIntents(m_vStackDiffNodeIntents); + m_pParseCurrentParentNode->setElement(m_parseLine.getName(), pNode); + + // m_pParseCurrentParentNode = pItem; } // --------------------------------------------------------------------- -void WsjcppYaml::process_sameIntent_emptyName_hasValue_arrayItem(WsjcppYamlParserStatus &st) { - if (st.pCurItem->isUndefined()) { - st.pCurItem->doArray(); +void WsjcppYaml::process_emptyName_hasValue_arrayItem() { + // std::cout << "process_emptyName_hasValue_arrayItem " << std::endl; + if (m_pParseCurrentParentNode->isUndefined()) { + m_pParseCurrentParentNode->doArray(); } - WsjcppYamlItem *pItem = new WsjcppYamlItem( - st.pCurItem, st.placeInFile, - WsjcppYamlItemType::WSJCPP_YAML_ITEM_VALUE + WsjcppYamlNode *pNode = new WsjcppYamlNode( + m_pParseCurrentParentNode, m_parsePlaceInFile, + WSJCPP_YAML_NODE_VALUE ); - pItem->setComment(st.line.getComment()); - pItem->setValue(st.line.getValue(), st.line.hasValueDoubleQuotes()); - st.pCurItem->appendElement(pItem); - st.pCurItem = pItem; - st.nIntent = st.nIntent + 2; + pNode->setComment(m_parseLine.getComment()); + pNode->setValue(m_parseLine.getValue(), m_parseLine.getValueQuotes()); + m_pParseCurrentParentNode->appendElement(pNode); + // m_pParseCurrentParentNode = pNode; + pNode->setNodeIntents(m_vStackDiffNodeIntents); } // --------------------------------------------------------------------- -void WsjcppYaml::process_sameIntent_emptyName_hasValue_noArrayItem(WsjcppYamlParserStatus &st) { - st.logUnknownLine("TODO process_sameIntent_emptyName_hasValue_noArrayItem"); +void WsjcppYaml::process_emptyName_hasValue_noArrayItem() { + WsjcppLog::warn(TAG, "TODO process_emptyName_hasValue_noArrayItem"); + this->logUnknownParseLine(); + } // --------------------------------------------------------------------- -void WsjcppYaml::process_sameIntent_emptyName_emptyValue_arrayItem(WsjcppYamlParserStatus &st) { - if (st.pCurItem->isUndefined()) { - st.pCurItem->doArray(); +void WsjcppYaml::process_emptyName_emptyValue_arrayItem() { + if (m_pParseCurrentParentNode->isUndefined()) { + m_pParseCurrentParentNode->doArray(); } - WsjcppYamlItem *pItem = new WsjcppYamlItem( - st.pCurItem, st.placeInFile, - WsjcppYamlItemType::WSJCPP_YAML_ITEM_VALUE + WsjcppYamlNode *pNode = new WsjcppYamlNode( + m_pParseCurrentParentNode, m_parsePlaceInFile, + WSJCPP_YAML_NODE_VALUE ); - pItem->setComment(st.line.getComment()); - pItem->setValue(st.line.getValue(), st.line.hasValueDoubleQuotes()); - st.pCurItem->appendElement(pItem); - st.pCurItem = pItem; - st.nIntent = st.nIntent + 2; + pNode->setComment(m_parseLine.getComment()); + pNode->setValue(m_parseLine.getValue(), m_parseLine.getValueQuotes()); + pNode->setNodeIntents(m_vStackDiffNodeIntents); + m_pParseCurrentParentNode->appendElement(pNode); } // --------------------------------------------------------------------- -void WsjcppYaml::process_sameIntent_emptyName_emptyValue_noArrayItem(WsjcppYamlParserStatus &st) { - WsjcppYamlItem *pItem = new WsjcppYamlItem( - st.pCurItem, st.placeInFile, - WsjcppYamlItemType::WSJCPP_YAML_ITEM_EMPTY +void WsjcppYaml::process_emptyName_emptyValue_noArrayItem() { + // std::cout << "process_emptyName_emptyValue_noArrayItem " << std::endl; + WsjcppYamlNode *pNode = new WsjcppYamlNode( + m_pParseCurrentParentNode, m_parsePlaceInFile, + WSJCPP_YAML_NODE_EMPTY ); - pItem->setComment(st.line.getComment()); - st.pCurItem->appendElement(pItem); + pNode->setComment(m_parseLine.getComment()); + pNode->setNodeIntents(m_vStackDiffNodeIntents); + m_pParseCurrentParentNode->appendElement(pNode); } // --------------------------------------------------------------------- +void WsjcppYaml::logUnknownParseLine() { + WsjcppLog::warn(TAG, "\n" + " error:\n" + " desc: \"unknown_line\"\n" + " line_number: " + std::to_string(m_pParseCurrentParentNode->getPlaceInFile().getNumberOfLine()) + "\n" + " line: \"" + m_parsePlaceInFile.getLine() + "\"\n" + " intent: " + std::to_string(m_nParseCurrentIntent) + "\n" + " filename: \"" + m_pParseCurrentParentNode->getPlaceInFile().getFilename() + "\"" + ); +} \ No newline at end of file diff --git a/src/wsjcpp_yaml.h b/src/wsjcpp_yaml.h index 445e328..215f394 100644 --- a/src/wsjcpp_yaml.h +++ b/src/wsjcpp_yaml.h @@ -11,12 +11,12 @@ // --------------------------------------------------------------------- -enum WsjcppYamlItemType { - WSJCPP_YAML_ITEM_UNDEFINED, - WSJCPP_YAML_ITEM_EMPTY, - WSJCPP_YAML_ITEM_ARRAY, - WSJCPP_YAML_ITEM_MAP, - WSJCPP_YAML_ITEM_VALUE +enum WsjcppYamlNodeType { + WSJCPP_YAML_NODE_UNDEFINED = 0, + WSJCPP_YAML_NODE_EMPTY = 1, + WSJCPP_YAML_NODE_ARRAY = 2, + WSJCPP_YAML_NODE_MAP = 3, + WSJCPP_YAML_NODE_VALUE = 4 }; // --------------------------------------------------------------------- @@ -42,6 +42,15 @@ class WsjcppYamlPlaceInFile { std::string m_sLine; }; +// --------------------------------------------------------------------- +// WsjcppYamlQuotes + +enum WsjcppYamlQuotes { + WSJCPP_YAML_QUOTES_NONE, + WSJCPP_YAML_QUOTES_DOUBLE, + WSJCPP_YAML_QUOTES_SINGLE +}; + // --------------------------------------------------------------------- /*! \brief Class for keep data of yaml node @@ -49,15 +58,15 @@ class WsjcppYamlPlaceInFile { Basic class for yaml tree */ -class WsjcppYamlItem { // TODO: rename to node +class WsjcppYamlNode { public: - WsjcppYamlItem( - WsjcppYamlItem *pParent, + WsjcppYamlNode( + WsjcppYamlNode *pParent, const WsjcppYamlPlaceInFile &placeInFile, - WsjcppYamlItemType nItemType + WsjcppYamlNodeType nItemType ); - ~WsjcppYamlItem(); - WsjcppYamlItem *getParent(); + ~WsjcppYamlNode(); + WsjcppYamlNode *getParent(); WsjcppYamlPlaceInFile getPlaceInFile(); void setPlaceInFile(const WsjcppYamlPlaceInFile &placeInFile); @@ -65,9 +74,9 @@ class WsjcppYamlItem { // TODO: rename to node void setComment(const std::string &sComment); std::string getComment(); - void setName(const std::string &sName, bool bHasQuotes); + void setName(const std::string &sName, WsjcppYamlQuotes nNameQuotes = WSJCPP_YAML_QUOTES_NONE); std::string getName(); - bool hasNameDoubleQuotes(); + WsjcppYamlQuotes getNameQuotes(); bool isEmpty(); void doEmpty(); @@ -79,57 +88,61 @@ class WsjcppYamlItem { // TODO: rename to node bool isMap(); bool hasElement(const std::string &sName); - WsjcppYamlItem *getElement(const std::string &sName); - bool setElement(const std::string &sName, WsjcppYamlItem *pItem); + WsjcppYamlNode *getElement(const std::string &sName); + bool setElement(const std::string &sName, WsjcppYamlNode *pItem); bool removeElement(const std::string &sName); std::vector getKeys(); - bool setElementValue(const std::string &sName, bool bHasNameQuotes, const std::string &sValue, bool bHasValueQuotes); - bool createElementMap(const std::string &sName, bool bHasNameQuotes); - WsjcppYamlItem *createElementMap(); - bool createElementArray(const std::string &sName, bool bHasNameQuotes); + bool setElementValue( + const std::string &sName, const std::string &sValue, + WsjcppYamlQuotes nNameQuotes = WSJCPP_YAML_QUOTES_NONE, + WsjcppYamlQuotes nValueQuotes = WSJCPP_YAML_QUOTES_NONE + ); + + bool createElementMap(const std::string &sName, WsjcppYamlQuotes nNameQuotes = WSJCPP_YAML_QUOTES_NONE); + WsjcppYamlNode *createElementMap(); + bool createElementArray(const std::string &sName, WsjcppYamlQuotes nNameQuotes = WSJCPP_YAML_QUOTES_NONE); bool isArray(); int getLength(); - WsjcppYamlItem *getElement(int i); - bool appendElement(WsjcppYamlItem *pItem); - bool appendElementValue(const std::string &sValue, bool bHasValueQuotes); + WsjcppYamlNode *getElement(int i); + bool appendElement(WsjcppYamlNode *pItem); + bool appendElementValue(const std::string &sValue, WsjcppYamlQuotes nValueQuotes = WSJCPP_YAML_QUOTES_NONE); bool removeElement(int i); bool isValue(); - std::string getValue(); - void setValue(const std::string &sValue, bool bHasQuotes); - bool hasValueDoubleQuotes(); + + std::string getValue(); // contains only strings + void setValue(const std::string &sValue, WsjcppYamlQuotes nQuotes = WSJCPP_YAML_QUOTES_NONE); + WsjcppYamlQuotes getValueQuotes(); + + std::string getSerializedName(); std::string toString(std::string sIntent = ""); std::string getItemTypeAsString(); - WsjcppYamlItem &operator[](int idx) { return *(this->getElement(idx)); } - WsjcppYamlItem &operator[](const std::string &sName) { return *(this->getElement(sName)); } - std::string getForLogFormat(); + int getNodeLastIntent(); + std::string getStringNodeLastIntent(); + void setNodeIntents(const std::vector & vNodeIntents); + int getNodeIntent(); private: + void throw_error(const std::string &sError); + std::string TAG; - WsjcppYamlItem *m_pParent; + WsjcppYamlNode *m_pParent; WsjcppYamlPlaceInFile m_placeInFile; - WsjcppYamlItemType m_nItemType; - std::vector m_vObjects; + WsjcppYamlNodeType m_nItemType; + std::vector m_vObjects; std::string m_sValue; // if it is not array or map - bool m_bValueHasDoubleQuotes; + WsjcppYamlQuotes m_nValueQuotes; std::string m_sName; - bool m_bNameHasDoubleQuotes; + WsjcppYamlQuotes m_nNameQuotes; std::string m_sComment; -}; - -// --------------------------------------------------------------------- - -enum WsjcppYamlParserLineStates { - NO, - VALUE, - COMMENT, - STRING, - ESCAPING + int m_nNodeDiffIntent; + std::string m_sNodeDiffIntent; + int m_nNodeIntent; }; // --------------------------------------------------------------------- @@ -144,73 +157,136 @@ class WsjcppYamlParsebleLine { int getIntent(); // prefix length bool isArrayItem(); std::string getComment(); + bool hasComment(); std::string getName(); - bool hasNameDoubleQuotes(); + WsjcppYamlQuotes getNameQuotes(); bool isEmptyName(); std::string getValue(); - bool hasValueDoubleQuotes(); + WsjcppYamlQuotes getValueQuotes(); bool isEmptyValue(); + bool isEmptyLine(); - void parseLine(const std::string &sLine); + bool parseLine(const std::string &sLine, std::string &sError); private: + std::string TAG; - int m_nLine; + int m_nLineNumber; std::string m_sPrefix; bool m_bArrayItem; std::string m_sComment; - std::string m_sName; + std::string m_sTagName; std::string m_sValue; - bool m_bNameHasQuotes; - bool m_bValueHasQuotes; + WsjcppYamlQuotes m_nNameQuotes; + WsjcppYamlQuotes m_nValueQuotes; + bool m_bHasComment; + bool m_bEmptyLine; + bool canTagName(const std::string &sVal); std::string removeStringDoubleQuotes(const std::string &sValue); + std::string removeStringSingleQuotes(const std::string &sValue); }; // --------------------------------------------------------------------- -class WsjcppYamlParserStatus { +class WsjcppYamlCursor { public: - int nIntent; - WsjcppYamlItem *pCurItem; - WsjcppYamlParsebleLine line; - WsjcppYamlPlaceInFile placeInFile; - void logUnknownLine(const std::string &sPrefix); + WsjcppYamlCursor(WsjcppYamlNode *pCurrentNode); + WsjcppYamlCursor(); + ~WsjcppYamlCursor(); + + // null or undefined + bool isNull() const; + + // isUndefined + bool isUndefined() const; + + // value + bool isValue() const; + + // array + bool isArray() const; + size_t size() const; + // WsjcppYamlCursor &push(const std::string &sVal); + // WsjcppYamlCursor &push(int nVal); + // WsjcppYamlCursor &push(bool bVal); + // WsjcppYamlCursor &remove(int nIdx); + + // map + bool isMap() const; + std::vector keys() const; + bool hasKey(const std::string &sKey) const; + // WsjcppYamlCursor &set(const std::string &sName, const std::string &sValue); + // WsjcppYamlCursor &set(const std::string &sName, int nValue); + // WsjcppYamlCursor &set(const std::string &sName, bool bValue); + // WsjcppYamlCursor &remove(const std::string &sKey); + + // comment + std::string comment(); + WsjcppYamlCursor &comment(const std::string& sComment); + + // val + std::string valStr(); + WsjcppYamlCursor &val(const std::string &sValue); + WsjcppYamlCursor &val(const char *sValue); + int valInt(); + WsjcppYamlCursor &val(int nValue); + bool valBool(); + WsjcppYamlCursor &val(bool bValue); + + + WsjcppYamlCursor operator[](int idx) const; + WsjcppYamlCursor operator[](const std::string &sName) const; + + private: + std::string TAG; + WsjcppYamlNode *m_pCurrentNode; }; + // --------------------------------------------------------------------- class WsjcppYaml { public: WsjcppYaml(); ~WsjcppYaml(); - bool loadFromFile(const std::string &sFileName); + void clear(); + bool loadFromFile(const std::string &sFileName, std::string &sError); bool saveToFile(const std::string &sFileName); - bool loadFromString(const std::string &sBuffer); - bool loadFromString(std::string &sBuffer); + bool loadFromString(const std::string &sBufferName, const std::string &sBuffer, std::string &sError); bool saveToString(std::string &sBuffer); + WsjcppYamlNode *getRoot(); - WsjcppYamlItem *getRoot(); - WsjcppYamlItem &operator[](int idx) { return *(getRoot()->getElement(idx)); } - WsjcppYamlItem &operator[](const std::string &sName) { return *(getRoot()->getElement(sName)); } + WsjcppYamlCursor getCursor() const; + WsjcppYamlCursor operator[](int idx) const; + WsjcppYamlCursor operator[](const std::string &sName) const; private: std::string TAG; + // TODO replace to WsjcppCore::split() std::vector splitToLines(const std::string &sBuffer); - bool parse(const std::string &sFileName, const std::string &sBuffer); - void process_sameIntent_hasName_emptyValue_arrayItem(WsjcppYamlParserStatus &st); - void process_sameIntent_hasName_emptyValue_noArrayItem(WsjcppYamlParserStatus &st); - void process_sameIntent_hasName_hasValue_arrayItem(WsjcppYamlParserStatus &st); - void process_sameIntent_hasName_hasValue_noArrayItem(WsjcppYamlParserStatus &st); - void process_sameIntent_emptyName_hasValue_arrayItem(WsjcppYamlParserStatus &st); - void process_sameIntent_emptyName_hasValue_noArrayItem(WsjcppYamlParserStatus &st); - void process_sameIntent_emptyName_emptyValue_arrayItem(WsjcppYamlParserStatus &st); - void process_sameIntent_emptyName_emptyValue_noArrayItem(WsjcppYamlParserStatus &st); + bool parse(const std::string &sFileName, const std::string &sBuffer, std::string &sError); + void process_hasName_emptyValue_arrayItem(); + void process_hasName_emptyValue_noArrayItem(); + void process_hasName_hasValue_arrayItem(); + void process_hasName_hasValue_noArrayItem(); + void process_emptyName_hasValue_arrayItem(); + void process_emptyName_hasValue_noArrayItem(); + void process_emptyName_emptyValue_arrayItem(); + void process_emptyName_emptyValue_noArrayItem(); std::vector m_sLines; - WsjcppYamlItem *m_pRoot; + WsjcppYamlNode *m_pRoot; + + // prsing line status + void logUnknownParseLine(); + WsjcppYamlNode *m_pParseCurrentParentNode; + int m_nParseCurrentIntent; + WsjcppYamlPlaceInFile m_parsePlaceInFile; + WsjcppYamlParsebleLine m_parseLine; + std::vector m_vStackDiffNodeIntents; }; #endif // WSJCPP_YAML_H diff --git a/unit-tests.wsjcpp/CMakeLists.txt b/unit-tests.wsjcpp/CMakeLists.txt index ec00433..a2008dd 100644 --- a/unit-tests.wsjcpp/CMakeLists.txt +++ b/unit-tests.wsjcpp/CMakeLists.txt @@ -1,4 +1,4 @@ -# Automaticly generated by wsjcpp@v0.1.7 +# Automaticly generated by wsjcpp@v0.2.0 cmake_minimum_required(VERSION 3.0) project(unit-tests C CXX) @@ -34,25 +34,23 @@ list (APPEND WSJCPP_SOURCES "../src/wsjcpp_yaml.h") # unit-tests list (APPEND WSJCPP_INCLUDE_DIRS "src") -list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_line_parser.h") list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_line_parser.cpp") -list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_array.h") list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_array.cpp") -list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_map.h") list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_map.cpp") -list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_hierarchical_map.h") list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_hierarchical_map.cpp") -list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_quotes.h") list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_quotes.cpp") -list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_comments.h") list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_comments.cpp") -list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_all.h") list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_all.cpp") -list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_array_included_map.h") list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_yaml_parser_array_included_map.cpp") - -# required-libraries -list (APPEND WSJCPP_LIBRARIES "-lpthread") +list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_remove_element_for_map.cpp") +list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_remove_element_in_array.cpp") +list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_memory_leaks.cpp") +list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_read_yaml.cpp") +list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_read_write_file.cpp") +list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_cursor.cpp") +list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_tag_names.cpp") +list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_cleanup.cpp") +list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_append_elements.cpp") include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.user-custom.txt) @@ -63,11 +61,3 @@ add_executable ("unit-tests" ${WSJCPP_SOURCES}) target_link_libraries("unit-tests" -lpthread ${WSJCPP_LIBRARIES} ) -install( - TARGETS - "unit-tests" - RUNTIME DESTINATION - /usr/bin -) - - diff --git a/unit-tests.wsjcpp/data-tests/for-memory-leak/some.yml b/unit-tests.wsjcpp/data-tests/for-memory-leak/some.yml new file mode 100644 index 0000000..123edfc --- /dev/null +++ b/unit-tests.wsjcpp/data-tests/for-memory-leak/some.yml @@ -0,0 +1,61 @@ +# example yaml for test memeoty leak +doe: "a deer, a female deer" +ray: "a drop of golden sun" +pi: 3.14159 +xmas: true +french-hens: 3 +calling-birds: + - huey + - dewey + - louie + - fred +xmas-fifth-day: + calling-birds: four + french-hens: 3 + golden-rings: 5 + partridges: + count: 1 + location: "a pear tree" + turtle-doves: two + +# example yaml again +again0: + doe: "a deer, a female deer" + ray: "a drop of golden sun" + pi: 3.14159 + xmas: true + french-hens: 3 + calling-birds: + - huey + - dewey + - louie + - fred + xmas-fifth-day: + calling-birds: four + french-hens: 3 + golden-rings: 5 + partridges: + count: 1 + location: "a pear tree" + turtle-doves: two + +# example yaml again2 +again2: + doe: "a deer, a female deer" + ray: "a drop of golden sun" + pi: 3.14159 + xmas: true + french-hens: 3 + calling-birds: + - huey + - dewey + - louie + - fred + xmas-fifth-day: + calling-birds: four + french-hens: 3 + golden-rings: 5 + partridges: + count: 1 + location: "a pear tree" + turtle-doves: two \ No newline at end of file diff --git a/unit-tests.wsjcpp/data-tests/parser-simple-array.yml b/unit-tests.wsjcpp/data-tests/parser-simple-array.yml new file mode 100644 index 0000000..15fed08 --- /dev/null +++ b/unit-tests.wsjcpp/data-tests/parser-simple-array.yml @@ -0,0 +1,12 @@ +# simple array test +param1: none value1 # it's value for something # olala +array-test2 : # some comment 2 + - value21 # comment v21 + - value22 # comment v22 + - true # comment true + # some + - falsesome + - free@free + - # empty + - 1 +param2: val2 # value 2 \ No newline at end of file diff --git a/unit-tests.wsjcpp/data-tests/read-file/example-voiting-app/docker-compose.yml b/unit-tests.wsjcpp/data-tests/read-file/example-voiting-app/docker-compose.yml new file mode 100644 index 0000000..0a02219 --- /dev/null +++ b/unit-tests.wsjcpp/data-tests/read-file/example-voiting-app/docker-compose.yml @@ -0,0 +1,61 @@ +# https://github.com/dockersamples/example-voting-app/blob/master/docker-compose.yml + +version: "3" + +services: + vote: + build: ./vote + command: python app.py + volumes: + - ./vote:/app + ports: + - "5000:80" + networks: + - front-tier + - back-tier + + result: + build: ./result + command: nodemon server.js + volumes: + - ./result:/app + ports: + - "5001:80" + - "5858:5858" + networks: + - front-tier + - back-tier + + worker: + build: + context: ./worker + depends_on: + - "redis" + - "db" + networks: + - back-tier + + redis: + image: redis:alpine + container_name: redis + ports: ["6379"] + networks: + - back-tier + + db: + image: postgres:9.4 + container_name: db + environment: + POSTGRES_USER: "postgres" + POSTGRES_PASSWORD: "postgres" + volumes: + - "db-data:/var/lib/postgresql/data" + networks: + - back-tier + +volumes: + db-data: + +networks: + front-tier: + back-tier: diff --git a/unit-tests.wsjcpp/data-tests/read-write-file/docker-compose.yml b/unit-tests.wsjcpp/data-tests/read-write-file/docker-compose.yml new file mode 100644 index 0000000..acc6124 --- /dev/null +++ b/unit-tests.wsjcpp/data-tests/read-write-file/docker-compose.yml @@ -0,0 +1,66 @@ +# https://github.com/dockersamples/example-voting-app/blob/master/docker-compose.yml + +version: "3" + +services: + # service vote + vote: + build: ./vote + command: python app.py + volumes: + - ./vote:/app + ports: + - "5000:80" + networks: + - front-tier + - back-tier + + # service result + result: + build: ./result + command: nodemon server.js + volumes: + - ./result:/app + ports: + # ports forward + - "5001:80" # some + + - "5858:5858" + + networks: + - front-tier + - back-tier + + worker: + build: + context: ./worker + depends_on: + - "redis" + - "db" + networks: + - back-tier + + redis: + image: redis:alpine + container_name: redis + ports: ["6379"] + networks: + - back-tier + + db: + image: postgres:9.4 + container_name: db + environment: + POSTGRES_USER: "postgres" + POSTGRES_PASSWORD: "postgres" + volumes: + - "db-data:/var/lib/postgresql/data" + networks: + - back-tier + +volumes: + db-data: + +networks: + front-tier: + back-tier: diff --git a/unit-tests.wsjcpp/data-tests/remove-element-in-array.yml b/unit-tests.wsjcpp/data-tests/remove-element-in-array.yml new file mode 100644 index 0000000..465166a --- /dev/null +++ b/unit-tests.wsjcpp/data-tests/remove-element-in-array.yml @@ -0,0 +1,9 @@ +# Some comment 1 + +arr1: + + - name: i1 + var2: 2 + - name: i2 + - name: i3 + - very different array items type \ No newline at end of file diff --git a/unit-tests.wsjcpp/parser_yaml.py b/unit-tests.wsjcpp/parser_yaml.py new file mode 100755 index 0000000..9476c83 --- /dev/null +++ b/unit-tests.wsjcpp/parser_yaml.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import yaml + + +a_yaml_file = open("./data-tests/read-write-file/docker-compose.yml") + +parsed_yaml_file = yaml.load(a_yaml_file, Loader=yaml.FullLoader) + +print(parsed_yaml_file) + +a_yaml_file2 = open("./data-tests/parser-simple-array/file.yml") + +parsed_yaml_file2 = yaml.load(a_yaml_file2, Loader=yaml.FullLoader) + +print(parsed_yaml_file2) diff --git a/unit-tests.wsjcpp/src/get_current_rss.h b/unit-tests.wsjcpp/src/get_current_rss.h new file mode 100644 index 0000000..54231fd --- /dev/null +++ b/unit-tests.wsjcpp/src/get_current_rss.h @@ -0,0 +1,121 @@ +/* + * Author: David Robert Nadeau + * Site: http://NadeauSoftware.com/ + * License: Creative Commons Attribution 3.0 Unported License + * http://creativecommons.org/licenses/by/3.0/deed.en_US + */ +// https://stackoverflow.com/questions/669438/how-to-get-memory-usage-at-runtime-using-c + +#if defined(_WIN32) +#include +#include + +#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) +#include +#include + +#if defined(__APPLE__) && defined(__MACH__) +#include + +#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) +#include +#include + +#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__) +#include + +#endif + +#else +#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS." +#endif + + + +/** + * Returns the peak (maximum so far) resident set size (physical + * memory use) measured in bytes, or zero if the value cannot be + * determined on this OS. + */ +size_t getPeakRSS( ) +{ +#if defined(_WIN32) + /* Windows -------------------------------------------------- */ + PROCESS_MEMORY_COUNTERS info; + GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); + return (size_t)info.PeakWorkingSetSize; + +#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) + /* AIX and Solaris ------------------------------------------ */ + struct psinfo psinfo; + int fd = -1; + if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 ) + return (size_t)0L; /* Can't open? */ + if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) ) + { + close( fd ); + return (size_t)0L; /* Can't read? */ + } + close( fd ); + return (size_t)(psinfo.pr_rssize * 1024L); + +#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) + /* BSD, Linux, and OSX -------------------------------------- */ + struct rusage rusage; + getrusage( RUSAGE_SELF, &rusage ); +#if defined(__APPLE__) && defined(__MACH__) + return (size_t)rusage.ru_maxrss; +#else + return (size_t)(rusage.ru_maxrss * 1024L); +#endif + +#else + /* Unknown OS ----------------------------------------------- */ + return (size_t)0L; /* Unsupported. */ +#endif +} + + + + + +/** + * Returns the current resident set size (physical memory use) measured + * in bytes, or zero if the value cannot be determined on this OS. + */ +size_t getCurrentRSS( ) +{ +#if defined(_WIN32) + /* Windows -------------------------------------------------- */ + PROCESS_MEMORY_COUNTERS info; + GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); + return (size_t)info.WorkingSetSize; + +#elif defined(__APPLE__) && defined(__MACH__) + /* OSX ------------------------------------------------------ */ + struct mach_task_basic_info info; + mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; + if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO, + (task_info_t)&info, &infoCount ) != KERN_SUCCESS ) + return (size_t)0L; /* Can't access? */ + return (size_t)info.resident_size; + +#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__) + /* Linux ---------------------------------------------------- */ + long rss = 0L; + FILE* fp = NULL; + if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL ) + return (size_t)0L; /* Can't open? */ + if ( fscanf( fp, "%*s%ld", &rss ) != 1 ) + { + fclose( fp ); + return (size_t)0L; /* Can't read? */ + } + fclose( fp ); + return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE); + +#else + /* AIX, BSD, Solaris, and Unknown OS ------------------------ */ + return (size_t)0L; /* Unsupported. */ +#endif +} \ No newline at end of file diff --git a/unit-tests.wsjcpp/src/process_mem_usage.h b/unit-tests.wsjcpp/src/process_mem_usage.h new file mode 100644 index 0000000..c0aa94e --- /dev/null +++ b/unit-tests.wsjcpp/src/process_mem_usage.h @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +// https://stackoverflow.com/questions/669438/how-to-get-memory-usage-at-runtime-using-c + +////////////////////////////////////////////////////////////////////////////// +// +// process_mem_usage(double &, double &) - takes two doubles by reference, +// attempts to read the system-dependent data for a process' virtual memory +// size and resident set size, and return the results in KB. +// +// On failure, returns 0.0, 0.0 + +void process_mem_usage(double& vm_usage, double& resident_set) +{ + using std::ios_base; + using std::ifstream; + using std::string; + + vm_usage = 0.0; + resident_set = 0.0; + + // 'file' stat seems to give the most reliable results + // + ifstream stat_stream("/proc/self/stat",ios_base::in); + if (!stat_stream.is_open()) { + return; + } + + // dummy vars for leading entries in stat that we don't care about + // + string pid, comm, state, ppid, pgrp, session, tty_nr; + string tpgid, flags, minflt, cminflt, majflt, cmajflt; + string utime, stime, cutime, cstime, priority, nice; + string O, itrealvalue, starttime; + + // the two fields we want + // + unsigned long vsize; + long rss; + + stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr + >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt + >> utime >> stime >> cutime >> cstime >> priority >> nice + >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest + + stat_stream.close(); + + long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages + vm_usage = vsize / 1024.0; + resident_set = rss * page_size_kb; +} \ No newline at end of file diff --git a/unit-tests.wsjcpp/src/unit_test_append_elements.cpp b/unit-tests.wsjcpp/src/unit_test_append_elements.cpp new file mode 100644 index 0000000..93443b6 --- /dev/null +++ b/unit-tests.wsjcpp/src/unit_test_append_elements.cpp @@ -0,0 +1,73 @@ + +#include +#include +#include + +// --------------------------------------------------------------------- +// UnitTestAppendElements + +class UnitTestAppendElements : public WsjcppUnitTestBase { + public: + UnitTestAppendElements(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + +REGISTRY_WSJCPP_UNIT_TEST(UnitTestAppendElements) + +UnitTestAppendElements::UnitTestAppendElements() + : WsjcppUnitTestBase("UnitTestAppendElements") { +} + +// --------------------------------------------------------------------- + +bool UnitTestAppendElements::doBeforeTest() { + // do something before test + return true; +} + +// --------------------------------------------------------------------- + +void UnitTestAppendElements::executeTest() { + + WsjcppYaml yml; + yml.getRoot()->setElementValue("p1", "val1"); + yml.getRoot()->createElementMap("some"); + WsjcppYamlNode *pSome = yml.getRoot()->getElement("some"); + pSome->setElementValue("p2", "val2"); + pSome->createElementMap("sub-some"); + WsjcppYamlNode *pSubSome = pSome->getElement("sub-some"); + pSubSome->setElementValue("p3", "val3"); + pSome->createElementArray("arr-some"); + WsjcppYamlNode *pArrSome = pSome->getElement("arr-some"); + pArrSome->appendElementValue("1234"); + WsjcppYamlPlaceInFile placeInFile; + WsjcppYamlNode *pItemMap = new WsjcppYamlNode(pArrSome, placeInFile, WSJCPP_YAML_NODE_MAP); + pArrSome->appendElement(pItemMap); + pItemMap->setElementValue("p4", "val4"); + pItemMap->setElementValue("p5", "val5"); + yml.getRoot()->setElementValue("p6", "val6"); + + compare("created yaml 1", yml.getRoot()->toString(), + "p1: val1\n" + "some:\n" + " p2: val2\n" + " sub-some:\n" + " p3: val3\n" + " arr-some:\n" + " - 1234\n" + " - p4: val4\n" + " p5: val5\n" + "p6: val6" + ); +} + +// --------------------------------------------------------------------- + +bool UnitTestAppendElements::doAfterTest() { + // do somethig after test + return true; +} + + diff --git a/unit-tests.wsjcpp/src/unit_test_cleanup.cpp b/unit-tests.wsjcpp/src/unit_test_cleanup.cpp new file mode 100644 index 0000000..d713084 --- /dev/null +++ b/unit-tests.wsjcpp/src/unit_test_cleanup.cpp @@ -0,0 +1,81 @@ + +#include +#include +#include + +// --------------------------------------------------------------------- +// UnitTestCleanup + +class UnitTestCleanup : public WsjcppUnitTestBase { + public: + UnitTestCleanup(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + +REGISTRY_WSJCPP_UNIT_TEST(UnitTestCleanup) + +UnitTestCleanup::UnitTestCleanup() + : WsjcppUnitTestBase("UnitTestCleanup") { +} + +// --------------------------------------------------------------------- + +bool UnitTestCleanup::doBeforeTest() { + // do something before test + return true; +} + +// --------------------------------------------------------------------- + +void UnitTestCleanup::executeTest() { + std::string sTestYaml1 = + "# Some comment 1\n" + "test10: one\n" + "test20: two # some comment 2\n" + ; + + std::string sTestYaml2 = + "# Some comment 1\n" + "test11: one\n" + "test20: two # some comment 2\n" + "test22: two # some comment 2\n" + ; + + WsjcppYaml yaml; + std::string sError; + + if (!compare("Error parsing 1", yaml.loadFromString("parse1", sTestYaml1, sError), true)) { + WsjcppLog::err(TAG, sError); + return; + } + + compare("(1) has test10", yaml.getRoot()->hasElement("test10"), true); + compare("(1) has test11", yaml.getRoot()->hasElement("test11"), false); + compare("(1) has test20", yaml.getRoot()->hasElement("test20"), true); + compare("(1) has test22", yaml.getRoot()->hasElement("test22"), false); + + if (!compare("Error parsing 2", yaml.loadFromString("parse2", sTestYaml2, sError), true)) { + WsjcppLog::err(TAG, sError); + return; + } + + compare("(2) has test10", yaml.getRoot()->hasElement("test10"), false); + compare("(2) has test11", yaml.getRoot()->hasElement("test11"), true); + compare("(2) has test20", yaml.getRoot()->hasElement("test20"), true); + compare("(2) has test22", yaml.getRoot()->hasElement("test22"), true); + + yaml.clear(); + + compare("(3) has root", yaml.getRoot() == nullptr, true); +} + +// --------------------------------------------------------------------- + +bool UnitTestCleanup::doAfterTest() { + // do somethig after test + return true; +} + + diff --git a/unit-tests.wsjcpp/src/unit_test_cursor.cpp b/unit-tests.wsjcpp/src/unit_test_cursor.cpp new file mode 100644 index 0000000..d9ef0d6 --- /dev/null +++ b/unit-tests.wsjcpp/src/unit_test_cursor.cpp @@ -0,0 +1,176 @@ + +#include +#include +#include + +// --------------------------------------------------------------------- +// UnitTestCursor + +class UnitTestCursor : public WsjcppUnitTestBase { + public: + UnitTestCursor(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + +REGISTRY_WSJCPP_UNIT_TEST(UnitTestCursor) + +UnitTestCursor::UnitTestCursor() + : WsjcppUnitTestBase("UnitTestCursor") { +} + +// --------------------------------------------------------------------- + +bool UnitTestCursor::doBeforeTest() { + // do something before test + return true; +} + +// --------------------------------------------------------------------- + +void UnitTestCursor::executeTest() { + + std::string sTestYaml = + "# Some comment 1\n" + "map1: \n" + " map11: \n" + " sss: \n" + " map111: \n" + " param1111: v1111\n" + " param1112: v1112\n" + " map112: \n" + " param1121: v1121\n" + " param1122: v1122\n" + " map113: \n" + " param1131: v1131\n" + " param1132: v1132\n" + " map12: \n" + " param121: v121\n" + " param122: v122\n" + " map123: \n" + " param1231: v1231\n" + " param1232: v1232\n" + " param1232: v1232\n" + "param2: v2 # some comment 2\n" + "arr1: # some comment array 1\n" + " - some1\n" + " - 3\n" + "\n" + " - Yes\n" + " # empty\n" + " - no\n" + " - true\n" + " - False\n" + "\n" // empty line + ; + + WsjcppYaml yaml; + std::string sError; + if (!compare("Error parsing", yaml.loadFromString("test_cursor", sTestYaml, sError), true)) { + WsjcppLog::err(TAG, sError); + return; + } + + compare("map1 is null", yaml["map1"].isNull(), false); + compare("map1 is undefined", yaml["map1"].isUndefined(), false); + compare("map1 is value", yaml["map1"].isValue(), false); + compare("map1 is array", yaml["map1"].isArray(), false); + compare("map1 is map", yaml["map1"].isMap(), true); + + compare("map1-1111 is null", yaml["map1-1111"].isNull(), true); + compare("map1 is undefined", yaml["map1-1111"].isUndefined(), false); + compare("map1 is value", yaml["map1-1111"].isValue(), false); + compare("map1-1111 is array", yaml["map1-1111"].isArray(), false); + compare("map1-1111 is map", yaml["map1-1111"].isMap(), false); + + compare("arr1 is null", yaml["arr1"].isNull(), false); + compare("arr1 is undefined", yaml["arr1"].isUndefined(), false); + compare("arr1 is value", yaml["arr1"].isValue(), false); + compare("arr1 is array", yaml["arr1"].isArray(), true); + compare("arr1 is map", yaml["arr1"].isMap(), false); + + compare("map1.map11.sss is null", yaml["map1"]["map11"]["sss"].isNull(), false); + compare("map1.map11.sss is undefined", yaml["map1"]["map11"]["sss"].isUndefined(), true); + compare("map1.map11.sss is value", yaml["map1"]["map11"]["sss"].isValue(), false); + compare("map1.map11.sss is array", yaml["map1"]["map11"]["sss"].isArray(), false); + compare("map1.map11.sss is map", yaml["map1"]["map11"]["sss"].isMap(), false); + + compare("map1.map11.map111.param1111 is null", yaml["map1"]["map11"]["map111"]["param1111"].isNull(), false); + compare("map1.map11.map111.param1111 is undefined", yaml["map1"]["map11"]["map111"]["param1111"].isUndefined(), false); + compare("map1.map11.map111.param1111 is value", yaml["map1"]["map11"]["map111"]["param1111"].isValue(), true); + compare("map1.map11.map111.param1111 is array", yaml["map1"]["map11"]["map111"]["param1111"].isArray(), false); + compare("map1.map11.map111.param1111 is map", yaml["map1"]["map11"]["map111"]["param1111"].isMap(), false); + + compare("map use as array", yaml["map1"][0].isNull(), true); + compare("array use as map", yaml["arr1"]["0"].isNull(), true); + compare("array use as map", yaml["arr1"][0].isNull(), false); + + compare("array size", yaml["arr1"].comment(), "some comment array 1"); + compare("array size", yaml["arr1"].size(), 6); + compare("array el 0", yaml["arr1"][0].valStr(), "some1"); + compare("array el 1", yaml["arr1"][1].valStr(), "3"); + compare("array el 2", yaml["arr1"][2].valStr(), "Yes"); + compare("array el 3", yaml["arr1"][3].valStr(), "no"); + compare("array el 4", yaml["arr1"][4].valStr(), "true"); + compare("array el 5", yaml["arr1"][5].valStr(), "False"); + + compare("array bool el 2", yaml["arr1"][2].valBool(), true); + compare("array bool el 3", yaml["arr1"][3].valBool(), false); + compare("array bool el 4", yaml["arr1"][4].valBool(), true); + compare("array bool el 5", yaml["arr1"][5].valBool(), false); + + // int + compare("array size", yaml["arr1"][1].valInt(), 3); + yaml["arr1"][1].val(10); + compare("array size", yaml["arr1"][1].valInt(), 10); + + // string + compare("array el 0 - 1", yaml["arr1"][0].valStr(), "some1"); + yaml["arr1"][0].val("different value").comment("1234"); + compare("array el 0 - 2", yaml["arr1"][0].valStr(), "different value"); + compare("array el 0 - 3", yaml["arr1"][0].comment(), "1234"); + + // bool + compare("array bool el 4", yaml["arr1"][4].valStr(), "true"); + compare("array bool el 4", yaml["arr1"][4].valBool(), true); + yaml["arr1"][4].val(true); + compare("array bool el 4", yaml["arr1"][4].valStr(), "yes"); + compare("array bool el 4", yaml["arr1"][4].valBool(), true); + yaml["arr1"][4].val(false); + compare("array bool el 4", yaml["arr1"][4].valStr(), "no"); + compare("array bool el 4", yaml["arr1"][4].valBool(), false); + + // map + compare("map1.map12", yaml["map1"]["map12"].isMap(), true); + + std::vector vKeys = yaml["map1"]["map12"].keys(); + compare("map1.map12 keys size", vKeys.size(), 4); + if (vKeys.size() == 4) { + compare("map1.map12 keys 0", vKeys[0], "param121"); + compare("map1.map12 keys 1", vKeys[1], "param122"); + compare("map1.map12 keys 2", vKeys[2], "map123"); + compare("map1.map12 keys 3", vKeys[3], "param1232"); + } + compare("map1.map12 has key1", yaml["map1"]["map12"].hasKey("some"), false); + compare("map1.map12 has key2", yaml["map1"]["map12"].hasKey("map123"), true); + compare("map1.map12 is value", yaml["map1"]["map12"]["map123"].isValue(), false); + compare("map1.map12 is value", yaml["map1"]["map12"]["param122"].isValue(), true); + + + /* WsjcppYamlCursor &push(const std::string &sVal); + WsjcppYamlCursor &push(int nVal); + WsjcppYamlCursor &push(bool bVal); + WsjcppYamlCursor &remove(int nIdx);*/ + + +} + +// --------------------------------------------------------------------- + +bool UnitTestCursor::doAfterTest() { + // do somethig after test + return true; +} + + diff --git a/unit-tests.wsjcpp/src/unit_test_line_parser.cpp b/unit-tests.wsjcpp/src/unit_test_line_parser.cpp index 08ccfe0..9dca9ca 100644 --- a/unit-tests.wsjcpp/src/unit_test_line_parser.cpp +++ b/unit-tests.wsjcpp/src/unit_test_line_parser.cpp @@ -1,8 +1,19 @@ -#include "unit_test_line_parser.h" +#include #include #include #include +// --------------------------------------------------------------------- +// UnitTestLineParser + +class UnitTestLineParser : public WsjcppUnitTestBase { + public: + UnitTestLineParser(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + REGISTRY_WSJCPP_UNIT_TEST(UnitTestLineParser) UnitTestLineParser::UnitTestLineParser() @@ -13,7 +24,7 @@ UnitTestLineParser::UnitTestLineParser() // --------------------------------------------------------------------- bool UnitTestLineParser::doBeforeTest() { - // nothing + // do something before test return true; } @@ -27,18 +38,18 @@ void UnitTestLineParser::executeTest() { std::string sPrefix, bool isArrayItem, std::string sName, - bool bNameHasQuotes, + WsjcppYamlQuotes nNameQuotes, std::string sValue, - bool bValueHasQuotes, + WsjcppYamlQuotes nValueQuotes, std::string sComment ) : nNumberOfTest(nNumberOfTest), sLine(sLine), sPrefix(sPrefix), isArrayItem(isArrayItem), sName(sName), - bNameHasQuotes(bNameHasQuotes), + nNameQuotes(nNameQuotes), sValue(sValue), - bValueHasQuotes(bValueHasQuotes), + nValueQuotes(nValueQuotes), sComment(sComment) { // @@ -48,35 +59,81 @@ void UnitTestLineParser::executeTest() { std::string sPrefix; bool isArrayItem; std::string sName; - bool bNameHasQuotes; + WsjcppYamlQuotes nNameQuotes; std::string sValue; - bool bValueHasQuotes; + WsjcppYamlQuotes nValueQuotes; std::string sComment; }; std::vector vTestLines; - vTestLines.push_back(LineTest(1, "# Some comment 1 ", "", false, "", false, "", false, "Some comment 1")); - vTestLines.push_back(LineTest(2, " test2: \"t\\\"wo\" # some comment 2 ", " ", false, "test2", false, "t\"wo", true, "some comment 2")); - vTestLines.push_back(LineTest(3, " test3:", " ", false, "test3", false, "", false, "")); - vTestLines.push_back(LineTest(4, " - test4", " ", true, "", false, "test4", false, "")); - vTestLines.push_back(LineTest(5, "", "", false, "", false, "", false, "")); - vTestLines.push_back(LineTest(6, " - \"test4:111\"", " ", true, "", false, "test4:111", true, "")); - vTestLines.push_back(LineTest(7, "issues: https://github.com/wsjcpp/wsjcpp-yaml/issues", "", false, "issues", false, "https://github.com/wsjcpp/wsjcpp-yaml/issues", false, "")); + vTestLines.push_back(LineTest(1, + "# Some comment 1 ", "", + false, // array node + "", WSJCPP_YAML_QUOTES_NONE, // name + "", WSJCPP_YAML_QUOTES_NONE, // value + "Some comment 1" // comment + )); + vTestLines.push_back(LineTest(2, + " test2: \"t\\\"wo\" # some comment 2 ", " ", + false, // array node + "test2", WSJCPP_YAML_QUOTES_NONE, // name + "t\"wo", WSJCPP_YAML_QUOTES_DOUBLE, // value + "some comment 2" // comment + )); + vTestLines.push_back(LineTest(3, + " test3:", " ", + false, // array node + "test3", WSJCPP_YAML_QUOTES_NONE, // name + "", WSJCPP_YAML_QUOTES_NONE, // value + "" // comment + )); + vTestLines.push_back(LineTest(4, + " - test4", " ", + true, // array node + "", WSJCPP_YAML_QUOTES_NONE, // name + "test4", WSJCPP_YAML_QUOTES_NONE, // value + "" // comment + )); + vTestLines.push_back(LineTest(5, + "", "", + false, // array node + "", WSJCPP_YAML_QUOTES_NONE, // name + "", WSJCPP_YAML_QUOTES_NONE, // value + "" // comment + )); + vTestLines.push_back(LineTest(6, + " - \"test4:111\"", " ", + true, // array node + "", WSJCPP_YAML_QUOTES_NONE, // name + "test4:111", WSJCPP_YAML_QUOTES_DOUBLE, // value + "" // comment + )); + vTestLines.push_back(LineTest(7, + "issues: https://github.com/wsjcpp/wsjcpp-yaml/issues", "", + false, // array node + "issues", WSJCPP_YAML_QUOTES_NONE, // name + "https://github.com/wsjcpp/wsjcpp-yaml/issues", WSJCPP_YAML_QUOTES_NONE, // value + "" // comment + )); for (int i = 0; i < vTestLines.size(); i++) { LineTest test = vTestLines[i]; - + std::string tagline = "{line:" + std::to_string(test.nNumberOfTest) + ": '" + test.sLine + "'}"; + WsjcppYamlParsebleLine line(test.nNumberOfTest); - line.parseLine(test.sLine); + std::string sError; + if (!compare(tagline + ", parseLine", line.parseLine(test.sLine, sError), true)) { + WsjcppLog::err(tagline + ", parseLine", sError); + return; + } - std::string tagline = "{line:" + std::to_string(test.nNumberOfTest) + ": '" + test.sLine + "'}"; compare(tagline + ", prefix", line.getPrefix(), test.sPrefix); compare(tagline + ", arrayitem", line.isArrayItem(), test.isArrayItem); compare(tagline + ", name", line.getName(), test.sName); - compare(tagline + ", name-has-quotes", line.hasNameDoubleQuotes(), test.bNameHasQuotes); + compare(tagline + ", name-has-quotes", line.getNameQuotes(), test.nNameQuotes); compare(tagline + ", value", line.getValue(), test.sValue); - compare(tagline + ", value-has-quotes", line.hasValueDoubleQuotes(), test.bValueHasQuotes); + compare(tagline + ", value-quotes", line.getValueQuotes(), test.nValueQuotes); compare(tagline + ", comment", line.getComment(), test.sComment); } } @@ -84,6 +141,6 @@ void UnitTestLineParser::executeTest() { // --------------------------------------------------------------------- bool UnitTestLineParser::doAfterTest() { - // nothing + // do somethig after test return true; } \ No newline at end of file diff --git a/unit-tests.wsjcpp/src/unit_test_line_parser.h b/unit-tests.wsjcpp/src/unit_test_line_parser.h deleted file mode 100644 index e685ece..0000000 --- a/unit-tests.wsjcpp/src/unit_test_line_parser.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UNIT_TEST_LINE_PARSER_H -#define UNIT_TEST_LINE_PARSER_H - -#include - -class UnitTestLineParser : public WsjcppUnitTestBase { - public: - UnitTestLineParser(); - virtual bool doBeforeTest() override; - virtual void executeTest() override; - virtual bool doAfterTest() override; -}; - -#endif // UNIT_TEST_LINE_PARSER_H \ No newline at end of file diff --git a/unit-tests.wsjcpp/src/unit_test_memory_leaks.cpp b/unit-tests.wsjcpp/src/unit_test_memory_leaks.cpp new file mode 100644 index 0000000..43657b9 --- /dev/null +++ b/unit-tests.wsjcpp/src/unit_test_memory_leaks.cpp @@ -0,0 +1,79 @@ + +#include +#include +#include +#include "get_current_rss.h" +#include "process_mem_usage.h" + + +// --------------------------------------------------------------------- +// UnitTestMemoryLeaks + +class UnitTestMemoryLeaks : public WsjcppUnitTestBase { + public: + UnitTestMemoryLeaks(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; + + private: + void createManyTimesObjects(); +}; + +REGISTRY_WSJCPP_UNIT_TEST(UnitTestMemoryLeaks) + +UnitTestMemoryLeaks::UnitTestMemoryLeaks() + : WsjcppUnitTestBase("UnitTestMemoryLeaks") { +} + +// --------------------------------------------------------------------- + +bool UnitTestMemoryLeaks::doBeforeTest() { + // do something before test + return true; +} + +// --------------------------------------------------------------------- + +void UnitTestMemoryLeaks::createManyTimesObjects() { + std::string sFilepath = "./data-tests/for-memory-leak/some.yml"; + std::string sError; + for (int i = 0; i < 10000; i++) { + WsjcppYaml yaml; + if (!compare("Error parsing", yaml.loadFromFile(sFilepath, sError), true)) { + WsjcppLog::err(TAG, sError); + return; + } + } +} + +// --------------------------------------------------------------------- + +void UnitTestMemoryLeaks::executeTest() { + double nBeforeVm, nBeforeRss; + double nAfterVm, nAfterRss; + std::string sFilepath = "./data-tests/for-memory-leak/some.yml"; + + // first use for memory alloc memory for work + createManyTimesObjects(); + + process_mem_usage(nBeforeVm, nBeforeRss); + compare("memory vm not null", (int)nBeforeVm > 0, true); + compare("memory vm not null", (int)nBeforeRss > 0, true); + + // code again check the memoty leak + createManyTimesObjects(); + + process_mem_usage(nAfterVm, nAfterRss); + compare("memory vm", (int)nAfterVm, (int)nBeforeVm); + compare("memory rss", (int)nAfterRss, (int)nBeforeRss); +} + +// --------------------------------------------------------------------- + +bool UnitTestMemoryLeaks::doAfterTest() { + // do somethig after test + return true; +} + + diff --git a/unit-tests.wsjcpp/src/unit_test_read_write_file.cpp b/unit-tests.wsjcpp/src/unit_test_read_write_file.cpp new file mode 100644 index 0000000..361233d --- /dev/null +++ b/unit-tests.wsjcpp/src/unit_test_read_write_file.cpp @@ -0,0 +1,70 @@ + +#include +#include +#include + +// --------------------------------------------------------------------- +// UnitTestReadWriteFile + +class UnitTestReadWriteFile : public WsjcppUnitTestBase { + public: + UnitTestReadWriteFile(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + +REGISTRY_WSJCPP_UNIT_TEST(UnitTestReadWriteFile) + +UnitTestReadWriteFile::UnitTestReadWriteFile() + : WsjcppUnitTestBase("UnitTestReadWriteFile") { +} + +// --------------------------------------------------------------------- + +bool UnitTestReadWriteFile::doBeforeTest() { + // do something before test + return true; +} + +// --------------------------------------------------------------------- + +void UnitTestReadWriteFile::executeTest() { + WsjcppYaml yaml; + std::string sFilepath = "./data-tests/read-write-file/docker-compose.yml"; + std::string sFilepathOutput = "./data-tests/read-write-file/docker-compose.output.yml"; + std::string sError; + if (!compare("Error parsing", yaml.loadFromFile(sFilepath, sError), true)) { + WsjcppLog::err(TAG, sError); + return; + } + + compare("has version", yaml.getRoot()->hasElement("version"), true); + compare("has volumes", yaml.getRoot()->hasElement("volumes"), true); + compare("has networks", yaml.getRoot()->hasElement("networks"), true); + compare("has services", yaml.getRoot()->hasElement("services"), true); + + compare("version-value", yaml.getRoot()->getElement("version")->getValue(), "3"); + + if (!compare("Error parsing", yaml.saveToFile(sFilepathOutput), true)) { + WsjcppLog::err(TAG, sError); + return; + } + + std::string sOriginalFileContent; + WsjcppCore::readTextFile(sFilepath, sOriginalFileContent); + std::string sOutputFileContent; + WsjcppCore::readTextFile(sFilepathOutput, sOutputFileContent); + + compare("compare conteent ", sOutputFileContent, sOriginalFileContent); + +} + +// --------------------------------------------------------------------- + +bool UnitTestReadWriteFile::doAfterTest() { + // do somethig after test + return true; +} + + diff --git a/unit-tests.wsjcpp/src/unit_test_read_yaml.cpp b/unit-tests.wsjcpp/src/unit_test_read_yaml.cpp new file mode 100644 index 0000000..c810078 --- /dev/null +++ b/unit-tests.wsjcpp/src/unit_test_read_yaml.cpp @@ -0,0 +1,238 @@ + +#include +#include +#include + +// --------------------------------------------------------------------- +// UnitTestReadYaml + +class UnitTestReadYaml : public WsjcppUnitTestBase { + public: + UnitTestReadYaml(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + +REGISTRY_WSJCPP_UNIT_TEST(UnitTestReadYaml) + +UnitTestReadYaml::UnitTestReadYaml() + : WsjcppUnitTestBase("UnitTestReadYaml") { +} + +// --------------------------------------------------------------------- + +bool UnitTestReadYaml::doBeforeTest() { + // do something before test + return true; +} + +// --------------------------------------------------------------------- + +void UnitTestReadYaml::executeTest() { + WsjcppYaml yaml; + std::string sFilepath = "./data-tests/read-file/example-voiting-app/docker-compose.yml"; + std::string sError; + if (!compare("Error parsing", yaml.loadFromFile(sFilepath, sError), true)) { + WsjcppLog::err(TAG, sError); + return; + } + + compare("has version", yaml.getRoot()->hasElement("version"), true); + compare("has version is value", yaml.getRoot()->getElement("version")->isValue(), true); + compare("version-value", yaml.getRoot()->getElement("version")->getValue(), "3"); + + compare("has services", yaml.getRoot()->hasElement("services"), true); + compare("has services is map", yaml.getRoot()->getElement("services")->isMap(), true); + + + WsjcppYamlNode *pServices = yaml.getRoot()->getElement("services"); + + // services.vote + { + compare("has services.vote", pServices->hasElement("vote"), true); + compare("services.vote is map", pServices->getElement("vote")->isMap(), true); + compare("services.vote keys size 5", pServices->getElement("vote")->getKeys().size(), 5); + + WsjcppYamlNode *pVote = pServices->getElement("vote"); + + compare("has services.vote.build", pVote->hasElement("build"), true); + compare("services.vote.build val", pVote->getElement("build")->getValue(), "./vote"); + + compare("has services.vote.command", pVote->hasElement("command"), true); + compare("services.vote.command val", pVote->getElement("command")->getValue(), "python app.py"); + + WsjcppYamlNode *pVolumes = pVote->getElement("volumes"); + compare("services.vote.volumes is array", pVolumes->isArray(), true); + compare("services.vote.volumes size 1", pVolumes->getLength(), 1); + compare("services.vote.volumes val 0", pVolumes->getElement(0)->getValue(), "./vote:/app"); + + WsjcppYamlNode *pVotePorts = pVote->getElement("ports"); + compare("services.vote.ports is array", pVotePorts->isArray(), true); + compare("services.vote.ports size 1", pVotePorts->getLength(), 1); + compare("services.vote.ports val 0", pVotePorts->getElement(0)->getValue(), "5000:80"); + + WsjcppYamlNode *pVoteNetworks = pVote->getElement("networks"); + compare("services.vote.networks size 2", pVoteNetworks->getLength(), 2); + compare("services.vote.networks val 0", pVoteNetworks->getElement(0)->getValue(), "front-tier"); + compare("services.vote.networks val 1", pVoteNetworks->getElement(1)->getValue(), "back-tier"); + } + + // services.result + { + compare("has services.result", pServices->hasElement("result"), true); + compare("services.result is map", pServices->getElement("result")->isMap(), true); + compare("services.result keys size 5", pServices->getElement("result")->getKeys().size(), 5); + + WsjcppYamlNode *pResult = pServices->getElement("result"); + + compare("has services.result.build", pResult->hasElement("build"), true); + compare("services.result.build val", pResult->getElement("build")->getValue(), "./result"); + + compare("has services.result.command", pResult->hasElement("command"), true); + compare("services.result.command val", pResult->getElement("command")->getValue(), "nodemon server.js"); + + WsjcppYamlNode *pResultVolumes = pResult->getElement("volumes"); + compare("services.result.volumes is array", pResultVolumes->isArray(), true); + compare("services.result.volumes size 1", pResultVolumes->getLength(), 1); + compare("services.result.volumes val 0", pResultVolumes->getElement(0)->getValue(), "./result:/app"); + + WsjcppYamlNode *pResultPorts = pResult->getElement("ports"); + compare("services.result.ports is array", pResultPorts->isArray(), true); + compare("services.result.ports size 2", pResultPorts->getLength(), 2); + compare("services.result.ports val 0", pResultPorts->getElement(0)->getValue(), "5001:80"); + compare("services.result.ports val 1", pResultPorts->getElement(1)->getValue(), "5858:5858"); + + WsjcppYamlNode *pResultNetworks = pResult->getElement("networks"); + compare("services.result.networks size 2", pResultNetworks->getLength(), 2); + compare("services.result.networks val 0", pResultNetworks->getElement(0)->getValue(), "front-tier"); + compare("services.result.networks val 1", pResultNetworks->getElement(1)->getValue(), "back-tier"); + } + + // services.worker + { + compare("has services.worker", pServices->hasElement("worker"), true); + compare("has services.worker is map", pServices->getElement("worker")->isMap(), true); + compare("services.worker keys size 3", pServices->getElement("worker")->getKeys().size(), 3); + WsjcppYamlNode *pWorker = pServices->getElement("worker"); + + compare("has services.worker.build", pWorker->hasElement("build"), true); + + compare("has services.worker.depends_on", pWorker->hasElement("depends_on"), true); + compare("has services.worker.networks", pWorker->hasElement("networks"), true); + + WsjcppYamlNode *pWorkerBuild = pWorker->getElement("build"); + compare("services.worker.build is map", pWorkerBuild->isMap(), true); + compare("has services.worker.build.context", pWorkerBuild->hasElement("context"), true); + compare("services.worker.build.context val", pWorkerBuild->getElement("context")->getValue(), "./worker"); + + WsjcppYamlNode *pWorkerDependsOn = pWorker->getElement("depends_on"); + compare("has services.worker.depends_on", pWorkerDependsOn->isArray(), true); + compare("services.worker.depends_on size 2", pWorkerDependsOn->getLength(), 2); + compare("services.worker.depends_on val 0", pWorkerDependsOn->getElement(0)->getValue(), "redis"); + compare("services.worker.depends_on val 1", pWorkerDependsOn->getElement(1)->getValue(), "db"); + + WsjcppYamlNode *pWorkerNetworks = pWorker->getElement("networks"); + compare("services.worker.networks size 1", pWorkerNetworks->getLength(), 1); + compare("services.worker.networks val 0", pWorkerNetworks->getElement(0)->getValue(), "back-tier"); + } + + // services.redis + { + compare("has services.redis", pServices->hasElement("redis"), true); + compare("services.redis is map", pServices->getElement("redis")->isMap(), true); + compare("services.redis keys size 4", pServices->getElement("redis")->getKeys().size(), 4); + + WsjcppYamlNode *pRedis = pServices->getElement("redis"); + compare("has services.redis.image", pRedis->hasElement("image"), true); + compare("has services.redis.container_name", pRedis->hasElement("container_name"), true); + compare("has services.redis.ports", pRedis->hasElement("ports"), true); + compare("has services.redis.networks", pRedis->hasElement("networks"), true); + + compare("services.redis.image value", pRedis->getElement("image")->getValue(), "redis:alpine"); + compare("services.redis.container_name", pRedis->getElement("container_name")->getValue(), "redis"); + + WsjcppYamlNode *pRedisPorts = pRedis->getElement("ports"); + // TODO bug #17 + compare("services.redis.ports is value", pRedisPorts->isValue(), true); + compare("services.redis.ports value", pRedisPorts->getValue(), "[\"6379\"]"); + + WsjcppYamlNode *pRedisNetworks = pRedis->getElement("networks"); + compare("services.redis.networks size 1", pRedisNetworks->getLength(), 1); + compare("services.redis.networks val 0", pRedisNetworks->getElement(0)->getValue(), "back-tier"); + } + + // services.db + { + compare("has services.db", pServices->hasElement("db"), true); + compare("has services.db is map", pServices->getElement("db")->isMap(), true); + compare("services.db keys size 5", pServices->getElement("db")->getKeys().size(), 5); + + WsjcppYamlNode *pServicesDb = pServices->getElement("db"); + + compare("has services.db.image", pServicesDb->hasElement("image"), true); + compare("services.db.image value", pServicesDb->getElement("image")->getValue(), "postgres:9.4"); + compare("services.db.container_name", pServicesDb->getElement("container_name")->getValue(), "db"); + + compare("has services.db.environment", pServicesDb->hasElement("environment"), true); + compare("services.db.environment is map", pServicesDb->getElement("environment")->isMap(), true); + + WsjcppYamlNode *pDbEnvironment = pServicesDb->getElement("environment"); + + compare("has services.db.environment.POSTGRES_USER", pDbEnvironment->hasElement("POSTGRES_USER"), true); + compare("services.db.environment.POSTGRES_USER", pDbEnvironment->getElement("POSTGRES_USER")->getValue(), "postgres"); + + compare("has services.db.environment.POSTGRES_PASSWORD", pDbEnvironment->hasElement("POSTGRES_PASSWORD"), true); + compare("services.db.environment.POSTGRES_PASSWORD", pDbEnvironment->getElement("POSTGRES_PASSWORD")->getValue(), "postgres"); + + compare("has services.db.volumes", pServicesDb->hasElement("volumes"), true); + compare("services.db.volumes is array", pServicesDb->getElement("volumes")->isArray(), true); + + WsjcppYamlNode *pDbVolumes = pServicesDb->getElement("volumes"); + compare("services.db.volumes size 1", pDbVolumes->getLength(), 1); + compare("services.db.volumes val 0", pDbVolumes->getElement(0)->getValue(), "db-data:/var/lib/postgresql/data"); + + compare("has services.db.networks", pServicesDb->hasElement("networks"), true); + compare("services.db.networks is array", pServicesDb->getElement("networks")->isArray(), true); + + WsjcppYamlNode *pDbNetworks = pServicesDb->getElement("networks"); + compare("services.db.networks size 1", pDbNetworks->getLength(), 1); + compare("services.db.networks val 0", pDbNetworks->getElement(0)->getValue(), "back-tier"); + } + + // volumes + { + compare("has volumes", yaml.getRoot()->hasElement("volumes"), true); + compare("has volumes is map", yaml.getRoot()->getElement("volumes")->isMap(), true); + + WsjcppYamlNode *pVolumes = yaml.getRoot()->getElement("volumes"); + + compare("has volumes.db-data", pVolumes->hasElement("db-data"), true); + compare("has volumes.db-data is undefined", pVolumes->getElement("db-data")->isUndefined(), true); + compare("has volumes keys size 1", pVolumes->getKeys().size(), 1); + } + + // networks + { + compare("has networks", yaml.getRoot()->hasElement("networks"), true); + compare("has networks is map", yaml.getRoot()->getElement("networks")->isMap(), true); + + WsjcppYamlNode *pNeworks = yaml.getRoot()->getElement("networks"); + compare("has networks keys size 2", pNeworks->getKeys().size(), 2); + + compare("has networks.front-tier", pNeworks->hasElement("front-tier"), true); + compare("has networks.front-tier is undefined", pNeworks->getElement("front-tier")->isUndefined(), true); + + compare("has networks.back-tier", pNeworks->hasElement("back-tier"), true); + compare("has networks.back-tier is undefined", pNeworks->getElement("back-tier")->isUndefined(), true); + } +} + +// --------------------------------------------------------------------- + +bool UnitTestReadYaml::doAfterTest() { + // do somethig after test + return true; +} + + diff --git a/unit-tests.wsjcpp/src/unit_test_remove_element_for_map.cpp b/unit-tests.wsjcpp/src/unit_test_remove_element_for_map.cpp new file mode 100644 index 0000000..4029047 --- /dev/null +++ b/unit-tests.wsjcpp/src/unit_test_remove_element_for_map.cpp @@ -0,0 +1,92 @@ + +#include +#include +#include + +// --------------------------------------------------------------------- +// UnitTestRemoveElementForMap + +class UnitTestRemoveElementForMap : public WsjcppUnitTestBase { + public: + UnitTestRemoveElementForMap(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + +REGISTRY_WSJCPP_UNIT_TEST(UnitTestRemoveElementForMap) + +UnitTestRemoveElementForMap::UnitTestRemoveElementForMap() + : WsjcppUnitTestBase("UnitTestRemoveElementForMap") { +} + +// --------------------------------------------------------------------- + +bool UnitTestRemoveElementForMap::doBeforeTest() { + // do something before test + return true; +} + +// --------------------------------------------------------------------- + +void UnitTestRemoveElementForMap::executeTest() { + std::string sTestYaml = + "# Some comment 1\n" + "map1: \n" + " map11: \n" + " map111: \n" + " param1111: v1111\n" + " param1112: v1112\n" + " map112: \n" + " param1121: v1121\n" + " param1122: v1122\n" + " map113: \n" + " param1131: v1131\n" + " param1132: v1132\n" + " map12: \n" + " param121: v121\n" + " param122: v122\n" + " map123: \n" + " param1231: v1231\n" + " param1232: v1232\n" + "param2: v2 # some comment 2\n" + "\n" // empty line + ; + + WsjcppYaml yaml; + std::string sError; + if (!compare("Error parsing", yaml.loadFromString("rm_elem_in_map", sTestYaml, sError), true)) { + WsjcppLog::err(TAG, sError); + return; + } + + WsjcppYamlNode *pMap1 = yaml.getRoot()->getElement("map1"); + WsjcppYamlNode *pMap11 = pMap1->getElement("map11"); + + compare("has map111", pMap11->hasElement("map111"), true); + compare("has map112", pMap11->hasElement("map112"), true); + compare("has map113", pMap11->hasElement("map113"), true); + pMap11->removeElement("map112"); + + compare("has map111", pMap11->hasElement("map111"), true); + compare("has map112", pMap11->hasElement("map112"), false); + compare("has map113", pMap11->hasElement("map113"), true); + pMap11->removeElement("map111"); + + compare("has map111", pMap11->hasElement("map111"), false); + compare("has map112", pMap11->hasElement("map112"), false); + compare("has map113", pMap11->hasElement("map113"), true); + + compare("has map11", pMap1->hasElement("map11"), true); + yaml.getRoot()->getElement("map1")->removeElement("map11"); + compare("has map11", pMap1->hasElement("map11"), false); +} + +// --------------------------------------------------------------------- + +bool UnitTestRemoveElementForMap::doAfterTest() { + // do somethig after test + return true; +} + + diff --git a/unit-tests.wsjcpp/src/unit_test_remove_element_in_array.cpp b/unit-tests.wsjcpp/src/unit_test_remove_element_in_array.cpp new file mode 100644 index 0000000..28f95de --- /dev/null +++ b/unit-tests.wsjcpp/src/unit_test_remove_element_in_array.cpp @@ -0,0 +1,65 @@ + +#include +#include +#include + +// --------------------------------------------------------------------- +// UnitTestRemoveElementInArray + +class UnitTestRemoveElementInArray : public WsjcppUnitTestBase { + public: + UnitTestRemoveElementInArray(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + +REGISTRY_WSJCPP_UNIT_TEST(UnitTestRemoveElementInArray) + +UnitTestRemoveElementInArray::UnitTestRemoveElementInArray() + : WsjcppUnitTestBase("UnitTestRemoveElementInArray") { +} + +// --------------------------------------------------------------------- + +bool UnitTestRemoveElementInArray::doBeforeTest() { + // do something before test + return true; +} + +// --------------------------------------------------------------------- + +void UnitTestRemoveElementInArray::executeTest() { + + std::string sFilepath = "./data-tests/remove-element-in-array.yml"; + WsjcppYaml yaml; + std::string sError; + if (!compare("Error parsing", yaml.loadFromFile(sFilepath, sError), true)) { + WsjcppLog::err(TAG, sError); + return; + } + + + WsjcppYamlNode *pArr1 = yaml.getRoot()->getElement("arr1"); + compare("arr1 len", pArr1->getLength(), 4); + compare("arr1 name0 ", pArr1->getElement(0)->getElement("name")->getValue(), "i1"); + compare("arr1 name1 ", pArr1->getElement(1)->getElement("name")->getValue(), "i2"); + compare("arr1 name2 ", pArr1->getElement(2)->getElement("name")->getValue(), "i3"); + compare("arr1 name3 ", pArr1->getElement(3)->getValue(), "very different array items type"); + + pArr1->removeElement(1); + + compare("arr1 len", pArr1->getLength(), 3); + compare("arr1 name0 ", pArr1->getElement(0)->getElement("name")->getValue(), "i1"); + compare("arr1 name1 ", pArr1->getElement(1)->getElement("name")->getValue(), "i3"); + compare("arr1 name2 ", pArr1->getElement(2)->getValue(), "very different array items type"); +} + +// --------------------------------------------------------------------- + +bool UnitTestRemoveElementInArray::doAfterTest() { + // do somethig after test + return true; +} + + diff --git a/unit-tests.wsjcpp/src/unit_test_tag_names.cpp b/unit-tests.wsjcpp/src/unit_test_tag_names.cpp new file mode 100644 index 0000000..0770534 --- /dev/null +++ b/unit-tests.wsjcpp/src/unit_test_tag_names.cpp @@ -0,0 +1,65 @@ + +#include +#include +#include + +// --------------------------------------------------------------------- +// UnitTestTagNames + +class UnitTestTagNames : public WsjcppUnitTestBase { + public: + UnitTestTagNames(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + +REGISTRY_WSJCPP_UNIT_TEST(UnitTestTagNames) + +UnitTestTagNames::UnitTestTagNames() + : WsjcppUnitTestBase("UnitTestTagNames") { +} + +// --------------------------------------------------------------------- + +bool UnitTestTagNames::doBeforeTest() { + // do something before test + return true; +} + +// --------------------------------------------------------------------- + +void UnitTestTagNames::executeTest() { + + std::string sTestYaml = "./test10: one"; + WsjcppYaml yaml; + std::string sError; + // wrong + compare("wrong name", yaml.loadFromString("wrong name", "./test10: one", sError), false); + compare("name use quotes 1", yaml.loadFromString("name use quotes", "\"./test10\": one", sError), true); + compare("name use quotes 2 - wrong", yaml.loadFromString("name use quotes", "\"./te\"st10\": one", sError), false); + compare("name use quotes 3", yaml.loadFromString("name use quotes", "\"./te\\\"st10\": one", sError), true); + + compare("array", yaml.loadFromString("array", + "arr1: \n" + " - ./te:11\n" + " - \"./te\":11\n" + , sError), true); + + compare("arr1 is array", yaml.getRoot()->getElement("arr1")->isArray(), true); + compare("arr1 size 2", yaml.getRoot()->getElement("arr1")->getLength(), 2); + compare("arr1 el 0 is value", yaml.getRoot()->getElement("arr1")->getElement(0)->isValue(), true); + compare("arr1 el 0 is value", yaml.getRoot()->getElement("arr1")->getElement(0)->getValue(), "./te:11"); + compare("arr1 el 1 is map", yaml.getRoot()->getElement("arr1")->getElement(1)->isMap(), true); + compare("arr1 el 1 is map", yaml.getRoot()->getElement("arr1")->getElement(1)->hasElement("./te"), true); + compare("arr1 el 1 is map", yaml.getRoot()->getElement("arr1")->getElement(1)->getElement("./te")->getValue(), "11"); +} + +// --------------------------------------------------------------------- + +bool UnitTestTagNames::doAfterTest() { + // do somethig after test + return true; +} + + diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_all.cpp b/unit-tests.wsjcpp/src/unit_test_yaml_parser_all.cpp index 0a11dba..9f2894b 100644 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_all.cpp +++ b/unit-tests.wsjcpp/src/unit_test_yaml_parser_all.cpp @@ -1,9 +1,20 @@ -#include "unit_test_yaml_parser_all.h" +#include #include #include -#include #include +// --------------------------------------------------------------------- +// UnitTestYamlParserAll + +class UnitTestYamlParserAll : public WsjcppUnitTestBase { + public: + UnitTestYamlParserAll(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + + REGISTRY_WSJCPP_UNIT_TEST(UnitTestYamlParserAll) UnitTestYamlParserAll::UnitTestYamlParserAll() @@ -14,7 +25,7 @@ UnitTestYamlParserAll::UnitTestYamlParserAll() // --------------------------------------------------------------------- bool UnitTestYamlParserAll::doBeforeTest() { - // nothing + // do something before test return true; } @@ -22,7 +33,7 @@ bool UnitTestYamlParserAll::doBeforeTest() { void UnitTestYamlParserAll::executeTest() { - std::string g_sTestYaml = + std::string sTestYaml = "# Some comment 1\n" "test10: one\n" "test20: two # some comment 2\n" @@ -48,16 +59,19 @@ void UnitTestYamlParserAll::executeTest() { ; WsjcppYaml yaml; - if (!compare("Error parsing", yaml.loadFromString(g_sTestYaml), true)) { + std::string sError; + if (!compare("Error parsing", yaml.loadFromString("parse_all", sTestYaml, sError), true)) { + WsjcppLog::err(TAG, sError); return; } - std::string sSaved = ""; - if (yaml.saveToString(sSaved)) { - WsjcppLog::info(TAG, "\n>>>>\n" + sSaved); + std::string sSaved1 = ""; + if (!compare("Error saving", yaml.saveToString(sSaved1), true)) { + compare("yaml_saved 2-test", sSaved1, sTestYaml); + return; } - WsjcppYamlItem *pItem = nullptr; + WsjcppYamlNode *pItem = nullptr; compare("test10", yaml.getRoot()->getElement("test10")->getValue(), "one"); compare("test20", yaml.getRoot()->getElement("test20")->getValue(), "two"); @@ -83,15 +97,15 @@ void UnitTestYamlParserAll::executeTest() { pItem = yaml.getRoot()->getElement("map60")->getElement("test80"); compare("test80_comment", pItem->getValue(), "opa2"); - sSaved = ""; - if (compare("save yaml", yaml.saveToString(sSaved), true)) { - compare("yaml_save", sSaved, g_sTestYaml); + std::string sSaved2 = ""; + if (compare("saving yaml", yaml.saveToString(sSaved2), true)) { + compare("yaml_saved 1-2", sSaved1, sSaved2); } } // --------------------------------------------------------------------- bool UnitTestYamlParserAll::doAfterTest() { - // nothing + // do something after test return true; } diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_all.h b/unit-tests.wsjcpp/src/unit_test_yaml_parser_all.h deleted file mode 100644 index 2383eef..0000000 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_all.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UNIT_TEST_YAML_PARSER_ALL_H -#define UNIT_TEST_YAML_PARSER_ALL_H - -#include - -class UnitTestYamlParserAll : public WsjcppUnitTestBase { - public: - UnitTestYamlParserAll(); - virtual bool doBeforeTest() override; - virtual void executeTest() override; - virtual bool doAfterTest() override; -}; - -#endif // UNIT_TEST_YAML_PARSER_ALL_H \ No newline at end of file diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_array_included_map.cpp b/unit-tests.wsjcpp/src/unit_test_yaml_parser_array_included_map.cpp index 1467d64..b160229 100644 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_array_included_map.cpp +++ b/unit-tests.wsjcpp/src/unit_test_yaml_parser_array_included_map.cpp @@ -1,8 +1,19 @@ -#include "unit_test_yaml_parser_array_included_map.h" +#include #include #include #include +// --------------------------------------------------------------------- +// UnitTestYamlParserArrayIncludedMap + +class UnitTestYamlParserArrayIncludedMap : public WsjcppUnitTestBase { + public: + UnitTestYamlParserArrayIncludedMap(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + REGISTRY_WSJCPP_UNIT_TEST(UnitTestYamlParserArrayIncludedMap) UnitTestYamlParserArrayIncludedMap::UnitTestYamlParserArrayIncludedMap() @@ -21,7 +32,7 @@ bool UnitTestYamlParserArrayIncludedMap::doBeforeTest() { void UnitTestYamlParserArrayIncludedMap::executeTest() { - std::string g_sTestYaml = + std::string sTestYaml = "#test array included map\n" "param1: none value1 # it's value for something # olala \n" "array-test2 : # some comment 2 \n" @@ -38,11 +49,13 @@ void UnitTestYamlParserArrayIncludedMap::executeTest() { ; WsjcppYaml yaml; - if (!compare("Error parsing", yaml.loadFromString(g_sTestYaml), true)) { + std::string sError; + if (!compare("Error parsing", yaml.loadFromString("map_in_array", sTestYaml, sError), true)) { + WsjcppLog::err(TAG, sError); return; } - WsjcppYamlItem *pItem = nullptr; + WsjcppYamlNode *pItem = nullptr; compare("param1-value", yaml.getRoot()->getElement("param1")->getValue(), "none value1"); compare("param1-line", yaml.getRoot()->getElement("param1")->getPlaceInFile().getLine(), "param1: none value1 # it's value for something # olala "); @@ -57,14 +70,14 @@ void UnitTestYamlParserArrayIncludedMap::executeTest() { compare("array-test2-element0-comment", pItem->getComment(), "comment v21"); pItem = yaml.getRoot()->getElement("array-test2")->getElement(1); - compare("array-test2-element1-value", yaml["array-test2"][1].getValue(), "value22"); - compare("array-test2-element1-comment", yaml["array-test2"][1].getComment(), "comment v22"); + compare("array-test2-element1-value", yaml.getRoot()->getElement("array-test2")->getElement(1)->getValue(), "value22"); + compare("array-test2-element1-comment", yaml.getRoot()->getElement("array-test2")->getElement(1)->getComment(), "comment v22"); pItem = yaml.getRoot()->getElement("array-test2")->getElement(2); compare("array-test2-element2-value", pItem->getValue(), "true"); compare("array-test2-element2-comment", pItem->getComment(), "comment true"); - compare("array-and-map-length", yaml["array-and-map"].getLength(), 2); + compare("array-and-map-length", yaml.getRoot()->getElement("array-and-map")->getLength(), 2); pItem = yaml.getRoot()->getElement("array-and-map")->getElement(0); compare("array-and-map-element0-value", pItem->getElement("submap-param1")->getValue(), "v01"); diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_array_included_map.h b/unit-tests.wsjcpp/src/unit_test_yaml_parser_array_included_map.h deleted file mode 100644 index 97cfbc1..0000000 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_array_included_map.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UNIT_TEST_YAML_PARSER_ARRAY_INCLUDED_MAP_H -#define UNIT_TEST_YAML_PARSER_ARRAY_INCLUDED_MAP_H - -#include - -class UnitTestYamlParserArrayIncludedMap : public WsjcppUnitTestBase { - public: - UnitTestYamlParserArrayIncludedMap(); - virtual bool doBeforeTest() override; - virtual void executeTest() override; - virtual bool doAfterTest() override; -}; - -#endif // UNIT_TEST_YAML_PARSER_ARRAY_INCLUDED_MAP_H \ No newline at end of file diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_comments.cpp b/unit-tests.wsjcpp/src/unit_test_yaml_parser_comments.cpp index b0ad677..0c11427 100644 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_comments.cpp +++ b/unit-tests.wsjcpp/src/unit_test_yaml_parser_comments.cpp @@ -1,8 +1,19 @@ -#include "unit_test_yaml_parser_comments.h" +#include #include #include #include +// --------------------------------------------------------------------- +// UnitTestYamlParserComments + +class UnitTestYamlParserComments : public WsjcppUnitTestBase { + public: + UnitTestYamlParserComments(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + REGISTRY_WSJCPP_UNIT_TEST(UnitTestYamlParserComments) UnitTestYamlParserComments::UnitTestYamlParserComments() @@ -21,7 +32,7 @@ bool UnitTestYamlParserComments::doBeforeTest() { void UnitTestYamlParserComments::executeTest() { - std::string g_sTestYaml = + std::string sTestYaml = "# Some comment 1\n" "param1: value1 # comment 2 # comment\n" "param2: value2 # some \"comment 3\"\n" @@ -40,32 +51,34 @@ void UnitTestYamlParserComments::executeTest() { WsjcppYaml yaml; - if (!compare("Error parsing", yaml.loadFromString(g_sTestYaml), true)) { + std::string sError; + if (!compare("Error parsing", yaml.loadFromString("comments", sTestYaml, sError), true)) { + WsjcppLog::err(TAG, sError); return; } // TODO: .findLine(0) - compare("param1", yaml["param1"].getValue(), "value1"); - compare("param1", yaml["param1"].getComment(), "comment 2 # comment"); + compare("param1", yaml.getRoot()->getElement("param1")->getValue(), "value1"); + compare("param1", yaml.getRoot()->getElement("param1")->getComment(), "comment 2 # comment"); - compare("param2", yaml["param2"].getValue(), "value2"); - compare("param2", yaml["param2"].getComment(), "some \"comment 3\""); + compare("param2", yaml.getRoot()->getElement("param2")->getValue(), "value2"); + compare("param2", yaml.getRoot()->getElement("param2")->getComment(), "some \"comment 3\""); - compare("array1-comment", yaml["array1"].getComment(), "comment 5"); - compare("array1-length", yaml["array1"].getLength(), 2); - compare("array1-element0-value", yaml["array1"][0].getValue(), "val1"); - compare("array1-element0-comment", yaml["array1"][0].getComment(), "comment 6"); + compare("array1-comment", yaml.getRoot()->getElement("array1")->getComment(), "comment 5"); + compare("array1-length", yaml.getRoot()->getElement("array1")->getLength(), 2); + compare("array1-element0-value", yaml.getRoot()->getElement("array1")->getElement(0)->getValue(), "val1"); + compare("array1-element0-comment", yaml.getRoot()->getElement("array1")->getElement(0)->getComment(), "comment 6"); // TODO: .findLine(7) - compare("array1-element1-value", yaml["array1"][1].getValue(), "val2"); - compare("array1-element1-comment", yaml["array1"][1].getComment(), "comment 8"); + compare("array1-element1-value", yaml.getRoot()->getElement("array1")->getElement(1)->getValue(), "val2"); + compare("array1-element1-comment", yaml.getRoot()->getElement("array1")->getElement(1)->getComment(), "comment 8"); - compare("map1-comment", yaml["map1"].getComment(), "comment 9"); - compare("map1-p1-comment", yaml["map1"]["p1"].getComment(), "comment 10"); - compare("map1-p2-comment", yaml["map1"]["p2"].getComment(), "comment 12"); + compare("map1-comment", yaml.getRoot()->getElement("map1")->getComment(), "comment 9"); + compare("map1-p1-comment", yaml.getRoot()->getElement("map1")->getElement("p1")->getComment(), "comment 10"); + compare("map1-p2-comment", yaml.getRoot()->getElement("map1")->getElement("p2")->getComment(), "comment 12"); // compare("param2", yaml.getRoot()->getElement("param2")->getValue(), "value2"); @@ -81,7 +94,7 @@ void UnitTestYamlParserComments::executeTest() { "array1: # comment 5\n" " - val1 # comment 6\n" " # comment 7\n" - " \n" + "\n" " - val2 # comment 8\n" "map1: # comment 9\n" " p1: val 1 # comment 10\n" diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_comments.h b/unit-tests.wsjcpp/src/unit_test_yaml_parser_comments.h deleted file mode 100644 index 0acc039..0000000 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_comments.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UNIT_TEST_YAML_PARSER_COMMENTS_H -#define UNIT_TEST_YAML_PARSER_COMMENTS_H - -#include - -class UnitTestYamlParserComments : public WsjcppUnitTestBase { - public: - UnitTestYamlParserComments(); - virtual bool doBeforeTest() override; - virtual void executeTest() override; - virtual bool doAfterTest() override; -}; - -#endif // UNIT_TEST_YAML_PARSER_COMMENTS_H \ No newline at end of file diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_hierarchical_map.cpp b/unit-tests.wsjcpp/src/unit_test_yaml_parser_hierarchical_map.cpp index d218a4f..7ea6895 100644 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_hierarchical_map.cpp +++ b/unit-tests.wsjcpp/src/unit_test_yaml_parser_hierarchical_map.cpp @@ -1,8 +1,19 @@ -#include "unit_test_yaml_parser_hierarchical_map.h" +#include #include #include #include +// --------------------------------------------------------------------- +// UnitTestYamlParserHierarchicalMap + +class UnitTestYamlParserHierarchicalMap : public WsjcppUnitTestBase { + public: + UnitTestYamlParserHierarchicalMap(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + REGISTRY_WSJCPP_UNIT_TEST(UnitTestYamlParserHierarchicalMap) UnitTestYamlParserHierarchicalMap::UnitTestYamlParserHierarchicalMap() @@ -21,7 +32,7 @@ bool UnitTestYamlParserHierarchicalMap::doBeforeTest() { void UnitTestYamlParserHierarchicalMap::executeTest() { - std::string g_sTestYaml = + std::string sTestYaml = "# Some comment 1\n" "map1: \n" " map11: \n" @@ -45,11 +56,13 @@ void UnitTestYamlParserHierarchicalMap::executeTest() { ; WsjcppYaml yaml; - if (!compare("Error parsing", yaml.loadFromString(g_sTestYaml), true)) { + std::string sError; + if (!compare("Error parsing", yaml.loadFromString("hard_map", sTestYaml, sError), true)) { + WsjcppLog::err(TAG, sError); return; } - WsjcppYamlItem *pItem = nullptr; + WsjcppYamlNode *pItem = nullptr; pItem = yaml.getRoot()->getElement("map1")->getElement("map11")->getElement("map111"); compare("param1111", pItem->getElement("param1111")->getValue(), "v1111"); @@ -96,7 +109,7 @@ void UnitTestYamlParserHierarchicalMap::executeTest() { " map123:\n" " param1231: v1231\n" " param1232: v1232\n" - "param2: v2 # some comment 2" + "param2: v2 # some comment 2\n" ); } } diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_hierarchical_map.h b/unit-tests.wsjcpp/src/unit_test_yaml_parser_hierarchical_map.h deleted file mode 100644 index f3b7541..0000000 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_hierarchical_map.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UNIT_TEST_YAML_PARSER_HIERARCHICAL_MAP_H -#define UNIT_TEST_YAML_PARSER_HIERARCHICAL_MAP_H - -#include - -class UnitTestYamlParserHierarchicalMap : public WsjcppUnitTestBase { - public: - UnitTestYamlParserHierarchicalMap(); - virtual bool doBeforeTest() override; - virtual void executeTest() override; - virtual bool doAfterTest() override; -}; - -#endif // UNIT_TEST_YAML_PARSER_HIERARCHICAL_MAP_H \ No newline at end of file diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_quotes.cpp b/unit-tests.wsjcpp/src/unit_test_yaml_parser_quotes.cpp index b913b9f..dbfc4d1 100644 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_quotes.cpp +++ b/unit-tests.wsjcpp/src/unit_test_yaml_parser_quotes.cpp @@ -1,8 +1,19 @@ -#include "unit_test_yaml_parser_quotes.h" +#include #include #include #include +// --------------------------------------------------------------------- +// UnitTestYamlParserQuotes + +class UnitTestYamlParserQuotes : public WsjcppUnitTestBase { + public: + UnitTestYamlParserQuotes(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + REGISTRY_WSJCPP_UNIT_TEST(UnitTestYamlParserQuotes) UnitTestYamlParserQuotes::UnitTestYamlParserQuotes() @@ -21,11 +32,13 @@ bool UnitTestYamlParserQuotes::doBeforeTest() { void UnitTestYamlParserQuotes::executeTest() { - std::string g_sTestYaml = + std::string sTestYaml = "# Some comment 1\n" "param1: \"value1\" # v1\n" "param2: \" #$!!!value2\" # val 2\n" "\" param3 olala\" : val 3 # val 3*** \n" + "param4: ' #$!!!value4' # val 4\n" + "'param5 aha': ' #$!!!value5' # val 5\n" "url: \"https://github.com/wsjcpp/wsjcpp-yaml\"\n" "issues: https://github.com/wsjcpp/wsjcpp-yaml/issues\n" "empty: \"\"\n" @@ -36,26 +49,31 @@ void UnitTestYamlParserQuotes::executeTest() { WsjcppYaml yaml; - if (!compare("Error parsing", yaml.loadFromString(g_sTestYaml), true)) { + std::string sError; + if (!compare("Error parsing", yaml.loadFromString("parse_quotes", sTestYaml, sError), true)) { + WsjcppLog::err(TAG, sError); return; } // TODO: .findLine(0) - compare("param1", yaml["param1"].getValue(), "value1"); - compare("param1", yaml["param1"].getComment(), "v1"); + compare("param1", yaml.getRoot()->getElement("param1")->getValue(), "value1"); + compare("param1", yaml.getRoot()->getElement("param1")->getComment(), "v1"); - compare("param2", yaml["param2"].getValue(), " #$!!!value2"); - compare("param2", yaml["param2"].getComment(), "val 2"); + compare("param2", yaml.getRoot()->getElement("param2")->getValue(), " #$!!!value2"); + compare("param2", yaml.getRoot()->getElement("param2")->getComment(), "val 2"); + + compare(" param3 olala", yaml.getRoot()->getElement(" param3 olala")->getValue(), "val 3"); + compare(" param3 olala", yaml.getRoot()->getElement(" param3 olala")->getComment(), "val 3***"); - compare(" param3 olala", yaml[" param3 olala"].getValue(), "val 3"); - compare(" param3 olala", yaml[" param3 olala"].getComment(), "val 3***"); + compare("param4 val", yaml.getRoot()->getElement("param4")->getValue(), " #$!!!value4"); + compare("param4 comment", yaml.getRoot()->getElement("param4")->getValue(), " #$!!!value4"); - compare("url-value", yaml["url"].getValue(), "https://github.com/wsjcpp/wsjcpp-yaml"); - compare("issues-value", yaml["issues"].getValue(), "https://github.com/wsjcpp/wsjcpp-yaml/issues"); - compare("empty-value", yaml["empty"].getValue(), ""); + compare("url-value", yaml.getRoot()->getElement("url")->getValue(), "https://github.com/wsjcpp/wsjcpp-yaml"); + compare("issues-value", yaml.getRoot()->getElement("issues")->getValue(), "https://github.com/wsjcpp/wsjcpp-yaml/issues"); + compare("empty-value", yaml.getRoot()->getElement("empty")->getValue(), ""); - compare("array-element0-value", yaml["array"][0].getValue(), "https://github.com/wsjcpp/wsjcpp-core:v0.0.1"); + compare("array-element0-value", yaml.getRoot()->getElement("array")->getElement(0)->getValue(), "https://github.com/wsjcpp/wsjcpp-core:v0.0.1"); std::string sSaved = ""; compare("save yaml", yaml.saveToString(sSaved), true); @@ -64,12 +82,14 @@ void UnitTestYamlParserQuotes::executeTest() { "param1: \"value1\" # v1\n" "param2: \" #$!!!value2\" # val 2\n" "\" param3 olala\": val 3 # val 3***\n" + "param4: ' #$!!!value4' # val 4\n" + "'param5 aha': ' #$!!!value5' # val 5\n" "url: \"https://github.com/wsjcpp/wsjcpp-yaml\"\n" "issues: https://github.com/wsjcpp/wsjcpp-yaml/issues\n" "empty: \"\"\n" "array:\n" " - \"https://github.com/wsjcpp/wsjcpp-core:v0.0.1\"" - ); + ); } // --------------------------------------------------------------------- diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_quotes.h b/unit-tests.wsjcpp/src/unit_test_yaml_parser_quotes.h deleted file mode 100644 index 21d379c..0000000 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_quotes.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UNIT_TEST_YAML_PARSER_QUOTES_H -#define UNIT_TEST_YAML_PARSER_QUOTES_H - -#include - -class UnitTestYamlParserQuotes : public WsjcppUnitTestBase { - public: - UnitTestYamlParserQuotes(); - virtual bool doBeforeTest() override; - virtual void executeTest() override; - virtual bool doAfterTest() override; -}; - -#endif // UNIT_TEST_YAML_PARSER_QUOTES_H \ No newline at end of file diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_array.cpp b/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_array.cpp index 76d4013..a9f5b38 100644 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_array.cpp +++ b/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_array.cpp @@ -1,8 +1,19 @@ -#include "unit_test_yaml_parser_simple_array.h" +#include #include #include #include +// --------------------------------------------------------------------- +// UnitTestYamlParserSimpleArray + +class UnitTestYamlParserSimpleArray : public WsjcppUnitTestBase { + public: + UnitTestYamlParserSimpleArray(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + REGISTRY_WSJCPP_UNIT_TEST(UnitTestYamlParserSimpleArray) UnitTestYamlParserSimpleArray::UnitTestYamlParserSimpleArray() @@ -20,28 +31,16 @@ bool UnitTestYamlParserSimpleArray::doBeforeTest() { // --------------------------------------------------------------------- void UnitTestYamlParserSimpleArray::executeTest() { - - std::string g_sTestYaml = - "# simple array test\n" - "param1: none value1 # it's value for something # olala \n" - "array-test2 : # some comment 2 \n" - " - value21 # comment v21 \n" - " - value22 # comment v22 \n" - " - true # comment true \n" - " # some\n" - " - falsesome \n" - " - free@free \n" - " - # empty \n" - " - 1\n" - "param2: val2 # value 2 \n" - ; - + + std::string sFilepath = "./data-tests/parser-simple-array.yml"; WsjcppYaml yaml; - if (!compare("Error parsing", yaml.loadFromString(g_sTestYaml), true)) { + std::string sError; + if (!compare("Error parsing", yaml.loadFromFile(sFilepath, sError), true)) { + WsjcppLog::err(TAG, sError); return; } - WsjcppYamlItem *pItem = nullptr; + WsjcppYamlNode *pItem = nullptr; compare("param1-value", yaml.getRoot()->getElement("param1")->getValue(), "none value1"); compare("param1-line", yaml.getRoot()->getElement("param1")->getPlaceInFile().getLine(), "param1: none value1 # it's value for something # olala "); @@ -59,30 +58,30 @@ void UnitTestYamlParserSimpleArray::executeTest() { compare("array-test2-element1-value", pItem->getValue(), "value22"); compare("array-test2-element1-comment", pItem->getComment(), "comment v22"); - compare("array-test2-element2-value", yaml["array-test2"][2].getValue(), "true"); - compare("array-test2-element2-line", yaml["array-test2"][2].getPlaceInFile().getLine(), " - true # comment true "); - compare("array-test2-element2-original-number-of-line", yaml["array-test2"][2].getPlaceInFile().getNumberOfLine(), 5); - compare("array-test2-element2-comment", yaml["array-test2"][2].getComment(), "comment true"); + compare("array-test2-element2-value", yaml.getRoot()->getElement("array-test2")->getElement(2)->getValue(), "true"); + compare("array-test2-element2-line", yaml.getRoot()->getElement("array-test2")->getElement(2)->getPlaceInFile().getLine(), " - true # comment true "); + compare("array-test2-element2-original-number-of-line", yaml.getRoot()->getElement("array-test2")->getElement(2)->getPlaceInFile().getNumberOfLine(), 5); + compare("array-test2-element2-comment", yaml.getRoot()->getElement("array-test2")->getElement(2)->getComment(), "comment true"); - compare("array-test2-element3-value", yaml["array-test2"][3].getValue(), "falsesome"); - compare("array-test2-element3-line", yaml["array-test2"][3].getPlaceInFile().getLine(), " - falsesome "); - compare("array-test2-element3-original-number-of-line", yaml["array-test2"][3].getPlaceInFile().getNumberOfLine(), 7); - compare("array-test2-element3-comment", yaml["array-test2"][3].getComment(), ""); + compare("array-test2-element3-value", yaml.getRoot()->getElement("array-test2")->getElement(3)->getValue(), "falsesome"); + compare("array-test2-element3-line", yaml.getRoot()->getElement("array-test2")->getElement(3)->getPlaceInFile().getLine(), " - falsesome "); + compare("array-test2-element3-original-number-of-line", yaml.getRoot()->getElement("array-test2")->getElement(3)->getPlaceInFile().getNumberOfLine(), 7); + compare("array-test2-element3-comment", yaml.getRoot()->getElement("array-test2")->getElement(3)->getComment(), ""); - compare("array-test2-element4-value", yaml["array-test2"][4].getValue(), "free@free"); - compare("array-test2-element4-line", yaml["array-test2"][4].getPlaceInFile().getLine(), " - free@free "); - compare("array-test2-element4-original-number-of-line", yaml["array-test2"][4].getPlaceInFile().getNumberOfLine(), 8); - compare("array-test2-element4-comment", yaml["array-test2"][4].getComment(), ""); - - compare("array-test2-element5-value", yaml["array-test2"][5].getValue(), ""); - compare("array-test2-element5-line", yaml["array-test2"][5].getPlaceInFile().getLine(), " - # empty "); - compare("array-test2-element5-original-number-of-line", yaml["array-test2"][5].getPlaceInFile().getNumberOfLine(), 9); - compare("array-test2-element5-comment", yaml["array-test2"][5].getComment(), "empty"); - - compare("array-test2-element6-value", yaml["array-test2"][6].getValue(), "1"); - compare("array-test2-element6-line", yaml["array-test2"][6].getPlaceInFile().getLine(), " - 1"); - compare("array-test2-element6-original-number-of-line", yaml["array-test2"][6].getPlaceInFile().getNumberOfLine(), 10); - compare("array-test2-element6-comment", yaml["array-test2"][6].getComment(), ""); + compare("array-test2-element4-value", yaml.getRoot()->getElement("array-test2")->getElement(4)->getValue(), "free@free"); + compare("array-test2-element4-line", yaml.getRoot()->getElement("array-test2")->getElement(4)->getPlaceInFile().getLine(), " - free@free "); + compare("array-test2-element4-original-number-of-line", yaml.getRoot()->getElement("array-test2")->getElement(4)->getPlaceInFile().getNumberOfLine(), 8); + compare("array-test2-element4-comment", yaml.getRoot()->getElement("array-test2")->getElement(4)->getComment(), ""); + + compare("array-test2-element5-value", yaml.getRoot()->getElement("array-test2")->getElement(5)->getValue(), ""); + compare("array-test2-element5-line", yaml.getRoot()->getElement("array-test2")->getElement(5)->getPlaceInFile().getLine(), " - # empty "); + compare("array-test2-element5-original-number-of-line", yaml.getRoot()->getElement("array-test2")->getElement(5)->getPlaceInFile().getNumberOfLine(), 9); + compare("array-test2-element5-comment", yaml.getRoot()->getElement("array-test2")->getElement(5)->getComment(), "empty"); + + compare("array-test2-element6-value", yaml.getRoot()->getElement("array-test2")->getElement(6)->getValue(), "1"); + compare("array-test2-element6-line", yaml.getRoot()->getElement("array-test2")->getElement(6)->getPlaceInFile().getLine(), " - 1"); + compare("array-test2-element6-original-number-of-line", yaml.getRoot()->getElement("array-test2")->getElement(6)->getPlaceInFile().getNumberOfLine(), 10); + compare("array-test2-element6-comment", yaml.getRoot()->getElement("array-test2")->getElement(6)->getComment(), ""); compare("param2-value", yaml.getRoot()->getElement("param2")->getValue(), "val2"); compare("param2-line", yaml.getRoot()->getElement("param2")->getPlaceInFile().getLine(), "param2: val2 # value 2 "); diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_array.h b/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_array.h deleted file mode 100644 index a9f29f7..0000000 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_array.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UNIT_TEST_YAML_PARSER_SIMPLE_ARRAY_H -#define UNIT_TEST_YAML_PARSER_SIMPLE_ARRAY_H - -#include - -class UnitTestYamlParserSimpleArray : public WsjcppUnitTestBase { - public: - UnitTestYamlParserSimpleArray(); - virtual bool doBeforeTest() override; - virtual void executeTest() override; - virtual bool doAfterTest() override; -}; - -#endif // UNIT_TEST_YAML_PARSER_SIMPLE_ARRAY_H \ No newline at end of file diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_map.cpp b/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_map.cpp index 287ac6a..2730591 100644 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_map.cpp +++ b/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_map.cpp @@ -1,8 +1,19 @@ -#include "unit_test_yaml_parser_simple_map.h" +#include #include #include #include +// --------------------------------------------------------------------- +// UnitTestYamlParserSimpleMap + +class UnitTestYamlParserSimpleMap : public WsjcppUnitTestBase { + public: + UnitTestYamlParserSimpleMap(); + virtual bool doBeforeTest() override; + virtual void executeTest() override; + virtual bool doAfterTest() override; +}; + REGISTRY_WSJCPP_UNIT_TEST(UnitTestYamlParserSimpleMap) UnitTestYamlParserSimpleMap::UnitTestYamlParserSimpleMap() @@ -21,7 +32,7 @@ bool UnitTestYamlParserSimpleMap::doBeforeTest() { void UnitTestYamlParserSimpleMap::executeTest() { - std::string g_sTestYaml = + std::string sTestYaml = "# Some comment 1\n" "param1: value1\n" "param2: value2 # some comment 2\n" @@ -29,11 +40,13 @@ void UnitTestYamlParserSimpleMap::executeTest() { ; WsjcppYaml yaml; - if (!compare("Error parsing", yaml.loadFromString(g_sTestYaml), true)) { + std::string sError; + if (!compare("Error parsing", yaml.loadFromString("simple_map", sTestYaml, sError), true)) { + WsjcppLog::err(TAG, sError); return; } - WsjcppYamlItem *pItem = nullptr; + WsjcppYamlNode *pItem = nullptr; compare("param1", yaml.getRoot()->getElement("param1")->getValue(), "value1"); compare("param2", yaml.getRoot()->getElement("param2")->getValue(), "value2"); compare("param2", yaml.getRoot()->getElement("param2")->getComment(), "some comment 2"); @@ -44,7 +57,7 @@ void UnitTestYamlParserSimpleMap::executeTest() { compare("yaml_save", sSaved, "# Some comment 1\n" "param1: value1\n" - "param2: value2 # some comment 2" + "param2: value2 # some comment 2\n" ); } } diff --git a/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_map.h b/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_map.h deleted file mode 100644 index 1f74d69..0000000 --- a/unit-tests.wsjcpp/src/unit_test_yaml_parser_simple_map.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UNIT_TEST_YAML_PARSER_SIMPLE_MAP_H -#define UNIT_TEST_YAML_PARSER_SIMPLE_MAP_H - -#include - -class UnitTestYamlParserSimpleMap : public WsjcppUnitTestBase { - public: - UnitTestYamlParserSimpleMap(); - virtual bool doBeforeTest() override; - virtual void executeTest() override; - virtual bool doAfterTest() override; -}; - -#endif // UNIT_TEST_YAML_PARSER_SIMPLE_MAP_H \ No newline at end of file diff --git a/wsjcpp.yml b/wsjcpp.yml index be57f36..68fbc4e 100644 --- a/wsjcpp.yml +++ b/wsjcpp.yml @@ -1,30 +1,23 @@ wsjcpp_version: v0.0.1 cmake_minimum_required: 3.0 cmake_cxx_standard: 11 - name: wsjcpp-yaml version: v0.1.3 description: Read/Write yaml files issues: https://github.com/wsjcpp/wsjcpp-yaml/issues - repositories: - type: main url: "https://github.com/wsjcpp/wsjcpp-yaml" - keywords: - c++ - yaml - parser - reader - writer - authors: - name: Evgenii Sopov email: mrseakg@gmail.com -required-libraries: - - pthread - dependencies: - name: "wsjcpp-core" version: "v0.2.1" @@ -58,4 +51,21 @@ unit-tests: description: YamlParserAll - name: YamlParserArrayIncludedMap description: YamlParserArrayIncludedMap - + - name: "RemoveElementForMap" + description: "" + - name: "RemoveElementInArray" + description: "" + - name: "MemoryLeaks" + description: "" + - name: "ReadYaml" + description: "" + - name: "ReadWriteFile" + description: "" + - name: "Cursor" + description: "" + - name: "TagNames" + description: "" + - name: "Cleanup" + description: "" + - name: "AppendElements" + description: ""