FF-1805: New flow element Matches All

This commit is contained in:
John Andrews
2024-09-23 10:14:04 +12:00
parent 3a324ec8da
commit dddb4c6670
4 changed files with 255 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
namespace FileFlows.BasicNodes.Functions;
/// <summary>
/// A flow element that matches all conditions
/// </summary>
public class MatchesAll : Node
{
/// <inheritdoc />
public override int Inputs => 1;
/// <inheritdoc />
public override int Outputs => 2;
/// <inheritdoc />
public override FlowElementType Type => FlowElementType.Logic;
/// <inheritdoc />
public override string Icon => "fas fa-equals";
/// <inheritdoc />
public override bool FailureNode => true;
/// <inheritdoc />
public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/matches-all";
/// <summary>
/// Gets or sets replacements to replace
/// </summary>
[KeyValue(1, showVariables: true, allowDuplicates: true)]
[Required]
public List<KeyValuePair<string, string>> MatchConditions { get; set; }
/// <inheritdoc />
public override int Execute(NodeParameters args)
{
if (MatchConditions?.Any() != true)
{
args.FailureReason = "No matches defined";
args.Logger.ELog(args.FailureReason);
return -1;
}
foreach (var match in MatchConditions)
{
try
{
object value;
if (Regex.IsMatch(match.Key, @"\{[\w\d\.-]+\}") &&
args.Variables.TryGetValue(match.Key[1..^1], out var varValue))
value = varValue;
else
value = args.ReplaceVariables(match.Key, stripMissing: true);
if (args.MathHelper.IsMathOperation(match.Value))
{
string strValue = value?.ToString()?.Trim() ?? string.Empty;
if (args.MathHelper.IsFalse(match.Value, strValue))
{
args.Logger?.ILog($"Did not match found '{match.Value}' = {strValue}");
return 2;
}
args.Logger?.ILog($"Did match found '{match.Value}' = {strValue}");
continue;
}
if (args.StringHelper.Matches(match.Value, value) == false)
{
args.Logger?.ILog($"Did not match found '{match.Value}' = {value}");
return 2;
}
args.Logger?.ILog($"Did match found '{match.Value}' = {value}");
}
catch (Exception ex)
{
// Ignored
args.Logger?.ILog($"Error matching match found '{match.Value}': {ex.Message}");
return 2;
}
}
args.Logger?.ILog("All matches passed");
return 1;
}
}

View File

