Skip to content

Commit

Permalink
fix(flags): Handle bool value matching (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
neilkakkar authored Mar 22, 2024
1 parent dd92839 commit b520772
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 7 deletions.
23 changes: 16 additions & 7 deletions lib/FeatureFlag.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ public static function matchProperty($property, $propertyValues)
}

if ($operator == "icontains") {
return strpos(strtolower(strval($overrideValue)), strtolower(strval($value))) !== false;
return strpos(strtolower(FeatureFlag::valueToString($overrideValue)), strtolower(FeatureFlag::valueToString($value))) !== false;
}

if ($operator == "not_icontains") {
return strpos(strtolower(strval($overrideValue)), strtolower(strval($value))) == false;
return strpos(strtolower(FeatureFlag::valueToString($overrideValue)), strtolower(FeatureFlag::valueToString($value))) == false;
}

if (in_array($operator, ["regex", "not_regex"])) {
Expand All @@ -65,12 +65,12 @@ public static function matchProperty($property, $propertyValues)

if (!is_null($parsedValue) && !is_null($overrideValue)) {
if (is_string($overrideValue)) {
return FeatureFlag::compare($overrideValue, strval($value), $operator);
return FeatureFlag::compare($overrideValue, FeatureFlag::valueToString($value), $operator);
} else {
return FeatureFlag::compare($overrideValue, $parsedValue, $operator, "numeric");
}
} else {
return FeatureFlag::compare(strval($overrideValue), strval($value), $operator);
return FeatureFlag::compare(FeatureFlag::valueToString($overrideValue), FeatureFlag::valueToString($value), $operator);
}
}

Expand Down Expand Up @@ -246,9 +246,18 @@ private static function convertToDateTime($value) {
private static function computeExactMatch($value, $overrideValue)
{
if (is_array($value)) {
return in_array(strtolower(strval($overrideValue)), array_map('strtolower', $value));
return in_array(strtolower(FeatureFlag::valueToString($overrideValue)), array_map('strtolower', array_map(fn($val) => FeatureFlag::valueToString($val) , $value)));
}
return strtolower(FeatureFlag::valueToString($value)) == strtolower(FeatureFlag::valueToString($overrideValue));
}

private static function valueToString($value)
{
if (is_bool($value)) {
return $value ? "true" : "false";
} else {
return strval($value);
}
return strtolower(strval($value)) == strtolower(strval($overrideValue));
}

private static function compare($lhs, $rhs, $operator, $type = "string")
Expand Down
73 changes: 73 additions & 0 deletions test/FeatureFlagTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,79 @@ public function testFlagPersonProperties()
$this->checkEmptyErrorLogs();
}

