Skip to content

Commit

Permalink
Merge pull request #24 from NatVanG/drillthroughjsonpointer
Browse files Browse the repository at this point in the history
Drillthrough jsonpointer in rules data mapping part.
NatVanG authored Nov 19, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents a6caee9 + cf63b62 commit d6dd501
Showing 11 changed files with 941 additions and 137 deletions.
86 changes: 86 additions & 0 deletions PBIXInspectorLibrary/CustomRules/SetDifferenceRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using Json.Logic;
using Json.More;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;


namespace PBIXInspectorLibrary.CustomRules;

/// <summary>
/// Handles the `diff` operation.
/// </summary>
[Operator("diff")]
[JsonConverter(typeof(SetDifferenceRuleJsonConverter))]
public class SetDifferenceRule : Json.Logic.Rule
{
internal Json.Logic.Rule Set1 { get; }
internal Json.Logic.Rule Set2 { get; }

public SetDifferenceRule(Json.Logic.Rule set1, Json.Logic.Rule set2)
{
Set1 = set1;
Set2 = set2;
}

/// <summary>
/// Applies the rule to the input data.
/// </summary>
/// <param name="data">The input data.</param>
/// <param name="contextData">
/// Optional secondary data. Used by a few operators to pass a secondary
/// data context to inner operators.
/// </param>
/// <returns>The result of the rule.</returns>
public override JsonNode? Apply(JsonNode? data, JsonNode? contextData = null)
{
var set1 = Set1.Apply(data, contextData);
var set2 = Set2.Apply(data, contextData);

if (set1 is not JsonArray || set2 is not JsonArray)
return new JsonArray();

var arr1 = (JsonArray)set1;
var arr2 = (JsonArray)set2;

var difference = new JsonArray();

foreach (var item in arr1)
{
if (!arr2.Any(x => item.IsEquivalentTo(x)))
{
var copy = item.Copy();
if (!difference.Any(x => x.IsEquivalentTo(copy)))
{
difference.Add(copy);
}
}
}

return difference;
}
}

internal class SetDifferenceRuleJsonConverter : JsonConverter<SetDifferenceRule>
{
public override SetDifferenceRule? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var parameters = JsonSerializer.Deserialize<Json.Logic.Rule[]>(ref reader, options);

if (parameters is not { Length: 2 })
throw new JsonException("The difference rule needs an array with 2 parameters.");

return new SetDifferenceRule(parameters[0], parameters[1]);
}

public override void Write(Utf8JsonWriter writer, SetDifferenceRule value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName("difference");
writer.WriteStartArray();
writer.WriteRule(value.Set1, options);
writer.WriteRule(value.Set2, options);
writer.WriteEndArray();
writer.WriteEndObject();
}
}
90 changes: 90 additions & 0 deletions PBIXInspectorLibrary/CustomRules/SetEqualRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using Json.Logic;
using Json.More;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;


namespace PBIXInspectorLibrary.CustomRules;

/// <summary>
/// Handles the `equalsets` operation.
/// </summary>
[Operator("equalsets")]
[JsonConverter(typeof(SetEqualRuleJsonConverter))]
public class SetEqualRule : Json.Logic.Rule
{
internal Json.Logic.Rule Set1 { get; }
internal Json.Logic.Rule Set2 { get; }

public SetEqualRule(Json.Logic.Rule set1, Json.Logic.Rule set2)
{
Set1 = set1;
Set2 = set2;
}

/// <summary>
/// Applies the rule to the input data.
/// </summary>
/// <param name="data">The input data.</param>
/// <param name="contextData">
/// Optional secondary data. Used by a few operators to pass a secondary
/// data context to inner operators.
/// </param>
/// <returns>The result of the rule.</returns>
public override JsonNode? Apply(JsonNode? data, JsonNode? contextData = null)
{
var set1 = Set1.Apply(data, contextData);
var set2 = Set2.Apply(data, contextData);

if (set1 is not JsonArray || set2 is not JsonArray)
return new JsonArray();

var arr1 = (JsonArray)set1;
var arr2 = (JsonArray)set2;

var symmetricDifference = new JsonArray();

foreach (var item in arr1)
{
if (!arr2.Any(x => item.IsEquivalentTo(x)))
{
return false;
}
}

foreach (var item in arr2)
{
if (!arr1.Any(x => item.IsEquivalentTo(x)))
{
return false;
}
}

return true;
}
}

