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