public function testFlagPersonBooleanProperties()
{
$this->http_client = new MockedHttpClient(host: "app.posthog.com", flagEndpointResponse: MockedResponses::LOCAL_EVALUATION_BOOLEAN_REQUEST);

$this->client = new Client(
self::FAKE_API_KEY,
[
"debug" => true,
],
$this->http_client,
"test"
);

PostHog::init(null, null, $this->client);

$this->assertTrue(PostHog::getFeatureFlag('person-flag', 'some-distinct-id', [], ["region" => "true", "region_array" => "true"], [], true, false));

PostHog::flush();
$this->assertEquals(
$this->http_client->calls,
array(
0 => array(
"path" => "/api/feature_flag/local_evaluation?send_cohorts&token=random_key",
"payload" => null,
"extraHeaders" => array(0 => 'User-Agent: posthog-php/3.0.3', 1 => 'Authorization: Bearer test'),
"requestOptions" => array(),
),
// no decide or capture calls
)
);

$this->checkEmptyErrorLogs();

// reset calls
$this->http_client->calls = array();

$this->assertTrue(PostHog::getFeatureFlag('person-flag', 'some-distinct-id', [], ["region" => "true", "region_array" => true], [], true, false));
$this->assertTrue(PostHog::getFeatureFlag('person-flag', 'some-distinct-id', [], ["region" => true, "region_array" => true], [], true, false));
$this->assertTrue(PostHog::getFeatureFlag('person-flag', 'some-distinct-id', [], ["region" => true, "region_array" => "true"], [], true, false));
$this->assertFalse(PostHog::getFeatureFlag('person-flag', 'some-distinct-id', [], ["region" => 1, "region_array" => "1"], [], true, false));
$this->assertFalse(PostHog::getFeatureFlag('person-flag', 'some-distinct-id', [], ["region" => true, "region_array" => "1"], [], true, false));
$this->assertFalse(PostHog::getFeatureFlag('person-flag', 'some-distinct-id', [], ["region" => "1", "region_array" => "true"], [], true, false));

$this->assertEquals(
$this->http_client->calls,
array()
// no decide or capture calls
);

$this->assertTrue(PostHog::getFeatureFlag('person-flag-with-boolean', 'some-distinct-id', [], ["region" => "true", "region_array" => true], [], true, false));
$this->assertTrue(PostHog::getFeatureFlag('person-flag-with-boolean', 'some-distinct-id', [], ["region" => "true", "region_array" => true], [], true, false));
$this->assertTrue(PostHog::getFeatureFlag('person-flag-with-boolean', 'some-distinct-id', [], ["region" => true, "region_array" => true], [], true, false));
$this->assertTrue(PostHog::getFeatureFlag('person-flag-with-boolean', 'some-distinct-id', [], ["region" => true, "region_array" => "true"], [], true, false));
$this->assertFalse(PostHog::getFeatureFlag('person-flag-with-boolean', 'some-distinct-id', [], ["region" => true, "region_array" => "false"], [], true, false));
$this->assertFalse(PostHog::getFeatureFlag('person-flag-with-boolean', 'some-distinct-id', [], ["region" => false, "region_array" => "true"], [], true, false));

$this->assertEquals(
$this->http_client->calls,
array()
// no decide or capture calls
);

$this->assertTrue(PostHog::getFeatureFlag('person-flag-with-boolean-icontains', 'some-distinct-id', [], ["region" => "true", "region_array" => true], [], true, false));
$this->assertTrue(PostHog::getFeatureFlag('person-flag-with-boolean-icontains', 'some-distinct-id', [], ["region" => true, "region_array" => true], [], true, false));
$this->assertFalse(PostHog::getFeatureFlag('person-flag-with-boolean-icontains', 'some-distinct-id', [], ["region" => false, "region_array" => "true"], [], true, false));

$this->assertEquals(
$this->http_client->calls,
array()
// no decide or capture calls
);
}

public function testFlagGroupProperties()
{
$this->http_client = new MockedHttpClient(host: "app.posthog.com", flagEndpointResponse: MockedResponses::LOCAL_EVALUATION_GROUP_PROPERTIES_REQUEST);
Expand Down
92 changes: 92 additions & 0 deletions test/assests/MockedResponses.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,98 @@ class MockedResponses
],
];

public const LOCAL_EVALUATION_BOOLEAN_REQUEST = [
'count' => 1,
'next' => null,
'previous' => null,
'flags' => [
[
"id" => 1,
"name" => "",
"key" => "person-flag",
"filters" => [
"groups" => [
[
"properties" => [
[
"key" => "region_array",
"value" => ["true"],
"operator" => "exact",
"type" => "person"
],
[
"key" => "region",
"value" => "true",
"operator" => "exact",
"type" => "person"
],
],
"rollout_percentage" => 100
]
]
],
"deleted" => false,
"active" => true,
"is_simple_flag" => true,
"rollout_percentage" => null
],
[
"id" => 2,
"name" => "",
"key" => "person-flag-with-boolean",
"filters" => [
"groups" => [
[
"properties" => [
[
"key" => "region_array",
"value" => [true],
"operator" => "exact",
"type" => "person"
],
[
"key" => "region",
"value" => true,
"operator" => "exact",
"type" => "person"
],
],
"rollout_percentage" => 100
]
]
],
"deleted" => false,
"active" => true,
"is_simple_flag" => true,
"rollout_percentage" => null
],
[
"id" => 2,
"name" => "",
"key" => "person-flag-with-boolean-icontains",
"filters" => [
"groups" => [
[
"properties" => [
[
"key" => "region",
"value" => true,
"operator" => "icontains",
"type" => "person"
],
],
"rollout_percentage" => 100
]
]
],
"deleted" => false,
"active" => true,
"is_simple_flag" => true,
"rollout_percentage" => null
]
],
];

public const LOCAL_EVALUATION_MULTIPLE_REQUEST = [
'count' => 2,
'next' => null,
Expand Down

0 comments on commit b520772

Please sign in to comment.