From 00219b84240f4514f1c6087f9232c710608470e9 Mon Sep 17 00:00:00 2001 From: Phitherek Date: Sat, 6 Apr 2013 23:03:27 +0200 Subject: [PATCH] ModInfo class after tests --- 3m.h | 31 ++++--- 3mExceptions.h | 4 +- ModInfo.cpp | 16 ++-- ModInfo.h | 2 +- tests/Makefile | 4 +- tests/ModInfoTest.cpp | 204 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 241 insertions(+), 20 deletions(-) create mode 100644 tests/ModInfoTest.cpp diff --git a/3m.h b/3m.h index 12126c5..fb52eb4 100644 --- a/3m.h +++ b/3m.h @@ -1,6 +1,7 @@ #ifndef _3M_H #define _3M_H #include +#include #include "ConfigFile.h" #include "3mExceptions.h" #include "LocalModDescription.h" @@ -21,11 +22,11 @@ /// \namespace mmm /// \brief A global namespace for 3m. namespace mmm { -/// \fn std::string strip_endl(std::string s) +/// \fn inline std::string strip_endl(std::string s) /// \brief A function that strips endline signs from the string. /// \param s A string to strip endline signs from. /// \return Stripped string. -std::string strip_endl(std::string s) { +inline std::string strip_endl(std::string s) { int len = s.length(); for(int i = 0; i < len; i++) { if(s[i] == '\n') { @@ -37,17 +38,25 @@ std::string strip_endl(std::string s) { return s; } -/// \fn std::string strgetline(std::string *str) -/// \brief A function that gets line from the multiline string and erases it from this string. -/// \param[in,out] str A pointer to the string to get line from. The line is erased from the string. -/// \return Line from the string. -std::string strgetline(std::string *str) { +/// \fn inline std::vector strtovec(std::string *str) +/// \brief A function that converts a multiline string to a vector of strings. +/// \param str A string to convert to vector. +/// \return Vector of strings, each one a line from original string +inline std::vector& strtovec(std::string str) { std::string line = ""; -int i; -for(i = 0; (*str)[i] != '\n'; i++) { -line += (*str)[i]; +static std::vector vec; +vec.clear(); +for(unsigned int i = 0; i < str.length(); i++) { + if(str[i] == '\n' || str[i] == '\r') { + if(line != "") { + vec.push_back(line); + line = ""; + } + } else { + line += str[i]; + } } -return line; +return vec; } } #endif diff --git a/3mExceptions.h b/3mExceptions.h index a2fe902..55e99e3 100644 --- a/3mExceptions.h +++ b/3mExceptions.h @@ -47,9 +47,9 @@ class BadResponseException: public std::exception { private: std::string _response; public: - OutOfBoundsException(std::string response); ///< \brief A constructor with parameters. + BadResponseException(std::string response); ///< \brief A constructor with parameters. ///< \param response HTTP response that caused the exception. - ~OutOfBoundsException() throw(); ///< A destructor, as needed by std::exception. + ~BadResponseException() throw(); ///< A destructor, as needed by std::exception. const char* what() const throw(); ///< \brief A function returning error message. /// \return Error message. }; diff --git a/ModInfo.cpp b/ModInfo.cpp index 6cbbf1d..07e349b 100644 --- a/ModInfo.cpp +++ b/ModInfo.cpp @@ -1,6 +1,9 @@ #include "ModInfo.h" #include "NetSocket++/NetSocketPP.h" #include +#include +#include +#include using namespace mmm; ModInfo::ModInfo() { @@ -27,11 +30,12 @@ ModInfo::ModInfo(ModInfoDescription mid) { if(data.getResponse() != "200 OK") { throw BadResponseException(data.getResponse()); } - std::string modinfo = data.getContent(); + std::string smodinfo = data.getContent(); + std::vector modinfo = strtovec(smodinfo); std::string action = "detect"; -for(unsigned int i = 0; i < modinfo.length(); i++) { +for(unsigned int i = 0; i < modinfo.size(); i++) { std::string line = ""; - line = strgetline(&modinfo); + line = modinfo[i]; if(line[0] != NULL && line[0] != ' ' && line[0] != '\n' && line[0] != '\r') { if(action == "detect") { if(line[0] == '{') { @@ -40,6 +44,7 @@ for(unsigned int i = 0; i < modinfo.length(); i++) { name += line[i]; } _name = name; + _desc.setName(name); action = "parse"; } else { std::string msg = ""; @@ -182,6 +187,7 @@ ModInfo::ModInfo(std::string path) { name += line[i]; } _name = name; + _desc.setName(name); action = "parse"; } else { std::string msg = ""; @@ -307,7 +313,7 @@ void ModInfo::write() { throw NonEditableException("Tried to write back remotely obtained modinfo file!"); } std::ofstream modinfo(_localPath.c_str()); - if(!ofstream) { + if(!modinfo) { throw FileException(_localPath, "writing", "Could not open file!"); } modinfo << "{" << _name << "}" << std::endl << "[description]" << std::endl << _description << std::endl << "[release]" << std::endl << _release << std::endl << "[deps]" << std::endl; @@ -326,7 +332,7 @@ void ModInfo::releaseInc() { _release++; } -void ModInfo::~ModInfo() { +ModInfo::~ModInfo() { ModInfoDescription emptymid; _desc = emptymid; _edit = false; diff --git a/ModInfo.h b/ModInfo.h index 218afe3..d90c18a 100644 --- a/ModInfo.h +++ b/ModInfo.h @@ -20,7 +20,7 @@ bool _edit; std::string _localPath; public: ModInfo(); ///< A constructor. -ModInfo(ModInfoDescripton mid); ///< \brief A constructor from ModInfoDescription object. +ModInfo(ModInfoDescription mid); ///< \brief A constructor from ModInfoDescription object. ///< Tries to download and parse remote modinfo file. ///< \param mid A ModInfoDescription object. ModInfo(std::string path); ///< \brief A construtor from the path to local modinfo file. diff --git a/tests/Makefile b/tests/Makefile index 6d438fe..7be59cc 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -6,6 +6,7 @@ all: ${CXX} ${CXXFLAGS} -o ModListListTest ModListListTest.cpp ../ModListList.cpp ../ModListDescription.cpp ../3mExceptions.cpp ${CXX} ${CXXFLAGS} -o LocalModListTest LocalModListTest.cpp ../LocalModList.cpp ../LocalModDescription.cpp ../ModDescription.cpp ../3mExceptions.cpp ../ConfigFile.cpp ${CXX} ${CXXFLAGS} -o RepositoryInfoTest RepositoryInfoTest.cpp ../RepositoryModDescription.cpp ../ModDescription.cpp ../3mExceptions.cpp ../ConfigFile.cpp ../RepositoryInfo.cpp + ${CXX} ${CXXFLAGS} -o ModInfoTest ModInfoTest.cpp ../ModInfo.cpp ../ModInfoDescription.cpp ../ModDescription.cpp ../3mExceptions.cpp -lnetsocketpp debug: ${CXX} ${CXXFLAGS} -o ConfigFileTest ConfigFileTest.cpp ../ConfigFile.cpp ../3mExceptions.cpp -g ${CXX} ${CXXFLAGS} -o ModDescriptionTest ModDescriptionTest.cpp ../ModDescription.cpp -g @@ -13,5 +14,6 @@ debug: ${CXX} ${CXXFLAGS} -o ModListListTest ModListListTest.cpp ../ModListList.cpp ../ModListDescription.cpp ../3mExceptions.cpp -g ${CXX} ${CXXFLAGS} -o LocalModListTest LocalModListTest.cpp ../LocalModList.cpp ../LocalModDescription.cpp ../ModDescription.cpp ../3mExceptions.cpp ../ConfigFile.cpp -g ${CXX} ${CXXFLAGS} -o RepositoryInfoTest RepositoryInfoTest.cpp ../RepositoryModDescription.cpp ../ModDescription.cpp ../3mExceptions.cpp ../ConfigFile.cpp ../RepositoryInfo.cpp -g + ${CXX} ${CXXFLAGS} -o ModInfoTest ModInfoTest.cpp ../ModInfo.cpp ../ModInfoDescription.cpp ../ModDescription.cpp ../3mExceptions.cpp -lnetsocketpp -g clean: - rm -rf ConfigFileTest ModDescriptionTest LocalModDescriptionTest ModListListTest LocalModListTest RepositoryInfoTest + rm -rf ConfigFileTest ModDescriptionTest LocalModDescriptionTest ModListListTest LocalModListTest RepositoryInfoTest ModInfoTest diff --git a/tests/ModInfoTest.cpp b/tests/ModInfoTest.cpp new file mode 100644 index 0000000..ff8507d --- /dev/null +++ b/tests/ModInfoTest.cpp @@ -0,0 +1,204 @@ +#include "../ModInfo.h" +#include "NetSocket++/NetSocketPP.h" +#include "../ModDescription.h" +#include "../ModInfoDescription.h" +#include "../3mExceptions.h" +#include +#include +#include +using namespace std; + +int main() { + char mode; + cout << "Select mode: Download and parse (r)emote modinfo file, Open, parse and edit (l)ocal modinfo file, Create (n)ew modinfo file: "; + cin >> mode; + if(mode == 'r') { + string server; + string path; + cout << "Enter server where modinfo is located: "; + cin >> server; + cout << "Enter path of the remote modinfo: "; + cin >> path; + mmm::ModInfoDescription midesc("", server, path); + try { + mmm::ModInfo mi(midesc); + cout << "Got modinfo: " << mi.getName() << "!" << endl << "description: " << mi.getDescription() << endl << "release: " << mi.getReleaseNr() << endl << "dependencies:" << endl; + mi.resetDependencyIterator(); + while(!mi.dependenciesEnd()) { + std::string dep = mi.getNextDependency(); + if(dep != "") { + cout << dep << endl; + } + } + cout << "repository type: " << mi.getRepositoryType() << endl << "repository address: " << mi.getRepositoryAddress() << endl; + cout << "All OK!" << endl; + } catch (NetSocketPP::NetworkException &exc) { + cerr << "NetSocket++ throwed NetworkException: " << exc.what() << "! Exiting..." << endl; + return EXIT_FAILURE; + } catch (NetSocketPP::SocketException &exc) { + cerr << "NetSocket++ throwed SocketException: " << exc.what() << "! Exiting..." << endl; + return EXIT_FAILURE; + } catch (mmm::ParseException &exc) { + cerr << "ParseException occured: " << exc.what() << ". That means your remote modinfo file is not formatted properly! Exiting..." << endl; + return EXIT_FAILURE; + } catch (mmm::BadResponseException &exc) { + cerr << "BadResponseException occured: " << exc.what() << ". That usually means you have given wrong modinfo server or path. Exiting..." << endl; + return EXIT_FAILURE; + } + } else if(mode == 'l') { + std::string path; + cout << "Path to local modinfo file: "; + cin >> path; + try { + mmm::ModInfo mi(path); + char action; + do { + cout << "Select action: (l)ist modinfo, (i)ncrease modinfo release, (e)dit all modinfo fields, (s)ave and exit, (q)uit without saving: "; + cin >> action; + if(action == 'l') { + cout << "name: " << mi.getName() << endl << "description: " << mi.getDescription() << endl << "release: " << mi.getReleaseNr() << endl << "dependencies:" << endl; + mi.resetDependencyIterator(); + while(!mi.dependenciesEnd()) { + std::string dep = mi.getNextDependency(); + if(dep != "") { + cout << dep << endl; + } + } + cout << "repository type: " << mi.getRepositoryType() << endl << "repository address: " << mi.getRepositoryAddress() << endl; + } else if(action == 'i') { + mi.releaseInc(); + } else if(action == 'e') { + std::string name, desc, dep, repotype, repoaddr; + int release; + cout << "name: "; + cin >> name; + if(name != "") { + mi.setName(name); + } + cout << "description: "; + cin >> desc; + if(desc != "") { + mi.setDescription(desc); + } + cout << "release: "; + cin >> release; + if(release > 0) { + mi.setReleaseNr(release); + } + cout << "dependencies ('end' to finish): "; + do { + cin >> dep; + if(dep != "" && dep != "end") { + mi.insertDependency(dep); + } + } while(dep != "end"); + cout << "repository type: "; + cin >> repotype; + if(repotype != "") { + mi.setRepositoryType(repotype); + } + cout << "repository address: "; + cin >> repoaddr; + if(repoaddr != "") { + mi.setRepositoryAddress(repoaddr); + } + } else if(action != 's' && action != 'q') { + cout << "Unknown action!" << endl; + } + } while(action != 's' && action != 'q'); + if(action == 's') { + mi.write(); + } + cout << "All OK!" << endl; + } catch(mmm::FileException &exc) { + cerr << "FileException occured: " << exc.what() << "! Exiting..." << endl; + return EXIT_FAILURE; + } catch(mmm::ParseException &exc) { + cerr << "ParseException occured: " << exc.what() << ". That means your remote modinfo file is not formatted properly! Exiting..." << endl; + return EXIT_FAILURE; + } catch(mmm::NonEditableException &exc) { + cerr << "NonEditableException occured: " << exc.what() << "! Exiting..." << endl; + return EXIT_FAILURE; + } + } else if(mode == 'n') { + std::string path; + cout << "Path to new modinfo file: "; + cin >> path; + try { + mmm::ModInfo mi; + mi.setPath(path); + char action; + do { + cout << "Select action: (l)ist modinfo, (i)ncrease modinfo release, (e)dit all modinfo fields, (s)ave and exit, (q)uit without saving: "; + cin >> action; + if(action == 'l') { + cout << "name: " << mi.getName() << endl << "description: " << mi.getDescription() << endl << "release: " << mi.getReleaseNr() << endl << "dependencies:" << endl; + mi.resetDependencyIterator(); + while(!mi.dependenciesEnd()) { + std::string dep = mi.getNextDependency(); + if(dep != "") { + cout << dep << endl; + } + } + cout << "repository type: " << mi.getRepositoryType() << endl << "repository address: " << mi.getRepositoryAddress() << endl; + } else if(action == 'i') { + mi.releaseInc(); + } else if(action == 'e') { + std::string name, desc, dep, repotype, repoaddr; + int release; + cout << "name: "; + cin >> name; + if(name != "") { + mi.setName(name); + } + cout << "description: "; + cin >> desc; + if(desc != "") { + mi.setDescription(desc); + } + cout << "release: "; + cin >> release; + if(release > 0) { + mi.setReleaseNr(release); + } + cout << "dependencies ('end' to finish): "; + do { + cin >> dep; + if(dep != "" && dep != "end") { + mi.insertDependency(dep); + } + } while(dep != "end"); + cout << "repository type: "; + cin >> repotype; + if(repotype != "") { + mi.setRepositoryType(repotype); + } + cout << "repository address: "; + cin >> repoaddr; + if(repoaddr != "") { + mi.setRepositoryAddress(repoaddr); + } + } else if(action != 's' && action != 'q') { + cout << "Unknown action!" << endl; + } + } while(action != 's' && action != 'q'); + if(action == 's') { + mi.write(); + } + cout << "All OK!" << endl; + } catch(mmm::FileException &exc) { + cerr << "FileException occured: " << exc.what() << "! Exiting..." << endl; + return EXIT_FAILURE; + } catch(mmm::ParseException &exc) { + cerr << "ParseException occured: " << exc.what() << ". That means your remote modinfo file is not formatted properly! Exiting..." << endl; + return EXIT_FAILURE; + } catch(mmm::NonEditableException &exc) { + cerr << "NonEditableException occured: " << exc.what() << "! Exiting..." << endl; + return EXIT_FAILURE; + } + } else { + cerr << "Unknown mode: " << mode << "! Exiting..."; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +}