Commit cef7980f authored by Matthieu Dorier's avatar Matthieu Dorier

finished API, started CppUnit testing

parent 5ff11a14
......@@ -9,7 +9,6 @@
cmake_minimum_required (VERSION 3.0)
project (hepnos CXX)
enable_testing ()
add_definitions (-g)
......@@ -46,6 +45,19 @@ xpkg_import_module (bake-server REQUIRED bake-server)
xpkg_import_module (ch-placement REQUIRED ch-placement)
find_package (yaml-cpp REQUIRED)
find_package (CppUnit)
if (CPPUNIT_FOUND)
message(STATUS "CppUnit found, unit tests will be compiled")
include_directories(${CPPUNIT_INCLUDE_DIR})
enable_testing()
else (CPPUNIT_FOUND)
message(STATUS "CppUnit not found, unit tests will not be compiled")
endif (CPPUNIT_FOUND)
add_subdirectory (src)
add_subdirectory (test)
add_subdirectory (bin)
if(CPPUNIT_FOUND AND ENABLE_TESTS)
message(STATUS "Unit tests are enabled, will be built")
add_subdirectory (test)
endif(CPPUNIT_FOUND AND ENABLE_TESTS)
add_executable(hepnos-service hepnos-service.cpp hepnos-service-util.cpp)
target_link_libraries(hepnos-service sdskv-server bake-server yaml-cpp)
add_executable(hepnos-daemon hepnos-daemon.cpp)
target_link_libraries(hepnos-daemon hepnos-service yaml-cpp margo bake-server sdskv-server)
/*
* (C) 2018 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <unistd.h>
#include <mpi.h>
#include <margo.h>
#include <bake-server.h>
#include <sdskv-server.h>
#include <yaml-cpp/yaml.h>
#include "hepnos-service.h"
#define ASSERT(__cond, __msg, ...) { if(!(__cond)) { fprintf(stderr, "[%s:%d] " __msg, __FILE__, __LINE__, __VA_ARGS__); exit(-1); } }
void usage(void)
{
fprintf(stderr, "Usage: hepnos-service <addr> <config>\n");
fprintf(stderr, " <addr> the Mercury address to listen on (e.g. tcp://)\n");
fprintf(stderr, " <config> path to the YAML file to generate for clients\n");
exit(-1);
}
int main(int argc, char *argv[])
{
char* listen_addr;
char* config_file;
int rank;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(argc != 3) {
if(rank == 0) {
usage();
}
MPI_Finalize();
exit(0);
}
listen_addr = argv[1];
config_file = argv[2];
hepnos_run_service(MPI_COMM_WORLD, listen_addr, config_file);
MPI_Finalize();
}
#include "hepnos-service-util.hpp"
int hepnos_sdskv_provider_setup(sdskv_provider_t sdskv_provider) {
}
#ifndef __HEPNOS_SERVICE_UTIL_H
#define __HEPNOS_SERVICE_UTIL_H
#include <sdskv-server.h>
int hepnos_sdskv_provider_setup(sdskv_provider_t sdskv_provider);
#endif
#
# Find the CppUnit includes and library
#
# This module defines
# CPPUNIT_INCLUDE_DIR, where to find tiff.h, etc.
# CPPUNIT_LIBRARIES, the libraries to link against to use CppUnit.
# CPPUNIT_FOUND, If false, do not try to use CppUnit.
# also defined, but not for general use are
# CPPUNIT_LIBRARY, where to find the CppUnit library.
# CPPUNIT_DEBUG_LIBRARY, where to find the CppUnit library in debug mode.
FIND_PATH(CPPUNIT_INCLUDE_DIR cppunit/TestCase.h HINTS
/usr/local/include
/usr/include
ENV CppUnit_ROOT
)
# With Win32, important to have both
IF(WIN32)
FIND_LIBRARY(CPPUNIT_LIBRARY cppunit
${CPPUNIT_INCLUDE_DIR}/../lib
/usr/local/lib
/usr/lib)
FIND_LIBRARY(CPPUNIT_DEBUG_LIBRARY cppunitd
${CPPUNIT_INCLUDE_DIR}/../lib
/usr/local/lib
/usr/lib)
ELSE(WIN32)
# On unix system, debug and release have the same name
FIND_LIBRARY(CPPUNIT_LIBRARY cppunit
${CPPUNIT_INCLUDE_DIR}/../lib
/usr/local/lib
/usr/lib)
FIND_LIBRARY(CPPUNIT_DEBUG_LIBRARY cppunit
${CPPUNIT_INCLUDE_DIR}/../lib
/usr/local/lib
/usr/lib)
ENDIF(WIN32)
IF(CPPUNIT_INCLUDE_DIR)
IF(CPPUNIT_LIBRARY)
SET(CPPUNIT_FOUND "YES")
SET(CPPUNIT_LIBRARIES ${CPPUNIT_LIBRARY} ${CMAKE_DL_LIBS})
SET(CPPUNIT_DEBUG_LIBRARIES ${CPPUNIT_DEBUG_LIBRARY}
${CMAKE_DL_LIBS})
ENDIF(CPPUNIT_LIBRARY)
ENDIF(CPPUNIT_INCLUDE_DIR)
#ifndef __HEPNOS_SERVICE_H
#define __HEPNOS_SERVICE_H
#include <mpi.h>
#ifdef __cplusplus
extern "C" {
#endif
void hepnos_run_service(MPI_Comm comm, const char* listen_addr, const char* config_file);
#ifdef __cplusplus
}
#endif
#endif
#ifndef __HEPNOS_H
#define __HEPNOS_H
#include <hepnos/DataStore.hpp>
#include <hepnos/DataSet.hpp>
#include <hepnos/Demangle.hpp>
#include <hepnos/Event.hpp>
#include <hepnos/EventNumber.hpp>
#include <hepnos/Exception.hpp>
#include <hepnos/KeyValueContainer.hpp>
#include <hepnos/Run.hpp>
#include <hepnos/RunNumber.hpp>
#include <hepnos/RunSet.hpp>
#include <hepnos/SubRun.hpp>
#include <hepnos/SubRunNumber.hpp>
#endif
......@@ -237,6 +237,11 @@ class DataStore {
*/
DataSet createDataSet(const std::string& name);
/**
* @brief Shuts down the HEPnOS service.
*/
void shutdown();
private:
/**
......
......@@ -7,11 +7,14 @@
#define __HEPNOS_EVENT_NUMBER_H
#include <cstdint>
#include <limits>
namespace hepnos {
typedef std::uint64_t EventNumber;
const EventNumber InvalidEventNumber = std::numeric_limits<EventNumber>::max();
}
#endif
......@@ -7,11 +7,14 @@
#define __HEPNOS_RUN_NUMBER_H
#include <cstdint>
#include <limits>
namespace hepnos {
typedef std::uint64_t RunNumber;
const RunNumber InvalidRunNumber = std::numeric_limits<RunNumber>::max();
}
#endif
......@@ -22,6 +22,7 @@ namespace hepnos {
class RunSet {
friend class DataSet::Impl;
friend class DataSet;
private:
......@@ -81,6 +82,18 @@ class RunSet {
class const_iterator;
class iterator;
/**
* @brief Accesses an existing Run using the ()
* operator. If no Run correspond to the provided number,
* the function returns a Run instance r such that
* r.valid() is false.
*
* @param runNumber run number of the Run to retrieve.
*
* @return a Run corresponding to the provided number.
*/
Run operator()(const RunNumber& runNumber);
/**
* @brief Searches this RunSet for a Run with
* the provided run number and returns an iterator to
......
......@@ -7,11 +7,14 @@
#define __HEPNOS_SUB_RUN_NUMBER_H
#include <cstdint>
#include <limits>
namespace hepnos {
typedef std::uint64_t SubRunNumber;
const SubRunNumber InvalidSubRunNumber = std::numeric_limits<SubRunNumber>::max();
}
#endif
......@@ -6,6 +6,8 @@ set(hepnos-src DataStore.cpp
SubRun.cpp
Event.cpp)
set(hepnos-service-src service/HEPnOSService.cpp)
# load package helper for generating cmake CONFIG packages
include (CMakePackageConfigHelpers)
......@@ -15,8 +17,8 @@ set (hepnos-pkg "share/cmake/hepnos")
#
# library version set here (e.g. for shared libs).
#
set (HEPNOS_VERSION_MAJOR 1)
set (HEPNOS_VERSION_MINOR 0)
set (HEPNOS_VERSION_MAJOR 0)
set (HEPNOS_VERSION_MINOR 1)
set (HEPNOS_VERSION_PATCH 0)
set (hepnos-vers "${HEPNOS_VERSION_MAJOR}.${HEPNOS_VERSION_MINOR}")
set (HEPNOS_VERSION "${hepnos-vers}.${HEPNOS_VERSION_PATCH}")
......@@ -35,6 +37,18 @@ set_target_properties (hepnos
PROPERTIES VERSION ${HEPNOS_VERSION}
SOVERSION ${HEPNOS_VERSION_MAJOR})
add_library(hepnos-service ${hepnos-service-src})
target_link_libraries (hepnos mercury margo yaml-cpp sdskv-client sdskv-server bake-client bake-server ch-placement)
target_include_directories (hepnos-service PUBLIC $<INSTALL_INTERFACE:include>)
# local include's BEFORE, in case old incompatable .h files in prefix/include
target_include_directories (hepnos-service BEFORE PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>)
# for shared libs, establish the lib version
set_target_properties (hepnos-service
PROPERTIES VERSION ${HEPNOS_VERSION}
SOVERSION ${HEPNOS_VERSION_MAJOR})
#
# installation stuff (packaging and install commands)
#
......@@ -49,12 +63,13 @@ configure_file (hepnos-config.cmake.in hepnos-config.cmake @ONLY)
#
# "make install" rules
#
#install (TARGETS hepnos EXPORT hepnos-targets
# ARCHIVE DESTINATION lib
# LIBRARY DESTINATION lib)
#install (EXPORT hepnos-targets
# DESTINATION ${hepnos-pkg}
# FILE "hepnos-targets.cmake")
install (TARGETS hepnos EXPORT hepnos-targets
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib)
install (TARGETS hepnos-service ARCHIVE DESTINATION lib LIBRARY DESTINATION lib)
install (EXPORT hepnos-targets
DESTINATION ${hepnos-pkg}
FILE "hepnos-targets.cmake")
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/hepnos-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/hepnos-config-version.cmake"
"../cmake/xpkg-import.cmake"
......@@ -62,3 +77,6 @@ install (FILES "${CMAKE_CURRENT_BINARY_DIR}/hepnos-config.cmake"
install (DIRECTORY ../include/hepnos
DESTINATION include
FILES_MATCHING PATTERN "*.hpp")
install (DIRECTORY ../include/hepnos
DESTINATION include
FILES_MATCHING PATTERN "*.h")
......@@ -6,6 +6,7 @@
#include "hepnos/DataSet.hpp"
#include "hepnos/Run.hpp"
#include "hepnos/RunSet.hpp"
#include "private/RunSetImpl.hpp"
#include "private/RunImpl.hpp"
#include "private/DataSetImpl.hpp"
#include "private/DataStoreImpl.hpp"
......@@ -36,7 +37,10 @@ DataSet::DataSet(const DataSet& other)
other.m_impl->m_container,
other.m_impl->m_name)) {}
DataSet::DataSet(DataSet&&) = default;
DataSet::DataSet(DataSet&& other)
: m_impl(std::move(other.m_impl)) {
m_impl->m_runset.m_impl->m_dataset = this;
}
DataSet& DataSet::operator=(const DataSet& other) {
if(this == &other) return *this;
......@@ -48,7 +52,12 @@ DataSet& DataSet::operator=(const DataSet& other) {
return *this;
}
DataSet& DataSet::operator=(DataSet&&) = default;
DataSet& DataSet::operator=(DataSet&& other) {
if(this == &other) return *this;
m_impl = std::move(other.m_impl);
m_impl->m_runset.m_impl->m_dataset = this;
return *this;
}
DataSet::~DataSet() {}
......@@ -59,7 +68,7 @@ DataSet DataSet::next() const {
size_t s = m_impl->m_datastore->m_impl->nextKeys(
m_impl->m_level, m_impl->m_container, m_impl->m_name, keys, 1);
if(s == 0) return DataSet();
return DataSet(m_impl->m_datastore, m_impl->m_level, m_impl->m_container, keys[0]);
return DataSet(m_impl->m_datastore, m_impl->m_level, keys[0]);
}
bool DataSet::valid() const {
......@@ -111,8 +120,9 @@ std::string DataSet::fullname() const {
}
DataSet DataSet::createDataSet(const std::string& name) {
if(name.find('/') != std::string::npos) {
throw Exception("Invalid character '/' in dataset name");
if(name.find('/') != std::string::npos
|| name.find('%') != std::string::npos) {
throw Exception("Invalid character '/' or '%' in dataset name");
}
std::string parent = fullname();
m_impl->m_datastore->m_impl->store(m_impl->m_level+1, parent, name, std::vector<char>());
......@@ -120,6 +130,9 @@ DataSet DataSet::createDataSet(const std::string& name) {
}
Run DataSet::createRun(const RunNumber& runNumber) {
if(InvalidRunNumber == runNumber) {
throw Exception("Trying to create a Run with InvalidRunNumber");
}
std::string parent = fullname();
std::string runStr = Run::Impl::makeKeyStringFromRunNumber(runNumber);
m_impl->m_datastore->m_impl->store(m_impl->m_level+1, parent, runStr, std::vector<char>());
......@@ -138,8 +151,9 @@ Run DataSet::operator()(const RunNumber& runNumber) const {
DataSet::iterator DataSet::find(const std::string& datasetName) {
int ret;
if(datasetName.find('/') != std::string::npos) {
throw Exception("Invalid character '/' in dataset name");
if(datasetName.find('/') != std::string::npos
|| datasetName.find('%') != std::string::npos) {
throw Exception("Invalid character '/' or '%' in dataset name");
}
std::vector<char> data;
std::string parent = fullname();
......
......@@ -54,7 +54,7 @@ DataStore::iterator DataStore::find(const std::string& datasetName) {
if(!b) {
return m_impl->m_end;
}
return iterator(DataSet(this, 1, datasetName));
return iterator(DataSet(this, 1, "", datasetName));
}
DataSet DataStore::operator[](const std::string& datasetName) const {
......@@ -137,6 +137,12 @@ DataSet DataStore::createDataSet(const std::string& name) {
return DataSet(this, 1, "", name);
}
void DataStore::shutdown() {
for(auto addr : m_impl->m_addrs) {
margo_shutdown_remote_instance(m_impl->m_mid, addr);
}
}
////////////////////////////////////////////////////////////////////////////////////////////
// DataStore::const_iterator::Impl implementation
////////////////////////////////////////////////////////////////////////////////////////////
......
......@@ -11,7 +11,7 @@
namespace hepnos {
Run::Run()
: m_impl(std::make_unique<Run::Impl>(nullptr, 0, "", 0)) {}
: m_impl(std::make_unique<Run::Impl>(nullptr, 0, "", InvalidRunNumber)) {}
Run::Run(DataStore* ds, uint8_t level, const std::string& container, const RunNumber& rn)
: m_impl(std::make_unique<Run::Impl>(ds, level, container, rn)) { }
......
......@@ -20,10 +20,16 @@ namespace hepnos {
////////////////////////////////////////////////////////////////////////////////////////////
RunSet::RunSet(DataSet* ds)
: m_impl(std::make_unique<RunSet::Impl>(ds)) {}
: m_impl(std::make_unique<RunSet::Impl>(ds)) {
}
RunSet::~RunSet() {}
Run RunSet::operator()(const RunNumber& runNumber) {
auto it = find(runNumber);
return std::move(*it);
}
RunSet::iterator RunSet::find(const RunNumber& runNumber) {
int ret;
std::vector<char> data;
......
......@@ -12,7 +12,7 @@
namespace hepnos {
SubRun::SubRun()
: m_impl(std::make_unique<Impl>(nullptr, 0, "", 0)) {}
: m_impl(std::make_unique<Impl>(nullptr, 0, "", InvalidSubRunNumber)) {}
SubRun::SubRun(DataStore* ds, uint8_t level, const std::string& container, const SubRunNumber& rn)
: m_impl(std::make_unique<Impl>(ds, level, container, rn)) { }
......
......@@ -7,6 +7,7 @@
#define __HEPNOS_PRIVATE_DATASTORE_IMPL
#include <vector>
#include <unordered_set>
#include <functional>
#include <iostream>
#include <yaml-cpp/yaml.h>
......@@ -28,6 +29,7 @@ class DataStore::Impl {
public:
margo_instance_id m_mid; // Margo instance
std::unordered_set<hg_addr_t> m_addrs; // Addresses used by the service
sdskv_client_t m_sdskv_client; // SDSKV client
bake_client_t m_bake_client; // BAKE client
std::vector<sdskv_provider_handle_t> m_sdskv_ph; // list of SDSKV provider handlers
......@@ -81,6 +83,7 @@ class DataStore::Impl {
cleanup();
throw Exception("margo_addr_lookup failed");
}
m_addrs.insert(addr);
if(it->second.IsScalar()) {
uint16_t provider_id = it->second.as<uint16_t>();
sdskv_provider_handle_t ph;
......@@ -128,6 +131,7 @@ class DataStore::Impl {
cleanup();
throw Exception("margo_addr_lookup failed");
}
m_addrs.insert(addr);
if(it->second.IsScalar()) {
uint16_t provider_id = it->second.as<uint16_t>();
bake_provider_handle_t ph;
......
......@@ -13,44 +13,27 @@
#include <bake-server.h>
#include <sdskv-server.h>
#include <yaml-cpp/yaml.h>
#include "hepnos-service-util.hpp"
#include "hepnos-service.h"
#define ASSERT(__cond, __msg, ...) { if(!(__cond)) { fprintf(stderr, "[%s:%d] " __msg, __FILE__, __LINE__, __VA_ARGS__); exit(-1); } }
void usage(void)
{
fprintf(stderr, "Usage: hepnos-service <addr> <config>\n");
fprintf(stderr, " <addr> the Mercury address to listen on (e.g. tcp://)\n");
fprintf(stderr, " <config> path to the YAML file to generate for clients\n");
exit(-1);
}
static void generate_config_file(MPI_Comm comm, const char* addr, const char* config_file);
int main(int argc, char *argv[])
void hepnos_run_service(MPI_Comm comm, const char* listen_addr, const char* config_file)
{
char* listen_addr;
char* config_file;
margo_instance_id mid;
int ret;
/* check args */
if (argc != 3)
usage();
listen_addr = argv[1];
config_file = argv[2];
/* MPI required for SSG bootstrapping */
MPI_Init(&argc, &argv);
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_rank(comm, &rank);
/* Margo initialization */
mid = margo_init(listen_addr, MARGO_SERVER_MODE, 0, -1);
if (mid == MARGO_INSTANCE_NULL)
{
fprintf(stderr, "Error: Unable to initialize margo\n");
return -1;
MPI_Abort(MPI_COMM_WORLD, -1);
return;
}
margo_enable_remote_shutdown(mid);
......@@ -61,8 +44,6 @@ int main(int argc, char *argv[])
hg_size_t self_addr_str_size = 128;
margo_addr_to_string(mid, self_addr_str, &self_addr_str_size, self_addr);
generate_config_file(MPI_COMM_WORLD, self_addr_str, config_file);
/* Bake provider initialization */
uint16_t bake_mplex_id = 1;
char bake_target_name[128];
......@@ -94,11 +75,9 @@ int main(int argc, char *argv[])
margo_addr_free(mid, self_addr);
margo_wait_for_finalize(mid);
MPI_Finalize();
generate_config_file(MPI_COMM_WORLD, self_addr_str, config_file);
return 0;
margo_wait_for_finalize(mid);
}
static void generate_config_file(MPI_Comm comm, const char* addr, const char* config_file)
......
#!/bin/sh
ctest --output-on-failure
# Move the configuration file used for the configuration test
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run-test.sh ${CMAKE_CURRENT_BINARY_DIR}/run-test.sh COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-util.sh ${CMAKE_CURRENT_BINARY_DIR}/test-util.sh COPYONLY)
add_executable(example example.cpp)
target_link_libraries(example hepnos ${Boost_LIBRARIES})
set(CTEST_ENVIRONMENT "MKTEMP=mktemp" "TIMEOUT=timeout")
add_executable(DataStoreTest DataStoreTest.cpp HEPnOSTestMain.cpp)
target_link_libraries(DataStoreTest cppunit hepnos hepnos-service)
add_executable(DataSetTest DataSetTest.cpp HEPnOSTestMain.cpp)
target_link_libraries(DataSetTest cppunit hepnos hepnos-service)
add_executable(RunSetTest RunSetTest.cpp HEPnOSTestMain.cpp)
target_link_libraries(RunSetTest cppunit hepnos hepnos-service)
add_test(NAME DataStoreTest COMMAND run-test.sh ./DataStoreTest)
add_test(NAME DataSetTest COMMAND run-test.sh ./DataSetTest)
add_test(NAME RunSetTest COMMAND run-test.sh ./RunSetTest)
#define CPPUNIT_ASSERT_EQUAL_STR(__x,__y) CPPUNIT_ASSERT_EQUAL(std::string(__x), std::string(__y))
#include "DataSetTest.hpp"
#include "CppUnitAdditionalMacros.hpp"
CPPUNIT_TEST_SUITE_REGISTRATION( DataSetTest );
using namespace hepnos;
void DataSetTest::setUp() {}
void DataSetTest::tearDown() {}
void DataSetTest::testFillDataStore() {
auto mds = datastore->createDataSet("matthieu");
datastore->createDataSet("shane");
datastore->createDataSet("phil");
datastore->createDataSet("rob");
// erroneous dataset creations
// "/" is forbidden in the name, will throw an exception
CPPUNIT_ASSERT_THROW(
mds.createDataSet("ds0/AAA"),
hepnos::Exception);
// "%" is forbidden in the name, will throw an exception
CPPUNIT_ASSERT_THROW(
mds.createDataSet("ds0%RRS"),
hepnos::Exception);
// correct dataset creation
DataSet ds1 = mds.createDataSet("ds1");
// assert the characteristics of the created dataset
CPPUNIT_ASSERT(ds1.valid());
CPPUNIT_ASSERT_EQUAL_STR("ds1", ds1.name());
CPPUNIT_ASSERT_EQUAL_STR("matthieu", ds1.container());
CPPUNIT_ASSERT_EQUAL_STR("matthieu/ds1", ds1.fullname());
// assert comparison with a default-constructed dataset
DataSet ds0;
CPPUNIT_ASSERT(ds0 != ds1);
CPPUNIT_ASSERT(!(ds0 == ds1));
// assert that ds1.next() is not valid
DataSet ds2 = ds1.next();
CPPUNIT_ASSERT(!ds2.valid());
// create more datasets
DataSet ds3 = mds.createDataSet("ds3");
ds2 = mds.createDataSet("ds2");
// assert that these are valid
CPPUNIT_ASSERT(ds2.valid());
CPPUNIT_ASSERT(ds3.valid());
// assert that ds1.next() == ds2 and ds2.next() == ds3
CPPUNIT_ASSERT(ds2 == ds1.next());
CPPUNIT_ASSERT(ds3 == ds2.next());
// create more datasets for future tests
DataSet ds4 = mds.createDataSet("dsB");
DataSet ds5 = mds.createDataSet("dsD");
CPPUNIT_ASSERT(ds4.valid());
CPPUNIT_ASSERT(ds5.valid());
}
void DataSetTest::testBraketOperator() {
DataSet mds = (*datastore)["matthieu"];
CPPUNIT_ASSERT(mds.valid());
// check that accessing a dataset that does not exist
// yields a non-valid DataSet
DataSet ds6 = mds["ds6"];
CPPUNIT_ASSERT(!ds6.valid());
// check that accessing a dataset that exists yields
// a valid DataSet instance with correct information
DataSet ds2 = mds["ds2"];
CPPUNIT_ASSERT(ds2.valid());
CPPUNIT_ASSERT_EQUAL_STR("ds2", ds2.name());
CPPUNIT_ASSERT_EQUAL_STR("matthieu", ds2.container());
CPPUNIT_ASSERT_EQUAL_STR("matthieu/ds2", ds2.fullname());
}
void DataSetTest::testFind() {
DataSet mds = (*datastore)["matthieu"];
CPPUNIT_ASSERT(mds.valid());
// test calling find for a DataSet that does not exist
{
auto it = mds.find("ds6");
CPPUNIT_ASSERT(it == mds.end());
CPPUNIT_ASSERT(!(it->valid()));
}
// test calling find for a DataSet that exists
{
auto it = mds.find("ds2");
CPPUNIT_ASSERT(it != mds.end());
CPPUNIT_ASSERT(it->valid());
CPPUNIT_ASSERT_EQUAL_STR("ds2",it->name());
// test iteration
++it;
CPPUNIT_ASSERT(it->valid());
CPPUNIT_ASSERT_EQUAL_STR("ds3",it->name());
}
}
void DataSetTest::testBeginEnd() {
DataSet mds = (*datastore)["matthieu"];
CPPUNIT_ASSERT(mds.valid());
std::vector<std::string> names = {
"ds1", "ds2", "ds3", "dsB", "dsD"};
auto it = mds.begin();
for(int i=0; i < names.size(); i++, it++) {
CPPUNIT_ASSERT_EQUAL(names[i], it->name());
}
CPPUNIT_ASSERT(it == mds.end());
}
void DataSetTest::testLowerUpperBounds() {
DataSet mds = (*datastore)["matthieu"];
CPPUNIT_ASSERT(mds.valid());
{
auto it = mds.lower_bound("dsB");
CPPUNIT_ASSERT(it->valid());
CPPUNIT_ASSERT(it->name() == "dsB");
}
{
auto it = mds.lower_bound("dsC");
CPPUNIT_ASSERT(it->valid());
CPPUNIT_ASSERT(it->name() == "dsD");
}
{
auto it = mds.lower_bound("dsA");
CPPUNIT_ASSERT(it->valid());
CPPUNIT_ASSERT(it->name() == "dsB");
}
{
auto it = mds.lower_bound("dsE");
CPPUNIT_ASSERT(!(it->valid()));
CPPUNIT_ASSERT(it == mds.end());
}