ProviderTestHelpers.h
Go to the documentation of this file.
1 /**
2  * @file ProviderTestHelpers.h
3  * @brief Helper classes to be used together with LArSoft's unit test
4  * @date May 10th, 2016
5  * @author Gianluca Petrillo (petrillo@fnal.gov)
6  * @see ProviderList.h
7  *
8  *
9  * Currently provides:
10  * - `ProviderSetupClass` class (and `setupProvider()` helper) to be specialised
11  * to support the setup of a specific service provider
12  * - `SimpleEnvironmentSetupClass` class (and `simpleEnvironmentSetup()` helper)
13  * to be specialised to support the one-step set up of the provider in a
14  * LArSoft tester environment
15  *
16  * This is a pure template header. It does not require additional libraries to
17  * be linked.
18  */
19 
20 
21 #ifndef LARCORE_TESTUTILS_PROVIDERTESTHELPERS_H
22 #define LARCORE_TESTUTILS_PROVIDERTESTHELPERS_H 1
23 
24 
25 // C/C++ standard libraries
26 #include <functional> // std::function<>
27 #include <memory> // std::unique_ptr<>, std::make_unique()
28 #include <string>
29 #include <utility> // std::forward()
30 
31 
32 /// LArSoft test utilities
33 namespace testing {
34 
35 
36  /// Generic setup provider function type
37  template <typename Prov, typename... Args>
38  using setupProvider_t = std::function<std::unique_ptr<Prov>(Args...)>;
39 
40 
41  /// A default implementation for provider setup class
42  template <typename Prov>
43  struct DefaultSetupProviderClass {
44 
45  /// Instantiates a new provider with specified arguments for constructor
46  template <typename... Args>
47  static std::unique_ptr<Prov> setup(Args&&... args)
48  { return std::make_unique<Prov>(std::forward<Args>(args)...); }
49 
50  }; // DefaultSetupProviderClass()
51 
52 
53  /** **************************************************************************
54  * @brief Class to create and set up a new provider.
55  * @tparam Prov type of provider being set up
56  *
57  * The class `ProviderSetupClass<Prov>` is used by ProviderList to create and
58  * set up a new service provider. The class must have a static method
59  * `setup()`, compatible with setupProvider_t signature: it must return
60  * a fully set up provider contained in a std::unique_ptr<Prov>.
61  *
62  * An example of implementation is `DefaultSetupProviderClass`, that is in
63  * fact the default implementation.
64  *
65  * An example to implement a specific setup for a provider, `MyProvider`:
66  *
67  * template <>
68  * struct ProviderSetupClass<MyProvider> {
69  *
70  * static std::unique_ptr<MyProvider> setup
71  * (MyProvider::Config const& cfg)
72  * { return std::make_unique<MyProvider>(fhicl::Table<Config>(cfg)); }
73  *
74  * }; // ProviderSetupClass<MyProvider>
75  *
76  * calling a MyProvider(fhicl::Table<Config> const&) constructor.
77  *
78  */
79  template <typename Prov>
80  struct ProviderSetupClass: public DefaultSetupProviderClass<Prov> {};
81 
82 
83  /**
84  * @brief Function calling ProviderSetupClass<>::setup for the specified provider
85  * @tparam Prov type of the provider to be created and set up
86  * @tparam Args types of arguments to the setup function
87  * @param args arguments to the setup function
88  * @return a pointer to the newly created and set up provider
89  * @see ProviderSetup
90  *
91  * This function provides a function-like interface to the ProviderSetup
92  * classes. An example of its use to create an instance of `MyProvider` is:
93  *
94  * auto prov = testing::setupProvider<MyProv>
95  * (pset.get<fhicl::ParameterSet>("services.MyProviderService"));
96  *
97  * if `MyProvider` provider has a constructor taking a fhicl::ParameterSet.
98  */
99  template <typename Prov, typename... Args>
100  std::unique_ptr<Prov> setupProvider(Args&&... args)
101  { return ProviderSetupClass<Prov>::setup(std::forward<Args>(args)...); }
102 
103 
104  /** **************************************************************************
105  * @brief Environment helper to set up a service provider
106  * @tparam Prov type of provider being set up
107  * @tparam TestEnv type of environment to set up
108  * @see simpleEnvironmentSetup()
109  *
110  * The `setup()` static method of this class implements a simple set up of
111  * a service provider Prov in an existing testing environment:
112  *
113  * static Prov* setup(TestEnv&);
114  *
115  * If such a class is available for a given provider, the environment
116  * testing::TesterEnvironment offers the one-stop `SimpleProviderSetup()`
117  * method for the complete set up of that provider.
118  *
119  * The setup() function will typically:
120  *
121  * * find a suitable configuration for the service
122  * * instantiate and set up the provider
123  * * register the provider and possibly the interface it implements into the
124  * environment
125  *
126  * The environment is expected to expose an interface equivalent to the one
127  * of `testing::TesterEnvironment`.
128  *
129  * See SimpleEnvironmentStandardSetupClass for a class suitable as base class
130  * for your own implementation.
131  *
132  * To implement a setup for MyProvider, the specialisation can follow the
133  * pattern:
134  *
135  * template <typename TestEnv>
136  * struct SimpleEnvironmentSetupClass<MyProvider, TestEnv> {
137  *
138  * static MyProvider* setup(TestEnv& env)
139  * {
140  * // create and set up the provider, e.g.
141  * auto prov = std::make_unique<MyProvider>(
142  * // constructor arguments...
143  * );
144  * // yield and register the provider to the environment
145  * MyProvider* prov_ptr = env.AcquireProvider<MyProvider>(prov);
146  * return prov_ptr;
147  * } // setup()
148  *
149  * }; // SimpleEnvironmentSetupClass<MyProvider>
150  *
151  * Note that the class must be fully constructed by the default constructor,
152  * in order for it to work with the tester environment.
153  */
154  template <typename Prov, typename TestEnv>
156 
157 
158  /**
159  * @brief Basic implementation of a environment setup helper.
160  * @tparam Prov type of provider being set up
161  * @tparam TestEnv type of environment to set up
162  * @tparam Interface (optional) type of interface being implemented
163  * @see SimpleEnvironmentSetupClass()
164  *
165  * The `setup()` static method of this class implements a simple set up of
166  * a service provider Prov in an existing testing environment.
167  *
168  * The setup() function:
169  *
170  * * finds a suitable configuration for the service from the environment
171  * * instantiates and sets up the provider
172  * * registers the provider and the interface it implements into the
173  * environment
174  *
175  * The environment is expected to expose an interface equivalent to the one
176  * of `testing::TesterEnvironment`.
177  * Use this as:
178  *
179  * template <typename TestEnv>
180  * struct SimpleEnvironmentSetupClass<MyProv, TestEnv>
181  * : public SimpleEnvironmentStandardSetupClass<MyProv, TestEnv, MyInterface>
182  * {
183  * SimpleEnvironmentSetupClass():
184  * SimpleEnvironmentStandardSetupClass<MyProvider, TestEnv, MyInterface>("MyService")
185  * {}
186  * };
187  *
188  * to register a provider of type MyProvider that implements a provider
189  * interface MyInterface, reading its configuration from the service
190  * configuration of `"MyService"` (that is, `services.MyService`).
191  *
192  * The environment is then expected to react to both MyProvider and
193  * MyInterface types:
194  *
195  * env.Provider<MyProvider>();
196  * env.Provider<MyInterface>();
197  *
198  * both return a pointer to the same provider.
199  * If instead MyInterface is `void` (default), no interface is registered.
200  *
201  * @note This class itself is *not* suitable for direct use in the test
202  * environment, lacking a default constructor. The setup class can inherit
203  * from it, as in the example above.
204  */
205  template <typename Prov, typename Interface, typename TestEnv>
207  (TestEnv& env, std::string service_name)
208  {
209  return
210  env.template SetupProviderFromServiceFor<Interface, Prov>(service_name);
211  }
212 
213  // overload for providers with no shared interface
214  template <typename Prov, typename TestEnv>
216  (TestEnv& env, std::string service_name)
217  { return env.template SetupProviderFromService<Prov>(service_name); }
218 
219 
220  /**
221  * @brief Sets up a provider in a specified test environment
222  * @tparam Prov type of the provider to be set up
223  * @tparam TestEnv type of the environment
224  * @param env the environment to be set up
225  * @return a pointer to the newly set up provider
226  * @see SimpleEnvironmentSetupClass
227  *
228  * This function performs the over-simple set up of a provider.
229  * The set up is completely delegated to a SimpleEnvironmentSetupClass
230  * class. No such class is provided by default, and service implementers
231  * must write their own to allow this one to work.
232  */
233  template <typename Prov, typename TestEnv>
234  Prov* simpleEnvironmentSetup(TestEnv& env)
236 
237 
238 } // namespace testing
239 
240 #endif // LARCORE_TESTUTILS_PROVIDERTESTHELPERS_H
LArSoft test utilities.
std::function< std::unique_ptr< Prov >(Args...)> setupProvider_t
Generic setup provider function type.
std::string string
Definition: nybbler.cc:12
static std::unique_ptr< Prov > setup(Args &&...args)
Instantiates a new provider with specified arguments for constructor.
static QCString args
Definition: declinfo.cpp:674
Prov * simpleEnvironmentSetup(TestEnv &env)
Sets up a provider in a specified test environment.
Environment helper to set up a service provider.
A default implementation for provider setup class.
Class to create and set up a new provider.
std::unique_ptr< Prov > setupProvider(Args &&...args)
Function calling ProviderSetup<>::setup for the specified provider.
Prov * SimpleEnvironmentStandardSetupByName(TestEnv &env, std::string service_name)
Basic implementation of a environment setup helper.
static void setup()
Definition: qtextcodec.cpp:110