From 9cf4daca3bb7ed7adf4db850b40a29be2771c588 Mon Sep 17 00:00:00 2001 From: Matteo Cypriani Date: Thu, 11 Feb 2010 09:46:40 +0100 Subject: [PATCH] [Positioning] Add Configuration and UserInterface - Add class Configuration, a stock for the configuration structure. - Add class UserInterface, that handles the configuration input. - Update owlps-positioning.cc (delete old stuff like configuration) and delete owlps-positioning.hh: we now have a compilable executable. --- .gitignore | 1 + owlps-positioning/.gitignore | 1 + owlps-positioning/Makefile | 12 +- owlps-positioning/TODO | 5 + owlps-positioning/configuration.cc | 40 ++++++ owlps-positioning/configuration.hh | 26 ++++ owlps-positioning/owlps-positioning.cc | 66 +-------- owlps-positioning/owlps-positioning.hh | 14 -- owlps-positioning/stock.cc | 8 +- owlps-positioning/tests/configuration_test.hh | 22 +++ owlps-positioning/tests/userinterface_test.hh | 88 ++++++++++++ owlps-positioning/userinterface.cc | 128 ++++++++++++++++++ owlps-positioning/userinterface.hh | 40 ++++++ 13 files changed, 367 insertions(+), 84 deletions(-) create mode 100644 owlps-positioning/configuration.cc create mode 100644 owlps-positioning/configuration.hh delete mode 100644 owlps-positioning/owlps-positioning.hh create mode 100644 owlps-positioning/tests/configuration_test.hh create mode 100644 owlps-positioning/tests/userinterface_test.hh create mode 100644 owlps-positioning/userinterface.cc create mode 100644 owlps-positioning/userinterface.hh diff --git a/.gitignore b/.gitignore index 1f59a6a..05198fa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *~ *.o *.swp +*.orig diff --git a/owlps-positioning/.gitignore b/owlps-positioning/.gitignore index 237906e..9e8be5e 100644 --- a/owlps-positioning/.gitignore +++ b/owlps-positioning/.gitignore @@ -2,3 +2,4 @@ doc csv/*.csv tests/*.cc tests/tests +owlps-positioning diff --git a/owlps-positioning/Makefile b/owlps-positioning/Makefile index b175b93..d2a172a 100644 --- a/owlps-positioning/Makefile +++ b/owlps-positioning/Makefile @@ -17,7 +17,7 @@ RM_RECURSIVE = \rm -fr CP = cp -v # Autres outils -STYLE = astyle --style=gnu +STYLE = astyle --style=gnu --formatted CPPCHECK = cppcheck --enable=all DOXYGEN = doxygen @@ -26,20 +26,20 @@ GXX = g++-4.4 TESTSGXXFLAGS = -I$(TEST_DIR) -I. GXXFLAGS = $(DEBUG) -Wall -Wextra $(STLPORTGXXFLAGS) LD = $(GXX) -LDFLAGS = -lm -lrt -LIBS = -lpq -lboost_program_options-mt +LDFLAGS = -lm -lrt -lboost_program_options +#LIBS = -lpq TARGET = owlps-positioning #HEADER = owlps-positioning.hh OBJ = posutil.o stock.o timestamp.o point3d.o referencepoint.o \ waypoint.o building.o area.o wifidevice.o accesspoint.o \ mobile.o measurement.o calibrationmeasurement.o request.o \ - inputcsv.o + inputcsv.o configuration.o userinterface.o all: $(TARGET) %: %.o - $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(LD) $(LDFLAGS) -o $@ $^ %.o: %.cc $(HEADER) $(GXX) $(GXXFLAGS) -c $< @@ -49,6 +49,8 @@ $(TEST_DIR)/%_test.o: %.o posutil.o: posutil.hh stock.o: stock.hh +configuration.o: configuration.hh +userinterface.o: userinterface.hh configuration.o timestamp.o: timestamp.hh point3d.o: point3d.hh referencepoint.o : referencepoint.hh point3d.o diff --git a/owlps-positioning/TODO b/owlps-positioning/TODO index b4d4516..6b5fe18 100644 --- a/owlps-positioning/TODO +++ b/owlps-positioning/TODO @@ -4,6 +4,11 @@ utilisant les champs de direction. ° Lire la direction en tant qu'entier plutôt que float ? +- Tests unitaires + Écrire une classe utilitaire pour les tests contenant par exemple + une fonction pour écrire un fichier de test à partir d'un + vector. + - Réorganisation du dépôt ? owlps-positioning/src owlps-positioning/include diff --git a/owlps-positioning/configuration.cc b/owlps-positioning/configuration.cc new file mode 100644 index 0000000..da8ce29 --- /dev/null +++ b/owlps-positioning/configuration.cc @@ -0,0 +1,40 @@ +#include "configuration.hh" + +namespace po = boost::program_options ; + + + +/* *** Attribute definitions *** */ + +po::variables_map Configuration::configuration ; + + + +/* *** Read accessors *** */ + + +po::variables_map& Configuration::getw_configuration() +{ + return configuration ; +} + + +bool Configuration::is_configured(const std::string &key) +{ + if (configuration.count(key)) + return true ; + return false ; +} + + +const std::string& +Configuration::get_string_value(const std::string &key) +{ + return configuration[key].as() ; +} + + +int Configuration::get_int_value(const std::string &key) +{ + return configuration[key].as() ; +} diff --git a/owlps-positioning/configuration.hh b/owlps-positioning/configuration.hh new file mode 100644 index 0000000..67d0a57 --- /dev/null +++ b/owlps-positioning/configuration.hh @@ -0,0 +1,26 @@ +#ifndef _OWLPS_POSITIONING_CONFIGURATION_HH_ +#define _OWLPS_POSITIONING_CONFIGURATION_HH_ + +#include +#include + +/// Stocks the configuration of the program +class Configuration +{ +private: + /// Configuration structure + static boost::program_options::variables_map configuration ; + + +public: + /// Get a reference to the configuration structure + static boost::program_options::variables_map& getw_configuration(void) ; + /// Checks if the key exists in the configuration + static bool is_configured(const std::string &key) ; + /// Get the string value corresponding to \em key + static const std::string& get_string_value(const std::string &key) ; + /// Get the int value corresponding to \em key + static int get_int_value(const std::string &key) ; +} ; + +#endif // _OWLPS_POSITIONING_CONFIGURATION_HH_ diff --git a/owlps-positioning/owlps-positioning.cc b/owlps-positioning/owlps-positioning.cc index fc9b309..035d662 100644 --- a/owlps-positioning/owlps-positioning.cc +++ b/owlps-positioning/owlps-positioning.cc @@ -1,64 +1,10 @@ -#include "owlps-positioning.hh" +#include "userinterface.hh" -int main(int argc, char** argv) + +int main(int argc, char **argv) { - string config_filename = DEFAULT_CONFIG_FILE; - int port, mport; + UserInterface *ui = new UserInterface(argc, argv) ; + delete ui ; // We don't need it any more - - /* Options spécifiques à la ligne de commandes */ - po::options_description generic("Options générales "); - generic.add_options() - ("help,h", "Affichage de l'aide") - ("config-file,f", po::value(), "Fichier de configuration") - ("input-topo,T", po::value(), "Input file topology") - ("input-waypoint,W", po::value(), "Input file waypoint") - ("input-refpoint,R", po::value(), "Input file reference point") - ("input-ap,A", po::value(), "Input file accesspoint") - ; - - /* Options ligne de commandes & fichier de configuration */ - po::options_description config("Paramètres "); - config.add_options() - ("server.port,l", po::value(&port) -> default_value(9902), "Port d'écoute du serveur") - ("server.mobile-port,p", po::value(&mport) -> default_value(9903), "Port d'envoi vers le mobile") - ("db.name,D", po::value(), "Nom de la base de données à utiliser") - ("db.host,H", po::value(), "Adresse de l'hôte hébergeant la base de données") - ("db.user,U", po::value(), "Nom de l'utilisateur pour la connexion à la base de données") - ("db.passwd,P", po::value(), "Mot de passe pour la connexion à la base de données") - ; - - /* Total des options acceptées en ligne de commandes */ - po::options_description cmd_line_options("Options acceptées ") ; - cmd_line_options.add(generic).add(config) ; - - /* Parcours de la ligne de commandes */ - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, cmd_line_options), vm) ; - - if (vm.count("help")) // L'utilisateur a demandé l'aide - { - cout << cmd_line_options << endl ; - return 0 ; - } - - if (vm.count("config-file")) // L'utilisateur a spécifié un fichier de config - config_filename = vm["config-file"].as() ; - - ifstream ifs(config_filename.c_str()); - if (!ifs.is_open()) - cerr << "Attention ! Erreur lors de l'ouverture du fichier de configuration « " << config_filename << " » : le fichier n'existe pas ou ne peut être lu.\nUtilisation des valeurs par défaut..." << endl ; - else // Parcours du fichier de config - po::store(po::parse_config_file(ifs, config), vm) ; - - po::notify(vm); - - Server server(port, mport); - - if (server.init(vm)) - return 1 ; - - server.start(); - - return 0; + return 0 ; } diff --git a/owlps-positioning/owlps-positioning.hh b/owlps-positioning/owlps-positioning.hh deleted file mode 100644 index 948166f..0000000 --- a/owlps-positioning/owlps-positioning.hh +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _OWLPS_HH_ -#define _OWLPS_HH_ - -#include -#include - -#include - -#include "server.hh" - -//using namespace std ; -//namespace po = boost::program_options ; - -#endif // _OWLPS_HH_ diff --git a/owlps-positioning/stock.cc b/owlps-positioning/stock.cc index 2ea0dd1..686a85d 100644 --- a/owlps-positioning/stock.cc +++ b/owlps-positioning/stock.cc @@ -7,13 +7,11 @@ using std::tr1::unordered_map ; -/* *** Attribute definition *** */ +/* *** Attribute definitions *** */ -unordered_map Stock::mobiles = - unordered_map() ; +unordered_map Stock::mobiles ; -unordered_map Stock::aps = - unordered_map() ; +unordered_map Stock::aps ; diff --git a/owlps-positioning/tests/configuration_test.hh b/owlps-positioning/tests/configuration_test.hh new file mode 100644 index 0000000..80544d1 --- /dev/null +++ b/owlps-positioning/tests/configuration_test.hh @@ -0,0 +1,22 @@ +#include + +#include "configuration.hh" + +class Configuration_test: public CxxTest::TestSuite +{ +public: + + void test_accessors(void) + { + // Non-configured values + TS_ASSERT(! Configuration::is_configured("miaou")) ; + TS_ASSERT(! Configuration::is_configured("ouaf")) ; + + /* + * Due to the lack of direct variables_map manipulators, it is + * hard to manually add values in order to test them. + * Some other tests are done in userinterface_test.hh. + */ + } + +} ; diff --git a/owlps-positioning/tests/userinterface_test.hh b/owlps-positioning/tests/userinterface_test.hh new file mode 100644 index 0000000..b46f601 --- /dev/null +++ b/owlps-positioning/tests/userinterface_test.hh @@ -0,0 +1,88 @@ +#include + +#include "userinterface.hh" + +#include +#include + +class UserInterface_test: public CxxTest::TestSuite +{ +private: + std::string config_file_name ; + std::vector config_lines ; // Test config file contents + +public: + + UserInterface_test(void) + { + // If we cannot open the file, we want to stop the test + CxxTest::setAbortTestOnFail(true) ; + + // Filling name and contents of the config test file + config_file_name = "/tmp/UserInterface_test_config_file.csv" ; + config_lines.push_back("\n") ; + config_lines.push_back("[server]\n") ; + config_lines.push_back("\n") ; + config_lines.push_back("port = 42\n") ; + config_lines.push_back("\n") ; + + // Opening the file + std::ofstream config_file ; + config_file.open(config_file_name.c_str()) ; + if (! config_file) + TS_FAIL("Cannot open test config file for creation!") ; + + // Writing contents to the file + for (std::vector::const_iterator i = config_lines.begin() ; + i != config_lines.end() ; ++i) + config_file << *i ; + + config_file.close() ; + + // Back to the normal behaviour (i.e. do not abort on fail) + CxxTest::setAbortTestOnFail(false) ; + } + + + ~UserInterface_test(void) + { + // Deleting the test config file + if (remove(config_file_name.c_str()) == -1) + TS_WARN("Cannot remove test config file!") ; + } + + + static UserInterface_test* createSuite(void) + { + return new UserInterface_test() ; + } + + + static void destroySuite(UserInterface_test *suite) + { + delete suite ; + } + + + void test_constructors(void) + { + // Note: as --help makes the program exit, we cannot test it. + const char *argv[] = + { + "owlps-positioning", // program name + "--config-file", + config_file_name.c_str() + } ; + int argc = 3 ; + + UserInterface ui(argc, const_cast(argv)) ; + + TS_ASSERT(Configuration::is_configured("server.port")) ; + TS_ASSERT(Configuration::is_configured("config-file")) ; + + TS_ASSERT_EQUALS(Configuration::get_int_value("server.port"), 42) ; + TS_ASSERT_EQUALS(Configuration::get_string_value("config-file"), + config_file_name) ; + } + +} ; diff --git a/owlps-positioning/userinterface.cc b/owlps-positioning/userinterface.cc new file mode 100644 index 0000000..1ec4a68 --- /dev/null +++ b/owlps-positioning/userinterface.cc @@ -0,0 +1,128 @@ +#include "userinterface.hh" +#include "configuration.hh" + +#include +#include +#include + +using namespace std ; +namespace po = boost::program_options ; + + + +/* *** Default value definitions *** */ + +#define DEFAULT_CONFIG_FILE_NAME "cfg/owlps-positioning.cfg" +#define DEFAULT_LISTENING_PORT 9902 + + + +/* *** Constructors *** */ + + +UserInterface::UserInterface(const int argc, char **argv) +{ + cli_argument_count = argc ; + cli_argument_values = argv ; + config_file_name = DEFAULT_CONFIG_FILE_NAME ; + + cli_options = new po::options_description("General options") ; + file_options = new po::options_description("Parameters") ; + fill_options() ; + + parse_options() ; +} + + +UserInterface::~UserInterface() +{ + delete cli_options ; + delete file_options ; +} + + + +/* *** Operations *** */ + + +void UserInterface::fill_options() +{ + fill_cli_options() ; + fill_file_options() ; + + // File options are also accepted on the command line + cli_options->add(*file_options) ; +} + + +void UserInterface::fill_cli_options() +{ + cli_options->add_options() + ("help,h", "Print help") + ("config-file,f", po::value(), + "Alternative configuration file") + ; +} + + +void UserInterface::fill_file_options() +{ + file_options->add_options() + ("server.port,l", po::value() + ->default_value(DEFAULT_LISTENING_PORT), + "Server listening port") + ; +} + + +void UserInterface::parse_options() +{ + parse_command_line() ; + print_usage_and_exit_if_requested() ; + + // Was the config file name specified on the command line? + if (Configuration::is_configured("config-file")) + config_file_name = Configuration::get_string_value("config-file") ; + + parse_file() ; + + po::notify(Configuration::getw_configuration()) ; +} + + +void UserInterface::parse_command_line() const +{ + po::store(po::parse_command_line(cli_argument_count, + cli_argument_values, + *cli_options), + Configuration::getw_configuration()) ; +} + + +void UserInterface::print_usage_and_exit_if_requested() const +{ + if (Configuration::is_configured("help")) + { + cout << *cli_options ; + exit(0) ; + } +} + + +void UserInterface::parse_file() const +{ + ifstream config_file(config_file_name.c_str()) ; + + if (! config_file) + { + cerr + << "Warning! Error opening input configuration file « " + << config_file_name + << " »! Using command line and default values…" + << endl ; + return ; + } + + po::store(po::parse_config_file(config_file, *file_options), + Configuration::getw_configuration()) ; +} diff --git a/owlps-positioning/userinterface.hh b/owlps-positioning/userinterface.hh new file mode 100644 index 0000000..1bee921 --- /dev/null +++ b/owlps-positioning/userinterface.hh @@ -0,0 +1,40 @@ +#ifndef _OWLPS_POSITIONING_USERINTERFACE_HH_ +#define _OWLPS_POSITIONING_USERINTERFACE_HH_ + +#include +#include + +/// Handles configuration inputs from user +class UserInterface +{ +protected: + std::string config_file_name ; + int cli_argument_count ; + char **cli_argument_values ; + boost::program_options::options_description *cli_options ; + boost::program_options::options_description *file_options ; + + /** @name Operations */ + //@{ + /// Fill in all the options + void fill_options(void) ; + /// Fill in the options accepted on the command line + void fill_cli_options(void) ; + /// \brief Fill in the options accepted on the command line and in + /// the configuration file + void fill_file_options(void) ; + /// Parse all the configuration inputs and updates Configuration + void parse_options(void) ; + void parse_command_line(void) const ; + void parse_file(void) const ; + /// If help was requested by user, displays accepted options and exit + void print_usage_and_exit_if_requested(void) const ; + //@} + +public: + UserInterface(const int argc, char **argv) ; + + ~UserInterface(void) ; +} ; + +#endif // _OWLPS_POSITIONING_USERINTERFACE_HH_