internal class SetEqualRuleJsonConverter : JsonConverter<SetEqualRule>
{
public override SetEqualRule? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var parameters = JsonSerializer.Deserialize<Json.Logic.Rule[]>(ref reader, options);

if (parameters is not { Length: 2 })
throw new JsonException("The symdiff rule needs an array with 2 parameters.");

return new SetEqualRule(parameters[0], parameters[1]);
}

public override void Write(Utf8JsonWriter writer, SetEqualRule value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName("symdiff");
writer.WriteStartArray();
writer.WriteRule(value.Set1, options);
writer.WriteRule(value.Set2, options);
writer.WriteEndArray();
writer.WriteEndObject();
}
}
86 changes: 86 additions & 0 deletions PBIXInspectorLibrary/CustomRules/SetIntersectionRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using Json.Logic;
using Json.More;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;


namespace PBIXInspectorLibrary.CustomRules;

/// <summary>
/// Handles the `intersection` operation.
/// </summary>
[Operator("intersection")]
[JsonConverter(typeof(SetIntersectionRuleJsonConverter))]
public class SetIntersectionRule : Json.Logic.Rule
{
internal Json.Logic.Rule Set1 { get; }
internal Json.Logic.Rule Set2 { get; }

public SetIntersectionRule(Json.Logic.Rule set1, Json.Logic.Rule set2)
{
Set1 = set1;
Set2 = set2;
}

/// <summary>
/// Applies the rule to the input data.
/// </summary>
/// <param name="data">The input data.</param>
/// <param name="contextData">
/// Optional secondary data. Used by a few operators to pass a secondary
/// data context to inner operators.
/// </param>
/// <returns>The result of the rule.</returns>
public override JsonNode? Apply(JsonNode? data, JsonNode? contextData = null)
{
var set1 = Set1.Apply(data, contextData);
var set2 = Set2.Apply(data, contextData);

if (set1 is not JsonArray || set2 is not JsonArray)
return new JsonArray();

var arr1 = (JsonArray)set1;
var arr2 = (JsonArray)set2;

var intersection = new JsonArray();

foreach (var item in arr1)
{
if (arr2.Any(x => item.IsEquivalentTo(x)))
{
var copy = item.Copy();
if (!intersection.Any(x => x.IsEquivalentTo(copy)))
{
intersection.Add(copy);
}
}
}

return intersection;
}
}

internal class SetIntersectionRuleJsonConverter : JsonConverter<SetIntersectionRule>
{
public override SetIntersectionRule? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var parameters = JsonSerializer.Deserialize<Json.Logic.Rule[]>(ref reader, options);

if (parameters is not { Length: 2 })
throw new JsonException("The intersection rule needs an array with 2 parameters.");

return new SetIntersectionRule(parameters[0], parameters[1]);
}

public override void Write(Utf8JsonWriter writer, SetIntersectionRule value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName("intersection");
writer.WriteStartArray();
writer.WriteRule(value.Set1, options);
writer.WriteRule(value.Set2, options);
writer.WriteEndArray();
writer.WriteEndObject();
}
}
98 changes: 98 additions & 0 deletions PBIXInspectorLibrary/CustomRules/SetSymmetricDifferenceRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using Json.Logic;
using Json.More;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;


namespace PBIXInspectorLibrary.CustomRules;

