Skip to content

Commit

Permalink
Merge pull request #25 from growthbook/fixing-eval-isin-failure
Browse files Browse the repository at this point in the history
Fixed differing null/empty evaluation during non-array IsIn condition
  • Loading branch information
Norhaven authored Feb 2, 2024
2 parents 57b6b0b + c23ec36 commit 1bbc78b
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.1]

- Fixed issue with empty string value sent to IsIn condition evaluation.

## [1.0.0]

- Fully implemented version 0.5.2 of the GrowthBook SDK spec.
Expand Down
63 changes: 63 additions & 0 deletions GrowthBook.Tests/CustomTests/RegressionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using Newtonsoft.Json;
using Xunit;

namespace GrowthBook.Tests.CustomTests;

public class RegressionTests : UnitTest
{
[Fact]
public void EvalIsInConditionShouldNotDifferWhenAttributeIsEmptyInsteadOfNull()
{
var featureJson = """
{
"defaultValue": false,
"rules": [
{
"condition": {
"userId": {
"$in": [
"ac1",
"ac2",
"ac3"
]
}
},
"force": true
}
]
}
""";

var feature = JsonConvert.DeserializeObject<Feature>(featureJson);

var staticFeatures = new Dictionary<string, Feature>
{
["test-in-op"] = feature
};

var context = new Context
{
Features = staticFeatures
};

var growthBook = new GrowthBook(context);

// The initial evaluation will use a null userId value.

var flag = growthBook.IsOn("test-in-op");
flag.Should().BeFalse("because the userId property in the attributes JSON is null");

// Try again with a userId that is an empty string instead.

context.Attributes.Add("userId", string.Empty);

var errorFlag = growthBook.IsOn("test-in-op");
errorFlag.Should().BeFalse("because an empty string is considered falsy and should not differ from the null case");
}
}
7 changes: 7 additions & 0 deletions GrowthBook/Extensions/JsonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ internal static class JsonExtensions
/// <returns>True if null, false otherwise.</returns>
public static bool IsNull(this JToken token) => token is null || token.Type == JTokenType.Null;

/// <summary>
/// Determines whether the <see cref="JToken"/> is either null, <see cref="JTokenType.Null"/>, an empty string, or whitespace.
/// </summary>
/// <param name="token">The JSON token to verify.</param>
/// <returns>True if null, empty, or whitespace, false otherwise.</returns>
public static bool IsNullOrWhitespace(this JToken token) => token.IsNull() || token.ToString().IsNullOrWhitespace();

/// <summary>
/// Gets the value of the named attribute key within the current <see cref="JObject"/>.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion GrowthBook/GrowthBook.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<RepositoryUrl>https://github.com/growthbook/growthbook-csharp.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>GrowthBook,A/B test,feature toggle,flag</PackageTags>
<Version>1.0.0</Version>
<Version>1.0.1</Version>
<Title>GrowthBook C# SDK</Title>
<PackageProjectUrl>https://www.growthbook.io/</PackageProjectUrl>
</PropertyGroup>
Expand Down
3 changes: 2 additions & 1 deletion GrowthBook/Providers/ConditionEvaluationProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using GrowthBook.Extensions;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;

Expand Down Expand Up @@ -383,7 +384,7 @@ private bool IsIn(JToken conditionValue, JToken actualValue)
return true;
}

if (conditionValue is null || actualValue is null)
if (conditionValue.IsNullOrWhitespace() || actualValue.IsNullOrWhitespace())
{
return false;
}
Expand Down

0 comments on commit 1bbc78b

Please sign in to comment.