diff options
| author | Dan Goodliffe <dan@randomdan.homeip.net> | 2020-08-31 19:52:11 +0100 | 
|---|---|---|
| committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2020-09-05 17:30:07 +0100 | 
| commit | fc6e9a3316b608b30b5a25b347774181f1730c59 (patch) | |
| tree | 67c74913d0d199dc6c366de8c05bfa91e4d452bc | |
| parent | Clang format all the code (diff) | |
| download | netfs-fc6e9a3316b608b30b5a25b347774181f1730c59.tar.bz2 netfs-fc6e9a3316b608b30b5a25b347774181f1730c59.tar.xz netfs-fc6e9a3316b608b30b5a25b347774181f1730c59.zip  | |
First cut extensible mapper
Replaces the weird fallback half implementation with something that looks
remotely fit for purpose.
| -rw-r--r-- | netfs/daemon/daemonVolume.cpp | 4 | ||||
| -rw-r--r-- | netfs/fuse/Jamfile.jam | 4 | ||||
| -rw-r--r-- | netfs/fuse/fuseApp.cpp | 16 | ||||
| -rw-r--r-- | netfs/fuse/fuseApp.h | 2 | ||||
| -rw-r--r-- | netfs/fuse/fuseConfig.ice | 3 | ||||
| -rw-r--r-- | netfs/ice/Jamfile.jam | 6 | ||||
| -rw-r--r-- | netfs/ice/entryResolver.h | 20 | ||||
| -rw-r--r-- | netfs/ice/mapper.ice | 31 | ||||
| -rw-r--r-- | netfs/ice/typeConverter.cpp | 16 | ||||
| -rw-r--r-- | netfs/ice/typeConverter.h | 11 | ||||
| -rw-r--r-- | netfs/lib/defaultMapper.cpp | 26 | ||||
| -rw-r--r-- | netfs/lib/defaultMapper.h | 21 | ||||
| -rw-r--r-- | netfs/lib/entCache.h | 31 | ||||
| -rw-r--r-- | netfs/lib/entCache.impl.h | 70 | ||||
| -rw-r--r-- | netfs/lib/entryResolver.h | 14 | ||||
| -rw-r--r-- | netfs/unittests/Jamfile.jam | 2 | ||||
| -rw-r--r-- | netfs/unittests/testLib.cpp | 62 | 
17 files changed, 157 insertions, 182 deletions
diff --git a/netfs/daemon/daemonVolume.cpp b/netfs/daemon/daemonVolume.cpp index 3ae43da..7ae3a1f 100644 --- a/netfs/daemon/daemonVolume.cpp +++ b/netfs/daemon/daemonVolume.cpp @@ -7,6 +7,7 @@  #include <boost/algorithm/string/predicate.hpp>  #include <cerrno>  #include <climits> +#include <defaultMapper.h>  #include <entCache.h>  #include <fcntl.h>  #include <map> @@ -16,7 +17,8 @@  extern std::map<Ice::Int, int> files;  VolumeServer::VolumeServer(const std::filesystem::path & r, const EntCache<User> & u, const EntCache<Group> & g) : -	root(std::filesystem::canonical(r)), userLookup(u), groupLookup(g), converter(u, g) +	root(std::filesystem::canonical(r)), userLookup(u), groupLookup(g), +	converter(std::make_shared<NetFS::Mapping::DefaultMapper>())  {  } diff --git a/netfs/fuse/Jamfile.jam b/netfs/fuse/Jamfile.jam index 14338d5..8516d8b 100644 --- a/netfs/fuse/Jamfile.jam +++ b/netfs/fuse/Jamfile.jam @@ -6,6 +6,8 @@ obj fuseConfig : fuseConfig.ice :  	<toolset>tidy:<checker>none  	<library>../ice//netfs-api  	<implicit-dependency>../ice//netfs-api +	<library>..//slicer +	<include>.  ;  lib netfs-client-configuration :  	fuseConfig @@ -19,9 +21,11 @@ lib netfs-client-configuration :  	<library>..//Ice  	<library>..//slicer  	<library>..//adhocutil +	<include>.  	: :  	<library>..//Ice  	<library>..//slicer +	<include>.  	;  lib netfs-client : diff --git a/netfs/fuse/fuseApp.cpp b/netfs/fuse/fuseApp.cpp index 78a3a03..f0576b3 100644 --- a/netfs/fuse/fuseApp.cpp +++ b/netfs/fuse/fuseApp.cpp @@ -7,6 +7,7 @@  #include <boost/lexical_cast.hpp>  #include <compileTimeFormatter.h>  #include <cstring> +#include <defaultMapper.h>  #include <entCache.h>  #include <safeMapFind.h>  #include <slicer/slicer.h> @@ -17,10 +18,7 @@ namespace AdHoc {  	template class CallCacheable<struct stat, std::string>;  } -NetFS::FuseApp::FuseApp(Ice::StringSeq && a) : -	iceArgs(std::move(a)), sessionOpened(false), openHandleId(0), converter(userLookup, groupLookup) -{ -} +NetFS::FuseApp::FuseApp(Ice::StringSeq && a) : iceArgs(std::move(a)), sessionOpened(false), openHandleId(0) { }  NetFS::FuseApp::~FuseApp()  { @@ -80,7 +78,11 @@ NetFS::FuseApp::init(struct fuse_conn_info *, struct fuse_config *)  			fcr = configureFromFile(arg.substr(0, colon), arg.substr(colon + 1));  		}  	} +	if (!fcr->mapper) { +		fcr->mapper = std::make_shared<Mapping::DefaultMapper>(); +	}  	BOOST_ASSERT(fcr); +	converter.mapper = fcr->mapper;  	return this;  } @@ -275,8 +277,6 @@ NetFS::ReqEnv  NetFS::FuseApp::reqEnv()  {  	struct fuse_context * c = fuse_get_context(); -	NetFS::ReqEnv re; -	userLookup.getName(c->uid, &re.user); -	groupLookup.getName(c->gid, &re.grp); -	return re; +	const auto t = converter.mapper->mapFileSystem(c->uid, c->gid); +	return {t.username, t.groupname};  } diff --git a/netfs/fuse/fuseApp.h b/netfs/fuse/fuseApp.h index d373e94..b905b23 100644 --- a/netfs/fuse/fuseApp.h +++ b/netfs/fuse/fuseApp.h @@ -111,8 +111,6 @@ namespace NetFS {  		OpenFiles openFiles;  		int openHandleId; -		EntCache<User> userLookup; -		EntCache<Group> groupLookup;  		EntryTypeConverter converter;  		using StatCache = AdHoc::Cache<struct stat, std::string>; diff --git a/netfs/fuse/fuseConfig.ice b/netfs/fuse/fuseConfig.ice index 52116ea..2d2bf9f 100644 --- a/netfs/fuse/fuseConfig.ice +++ b/netfs/fuse/fuseConfig.ice @@ -1,4 +1,5 @@  #include <exceptions.ice> +#include <mapper.ice>  module NetFS {  	module Client { @@ -20,6 +21,8 @@ module NetFS {  			["slicer:name:async"]  			bool Async = false; + +			Mapping::Mapper mapper;  		};  		["slicer:key:name","slicer:value:resource","slicer:item:resource"] diff --git a/netfs/ice/Jamfile.jam b/netfs/ice/Jamfile.jam index cfb4f14..a695712 100644 --- a/netfs/ice/Jamfile.jam +++ b/netfs/ice/Jamfile.jam @@ -6,14 +6,18 @@ obj file : file.ice : <toolset>tidy:<checker>none ;  obj service : service.ice : <toolset>tidy:<checker>none ;  obj types : types.ice : <toolset>tidy:<checker>none ;  obj volume : volume.ice : <toolset>tidy:<checker>none ; -alias gen : directory exceptions file service types volume ; +obj mapper : mapper.ice : <toolset>tidy:<checker>none ; +alias gen : directory exceptions file service types volume mapper ;  lib netfs-api :  	gen +	mapper.ice  	[ glob *.cpp ] :  	<library>..//Ice  	<library>..//pthread  	<library>..//adhocutil +	<library>..//slicer  	<implicit-dependency>gen +	<slicer>pure  	: :  	<include>.  	<library>..//Ice diff --git a/netfs/ice/entryResolver.h b/netfs/ice/entryResolver.h deleted file mode 100644 index 973af4c..0000000 --- a/netfs/ice/entryResolver.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef NETFS_ENTRYRESOLVER_H -#define NETFS_ENTRYRESOLVER_H - -#include <cstdint> -#include <unistd.h> - -enum class ResolvedAs : uint8_t { -	Real, -	Fallback, -}; - -template<typename id_t, typename name_t> class EntryResolver { -public: -	virtual ~EntryResolver() = default; - -	virtual ResolvedAs getID(const name_t &, id_t *) const = 0; -	virtual ResolvedAs getName(const id_t &, name_t *) const = 0; -}; - -#endif diff --git a/netfs/ice/mapper.ice b/netfs/ice/mapper.ice new file mode 100644 index 0000000..d2f31e8 --- /dev/null +++ b/netfs/ice/mapper.ice @@ -0,0 +1,31 @@ +#ifndef _MAPPER +#define _MAPPER + +#include "exceptions.ice" + +module NetFS { +	module Mapping { +		["slicer:ignore"] +		local struct Transport { +			string username; +			string groupname; +			int mask; +		}; + +		["slicer:ignore"] +		local struct FileSystem { +			int uid; +			int gid; +			int mask; +		}; + +		local class Mapper { +			Transport mapFileSystem(int uid, int gid) throws SystemError; +			FileSystem mapTransport(string un, string gn) throws SystemError; +		}; +	}; + +} + +#endif + diff --git a/netfs/ice/typeConverter.cpp b/netfs/ice/typeConverter.cpp index e365c5d..6b33828 100644 --- a/netfs/ice/typeConverter.cpp +++ b/netfs/ice/typeConverter.cpp @@ -1,7 +1,7 @@  #include "typeConverter.h"  #include <boost/numeric/conversion/cast.hpp> -EntryTypeConverter::EntryTypeConverter(const UserLookup & u, const GroupLookup & g) : userLookup(u), groupLookup(g) { } +EntryTypeConverter::EntryTypeConverter(NetFS::Mapping::MapperPtr m) : mapper(m) { }  // Wrapper function to assure no unexpected corruption occurs  // during narrowing assignments. @@ -16,14 +16,15 @@ safeAssign(T & t, const S & s)  struct stat  EntryTypeConverter::convert(const NetFS::Attr & a) const  { +	auto map = mapper->mapTransport(a.uid, a.gid);  	struct stat s {  	};  	s.st_dev = a.dev;  	s.st_ino = a.inode; -	s.st_mode = a.mode; +	s.st_mode = a.mode & ~map.mask;  	s.st_nlink = a.links; -	userLookup.getID(a.uid, &s.st_uid); -	groupLookup.getID(a.gid, &s.st_gid); +	s.st_uid = map.uid; +	s.st_gid = map.gid;  	s.st_rdev = a.rdev;  	s.st_size = a.size;  	s.st_blksize = a.blockSize; @@ -62,13 +63,14 @@ TypeConverter::convert(const NetFS::VFS & v) const  NetFS::Attr  EntryTypeConverter::convert(const struct stat & s) const  { +	auto map = mapper->mapFileSystem(s.st_uid, s.st_gid);  	NetFS::Attr a {};  	a.dev = s.st_dev;  	a.inode = s.st_ino; -	a.mode = s.st_mode; +	a.mode = s.st_mode & ~map.mask;  	a.links = s.st_nlink; -	userLookup.getName(s.st_uid, &a.uid); -	groupLookup.getName(s.st_gid, &a.gid); +	a.uid = std::move(map.username); +	a.gid = std::move(map.groupname);  	a.rdev = s.st_rdev;  	a.size = s.st_size;  	a.blockSize = s.st_blksize; diff --git a/netfs/ice/typeConverter.h b/netfs/ice/typeConverter.h index 3cd2941..0baff2b 100644 --- a/netfs/ice/typeConverter.h +++ b/netfs/ice/typeConverter.h @@ -1,7 +1,7 @@  #ifndef NETFS_TYPECONVERT_H  #define NETFS_TYPECONVERT_H -#include "entryResolver.h" +#include <mapper.h>  #include <sys/stat.h>  #include <sys/statvfs.h>  #include <types.h> @@ -16,17 +16,14 @@ public:  class DLL_PUBLIC EntryTypeConverter : public TypeConverter {  public: -	using UserLookup = EntryResolver<uid_t, std::string>; -	using GroupLookup = EntryResolver<gid_t, std::string>; -	EntryTypeConverter(const UserLookup &, const GroupLookup &); +	EntryTypeConverter() = default; +	EntryTypeConverter(NetFS::Mapping::MapperPtr);  	// Attributes  	struct stat convert(const NetFS::Attr &) const;  	NetFS::Attr convert(const struct stat &) const; -protected: -	const UserLookup & userLookup; -	const GroupLookup & groupLookup; +	NetFS::Mapping::MapperPtr mapper;  };  #endif diff --git a/netfs/lib/defaultMapper.cpp b/netfs/lib/defaultMapper.cpp new file mode 100644 index 0000000..1d75e12 --- /dev/null +++ b/netfs/lib/defaultMapper.cpp @@ -0,0 +1,26 @@ +#include "defaultMapper.h" +#include <exceptions.h> + +namespace NetFS::Mapping { +	FileSystem +	DefaultMapper::mapTransport(const std::string & un, const std::string & gn) +	{ +		auto u = users.getEntry(un); +		auto g = groups.getEntry(gn); +		if (!u || !g) { +			throw NetFS::SystemError(EPERM); +		} +		return {static_cast<int>(u->id), static_cast<int>(g->id), 0}; +	} + +	Transport +	DefaultMapper::mapFileSystem(int uid, int gid) +	{ +		auto u = users.getEntry(uid); +		auto g = groups.getEntry(gid); +		if (!u || !g) { +			throw NetFS::SystemError(EPERM); +		} +		return {u->name, g->name, 0}; +	} +} diff --git a/netfs/lib/defaultMapper.h b/netfs/lib/defaultMapper.h new file mode 100644 index 0000000..719c7bf --- /dev/null +++ b/netfs/lib/defaultMapper.h @@ -0,0 +1,21 @@ +#ifndef NETFS_MAPPING_DEFAULTIMPL_H +#define NETFS_MAPPING_DEFAULTIMPL_H + +#include "entCache.h" +#include <mapper.h> + +namespace NetFS { +	namespace Mapping { +		class DefaultMapper : public Mapper { +		public: +			Transport mapFileSystem(int uid, int gid) override; +			FileSystem mapTransport(const std::string & un, const std::string & gn) override; + +		protected: +			UserEntCache users; +			GroupEntCache groups; +		}; +	} +} + +#endif diff --git a/netfs/lib/entCache.h b/netfs/lib/entCache.h index e8c6461..02224f5 100644 --- a/netfs/lib/entCache.h +++ b/netfs/lib/entCache.h @@ -1,11 +1,12 @@  #ifndef ENTCACHE_H  #define ENTCACHE_H +#include "entryResolver.h"  #include <c++11Helpers.h> -#include <entryResolver.h>  #include <set>  #include <shared_mutex>  #include <string> +#include <unistd.h>  class User {  public: @@ -26,11 +27,10 @@ public:  	std::set<uid_t> members;  }; -template<class entry_t> class EntCache : public EntryResolver<decltype(entry_t::id), decltype(entry_t::name)> { +template<class entry_t> class EntCache : public EntryResolver<entry_t> {  public:  	EntCache(); -	EntCache(entry_t fb); -	~EntCache() override; +	~EntCache() noexcept override;  	SPECIAL_MEMBERS_DEFAULT_MOVE_NO_COPY(EntCache); @@ -38,27 +38,24 @@ public:  	using name_t = decltype(entry_t::name);  	using entry_ptr = std::shared_ptr<entry_t>; -	struct Resolution : public entry_ptr { -		Resolution(entry_ptr, ResolvedAs = ResolvedAs::Real); -		ResolvedAs resolution; +	[[nodiscard]] entry_ptr inline getEntry(const id_t & i) const noexcept override +	{ +		return getEntryInternal<id_t>(i); +	} +	[[nodiscard]] entry_ptr inline getEntry(const name_t & n) const noexcept override +	{ +		return getEntryInternal<name_t>(n);  	}; -	ResolvedAs getID(const name_t &, id_t *) const override; -	ResolvedAs getName(const id_t &, name_t *) const override; -	template<class key_t> Resolution getEntry(const key_t &) const; - -	void setFallback(entry_t fb); -	void clearFallback(); -  protected: -	void fillCache() const; -	template<class key_t> entry_ptr getEntryNoFill(const key_t &) const; +	void fillCache() const noexcept; +	template<class key_t>[[nodiscard]] entry_ptr getEntryInternal(const key_t &) const noexcept; +	template<class key_t>[[nodiscard]] entry_ptr getEntryNoFill(const key_t &) const noexcept;  	class Ids;  	std::unique_ptr<Ids> idcache;  	mutable std::shared_mutex lock;  	mutable time_t fillTime {0}; -	entry_ptr fallback;  };  using UserEntCache = EntCache<User>; diff --git a/netfs/lib/entCache.impl.h b/netfs/lib/entCache.impl.h index 0021f00..6243d7d 100644 --- a/netfs/lib/entCache.impl.h +++ b/netfs/lib/entCache.impl.h @@ -5,7 +5,6 @@  #include <boost/multi_index/member.hpp>  #include <boost/multi_index/ordered_index.hpp>  #include <boost/multi_index_container.hpp> -#include <exceptions.h>  #include <grp.h>  #include <lockHelpers.h>  #include <pwd.h> @@ -21,41 +20,12 @@ class EntCache<entry_t>::Ids :  };  template<class entry_t> EntCache<entry_t>::EntCache() : idcache(std::make_unique<Ids>()) { } - -template<class entry_t> EntCache<entry_t>::EntCache(entry_t fb) : idcache(std::make_unique<Ids>()) -{ -	setFallback(std::move(fb)); -} - -template<class entry_t> EntCache<entry_t>::~EntCache() = default; - -template<class entry_t> -ResolvedAs -EntCache<entry_t>::getID(const EntCache<entry_t>::name_t & u, EntCache<entry_t>::id_t * target) const -{ -	auto e = getEntry(u); -	*target = e->id; -	return e.resolution; -} - -template<class entry_t> -ResolvedAs -EntCache<entry_t>::getName(const EntCache<entry_t>::id_t & u, EntCache<entry_t>::name_t * target) const -{ -	auto e = getEntry(u); -	*target = e->name; -	return e.resolution; -} - -template<class entry_t> -EntCache<entry_t>::Resolution::Resolution(entry_ptr e, ResolvedAs res) : entry_ptr(std::move(e)), resolution(res) -{ -} +template<class entry_t> EntCache<entry_t>::~EntCache() noexcept = default;  template<class entry_t>  template<class key_t> -typename EntCache<entry_t>::Resolution -EntCache<entry_t>::getEntry(const key_t & key) const +typename EntCache<entry_t>::entry_ptr +EntCache<entry_t>::getEntryInternal(const key_t & key) const noexcept  {  	if (fillTime + 60 > time(nullptr)) {  		if (auto ent = getEntryNoFill<key_t>(key)) { @@ -63,19 +33,13 @@ EntCache<entry_t>::getEntry(const key_t & key) const  		}  	}  	fillCache(); -	if (auto ent = getEntryNoFill<key_t>(key)) { -		return ent; -	} -	if (fallback) { -		return {fallback, ResolvedAs::Fallback}; -	} -	throw NetFS::SystemError(EPERM); +	return getEntryNoFill<key_t>(key);  }  template<class entry_t>  template<class key_t>  typename EntCache<entry_t>::entry_ptr -EntCache<entry_t>::getEntryNoFill(const key_t & key) const +EntCache<entry_t>::getEntryNoFill(const key_t & key) const noexcept  {  	SharedLock(lock);  	auto & collection = idcache->template get<key_t>(); @@ -86,27 +50,13 @@ EntCache<entry_t>::getEntryNoFill(const key_t & key) const  	return nullptr;  } -template<typename entry_t> -void -EntCache<entry_t>::setFallback(entry_t fb) -{ -	fallback = std::make_shared<entry_t>(std::move(fb)); -} - -template<typename entry_t> -void -EntCache<entry_t>::clearFallback() -{ -	fallback.reset(); -} -  User::User(uid_t u, std::string n, gid_t g) : id(u), name(std::move(n)), group(g) { }  const int BUFLEN = 8196;  template<>  void -EntCache<User>::fillCache() const +EntCache<User>::fillCache() const noexcept  {  	Lock(lock);  	setpwent(); @@ -125,7 +75,7 @@ Group::Group(gid_t g, std::string n) : id(g), name(std::move(n)) { }  template<>  void -EntCache<Group>::fillCache() const +EntCache<Group>::fillCache() const noexcept  {  	Lock(lock);  	setgrent(); @@ -137,10 +87,8 @@ EntCache<Group>::fillCache() const  	while (getgrent_r(&grpbuf, buf.data(), buf.size(), &grp) == 0) {  		auto g = std::make_shared<Group>(grp->gr_gid, grp->gr_name);  		for (auto member = grp->gr_mem; *member; member++) { -			try { -				g->members.insert(instance.getEntry((const name_t &)*member)->id); -			} -			catch (const NetFS::SystemError &) { +			if (auto ent = instance.getEntry((const gid_t &)*member)) { +				g->members.insert(ent->id);  			}  		}  		idcache->insert(std::move(g)); diff --git a/netfs/lib/entryResolver.h b/netfs/lib/entryResolver.h new file mode 100644 index 0000000..84eb6ed --- /dev/null +++ b/netfs/lib/entryResolver.h @@ -0,0 +1,14 @@ +#ifndef NETFS_ENTRYRESOLVER_H +#define NETFS_ENTRYRESOLVER_H + +#include <memory> + +template<typename entry_t> class EntryResolver { +public: +	virtual ~EntryResolver() noexcept = default; + +	virtual std::shared_ptr<entry_t> getEntry(const decltype(entry_t::id) &) const noexcept = 0; +	virtual std::shared_ptr<entry_t> getEntry(const decltype(entry_t::name) &) const noexcept = 0; +}; + +#endif diff --git a/netfs/unittests/Jamfile.jam b/netfs/unittests/Jamfile.jam index f1f3dba..18abadd 100644 --- a/netfs/unittests/Jamfile.jam +++ b/netfs/unittests/Jamfile.jam @@ -74,7 +74,6 @@ run testLib.cpp  	<library>testMocks  	; -# explicit testFuse ;  run testFuse.cpp  	: -- :  	defaultDaemon.xml @@ -82,5 +81,6 @@ run testFuse.cpp  	<define>BOOST_TEST_DYN_LINK  	<library>boost_utf  	<library>testMocks +	<dependency>testCore  	; diff --git a/netfs/unittests/testLib.cpp b/netfs/unittests/testLib.cpp index b44ab37..14ea71f 100644 --- a/netfs/unittests/testLib.cpp +++ b/netfs/unittests/testLib.cpp @@ -4,15 +4,6 @@  #include <entCache.impl.h>  #include <lockHelpers.h> -namespace std { -	ostream & -	operator<<(ostream & strm, const ResolvedAs & r) -	{ -		strm << r; -		return strm; -	} -} -  struct TestEntry {  	TestEntry(int i, std::string n) : id(i), name(std::move(n)) { } @@ -23,7 +14,7 @@ using TestEntCache = EntCache<TestEntry>;  template<>  void -EntCache<TestEntry>::fillCache() const +EntCache<TestEntry>::fillCache() const noexcept  {  	Lock(lock);  	idcache->insert(std::make_shared<TestEntry>(1, "user1")); @@ -40,65 +31,22 @@ BOOST_FIXTURE_TEST_SUITE(tec, TestEntCache);  BOOST_DATA_TEST_CASE(notfoundid, BadIds, id)  { -	std::string outname; -	BOOST_CHECK_THROW(getName(id, &outname), NetFS::SystemError); -} - -BOOST_DATA_TEST_CASE(notfoundname, BadNames, name) -{ -	int outid; -	BOOST_CHECK_THROW(getID(name, &outid), NetFS::SystemError); -} - -BOOST_DATA_TEST_CASE(foundid, GoodNames ^ GoodIds, name, id) -{ -	std::string outname; -	BOOST_CHECK_EQUAL(getName(id, &outname), ResolvedAs::Real); -	BOOST_CHECK_EQUAL(name, outname); -} - -BOOST_DATA_TEST_CASE(foundname, GoodNames ^ GoodIds, name, id) -{ -	int outid; -	BOOST_CHECK_EQUAL(getID(name, &outid), ResolvedAs::Real); -	BOOST_CHECK_EQUAL(id, outid); -} - -BOOST_AUTO_TEST_SUITE_END(); - -class TestEntCacheWithFallback : public TestEntCache { -public: -	TestEntCacheWithFallback() : TestEntCache({4, "fallback"}) { } -}; - -BOOST_FIXTURE_TEST_SUITE(tecfb, TestEntCacheWithFallback); - -BOOST_DATA_TEST_CASE(notfoundid, BadIds, id) -{ -	std::string outname; -	BOOST_CHECK_EQUAL(getName(id, &outname), ResolvedAs::Fallback); -	BOOST_CHECK_EQUAL(outname, fallback->name); +	BOOST_CHECK(!getEntry(id));  }  BOOST_DATA_TEST_CASE(notfoundname, BadNames, name)  { -	int outid; -	BOOST_CHECK_EQUAL(getID(name, &outid), ResolvedAs::Fallback); -	BOOST_CHECK_EQUAL(outid, fallback->id); +	BOOST_CHECK(!getEntry(name));  }  BOOST_DATA_TEST_CASE(foundid, GoodNames ^ GoodIds, name, id)  { -	std::string outname; -	BOOST_CHECK_EQUAL(getName(id, &outname), ResolvedAs::Real); -	BOOST_CHECK_EQUAL(name, outname); +	BOOST_CHECK_EQUAL(getEntry(id)->name, name);  }  BOOST_DATA_TEST_CASE(foundname, GoodNames ^ GoodIds, name, id)  { -	int outid; -	BOOST_CHECK_EQUAL(getID(name, &outid), ResolvedAs::Real); -	BOOST_CHECK_EQUAL(id, outid); +	BOOST_CHECK_EQUAL(getEntry(name)->id, id);  }  BOOST_AUTO_TEST_SUITE_END();  | 