/// <summary>
/// Handles the `symdiff` operation.
/// </summary>
[Operator("symdiff")]
[JsonConverter(typeof(SetSymmetricDifferenceRuleJsonConverter))]
public class SetSymmetricDifferenceRule : Json.Logic.Rule
{
internal Json.Logic.Rule Set1 { get; }
internal Json.Logic.Rule Set2 { get; }

public SetSymmetricDifferenceRule(Json.Logic.Rule set1, Json.Logic.Rule set2)
{
Set1 = set1;
Set2 = set2;
}

/// <summary>
/// Applies the rule to the input data.
/// </summary>
/// <param name="data">The input data.</param>
/// <param name="contextData">
/// Optional secondary data. Used by a few operators to pass a secondary
/// data context to inner operators.
/// </param>
/// <returns>The result of the rule.</returns>
public override JsonNode? Apply(JsonNode? data, JsonNode? contextData = null)
{
var set1 = Set1.Apply(data, contextData);
var set2 = Set2.Apply(data, contextData);

if (set1 is not JsonArray || set2 is not JsonArray)
return new JsonArray();

var arr1 = (JsonArray)set1;
var arr2 = (JsonArray)set2;

var symmetricDifference = new JsonArray();

foreach (var item in arr1)
{
if (!arr2.Any(x => item.IsEquivalentTo(x)))
{
var copy = item.Copy();
if (!symmetricDifference.Any(x => x.IsEquivalentTo(copy)))
{
symmetricDifference.Add(copy);
}
}
}

foreach (var item in arr2)
{
if (!arr1.Any(x => item.IsEquivalentTo(x)))
{
var copy = item.Copy();
if (!symmetricDifference.Any(x => x.IsEquivalentTo(copy)))
{
symmetricDifference.Add(copy);
}
}
}

return symmetricDifference;
}
}

internal class SetSymmetricDifferenceRuleJsonConverter : JsonConverter<SetSymmetricDifferenceRule>
{
public override SetSymmetricDifferenceRule? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var parameters = JsonSerializer.Deserialize<Json.Logic.Rule[]>(ref reader, options);

if (parameters is not { Length: 2 })
throw new JsonException("The symdiff rule needs an array with 2 parameters.");

return new SetSymmetricDifferenceRule(parameters[0], parameters[1]);
}

public override void Write(Utf8JsonWriter writer, SetSymmetricDifferenceRule value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName("symdiff");
writer.WriteStartArray();
writer.WriteRule(value.Set1, options);
writer.WriteRule(value.Set2, options);
writer.WriteEndArray();
writer.WriteEndObject();
}
}
92 changes: 92 additions & 0 deletions PBIXInspectorLibrary/CustomRules/SetUnionRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using Json.Logic;
using Json.More;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;


namespace PBIXInspectorLibrary.CustomRules;

/// <summary>
/// Handles the `union` operation.
/// </summary>
[Operator("union")]
[JsonConverter(typeof(SetUnionRuleJsonConverter))]
public class SetUnionRule : Json.Logic.Rule
{
internal Json.Logic.Rule Set1 { get; }
internal Json.Logic.Rule Set2 { get; }

public SetUnionRule(Json.Logic.Rule set1, Json.Logic.Rule set2)
{
Set1 = set1;
Set2 = set2;
}

/// <summary>
/// Applies the rule to the input data.
/// </summary>
/// <param name="data">The input data.</param>
/// <param name="contextData">
/// Optional secondary data. Used by a few operators to pass a secondary
/// data context to inner operators.
/// </param>
/// <returns>The result of the rule.</returns>
public override JsonNode? Apply(JsonNode? data, JsonNode? contextData = null)
{
var set1 = Set1.Apply(data, contextData);
var set2 = Set2.Apply(data, contextData);

if (set1 is not JsonArray || set2 is not JsonArray)
return new JsonArray();

var arr1 = (JsonArray)set1;
var arr2 = (JsonArray)set2;

var union = new JsonArray();

foreach (var item in arr1)
{
var copy = item.Copy();
if (!union.Any(x => x.IsEquivalentTo(copy)))
{
union.Add(copy);
}
}

foreach (var item in arr2)
{
var copy = item.Copy();
if (!union.Any(x => x.IsEquivalentTo(copy)))
{
union.Add(copy);
}
}

return union;
}
}

