MINIFICPP-380 Added missing toLower EL function

This closes #250.

Signed-off-by: Marc Parisi <phrocker@apache.org>
diff --git a/extensions/expression-language/Expression.cpp b/extensions/expression-language/Expression.cpp
index 2fdc541..de737ed 100644
--- a/extensions/expression-language/Expression.cpp
+++ b/extensions/expression-language/Expression.cpp
@@ -67,6 +67,12 @@
   return result;
 }
 
+std::string expr_toLower(const std::vector<std::string> &args) {
+  std::string result = args[0];
+  std::transform(result.begin(), result.end(), result.begin(), ::tolower);
+  return result;
+}
+
 std::string expr_substring(const std::vector<std::string> &args) {
   if (args.size() < 3) {
     return args[0].substr(std::stoul(args[1]));
@@ -306,6 +312,8 @@
     return make_dynamic_function_incomplete<expr_hostname>(function_name, args, 0);
   } else if (function_name == "toUpper") {
     return make_dynamic_function_incomplete<expr_toUpper>(function_name, args, 1);
+  } else if (function_name == "toLower") {
+    return make_dynamic_function_incomplete<expr_toLower>(function_name, args, 1);
   } else if (function_name == "substring") {
     return make_dynamic_function_incomplete<expr_substring>(function_name, args, 2);
   } else if (function_name == "substringBefore") {
diff --git a/libminifi/test/expression-language-tests/ExpressionLanguageTests.cpp b/libminifi/test/expression-language-tests/ExpressionLanguageTests.cpp
index 27d3304..d6ab607 100644
--- a/libminifi/test/expression-language-tests/ExpressionLanguageTests.cpp
+++ b/libminifi/test/expression-language-tests/ExpressionLanguageTests.cpp
@@ -150,6 +150,15 @@
   REQUIRE("text_before__FLOW_A_ATTR_VALUE_A__text_after" == expr({flow_file_a}));
 }
 
+TEST_CASE("ToLower function", "[expressionLanguageTestToLowerFunction]") {  // NOLINT
+  auto expr = expression::compile(R"(text_before${
+                                       attr_a : toLower()
+                                     }text_after)");
+  auto flow_file_a = std::make_shared<MockFlowFile>();
+  flow_file_a->addAttribute("attr_a", "__FLOW_A_ATTR_VALUE_A__");
+  REQUIRE("text_before__flow_a_attr_value_a__text_after" == expr({flow_file_a}));
+}
+
 TEST_CASE("GetFile PutFile dynamic attribute", "[expressionLanguageTestGetFilePutFileDynamicAttribute]") {  // NOLINT
   TestController testController;