Rework envMock
Instead of mocking all the functions, only mock std::getenv.
Now each test only needs to provide an EnvImpl that delegate calls to
mockEnv in order to inject dependencies on std::getenv. This for several
reasons:
1. Any call to env::getEnv() will be calling the real implementation of
the C++ code, and testing real code is better than testing mocks.
2. It is easier to write a fake class that takes a config string which
can greatly simplify test cases.
3. We can now write unit tests that ensure the number of times
std::getenv gets called (should be once, but multiple times right now).
Tested: unit tests still pass
Signed-off-by: Kun Yi <kunyi731@gmail.com>
Change-Id: I3e5aff7fa5d025de1b8ae798af43b97d31151ab9
diff --git a/env.hpp b/env.hpp
index b3ddff5..b8c3815 100644
--- a/env.hpp
+++ b/env.hpp
@@ -2,20 +2,48 @@
#include "sensorset.hpp"
+#include <fstream>
#include <string>
namespace env
{
+/** @class Env
+ * @brief Overridable std::getenv interface
+ */
+struct Env
+{
+ virtual ~Env() = default;
+
+ virtual const char* get(const char* key) const = 0;
+};
+
+/** @class EnvImpl
+ * @brief Concrete implementation that calls std::getenv
+ */
+struct EnvImpl : public Env
+{
+ const char* get(const char* key) const override;
+};
+
+/** @brief Default instantiation of Env */
+extern EnvImpl env_impl;
+
/** @brief Reads an environment variable
*
* Reads the environment for that key
*
* @param[in] key - the key
+ * @param[in] env - env interface that defaults to calling std::getenv
*
* @return string - the env var value
*/
-std::string getEnv(const char* key);
+inline std::string getEnv(const char* key, const Env* env = &env_impl)
+{
+ // Be aware value could be nullptr
+ auto value = env->get(key);
+ return (value) ? std::string(value) : std::string();
+}
/** @brief Reads an environment variable
*
@@ -23,21 +51,38 @@
*
* @param[in] prefix - the variable prefix
* @param[in] sensor - Sensor details
+ * @param[in] env - env interface that defaults to calling std::getenv
*
* @return string - the env var value
*/
-std::string getEnv(const char* prefix, const SensorSet::key_type& sensor);
+inline std::string getEnv(const char* prefix, const SensorSet::key_type& sensor,
+ const Env* env = &env_impl)
+{
+ std::string key;
+
+ key.assign(prefix);
+ key.append(1, '_');
+ key.append(sensor.first);
+ key.append(sensor.second);
+
+ return getEnv(key.c_str(), env);
+}
/** @brief Reads an environment variable, and takes type and id separately
*
* @param[in] prefix - the variable prefix
* @param[in] type - sensor type, like 'temp'
* @param[in] id - sensor ID, like '5'
+ * @param[in] env - env interface that defaults to calling std::getenv
*
* @return string - the env var value
*/
-std::string getEnv(const char* prefix, const std::string& type,
- const std::string& id);
+inline std::string getEnv(const char* prefix, const std::string& type,
+ const std::string& id, const Env* env = &env_impl)
+{
+ SensorSet::key_type sensor{type, id};
+ return getEnv(prefix, sensor, env);
+}
/** @brief Gets the ID for the sensor with a level of indirection
*
@@ -48,7 +93,31 @@
* @param[in] fileSuffix - The file suffix
* @param[in] sensor - Sensor details
*/
-std::string getIndirectID(std::string path, const std::string& fileSuffix,
- const SensorSet::key_type& sensor);
+inline std::string getIndirectID(std::string path,
+ const std::string& fileSuffix,
+ const SensorSet::key_type& sensor)
+{
+ std::string content;
+
+ path.append(sensor.first);
+ path.append(sensor.second);
+ path.append(1, '_');
+ path.append(fileSuffix);
+
+ std::ifstream handle(path.c_str());
+ if (!handle.fail())
+ {
+ content.assign((std::istreambuf_iterator<char>(handle)),
+ (std::istreambuf_iterator<char>()));
+
+ if (!content.empty())
+ {
+ // remove the newline
+ content.pop_back();
+ }
+ }
+
+ return content;
+}
} // namespace env