internal class SetUnionRuleJsonConverter : JsonConverter<SetUnionRule>
{
public override SetUnionRule? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var parameters = JsonSerializer.Deserialize<Json.Logic.Rule[]>(ref reader, options);

if (parameters is not { Length: 2 })
throw new JsonException("The union rule needs an array with 2 parameters.");

return new SetUnionRule(parameters[0], parameters[1]);
}

public override void Write(Utf8JsonWriter writer, SetUnionRule value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName("union");
writer.WriteStartArray();
writer.WriteRule(value.Set1, options);
writer.WriteRule(value.Set2, options);
writer.WriteEndArray();
writer.WriteEndObject();
}
}
158 changes: 62 additions & 96 deletions PBIXInspectorLibrary/Inspector.cs
Original file line number Diff line number Diff line change
@@ -19,9 +19,9 @@ public class Inspector : InspectorBase
private const string FILTEREXPRESSIONMARKER = "?";
private const string JSONPOINTERSTART = "/";
private const string CONTEXTARRAY = ".";
internal const char DRILLCHAR = '>';

private string _pbiFilePath, _rulesFilePath;
//private PbiFile _pbiFile;
private InspectionRules? _inspectionRules;

public event EventHandler<MessageIssuedEventArgs>? MessageIssued;
@@ -75,12 +75,6 @@ public Inspector(string pbiFilePath, string rulesFilePath) : base(pbiFilePath, r

private PbiFile InitPbiFile(string pbiFilePath)
{
//if (!File.Exists(pbiFilePath))
//{
// throw new PBIXInspectorException(string.Format("The PBI file with path \"{0}\" does not exist.", pbiFilePath));
//}
//else
//{
switch (PbiFile.PBIFileType(pbiFilePath))
{
case PbiFile.PBIFileTypeEnum.PBIX:
@@ -94,7 +88,6 @@ private PbiFile InitPbiFile(string pbiFilePath)
default:
throw new PBIXInspectorException(string.Format("Could not determine the extension of PBI file with path \"{0}\".", pbiFilePath));
}
//}
}

private void AddCustomRulesToRegistry()
@@ -117,7 +110,11 @@ private void AddCustomRulesToRegistry()
Json.Logic.RuleRegistry.AddRule<CustomRules.ToRecordRule>();
Json.Logic.RuleRegistry.AddRule<CustomRules.DrillVariableRule>();
Json.Logic.RuleRegistry.AddRule<CustomRules.RectOverlapRule>();

Json.Logic.RuleRegistry.AddRule<CustomRules.SetIntersectionRule>();
Json.Logic.RuleRegistry.AddRule<CustomRules.SetUnionRule>();
Json.Logic.RuleRegistry.AddRule<CustomRules.SetDifferenceRule>();
Json.Logic.RuleRegistry.AddRule<CustomRules.SetSymmetricDifferenceRule>();
Json.Logic.RuleRegistry.AddRule<CustomRules.SetEqualRule>();
}

/// <summary>
@@ -219,7 +216,9 @@ public IEnumerable<TestResult> Inspect()

bool result = false;

var newdata = MapRuleDataPointersToValues(contextNodeArray, rule, contextNodeArray);
//HACK: checking if the rule's intention is to return an array or a single object
var node = rule.Path.Contains("*") || rule.Path.Contains("?") ? contextNodeArray : (contextNodeArray != null ? contextNodeArray.FirstOrDefault() : null);
var newdata = MapRuleDataPointersToValues(node, rule, contextNodeArray);

//TODO: the following commented line does not work with the variableRule implementation with context array passed in.
//var jruleresult = jrule.Apply(newdata, contextNodeArray);
@@ -398,81 +397,6 @@ private JsonArray ConvertToJsonArray(List<JToken>? tokens)
return tokens;
}

