json_parser_utils: Add variable support
Enhance the json_parser_utils functions to support optional usage of
variables in JSON values.
Variables are specified using the syntax `${variable_name}`.
Variable values are specified in an optional new parameter to the
parsing functions. Parsing functions will replace the variable with the
corresponding variable value.
Example:
```
{
"inventory_path": "/xyz/openbmc_project/inventory/system/chassis${chassis_number}"
}
```
Tested:
* Ran automated test cases.
Change-Id: Ib8f5d9b27ccc96ca9d16eb9a044321233f81ba18
Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
diff --git a/test/json_parser_utils_tests.cpp b/test/json_parser_utils_tests.cpp
index e4f591c..af49977 100644
--- a/test/json_parser_utils_tests.cpp
+++ b/test/json_parser_utils_tests.cpp
@@ -26,6 +26,7 @@
#include <gtest/gtest.h>
using namespace phosphor::power::json_parser_utils;
+using namespace phosphor::power::json_parser_utils::internal;
using json = nlohmann::json;
TEST(JSONParserUtilsTests, GetRequiredProperty)
@@ -66,6 +67,14 @@
EXPECT_EQ(value, 7);
}
+ // Test where works: Variable specified
+ {
+ std::map<std::string, std::string> variables{{"bit_pos", "3"}};
+ const json element = R"( "${bit_pos}" )"_json;
+ uint8_t value = parseBitPosition(element, variables);
+ EXPECT_EQ(value, 3);
+ }
+
// Test where fails: Element is not an integer
try
{
@@ -101,6 +110,19 @@
{
EXPECT_STREQ(e.what(), "Element is not a bit position");
}
+
+ // Test where fails: Variable specified: Value < 0
+ try
+ {
+ std::map<std::string, std::string> variables{{"bit_pos", "-1"}};
+ const json element = R"( "${bit_pos}" )"_json;
+ parseBitPosition(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a bit position");
+ }
}
TEST(JSONParserUtilsTests, ParseBitValue)
@@ -119,6 +141,14 @@
EXPECT_EQ(value, 1);
}
+ // Test where works: Variable specified
+ {
+ std::map<std::string, std::string> variables{{"bit_val", "1"}};
+ const json element = R"( "${bit_val}" )"_json;
+ uint8_t value = parseBitValue(element, variables);
+ EXPECT_EQ(value, 1);
+ }
+
// Test where fails: Element is not an integer
try
{
@@ -154,6 +184,19 @@
{
EXPECT_STREQ(e.what(), "Element is not a bit value");
}
+
+ // Test where fails: Variable specified: Not an integer
+ try
+ {
+ std::map<std::string, std::string> variables{{"bit_val", "one"}};
+ const json element = R"( "${bit_val}" )"_json;
+ parseBitValue(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an integer");
+ }
}
TEST(JSONParserUtilsTests, ParseBoolean)
@@ -172,6 +215,22 @@
EXPECT_EQ(value, false);
}
+ // Test where works: Variable specified: true
+ {
+ std::map<std::string, std::string> variables{{"bool_val", "true"}};
+ const json element = R"( "${bool_val}" )"_json;
+ bool value = parseBoolean(element, variables);
+ EXPECT_EQ(value, true);
+ }
+
+ // Test where works: Variable specified: false
+ {
+ std::map<std::string, std::string> variables{{"bool_val", "false"}};
+ const json element = R"( "${bool_val}" )"_json;
+ bool value = parseBoolean(element, variables);
+ EXPECT_EQ(value, false);
+ }
+
// Test where fails: Element is not a boolean
try
{
@@ -183,25 +242,66 @@
{
EXPECT_STREQ(e.what(), "Element is not a boolean");
}
+
+ // Test where fails: Variable specified: Variables map not specified
+ try
+ {
+ const json element = R"( "${bool_val}" )"_json;
+ parseBoolean(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a boolean");
+ }
+
+ // Test where fails: Variable specified: Value is not a boolean
+ try
+ {
+ std::map<std::string, std::string> variables{{"bool_val", "3.2"}};
+ const json element = R"( "${bool_val}" )"_json;
+ parseBoolean(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a boolean");
+ }
}
TEST(JSONParserUtilsTests, ParseDouble)
{
- // Test where works: floating point value
+ // Test where works: Floating point value
{
const json element = R"( 1.03 )"_json;
double value = parseDouble(element);
EXPECT_EQ(value, 1.03);
}
- // Test where works: integer value
+ // Test where works: Integer value
{
- const json element = R"( 24 )"_json;
+ const json element = R"( -24 )"_json;
double value = parseDouble(element);
+ EXPECT_EQ(value, -24.0);
+ }
+
+ // Test where works: Variable specified: Floating point value
+ {
+ std::map<std::string, std::string> variables{{"var", "-1.03"}};
+ const json element = R"( "${var}" )"_json;
+ double value = parseDouble(element, variables);
+ EXPECT_EQ(value, -1.03);
+ }
+
+ // Test where works: Variable specified: Integer value
+ {
+ std::map<std::string, std::string> variables{{"var", "24"}};
+ const json element = R"( "${var}" )"_json;
+ double value = parseDouble(element, variables);
EXPECT_EQ(value, 24.0);
}
- // Test where fails: Element is not a number
+ // Test where fails: Element is not a double
try
{
const json element = R"( true )"_json;
@@ -210,7 +310,84 @@
}
catch (const std::invalid_argument& e)
{
- EXPECT_STREQ(e.what(), "Element is not a number");
+ EXPECT_STREQ(e.what(), "Element is not a double");
+ }
+
+ // Test where fails: Variable specified: Variables map not specified
+ try
+ {
+ const json element = R"( "${var}" )"_json;
+ parseDouble(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a double");
+ }
+
+ // Test where fails: Variable specified: Leading whitespace
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", " -1.03"}};
+ const json element = R"( "${var}" )"_json;
+ parseDouble(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a double");
+ }
+
+ // Test where fails: Variable specified: Trailing whitespace
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "-1.03 "}};
+ const json element = R"( "${var}" )"_json;
+ parseDouble(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a double");
+ }
+
+ // Test where fails: Variable specified: Starts with non-number character
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "x-1.03"}};
+ const json element = R"( "${var}" )"_json;
+ parseDouble(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a double");
+ }
+
+ // Test where fails: Variable specified: Ends with non-number character
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "-1.03x"}};
+ const json element = R"( "${var}" )"_json;
+ parseDouble(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a double");
+ }
+
+ // Test where fails: Variable specified: Not a double
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "foo"}};
+ const json element = R"( "${var}" )"_json;
+ parseDouble(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not a double");
}
}
@@ -237,6 +414,14 @@
EXPECT_EQ(value, 0xf);
}
+ // Test where works: Variable specified
+ {
+ std::map<std::string, std::string> variables{{"var", "ed"}};
+ const json element = R"( "0x${var}" )"_json;
+ uint8_t value = parseHexByte(element, variables);
+ EXPECT_EQ(value, 0xed);
+ }
+
// Test where fails: "0xfff"
try
{
@@ -320,6 +505,19 @@
{
EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
}
+
+ // Test where fails: Variable specified: Not a hex string
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "0xsz"}};
+ const json element = R"( "${var}" )"_json;
+ parseHexByte(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
+ }
}
TEST(JSONParserUtilsTests, ParseHexByteArray)
@@ -332,6 +530,16 @@
EXPECT_EQ(hexBytes, expected);
}
+ // Test where works: Variables specified
+ {
+ std::map<std::string, std::string> variables{{"var1", "0xCC"},
+ {"var2", "0xFF"}};
+ const json element = R"( [ "${var1}", "${var2}" ] )"_json;
+ std::vector<uint8_t> hexBytes = parseHexByteArray(element, variables);
+ std::vector<uint8_t> expected = {0xcc, 0xff};
+ EXPECT_EQ(hexBytes, expected);
+ }
+
// Test where fails: Element is not an array
try
{
@@ -343,6 +551,20 @@
{
EXPECT_STREQ(e.what(), "Element is not an array");
}
+
+ // Test where fails: Variables specified: Invalid byte value
+ try
+ {
+ std::map<std::string, std::string> variables{{"var1", "0xCC"},
+ {"var2", "99"}};
+ const json element = R"( [ "${var1}", "${var2}" ] )"_json;
+ parseHexByteArray(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
+ }
}
TEST(JSONParserUtilsTests, ParseInt8)
@@ -361,6 +583,14 @@
EXPECT_EQ(value, 127);
}
+ // Test where works: Variable specified
+ {
+ std::map<std::string, std::string> variables{{"var", "-23"}};
+ const json element = R"( "${var}" )"_json;
+ int8_t value = parseInt8(element, variables);
+ EXPECT_EQ(value, -23);
+ }
+
// Test where fails: Element is not an integer
try
{
@@ -396,6 +626,148 @@
{
EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
}
+
+ // Test where fails: Variable specified: Value > INT8_MAX
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "128"}};
+ const json element = R"( "${var}" )"_json;
+ parseInt8(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
+ }
+}
+
+TEST(JSONParserUtilsTests, ParseInteger)
+{
+ // Test where works: Zero
+ {
+ const json element = R"( 0 )"_json;
+ int value = parseInteger(element);
+ EXPECT_EQ(value, 0);
+ }
+
+ // Test where works: Positive value
+ {
+ const json element = R"( 103 )"_json;
+ int value = parseInteger(element);
+ EXPECT_EQ(value, 103);
+ }
+
+ // Test where works: Negative value
+ {
+ const json element = R"( -24 )"_json;
+ int value = parseInteger(element);
+ EXPECT_EQ(value, -24);
+ }
+
+ // Test where works: Variable specified: Positive value
+ {
+ std::map<std::string, std::string> variables{{"var", "1024"}};
+ const json element = R"( "${var}" )"_json;
+ int value = parseInteger(element, variables);
+ EXPECT_EQ(value, 1024);
+ }
+
+ // Test where works: Variable specified: Negative value
+ {
+ std::map<std::string, std::string> variables{{"var", "-9924"}};
+ const json element = R"( "${var}" )"_json;
+ int value = parseInteger(element, variables);
+ EXPECT_EQ(value, -9924);
+ }
+
+ // Test where fails: Element is not a integer
+ try
+ {
+ const json element = R"( true )"_json;
+ parseInteger(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an integer");
+ }
+
+ // Test where fails: Variable specified: Variables map not specified
+ try
+ {
+ const json element = R"( "${var}" )"_json;
+ parseInteger(element);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an integer");
+ }
+
+ // Test where fails: Variable specified: Leading whitespace
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", " -13"}};
+ const json element = R"( "${var}" )"_json;
+ parseInteger(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an integer");
+ }
+
+ // Test where fails: Variable specified: Trailing whitespace
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "-13 "}};
+ const json element = R"( "${var}" )"_json;
+ parseInteger(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an integer");
+ }
+
+ // Test where fails: Variable specified: Starts with non-number character
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "x-13"}};
+ const json element = R"( "${var}" )"_json;
+ parseInteger(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an integer");
+ }
+
+ // Test where fails: Variable specified: Ends with non-number character
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "-13x"}};
+ const json element = R"( "${var}" )"_json;
+ parseInteger(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an integer");
+ }
+
+ // Test where fails: Variable specified: Not an integer
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "foo"}};
+ const json element = R"( "${var}" )"_json;
+ parseInteger(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an integer");
+ }
}
TEST(JSONParserUtilsTests, ParseString)
@@ -414,6 +786,22 @@
EXPECT_EQ(value, "vdd_regulator");
}
+ // Test where works: Variable specified: Empty string
+ {
+ std::map<std::string, std::string> variables{{"var", ""}};
+ const json element = R"( "${var}" )"_json;
+ std::string value = parseString(element, true, variables);
+ EXPECT_EQ(value, "");
+ }
+
+ // Test where works: Variable specified: Non-empty string
+ {
+ std::map<std::string, std::string> variables{{"var", "vio_regulator"}};
+ const json element = R"( "${var}" )"_json;
+ std::string value = parseString(element, false, variables);
+ EXPECT_EQ(value, "vio_regulator");
+ }
+
// Test where fails: Element is not a string
try
{
@@ -437,6 +825,32 @@
{
EXPECT_STREQ(e.what(), "Element contains an empty string");
}
+
+ // Test where fails: Variable specified: Empty string
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", ""}};
+ const json element = R"( "${var}" )"_json;
+ parseString(element, false, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element contains an empty string");
+ }
+
+ // Test where fails: Variable specified: Variable not defined
+ try
+ {
+ std::map<std::string, std::string> variables{{"var1", "foo"}};
+ const json element = R"( "${var2}" )"_json;
+ parseString(element, false, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Undefined variable: var2");
+ }
}
TEST(JSONParserUtilsTests, ParseUint8)
@@ -455,6 +869,14 @@
EXPECT_EQ(value, 255);
}
+ // Test where works: Variable specified
+ {
+ std::map<std::string, std::string> variables{{"var", "19"}};
+ const json element = R"( "${var}" )"_json;
+ uint8_t value = parseUint8(element, variables);
+ EXPECT_EQ(value, 19);
+ }
+
// Test where fails: Element is not an integer
try
{
@@ -490,6 +912,19 @@
{
EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
}
+
+ // Test where fails: Variable specified: Value > UINT8_MAX
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "256"}};
+ const json element = R"( "${var}" )"_json;
+ parseUint8(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
+ }
}
TEST(JSONParserUtilsTests, ParseUnsignedInteger)
@@ -501,6 +936,14 @@
EXPECT_EQ(value, 1);
}
+ // Test where works: Variable specified
+ {
+ std::map<std::string, std::string> variables{{"var", "25678"}};
+ const json element = R"( "${var}" )"_json;
+ unsigned int value = parseUnsignedInteger(element, variables);
+ EXPECT_EQ(value, 25678);
+ }
+
// Test where fails: Element is not an integer
try
{
@@ -510,7 +953,7 @@
}
catch (const std::invalid_argument& e)
{
- EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
+ EXPECT_STREQ(e.what(), "Element is not an integer");
}
// Test where fails: Value < 0
@@ -524,6 +967,19 @@
{
EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
}
+
+ // Test where fails: Variable specified: Value < 0
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "-23"}};
+ const json element = R"( "${var}" )"_json;
+ parseUnsignedInteger(element, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
+ }
}
TEST(JSONParserUtilsTests, VerifyIsArray)
@@ -599,3 +1055,154 @@
EXPECT_STREQ(e.what(), "Element contains an invalid property");
}
}
+
+TEST(JSONParserUtilsTests, ExpandVariables)
+{
+ // Test where works: Single variable: Variable is entire value: Lower case
+ // in variable name
+ {
+ std::map<std::string, std::string> variables{{"var", "vio_regulator"}};
+ std::string value{"${var}"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "vio_regulator");
+ }
+
+ // Test where works: Multiple variables: Variables are part of value: Upper
+ // case and underscore in variable name
+ {
+ std::map<std::string, std::string> variables{
+ {"CHASSIS_NUMBER", "1"}, {"REGULATOR", "vcs_vio"}, {"RAIL", "vio"}};
+ std::string value{
+ "chassis${CHASSIS_NUMBER}_${REGULATOR}_regulator_${RAIL}_rail"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "chassis1_vcs_vio_regulator_vio_rail");
+ }
+
+ // Test where works: Variable at start of value: Number in variable name
+ {
+ std::map<std::string, std::string> variables{{"var1", "vio_regulator"}};
+ std::string value{"${var1}_rail"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "vio_regulator_rail");
+ }
+
+ // Test where works: Variable at end of value
+ {
+ std::map<std::string, std::string> variables{{"chassis_number", "3"}};
+ std::string value{
+ "/xyz/openbmc_project/inventory/system/chassis${chassis_number}"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "/xyz/openbmc_project/inventory/system/chassis3");
+ }
+
+ // Test where works: Variable has empty value: Start of value
+ {
+ std::map<std::string, std::string> variables{{"chassis_prefix", ""}};
+ std::string value{"${chassis_prefix}vio_regulator"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "vio_regulator");
+ }
+
+ // Test where works: Variable has empty value: Middle of value
+ {
+ std::map<std::string, std::string> variables{{"chassis_number", ""}};
+ std::string value{"c${chassis_number}_vio_regulator"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "c_vio_regulator");
+ }
+
+ // Test where works: Variable has empty value: End of value
+ {
+ std::map<std::string, std::string> variables{{"chassis_number", ""}};
+ std::string value{
+ "/xyz/openbmc_project/inventory/system/chassis${chassis_number}"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "/xyz/openbmc_project/inventory/system/chassis");
+ }
+
+ // Test where works: No variables specified
+ {
+ std::map<std::string, std::string> variables{{"var", "vio_regulator"}};
+ std::string value{"vcs_rail"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "vcs_rail");
+ }
+
+ // Test where works: Nested variable expansion
+ {
+ std::map<std::string, std::string> variables{{"var1", "${var2}"},
+ {"var2", "vio_reg"}};
+ std::string value{"${var1}_rail"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "vio_reg_rail");
+ }
+
+ // Test where fails: Variables map is empty
+ {
+ std::map<std::string, std::string> variables{};
+ std::string value{"${var}_rail"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "${var}_rail");
+ }
+
+ // Test where fails: Variable missing $
+ {
+ std::map<std::string, std::string> variables{{"var", "vio_reg"}};
+ std::string value{"{var}_rail"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "{var}_rail");
+ }
+
+ // Test where fails: Variable missing {
+ {
+ std::map<std::string, std::string> variables{{"var", "vio_reg"}};
+ std::string value{"$var}_rail"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "$var}_rail");
+ }
+
+ // Test where fails: Variable missing }
+ {
+ std::map<std::string, std::string> variables{{"var", "vio_reg"}};
+ std::string value{"${var_rail"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "${var_rail");
+ }
+
+ // Test where fails: Variable missing name
+ {
+ std::map<std::string, std::string> variables{{"var", "vio_reg"}};
+ std::string value{"${}_rail"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "${}_rail");
+ }
+
+ // Test where fails: Variable name has invalid characters
+ {
+ std::map<std::string, std::string> variables{{"var-2", "vio_reg"}};
+ std::string value{"${var-2}_rail"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "${var-2}_rail");
+ }
+
+ // Test where fails: Variable has unexpected whitespace
+ {
+ std::map<std::string, std::string> variables{{"var", "vio_reg"}};
+ std::string value{"${ var }_rail"};
+ expandVariables(value, variables);
+ EXPECT_EQ(value, "${ var }_rail");
+ }
+
+ // Test where fails: Undefined variable
+ try
+ {
+ std::map<std::string, std::string> variables{{"var", "vio_reg"}};
+ std::string value{"${foo}_rail"};
+ expandVariables(value, variables);
+ ADD_FAILURE() << "Should not have reached this line.";
+ }
+ catch (const std::invalid_argument& e)
+ {
+ EXPECT_STREQ(e.what(), "Undefined variable: foo");
+ }
+}