From 3e0b13cf375486da5ee94b836e61fd6a5978f328 Mon Sep 17 00:00:00 2001 From: Enrico Zini Date: Wed, 9 Sep 2015 22:40:25 +0200 Subject: Removed ept/popcon and removed dependency on tagcoll by bundling the minimum of it that we need --- ept/CMakeLists.txt | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'ept/CMakeLists.txt') diff --git a/ept/CMakeLists.txt b/ept/CMakeLists.txt index 96e1746..5f27f14 100644 --- a/ept/CMakeLists.txt +++ b/ept/CMakeLists.txt @@ -1,28 +1,25 @@ project( ept ) include( ${WIBBLE_TEST_CMAKE} ) -file( GLOB src *.cpp debtags/*.cc debtags/maint/*.cc - popcon/*.cc popcon/maint/*.cc apt/*.cc axi/*.cc ) +file( GLOB src *.cpp debtags/*.cc debtags/maint/*.cc debtags/coll/*.cc + apt/*.cc axi/*.cc utils/*.cc ) file( GLOB h_top *.h ) file( GLOB h_apt apt/*.h ) file( GLOB h_debtags debtags/*.h debtags/*.tcc ) file( GLOB h_debtags_maint debtags/maint/*.h debtags/maint/*.tcc ) -file( GLOB h_popcon popcon/*.h ) -file( GLOB h_popcon_maint popcon/maint/*.h ) file( GLOB h_axi axi/*.h ) +file( GLOB h_utils utils/*.h ) file( GLOB debtagstesth debtags/*.test.h debtags/maint/*.test.h ) -file( GLOB popcontesth popcon/*.test.h ) file( GLOB apttesth apt/*.test.h ) file( GLOB axitesth axi/*.test.h ) -set( testh ${debtagstesth} ${popcontesth} - ${apttesth} ${axitesth} ) +set( testh ${debtagstesth} ${apttesth} ${axitesth} ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${TAGCOLL_INCLUDE_DIRS} ${WIBBLE_INCLUDE_DIRS} ) link_libraries( ${WIBBLE_LIBRARIES} ${TAGCOLL_LIBRARIES} apt-pkg xapian -lpthread ) -add_definitions( -fexceptions -fPIC -fvisibility=default ) +add_definitions( --std=c++11 -fexceptions -fPIC -fvisibility=default ) add_library( ept SHARED ${src} ) add_library( ept-static STATIC ${src} ) @@ -69,10 +66,6 @@ add_custom_command( COMMAND mkdir -p test-env/debtags/empty COMMAND mkdir -p test-env/debtags/user COMMAND mkdir -p test-env/xapian/ - COMMAND mkdir -p test-env/popcon/ - COMMAND mkdir -p test-env/popcon/empty - COMMAND cp -a ${datadir}/popcon/all-popcon-results.txt.gz test-env/popcon/ - COMMAND cp -a ${datadir}/popcon/popularity-contest test-env/popcon/ COMMAND touch data-stamp ) install( TARGETS ept ept-static @@ -84,6 +77,5 @@ install( FILES ${h_top} DESTINATION include/ept ) install( FILES ${h_apt} DESTINATION include/ept/apt ) install( FILES ${h_debtags} DESTINATION include/ept/debtags ) install( FILES ${h_debtags_maint} DESTINATION include/ept/debtags/maint ) -install( FILES ${h_popcon} DESTINATION include/ept/popcon ) -install( FILES ${h_popcon_maint} DESTINATION include/ept/popcon/maint ) install( FILES ${h_axi} DESTINATION include/ept/axi ) +install( FILES ${h_utils} DESTINATION include/ept/utils ) -- cgit v1.2.3 From c4dce3d9e4331b9f2fdbef5517a054ebf20c7d3d Mon Sep 17 00:00:00 2001 From: Enrico Zini Date: Thu, 10 Sep 2015 11:23:57 +0200 Subject: Use build-in test framework instead of wibble --- CMakeLists.txt | 17 +-- debian/rules | 2 +- ept/CMakeLists.txt | 47 +++------ ept/apt/apt-test.cc | 209 +++++++++++++++++++++++++++++++++++++ ept/apt/apt.test.h | 193 ---------------------------------- ept/apt/packagerecord-test.cc | 126 +++++++++++++++++++++++ ept/apt/packagerecord.test.h | 138 ------------------------- ept/apt/recordparser-test.cc | 200 ++++++++++++++++++++++++++++++++++++ ept/apt/recordparser.test.h | 228 ----------------------------------------- ept/apt/version-test.cc | 119 +++++++++++++++++++++ ept/apt/version.test.h | 136 ------------------------ ept/axi/axi-test.cc | 37 +++++++ ept/axi/axi.test.h | 58 ----------- ept/debtags/debtags-test.cc | 167 ++++++++++++++++++++++++++++++ ept/debtags/debtags.test.h | 197 ----------------------------------- ept/debtags/vocabulary-test.cc | 195 +++++++++++++++++++++++++++++++++++ ept/debtags/vocabulary.test.h | 222 --------------------------------------- ept/test-main.h | 186 --------------------------------- ept/test-runner.h | 63 ------------ ept/test.h | 31 +----- ept/utils/tests.h | 6 ++ run-check | 59 +++++++++++ 22 files changed, 1138 insertions(+), 1498 deletions(-) create mode 100644 ept/apt/apt-test.cc delete mode 100644 ept/apt/apt.test.h create mode 100644 ept/apt/packagerecord-test.cc delete mode 100644 ept/apt/packagerecord.test.h create mode 100644 ept/apt/recordparser-test.cc delete mode 100644 ept/apt/recordparser.test.h create mode 100644 ept/apt/version-test.cc delete mode 100644 ept/apt/version.test.h create mode 100644 ept/axi/axi-test.cc delete mode 100644 ept/axi/axi.test.h create mode 100644 ept/debtags/debtags-test.cc delete mode 100644 ept/debtags/debtags.test.h create mode 100644 ept/debtags/vocabulary-test.cc delete mode 100644 ept/debtags/vocabulary.test.h delete mode 100644 ept/test-main.h delete mode 100644 ept/test-runner.h create mode 100755 run-check (limited to 'ept/CMakeLists.txt') diff --git a/CMakeLists.txt b/CMakeLists.txt index c4b9686..db91197 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.2) include( FindPkgConfig ) include( FindDoxygen ) -add_custom_target( unit ) +add_custom_target(check COMMAND ${CMAKE_SOURCE_DIR}/run-check ${CMAKE_BINARY_DIR}/ept/test-ept) set( EPT_VERSION "1.0.14" ) @@ -22,20 +22,7 @@ set( APT_INCLUDES "/usr/include/" CACHE STRING "apt include path" ) set( APT_LINKDIRS "/usr/lib/" CACHE STRING "apt library path" ) set( OPT_FLAGS "-O0 -g" CACHE STRING "optimization level" ) -option( INTERNAL_WIBBLE "use internal copy of wibble" ) -option( RPM "using apt-rpm" ) - -if( INTERNAL_WIBBLE ) - add_subdirectory( wibble ) - set( WIBBLE_INCLUDE_DIRS ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ) - set( WIBBLE_LIBRARY_DIRS ${wibble_BINARY_DIR} ) - set( WIBBLE_LIBRARIES "wibble" ) - set( WIBBLE_TEST_CMAKE "${wibble_SOURCE_DIR}/test.cmake" ) -else( INTERNAL_WIBBLE ) - pkg_check_modules( WIBBLE REQUIRED "libwibble >= 1.0" ) - find_program( WIBBLE_TEST_GENRUNNER wibble-test-genrunner ) - set( WIBBLE_TEST_CMAKE "${WIBBLE_PREFIX}/share/wibble/test.cmake" ) -endif( INTERNAL_WIBBLE ) +pkg_check_modules( WIBBLE REQUIRED "libwibble >= 1.0" ) add_subdirectory( ept ) add_subdirectory( tools ) diff --git a/debian/rules b/debian/rules index 37484a8..9c9cd65 100755 --- a/debian/rules +++ b/debian/rules @@ -14,7 +14,7 @@ override_dh_fixperms: override_dh_auto_build: dh_auto_build - make -C $(BUILDDIR) unit + make -C $(BUILDDIR) check make -C $(BUILDDIR) doc override_dh_auto_install: diff --git a/ept/CMakeLists.txt b/ept/CMakeLists.txt index 5f27f14..3d2dadd 100644 --- a/ept/CMakeLists.txt +++ b/ept/CMakeLists.txt @@ -1,9 +1,11 @@ project( ept ) -include( ${WIBBLE_TEST_CMAKE} ) -file( GLOB src *.cpp debtags/*.cc debtags/maint/*.cc debtags/coll/*.cc - apt/*.cc axi/*.cc utils/*.cc ) +# Find sources and tests +file(GLOB src *.cpp debtags/*.cc debtags/maint/*.cc debtags/coll/*.cc apt/*.cc axi/*.cc utils/*.cc) +file(GLOB tests *-test.cc apt/*-test.cc debtags/*-test.cc axi/*-test.cc) +list(REMOVE_ITEM src ${tests}) +# Find headers file( GLOB h_top *.h ) file( GLOB h_apt apt/*.h ) file( GLOB h_debtags debtags/*.h debtags/*.tcc ) @@ -11,10 +13,10 @@ file( GLOB h_debtags_maint debtags/maint/*.h debtags/maint/*.tcc ) file( GLOB h_axi axi/*.h ) file( GLOB h_utils utils/*.h ) -file( GLOB debtagstesth debtags/*.test.h debtags/maint/*.test.h ) -file( GLOB apttesth apt/*.test.h ) -file( GLOB axitesth axi/*.test.h ) -set( testh ${debtagstesth} ${apttesth} ${axitesth} ) +#file( GLOB debtagstesth debtags/*.test.h debtags/maint/*.test.h ) +#file( GLOB apttesth apt/*.test.h ) +#file( GLOB axitesth axi/*.test.h ) +#set( testh ${debtagstesth} ${apttesth} ${axitesth} ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${TAGCOLL_INCLUDE_DIRS} ${WIBBLE_INCLUDE_DIRS} ) @@ -26,7 +28,10 @@ add_library( ept-static STATIC ${src} ) set_target_properties( ept PROPERTIES SOVERSION ${LIBEPT_SOVERSION} CLEAN_DIRECT_OUTPUT 1) set_target_properties( ept-static PROPERTIES SOVERSION ${LIBEPT_SOVERSION} OUTPUT_NAME "ept" CLEAN_DIRECT_OUTPUT 1) -set( TEST_ENV_DIR ${ept_BINARY_DIR}/test-env/ ) +add_executable(test-ept EXCLUDE_FROM_ALL utils/tests-main.cc ${tests}) +target_link_libraries(test-ept ept) +add_test(test-ept test-ept) +add_dependencies(check test-ept) configure_file( ${ept_SOURCE_DIR}/config.h.cmake-in ${ept_BINARY_DIR}/config.h ) @@ -41,32 +46,6 @@ configure_file( ${ept_SOURCE_DIR}/libept.pc.in # regression testing link_directories( ${CMAKE_CURRENT_BINARY_DIR}/../lib ) link_libraries( ept ) -wibble_add_test( ept-test ${testh} ) - -set( datastamp ${CMAKE_CURRENT_BINARY_DIR}/data-stamp ) -set( datadir ${CMAKE_CURRENT_SOURCE_DIR}/test-data ) -set( listfile wherever_debian_._Packages ) - -wibble_check_target( ept-test ${datastamp} ) - -execute_process( COMMAND dpkg --print-architecture OUTPUT_VARIABLE ARCH ) -string( REPLACE "\n" "" ARCH "${ARCH}" ) - -add_custom_command( - OUTPUT ${datastamp} - COMMAND mkdir -p test-env/etc test-env/state/lists/partial - test-env/cache test-env/debtags - test-env/cache/archives/partial test-env/desktop - COMMAND sed -e s,i386,${ARCH}, < ${datadir}/packagelist > test-env/state/lists/${listfile} - COMMAND cp -a ${datadir}/etc/sources.list test-env/etc/ - COMMAND sed -e s,i386,${ARCH}, < ${datadir}/dpkg-status > test-env/dpkg-status - COMMAND cp -a ${datadir}/desktop/*.desktop test-env/desktop/ - COMMAND cp ${datadir}/debtags/package-tags test-env/debtags/package-tags - COMMAND cp ${datadir}/debtags/vocabulary test-env/debtags/vocabulary - COMMAND mkdir -p test-env/debtags/empty - COMMAND mkdir -p test-env/debtags/user - COMMAND mkdir -p test-env/xapian/ - COMMAND touch data-stamp ) install( TARGETS ept ept-static LIBRARY DESTINATION lib/${CMAKE_LIBRARY_ARCHITECTURE} diff --git a/ept/apt/apt-test.cc b/ept/apt/apt-test.cc new file mode 100644 index 0000000..7646010 --- /dev/null +++ b/ept/apt/apt-test.cc @@ -0,0 +1,209 @@ +#include "ept/test.h" +#include "apt.h" +#include +#include + +using namespace std; +using namespace ept; +using namespace ept::tests; +using namespace ept::apt; + +namespace { + +struct AptTestEnvironment { + //ept::core::AptDatabase db; + AptTestEnvironment() { + pkgInitConfig (*_config); + _config->Set("Initialized", 1); + _config->Set("Dir", "."); + _config->Set("Dir::Cache", "cache"); + _config->Set("Dir::State", "state"); + _config->Set("Dir::Etc", "etc"); + _config->Set("Dir::Etc::sourcelist", "sources.list"); + _config->Set("Dir::State::status", "./dpkg-status"); + pkgInitSystem (*_config, _system); + } +}; + +class Tests : public TestCase +{ + using TestCase::TestCase; + + void register_tests() override + { + add_method("iterators", []() { + // Check that iterations iterates among some packages + AptTestEnvironment env; + Apt apt; + Apt::iterator i = apt.begin(); + wassert_true(i != apt.end()); + + size_t count = 0; + for (; i != apt.end(); ++i) + ++count; + + wassert_true(count > 100); + }); + + add_method("apt_exists", []() { + // Check that iteration gives some well-known packages + AptTestEnvironment env; + Apt apt; + set packages; + + std::copy(apt.begin(), apt.end(), inserter(packages, packages.begin())); + + wassert_true(packages.find("libsp1") != packages.end()); + // TODO this exposes a bug somewhere... sp definitely is among + // the packages + // wassert_true(packages.find("sp") != packages.end()); + wassert_true(packages.find("") == packages.end()); + }); + + add_method("timestamp", []() { + // Check that timestamp gives some meaningful timestamp + AptTestEnvironment env; + Apt apt; + time_t ts = apt.timestamp(); + wassert_true(ts > 1000000); + }); + + add_method("validity", []() { + // Check the package validator + AptTestEnvironment env; + Apt apt; + wassert_true(apt.isValid("apt")); + wassert_true(!apt.isValid("this-package-does-not-really-exists")); + }); + + add_method("versions", []() { + // Check the version instantiators + AptTestEnvironment env; + Apt apt; + std::string pkg("apt"); + Version ver = apt.candidateVersion(pkg); + wassert_true(ver.isValid()); + + ver = apt.installedVersion(pkg); + wassert_true(ver.isValid()); + + ver = apt.anyVersion(pkg); + wassert_true(ver.isValid()); + + std::string pkg1("this-package-does-not-really-exists"); + ver = apt.candidateVersion(pkg1); + wassert_true(!ver.isValid()); + + ver = apt.installedVersion(pkg1); + wassert_true(!ver.isValid()); + + ver = apt.anyVersion(pkg1); + wassert_true(!ver.isValid()); + }); + + add_method("version_validity", []() { + // Check the version validator + AptTestEnvironment env; + Apt apt; + Version ver = apt.candidateVersion("apt"); + wassert_true(apt.validate(ver) == ver); + + ver = Version("this-package-does-not-really-exists", "0.1"); + wassert_true(!apt.validate(ver).isValid()); + + ver = Version("apt", "0.31415"); + wassert_true(!apt.validate(ver).isValid()); + }); + + add_method("raw_record", []() { + // Check the raw record accessor + AptTestEnvironment env; + Apt apt; + string pkg("sp"); + Version ver = apt.candidateVersion(pkg); + wassert_true(ver.isValid()); + wassert_true(apt.validate(ver) == ver); + + string record = apt.rawRecord(ver); + wassert_true(record.find("Package: sp") != string::npos); + wassert_true(record.find("Section: text") != string::npos); + + record = apt.rawRecord(Version("sp", "0.31415")); + assert_eq(record, string()); + + assert_eq(apt.rawRecord(pkg), apt.rawRecord(apt.anyVersion(pkg))); + }); + + add_method("state", []() { + // Check the package state accessor + AptTestEnvironment env; + Apt apt; + PackageState s = apt.state("kdenetwork"); + wassert_true(s.isValid()); + wassert_true(s.isInstalled()); + + s = apt.state("this-package-does-not-really-exists"); + wassert_true(!s.isValid()); + }); + + add_method("record_iteration", []() { + // Check the record iterator (accessing with *) + AptTestEnvironment env; + Apt apt; + size_t count = 0; + for (Apt::record_iterator i = apt.recordBegin(); + i != apt.recordEnd(); ++i) + { + wassert_true((*i).size() > 8); + assert_eq((*i).substr(0, 8), "Package:"); + ++count; + } + wassert_true(count > 200); + }); + + add_method("record_iteration2", []() { + // Check the record iterator (accessing with ->) + AptTestEnvironment env; + Apt apt; + size_t count = 0; + for (Apt::record_iterator i = apt.recordBegin(); + i != apt.recordEnd(); ++i) + { + wassert_true(i->size() > 8); + assert_eq(i->substr(0, 8), "Package:"); + ++count; + } + wassert_true(count > 200); + }); + + add_method("stl_iteration", []() { + // Check that the iterators can be used with the algorithms + AptTestEnvironment env; + Apt apt; + vector out; + std::copy(apt.begin(), apt.end(), back_inserter(out)); + }); + + add_method("stl_record_iteration", []() { + // Check that the iterators can be used with the algorithms + AptTestEnvironment env; + Apt apt; + vector out; + std::copy(apt.recordBegin(), apt.recordEnd(), back_inserter(out)); + }); + + add_method("check_updates", []() { + // Check that checkUpdates will keep a working Apt object + AptTestEnvironment env; + Apt apt; + wassert_true(apt.isValid("apt")); + apt.checkCacheUpdates(); + wassert_true(apt.isValid("apt")); + apt.invalidateTimestamp(); + apt.checkCacheUpdates(); + wassert_true(apt.isValid("apt")); + }); + } +} tests("apt_apt"); + +} diff --git a/ept/apt/apt.test.h b/ept/apt/apt.test.h deleted file mode 100644 index ff4f315..0000000 --- a/ept/apt/apt.test.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2007 Enrico Zini - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include - -using namespace std; -using namespace ept; -using namespace ept::apt; - -struct TestApt : AptTestEnvironment { - Apt apt; - - // Check that iterations iterates among some packages - Test iterators() - { - Apt::iterator i = apt.begin(); - assert(i != apt.end()); - - size_t count = 0; - for (; i != apt.end(); ++i) - ++count; - - assert(count > 100); - } - - // Check that iteration gives some well-known packages - Test aptExists() - { - set packages; - - std::copy(apt.begin(), apt.end(), inserter(packages, packages.begin())); - - assert(packages.find("libsp1") != packages.end()); - // TODO this exposes a bug somewhere... sp definitely is among - // the packages - // assert(packages.find("sp") != packages.end()); - assert(packages.find("") == packages.end()); - } - - // Check that timestamp gives some meaningful timestamp - Test timestamp() - { - time_t ts = apt.timestamp(); - assert(ts > 1000000); - } - - // Check the package validator - Test validity() - { - assert(apt.isValid("apt")); - assert(!apt.isValid("this-package-does-not-really-exists")); - } - - // Check the version instantiators - Test versions() - { - std::string pkg("apt"); - Version ver = apt.candidateVersion(pkg); - assert(ver.isValid()); - - ver = apt.installedVersion(pkg); - assert(ver.isValid()); - - ver = apt.anyVersion(pkg); - assert(ver.isValid()); - - std::string pkg1("this-package-does-not-really-exists"); - ver = apt.candidateVersion(pkg1); - assert(!ver.isValid()); - - ver = apt.installedVersion(pkg1); - assert(!ver.isValid()); - - ver = apt.anyVersion(pkg1); - assert(!ver.isValid()); - } - - // Check the version validator - Test versionValidity() - { - Version ver = apt.candidateVersion("apt"); - assert(apt.validate(ver) == ver); - - ver = Version("this-package-does-not-really-exists", "0.1"); - assert(!apt.validate(ver).isValid()); - - ver = Version("apt", "0.31415"); - assert(!apt.validate(ver).isValid()); - } - - // Check the raw record accessor - Test rawRecord() - { - string pkg("sp"); - Version ver = apt.candidateVersion(pkg); - assert(ver.isValid()); - assert(apt.validate(ver) == ver); - - string record = apt.rawRecord(ver); - assert(record.find("Package: sp") != string::npos); - assert(record.find("Section: text") != string::npos); - - record = apt.rawRecord(Version("sp", "0.31415")); - assert_eq(record, string()); - - assert_eq(apt.rawRecord(pkg), apt.rawRecord(apt.anyVersion(pkg))); - } - - // Check the package state accessor - Test state() - { - PackageState s = apt.state("kdenetwork"); - assert(s.isValid()); - assert(s.isInstalled()); - - s = apt.state("this-package-does-not-really-exists"); - assert(!s.isValid()); - } - - // Check the record iterator (accessing with *) - Test recordIteration() - { - size_t count = 0; - for (Apt::record_iterator i = apt.recordBegin(); - i != apt.recordEnd(); ++i) - { - assert((*i).size() > 8); - assert_eq((*i).substr(0, 8), "Package:"); - ++count; - } - assert(count > 200); - } - - // Check the record iterator (accessing with ->) - Test recordIteration2() - { - size_t count = 0; - for (Apt::record_iterator i = apt.recordBegin(); - i != apt.recordEnd(); ++i) - { - assert(i->size() > 8); - assert_eq(i->substr(0, 8), "Package:"); - ++count; - } - assert(count > 200); - } - - // Check that the iterators can be used with the algorithms - Test stlIteration() - { - vector out; - std::copy(apt.begin(), apt.end(), back_inserter(out)); - } - - // Check that the iterators can be used with the algorithms - Test stlRecordIteration() - { - vector out; - std::copy(apt.recordBegin(), apt.recordEnd(), back_inserter(out)); - } - - // Check that checkUpdates will keep a working Apt object - Test checkUpdates() - { - assert(apt.isValid("apt")); - apt.checkCacheUpdates(); - assert(apt.isValid("apt")); - apt.invalidateTimestamp(); - apt.checkCacheUpdates(); - assert(apt.isValid("apt")); - } - -}; - -// vim:set ts=4 sw=4: diff --git a/ept/apt/packagerecord-test.cc b/ept/apt/packagerecord-test.cc new file mode 100644 index 0000000..b421f5b --- /dev/null +++ b/ept/apt/packagerecord-test.cc @@ -0,0 +1,126 @@ +#include "ept/test.h" +#include "packagerecord.h" + +namespace std { + ostream& operator<<(ostream& out, const set& s) + { + for (set::const_iterator i = s.begin(); + i != s.end(); ++i) + if (i == s.begin()) + out << *i; + else + out << ", " << *i; + return out; + } +} + +using namespace std; +using namespace ept; +using namespace ept::tests; +using namespace ept::apt; + +namespace { + +class Tests : public TestCase +{ + using TestCase::TestCase; + + void register_tests() override + { + add_method("supported_fields", []() { + // Check that the supported fields are understood + string record = + "Package: apt\n" + "Priority: important\n" + "Section: admin\n" + "Installed-Size: 4368\n" + "Maintainer: APT Development Team \n" + "Architecture: amd64\n" + "Source: apt\n" + "Version: 0.6.46.4-0.1\n" + "Replaces: libapt-pkg-doc (<< 0.3.7), libapt-pkg-dev (<< 0.3.7)\n" + "Provides: libapt-pkg-libc6.3-6-3.11\n" + "Depends: libc6 (>= 2.3.5-1), libgcc1 (>= 1:4.1.1-12), libstdc++6 (>= 4.1.1-12), debian-archive-keyring\n" + "Pre-Depends: debtags (maybe)\n" + "Suggests: aptitude | synaptic | gnome-apt | wajig, dpkg-dev, apt-doc, bzip2\n" + "Recommends: debtags (maybe)\n" + "Enhances: debian\n" + "Conflicts: marameo\n" + "Filename: pool/main/a/apt/apt_0.6.46.4-0.1_amd64.deb\n" + "Size: 1436478\n" + "MD5sum: 1776421f80d6300c77a608e77a9f4a15\n" + "SHA1: 1bd7337d2df56d267632cf72ac930c0a4895898f\n" + "SHA256: b92442ab60046b4d0728245f39cc932f26e17db9f7933a5ec9aaa63172f51fda\n" + "Description: Advanced front-end for dpkg\n" + " This is Debian's next generation front-end for the dpkg package manager.\n" + " It provides the apt-get utility and APT dselect method that provides a\n" + " simpler, safer way to install and upgrade packages.\n" + " .\n" + " APT features complete installation ordering, multiple source capability\n" + " and several other unique features, see the Users Guide in apt-doc.\n" + "Build-Essential: yes\n" + "Tag: admin::package-management, filetransfer::ftp, filetransfer::http, hardware::storage:cd, interface::commandline, network::client, protocol::{ftp,http,ipv6}, role::program, suite::debian, use::downloading, use::searching, works-with::software:package\n"; + + PackageRecord p(record); + + wassert(actual(p.size()) == 24u); + + wassert(actual(p.package()) == "apt"); + wassert(actual(p.priority()) == "important"); + wassert(actual(p.section()) == "admin"); + wassert(actual(p.installedSize()) == 4368u); + wassert(actual(p.maintainer()) == "APT Development Team "); + wassert(actual(p.architecture()) == "amd64"); + wassert(actual(p.source()) == "apt"); + wassert(actual(p.version()) == "0.6.46.4-0.1"); + wassert(actual(p.replaces()) == "libapt-pkg-doc (<< 0.3.7), libapt-pkg-dev (<< 0.3.7)"); + wassert(actual(p.provides()) == "libapt-pkg-libc6.3-6-3.11"); + wassert(actual(p.depends()) == "libc6 (>= 2.3.5-1), libgcc1 (>= 1:4.1.1-12), libstdc++6 (>= 4.1.1-12), debian-archive-keyring"); + wassert(actual(p.preDepends()) == "debtags (maybe)"); + wassert(actual(p.recommends()) == "debtags (maybe)"); + wassert(actual(p.suggests()) == "aptitude | synaptic | gnome-apt | wajig, dpkg-dev, apt-doc, bzip2"); + wassert(actual(p.enhances()) == "debian"); + wassert(actual(p.conflicts()) == "marameo"); + wassert(actual(p.filename()) == "pool/main/a/apt/apt_0.6.46.4-0.1_amd64.deb"); + wassert(actual(p.packageSize()) == 1436478u); + wassert(actual(p.md5sum()) == "1776421f80d6300c77a608e77a9f4a15"); + wassert(actual(p.sha1()) == "1bd7337d2df56d267632cf72ac930c0a4895898f"); + wassert(actual(p.sha256()) == "b92442ab60046b4d0728245f39cc932f26e17db9f7933a5ec9aaa63172f51fda"); + wassert(actual(p.description()) == "Advanced front-end for dpkg\n" + " This is Debian's next generation front-end for the dpkg package manager.\n" + " It provides the apt-get utility and APT dselect method that provides a\n" + " simpler, safer way to install and upgrade packages.\n" + " .\n" + " APT features complete installation ordering, multiple source capability\n" + " and several other unique features, see the Users Guide in apt-doc."); + wassert(actual(p.shortDescription()) == "Advanced front-end for dpkg"); + wassert(actual(p.longDescription()) == + "This is Debian's next generation front-end for the dpkg package manager.\n" + " It provides the apt-get utility and APT dselect method that provides a\n" + " simpler, safer way to install and upgrade packages.\n" + " .\n" + " APT features complete installation ordering, multiple source capability\n" + " and several other unique features, see the Users Guide in apt-doc."); + wassert(actual(p.buildEssential()) == true); + + std::set tags; + tags.insert("admin::package-management"); + tags.insert("filetransfer::ftp"); + tags.insert("filetransfer::http"); + tags.insert("hardware::storage:cd"); + tags.insert("interface::commandline"); + tags.insert("network::client"); + tags.insert("protocol::ftp"); + tags.insert("protocol::http"); + tags.insert("protocol::ipv6"); + tags.insert("role::program"); + tags.insert("suite::debian"); + tags.insert("use::downloading"); + tags.insert("use::searching"); + tags.insert("works-with::software:package"); + wassert(actual(p.tag()) == tags); + }); + } +} tests("apt_packagerecord"); + +} diff --git a/ept/apt/packagerecord.test.h b/ept/apt/packagerecord.test.h deleted file mode 100644 index 657cbab..0000000 --- a/ept/apt/packagerecord.test.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2007 Enrico Zini - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -namespace std { - ostream& operator<<(ostream& out, const set& s) - { - for (set::const_iterator i = s.begin(); - i != s.end(); ++i) - if (i == s.begin()) - out << *i; - else - out << ", " << *i; - return out; - } -} - -using namespace std; -using namespace ept; -using namespace ept::apt; - -struct TestAptPackagerecord { - - // Check that the supported fields are understood - Test supportedFields() - { - string record = - "Package: apt\n" - "Priority: important\n" - "Section: admin\n" - "Installed-Size: 4368\n" - "Maintainer: APT Development Team \n" - "Architecture: amd64\n" - "Source: apt\n" - "Version: 0.6.46.4-0.1\n" - "Replaces: libapt-pkg-doc (<< 0.3.7), libapt-pkg-dev (<< 0.3.7)\n" - "Provides: libapt-pkg-libc6.3-6-3.11\n" - "Depends: libc6 (>= 2.3.5-1), libgcc1 (>= 1:4.1.1-12), libstdc++6 (>= 4.1.1-12), debian-archive-keyring\n" - "Pre-Depends: debtags (maybe)\n" - "Suggests: aptitude | synaptic | gnome-apt | wajig, dpkg-dev, apt-doc, bzip2\n" - "Recommends: debtags (maybe)\n" - "Enhances: debian\n" - "Conflicts: marameo\n" - "Filename: pool/main/a/apt/apt_0.6.46.4-0.1_amd64.deb\n" - "Size: 1436478\n" - "MD5sum: 1776421f80d6300c77a608e77a9f4a15\n" - "SHA1: 1bd7337d2df56d267632cf72ac930c0a4895898f\n" - "SHA256: b92442ab60046b4d0728245f39cc932f26e17db9f7933a5ec9aaa63172f51fda\n" - "Description: Advanced front-end for dpkg\n" - " This is Debian's next generation front-end for the dpkg package manager.\n" - " It provides the apt-get utility and APT dselect method that provides a\n" - " simpler, safer way to install and upgrade packages.\n" - " .\n" - " APT features complete installation ordering, multiple source capability\n" - " and several other unique features, see the Users Guide in apt-doc.\n" - "Build-Essential: yes\n" - "Tag: admin::package-management, filetransfer::ftp, filetransfer::http, hardware::storage:cd, interface::commandline, network::client, protocol::{ftp,http,ipv6}, role::program, suite::debian, use::downloading, use::searching, works-with::software:package\n"; - - PackageRecord p(record); - - assert_eq(p.size(), 24u); - - assert_eq(p.package(), "apt"); - assert_eq(p.priority(), "important"); - assert_eq(p.section(), "admin"); - assert_eq(p.installedSize(), 4368u); - assert_eq(p.maintainer(), "APT Development Team "); - assert_eq(p.architecture(), "amd64"); - assert_eq(p.source(), "apt"); - assert_eq(p.version(), "0.6.46.4-0.1"); - assert_eq(p.replaces(), "libapt-pkg-doc (<< 0.3.7), libapt-pkg-dev (<< 0.3.7)"); - assert_eq(p.provides(), "libapt-pkg-libc6.3-6-3.11"); - assert_eq(p.depends(), "libc6 (>= 2.3.5-1), libgcc1 (>= 1:4.1.1-12), libstdc++6 (>= 4.1.1-12), debian-archive-keyring"); - assert_eq(p.preDepends(), "debtags (maybe)"); - assert_eq(p.recommends(), "debtags (maybe)"); - assert_eq(p.suggests(), "aptitude | synaptic | gnome-apt | wajig, dpkg-dev, apt-doc, bzip2"); - assert_eq(p.enhances(), "debian"); - assert_eq(p.conflicts(), "marameo"); - assert_eq(p.filename(), "pool/main/a/apt/apt_0.6.46.4-0.1_amd64.deb"); - assert_eq(p.packageSize(), 1436478u); - assert_eq(p.md5sum(), "1776421f80d6300c77a608e77a9f4a15"); - assert_eq(p.sha1(), "1bd7337d2df56d267632cf72ac930c0a4895898f"); - assert_eq(p.sha256(), "b92442ab60046b4d0728245f39cc932f26e17db9f7933a5ec9aaa63172f51fda"); - assert_eq(p.description(), "Advanced front-end for dpkg\n" - " This is Debian's next generation front-end for the dpkg package manager.\n" - " It provides the apt-get utility and APT dselect method that provides a\n" - " simpler, safer way to install and upgrade packages.\n" - " .\n" - " APT features complete installation ordering, multiple source capability\n" - " and several other unique features, see the Users Guide in apt-doc."); - assert_eq(p.shortDescription(), "Advanced front-end for dpkg"); - assert_eq(p.longDescription(), - "This is Debian's next generation front-end for the dpkg package manager.\n" - " It provides the apt-get utility and APT dselect method that provides a\n" - " simpler, safer way to install and upgrade packages.\n" - " .\n" - " APT features complete installation ordering, multiple source capability\n" - " and several other unique features, see the Users Guide in apt-doc."); - assert_eq(p.buildEssential(), true); - - std::set tags; - tags.insert("admin::package-management"); - tags.insert("filetransfer::ftp"); - tags.insert("filetransfer::http"); - tags.insert("hardware::storage:cd"); - tags.insert("interface::commandline"); - tags.insert("network::client"); - tags.insert("protocol::ftp"); - tags.insert("protocol::http"); - tags.insert("protocol::ipv6"); - tags.insert("role::program"); - tags.insert("suite::debian"); - tags.insert("use::downloading"); - tags.insert("use::searching"); - tags.insert("works-with::software:package"); - assert_eq(p.tag(), tags); - } - -}; - -// vim:set ts=4 sw=4: diff --git a/ept/apt/recordparser-test.cc b/ept/apt/recordparser-test.cc new file mode 100644 index 0000000..4e01e6b --- /dev/null +++ b/ept/apt/recordparser-test.cc @@ -0,0 +1,200 @@ +#include "ept/test.h" +#include "recordparser.h" + +using namespace ept::tests; +using namespace std; +using namespace ept; +using namespace ept::apt; + +namespace { + +const char* test_record = + "A:\n" + "D: da de di do du\n" + "B: b\n" + "C: c \n" + "Desc: this is the beginning\n" + " this is the continuation\n" + " this is the end\n"; + +class Tests : public TestCase +{ + using TestCase::TestCase; + + void register_tests() override + { + add_method("parsing", []() { + // Check that the fields are identified and broken up correctly + RecordParser p(test_record); + + wassert(actual(p.record()) == test_record); + wassert(actual(p.size()) == 5u); + }); + + add_method("field_tuples", []() { + RecordParser p(test_record); + wassert(actual(p.field(0)) == "A:\n"); + wassert(actual(p.field(1)) == "D: da de di do du\n"); + wassert(actual(p.field(2)) == "B: b\n"); + wassert(actual(p.field(3)) == "C: c \n"); + wassert(actual(p.field(4)) == "Desc: this is the beginning\n this is the continuation\n this is the end\n"); + }); + + add_method("field_keys", []() { + RecordParser p(test_record); + wassert(actual(p.name(0)) == "A"); + wassert(actual(p.name(1)) == "D"); + wassert(actual(p.name(2)) == "B"); + wassert(actual(p.name(3)) == "C"); + wassert(actual(p.name(4)) == "Desc"); + }); + + add_method("field_values", []() { + RecordParser p(test_record); + wassert(actual(p[0]) == ""); + wassert(actual(p[1]) == "da de di do du"); + wassert(actual(p[2]) == "b"); + wassert(actual(p[3]) == "c"); + wassert(actual(p[4]) == "this is the beginning\n this is the continuation\n this is the end"); + }); + + add_method("find_byname", []() { + // Check that the field search by name finds all the fields + RecordParser p(test_record); + + wassert(actual(p.index("A")) == 0u); + wassert(actual(p.index("D")) == 1u); + wassert(actual(p.index("B")) == 2u); + wassert(actual(p.index("C")) == 3u); + wassert(actual(p.index("Desc")) == 4u); + + wassert(actual(p.name(p.index("A"))) == "A"); + wassert(actual(p.name(p.index("B"))) == "B"); + wassert(actual(p.name(p.index("C"))) == "C"); + wassert(actual(p.name(p.index("D"))) == "D"); + wassert(actual(p.name(p.index("Desc"))) == "Desc"); + }); + + add_method("indexing", []() { + RecordParser p(test_record); + wassert(actual(p["A"]) == ""); + wassert(actual(p["B"]) == "b"); + wassert(actual(p["C"]) == "c"); + wassert(actual(p["D"]) == "da de di do du"); + wassert(actual(p["Desc"]) == "this is the beginning\n this is the continuation\n this is the end"); + }); + + add_method("missing_behaviour", []() { + RecordParser p(test_record); + // Missing fields give empty strings + wassert(actual(p.field(100)) == ""); + wassert(actual(p.name(100)) == ""); + wassert(actual(p[100]) == ""); + wassert(actual(p["Missing"]) == ""); + }); + + add_method("rescan", []() { + // Check that scanning twice replaces the old fields + std::string record = + "A: a\n" + "B: b\n" + "C: c\n"; + + RecordParser p(record); + wassert(actual(p.size()) == 3u); + wassert(actual(p["A"]) == "a"); + wassert(actual(p["B"]) == "b"); + wassert(actual(p["C"]) == "c"); + + std::string record1 = + "Foo: bar\n" + "A: different\n"; + + p.scan(record1); + + //for (size_t i = 0; i < p.size(); ++i) + // cerr << ">> " << i << "==" << p.index(p.name(i)) << " " << p.name(i) << " " << p[i] << endl; + + wassert(actual(p.size()) == 2u); + wassert(actual(p["A"]) == "different"); + wassert(actual(p["B"]) == ""); + wassert(actual(p["C"]) == ""); + wassert(actual(p["Foo"]) == "bar"); + }); + + add_method("real_life", []() { + // Real-life example + string record = + "Package: apt\n" + "Priority: important\n" + "Section: admin\n" + "Installed-Size: 4368\n" + "Maintainer: APT Development Team \n" + "Architecture: amd64\n" + "Version: 0.6.46.4-0.1\n" + "Replaces: libapt-pkg-doc (<< 0.3.7), libapt-pkg-dev (<< 0.3.7)\n" + "Provides: libapt-pkg-libc6.3-6-3.11\n" + "Depends: libc6 (>= 2.3.5-1), libgcc1 (>= 1:4.1.1-12), libstdc++6 (>= 4.1.1-12), debian-archive-keyring\n" + "Suggests: aptitude | synaptic | gnome-apt | wajig, dpkg-dev, apt-doc, bzip2\n" + "Filename: pool/main/a/apt/apt_0.6.46.4-0.1_amd64.deb\n" + "Size: 1436478\n" + "MD5sum: 1776421f80d6300c77a608e77a9f4a15\n" + "SHA1: 1bd7337d2df56d267632cf72ac930c0a4895898f\n" + "SHA256: b92442ab60046b4d0728245f39cc932f26e17db9f7933a5ec9aaa63172f51fda\n" + "Description: Advanced front-end for dpkg\n" + " This is Debian's next generation front-end for the dpkg package manager.\n" + " It provides the apt-get utility and APT dselect method that provides a\n" + " simpler, safer way to install and upgrade packages.\n" + " .\n" + " APT features complete installation ordering, multiple source capability\n" + " and several other unique features, see the Users Guide in apt-doc.\n" + "Build-Essential: yes\n" + "Tag: admin::package-management, filetransfer::ftp, filetransfer::http, hardware::storage:cd, interface::commandline, network::client, protocol::{ftp,http,ipv6}, role::program, suite::debian, use::downloading, use::searching, works-with::software:package\n"; + RecordParser p(record); + + wassert(actual(p.size()) == 19u); + + string rec1; + for (size_t i = 0; i < p.size(); ++i) + rec1 += p.field(i); + wassert(actual(record) == rec1); + }); + + add_method("buffer_termination", []() { + // Various buffer termination patterns + std::string record = + "A: a\n" + "B: b"; + + RecordParser p(record); + wassert(actual(p.size()) == 2u); + wassert(actual(p["A"]) == "a"); + wassert(actual(p["B"]) == "b"); + }); + + add_method("buffer_termination2", []() { + std::string record = + "A: a\n" + "B: b\n\n"; + + RecordParser p(record); + wassert(actual(p.size()) == 2u); + wassert(actual(p["A"]) == "a"); + wassert(actual(p["B"]) == "b"); + }); + + add_method("buffer_termination3", []() { + std::string record = + "A: a\n" + "B: b\n\n" + "C: c\n"; + + RecordParser p(record); + wassert(actual(p.size()) == 2u); + wassert(actual(p["A"]) == "a"); + wassert(actual(p["B"]) == "b"); + }); + } +} tests("apt_recordparser"); + +} diff --git a/ept/apt/recordparser.test.h b/ept/apt/recordparser.test.h deleted file mode 100644 index 629008f..0000000 --- a/ept/apt/recordparser.test.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2007 Enrico Zini - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -//#include - -using namespace std; -using namespace ept; -using namespace ept::apt; - -struct TestAptRecordparser { - std::string record; - TestAptRecordparser() - { - record = - "A:\n" - "D: da de di do du\n" - "B: b\n" - "C: c \n" - "Desc: this is the beginning\n" - " this is the continuation\n" - " this is the end\n"; - } - - // Check that the fields are identified and broken up correctly - Test parsing() - { - RecordParser p(record); - - assert_eq(p.record(), record); - assert_eq(p.size(), 5u); - } - - Test fieldTuples() - { - RecordParser p(record); - assert_eq(p.field(0), "A:\n"); - assert_eq(p.field(1), "D: da de di do du\n"); - assert_eq(p.field(2), "B: b\n"); - assert_eq(p.field(3), "C: c \n"); - assert_eq(p.field(4), "Desc: this is the beginning\n this is the continuation\n this is the end\n"); - } - - Test fieldKeys() - { - RecordParser p(record); - assert_eq(p.name(0), "A"); - assert_eq(p.name(1), "D"); - assert_eq(p.name(2), "B"); - assert_eq(p.name(3), "C"); - assert_eq(p.name(4), "Desc"); - } - - Test fieldValues() - { - RecordParser p(record); - assert_eq(p[0], ""); - assert_eq(p[1], "da de di do du"); - assert_eq(p[2], "b"); - assert_eq(p[3], "c"); - assert_eq(p[4], "this is the beginning\n this is the continuation\n this is the end"); - } - - // Check that the field search by name finds all the fields - Test findByName() - { - RecordParser p(record); - - assert_eq(p.index("A"), 0u); - assert_eq(p.index("D"), 1u); - assert_eq(p.index("B"), 2u); - assert_eq(p.index("C"), 3u); - assert_eq(p.index("Desc"), 4u); - - assert_eq(p.name(p.index("A")), "A"); - assert_eq(p.name(p.index("B")), "B"); - assert_eq(p.name(p.index("C")), "C"); - assert_eq(p.name(p.index("D")), "D"); - assert_eq(p.name(p.index("Desc")), "Desc"); - } - - Test indexing() - { - RecordParser p(record); - assert_eq(p["A"], ""); - assert_eq(p["B"], "b"); - assert_eq(p["C"], "c"); - assert_eq(p["D"], "da de di do du"); - assert_eq(p["Desc"], "this is the beginning\n this is the continuation\n this is the end"); - } - - Test missingBehaviour() - { - RecordParser p(record); - // Missing fields give empty strings - assert_eq(p.field(100), ""); - assert_eq(p.name(100), ""); - assert_eq(p[100], ""); - assert_eq(p["Missing"], ""); - } - - // Check that scanning twice replaces the old fields - Test rescan() - { - std::string record = - "A: a\n" - "B: b\n" - "C: c\n"; - - RecordParser p(record); - assert_eq(p.size(), 3u); - assert_eq(p["A"], "a"); - assert_eq(p["B"], "b"); - assert_eq(p["C"], "c"); - - std::string record1 = - "Foo: bar\n" - "A: different\n"; - - p.scan(record1); - - //for (size_t i = 0; i < p.size(); ++i) - // cerr << ">> " << i << "==" << p.index(p.name(i)) << " " << p.name(i) << " " << p[i] << endl; - - assert_eq(p.size(), 2u); - assert_eq(p["A"], "different"); - assert_eq(p["B"], ""); - assert_eq(p["C"], ""); - assert_eq(p["Foo"], "bar"); - } - - // Real-life example - Test realLife() - { - string record = - "Package: apt\n" - "Priority: important\n" - "Section: admin\n" - "Installed-Size: 4368\n" - "Maintainer: APT Development Team \n" - "Architecture: amd64\n" - "Version: 0.6.46.4-0.1\n" - "Replaces: libapt-pkg-doc (<< 0.3.7), libapt-pkg-dev (<< 0.3.7)\n" - "Provides: libapt-pkg-libc6.3-6-3.11\n" - "Depends: libc6 (>= 2.3.5-1), libgcc1 (>= 1:4.1.1-12), libstdc++6 (>= 4.1.1-12), debian-archive-keyring\n" - "Suggests: aptitude | synaptic | gnome-apt | wajig, dpkg-dev, apt-doc, bzip2\n" - "Filename: pool/main/a/apt/apt_0.6.46.4-0.1_amd64.deb\n" - "Size: 1436478\n" - "MD5sum: 1776421f80d6300c77a608e77a9f4a15\n" - "SHA1: 1bd7337d2df56d267632cf72ac930c0a4895898f\n" - "SHA256: b92442ab60046b4d0728245f39cc932f26e17db9f7933a5ec9aaa63172f51fda\n" - "Description: Advanced front-end for dpkg\n" - " This is Debian's next generation front-end for the dpkg package manager.\n" - " It provides the apt-get utility and APT dselect method that provides a\n" - " simpler, safer way to install and upgrade packages.\n" - " .\n" - " APT features complete installation ordering, multiple source capability\n" - " and several other unique features, see the Users Guide in apt-doc.\n" - "Build-Essential: yes\n" - "Tag: admin::package-management, filetransfer::ftp, filetransfer::http, hardware::storage:cd, interface::commandline, network::client, protocol::{ftp,http,ipv6}, role::program, suite::debian, use::downloading, use::searching, works-with::software:package\n"; - RecordParser p(record); - - assert_eq(p.size(), 19u); - - string rec1; - for (size_t i = 0; i < p.size(); ++i) - rec1 += p.field(i); - assert_eq(record, rec1); - } - - // Various buffer termination patterns - Test bufferTermination() - { - std::string record = - "A: a\n" - "B: b"; - - RecordParser p(record); - assert_eq(p.size(), 2u); - assert_eq(p["A"], "a"); - assert_eq(p["B"], "b"); - } - - Test bufferTermination2() - { - std::string record = - "A: a\n" - "B: b\n\n"; - - RecordParser p(record); - assert_eq(p.size(), 2u); - assert_eq(p["A"], "a"); - assert_eq(p["B"], "b"); - } - - Test bufferTermination3() - { - std::string record = - "A: a\n" - "B: b\n\n" - "C: c\n"; - - RecordParser p(record); - assert_eq(p.size(), 2u); - assert_eq(p["A"], "a"); - assert_eq(p["B"], "b"); - } - -}; - -// vim:set ts=4 sw=4: diff --git a/ept/apt/version-test.cc b/ept/apt/version-test.cc new file mode 100644 index 0000000..0fac7dc --- /dev/null +++ b/ept/apt/version-test.cc @@ -0,0 +1,119 @@ +#include "ept/test.h" +#include "version.h" + +using namespace std; +using namespace ept::tests; +using namespace ept::apt; + +namespace { + +class Tests : public TestCase +{ + using TestCase::TestCase; + + void register_tests() override + { + add_method("invalid", []() { + // Basic test for invalid version + Version test; + + wassert(actual(test.name()) == ""); + wassert(actual(test.version()) == ""); + wassert(actual(test.isValid()) == false); + + string p = test.name(); + + wassert(actual(p) == string()); + }); + + add_method("basic", []() { + // Basic test for version + Version test("test", "1.0"); + + wassert(actual(test.name()) == "test"); + wassert(actual(test.version()) == "1.0"); + wassert(actual(test.isValid()) == true); + + string p = test.name(); + + wassert(actual(p) == "test"); + + Version v(p, "1.1"); + wassert(actual(v.name()) == "test"); + wassert(actual(v.version()) == "1.1"); + wassert(actual(v.isValid()) == true); + }); + + add_method("comparison", []() { + // Comparison semanthics + Version test("test", "1.0"); + Version test1("test", "1.0"); + + wassert_true(test == test1); + wassert_true(! (test != test1)); + wassert_true(! (test < test1)); + wassert_true(! (test > test1)); + wassert_true(test <= test1); + wassert_true(test >= test1); + + + Version test2("test2", "1.0"); + + wassert_true(test != test2); + wassert_true(test != test2); + wassert_true(test < test2); + wassert_true(! (test > test2)); + wassert_true(test <= test2); + wassert_true(! (test >= test2)); + + + Version test3("test", "2.0"); + + wassert_true(test != test3); + wassert_true(test != test3); + wassert_true(test < test3); + wassert_true(! (test > test3)); + wassert_true(test <= test3); + wassert_true(! (test >= test3)); + }); + + add_method("value_copy", []() { + // Value-copy semanthics + Version test("test", "1.0"); + Version test1 = test; + + wassert_true(test == test1); + + Version test2; + test2 = test; + wassert_true(test == test2); + wassert_true(test1 == test2); + + Version test3("test", "1.0"); + wassert_true(test == test3); + wassert_true(test1 == test3); + wassert_true(test2 == test3); + }); + + add_method("upstream_version", []() { + // Extraction of upstream version + wassert(actual(Version("a", "10.0").upstreamVersion()) == "10.0"); + wassert(actual(Version("a", "10.0-1").upstreamVersion()) == "10.0"); + wassert(actual(Version("a", "10.0~foo.1-1.0").upstreamVersion()) == "10.0~foo.1"); + wassert(actual(Version("a", "1.0:10.0~foo.1-1.0").upstreamVersion()) == "10.0~foo.1"); + }); + + add_method("policy_comparison", []() { + // Debian policy comparison semanthics + wassert_true(Version("a", "10.0") > Version("a", "2.1")); + wassert_true(Version("a", "1:10.0") < Version("a", "2:2.1")); + wassert_true(Version("a", "10.0-1") < Version("a", "10.0-2")); + wassert_true(Version("a", "10.0-2") > Version("a", "10.0-1")); + wassert_true(Version("a", "1:10.0-1") <= Version("a", "1:10.0-1")); + wassert_true(Version("a", "1:10.0-1") >= Version("a", "1:10.0-1")); + // TODO: add more + }); + } +} tests("apt_version"); + +} diff --git a/ept/apt/version.test.h b/ept/apt/version.test.h deleted file mode 100644 index a06a5c6..0000000 --- a/ept/apt/version.test.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2007 Enrico Zini - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -using namespace std; -using namespace ept::apt; - -struct TestAptVersion { - - // Basic test for invalid version - Test invalid() - { - Version test; - - assert_eq(test.name(), ""); - assert_eq(test.version(), ""); - assert_eq(test.isValid(), false); - - string p = test.name(); - - assert_eq(p, string()); - } - - // Basic test for version - Test basic() - { - Version test("test", "1.0"); - - assert_eq(test.name(), "test"); - assert_eq(test.version(), "1.0"); - assert_eq(test.isValid(), true); - - string p = test.name(); - - assert_eq(p, "test"); - - Version v(p, "1.1"); - assert_eq(v.name(), "test"); - assert_eq(v.version(), "1.1"); - assert_eq(v.isValid(), true); - } - - // Comparison semanthics - Test comparison() - { - Version test("test", "1.0"); - Version test1("test", "1.0"); - - assert(test == test1); - assert(! (test != test1)); - assert(! (test < test1)); - assert(! (test > test1)); - assert(test <= test1); - assert(test >= test1); - - - Version test2("test2", "1.0"); - - assert(test != test2); - assert(test != test2); - assert(test < test2); - assert(! (test > test2)); - assert(test <= test2); - assert(! (test >= test2)); - - - Version test3("test", "2.0"); - - assert(test != test3); - assert(test != test3); - assert(test < test3); - assert(! (test > test3)); - assert(test <= test3); - assert(! (test >= test3)); - } - - // Value-copy semanthics - Test valueCopy() - { - Version test("test", "1.0"); - Version test1 = test; - - assert(test == test1); - - Version test2; - test2 = test; - assert(test == test2); - assert(test1 == test2); - - Version test3("test", "1.0"); - assert(test == test3); - assert(test1 == test3); - assert(test2 == test3); - } - - // Extraction of upstream version - Test upstreamVersion() - { - assert_eq(Version("a", "10.0").upstreamVersion(), "10.0"); - assert_eq(Version("a", "10.0-1").upstreamVersion(), "10.0"); - assert_eq(Version("a", "10.0~foo.1-1.0").upstreamVersion(), "10.0~foo.1"); - assert_eq(Version("a", "1.0:10.0~foo.1-1.0").upstreamVersion(), "10.0~foo.1"); - } - - // Debian policy comparison semanthics - Test policyComparison() - { - assert(Version("a", "10.0") > Version("a", "2.1")); - assert(Version("a", "1:10.0") < Version("a", "2:2.1")); - assert(Version("a", "10.0-1") < Version("a", "10.0-2")); - assert(Version("a", "10.0-2") > Version("a", "10.0-1")); - assert(Version("a", "1:10.0-1") <= Version("a", "1:10.0-1")); - assert(Version("a", "1:10.0-1") >= Version("a", "1:10.0-1")); - // TODO: add more - } - -}; - -// vim:set ts=4 sw=4: diff --git a/ept/axi/axi-test.cc b/ept/axi/axi-test.cc new file mode 100644 index 0000000..e8d7920 --- /dev/null +++ b/ept/axi/axi-test.cc @@ -0,0 +1,37 @@ +#include "ept/test.h" +#include "axi.h" +#include "ept/apt/apt.h" +#include +#include + +using namespace ept::tests; +using namespace std; +using namespace ept; + +namespace { + +struct DirMaker +{ + DirMaker(const std::string& name) + { + wibble::sys::fs::mkdirIfMissing(name, 0755); + } +}; + +class Tests : public TestCase +{ + using TestCase::TestCase; + + void register_tests() override + { + add_method("empty", []() { + // Access an empty index + DirMaker md("xapian"); + apt::Apt apt; + axi::OverrideIndexDir oid("./empty"); + wassert(actual(axi::timestamp()) == 0); + }); + } +} tests("axi"); + +} diff --git a/ept/axi/axi.test.h b/ept/axi/axi.test.h deleted file mode 100644 index 5481bd8..0000000 --- a/ept/axi/axi.test.h +++ /dev/null @@ -1,58 +0,0 @@ -// -*- mode: c++; tab-width: 4; indent-tabs-mode: t -*- -/* - * popcon test - * - * Copyright (C) 2007 Enrico Zini - * - * This program 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 2 of the License, or - * (at your option) any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -using namespace std; -using namespace ept; - -struct DirMaker -{ - DirMaker(const std::string& name) - { - wibble::sys::fs::mkdirIfMissing(name, 0755); - } -}; - -struct TestAxi : AptTestEnvironment -{ - DirMaker md; - axi::OverrideIndexDir oid; - apt::Apt apt; - - TestAxi() - : md( TEST_ENV_DIR "xapian"), oid( TEST_ENV_DIR "xapian") - { - } - -// Access an empty index - Test empty() - { - axi::OverrideIndexDir oid("./empty"); - assert_eq(axi::timestamp(), 0); - } -}; - -// vim:set ts=4 sw=4: diff --git a/ept/debtags/debtags-test.cc b/ept/debtags/debtags-test.cc new file mode 100644 index 0000000..3a8fca5 --- /dev/null +++ b/ept/debtags/debtags-test.cc @@ -0,0 +1,167 @@ +#include "debtags.h" +#include +#include +#include + +using namespace tagcoll; +using namespace std; +using namespace ept; +using namespace ept::debtags; +using namespace ept::tests; +using namespace wibble::operators; + +#define testfile TEST_ENV_DIR "debtags/package-tags" + +namespace { + +class Tests : public TestCase +{ + using TestCase::TestCase; + + void register_tests() override + { + add_method("iterate", []() { + EnvOverride eo("DEBTAGS_TAGS", testfile); + Debtags debtags; + for (Debtags::const_iterator i = debtags.begin(); i != debtags.end(); ++i) + { + *i; + i->first; + i->second; + } + }); + + add_method("lookup_tags", []() { + EnvOverride eo("DEBTAGS_TAGS", testfile); + Debtags debtags; + string p("debtags"); + std::set tags = debtags.getTagsOfItem(p); + wassert(actual(tags.empty()).isfalse()); + +#if 0 + for ( std::set< Tag >::iterator i = tags.begin(); i != tags.end(); ++ i ) { + std::cerr << i->id() << ": " << i->fullname() << std::endl; + } + std::cerr << "---" << std::endl; + Tag t = voc().tagByName( "interface::commandline" ); + std::cerr << t.id() << ": " << t.fullname() << std::endl; +#endif + + wassert(actual(tags.size()) == 8u); + wassert(actual(tags.find("devel::buildtools") != tags.end()).istrue()); + wassert(actual(tags.find("implemented-in::c++") != tags.end()).istrue()); + wassert(actual(tags.find("interface::commandline") != tags.end()).istrue()); + wassert(actual(tags.find("role::program") != tags.end()).istrue()); + wassert(actual(tags.find("scope::application") != tags.end()).istrue()); + wassert(actual(tags.find("suite::debian") != tags.end()).istrue()); + wassert(actual(tags.find("use::searching") != tags.end()).istrue()); + wassert(actual(tags.find("works-with::software:package") != tags.end()).istrue()); + }); + + add_method("lookup_packages", []() { + using namespace std; + EnvOverride eo("DEBTAGS_TAGS", testfile); + Debtags debtags; + + /* Get the 'debtags' package */ + string p("debtags"); + + /* Get its tags */ + std::set tags = debtags.getTagsOfItem(p); + wassert(actual(tags.empty()).isfalse()); + + /* + cerr << "Intersection size: " << endl; + using namespace wibble::operators; + std::set::const_iterator dbgi = tags.begin(); + cerr << "* " << dbgi->fullname() << ": " << dbgi->id() << endl; + std::set dbgres = debtags.tagdb().getItemsHavingTag(dbgi->id()); + std::set dbgpres = debtags.getItemsHavingTag(*dbgi); + cerr << " #pkgs " << dbgres.size() << " == " << dbgpres.size() << endl; + cerr << " #isec " << dbgres.size() << " == " << dbgpres.size() << endl; + cerr << " "; ppset(dbgpres); cerr << endl; + cerr << " "; piset(dbgres); cerr << endl; + for (++dbgi ; dbgi != tags.end(); ++dbgi) + { + cerr << "* " << dbgi->fullname() << ": " << dbgi->id() << endl; + std::set dbgpkgs = debtags.getItemsHavingTag(*dbgi); + std::set dbgids = debtags.tagdb().getItemsHavingTag(dbgi->id()); + cerr << " "; ppset(dbgpkgs); cerr << endl; + cerr << " "; piset(dbgids); cerr << endl; + cerr << " #pkgs " << dbgpkgs.size() << " == " << dbgids.size() << endl; + dbgres &= dbgids; + dbgpres &= dbgpkgs; + cerr << " #isec " << dbgres.size() << " == " << dbgpres.size() << endl; + } + cerr << " " << dbgres.size() << endl << "Results: " << endl; + for (std::set::const_iterator i = dbgres.begin(); i != dbgres.end(); ++i) + cerr << " " << *i << endl; + */ + + + // cerr << "Tags of debtags: "; + // for (std::set::const_iterator i = tags.begin(); i != tags.end(); ++i) + // { + // cerr << " " + i->fullname() << endl; + // std::set packages = debtags.getItemsHavingTag(*i); + // for (std::set::const_iterator p = packages.begin(); + // p != packages.end(); ++p) + // cerr << " PKG " << p->name() << endl; + // } + // cerr << endl; + + /* Get the items for the tagset of 'debtags' */ + std::set packages = debtags.getItemsHavingTags(tags); + //cerr << packages.size() << endl; + wassert(actual(packages.empty()).isfalse()); + /* + for ( std::set< Package >::iterator i = packages.begin(); i != packages.end(); ++ i ) + std::cerr << i->name() << std::endl; + std::cerr << "---" << std::endl; + std::cerr << p.name() << std::endl; + */ + /* They should at least contain 'debtags' */ + wassert(actual(p <= packages).istrue()); + + /* Get one of the tags of 'debtags' */ + std::string tag = *tags.begin(); + + /* Get its items */ + { + /* Need this workaround until I figure out how to tell the new GCC + * that TagDB is a TDBReadonlyDiskIndex and should behave as such + */ + std::set ts; + ts.insert(tag); + packages = debtags.getItemsHavingTags(ts); + } + //packages = c.debtags().tagdb().getItems(tag); + wassert(actual(packages.empty()).isfalse()); + /* They should at least contain 'debtags' */ + wassert(actual(p <= packages).istrue()); + + //c.debtags().getTags(""); // XXX HACK AWW! + }); + + add_method("empty", []() { + // If there is no data, Debtags should work as an empty collection + EnvOverride eo("DEBTAGS_TAGS", "./empty/notags"); + Debtags empty; + + wassert(actual(empty.begin() == empty.end()).istrue()); + wassert(actual(empty.timestamp()) == 0); + wassert(actual(empty.hasData()).isfalse()); + + set res = empty.getTagsOfItem("apt"); + wassert(actual(res.empty()).istrue()); + // TODO: currently does not compile because of a bug in tagcoll + //res = empty.getTagsOfItems(wibble::singleton(string("apt"))); + //assert(res.empty()); + + res = empty.getAllTags(); + wassert(actual(res.empty()).istrue()); + }); + } +} tests("debtags"); + +} diff --git a/ept/debtags/debtags.test.h b/ept/debtags/debtags.test.h deleted file mode 100644 index 8376a9d..0000000 --- a/ept/debtags/debtags.test.h +++ /dev/null @@ -1,197 +0,0 @@ -// -*- mode: c++; tab-width: 4; indent-tabs-mode: t -*- -/** - * @file - * @author Enrico Zini (enrico) - */ - -/* - * Test for the Debtags data provider - * - * Copyright (C) 2003-2007 Enrico Zini - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include - -#include -#include - -#ifndef EPT_DEBTAGS_TESTH -#define EPT_DEBTAGS_TESTH - -using namespace tagcoll; -using namespace std; -using namespace ept; -using namespace ept::debtags; -using namespace wibble::operators; - -#define testfile TEST_ENV_DIR "debtags/package-tags" - -struct TestDebtags : DebtagsTestEnvironment -{ - TestDebtags() {} - - Test _1() - { - EnvOverride eo("DEBTAGS_TAGS", testfile); - Debtags debtags; - for (Debtags::const_iterator i = debtags.begin(); i != debtags.end(); ++i) - { - *i; - i->first; - i->second; - } - } - - Test _2() - { - EnvOverride eo("DEBTAGS_TAGS", testfile); - Debtags debtags; - string p("debtags"); - std::set tags = debtags.getTagsOfItem(p); - assert( !tags.empty() ); - -#if 0 - for ( std::set< Tag >::iterator i = tags.begin(); i != tags.end(); ++ i ) { - std::cerr << i->id() << ": " << i->fullname() << std::endl; - } - std::cerr << "---" << std::endl; - Tag t = voc().tagByName( "interface::commandline" ); - std::cerr << t.id() << ": " << t.fullname() << std::endl; -#endif - - assert_eq( tags.size(), 8u ); - assert( tags.find("devel::buildtools") != tags.end() ); - assert( tags.find("implemented-in::c++") != tags.end() ); - assert( tags.find("interface::commandline") != tags.end() ); - assert( tags.find("role::program") != tags.end() ); - assert( tags.find("scope::application") != tags.end() ); - assert( tags.find("suite::debian") != tags.end() ); - assert( tags.find("use::searching") != tags.end() ); - assert( tags.find("works-with::software:package") != tags.end() ); -} - - Test _3() - { - using namespace std; - EnvOverride eo("DEBTAGS_TAGS", testfile); - Debtags debtags; - - /* Get the 'debtags' package */ - string p("debtags"); - - /* Get its tags */ - std::set tags = debtags.getTagsOfItem(p); - assert(!tags.empty()); - - /* - cerr << "Intersection size: " << endl; - using namespace wibble::operators; - std::set::const_iterator dbgi = tags.begin(); - cerr << "* " << dbgi->fullname() << ": " << dbgi->id() << endl; - std::set dbgres = debtags.tagdb().getItemsHavingTag(dbgi->id()); - std::set dbgpres = debtags.getItemsHavingTag(*dbgi); - cerr << " #pkgs " << dbgres.size() << " == " << dbgpres.size() << endl; - cerr << " #isec " << dbgres.size() << " == " << dbgpres.size() << endl; - cerr << " "; ppset(dbgpres); cerr << endl; - cerr << " "; piset(dbgres); cerr << endl; - for (++dbgi ; dbgi != tags.end(); ++dbgi) - { - cerr << "* " << dbgi->fullname() << ": " << dbgi->id() << endl; - std::set dbgpkgs = debtags.getItemsHavingTag(*dbgi); - std::set dbgids = debtags.tagdb().getItemsHavingTag(dbgi->id()); - cerr << " "; ppset(dbgpkgs); cerr << endl; - cerr << " "; piset(dbgids); cerr << endl; - cerr << " #pkgs " << dbgpkgs.size() << " == " << dbgids.size() << endl; - dbgres &= dbgids; - dbgpres &= dbgpkgs; - cerr << " #isec " << dbgres.size() << " == " << dbgpres.size() << endl; - } - cerr << " " << dbgres.size() << endl << "Results: " << endl; - for (std::set::const_iterator i = dbgres.begin(); i != dbgres.end(); ++i) - cerr << " " << *i << endl; - */ - - -// cerr << "Tags of debtags: "; -// for (std::set::const_iterator i = tags.begin(); i != tags.end(); ++i) -// { -// cerr << " " + i->fullname() << endl; -// std::set packages = debtags.getItemsHavingTag(*i); -// for (std::set::const_iterator p = packages.begin(); -// p != packages.end(); ++p) -// cerr << " PKG " << p->name() << endl; -// } -// cerr << endl; - - /* Get the items for the tagset of 'debtags' */ - std::set packages = debtags.getItemsHavingTags(tags); - //cerr << packages.size() << endl; - assert(!packages.empty()); - /* - for ( std::set< Package >::iterator i = packages.begin(); i != packages.end(); ++ i ) - std::cerr << i->name() << std::endl; - std::cerr << "---" << std::endl; - std::cerr << p.name() << std::endl; - */ - /* They should at least contain 'debtags' */ - assert( p <= packages ); - - /* Get one of the tags of 'debtags' */ - std::string tag = *tags.begin(); - - /* Get its items */ - { - /* Need this workaround until I figure out how to tell the new GCC - * that TagDB is a TDBReadonlyDiskIndex and should behave as such - */ - std::set ts; - ts.insert(tag); - packages = debtags.getItemsHavingTags(ts); - } - //packages = c.debtags().tagdb().getItems(tag); - assert(!packages.empty()); - /* They should at least contain 'debtags' */ - assert( p <= packages ); - - //c.debtags().getTags(""); // XXX HACK AWW! -} - - // If there is no data, Debtags should work as an empty collection - Test _4() - { - EnvOverride eo("DEBTAGS_TAGS", "./empty/notags"); - Debtags empty; - - assert(empty.begin() == empty.end()); - assert_eq(empty.timestamp(), 0); - assert(!empty.hasData()); - - set res = empty.getTagsOfItem("apt"); - assert(res.empty()); - // TODO: currently does not compile because of a bug in tagcoll - //res = empty.getTagsOfItems(wibble::singleton(string("apt"))); - //assert(res.empty()); - - res = empty.getAllTags(); - assert(res.empty()); -} - -}; - -#endif diff --git a/ept/debtags/vocabulary-test.cc b/ept/debtags/vocabulary-test.cc new file mode 100644 index 0000000..51f46f9 --- /dev/null +++ b/ept/debtags/vocabulary-test.cc @@ -0,0 +1,195 @@ +#include "ept/test.h" +#include "vocabulary.h" +#include "coll/set.h" +#include "ept/test.h" + +using namespace std; +using namespace tagcoll::utils; +using namespace ept::debtags; +using namespace ept::tests; + +#define testfile "debtags/vocabulary" + +namespace { + +class Tests : public TestCase +{ + using TestCase::TestCase; + + void register_tests() override + { + add_method("load", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; // this will throw if it failed to load + }); + + add_method("has_facet", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + assert_true( tags.hasFacet( "works-with" ) ); + assert_true( !tags.hasFacet( "blah" ) ); + }); + + add_method("has_tag", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + assert_true( tags.hasTag( "works-with::people" ) ); + assert_true( !tags.hasTag( "works-with::foobar" ) ); + }); + + add_method("tagdata", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + const voc::TagData *people = tags.tagData( "works-with::people" ), + *foobar = tags.tagData( "works-with::foobar" ), + *blahg = tags.tagData( "works-with::blahg" ), + *text = tags.tagData( "works-with::text" ), + *people2 = tags.tagData( "works-with::people" ); + assert_true( people != foobar ); + assert_true( people != text ); + assert_true( people != blahg ); + assert_true( foobar == blahg ); + assert_true( foobar == foobar ); + assert_true( people == people2 ); + assert_true( people == people ); + }); + + add_method("tags", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + std::string a = "works-with::people", + b = "works-with::foobar"; + std::set s = tags.tags(), + f = tags.tags( "works-with" ), + n = tags.tags( "nonsense" ); + assert_true( set_contains(s, a) ); + assert_true( set_contains(f, a) ); + assert_true( set_contains(s, f) ); + assert_true( !set_contains(s, b) ); + assert_true( !set_contains(f, b) ); + assert_true( n.empty() ); + }); + + add_method("facetdata", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + + const voc::FacetData* f = tags.facetData( "works-with" ); + assert_true(f); + wassert(actual(f->name) == "works-with"); + + const voc::TagData* t = tags.tagData( "works-with::people" ); + assert_true(t); + wassert(actual(t->name) == "works-with::people"); + }); + + add_method("facettags", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + + const voc::FacetData* f = tags.facetData( "works-with" ); + std::set x = tags.tags( "works-with" ); + assert_true( x == f->tags() ); + }); + + add_method("missing_facet", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + + const voc::FacetData* f = tags.facetData( "does-not-work-with" ); + assert_true(!f); + }); + + add_method("missing_facet1", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + + const voc::FacetData* f = tags.facetData( "legacy" ); + assert_true(f); + wassert(actual(f->shortDescription()) == ""); + wassert(actual(f->longDescription()) == ""); + //wassert(actual(f.shortDescription( "weehee" )) == "weehee"); + }); + + add_method("one_letter_tag", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + + // assert_true that one-character tag names are parsed correctly + assert_true( tags.hasTag( "implemented-in::c" ) ); + }); + + add_method("iterate_facets", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + + // assert_true that all facets are somehow working + std::set facets = tags.facets(); + + for (std::set::const_iterator i = facets.begin(); + i != facets.end(); i++) + { + const voc::FacetData* f = tags.facetData(*i); + assert_true(f); + } + }); + + add_method("iterate_tags", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary voc; + + // assert_true that all tags are somehow working + std::set tags = voc.tags(); + for (std::set::const_iterator i = tags.begin(); + i != tags.end(); i++) + { + const voc::TagData* t = voc.tagData(*i); + assert_true(t); + } + }); + + add_method("first_last", []() { + // Check for correctness of the first and last tag in the vocabulary + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + + const voc::TagData* first = tags.tagData("accessibility::TODO"); + assert_true(first); + wassert(actual(first->name) == string("accessibility::TODO")); + wassert(actual(first->shortDescription()) == string("Need an extra tag")); + + const voc::TagData* last = tags.tagData("x11::xserver"); + assert_true(last); + wassert(actual(last->name) == string("x11::xserver")); + wassert(actual(last->shortDescription()) == string("X Server")); + }); + + add_method("get_all_tags", []() { + EnvOverride eo("DEBTAGS_VOCABULARY", testfile); + Vocabulary tags; + + // check that we're seeing all the tags for a facet + std::set t = tags.tags("accessibility"); + wassert(actual(t.size()) == 10u); + + t = tags.tags("works-with-format"); + wassert(actual(t.size()) == 33u); + }); + + add_method("empty", []() { + // If there is no data, Vocabulary should work as an empty vocabulary + EnvOverride eo("DEBTAGS_VOCABULARY", "./empty/novocabularyhere"); + Vocabulary empty; + + assert_true(!empty.hasData()); + + set facets = empty.facets(); + wassert(actual(facets.size()) == 0u); + + set tags = empty.tags(); + wassert(actual(tags.size()) == 0u); + }); + } +} tests("debtags_vocabulary"); + +} diff --git a/ept/debtags/vocabulary.test.h b/ept/debtags/vocabulary.test.h deleted file mode 100644 index 4d698ea..0000000 --- a/ept/debtags/vocabulary.test.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Tag vocabulary access - * - * Copyright (C) 2003--2007 Enrico Zini - * - * This program 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 2 of the License, or - * (at your option) any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include "ept/test.h" - -using namespace std; -using namespace tagcoll::utils; -using namespace ept::debtags; - -#define testfile TEST_ENV_DIR "debtags/vocabulary" - - -struct TestVocabulary : DebtagsTestEnvironment -{ - Test _1() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; // this will throw if it failed to load -} - - Test _2() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - assert( tags.hasFacet( "works-with" ) ); - assert( !tags.hasFacet( "blah" ) ); -} - - Test _3() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - assert( tags.hasTag( "works-with::people" ) ); - assert( !tags.hasTag( "works-with::foobar" ) ); -} - - Test _4() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - const voc::TagData *people = tags.tagData( "works-with::people" ), - *foobar = tags.tagData( "works-with::foobar" ), - *blahg = tags.tagData( "works-with::blahg" ), - *text = tags.tagData( "works-with::text" ), - *people2 = tags.tagData( "works-with::people" ); - assert( people != foobar ); - assert( people != text ); - assert( people != blahg ); - assert( foobar == blahg ); - assert( foobar == foobar ); - assert( people == people2 ); - assert( people == people ); -} - - Test _5() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - std::string a = "works-with::people", - b = "works-with::foobar"; - std::set s = tags.tags(), - f = tags.tags( "works-with" ), - n = tags.tags( "nonsense" ); - assert( set_contains(s, a) ); - assert( set_contains(f, a) ); - assert( set_contains(s, f) ); - assert( !set_contains(s, b) ); - assert( !set_contains(f, b) ); - assert( n.empty() ); -} - - Test _6() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - - const voc::FacetData* f = tags.facetData( "works-with" ); - assert(f); - assert_eq(f->name, "works-with"); - - const voc::TagData* t = tags.tagData( "works-with::people" ); - assert(t); - assert_eq(t->name, "works-with::people"); -} - - Test _7() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - - const voc::FacetData* f = tags.facetData( "works-with" ); - std::set x = tags.tags( "works-with" ); - assert( x == f->tags() ); -} - - Test _8() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - - const voc::FacetData* f = tags.facetData( "does-not-work-with" ); - assert(!f); -} - - Test _9() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - - const voc::FacetData* f = tags.facetData( "legacy" ); - assert(f); - assert_eq(f->shortDescription(), ""); - assert_eq(f->longDescription(), ""); - //assert_eq(f.shortDescription( "weehee" ), "weehee"); -} - - Test _10() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - - // assert that one-character tag names are parsed correctly - assert( tags.hasTag( "implemented-in::c" ) ); -} - - Test _11() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - - // assert that all facets are somehow working - std::set facets = tags.facets(); - - for (std::set::const_iterator i = facets.begin(); - i != facets.end(); i++) - { - const voc::FacetData* f = tags.facetData(*i); - assert(f); - } -} - - Test _12() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary voc; - - // assert that all tags are somehow working - std::set tags = voc.tags(); - for (std::set::const_iterator i = tags.begin(); - i != tags.end(); i++) - { - const voc::TagData* t = voc.tagData(*i); - assert(t); - } -} - -// Check for correctness of the first and last tag in the vocabulary - Test _13() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - - const voc::TagData* first = tags.tagData("accessibility::TODO"); - assert(first); - assert_eq(first->name, string("accessibility::TODO")); - assert_eq(first->shortDescription(), string("Need an extra tag")); - - const voc::TagData* last = tags.tagData("x11::xserver"); - assert(last); - assert_eq(last->name, string("x11::xserver")); - assert_eq(last->shortDescription(), string("X Server")); -} - - Test _14() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", testfile); - Vocabulary tags; - - // check that we're seeing all the tags for a facet - std::set t = tags.tags("accessibility"); - assert_eq(t.size(), 10u); - - t = tags.tags("works-with-format"); - assert_eq(t.size(), 33u); -} - -// If there is no data, Vocabulary should work as an empty vocabulary - Test _15() -{ - EnvOverride eo("DEBTAGS_VOCABULARY", "./empty/novocabularyhere"); - Vocabulary empty; - - assert(!empty.hasData()); - - set facets = empty.facets(); - assert_eq(facets.size(), 0u); - - set tags = empty.tags(); - assert_eq(tags.size(), 0u); -} - -}; diff --git a/ept/test-main.h b/ept/test-main.h deleted file mode 100644 index 7b2afbc..0000000 --- a/ept/test-main.h +++ /dev/null @@ -1,186 +0,0 @@ -// -*- C++ -*- -#include -#include - -struct Main { - - int suite, test; - int status[2]; - int confirm[2]; - FILE *f_confirm, *f_status; - pid_t pid; - int argc; - char **argv; - pid_t finished; - int status_code; - int test_ok; - - int suite_ok, suite_failed; - int total_ok, total_failed; - - int announced_suite; - std::string current; - - RunAll all; - - Main() : suite(0), test(0) { - suite_ok = suite_failed = 0; - total_ok = total_failed = 0; - test_ok = 0; - announced_suite = -1; - } - - void child() { - close( status[0] ); - close( confirm[1] ); - all.status = fdopen( status[1], "w" ); - all.confirm = fdopen( confirm[0], "r" ); - if ( argc > 1 ) { - RunSuite *s = all.findSuite( argv[1] ); - if (!s) { - std::cerr << "No such suite " << argv[1] << std::endl; - // todo dump possible suites? - exit(250); - } - all.runSuite( *s, test, 0, 1 ); - } - if ( argc == 1 ) { - all.runFrom( suite, test ); - } - fprintf( all.status, "done\n" ); - exit( 0 ); - } - - void testDied() - { - /* std::cerr << "test died: " << test << "/" - << suites[suite].testCount << std::endl; */ - if ( WIFEXITED( status_code ) ) { - if ( WEXITSTATUS( status_code ) == 250 ) - exit( 3 ); - if ( WEXITSTATUS( status_code ) == 0 ) - return; - } - std::cout << "failed test: "<< current; - if ( WIFEXITED( status_code ) ) - std::cout << " (exit status " << WEXITSTATUS( status_code ) << ")"; - if ( WIFSIGNALED( status_code ) ) - std::cout << " (caught signal " << WTERMSIG( status_code ) << ")"; - std::cout << std::endl; - // re-announce the suite - announced_suite --; - ++ test; // continue with next test - test_ok = 0; - suite_failed ++; - } - - void processStatus( const char *line ) { - if ( std::string("done") == line ) { // finished - finished = waitpid( pid, &status_code, 0 ); - assert_eq( pid, finished ); - assert( WIFEXITED( status_code ) ); - assert_eq( WEXITSTATUS( status_code ), 0 ); - std::cout << "overall " << total_ok << "/" - << total_ok + total_failed - << " ok" << std::endl; - exit( total_failed == 0 ? 0 : 1 ); - } - - if ( test_ok ) { - /* std::cerr << "test ok: " << test << "/" - << suites[suite].testCount << std::endl; */ - std::cout << "." << std::flush; - suite_ok ++; - ++ test; - test_ok = 0; - } - - if ( line[0] == 's' ) { - if ( line[2] == 'd' ) { - std::cout << " " << suite_ok << "/" << suite_ok + suite_failed - << " ok" << std::endl; - ++ suite; test = 0; - assert( !test_ok ); - total_ok += suite_ok; - total_failed += suite_failed; - suite_ok = suite_failed = 0; - } - if ( line[2] == 's' ) { - if ( announced_suite < suite ) { - std::cout << line + 5 << ": " << std::flush; - announced_suite = suite; - } - } - } - if ( line[0] == 't' ) { - if ( line[2] == 'd' ) { - fprintf( f_confirm, "ack\n" ); - fflush( f_confirm ); - test_ok = 1; - } - if ( line[2] == 's' ) { - fprintf( f_confirm, "ack\n" ); - fflush( f_confirm ); - current = line + 5; - } - } - } - - void parent() { - close( status[1] ); - close( confirm[0] ); - f_status = fdopen( status[0], "r" ); - f_confirm = fdopen( confirm[1], "w" ); - char *line = 0; - size_t n; - - while ( true ) { - if ( getline( &line, &n, f_status ) < 0 ) { - finished = waitpid( pid, &status_code, 0 ); - if ( finished < 0 ) { - perror( "waitpid failed" ); - exit( 5 ); - } - assert_eq( pid, finished ); - testDied(); - /* std::cerr << "child will be reforked at: " - << suite << " " << test << std::endl; */ - return; - } else { - // std::cerr << "reading pipe: " << line; - line[ strlen( line ) - 1 ] = 0; - processStatus( line ); - free( line ); - } - line = 0; - } - } - - int main( int _argc, char **_argv ) - { - argc = _argc; - argv = _argv; - - all.suiteCount = sizeof(suites)/sizeof(RunSuite); - all.suites = suites; - - while (true) { - if ( pipe( status ) ) - return 1; - if ( pipe( confirm ) ) - return 1; - pid = fork(); - if ( pid < 0 ) - return 2; - if ( pid == 0 ) { // child - child(); - } else { - parent(); - } - } - } -}; - -int main( int argc, char **argv ) { - return Main().main( argc, argv ); -} diff --git a/ept/test-runner.h b/ept/test-runner.h deleted file mode 100644 index 8fe4d12..0000000 --- a/ept/test-runner.h +++ /dev/null @@ -1,63 +0,0 @@ -#include - -#define RUN(x, y) x().y() - -struct RunTest { - const char *name; - void (*run)(); -}; - -struct RunSuite { - const char *name; - RunTest *tests; - int testCount; -}; - -struct RunAll { - RunSuite *suites; - int suiteCount; - FILE *status, *confirm; - - RunSuite *findSuite( std::string name ) { - for ( int i = 0; i < suiteCount; ++i ) - if ( suites[i].name == name ) - return suites + i; - return 0; - } - - void waitForAck() { - size_t n = 0; char *line = 0; - size_t read = getline( &line, &n, confirm ); - assert_eq( read, 4 ); - assert_eq( std::string( "ack\n" ), line ); - free( line ); - } - - void runSuite( RunSuite &s, int fromTest, int suite, int suiteCount ) - { - fprintf( status, "s/s: (%d/%d) %s\n", suite + 1, suiteCount, s.name ); - for ( int i = fromTest; i < s.testCount; ++i ) { - fprintf( status, "t/s: (%d/%d) %s\n", i, s.testCount, - s.tests[i].name ); - fflush( status ); - waitForAck(); - s.tests[i].run(); - fprintf( status, "t/d: %s\n", s.tests[i].name ); - fflush( status ); - waitForAck(); - // exit( 0 ); // TODO make this optional; safety vs - // performance tradeoff - } - fprintf( status, "s/d: %s\n", s.name ); - } - - void runFrom( int suite, int test ) - { - for ( int i = suite; i < suiteCount; ++i ) { - assert( suite <= suiteCount ); - runSuite( suites[i], test, i, suiteCount ); - test = 0; - } - } -}; - diff --git a/ept/test.h b/ept/test.h index fc29ed6..e0b8d20 100644 --- a/ept/test.h +++ b/ept/test.h @@ -1,8 +1,8 @@ -//#include -#include - -#include +#ifndef EPT_TEST_H +#define EPT_TEST_H +#include +#include #include #include #include @@ -13,29 +13,6 @@ #include #include - -#ifndef EPT_TEST_H -#define EPT_TEST_H - -struct AptTestEnvironment { - //ept::core::AptDatabase db; - AptTestEnvironment() { - pkgInitConfig (*_config); - _config->Set("Initialized", 1); - _config->Set("Dir", TEST_ENV_DIR); - _config->Set("Dir::Cache", "cache"); - _config->Set("Dir::State", "state"); - _config->Set("Dir::Etc", "etc"); - _config->Set("Dir::Etc::sourcelist", "sources.list"); - _config->Set("Dir::State::status", TEST_ENV_DIR "dpkg-status"); - pkgInitSystem (*_config, _system); - } -}; - -struct DebtagsTestEnvironment : AptTestEnvironment { - DebtagsTestEnvironment() {} -}; - struct EnvOverride { const char* name; diff --git a/ept/utils/tests.h b/ept/utils/tests.h index 6622cae..3b00a14 100644 --- a/ept/utils/tests.h +++ b/ept/utils/tests.h @@ -350,6 +350,12 @@ inline ActualFunction actual_function(std::function actual) { return Act throw TestFailed(e, __FILE__, __LINE__, #__VA_ARGS__, ept_test_location_info); \ } } while(0) +/// Shortcut to check that a given expression returns true +#define wassert_true(...) wassert(actual(__VA_ARGS__).istrue()) + +/// Shortcut to check that a given expression returns false +#define wassert_false(...) wassert(actual(__VA_ARGS__).isfalse()) + /** * Call a function returning its result, and raising TestFailed with the * appropriate backtrace information if it threw an exception. diff --git a/run-check b/run-check new file mode 100755 index 0000000..ea05d69 --- /dev/null +++ b/run-check @@ -0,0 +1,59 @@ +#!/bin/sh -e + +TOP_SRCDIR=$(readlink -f $(dirname "$0")) +CMD=$(readlink -f "$1") + +## Set up the test environment +datadir="${TOP_SRCDIR}/ept/test-data" +TESTDIR="`mktemp -d`" +cd "$TESTDIR" + +## Clean up the test environment at exit unless asked otherwise +cleanup() { + test -z "$PRESERVE" && rm -rf "$TESTDIR" +} +trap cleanup EXIT + +ARCH=$(dpkg --print-architecture) +listfile=wherever_debian_._Packages +mkdir -p etc state/lists/partial cache debtags cache/archives/partial desktop +sed -e s,i386,${ARCH}, < ${datadir}/packagelist > state/lists/${listfile} +cp -a ${datadir}/etc/sources.list etc/ +sed -e s,i386,${ARCH}, < ${datadir}/dpkg-status > dpkg-status +cp -a ${datadir}/desktop/*.desktop desktop/ +cp ${datadir}/debtags/package-tags debtags/package-tags +cp ${datadir}/debtags/vocabulary debtags/vocabulary +mkdir -p debtags/empty +mkdir -p debtags/user +mkdir -p xapian/ + +# Try to debug the libtool executable, if present +DIR=`dirname $CMD` +BASE=`basename $CMD` +if [ ! -z "$DEBUGGER" ] +then + echo "Running $DEBUGGER $CMD $ARGS" + RES=0 + if ! $DEBUGGER $CMD $ARGS + then + RES=$? + echo "Failed with result $RES" + fi +else + echo "Running $CMD $ARGS" + RES=0 + if ! $CMD $ARGS + then + RES=$? + echo "Failed with result $RES" + fi +fi + +if [ ! -z "$PAUSE" ] +then + echo "Post-test inspection requested." + echo "Exit this shell to cleanup the test environment." + bash +fi + +exit $RES -- cgit v1.2.3 From ac504b3ed0d23451a76056b1c5bbeb1a2977d265 Mon Sep 17 00:00:00 2001 From: Enrico Zini Date: Thu, 10 Sep 2015 12:15:48 +0200 Subject: Cleaned up unused tagcoll code --- ept/CMakeLists.txt | 4 +- ept/debtags/coll/TextFormat.cc | 87 ++++++++++- ept/debtags/coll/TextFormat.h | 53 +------ ept/debtags/coll/TextFormat.tcc | 176 --------------------- ept/debtags/coll/base.h | 333 ---------------------------------------- ept/debtags/coll/base.tcc | 191 ----------------------- ept/debtags/coll/fast.cc | 254 ++++++++++++++++++++++++++++++ ept/debtags/coll/fast.h | 101 ++++++------ ept/debtags/coll/fast.tcc | 326 --------------------------------------- ept/debtags/coll/set.h | 7 +- ept/debtags/debtags-test.cc | 1 - ept/debtags/debtags.cc | 18 +-- ept/debtags/debtags.h | 14 +- ept/debtags/vocabulary-test.cc | 2 +- 14 files changed, 402 insertions(+), 1165 deletions(-) delete mode 100644 ept/debtags/coll/TextFormat.tcc delete mode 100644 ept/debtags/coll/base.h delete mode 100644 ept/debtags/coll/base.tcc create mode 100644 ept/debtags/coll/fast.cc delete mode 100644 ept/debtags/coll/fast.tcc (limited to 'ept/CMakeLists.txt') diff --git a/ept/CMakeLists.txt b/ept/CMakeLists.txt index 3d2dadd..f5874bf 100644 --- a/ept/CMakeLists.txt +++ b/ept/CMakeLists.txt @@ -8,8 +8,8 @@ list(REMOVE_ITEM src ${tests}) # Find headers file( GLOB h_top *.h ) file( GLOB h_apt apt/*.h ) -file( GLOB h_debtags debtags/*.h debtags/*.tcc ) -file( GLOB h_debtags_maint debtags/maint/*.h debtags/maint/*.tcc ) +file( GLOB h_debtags debtags/*.h ) +file( GLOB h_debtags_maint debtags/maint/*.h ) file( GLOB h_axi axi/*.h ) file( GLOB h_utils utils/*.h ) diff --git a/ept/debtags/coll/TextFormat.cc b/ept/debtags/coll/TextFormat.cc index dac5696..98c94f8 100644 --- a/ept/debtags/coll/TextFormat.cc +++ b/ept/debtags/coll/TextFormat.cc @@ -19,13 +19,20 @@ */ #include "TextFormat.h" +#include "fast.h" +#include +#include #include #include +#include using namespace std; using namespace wibble; +using namespace wibble::operators; -namespace tagcoll { +namespace ept { +namespace debtags { +namespace coll { namespace textformat { // Parse an element @@ -156,7 +163,83 @@ int parseElement(FILE* in, const std::string& pathname, string& item) return EOF; } +static void printTagset(const std::set& ts, FILE* out) +{ + for (std::set::const_iterator i = ts.begin(); + i != ts.end(); i++) + if (i == ts.begin()) + { + if (fprintf(out, "%s", i->c_str()) < 0) + throw wibble::exception::System("writing tagset"); + } + else + { + if (fprintf(out, ", %s", i->c_str()) < 0) + throw wibble::exception::System("writing tagset"); + } +} + +inline static void outString(const std::string& str, FILE* out, const char* what) +{ + if (fwrite(str.data(), str.size(), 1, out) != 1) + throw wibble::exception::System(string("writing ") + what); } + + +// item1, item2, item3: tag1, tag2, tag3 + +//#define TRACE_PARSE +void parse(FILE* in, const std::string& pathname, Fast& out) +{ + string item; + + std::set itemset; + std::set tagset; + int sep; + enum {ITEMS, TAGS} state = ITEMS; + int line = 1; + do + { + sep = parseElement(in, pathname, item); + + if (item.size() != 0) + { + if (state == ITEMS) + itemset |= item; + else + tagset |= item; + } + + switch (sep) + { + case '\n': + line++; + case EOF: + if (!(itemset.empty() && tagset.empty())) + { + if (itemset.empty()) + throw std::runtime_error("no elements before ':' separator"); + if (tagset.empty()) + out.insert(itemset, std::set()); + else + out.insert(itemset, tagset); + } + itemset.clear(); + tagset.clear(); + state = ITEMS; + break; + case ':': + if (state == TAGS) + throw std::runtime_error("separator ':' appears twice"); + state = TAGS; + break; + default: + break; + } + } while (sep != EOF); } -#include "TextFormat.tcc" +} +} +} +} diff --git a/ept/debtags/coll/TextFormat.h b/ept/debtags/coll/TextFormat.h index 8b4c179..a35f664 100644 --- a/ept/debtags/coll/TextFormat.h +++ b/ept/debtags/coll/TextFormat.h @@ -26,53 +26,16 @@ #include #include #include -//#include #include //#define TRACE_PARSE -namespace tagcoll -{ +namespace ept { +namespace debtags { +namespace coll { +struct Fast; -namespace textformat -{ - -/** - * TagcollConsumer that serializes its input to an output stream - * - * The format of the output is: - * lines of "comma+space"-separated items, followed by "colon+space", - * followed by the corresponding "comma+space"-separated tags. - * Examples: - * ITEM: - * ITEM: TAG - * ITEM: TAG1, TAG2, TAG3 - * ITEM1, ITEM2, ITEM3: - * ITEM1, ITEM2, ITEM3: TAG1, TAG2, TAG3 - */ -class StdioWriter : public wibble::mixin::OutputIterator -{ -protected: - FILE* out; - -public: - StdioWriter(FILE* out) : out(out) {} - - template - StdioWriter& operator=(const std::pair& data); -}; - -class OstreamWriter : public wibble::mixin::OutputIterator -{ -protected: - std::ostream& out; - -public: - OstreamWriter(std::ostream& out) : out(out) {} - - template - OstreamWriter& operator=(const std::pair& data); -}; +namespace textformat { /** * Parse an element from input @@ -95,11 +58,11 @@ int parseElement(FILE* in, const std::string& pathname, std::string& item); * @param out * An output iterator accepting a std::pair */ -template -void parse(FILE* in, const std::string& pathname, OUT out); +void parse(FILE* in, const std::string& pathname, Fast& out); +} +} } } -// vim:set ts=4 sw=4: #endif diff --git a/ept/debtags/coll/TextFormat.tcc b/ept/debtags/coll/TextFormat.tcc deleted file mode 100644 index 2a153c9..0000000 --- a/ept/debtags/coll/TextFormat.tcc +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Serialize a tagged collection to a text file - * - * Copyright (C) 2003--2015 Enrico Zini - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TAGCOLL_TEXTFORMAT_TCC -#define TAGCOLL_TEXTFORMAT_TCC - -#include -//#include - -#include -#include -#include - -#include - -using namespace std; -using namespace wibble; -using namespace wibble::operators; - -static void printTagset(const std::set& ts, FILE* out) -{ - for (std::set::const_iterator i = ts.begin(); - i != ts.end(); i++) - if (i == ts.begin()) - { - if (fprintf(out, "%s", i->c_str()) < 0) - throw wibble::exception::System("writing tagset"); - } - else - { - if (fprintf(out, ", %s", i->c_str()) < 0) - throw wibble::exception::System("writing tagset"); - } -} - -namespace tagcoll { -namespace textformat { - -inline static void outString(const std::string& str, FILE* out, const char* what) -{ - if (fwrite(str.data(), str.size(), 1, out) != 1) - throw wibble::exception::System(string("writing ") + what); -} - -template -StdioWriter& StdioWriter::operator=(const std::pair& data) -{ - for (typename Items::const_iterator i = data.first.begin(); - i != data.first.end(); ++i) - { - if (i != data.first.begin()) - if (fputs(", ", out) == EOF) - throw wibble::exception::System("writing comma after item"); - outString(*i, out, "item"); - } - if (data.second.begin() != data.second.end()) - { - if (fputs(": ", out) == EOF) - throw wibble::exception::System("writing colon after items"); - for (typename Tags::const_iterator i = data.second.begin(); - i != data.second.end(); ++i) - { - if (i != data.second.begin()) - if (fputs(", ", out) == EOF) - throw wibble::exception::System("writing comma after tag"); - outString(*i, out, "tag"); - } - } - if (fputc('\n', out) == EOF) - throw wibble::exception::System("writing newline after tagset"); - return *this; -} - -template -OstreamWriter& OstreamWriter::operator=(const std::pair& data) -{ - for (typename Items::const_iterator i = data.first.begin(); - i != data.first.end(); ++i) - { - if (i != data.first.begin()) - out << ", "; - out << *i; - } - if (data.second.begin() != data.second.end()) - { - out << ": "; - for (typename Tags::const_iterator i = data.second.begin(); - i != data.second.end(); ++i) - { - if (i != data.second.begin()) - out << ", "; - out << *i; - } - } - out << endl; - return *this; -} - - - -// item1, item2, item3: tag1, tag2, tag3 - -//#define TRACE_PARSE -template -void parse(FILE* in, const std::string& pathname, OUT out) -{ - string item; - - std::set itemset; - std::set tagset; - int sep; - enum {ITEMS, TAGS} state = ITEMS; - int line = 1; - do - { - sep = parseElement(in, pathname, item); - - if (item.size() != 0) - { - if (state == ITEMS) - itemset |= item; - else - tagset |= item; - } - - switch (sep) - { - case '\n': - line++; - case EOF: - if (!(itemset.empty() && tagset.empty())) - { - if (itemset.empty()) - throw std::runtime_error("no elements before ':' separator"); - if (tagset.empty()) - *out = make_pair(itemset, wibble::Empty()); - else - *out = make_pair(itemset, tagset); - ++out; - } - itemset.clear(); - tagset.clear(); - state = ITEMS; - break; - case ':': - if (state == TAGS) - throw std::runtime_error("separator ':' appears twice"); - state = TAGS; - break; - default: - break; - } - } while (sep != EOF); -} - -} -} - -#endif diff --git a/ept/debtags/coll/base.h b/ept/debtags/coll/base.h deleted file mode 100644 index 02e59af..0000000 --- a/ept/debtags/coll/base.h +++ /dev/null @@ -1,333 +0,0 @@ -#ifndef TAGCOLL_COLL_BASE_H -#define TAGCOLL_COLL_BASE_H - -/** \file - * Base mixins for tagged collections - */ - -/* - * Copyright (C) 2003,2004,2005,2006 Enrico Zini - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -namespace std { -template class pair; -} - -namespace tagcoll { -namespace coll { - -template -class coll_traits; - -/** - * Interface for all collections of tagged items. - * - * \note The point of a collection is to track the tags attached to items, and - * not to store the items themselves. This means that collections are not - * required to keep track of items with no tags. - */ -template -class ReadonlyCollection -{ - const Self& self() const { return *static_cast(this); } - - class CardinalityOrder - { - const Self& coll; - public: - CardinalityOrder(const Self& coll) : coll(coll) {} - bool operator()(const typename coll_traits::tag_type& t1, const typename coll_traits::tag_type& t2) - { - // Returns true if t1 precedes t2, and false otherwise - return coll.getCardinality(t1) < coll.getCardinality(t2); - } - }; - - class DiscriminanceOrder - { - const Self& coll; - public: - DiscriminanceOrder(const Self& coll) : coll(coll) {} - bool operator()(const typename coll_traits::tag_type& t1, const typename coll_traits::tag_type& t2) - { - // Returns true if t1 precedes t2, and false otherwise - return coll.getDiscriminance(t1) < coll.getDiscriminance(t2); - } - }; - - template - class RelevanceOrder - { - const COLL& first; - const Self& second; - public: - RelevanceOrder(const COLL& first, const Self& second) - : first(first), second(second) {} - bool operator()(const typename coll_traits::tag_type& t1, const typename coll_traits::tag_type& t2); - }; - - /** - * Get the items which are tagged with at least the tag `tag' - * - * \return - * The items found, or an empty set if no items have that tag - */ - //virtual std::set getItemsHavingTag(const TAG& tag) const = 0; - - /** - * Get the tags attached to an item. - * - * \param item - * The item to query - * \return - * The set of tags, or an empty set if the item has no tags or it does - * not exist. - */ - //virtual std::set getTagsOfItem(const ITEM& item) const = 0; - -public: - /** - * Check if the collection contains a tag - * - * \param tag - * The tag to look for - * \return - * true if the collection contains tag, false otherwise - */ - bool hasTag(const typename coll_traits::tag_type& tag) const; - - /** - * Get the tags of item `item'. Return an empty set if `item' does not exist - */ - //std::set getTags(const typename Self::item_type& item) const = 0; - - /** - * Get all the tags attached to the items in a set. - * - * \param items - * The items to query - * \return - * The set of tags, or an empty set if the items have no tags or do not - * exist. - */ - template - typename coll_traits::tagset_type getTagsOfItems(const ITEMS& items) const; - - /** - * Get the items with tag `tag'. Return an empty set if `tag' does not exist - */ - //std::set getItems(const TAG& tag) const { return getItemsHavingTag(tag); } - - /** - * Get the items which are tagged with at least the tags `tags' - * - * \return - * The items found, or an empty set if no items have that tag - */ - template - typename coll_traits::itemset_type getItemsHavingTags(const TAGS& tags) const; - - /** - * Get the set of all the items that have tags according to this collection - */ - //virtual std::set getTaggedItems() const = 0; - - /** - * Get the set of all the tags in this collection - */ - //virtual std::set getAllTags() const = 0; - - /** - * Get all the tags in the collectin, as a vector - */ - std::vector::tag_type> getAllTagsAsVector() const; - - /** - * Get the cardinality of tag `tag' (that is, the number of items who have it) - */ - unsigned int getCardinality(const typename coll_traits::tag_type& tag) const; - - /** - * Return the discriminance value for this tag, that is, the minimum number - * of packages that would be eliminated by selecting only those tagged with - * this tag or only those not tagged with this tag. - */ - unsigned int getDiscriminance(const typename coll_traits::tag_type& tag) const - { - return self().getCardinality(tag) < self().tagCount() - self().getCardinality(tag) ? - self().getCardinality(tag) : - self().tagCount() - self().getCardinality(tag); - } - - /** - * Get the set of all tags in this collection that appear in tagsets - * containing `tags' - * - * Example: - * \code - * void refineSelection(const std::set& selection) - * { - * std::set extraTags = collection.getCompanionTags(selection); - * tagMenu.setAvailableOptions(extraTags); - * } - * \endcode - */ - template - typename coll_traits::tagset_type getCompanionTags(const TAGS& tags) const; - - /** - * Get the related items at the given maximum distance - * - * Examples: - * \code - * // Get the items related to a given one, at the given distance - * std::set getRelated(const Item& item, int distance) - * { - * std::set res = collection.getRelatedItems(collection.getTags(item), distance); - * return res - item; - * } - * - * // Get the items related to the given ones, at the given distance - * std::set getRelated(const std::set& items, int distance) - * { - * std::set res = collection.getRelatedItems(collection.getTags(items), distance); - * return res - items; - * } - * - * // Get the related items, increasing the distance until it finds at - * // least 'minimum' items - * std::set getRelated(const Item& item, int minimum) - * { - * std::set tags = collection.getTags(item); - * std::set res; - * for (int i = 0; i < tags.size() && res.size() < minimum; i++) - * res += collection.getRelatedItems(tags, i); - * return res - item; - * } - * \endcode - */ - template - typename coll_traits::itemset_type getRelatedItems(const TAGS& tags, int maxdistance = 1) const; - - /** - * Output all the contents of the collection to an output iterator - */ - template - void output(OUT out) const; - - /** - * Send to a consumer all the items which are tagged with at least the - * given tags - */ - template - void outputHavingTags(const TAGS& tags, OUT out) const; - - /** - * Get a vector containing all tags in this collection, sorted by - * increasing cardinality - */ - std::vector::tag_type> tagsInCardinalityOrder() const; - - /** - * Get a vector containing all tags in this collection, sorted by - * increasing discriminance value (@see getDiscriminance) - */ - std::vector::tag_type> tagsInDiscriminanceOrder() const; - - /** - * Get a vector containing all tags in this collection, sorted by - * increasing relevance to the filtering applied between coll and this - * collection - */ - template - std::vector::tag_type> tagsInRelevanceOrder(const COLL& coll) const; -}; - - -/** - * Interface for all collections of tagged items. - * - * \note The point of a collection is to track the tags attached to items, and - * not to store the items themselves. This means that collections are not - * required to keep track of items with no tags. - */ -template -class Collection : public ReadonlyCollection -{ -//protected: - /* - * Implementation note: to avoid problems with classes implementing only - * some of the virtual methods, they are given different names. The common - * 'comsume' methods are just inlined calls to the right virtual functions, - * and are a way of keeping the unoverridden methods from being hidden. - */ - - //void consumeItemUntagged(const ITEM&) {} - //void consumeItemsUntagged(const std::set&) {} - -public: - //virtual ~Collection() {} - - /** - * Apply a patch to the collection - * - * Example: - * \code - * void perform(const PatchList& change) - * { - * collection.applyChange(change); - * undo.push_back(change.getReverse()); - * } - * \endcode - */ -// void applyChange( -// const PatchList< -// typename coll_traits::item_type, -// typename coll_traits::tag_type>& change); -}; - - -template -class Inserter : public wibble::mixin::OutputIterator< Inserter > -{ - COLL& coll; - -public: - Inserter(COLL& coll) : coll(coll) {} - - template - Inserter& operator=(const std::pair& data) - { - coll.insert(data.first, data.second); - return *this; - } -}; - -template -Inserter inserter(COLL& target) -{ - return Inserter(target); -} - -} -} - -// vim:set ts=4 sw=4: -#endif diff --git a/ept/debtags/coll/base.tcc b/ept/debtags/coll/base.tcc deleted file mode 100644 index 546a513..0000000 --- a/ept/debtags/coll/base.tcc +++ /dev/null @@ -1,191 +0,0 @@ -#ifndef TAGCOLL_COLL_BASE_TCC -#define TAGCOLL_COLL_BASE_TCC - -/** \file - * Base mixins for tagged collections - */ - -/* - * Copyright (C) 2003,2004,2005,2006 Enrico Zini - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include - -namespace tagcoll { -namespace coll { - -template -class coll_traits; - -template template -bool ReadonlyCollection::RelevanceOrder::operator()( - const typename coll_traits::tag_type& t1, - const typename coll_traits::tag_type& t2) -{ - // New cardinality divided by the square root of the old cardinality. - // The square root is used to downplay the very common tags a bit - int csub1 = second.getCardinality(t1); - float cfull1 = first.getCardinality(t1); - int csub2 = second.getCardinality(t2); - float cfull2 = first.getCardinality(t2); - float rel1 = (float)(csub1 * csub1) / cfull1; - float rel2 = (float)(csub2 * csub2) / cfull2; - - return rel1 < rel2; -// return 10000 * second.getCardinality(t1) / first.getCardinality(t1) -// < 10000 * second.getCardinality(t2) / first.getCardinality(t2); -} - - -template -bool ReadonlyCollection::hasTag(const typename coll_traits::tag_type& tag) const -{ - return !self().getItemsHavingTag(tag).empty(); -} - -template template -typename coll_traits::tagset_type ReadonlyCollection::getTagsOfItems(const ITEMS& items) const -{ - using namespace wibble::operators; - typename coll_traits::tagset_type res; - for (typename ITEMS::const_iterator i = items.begin(); - i != items.end(); i++) - res |= self().getTagsOfItem(*i); - return res; -} - -template template -typename coll_traits::itemset_type ReadonlyCollection::getItemsHavingTags(const TAGS& tags) const -{ - using namespace wibble::operators; - if (tags.empty()) - return typename coll_traits::itemset_type(); - - typename TAGS::const_iterator i = tags.begin(); - typename coll_traits::itemset_type res = self().getItemsHavingTag(*i); - - for (++i ; i != tags.end(); ++i) - res &= self().getItemsHavingTag(*i); - - return res; -} - -template -std::vector::tag_type> ReadonlyCollection::getAllTagsAsVector() const -{ - std::set::tag_type> asSet = self().getAllTags(); - std::vector::tag_type> res; - res.reserve(asSet.size()); - std::copy(asSet.begin(), asSet.end(), back_inserter(res)); - return res; -} - -template -unsigned int ReadonlyCollection::getCardinality(const typename coll_traits::tag_type& tag) const -{ - return self().getItemsHavingTag(tag).size(); -} - -template template -typename coll_traits::tagset_type ReadonlyCollection::getCompanionTags(const TAGS& tags) const -{ - using namespace wibble::operators; - return self().getTagsOfItems(self().getItemsHavingTags(tags)) - tags; -} - -template template -typename coll_traits::itemset_type ReadonlyCollection::getRelatedItems(const TAGS& tags, int maxdistance) const -{ - using namespace wibble::operators; - - typename coll_traits::itemset_type packages; - typename coll_traits::itemset_type res; - - // First get a list of packages that have a non-empty intersection with `tags' - for (typename TAGS::const_iterator i = tags.begin(); i != tags.end(); i++) - packages |= self().getItemsHavingTag(*i); - - // Then keep only those within the given distance - for (typename coll_traits::itemset_type::const_iterator i = packages.begin(); i != packages.end(); i++) - { - int dist = utils::set_distance(tags, self().getTagsOfItem(*i)); - if (dist >= 0 && dist <= maxdistance) - res |= *i; - } - - return res; -} - -template template -void ReadonlyCollection::output(OUT out) const -{ - for (typename Self::const_iterator i = self().begin(); - i != self().end(); ++i) - { - *out = make_pair(wibble::singleton(i->first), i->second); - ++out; - } -} - -template template -void ReadonlyCollection::outputHavingTags(const TAGS& tags, OUT out) const -{ - typename coll_traits::itemset_type items = self().getItemsHavingTags(tags); - for (typename coll_traits::itemset_type::const_iterator i = items.begin(); - i != items.end(); ++i) - { - *out = std::make_pair(wibble::singleton(*i), self().getTagsOfItem(*i)); - ++out; - } -} - -template -std::vector::tag_type> ReadonlyCollection::tagsInCardinalityOrder() const -{ - std::vector::tag_type> res = self().getAllTagsAsVector(); - std::sort(res.begin(), res.end(), CardinalityOrder(self())); - return res; -} - -template -std::vector::tag_type> ReadonlyCollection::tagsInDiscriminanceOrder() const -{ - std::vector::tag_type> res = self().getAllTagsAsVector(); - std::sort(res.begin(), res.end(), DiscriminanceOrder(self())); - return res; -} - -/** - * Get a vector containing all tags in this collection, sorted by - * increasing relevance to the filtering applied between coll and this - * collection - */ -template template -std::vector::tag_type> ReadonlyCollection::tagsInRelevanceOrder(const COLL& coll) const -{ - std::vector::tag_type> res = self().getAllTagsAsVector(); - std::sort(res.begin(), res.end(), RelevanceOrder(coll, self())); - return res; -} - -} -} - -// vim:set ts=4 sw=4: -#endif diff --git a/ept/debtags/coll/fast.cc b/ept/debtags/coll/fast.cc new file mode 100644 index 0000000..9032bf6 --- /dev/null +++ b/ept/debtags/coll/fast.cc @@ -0,0 +1,254 @@ +/* + * Fast index for tag data + * + * Copyright (C) 2005,2006 Enrico Zini + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +using namespace std; +using namespace wibble::operators; + +namespace ept { +namespace debtags { +namespace coll { + +void Fast::insert(const std::set& items, const std::set& tags) +{ + using namespace wibble::operators; + + if (tags.empty()) + return; + + for (const auto& i: items) + insert(i, tags); +} + +void Fast::insert(const std::string& item, const std::set& tags) +{ + using namespace wibble::operators; + + if (tags.empty()) + return; + + auto iter = this->items.find(item); + if (iter == this->items.end()) + this->items.insert(std::make_pair(item, tags)); + else + iter->second |= tags; + + for (typename std::set::const_iterator i = tags.begin(); + i != tags.end(); ++i) + { + typename std::map< std::string, std::set >::iterator iter = this->tags.find(*i); + if (iter == this->tags.end()) + this->tags.insert(std::make_pair(*i, std::set() | item)); + else + iter->second |= item; + } +} + +void Fast::insert(const std::set& items, const std::string& tag) +{ + using namespace wibble::operators; + + for (typename std::set::const_iterator i = items.begin(); + i != items.end(); ++i) + { + typename std::map< std::string, std::set >::iterator iter = this->items.find(*i); + if (iter == this->items.end()) + this->items.insert(std::make_pair(*i, std::set() | tag)); + else + iter->second |= tag; + } + + typename std::map< std::string, std::set >::iterator iter = this->tags.find(tag); + if (iter == this->tags.end()) + this->tags.insert(std::make_pair(tag, items)); + else + iter->second |= items; +} + +std::set Fast::getItemsHavingTag(const std::string& tag) const +{ + typename map >::const_iterator i = tags.find(tag); + if (i != tags.end()) + return i->second; + else + return std::set(); +} + +std::set Fast::getItemsHavingTags(const std::set& tags) const +{ + using namespace wibble::operators; + if (tags.empty()) + return std::set(); + + auto i = tags.begin(); + auto res = getItemsHavingTag(*i); + + for (++i ; i != tags.end(); ++i) + res &= getItemsHavingTag(*i); + + return res; +} + + +std::set Fast::getTagsOfItem(const std::string& item) const +{ + typename map >::const_iterator i = items.find(item); + if (i != items.end()) + return i->second; + else + return std::set(); +} + +std::set Fast::getTaggedItems() const +{ + std::set res; + for (typename map >::const_iterator i = items.begin(); + i != items.end(); i++) + res |= i->first; + return res; +} + +std::set Fast::getAllTags() const +{ + std::set res; + for (typename map >::const_iterator i = tags.begin(); + i != tags.end(); i++) + res |= i->first; + return res; +} + +std::vector Fast::getAllTagsAsVector() const +{ + std::vector res; + for (typename map >::const_iterator i = tags.begin(); + i != tags.end(); i++) + res.push_back(i->first); + return res; +} + +std::set Fast::getTagsImplying(const std::string& tag) const +{ + // tag1 implies tag2 if the itemset of tag1 is a subset of the itemset of tag2 + std::set res; + std::set itemsToCheck = getItemsHavingTag(tag); + // TODO: choose which one is the most efficient implementation +#if 0 + // Roughly: + // O(n[pkgs per tag] * log(nitems) * log(n[items per pkg]) + n[tags per item] * n[items per tag]) + std::set tagsToCheck; + for (std::set::const_iterator i = itemsToCheck.begin(); + i != itemsToCheck.end(); ++i) + tagsToCheck |= getTags(*i); + for (std::set::const_iterator i = tagsToCheck.begin(); + i != tagsToCheck.end(); ++i) + if (utils::set_contains(itemsToCheck, getItems(*i))) + res |= *i; +#else + // O(ntags * n[items per tag]) + for (typename std::map >::const_iterator i = tags.begin(); + i != tags.end(); ++i) + if (utils::set_contains(itemsToCheck, getItemsHavingTag(i->first))) + res |= i->first; +#endif + return res - tag; +} + +std::set Fast::getItemsExactMatch(const std::set& tags) const +{ + std::set res = this->getItemsHavingTags(tags); + typename std::set::iterator i = res.begin(); + while (i != res.end()) + { + typename std::map >::const_iterator t = items.find(*i); + if (t != items.end() && t->second != tags) + { + typename std::set::iterator j = i; + ++i; + res.erase(j); + } else + ++i; + } + return res; +} + +std::string Fast::findTagWithMaxCardinality(size_t& card) const +{ + card = 0; + std::string res = std::string(); + for (typename std::map >::const_iterator i = tags.begin(); + i != tags.end(); ++i) + if (i->second.size() > card) + { + card = i->second.size(); + res = i->first; + } + return res; +} + +void Fast::removeTag(const std::string& tag) +{ + typename std::map >::iterator itag = tags.find(tag); + for (typename std::set::const_iterator iitemset = itag->second.begin(); + iitemset != itag->second.end(); ++iitemset) + { + typename std::map >::iterator iitem = items.find(*iitemset); + iitem->second -= tag; + if (iitem->second.empty()) + items.erase(iitem); + } + tags.erase(itag); +} + +Fast Fast::getChildCollection(const std::string& tag) const +{ + Fast res; + + auto itag = tags.find(tag); + for (const auto& i: itag->second) + { + auto iitem = items.find(i); + res.insert(i, iitem->second); + } + + res.removeTag(tag); + return res; +} + +void Fast::removeTagsWithCardinalityLessThan(size_t card) +{ + typename std::map >::const_iterator i = tags.begin(); + while (i != tags.end()) + { + if (i->second.size() < card) + { + typename std::map >::const_iterator j = i; + ++i; + removeTag(j->first); + } else + ++i; + } +} + +} +} +} diff --git a/ept/debtags/coll/fast.h b/ept/debtags/coll/fast.h index 7a4c2b8..747cefc 100644 --- a/ept/debtags/coll/fast.h +++ b/ept/debtags/coll/fast.h @@ -1,5 +1,5 @@ -#ifndef TAGCOLL_COLL_FAST_H -#define TAGCOLL_COLL_FAST_H +#ifndef EPT_DEBTAGS_COLL_FAST_H +#define EPT_DEBTAGS_COLL_FAST_H /** \file * Fast index for tag data @@ -23,51 +23,38 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include #include #include +#include +#include -namespace tagcoll { - +namespace ept { +namespace debtags { namespace coll { -template -class Fast; - -template -struct coll_traits< Fast > -{ - typedef ITEM item_type; - typedef TAG tag_type; - typedef std::set itemset_type; - typedef std::set tagset_type; -}; /** * In-memory collection with both item->tags and tag->items mappings. */ -template -class Fast : public coll::Collection< Fast > +class Fast { protected: - std::map > items; - std::map > tags; + std::map> items; + std::map> tags; #if 0 - virtual void consumeItem(const ITEM& item, const std::set& tags); - virtual void consumeItems(const std::set& items, const std::set& tags); + virtual void consumeItem(const std::string& item, const std::set& tags); + virtual void consumeItems(const std::set& items, const std::set& tags); - virtual std::set getItemsHavingTag(const TAG& tag) const; - virtual std::set getTagsOfItem(const ITEM& item) const; + virtual std::set getItemsHavingTag(const std::string& tag) const; + virtual std::set getTagsOfItem(const std::string& item) const; #endif public: - typedef typename std::map< ITEM, std::set >::const_iterator const_iterator; - typedef typename std::map< ITEM, std::set >::iterator iterator; - typedef typename std::map< ITEM, std::set >::value_type value_type; - - typedef typename std::map< TAG, std::set >::const_iterator const_tag_iterator; - typedef typename std::map< TAG, std::set >::iterator tag_iterator; + typedef std::map>::const_iterator const_iterator; + typedef std::map>::iterator iterator; + typedef std::map>::value_type value_type; + typedef std::map>::const_iterator const_tag_iterator; + typedef std::map>::iterator tag_iterator; const_iterator begin() const { return items.begin(); } const_iterator end() const { return items.end(); } @@ -79,60 +66,58 @@ public: tag_iterator tagBegin() { return tags.begin(); } tag_iterator tagEnd() { return tags.end(); } - template - void insert(const ITEMS& items, const TAGS& tags); - - void insert(const wibble::Singleton& item, const std::set& tags); - - void insert(const std::set& items, const wibble::Singleton& tag); + void insert(const std::string& item, const std::set& tags); + void insert(const std::set& items, const std::string& tag); + void insert(const std::set& items, const std::set& tags); void clear() { items.clear(); tags.clear(); } - std::set getTagsOfItem(const ITEM& item) const; - std::set getItemsHavingTag(const TAG& tag) const; + std::set getTagsOfItem(const std::string& item) const; + std::set getItemsHavingTag(const std::string& tag) const; + + /** + * Get the items which are tagged with at least the tags `tags' + * + * \return + * The items found, or an empty set if no items have that tag + */ + std::set getItemsHavingTags(const std::set& tags) const; bool empty() const { return items.empty(); } - bool hasItem(const ITEM& item) const { return items.find(item) != items.end(); } - bool hasTag(const TAG& tag) const { return tags.find(tag) != tags.end(); } - std::set getTaggedItems() const; - std::set getAllTags() const; - std::vector getAllTagsAsVector() const; + bool hasItem(const std::string& item) const { return items.find(item) != items.end(); } + bool hasTag(const std::string& tag) const { return tags.find(tag) != tags.end(); } + std::set getTaggedItems() const; + std::set getAllTags() const; + std::vector getAllTagsAsVector() const; unsigned int itemCount() const { return items.size(); } unsigned int tagCount() const { return tags.size(); } - /** - * Output all the contents of the reversed collection to an output iterator - */ - template - void outputReversed(OUT out) const; - #if 0 - void output(Consumer& consumer) const; + void output(Consumer& consumer) const; #endif // tag1 implies tag2 if the itemset of tag1 is a subset of the itemset of // tag2 - std::set getTagsImplying(const TAG& tag) const; + std::set getTagsImplying(const std::string& tag) const; // Return the items which have the exact tagset 'tags' - std::set getItemsExactMatch(const std::set& tags) const; + std::set getItemsExactMatch(const std::set& tags) const; - TAG findTagWithMaxCardinality(size_t& card) const; + std::string findTagWithMaxCardinality(size_t& card) const; /** * Return the collection with only those items that have this tag, but with * the given tag removed */ - Fast getChildCollection(const TAG& tag) const; + Fast getChildCollection(const std::string& tag) const; - void removeTag(const TAG& tag); + void removeTag(const std::string& tag); void removeTagsWithCardinalityLessThan(size_t card); }; } } - -// vim:set ts=4 sw=4: +} #endif diff --git a/ept/debtags/coll/fast.tcc b/ept/debtags/coll/fast.tcc deleted file mode 100644 index c8731c0..0000000 --- a/ept/debtags/coll/fast.tcc +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Fast index for tag data - * - * Copyright (C) 2005,2006 Enrico Zini - * - * This program 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 2 of the License, or - * (at your option) any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TAGCOLL_COLL_FAST_TCC -#define TAGCOLL_COLL_FAST_TCC - -#include -#include - -#include - -using namespace std; -using namespace wibble::operators; - -namespace tagcoll { -namespace coll { - -template template -void Fast::insert(const ITEMS& items, const TAGS& tags) -{ - using namespace wibble::operators; - - if (tags.empty()) - return; - - for (typename ITEMS::const_iterator i = items.begin(); - i != items.end(); ++i) - { - typename std::map< ITEM, std::set >::iterator iter = this->items.find(*i); - if (iter == this->items.end()) - this->items.insert(std::make_pair(*i, std::set() | tags)); - else - iter->second |= tags; - } - - for (typename TAGS::const_iterator i = tags.begin(); - i != tags.end(); ++i) - { - typename std::map< TAG, std::set >::iterator iter = this->tags.find(*i); - if (iter == this->tags.end()) - this->tags.insert(std::make_pair(*i, std::set() | items)); - else - iter->second |= items; - } -} - -template -void Fast::insert(const wibble::Singleton& item, const std::set& tags) -{ - using namespace wibble::operators; - - if (tags.empty()) - return; - - typename std::map< ITEM, std::set >::iterator iter = this->items.find(*item.begin()); - if (iter == this->items.end()) - this->items.insert(std::make_pair(*item.begin(), tags)); - else - iter->second |= tags; - - for (typename std::set::const_iterator i = tags.begin(); - i != tags.end(); ++i) - { - typename std::map< TAG, std::set >::iterator iter = this->tags.find(*i); - if (iter == this->tags.end()) - this->tags.insert(std::make_pair(*i, std::set() | *item.begin())); - else - iter->second |= *item.begin(); - } -} - -template -void Fast::insert(const std::set& items, const wibble::Singleton& tag) -{ - using namespace wibble::operators; - - for (typename std::set::const_iterator i = items.begin(); - i != items.end(); ++i) - { - typename std::map< ITEM, std::set >::iterator iter = this->items.find(*i); - if (iter == this->items.end()) - this->items.insert(std::make_pair(*i, std::set() | *tag.begin())); - else - iter->second |= *tag.begin(); - } - - typename std::map< TAG, std::set >::iterator iter = this->tags.find(*tag.begin()); - if (iter == this->tags.end()) - this->tags.insert(std::make_pair(*tag.begin(), items)); - else - iter->second |= items; -} - -template -std::set Fast::getItemsHavingTag(const TAG& tag) const -{ - typename map >::const_iterator i = tags.find(tag); - if (i != tags.end()) - return i->second; - else - return std::set(); -} - -template -std::set Fast::getTagsOfItem(const ITEM& item) const -{ - typename map >::const_iterator i = items.find(item); - if (i != items.end()) - return i->second; - else - return std::set(); -} - -template -std::set Fast::getTaggedItems() const -{ - std::set res; - for (typename map >::const_iterator i = items.begin(); - i != items.end(); i++) - res |= i->first; - return res; -} - -template -std::set Fast::getAllTags() const -{ - std::set res; - for (typename map >::const_iterator i = tags.begin(); - i != tags.end(); i++) - res |= i->first; - return res; -} - -template -std::vector Fast::getAllTagsAsVector() const -{ - std::vector res; - for (typename map >::const_iterator i = tags.begin(); - i != tags.end(); i++) - res.push_back(i->first); - return res; -} - -#if 0 -template -void Fast::output(Consumer& consumer) const -{ - for (typename map >::const_iterator i = items.begin(); - i != items.end(); i++) - consumer.consume(i->first, i->second); -} -#endif - -template template -void Fast::outputReversed(OUT out) const -{ - for (typename std::map >::const_iterator i = tags.begin(); - i != tags.end(); ++i) - { - *out = make_pair(wibble::singleton(i->first), i->second); - ++out; - } -} - - -template -std::set Fast::getTagsImplying(const TAG& tag) const -{ - // tag1 implies tag2 if the itemset of tag1 is a subset of the itemset of tag2 - std::set res; - std::set itemsToCheck = getItemsHavingTag(tag); - // TODO: choose which one is the most efficient implementation -#if 0 - // Roughly: - // O(n[pkgs per tag] * log(nitems) * log(n[items per pkg]) + n[tags per item] * n[items per tag]) - std::set tagsToCheck; - for (std::set::const_iterator i = itemsToCheck.begin(); - i != itemsToCheck.end(); ++i) - tagsToCheck |= getTags(*i); - for (std::set::const_iterator i = tagsToCheck.begin(); - i != tagsToCheck.end(); ++i) - if (utils::set_contains(itemsToCheck, getItems(*i))) - res |= *i; -#else - // O(ntags * n[items per tag]) - for (typename std::map >::const_iterator i = tags.begin(); - i != tags.end(); ++i) - if (utils::set_contains(itemsToCheck, getItemsHavingTag(i->first))) - res |= i->first; -#endif - return res - tag; -} - -template -std::set Fast::getItemsExactMatch(const std::set& tags) const -{ - std::set res = this->getItemsHavingTags(tags); - typename std::set::iterator i = res.begin(); - while (i != res.end()) - { - typename std::map >::const_iterator t = items.find(*i); - if (t != items.end() && t->second != tags) - { - typename std::set::iterator j = i; - ++i; - res.erase(j); - } else - ++i; - } - return res; -} - -template -TAG Fast::findTagWithMaxCardinality(size_t& card) const -{ - card = 0; - TAG res = TAG(); - for (typename std::map >::const_iterator i = tags.begin(); - i != tags.end(); ++i) - if (i->second.size() > card) - { - card = i->second.size(); - res = i->first; - } - return res; -} - -template -void Fast::removeTag(const TAG& tag) -{ - typename std::map >::iterator itag = tags.find(tag); - for (typename std::set::const_iterator iitemset = itag->second.begin(); - iitemset != itag->second.end(); ++iitemset) - { - typename std::map >::iterator iitem = items.find(*iitemset); - iitem->second -= tag; - if (iitem->second.empty()) - items.erase(iitem); - } - tags.erase(itag); -} - -template -Fast Fast::getChildCollection(const TAG& tag) const -{ - Fast res; - - typename std::map >::const_iterator itag = tags.find(tag); - for (typename std::set::const_iterator i = itag->second.begin(); - i != itag->second.end(); ++i) - { - typename std::map >::const_iterator iitem = items.find(*i); - res.insert(wibble::singleton(*i), iitem->second); - } - - res.removeTag(tag); - return res; -} - -template -void Fast::removeTagsWithCardinalityLessThan(size_t card) -{ - typename std::map >::const_iterator i = tags.begin(); - while (i != tags.end()) - { - if (i->second.size() < card) - { - typename std::map >::const_iterator j = i; - ++i; - removeTag(j->first); - } else - ++i; - } -} - - -#if 0 -template -void Fast::consumeItem(const ITEM& item, const std::set& tags) -{ - // Add the tags to the item - items[item] |= tags; - - // Add the item to the tags - for (typename std::set::const_iterator i = tags.begin(); i != tags.end(); i++) - this->tags[*i] |= item; -} - -template -void Fast::consumeItems(const std::set& items, const std::set& tags) -{ - for (typename std::set::const_iterator i = items.begin(); i != items.end(); i++) - // Add the tags to the item - this->items[*i] |= tags; - - for (typename std::set::const_iterator i = tags.begin(); i != tags.end(); i++) - // Add the items to the tag - this->tags[*i] |= items; -} -#endif - -} -} - -#include - -#endif - -// vim:set ts=4 sw=4: diff --git a/ept/debtags/coll/set.h b/ept/debtags/coll/set.h index f78116f..cabd939 100644 --- a/ept/debtags/coll/set.h +++ b/ept/debtags/coll/set.h @@ -26,7 +26,9 @@ #include #include -namespace tagcoll { +namespace ept { +namespace debtags { +namespace coll { namespace utils { template @@ -81,8 +83,9 @@ bool set_contains(const std::set& set1, const T& item) return set1.find(item) != set1.end(); } +} +} } } -// vim:set ts=4 sw=4: #endif diff --git a/ept/debtags/debtags-test.cc b/ept/debtags/debtags-test.cc index 3a8fca5..c03d3a2 100644 --- a/ept/debtags/debtags-test.cc +++ b/ept/debtags/debtags-test.cc @@ -3,7 +3,6 @@ #include #include -using namespace tagcoll; using namespace std; using namespace ept; using namespace ept::debtags; diff --git a/ept/debtags/debtags.cc b/ept/debtags/debtags.cc index b800c77..2fde09b 100644 --- a/ept/debtags/debtags.cc +++ b/ept/debtags/debtags.cc @@ -24,26 +24,18 @@ */ #include - -//#include -//#include #include "coll/TextFormat.h" - #include #include - #include #include #include - #include // WIFEXITED WEXITSTATUS #include // getpwuid, getuid #include // getpwuid #include // getuid - using namespace std; -using namespace tagcoll; using namespace wibble; namespace ept { @@ -73,7 +65,7 @@ void Debtags::load(const std::string& pathname) // Read the collection try { - tagcoll::textformat::parse(in, pathname, inserter(*this)); + coll::textformat::parse(in, pathname, *this); } catch (...) { fclose(in); throw; @@ -93,11 +85,3 @@ string Debtags::pathname() } } - -#include "coll/fast.tcc" -#include "coll/TextFormat.tcc" - -// Explicit template instantiations for our stuff -template class tagcoll::coll::Fast; - -// vim:set ts=4 sw=4: diff --git a/ept/debtags/debtags.h b/ept/debtags/debtags.h index a23b209..52d9347 100644 --- a/ept/debtags/debtags.h +++ b/ept/debtags/debtags.h @@ -26,16 +26,9 @@ #ifndef EPT_DEBTAGS_DEBTAGS_H #define EPT_DEBTAGS_DEBTAGS_H -#include #include #include -namespace ept { -namespace debtags { -class Debtags; -} -} - namespace ept { namespace debtags { @@ -51,7 +44,7 @@ namespace debtags { * It is possible to get a reference to the Vocabulary object using the * vocabulary() method. */ -class Debtags : public tagcoll::coll::Fast +class Debtags : public coll::Fast { protected: // User rc directory to store patches @@ -63,8 +56,8 @@ protected: void load(const std::string& pathname); public: - typedef tagcoll::coll::Fast coll_type; - typedef std::pair< std::string, std::set > value_type; + typedef ept::debtags::coll::Fast coll_type; + typedef std::pair< std::string, std::set > value_type; /// Create a Debtags object, reading the system database Debtags(); @@ -90,7 +83,6 @@ public: static std::string pathname(); }; - } } diff --git a/ept/debtags/vocabulary-test.cc b/ept/debtags/vocabulary-test.cc index 51f46f9..682e521 100644 --- a/ept/debtags/vocabulary-test.cc +++ b/ept/debtags/vocabulary-test.cc @@ -4,7 +4,7 @@ #include "ept/test.h" using namespace std; -using namespace tagcoll::utils; +using namespace ept::debtags::coll::utils; using namespace ept::debtags; using namespace ept::tests; -- cgit v1.2.3 From 40b6b11a49e9bd6e13261ed1471371cd497d4baf Mon Sep 17 00:00:00 2001 From: Enrico Zini Date: Thu, 10 Sep 2015 15:27:15 +0200 Subject: Also distribute debtags/coll headers --- ept/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'ept/CMakeLists.txt') diff --git a/ept/CMakeLists.txt b/ept/CMakeLists.txt index f5874bf..079cd95 100644 --- a/ept/CMakeLists.txt +++ b/ept/CMakeLists.txt @@ -10,6 +10,7 @@ file( GLOB h_top *.h ) file( GLOB h_apt apt/*.h ) file( GLOB h_debtags debtags/*.h ) file( GLOB h_debtags_maint debtags/maint/*.h ) +file( GLOB h_debtags_coll debtags/coll/*.h ) file( GLOB h_axi axi/*.h ) file( GLOB h_utils utils/*.h ) @@ -56,5 +57,6 @@ install( FILES ${h_top} DESTINATION include/ept ) install( FILES ${h_apt} DESTINATION include/ept/apt ) install( FILES ${h_debtags} DESTINATION include/ept/debtags ) install( FILES ${h_debtags_maint} DESTINATION include/ept/debtags/maint ) +install( FILES ${h_debtags_coll} DESTINATION include/ept/debtags/coll ) install( FILES ${h_axi} DESTINATION include/ept/axi ) install( FILES ${h_utils} DESTINATION include/ept/utils ) -- cgit v1.2.3