/*
private JToken? ExecuteTokenPath(JToken jo, string ruleName, string rulePath, bool rulePathErrorWhenNoMatch)
{
string parentPath, queryPath = string.Empty;
JToken? token = new JToken();
//TODO: a regex match to extract the substring would be better
if (rulePath.Contains(SUBJPATHSTART)) //check for subpath syntax
{
if (rulePath.EndsWith(SUBJPATHEND))
{
//TODO: currently subpath is assumed to be the last path (i.e. the whole string end in "})" but we should be able to resolve inner subpath and return to parent path
var index = rulePath.IndexOf(SUBJPATHSTART);
parentPath = rulePath.Substring(0, index);
queryPath = rulePath.Substring(index + SUBJPATHSTART.Length, rulePath.Length - (index + SUBJPATHSTART.Length) - 1);
var parentTokens = SelectTokens(jo, ruleName, parentPath, rulePathErrorWhenNoMatch);
if (parentTokens == null || parentTokens.Count() == 0) { return token; }
if (parentPath.Contains(FILTEREXPRESSIONMARKER))
{
JArray ja = new JArray();
foreach (var t in parentTokens)
{
//HACK: why do I have to parse a token into a token to make the subsequent SelectTokens call work?
var jt = JToken.Parse(t.ToString());
ja.Add(jt);
}
token = ja.SelectTokens(queryPath, rulePathErrorWhenNoMatch);
}
else
{
foreach (var t in parentTokens)
{
//var childtokens = SelectTokens((JObject?)t, rule.Name, childPath, rule.PathErrorWhenNoMatch); //TODO: this seems better but throws InvalidCastException
var childtokens = SelectTokens(((JObject)JToken.Parse(t.ToString())), ruleName, queryPath, rulePathErrorWhenNoMatch);
//only return children tokens, the reference to parent tokens is lost.
if (childtokens != null) tokens.AddRange(childtokens.ToList());
}
}
}
else
{
throw new PBIXInspectorException(string.Format("Path \"{0}\" needs to end with \"{1}\" as it contains a subpath.", rulePath, "}"));
}
}
else
{
tokens = SelectTokens(jo, ruleName, rulePath, rulePathErrorWhenNoMatch)?.ToList();
}
return tokens;
}
*/

/*
private IEnumerable<JToken>? SelectTokens(JObject? jo, string ruleName, string rulePath, bool rulePathErrorWhenNoMatch)
{
IEnumerable<JToken>? tokens;
//TODO: for some reason I can't catch Newtonsoft.Json.JsonException when rule.PathErrorWhenNoMatch is true
tokens = jo.SelectTokens(rulePath, false);
if (tokens == null || tokens.Count() == 0)
{
var msgType = rulePathErrorWhenNoMatch ? MessageTypeEnum.Error : MessageTypeEnum.Information;
OnMessageIssued(msgType, string.Format("Rule \"{0}\" with JPath \"{1}\" did not return any tokens.", ruleName, rulePath));
}
return tokens;
}
*/

