mirror of
https://github.com/KingDuckZ/kamokan.git
synced 2024-12-27 21:35:41 +00:00
Add unit test for IniFile and improve parser.
The test still fails because for some reason the parser doesn't want to skip the trailing spaces in values.
This commit is contained in:
parent
b4291becf0
commit
5b59ca3c41
4 changed files with 120 additions and 14 deletions
|
@ -26,7 +26,10 @@
|
||||||
#include <boost/spirit/include/qi_rule.hpp>
|
#include <boost/spirit/include/qi_rule.hpp>
|
||||||
#include <boost/spirit/include/qi_as_string.hpp>
|
#include <boost/spirit/include/qi_as_string.hpp>
|
||||||
#include <boost/spirit/include/qi_eol.hpp>
|
#include <boost/spirit/include/qi_eol.hpp>
|
||||||
|
#include <boost/spirit/include/qi_eoi.hpp>
|
||||||
#include <boost/spirit/include/qi_grammar.hpp>
|
#include <boost/spirit/include/qi_grammar.hpp>
|
||||||
|
#include <boost/spirit/include/qi_hold.hpp>
|
||||||
|
#include <boost/spirit/include/qi_char_class.hpp>
|
||||||
#include <boost/spirit/include/phoenix_stl.hpp>
|
#include <boost/spirit/include/phoenix_stl.hpp>
|
||||||
#include <boost/spirit/include/phoenix_operator.hpp>
|
#include <boost/spirit/include/phoenix_operator.hpp>
|
||||||
#include <boost/spirit/include/phoenix_bind.hpp>
|
#include <boost/spirit/include/phoenix_bind.hpp>
|
||||||
|
@ -45,7 +48,7 @@ namespace tawashi {
|
||||||
struct IniGrammar : boost::spirit::qi::grammar<Iterator, IniFile::IniMapType(), Skipper> {
|
struct IniGrammar : boost::spirit::qi::grammar<Iterator, IniFile::IniMapType(), Skipper> {
|
||||||
explicit IniGrammar (const std::string* parString);
|
explicit IniGrammar (const std::string* parString);
|
||||||
boost::spirit::qi::rule<Iterator, IniFile::IniMapType(), Skipper> start;
|
boost::spirit::qi::rule<Iterator, IniFile::IniMapType(), Skipper> start;
|
||||||
boost::spirit::qi::rule<Iterator, string_type(), Skipper> section_head;
|
boost::spirit::qi::rule<Iterator, string_type(), Skipper> section;
|
||||||
boost::spirit::qi::rule<Iterator, string_type(), Skipper> key;
|
boost::spirit::qi::rule<Iterator, string_type(), Skipper> key;
|
||||||
boost::spirit::qi::rule<Iterator, IniFile::KeyValueMapType::value_type(), Skipper> key_value;
|
boost::spirit::qi::rule<Iterator, IniFile::KeyValueMapType::value_type(), Skipper> key_value;
|
||||||
boost::spirit::qi::rule<Iterator, IniFile::KeyValueMapType(), Skipper> key_values;
|
boost::spirit::qi::rule<Iterator, IniFile::KeyValueMapType(), Skipper> key_values;
|
||||||
|
@ -61,33 +64,36 @@ namespace tawashi {
|
||||||
{
|
{
|
||||||
assert(m_master_string);
|
assert(m_master_string);
|
||||||
namespace px = boost::phoenix;
|
namespace px = boost::phoenix;
|
||||||
using boost::spirit::ascii::space;
|
|
||||||
using boost::spirit::qi::_val;
|
using boost::spirit::qi::_val;
|
||||||
using boost::spirit::_1;
|
using boost::spirit::_1;
|
||||||
using boost::spirit::qi::char_;
|
|
||||||
using boost::spirit::qi::eol;
|
using boost::spirit::qi::eol;
|
||||||
|
using boost::spirit::qi::eoi;
|
||||||
using boost::spirit::qi::raw;
|
using boost::spirit::qi::raw;
|
||||||
using boost::string_ref;
|
using boost::string_ref;
|
||||||
|
using boost::spirit::qi::hold;
|
||||||
|
using boost::spirit::qi::graph;
|
||||||
|
using boost::spirit::qi::blank;
|
||||||
typedef IniFile::KeyValueMapType::value_type refpair;
|
typedef IniFile::KeyValueMapType::value_type refpair;
|
||||||
|
|
||||||
section_head = '[' >> raw[+(char_ - ']')][_val = px::bind(
|
section = '[' >> raw[+(graph - ']') >> *(hold[+blank >> +(graph - ']')])]
|
||||||
&string_ref::substr,
|
[_val = px::bind(
|
||||||
px::construct<string_ref>(px::ref(*m_master_string)),
|
&string_ref::substr,
|
||||||
px::begin(_1) - px::ref(m_begin), px::size(_1)
|
px::construct<string_ref>(px::ref(*m_master_string)),
|
||||||
)] >> ']' >> eol;
|
px::begin(_1) - px::ref(m_begin), px::size(_1)
|
||||||
key = raw[+(char_ - '=')][_val = px::bind(
|
)] >> ']' >> (+eol | eoi);
|
||||||
|
key = raw[+(graph - '=') >> *(hold[+blank >> +(graph - '=')])][_val = px::bind(
|
||||||
&string_ref::substr,
|
&string_ref::substr,
|
||||||
px::construct<string_ref>(px::ref(*m_master_string)),
|
px::construct<string_ref>(px::ref(*m_master_string)),
|
||||||
px::begin(_1) - px::ref(m_begin), px::size(_1)
|
px::begin(_1) - px::ref(m_begin), px::size(_1)
|
||||||
)];
|
)];
|
||||||
key_value = key[px::bind(&refpair::first, _val) = _1] >> '=' >>
|
key_value = key[px::bind(&refpair::first, _val) = _1] >> '=' >>
|
||||||
raw[*(char_ - eol)][px::bind(&refpair::second, _val) = px::bind(
|
raw[*graph >> *(hold[+blank >> +graph])][px::bind(&refpair::second, _val) = px::bind(
|
||||||
&string_ref::substr,
|
&string_ref::substr,
|
||||||
px::construct<string_ref>(px::ref(*m_master_string)),
|
px::construct<string_ref>(px::ref(*m_master_string)),
|
||||||
px::begin(_1) - px::ref(m_begin), px::size(_1)
|
px::begin(_1) - px::ref(m_begin), px::size(_1)
|
||||||
)] >> eol;
|
)] >> (+eol | eoi);
|
||||||
key_values = *key_value;
|
key_values = *key_value;
|
||||||
start = *(section_head >> key_values);
|
start = *(section >> key_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
IniFile::IniMapType parse_ini (const std::string* parIni, bool& parParseOk, int& parParsedCharCount) {
|
IniFile::IniMapType parse_ini (const std::string* parIni, bool& parParseOk, int& parParsedCharCount) {
|
||||||
|
@ -135,6 +141,5 @@ namespace tawashi {
|
||||||
m_map = parse_ini(&m_raw_ini, m_parse_ok, m_parsed_chars);
|
m_map = parse_ini(&m_raw_ini, m_parse_ok, m_parsed_chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
IniFile::~IniFile() noexcept {
|
IniFile::~IniFile() noexcept = default;
|
||||||
}
|
|
||||||
} //namespace tawashi
|
} //namespace tawashi
|
||||||
|
|
|
@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME}
|
add_executable(${PROJECT_NAME}
|
||||||
check.cpp
|
check.cpp
|
||||||
|
test_ini_file.cpp
|
||||||
test_settings_bag.cpp
|
test_settings_bag.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
96
test/unit/test_ini_file.cpp
Normal file
96
test/unit/test_ini_file.cpp
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/* Copyright 2017, Michele Santullo
|
||||||
|
* This file is part of "tawashi".
|
||||||
|
*
|
||||||
|
* "tawashi" is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* "tawashi" is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch.hpp"
|
||||||
|
#include "ini_file.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <ciso646>
|
||||||
|
|
||||||
|
TEST_CASE ("Test parsing an ini text", "[!shouldfail][ini]") {
|
||||||
|
using tawashi::IniFile;
|
||||||
|
|
||||||
|
//empty data
|
||||||
|
{
|
||||||
|
std::string empty;
|
||||||
|
IniFile ini(std::move(empty));
|
||||||
|
CHECK(ini.parse_success());
|
||||||
|
CHECK(ini.parsed_characters() == 0);
|
||||||
|
CHECK(ini.parsed().empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
//valid data
|
||||||
|
{
|
||||||
|
std::string text(
|
||||||
|
"[empty_section]\n"
|
||||||
|
"[lololo]\n"
|
||||||
|
"\n"
|
||||||
|
" \n"
|
||||||
|
"\t\t \t\n"
|
||||||
|
"\tsample_key1\t = \t value 1\t\n"
|
||||||
|
"sample_key2= \t value 2_overwritten \n"
|
||||||
|
"sample_key2 =value 2\n"
|
||||||
|
" sample_key3=value 3\n"
|
||||||
|
"\n"
|
||||||
|
"sample_key4=\n"
|
||||||
|
"\n"
|
||||||
|
" [ section 2 ] \n"
|
||||||
|
"\tsect_2_val1=10\n"
|
||||||
|
"\tsect_2_val2=20"
|
||||||
|
);
|
||||||
|
const int text_len = static_cast<int>(text.size());
|
||||||
|
IniFile ini(std::move(text));
|
||||||
|
|
||||||
|
CHECK(ini.parse_success());
|
||||||
|
REQUIRE(ini.parsed_characters() == text_len);
|
||||||
|
|
||||||
|
const IniFile::IniMapType& parsed = ini.parsed();
|
||||||
|
CHECK(parsed.size() == 3);
|
||||||
|
REQUIRE_NOTHROW(parsed.at("lololo"));
|
||||||
|
REQUIRE_NOTHROW(parsed.at("section 2"));
|
||||||
|
REQUIRE_NOTHROW(parsed.at("empty_section"));
|
||||||
|
CHECK_THROWS(parsed.at("section3"));
|
||||||
|
|
||||||
|
const IniFile::KeyValueMapType& lololo = parsed.at("lololo");
|
||||||
|
REQUIRE(lololo.size() == 4);
|
||||||
|
CHECK(lololo.at("sample_key1") == "value 1");
|
||||||
|
CHECK(lololo.at("sample_key2") == "value 2");
|
||||||
|
CHECK(lololo.at("sample_key3") == "value 3");
|
||||||
|
CHECK(lololo.at("sample_key4") == "");
|
||||||
|
|
||||||
|
const IniFile::KeyValueMapType& empty_section = parsed.at("empty_section");
|
||||||
|
CHECK(empty_section.empty());
|
||||||
|
|
||||||
|
const IniFile::KeyValueMapType& section2 = parsed.at("section 2");
|
||||||
|
REQUIRE(section2.size() == 2);
|
||||||
|
CHECK(section2.at("sect_2_val1") == "10");
|
||||||
|
CHECK(section2.at("sect_2_val2") == "20");
|
||||||
|
}
|
||||||
|
|
||||||
|
//invalid data
|
||||||
|
{
|
||||||
|
std::string text(
|
||||||
|
"\n"
|
||||||
|
" \n"
|
||||||
|
"\t\t \t\n"
|
||||||
|
"\tsample_key1\t "
|
||||||
|
);
|
||||||
|
IniFile ini(std::move(text));
|
||||||
|
CHECK(not ini.parse_success());
|
||||||
|
CHECK(ini.parsed_characters() == 27);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
TEST_CASE ("Add and retrieve values from SettingsBag", "[settings][ini]") {
|
TEST_CASE ("Add and retrieve values from SettingsBag", "[settings][ini]") {
|
||||||
using tawashi::SettingsBag;
|
using tawashi::SettingsBag;
|
||||||
|
@ -58,6 +59,9 @@ TEST_CASE ("Add and retrieve values from SettingsBag", "[settings][ini]") {
|
||||||
CHECK(settings.as<std::string>("redis_mode") == "inet");
|
CHECK(settings.as<std::string>("redis_mode") == "inet");
|
||||||
CHECK(settings["base_uri"] == "http://127.0.0.1:8080");
|
CHECK(settings["base_uri"] == "http://127.0.0.1:8080");
|
||||||
|
|
||||||
|
CHECK_THROWS_AS(settings["not_in_ini"], std::out_of_range);
|
||||||
|
CHECK_THROWS_AS(settings.at("not_in_ini"), std::out_of_range);
|
||||||
|
|
||||||
settings.add_default("redis_server", "192.168.0.5");
|
settings.add_default("redis_server", "192.168.0.5");
|
||||||
settings.add_default("not_in_ini_empty", "");
|
settings.add_default("not_in_ini_empty", "");
|
||||||
settings.add_default("not_in_ini", "abcd");
|
settings.add_default("not_in_ini", "abcd");
|
||||||
|
|
Loading…
Reference in a new issue