@@ -0,0 +1,135 @@
#if(DEBUG)
using FileFlows.BasicNodes.Functions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace BasicNodes.Tests;
[TestClass]
public class MatchAllTests: TestBase
{
[TestMethod]
public void MatchesAll_AllMatch()
{
MatchesAll ele = new();
ele.MatchConditions = new()
{
new("{file.Size}", "<=100KB"),
new("{file.Size}", ">50KB")
};
var args = new FileFlows.Plugin.NodeParameters(null, Logger,
false, string.Empty, new LocalFileService());
args.Variables["file.Size"] = 80_000; // 80KB
var result = ele.Execute(args);
Assert.AreEqual(1, result); // All conditions match
}
[TestMethod]
public void MatchesAll_NotAllMatch()
{
MatchesAll ele = new();
ele.MatchConditions = new()
{
new("{file.Size}", "<=100KB"),
new("{file.Size}", ">100KB")
};
var args = new FileFlows.Plugin.NodeParameters(null, Logger,
false, string.Empty, new LocalFileService());
args.Variables["file.Size"] = 80_000; // 80KB
var result = ele.Execute(args);
Assert.AreEqual(2, result); // Not all conditions match
}
[TestMethod]
public void MatchesAll_MatchFailString()
{
MatchesAll ele = new();
ele.MatchConditions = new()
{
new("{file.Size}", "<=100KB"),
new("{file.Size}", ">50KB")
};
var args = new FileFlows.Plugin.NodeParameters(null, Logger,
false, string.Empty, new LocalFileService());
args.Variables["file.Size"] = "Invalid String";
var result = ele.Execute(args);
Assert.AreEqual(2, result); // Should fail because the value is not numeric
}
[TestMethod]
public void MatchesAll_True()
{
MatchesAll ele = new();
ele.MatchConditions = new()
{
new("{file.Deleted}", "true"),
new("{file.Size}", ">0")
};
var args = new FileFlows.Plugin.NodeParameters(null, Logger,
false, string.Empty, new LocalFileService());
args.Variables["file.Deleted"] = true;
args.Variables["file.Size"] = 50_000;
var result = ele.Execute(args);
Assert.AreEqual(1, result); // Both conditions pass
}
[TestMethod]
public void MatchesAll_False()
{
MatchesAll ele = new();
ele.MatchConditions = new()
{
new("{file.Deleted}", "true"),
new("{file.Size}", "<0")
};
var args = new FileFlows.Plugin.NodeParameters(null, Logger,
false, string.Empty, new LocalFileService());
args.Variables["file.Deleted"] = true;
args.Variables["file.Size"] = 50_000;
var result = ele.Execute(args);
Assert.AreEqual(2, result); // Second condition fails
}
[TestMethod]
public void MatchesAll_Regex()
{
MatchesAll ele = new();
ele.MatchConditions = new()
{
new("{file.Name}", "/.*batman.*/"),
new("{file.Name}", "/.*superman.*/")
};
var args = new FileFlows.Plugin.NodeParameters(null, Logger,
false, string.Empty, new LocalFileService());
args.Variables["file.Name"] = "Superman vs Batman (2017)";
var result = ele.Execute(args);
Assert.AreEqual(1, result); // Both regex conditions pass
}
[TestMethod]
public void MatchesAll_NoMatch()
{
MatchesAll ele = new();
ele.MatchConditions = new()
{
new("{file.Name}", "triggerthis"),
new("{file.Deleted}", "true")
};
var args = new FileFlows.Plugin.NodeParameters(null, Logger,
false, string.Empty, new LocalFileService());
args.Variables["file.Name"] = "Nothing";
args.Variables["file.Deleted"] = false;
var result = ele.Execute(args);
Assert.AreEqual(2, result); // Both conditions fail
}
}
#endif

View File

@@ -395,6 +395,28 @@
"CompressionMethod-Help": "Als Komprimierungsmethode wird LZMA2 empfohlen."
}
},
"Matches": {
"Description": "Vergleicht eine Menge von Werten und prüft die Bedingungen, um zu sehen, welche Ausgabe aufgerufen werden soll.",
"Fields": {
"MatchConditions": "",
"MatchConditionsKey": "Wert",
"MatchConditionsValue": "Ausdruck",
"MatchConditionsHelp": "Die Bedingungen, die getestet werden, um zu bestimmen, welche Ausgabe aufgerufen werden soll."
}
},
"MatchesAll": {
"Description": "Vergleicht eine Menge von Werten und prüft, ob alle Bedingungen übereinstimmen.",
"Fields": {
"MatchConditions": "",
"MatchConditionsKey": "Wert",
"MatchConditionsValue": "Ausdruck",
"MatchConditionsHelp": "Die Bedingungen, die geprüft werden, um festzustellen, welche Ausgabe aufgerufen werden soll."
},
"Outputs": {
"1": "Alle Bedingungen stimmen überein",
"2": "Nicht alle Bedingungen stimmen überein"
}
},
"IfBoolean": {
"Description": "Testet, ob eine Variable wahr oder falsch ist",
"Outputs": {

View File

@@ -410,6 +410,19 @@
"MatchConditions-Help": "The matches to test which output should be called."
}
},
"MatchesAll": {
"Description": "Compares a set of values and checks if all conditions match.",
"Fields": {
"MatchConditions": "",
"MatchConditionsKey": "Value",
"MatchConditionsValue": "Expression",
"MatchConditionsHelp": "The conditions to test, determining which output should be called."
},
"Outputs": {
"1": "All conditions match",
"2": "Not all conditions match"
}
},
"MoveFolder": {
"Description": "Moves a folder",
"Outputs": {