private IEnumerable<JToken>? SelectTokens(JToken? jo, string ruleName, string rulePath, bool rulePathErrorWhenNoMatch)
{
IEnumerable<JToken>? tokens;
@@ -514,21 +438,14 @@ private JsonArray ConvertToJsonArray(List<JToken>? tokens)
{
if (item.Value is JsonValue)
{

var value = item.Value.AsValue().Stringify();
//TODO: enable navigation to parent path
//while (value.StartsWith("."))
//{
// target = target.Parent;
// value = value.Substring(1, value.Length - 1);
//}

if (value.StartsWith(JSONPOINTERSTART)) //check for JsonPointer syntax
{
try
{
var pointer = JsonPointer.Parse(value);
var evalsuccess = pointer.TryEvaluate(target, out var newval);
//var pointer = JsonPointer.Parse(value);
//var evalsuccess = pointer.TryEvaluate(target, out var newval);
var evalsuccess = EvalPath(value, target, out var newval);
if (evalsuccess)
{
if (newval != null)
@@ -566,7 +483,7 @@ private JsonArray ConvertToJsonArray(List<JToken>? tokens)
}
}
}
else if (value.StartsWith(CONTEXTARRAY))
else if (value.Equals(CONTEXTARRAY))
{
//context array token was used so pass in the parent array
newdata.Add(new KeyValuePair<string, JsonNode?>(item.Key, contextNodeArray.Copy()));
@@ -595,6 +512,55 @@ private JsonArray ConvertToJsonArray(List<JToken>? tokens)
return newdata;
}

internal bool EvalPath(string pathString, JsonNode? data, out JsonNode? result)
{
if (pathString.Contains(DRILLCHAR))
{
var leftString = pathString.Substring(0, pathString.IndexOf(DRILLCHAR));
var rightString = pathString.Substring(pathString.IndexOf(DRILLCHAR) + 1);

var leftStringPath = string.Concat(leftString.StartsWith(JSONPOINTERSTART) ? string.Empty : JSONPOINTERSTART, leftString.Replace('.', '/'));
var pointer = JsonPointer.Parse(leftStringPath);
if (pointer.TryEvaluate(data, out result))
{
if (result is JsonValue val)
{
//remove single quotes from beginning and end of string if any.
string strVal;
if (val.ToString()!.StartsWith("'") && val.ToString()!.EndsWith("'"))
{
strVal = val.ToString()!.Substring(1, val.ToString()!.Length - 2);
}
else
{
strVal = val.ToString()!;
}

var pathEvalNode = JsonNode.Parse(strVal);
return EvalPath(rightString, pathEvalNode, out result);
}
else
{
return EvalPath(rightString, result, out result);
}
}
}
else if (pathString.Trim().Equals(CONTEXTARRAY))
{
result = data;
return true;
}
else
{
var pathStringPath = string.Concat(pathString.StartsWith(JSONPOINTERSTART) ? string.Empty : JSONPOINTERSTART, pathString.Replace('.', '/'));
var pointer = JsonPointer.Parse(pathStringPath);
return pointer.TryEvaluate(data, out result);
}

result = null;
return false;
}


private Encoding GetEncodingFromCodePage(int codePage)
{
179 changes: 178 additions & 1 deletion PBIXInspectorTests/CustomRulesTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using PBIXInspectorLibrary.CustomRules;
using Json.More;
using PBIXInspectorLibrary.CustomRules;
using System.Text.Json.Nodes;

namespace PBIXInspectorTests
@@ -75,6 +76,182 @@ public void StringContainsNoMatchTest()
var result = rule.Apply(null);
Assert.That((int)result.AsValue(), Is.EqualTo(0));
}

[Test]
public void SetIntersectionTest1()
{
var arr1 = "[\"a\",\"b\"]";
var arr2 = "[\"b\",\"c\"]";

var expected = "[\"b\"]";

var rule = new SetIntersectionRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That(result.IsEquivalentTo(JsonNode.Parse(expected)));
}

[Test]
public void SetIntersectionTest2()
{
var arr1 = "[\"a\",\"b\",\"c\"]";
var arr2 = "[\"b\",\"c\",\"d\"]";

var expected = "[\"b\", \"c\"]";

var rule = new SetIntersectionRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That(result.IsEquivalentTo(JsonNode.Parse(expected)));
}

[Test]
public void SetIntersectionTest3()
{
var arr1 = "[\"a\",\"b\",\"c\"]";
var arr2 = "[\"d\",\"e\",\"f\"]";

var expected = "[]";

var rule = new SetIntersectionRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That(result.IsEquivalentTo(JsonNode.Parse(expected)));
}

[Test]
public void SetIntersectionTest4()
{
var arr1 = "[\"d\",\"e\",\"f\"]";
var arr2 = "[\"a\",\"b\",\"c\"]";

var expected = "[]";

var rule = new SetIntersectionRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That(result.IsEquivalentTo(JsonNode.Parse(expected)));
}

[Test]
public void SetUnionTest1()
{
var arr1 = "[\"a\",\"b\",\"c\"]";
var arr2 = "[\"d\",\"e\",\"f\"]";

var expected = "[\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]";

var rule = new SetUnionRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That(result.IsEquivalentTo(JsonNode.Parse(expected)));
}

[Test]
public void SetUnionTest2()
{
var arr1 = "[]";
var arr2 = "[\"d\",\"e\",\"f\"]";

var expected = "[\"d\",\"e\",\"f\"]";

var rule = new SetUnionRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That(result.IsEquivalentTo(JsonNode.Parse(expected)));
}

[Test]
public void SetUnionTest3()
{
var arr1 = "[\"a\",\"b\",\"c\"]";
var arr2 = "[]";

var expected = "[\"a\",\"b\",\"c\"]";

var rule = new SetUnionRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That(result.IsEquivalentTo(JsonNode.Parse(expected)));
}

[Test]
public void SetUnionTest4()
{
var arr1 = "[\"a\",\"b\",\"c\",\"a\"]";
var arr2 = "[]";

var expected = "[\"a\",\"b\",\"c\"]";

var rule = new SetUnionRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That(result.IsEquivalentTo(JsonNode.Parse(expected)));
}

[Test]
public void SetUnionTest5()
{
var arr1 = "[\"a\",\"b\",\"c\",\"d\"]";
var arr2 = "[\"d\",\"e\",\"f\"]";

var expected = "[\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]";

var rule = new SetUnionRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That(result.IsEquivalentTo(JsonNode.Parse(expected)));
}

[Test]
public void SetDifferenceTest1()
{
var arr1 = "[\"a\",\"b\",\"c\"]";
var arr2 = "[\"c\",\"d\",\"e\"]";

var expected = "[\"a\",\"b\"]";

var rule = new SetDifferenceRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That(result.IsEquivalentTo(JsonNode.Parse(expected)));
}

[Test]
public void SetSymmetricDifferenceTest1()
{
var arr1 = "[\"a\",\"b\",\"c\"]";
var arr2 = "[\"c\",\"d\",\"e\"]";

var expected = "[\"a\",\"b\",\"d\",\"e\"]";

var rule = new SetSymmetricDifferenceRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That(result.IsEquivalentTo(JsonNode.Parse(expected)));
}

[Test]
public void SetEqualTest1()
{
var arr1 = "[\"a\",\"b\",\"c\"]";
var arr2 = "[\"c\",\"d\",\"e\"]";

var rule = new SetEqualRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That((bool)result.AsValue(), Is.False);
}

[Test]
public void SetEqualTest2()
{
var arr1 = "[\"a\",\"b\",\"c\"]";
var arr2 = "[\"a\",\"b\",\"c\"]";

var rule = new SetEqualRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That((bool)result.AsValue(), Is.True);
}

[Test]
public void SetEqualTest3()
{
var arr1 = "[\"a\",\"b\",\"c\"]";
var arr2 = "[\"c\",\"b\",\"a\"]";

var rule = new SetEqualRule(JsonNode.Parse(arr1), JsonNode.Parse(arr2));
var result = rule.Apply(null);
Assert.That((bool)result.AsValue(), Is.True);
}
#pragma warning restore CS8602
}
}
Binary file modified PBIXInspectorTests/Files/Inventory sample - fails.pbix
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -12,11 +12,11 @@
},
{
"name": "PBIDesktopVersion",
"value": "2.121.903.0 (23.09)"
"value": "2.123.684.0 (23.11)"
},
{
"name": "PBI_ProTooling",
"value": "[\"DevMode\"]"
"value": "[\"DevMode\",\"DaxQueryView_Desktop\"]"
}
],
"culture": "fr-FR",

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion PBIXInspectorWinForm/MainForm.Designer.cs

0 comments on commit d6dd501

Please sign in to comment.