Mercurial > code
changeset 496:3c783cf492ab
Remove ini
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 08 Dec 2015 18:29:12 +0100 |
parents | 3d6901394e41 |
children | 8b161d143975 |
files | CMakeLists.txt modules/ini/CMakeLists.txt modules/ini/ini.cpp modules/ini/ini.h modules/ini/test/configs/compact.conf modules/ini/test/configs/empty.conf modules/ini/test/configs/error-badcomment.conf modules/ini/test/configs/error-badinclude.conf modules/ini/test/configs/error-badsection.conf modules/ini/test/configs/error-nosection.conf modules/ini/test/configs/error-unterminatedsection.conf modules/ini/test/configs/includes.conf modules/ini/test/configs/lists.conf modules/ini/test/configs/multi.conf modules/ini/test/configs/novalue.conf modules/ini/test/configs/simple.conf modules/ini/test/configs/tokens.conf modules/ini/test/main.cpp |
diffstat | 18 files changed, 0 insertions(+), 1385 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Tue Dec 01 15:32:34 2015 +0100 +++ b/CMakeLists.txt Tue Dec 08 18:29:12 2015 +0100 @@ -55,7 +55,6 @@ ) endif () -add_subdirectory(modules/ini) add_subdirectory(modules/js) add_subdirectory(modules/json) add_subdirectory(modules/options)
--- a/modules/ini/CMakeLists.txt Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -# -# CMakeLists.txt -- ini module -# -# Copyright (c) 2013-2015 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -project(ini) - -if (WIN32) - set(LIBRARIES Shlwapi) -endif () - -code_define_module( - NAME ini - SOURCES - ${ini_SOURCE_DIR}/ini.cpp - ${ini_SOURCE_DIR}/ini.h - LIBRARIES - ${LIBRARIES} - RESOURCES - ${ini_SOURCE_DIR}/test/configs/compact.conf - ${ini_SOURCE_DIR}/test/configs/empty.conf - ${ini_SOURCE_DIR}/test/configs/error-badcomment.conf - ${ini_SOURCE_DIR}/test/configs/error-badinclude.conf - ${ini_SOURCE_DIR}/test/configs/error-badsection.conf - ${ini_SOURCE_DIR}/test/configs/error-nosection.conf - ${ini_SOURCE_DIR}/test/configs/error-unterminatedsection.conf - ${ini_SOURCE_DIR}/test/configs/includes.conf - ${ini_SOURCE_DIR}/test/configs/lists.conf - ${ini_SOURCE_DIR}/test/configs/multi.conf - ${ini_SOURCE_DIR}/test/configs/novalue.conf - ${ini_SOURCE_DIR}/test/configs/simple.conf - ${ini_SOURCE_DIR}/test/configs/tokens.conf -)
--- a/modules/ini/ini.cpp Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,445 +0,0 @@ -/* - * ini.cpp -- .ini file parsing - * - * Copyright (c) 2013-2015 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <cctype> -#include <cstring> -#include <iostream> -#include <iterator> -#include <fstream> -#include <sstream> -#include <stdexcept> - -#if defined(_WIN32) -# include <Shlwapi.h> // for PathIsRelative -#endif - -#include "ini.h" - -namespace { - -using namespace ini; - -using StreamIterator = std::istreambuf_iterator<char>; -using TokenIterator = std::vector<Token>::const_iterator; - -inline bool isAbsolute(const std::string &path) noexcept -{ -#if defined(_WIN32) - return !PathIsRelative(path.c_str()); -#else - return path.size() > 0 && path[0] == '/'; -#endif -} - -inline bool isQuote(char c) noexcept -{ - return c == '\'' || c == '"'; -} - -inline bool isSpace(char c) noexcept -{ - /* Custom version because std::isspace includes \n as space */ - return c == ' ' || c == '\t'; -} - -inline bool isList(char c) noexcept -{ - return c == '(' || c == ')' || c == ','; -} - -inline bool isReserved(char c) noexcept -{ - return isList(c) || isQuote(c) || c == '[' || c == ']' || c == '@' || c == '#' || c == '='; -} - -void analyzeLine(int &line, int &column, StreamIterator &it) noexcept -{ - assert(*it == '\n'); - - ++ line; - ++ it; - column = 0; -} - -void analyzeComment(int &column, StreamIterator &it, StreamIterator end) noexcept -{ - assert(*it == '#'); - - while (it != end && *it != '\n') { - ++ column; - ++ it; - } -} - -void analyzeSpaces(int &column, StreamIterator &it, StreamIterator end) noexcept -{ - assert(isSpace(*it)); - - while (it != end && isSpace(*it)) { - ++ column; - ++ it; - } -} - -void analyzeList(Tokens &list, int line, int &column, StreamIterator &it) noexcept -{ - assert(isList(*it)); - - switch (*it++) { - case '(': - list.emplace_back(Token::ListBegin, line, column++); - break; - case ')': - list.emplace_back(Token::ListEnd, line, column++); - break; - case ',': - list.emplace_back(Token::Comma, line, column++); - break; - default: - break; - } -} - -void analyzeSection(Tokens &list, int &line, int &column, StreamIterator &it, StreamIterator end) -{ - assert(*it == '['); - - std::string value; - int save = column; - - /* Read section name */ - ++ it; - while (it != end && *it != ']') { - if (*it == '\n') { - throw Error{line, column, "section not terminated, missing ']'"}; - } - if (isReserved(*it)) { - throw Error{line, column, "section name expected after '[', got '" + std::string(1, *it) + "'"}; - } - ++ column; - value += *it++; - } - - if (it == end) { - throw Error{line, column, "section name expected after '[', got <EOF>"}; - } - if (value.empty()) { - throw Error{line, column, "empty section name"}; - } - - /* Remove ']' */ - ++ it; - - list.emplace_back(Token::Section, line, save, std::move(value)); -} - -void analyzeAssign(Tokens &list, int &line, int &column, StreamIterator &it) -{ - assert(*it == '='); - - list.push_back({ Token::Assign, line, column++ }); - ++ it; -} - -void analyzeQuotedWord(Tokens &list, int &line, int &column, StreamIterator &it, StreamIterator end) -{ - std::string value; - int save = column; - char quote = *it++; - - while (it != end && *it != quote) { - // TODO: escape sequence - ++ column; - value += *it++; - } - - if (it == end) { - throw Error{line, column, "undisclosed '" + std::string(1, quote) + "', got <EOF>"}; - } - - /* Remove quote */ - ++ it; - - list.push_back({ Token::QuotedWord, line, save, std::move(value) }); -} - -void analyzeWord(Tokens &list, int &line, int &column, StreamIterator &it, StreamIterator end) -{ - assert(!isReserved(*it)); - - std::string value; - int save = column; - - while (it != end && !std::isspace(*it) && !isReserved(*it)) { - ++ column; - value += *it++; - } - - list.push_back({ Token::Word, line, save, std::move(value) }); -} - -void analyzeInclude(Tokens &list, int &line, int &column, StreamIterator &it, StreamIterator end) -{ - assert(*it == '@'); - - std::string include; - int save = column; - - /* Read include */ - ++ it; - while (it != end && !isSpace(*it)) { - ++ column; - include += *it++; - } - - if (include != "include") { - throw Error{line, column, "expected include after '@' token"}; - } - - list.push_back({ Token::Include, line, save }); -} - -Tokens analyze(StreamIterator &it, StreamIterator end) -{ - Tokens list; - int line = 1; - int column = 0; - - while (it != end) { - if (*it == '\n') { - analyzeLine(line, column, it); - } else if (*it == '#') { - analyzeComment(column, it, end); - } else if (*it == '[') { - analyzeSection(list, line, column, it, end); - } else if (*it == '=') { - analyzeAssign(list, line, column, it); - } else if (isSpace(*it)) { - analyzeSpaces(column, it, end); - } else if (*it == '@') { - analyzeInclude(list, line, column, it, end); - } else if (isQuote(*it)) { - analyzeQuotedWord(list, line, column, it, end); - } else if (isList(*it)) { - analyzeList(list, line, column, it); - } else { - analyzeWord(list, line, column, it, end); - } - } - - return list; -} - -void parseOptionValueSimple(Option &option, TokenIterator &it) -{ - assert(it->type() == Token::Word || it->type() == Token::QuotedWord); - - option.push_back((it++)->value()); -} - -void parseOptionValueList(Option &option, TokenIterator &it, TokenIterator end) -{ - assert(it->type() == Token::ListBegin); - - TokenIterator save = it++; - - while (it != end && it->type() != Token::ListEnd) { - switch (it->type()) { - case Token::Comma: - /* Previous must be a word */ - if (it[-1].type() != Token::Word && it[-1].type() != Token::QuotedWord) { - throw Error{it->line(), it->column(), "unexpected comma after '" + it[-1].value() + "'"}; - } - - ++ it; - break; - case Token::Word: - case Token::QuotedWord: - option.push_back((it++)->value()); - break; - default: - throw Error{it->line(), it->column(), "unexpected '" + it[-1].value() + "' in list construct"}; - break; - } - } - - if (it == end) { - throw Error{save->line(), save->column(), "unterminated list construct"}; - } - - /* Remove ) */ - ++ it; -} - -void parseOption(Section &sc, TokenIterator &it, TokenIterator end) -{ - Option option{it->value()}; - - TokenIterator save = it; - - /* No '=' or something else? */ - if (++it == end) { - throw Error{save->line(), save->column(), "expected '=' assignment, got <EOF>"}; - } - if (it->type() != Token::Assign) { - throw Error{it->line(), it->column(), "expected '=' assignment, got " + it->value()}; - } - - /* Empty options are allowed so just test for words */ - if (++it != end) { - if (it->type() == Token::Word || it->type() == Token::QuotedWord) { - parseOptionValueSimple(option, it); - } else if (it->type() == Token::ListBegin) { - parseOptionValueList(option, it, end); - } - } - - sc.push_back(std::move(option)); -} - -void parseInclude(Document &doc, TokenIterator &it, TokenIterator end) -{ - TokenIterator save = it; - - if (++it == end) { - throw Error{save->line(), save->column(), "expected file name after '@include' statement, got <EOF>"}; - } - - if (it->type() != Token::Word && it->type() != Token::QuotedWord) { - throw Error{it->line(), it->column(), "expected file name after '@include' statement, got " + it->value()}; - } - - if (doc.path().empty()) { - throw Error{it->line(), it->column(), "'@include' statement invalid with buffer documents"}; - } - - std::string value = (it++)->value(); - std::string file; - - if (!isAbsolute(value)) { -#if defined(_WIN32) - file = doc.path() + "\\" + value; -#else - file = doc.path() + "/" + value; -#endif - } else { - file = value; - } - - Document child{File{file}}; - - for (const auto &sc : child) { - doc.push_back(sc); - } -} - -void parseSection(Document &doc, TokenIterator &it, TokenIterator end) -{ - Section sc{it->value()}; - - /* Skip [section] */ - ++ it; - - /* Read until next section */ - while (it != end && it->type() != Token::Section) { - if (it->type() != Token::Word) { - throw Error{it->line(), it->column(), "unexpected token '" + it->value() + "' in section definition"}; - } - - parseOption(sc, it, end); - } - - doc.push_back(std::move(sc)); -} - -void parse(Document &doc, const Tokens &tokens) -{ - TokenIterator it = tokens.cbegin(); - TokenIterator end = tokens.cend(); - - while (it != end) { - /* Just ignore this */ - switch (it->type()) { - case Token::Include: - parseInclude(doc, it, end); - break; - case Token::Section: - parseSection(doc, it, end); - break; - default: - throw Error{it->line(), it->column(), "unexpected '" + it->value() + "' on root document"}; - } - } -} - -} // !namespace - -namespace ini { - -Tokens Document::analyze(const File &file) -{ - std::fstream stream{file.path}; - - if (!stream) { - throw std::runtime_error{std::strerror(errno)}; - } - - std::istreambuf_iterator<char> it{stream}; - std::istreambuf_iterator<char> end{}; - - return ::analyze(it, end); -} - -Tokens Document::analyze(const Buffer &buffer) -{ - std::istringstream stream{buffer.text}; - std::istreambuf_iterator<char> it{stream}; - std::istreambuf_iterator<char> end{}; - - return ::analyze(it, end); -} - -Document::Document(const File &file) - : m_path{file.path} -{ - /* Update path */ - auto pos = m_path.find_last_of("/\\"); - - if (pos != std::string::npos) { - m_path.erase(pos); - } else { - m_path = "."; - } - - parse(*this, analyze(file)); -} - -Document::Document(const Buffer &buffer) -{ - parse(*this, analyze(buffer)); -} - -void Document::dump(const Tokens &tokens) -{ - for (const Token &token: tokens) { - // TODO: add better description - std::cout << token.line() << ":" << token.column() << ": " << token.value() << std::endl; - } -} - -} // !ini
--- a/modules/ini/ini.h Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,546 +0,0 @@ -/* - * ini.h -- .ini file parsing - * - * Copyright (c) 2013-2015 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _INI_H_ -#define _INI_H_ - -/** - * @file ini.h - * @brief Configuration file parser. - */ - -#include <algorithm> -#include <cassert> -#include <exception> -#include <stdexcept> -#include <string> -#include <vector> - -/** - * Namespace for ini related classes. - */ -namespace ini { - -class Document; - -/** - * @class Error - * @brief Error in a file - */ -class Error : public std::exception { -private: - int m_line; //!< line number - int m_column; //!< line column - std::string m_message; //!< error message - -public: - /** - * Constructor. - * - * @param l the line - * @param c the column - * @param m the message - */ - inline Error(int l, int c, std::string m) noexcept - : m_line{l} - , m_column{c} - , m_message{std::move(m)} - { - } - - /** - * Get the line number. - * - * @return the line - */ - inline int line() const noexcept - { - return m_line; - } - - /** - * Get the column number. - * - * @return the column - */ - inline int column() const noexcept - { - return m_column; - } - - /** - * Return the raw error message (no line and column shown). - * - * @return the error message - */ - const char *what() const noexcept override - { - return m_message.c_str(); - } -}; - -/** - * @class Token - * @brief Describe a token read in the .ini source - * - * This class can be used when you want to parse a .ini file yourself. - * - * @see Document::analyze - */ -class Token { -public: - /** - * @brief Token type - */ - enum Type { - Include, //!< include statement - Section, //!< [section] - Word, //!< word without quotes - QuotedWord, //!< word with quotes - Assign, //!< = assignment - ListBegin, //!< begin of list ( - ListEnd, //!< end of list ) - Comma //!< list separation - }; - -private: - Type m_type; - int m_line; - int m_column; - std::string m_value; - -public: - /** - * Construct a token. - * - * @param type the type - * @param line the line - * @param column the column - * @param value the value - */ - Token(Type type, int line, int column, std::string value = "") noexcept - : m_type{type} - , m_line{line} - , m_column{column} - { - switch (type) { - case Include: - m_value = "@include"; - break; - case Section: - case Word: - case QuotedWord: - m_value = value; - break; - case Assign: - m_value = "="; - break; - case ListBegin: - m_value = "("; - break; - case ListEnd: - m_value = ")"; - break; - case Comma: - m_value = ","; - break; - default: - break; - } - } - - /** - * Get the type. - * - * @return the type - */ - inline Type type() const noexcept - { - return m_type; - } - - /** - * Get the line. - * - * @return the line - */ - inline int line() const noexcept - { - return m_line; - } - - /** - * Get the column. - * - * @return the column - */ - inline int column() const noexcept - { - return m_column; - } - - /** - * Get the value. For words, quoted words and section, the value is the content. Otherwise it's the - * characters parsed. - * - * @return the value - */ - inline const std::string &value() const noexcept - { - return m_value; - } -}; - -/** - * List of tokens in order they are analyzed. - */ -using Tokens = std::vector<Token>; - -/** - * @class Option - * @brief Option definition. - */ -class Option : public std::vector<std::string> { -private: - std::string m_key; - -public: - /** - * Construct an empty option. - * - * @param key the key - * @param value the value - */ - inline Option(std::string key) noexcept - : std::vector<std::string>{} - , m_key{std::move(key)} - { - } - - /** - * Construct a single option. - * - * @param key the key - * @param value the value - */ - inline Option(std::string key, std::string value) noexcept - : m_key{std::move(key)} - { - push_back(std::move(value)); - } - - /** - * Construct a list option. - * - * @param key the key - * @param values the values - */ - inline Option(std::string key, std::vector<std::string> values) noexcept - : std::vector<std::string>{std::move(values)} - , m_key{std::move(key)} - { - } - - /** - * Get the option key. - * - * @return the key - */ - inline const std::string &key() const noexcept - { - return m_key; - } - - /** - * Get the option value. - * - * @return the value - */ - inline const std::string &value() const noexcept - { - static std::string dummy; - - return empty() ? dummy : (*this)[0]; - } -}; - -/** - * @class Section - * @brief Section that contains one or more options. - */ -class Section : public std::vector<Option> { -private: - std::string m_key; - -public: - /** - * Construct a section with its name. - * - * @param key the key - * @pre key must not be empty - */ - inline Section(std::string key) noexcept - : m_key{std::move(key)} - { - assert(!m_key.empty()); - } - - /** - * Get the section key. - * - * @return the key - */ - inline const std::string &key() const noexcept - { - return m_key; - } - - /** - * Check if the section contains a specific option. - * - * @param key the option key - * @return true if the option exists - */ - inline bool contains(const std::string &key) const noexcept - { - return find(key) != end(); - } - - /** - * Access an option at the specified key. - * - * @param key the key - * @return the option - * @pre contains(key) must return true - */ - inline Option &operator[](const std::string &key) - { - assert(contains(key)); - - return *find(key); - } - - /** - * Overloaded function. - * - * @param key the key - * @return the option - * @pre contains(key) must return true - */ - inline const Option &operator[](const std::string &key) const - { - assert(contains(key)); - - return *find(key); - } - - /** - * Find an option by key and return an iterator. - * - * @param key the key - * @return the iterator or end() if not found - */ - inline iterator find(const std::string &key) noexcept - { - return std::find_if(begin(), end(), [&] (const auto &o) { - return o.key() == key; - }); - } - - /** - * Find an option by key and return an iterator. - * - * @param key the key - * @return the iterator or end() if not found - */ - inline const_iterator find(const std::string &key) const noexcept - { - return std::find_if(cbegin(), cend(), [&] (const auto &o) { - return o.key() == key; - }); - } - - /** - * Inherited operators. - */ - using std::vector<Option>::operator[]; -}; - -/** - * @class File - * @brief Source for reading .ini files. - */ -class File { -public: - /** - * Path to the file. - */ - std::string path; -}; - -/** - * @class Buffer - * @brief Source for reading ini from text. - * @note the include statement is not supported with buffers. - */ -class Buffer { -public: - /** - * The ini content. - */ - std::string text; -}; - -/** - * @class Document - * @brief Ini config file loader - */ -class Document : public std::vector<Section> { -private: - std::string m_path; - -public: - /** - * Analyze a file and extract tokens. If the function succeeds, that does not mean the content is valid, - * it just means that there are no syntax error. - * - * For example, this class does not allow adding options under no sections and this function will not - * detect that issue. - * - * @param file the file to read - * @return the list of tokens - * @throws Error on errors - */ - static Tokens analyze(const File &file); - - /** - * Overloaded function for buffers. - * - * @param buffer the buffer to read - * @return the list of tokens - * @throws Error on errors - */ - static Tokens analyze(const Buffer &buffer); - - /** - * Show all tokens and their description. - * - * @param tokens the tokens - */ - static void dump(const Tokens &tokens); - - /** - * Construct a document from a file. - * - * @param file the file to read - * @throws Error on errors - */ - Document(const File &file); - - /** - * Overloaded constructor for buffers. - * - * @param buffer the buffer to read - * @throws Error on errors - */ - Document(const Buffer &buffer); - - /** - * Get the current document path, only useful when constructed from File source. - * - * @return the path - */ - inline const std::string &path() const noexcept - { - return m_path; - } - - /** - * Check if a document has a specific section. - * - * @param key the key - * @return true if the document contains the section - */ - inline bool contains(const std::string &key) const noexcept - { - return std::find_if(begin(), end(), [&] (const auto &sc) { return sc.key() == key; }) != end(); - } - - /** - * Access a section at the specified key. - * - * @param key the key - * @return the section - * @pre contains(key) must return true - */ - inline Section &operator[](const std::string &key) - { - assert(contains(key)); - - return *find(key); - } - - /** - * Overloaded function. - * - * @param key the key - * @return the section - * @pre contains(key) must return true - */ - inline const Section &operator[](const std::string &key) const - { - assert(contains(key)); - - return *find(key); - } - - /** - * Find a section by key and return an iterator. - * - * @param key the key - * @return the iterator or end() if not found - */ - inline iterator find(const std::string &key) noexcept - { - return std::find_if(begin(), end(), [&] (const auto &o) { - return o.key() == key; - }); - } - - /** - * Find a section by key and return an iterator. - * - * @param key the key - * @return the iterator or end() if not found - */ - inline const_iterator find(const std::string &key) const noexcept - { - return std::find_if(cbegin(), cend(), [&] (const auto &o) { - return o.key() == key; - }); - } - - /** - * Inherited operators. - */ - using std::vector<Section>::operator[]; -}; - -} // !ini - -#endif // !_INI_H_
--- a/modules/ini/test/configs/compact.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -[general]verbose=true foreground=false[server]host=google.fr
--- a/modules/ini/test/configs/empty.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -# this file is completely empty \ No newline at end of file
--- a/modules/ini/test/configs/error-badcomment.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -[general] -verbose #hello = xyz
--- a/modules/ini/test/configs/error-badinclude.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -@include noquotes \ No newline at end of file
--- a/modules/ini/test/configs/error-badsection.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -[[general] -verbose = false
--- a/modules/ini/test/configs/error-nosection.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -# this file has no section -# and it's not valid -option = value
--- a/modules/ini/test/configs/error-unterminatedsection.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -# This file has unterminated section -[forgot \ No newline at end of file
--- a/modules/ini/test/configs/includes.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -# With some includes -@include "simple.conf" # comments also work here - -[standard] -verbose = false
--- a/modules/ini/test/configs/lists.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -[rule1] -servers = ( "abc", "bcd" ) - -[rule2] -servers = -( - xyz, - poi -)
--- a/modules/ini/test/configs/multi.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -[entity] -name = "Player" -version = 1.0 - -[entity] -name = "Subwinner" -version = 2.0 \ No newline at end of file
--- a/modules/ini/test/configs/novalue.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -[plugins] -histedit= "" -highlight= "" #empty -general = "" - -
--- a/modules/ini/test/configs/simple.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -[general] -option1=1 -option2 =2 -option3 = 3 - -# This file ends with a comment. \ No newline at end of file
--- a/modules/ini/test/configs/tokens.conf Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -[tokens] -bracket = "I have [brackets]" -at = "I have foo@at"
--- a/modules/ini/test/main.cpp Tue Dec 01 15:32:34 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,299 +0,0 @@ -/* - * main.cpp -- main test file for Ini - * - * Copyright (c) 2013-2015 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <iostream> - -#include <gtest/gtest.h> - -#include <ini.h> - -class BasicTest : public testing::Test { -protected: - ini::Document m_ini; - -public: - BasicTest() - : m_ini{ini::File{"ini/simple.conf"}} - { - } - -}; - -TEST_F(BasicTest, simple) -{ - ASSERT_EQ(1, static_cast<int>(m_ini.size())); -} - -TEST_F(BasicTest, operators) -{ - try { - ASSERT_EQ(3, static_cast<int>(m_ini[0].size())); - ASSERT_EQ("general", m_ini[0].key()); - ASSERT_EQ("general", m_ini["general"].key()); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } -} - -TEST_F(BasicTest, sectionOperators) -{ - try { - // option1=1 (indexes) - ASSERT_EQ("option1", m_ini[0][0].key()); - ASSERT_EQ("1", m_ini[0][0].value()); - - // option1=1 (keys) - ASSERT_EQ("option1", m_ini["general"]["option1"].key()); - ASSERT_EQ("1", m_ini["general"]["option1"].value()); - - // option2 =2 (indexes) - ASSERT_EQ("option2", m_ini[0][1].key()); - ASSERT_EQ("2", m_ini[0][1].value()); - - // option2 =2 (keys) - ASSERT_EQ("option2", m_ini["general"]["option2"].key()); - ASSERT_EQ("2", m_ini["general"]["option2"].value()); - - // option3 = 3 (indexes) - ASSERT_EQ("option3", m_ini[0][2].key()); - ASSERT_EQ("3", m_ini[0][2].value()); - - // option3 = 3 (keys) - ASSERT_EQ("option3", m_ini["general"]["option3"].key()); - ASSERT_EQ("3", m_ini["general"]["option3"].value()); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } -} - -/* -------------------------------------------------------- - * Reserved tokens in words - * -------------------------------------------------------- */ - -TEST(Tokens, reserved) -{ - try { - ini::Document doc{ini::File{"ini/tokens.conf"}}; - - ASSERT_EQ("I have [brackets]", doc["tokens"]["bracket"].value()); - ASSERT_EQ("I have foo@at", doc["tokens"]["at"].value()); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } -} - -/* -------------------------------------------------------- - * Multiple defini::Documenttion - * -------------------------------------------------------- */ - -class MultiTest : public testing::Test { -protected: - ini::Document m_ini; - -public: - MultiTest() - : m_ini{ini::File{"ini/multi.conf"}} - { - } -}; - -TEST_F(MultiTest, defined) -{ - ASSERT_EQ(2, static_cast<int>(m_ini.size())); - ASSERT_EQ("name", m_ini[0]["name"].key()); - ASSERT_EQ("Player", m_ini[0]["name"].value()); - ASSERT_EQ("version", m_ini[0]["version"].key()); - ASSERT_EQ("1.0", m_ini[0]["version"].value()); - ASSERT_EQ("name", m_ini[1]["name"].key()); - ASSERT_EQ("Subwinner", m_ini[1]["name"].value()); - ASSERT_EQ("version", m_ini[1]["version"].key()); - ASSERT_EQ("2.0", m_ini[1]["version"].value()); -} - -/* -------------------------------------------------------- - * Option with no values - * -------------------------------------------------------- */ - -class NoValueTest : public testing::Test { -protected: - ini::Document m_ini; - -public: - NoValueTest() - : m_ini{ini::File{"ini/novalue.conf"}} - { - } -}; - -TEST_F(NoValueTest, isDefined) -{ - ASSERT_EQ("plugins", m_ini[0].key()); - ASSERT_EQ("", m_ini["plugins"]["histedit"].value()); - ASSERT_EQ("", m_ini["plugins"]["highlight"].value()); - ASSERT_EQ("", m_ini["plugins"]["general"].value()); -} - -/* -------------------------------------------------------- - * Include tests - * -------------------------------------------------------- */ - -class IncludeTest : public testing::Test { -protected: - ini::Document m_ini; - -public: - IncludeTest() - : m_ini{ini::File{"ini/includes.conf"}} - { - } -}; - -TEST_F(IncludeTest, all) -{ - ASSERT_EQ(2, static_cast<int>(m_ini.size())); - - // from include - ASSERT_EQ("1", m_ini[0][0].value()); - ASSERT_EQ("2", m_ini[0][1].value()); - ASSERT_EQ("3", m_ini[0][2].value()); - - // from standard - ASSERT_EQ("false", m_ini[1][0].value()); -} - -/* -------------------------------------------------------- - * Compact - * -------------------------------------------------------- */ - -TEST(Compact, test) -{ - try { - ini::Document doc{ini::File{"ini/compact.conf"}}; - - ASSERT_EQ(2, static_cast<int>(doc.size())); - ASSERT_EQ("true", doc["general"]["verbose"].value()); - ASSERT_EQ("false", doc["general"]["foreground"].value()); - ASSERT_EQ("google.fr", doc["server"]["host"].value()); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } -} - -/* -------------------------------------------------------- - * Empty - * -------------------------------------------------------- */ - -TEST(Empty, test) -{ - try { - ini::Document doc{ini::File{"ini/empty.conf"}}; - } catch (const ini::Error &error) { - FAIL() << error.line() << ":" << error.column() << ": " << error.what(); - } -} - -/* -------------------------------------------------------- - * List - * -------------------------------------------------------- */ - -TEST(List, test) -{ - try { - std::vector<std::string> rule1{"abc", "bcd"}; - std::vector<std::string> rule2{"xyz", "poi"}; - ini::Document doc{ini::File{"ini/lists.conf"}}; - - ASSERT_EQ(rule1, doc[0][0]); - ASSERT_EQ(rule2, doc[1][0]); - } catch (const ini::Error &error) { - FAIL() << error.line() << ":" << error.column() << ": " << error.what(); - } -} - -/* -------------------------------------------------------- - * Errors - * -------------------------------------------------------- */ - -TEST(Errors, nosection) -{ - // An option outside a section is not allowed - try { - ini::Document doc{ini::File{"ini/error-nosection.conf"}}; - - FAIL() << "Failure expected, got success"; - } catch (const ini::Error &ex) { - ASSERT_EQ(3, ex.line()); - ASSERT_EQ(0, ex.column()); - } -} - -TEST(Errors, badcomment) -{ - // Comment can't between option-key and = assigment - try { - ini::Document doc{ini::File{"ini/error-badcomment.conf"}}; - - FAIL() << "Failure expected, got success"; - } catch (const ini::Error &ex) { - ASSERT_EQ(2, ex.line()); - ASSERT_EQ(0, ex.column()); - } -} - -TEST(Errors, badsection) -{ - // Bad section naming - try { - ini::Document doc{ini::File{"ini/error-badsection.conf"}}; - - FAIL() << "Failure expected, got success"; - } catch (const ini::Error &ex) { - ASSERT_EQ(1, ex.line()); - ASSERT_EQ(0, ex.column()); - } -} - -TEST(Errors, unterminatedsection) -{ - // Section unfinished - try { - ini::Document doc{ini::File{"ini/error-unterminatedsection.conf"}}; - - FAIL() << "Failure expected, got success"; - } catch (const ini::Error &ex) { - ASSERT_EQ(2, ex.line()); - ASSERT_EQ(6, ex.column()); - } -} - -TEST(Errors, notFound) -{ - try { - ini::Document doc{ini::File{"does not exists"}}; - - FAIL() << "Failure expected, got success"; - } catch (const std::exception &) { - } -} - -int main(int argc, char **argv) -{ - testing::InitGoogleTest(&argc, argv); - - return RUN_ALL_TESTS(); -}