Initial commit: CloudOps infrastructure platform

This commit is contained in:
root
2026-04-09 19:58:57 +02:00
commit 1166a52f26
7762 changed files with 839452 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Tests\Helper;
use Mautic\CoreBundle\Helper\CoreParametersHelper;
use Mautic\CoreBundle\Helper\PathsHelper;
use Mautic\CoreBundle\Twig\Helper\AssetsHelper;
use Mautic\CoreBundle\Twig\Helper\GravatarHelper;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Twig\Helper\AvatarHelper;
use Mautic\LeadBundle\Twig\Helper\DefaultAvatarHelper;
use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\Asset\Packages;
use Symfony\Component\HttpFoundation\RequestStack;
class AvatarHelperTest extends \PHPUnit\Framework\TestCase
{
private AssetsHelper $assetsHelperMock;
/**
* @var MockObject&PathsHelper
*/
private MockObject $pathsHelperMock;
private GravatarHelper $gravatarHelperMock;
private DefaultAvatarHelper $defaultAvatarHelperMock;
/**
* @var MockObject&Lead
*/
private MockObject $leadMock;
private AvatarHelper $avatarHelper;
protected function setUp(): void
{
$root = realpath(__DIR__.'/../../../../../');
/** @var Packages&MockObject $packagesMock */
$packagesMock = $this->createMock(Packages::class);
/** @var CoreParametersHelper&MockObject $coreParametersHelper */
$coreParametersHelper = $this->createMock(CoreParametersHelper::class);
$this->assetsHelperMock = new AssetsHelper($packagesMock);
$this->pathsHelperMock = $this->createMock(PathsHelper::class);
$this->pathsHelperMock->method('getSystemPath')
->willReturn('http://localhost');
$this->pathsHelperMock->method('getAssetsPath')
->willReturn($root.'/app/assets');
$this->pathsHelperMock->method('getMediaPath')
->willReturn($root.'/media');
$this->assetsHelperMock->setPathsHelper($this->pathsHelperMock);
$this->defaultAvatarHelperMock = new DefaultAvatarHelper($this->assetsHelperMock);
$this->gravatarHelperMock = new GravatarHelper($this->defaultAvatarHelperMock, $coreParametersHelper, $this->createMock(RequestStack::class));
$this->leadMock = $this->createMock(Lead::class);
$this->avatarHelper = new AvatarHelper($this->assetsHelperMock, $this->pathsHelperMock, $this->gravatarHelperMock, $this->defaultAvatarHelperMock);
}
/**
* Test to get gravatar.
*/
public function testGetAvatarWhenGravatar(): void
{
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
$_SERVER['SERVER_PORT'] = '80';
$_SERVER['SERVER_NAME'] = 'localhost';
$_SERVER['REQUEST_URI'] = 'localhost';
$this->leadMock->method('getPreferredProfileImage')
->willReturn('gravatar');
$this->leadMock->method('getSocialCache')
->willReturn([]);
$this->leadMock->method('getEmail')
->willReturn('mautic@acquia.com');
$avatar = $this->avatarHelper->getAvatar($this->leadMock);
$this->assertSame('https://www.gravatar.com/avatar/96f1b78c73c1ee806cf6a4168fe9bf77?s=250&d=http%3A%2F%2Flocalhost%2Fimages%2Favatar.png', $avatar, 'Gravatar image should be returned');
unset($_SERVER['SERVER_PROTOCOL']);
unset($_SERVER['SERVER_PORT']);
unset($_SERVER['SERVER_NAME']);
unset($_SERVER['REQUEST_URI']);
}
/**
* Test to get default image.
*/
public function testGetAvatarWhenDefault(): void
{
$this->leadMock->method('getPreferredProfileImage')
->willReturn('gravatar');
$this->leadMock->method('getSocialCache')
->willReturn([]);
$this->leadMock->method('getEmail')
->willReturn('');
$avatar = $this->avatarHelper->getAvatar($this->leadMock);
$this->assertSame('http://localhost/images/avatar.png', $avatar, 'Default image image should be returned');
}
}

View File

@@ -0,0 +1,179 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Tests\Helper;
use Doctrine\Common\Collections\ArrayCollection;
use Mautic\CoreBundle\Entity\IpAddress;
use Mautic\CoreBundle\Helper\IpLookupHelper;
use Mautic\EmailBundle\Entity\Email;
use Mautic\EmailBundle\Entity\Stat;
use Mautic\EmailBundle\Entity\StatRepository;
use Mautic\EmailBundle\Helper\BotRatioHelper;
use Mautic\LeadBundle\Deduplicate\ContactMerger;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Event\ContactIdentificationEvent;
use Mautic\LeadBundle\Helper\ContactRequestHelper;
use Mautic\LeadBundle\Model\LeadModel;
use Mautic\LeadBundle\Tracker\ContactTracker;
use Monolog\Logger;
use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\RequestStack;
class ContactRequestHelperTest extends \PHPUnit\Framework\TestCase
{
/**
* @var MockObject|LeadModel
*/
private MockObject $leadModel;
/**
* @var MockObject|ContactTracker
*/
private MockObject $contactTracker;
/**
* @var MockObject|IpLookupHelper
*/
private MockObject $ipLookupHelper;
/**
* @var MockObject|EventDispatcher
*/
private MockObject $dispatcher;
/**
* @var MockObject|RequestStack
*/
private MockObject $requestStack;
/**
* @var MockObject|Logger
*/
private MockObject $logger;
/**
* @var MockObject|StatRepository
*/
private MockObject $statRepository;
/**
* @var MockObject|BotRatioHelper
*/
private MockObject $botRatioHelper;
/**
* @var MockObject|Lead
*/
private MockObject $trackedContact;
/**
* @var MockObject|ContactMerger
*/
private MockObject $contactMerger;
protected function setUp(): void
{
parent::setUp();
$this->leadModel = $this->createMock(LeadModel::class);
$this->contactTracker = $this->createMock(ContactTracker::class);
$this->ipLookupHelper = $this->createMock(IpLookupHelper::class);
$this->requestStack = $this->createMock(RequestStack::class);
$this->logger = $this->createMock(Logger::class);
$this->dispatcher = $this->createMock(EventDispatcher::class);
$this->trackedContact = $this->createMock(Lead::class);
$this->contactMerger = $this->createMock(ContactMerger::class);
$this->statRepository = $this->createMock(StatRepository::class);
$this->botRatioHelper = $this->createMock(BotRatioHelper::class);
$this->trackedContact->method('getId')
->willReturn(1);
$this->trackedContact->method('getIpAddresses')
->willReturn(new ArrayCollection());
$this->contactTracker->method('getContact')
->willReturn($this->trackedContact);
$this->ipLookupHelper->method('getIpAddress')
->willReturn(new IpAddress());
}
public function testEventDoesNotIdentifyContact(): void
{
$query = [
'ct' => [
'lead' => 2,
'channel' => [
'email' => 1,
],
'stat' => 'abc123',
],
];
$email = $this->createMock(Email::class);
$email->method('getId')
->willReturn(2);
$stat = new Stat();
$stat->setEmail($email);
$this->contactMerger->expects($this->never())
->method('merge');
$this->leadModel->expects($this->once())
->method('checkForDuplicateContact')
->willReturn([$this->trackedContact, []]);
$helper = $this->getContactRequestHelper();
$this->assertEquals($this->trackedContact->getId(), $helper->getContactFromQuery($query)->getId());
}
public function testEventIdentifiesContact(): void
{
$query = [
'ct' => [
'lead' => 2,
'channel' => [
'email' => 1,
],
'stat' => 'abc123',
],
];
$contact = new Lead();
$this->dispatcher->method('dispatch')
->willReturnCallback(function (ContactIdentificationEvent $event) use ($contact) {
$event->setIdentifiedContact($contact, 'email');
return $event;
});
$this->contactMerger->expects($this->never())
->method('merge');
$helper = $this->getContactRequestHelper();
$foundContact = $helper->getContactFromQuery($query);
$this->assertTrue($contact === $foundContact);
}
private function getContactRequestHelper(): ContactRequestHelper
{
return new ContactRequestHelper(
$this->leadModel,
$this->contactTracker,
$this->ipLookupHelper,
$this->requestStack,
$this->logger,
$this->dispatcher,
$this->contactMerger,
$this->statRepository,
$this->botRatioHelper
);
}
}

View File

@@ -0,0 +1,203 @@
<?php
namespace Mautic\LeadBundle\Tests\Helper;
use Mautic\CoreBundle\Helper\DateTimeHelper;
use Mautic\LeadBundle\Helper\CustomFieldHelper;
use PHPUnit\Framework\TestCase;
class CustomFieldHelperTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
}
public function testFixValueTypeForBooleans(): void
{
$this->assertNull(CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_BOOLEAN, null));
$this->assertTrue(CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_BOOLEAN, 1));
$this->assertTrue(CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_BOOLEAN, true));
$this->assertTrue(CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_BOOLEAN, '1'));
$this->assertFalse(CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_BOOLEAN, '0'));
$this->assertFalse(CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_BOOLEAN, ''));
$this->assertFalse(CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_BOOLEAN, false));
$this->assertFalse(CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_BOOLEAN, 0));
}
public function testFixValueTypeForNumbers(): void
{
$this->assertNull(CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_NUMBER, null));
$this->assertEquals(1, CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_NUMBER, 1));
$this->assertEquals(1, CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_NUMBER, true));
$this->assertEquals(0, CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_NUMBER, false));
$this->assertEquals(5, CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_NUMBER, '5'));
$this->assertEquals(0, CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_NUMBER, ''));
$this->assertEquals(0, CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_NUMBER, '0'));
}
public function testFixValueTypeForSelect(): void
{
$this->assertNull(CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_SELECT, null));
$this->assertEquals('1', CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_SELECT, true));
$this->assertEquals('', CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_SELECT, false));
$this->assertEquals('1', CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_SELECT, 1));
$this->assertEquals('1', CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_SELECT, '1'));
$this->assertEquals('one', CustomFieldHelper::fixValueType(CustomFieldHelper::TYPE_SELECT, 'one'));
}
public function testFieldsValuesTransformerWithoutRelativesDates(): void
{
$values = [
'customdate' => '2020-11-01',
'customdatetime' => '2020-11-02 23:59:00',
'customtime' => '23:59:00',
'customnulldatetime' => null,
];
$fields = [
'customdate' => [
'type' => 'date',
],
'customdatetime' => [
'type' => 'datetime',
],
'customtime' => [
'type' => 'time',
],
'customnulldatetime' => [
'type' => 'datetime',
],
];
$this->assertSame($values, CustomFieldHelper::fieldsValuesTransformer($fields, $values));
}
public function testFieldsValuesTransformerWithRelativesDates(): void
{
$values = [
'customdate' => '-1 day',
'customdatetime' => '-1 day',
'customtime' => '-20 minutes',
'customnulldatetime' => null,
];
$fields = [
'customdate' => [
'type' => 'date',
],
'customdatetime' => [
'type' => 'datetime',
],
'customtime' => [
'type' => 'time',
],
'customnulldatetime' => [
'type' => 'datetime',
],
];
$expected = [
'customdate' => (new DateTimeHelper('-1 day'))->toLocalString('Y-m-d'),
'customdatetime' => (new DateTimeHelper('-1 day'))->toLocalString('Y-m-d H:i:s'),
'customtime' => (new DateTimeHelper('-20 minutes'))->toLocalString('H:i:s'),
'customnulldatetime' => null,
];
$this->assertSame($expected, CustomFieldHelper::fieldsValuesTransformer($fields, $values));
}
public function testFieldsValuesWithNullsOrEmptyStringsAreNotTransformedToRelativesDates(): void
{
$values = [
'customdate' => null,
'customdatetime' => null,
'customtime' => null,
'customemptystring' => '',
];
$fields = [
'customdate' => [
'type' => 'date',
],
'customdatetime' => [
'type' => 'datetime',
],
'customtime' => [
'type' => 'time',
],
'customemptystring' => [
'type' => 'datetime',
],
];
$expected = [
'customdate' => null,
'customdatetime' => null,
'customtime' => null,
'customemptystring' => null,
];
$this->assertSame($expected, CustomFieldHelper::fieldsValuesTransformer($fields, $values));
}
public function testFieldsValuesTransformerForDifferingValueTypes(): void
{
$fields = [
'select' => [
'type' => 'select',
],
'multiselect' => [
'type' => 'multiselect',
],
'number' => [
'type' => 'number',
],
'string' => [
'type' => 'text',
],
'boolean' => [
'type' => 'boolean',
],
];
$values = [
'select' => 'string',
'multiselect' => [
'array',
],
'number' => 100,
'string' => 'string',
'boolean' => 0,
];
$this->assertSame($values, CustomFieldHelper::fieldsValuesTransformer($fields, $values));
}
public function testFieldValueTransformerWithDateTimeFields(): void
{
$mockDateTimeHelper = $this->createMock(DateTimeHelper::class);
$mockDateTimeHelper->method('toLocalString')
->willReturn('2023-05-20 00:00:00');
$field = ['type' => 'datetime'];
$value = 'now';
$result = CustomFieldHelper::fieldValueTransfomer($field, $value, $mockDateTimeHelper);
$this->assertEquals('2023-05-20 00:00:00', $result, 'FieldValueTransformer was not able to transform datetime field properly');
$field = ['type' => 'date'];
$value = 'today';
$result = CustomFieldHelper::fieldValueTransfomer($field, $value, $mockDateTimeHelper);
$this->assertEquals('2023-05-20 00:00:00', $result, 'FieldValueTransformer was not able to transform date field properly');
$field = ['type' => 'time'];
$value = 'now';
$result = CustomFieldHelper::fieldValueTransfomer($field, $value, $mockDateTimeHelper);
$this->assertEquals('2023-05-20 00:00:00', $result, 'FieldValueTransformer was not able to transform time field properly');
}
protected function tearDown(): void
{
parent::tearDown();
}
}

View File

@@ -0,0 +1,133 @@
<?php
namespace Mautic\LeadBundle\Tests\Helper;
use Mautic\LeadBundle\Helper\CustomFieldValueHelper;
use PHPUnit\Framework\Assert;
class CustomFieldValueHelperTest extends \PHPUnit\Framework\TestCase
{
/**
* @param array<int|string> $fieldParams
*/
private function runNormalizeValueBooleans(array $fieldParams): void
{
$fields['core']['test'] = $fieldParams;
$fieldParams['value'] = 0;
$fields['core']['test2'] = $fieldParams;
$fieldParams['value'] = null;
$fields['core']['test3'] = $fieldParams;
$normalizedFields = CustomFieldValueHelper::normalizeValues($fields);
$this->assertEquals('Yes', $normalizedFields['core']['test']['normalizedValue']);
$this->assertEquals('No', $normalizedFields['core']['test2']['normalizedValue']);
$this->assertEquals('', $normalizedFields['core']['test3']['normalizedValue']);
}
public function testNormalizeValueBooleans(): void
{
$fieldParams = [
'type' => CustomFieldValueHelper::TYPE_BOOLEAN,
'value' => 1,
'properties'=> 'a:2:{s:2:"no";s:2:"No";s:3:"yes";s:3:"Yes";}',
];
$this->runNormalizeValueBooleans($fieldParams);
}
public function testNormalizeValueBooleansWithDifferentProperties(): void
{
$fieldParams = [
'type' => CustomFieldValueHelper::TYPE_BOOLEAN,
'value' => 1,
'properties'=> 'a:2:{s:3:"yes";s:3:"Yes";s:2:"no";s:2:"No";}',
];
$this->runNormalizeValueBooleans($fieldParams);
}
public function testNormalizeValueSelect(): void
{
$fields['core']['test'] = [
'type' => CustomFieldValueHelper::TYPE_SELECT,
'value' => 'second',
'properties'=> 'a:1:{s:4:"list";a:2:{i:0;a:2:{s:5:"label";s:12:"First option";s:5:"value";s:5:"first";}i:1;a:2:{s:5:"label";s:13:"Second option";s:5:"value";s:6:"second";}}}',
];
$normalizedFields = CustomFieldValueHelper::normalizeValues($fields);
$this->assertEquals('Second option', $normalizedFields['core']['test']['normalizedValue']);
}
public function testNormalizeValueSelectWithoutProperties(): void
{
$fields['core']['test'] = [
'type' => CustomFieldValueHelper::TYPE_SELECT,
'value' => 'second',
];
$normalizedFields = CustomFieldValueHelper::normalizeValues($fields);
$this->assertEquals('second', $normalizedFields['core']['test']['normalizedValue']);
}
public function testNormalizeValueMultiSelect(): void
{
$fieldParams = [
'type' => CustomFieldValueHelper::TYPE_MULTISELECT,
'value' => 'option 1',
'properties'=> 'a:1:{s:4:"list";a:3:{i:0;a:2:{s:5:"label";s:12:"Option 1 yes";s:5:"value";s:8:"option 1";}i:1;a:2:{s:5:"label";s:12:"Option 2 yes";s:5:"value";s:8:"option 2";}i:2;a:2:{s:5:"label";s:12:"Option 3 yes";s:5:"value";s:8:"option 3";}}}',
];
$fields['core']['test'] = $fieldParams;
$fieldParams['value'] = 'option 4';
$fields['core']['test2'] = $fieldParams;
$normalizedFields = CustomFieldValueHelper::normalizeValues($fields);
$this->assertEquals('Option 1 yes', $normalizedFields['core']['test']['normalizedValue']);
$this->assertEquals('option 4', $normalizedFields['core']['test2']['normalizedValue']);
}
public function testSetValueFromPropertiesListWithoutList(): void
{
Assert::assertSame(
'value_1',
CustomFieldValueHelper::setValueFromPropertiesList([], 'value_1')
);
}
public function testSetValueFromPropertiesListWithStringList(): void
{
Assert::assertSame(
'value_1',
CustomFieldValueHelper::setValueFromPropertiesList(['list' => 'some|string'], 'value_1')
);
}
public function testSetValueFromPropertiesListWithAssociativeArrayList(): void
{
Assert::assertSame(
'value_1',
CustomFieldValueHelper::setValueFromPropertiesList(
['list' => ['value_1' => 'Label 1']],
'value_1'
)
);
}
public function testSetValueFromPropertiesListWithArrayList(): void
{
Assert::assertSame(
'Label 1',
CustomFieldValueHelper::setValueFromPropertiesList(
[
'list' => [
['value' => 'value_1', 'label' => 'Label 1'],
],
],
'value_1'
)
);
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Mautic\LeadBundle\Tests\Helper;
use Mautic\LeadBundle\Entity\LeadField;
use Mautic\LeadBundle\Entity\LeadFieldRepository;
use Mautic\LeadBundle\Helper\FieldAliasHelper;
use Mautic\LeadBundle\Model\FieldModel;
class FieldAliasHelperTest extends \PHPUnit\Framework\TestCase
{
private \PHPUnit\Framework\MockObject\MockObject $fieldModel;
private \PHPUnit\Framework\MockObject\MockObject $fieldRepository;
private FieldAliasHelper $helper;
protected function setUp(): void
{
parent::setUp();
$this->fieldRepository = $this->createMock(LeadFieldRepository::class);
$this->fieldModel = $this->getMockBuilder(FieldModel::class)
->onlyMethods(['cleanAlias', 'getRepository'])
->disableOriginalConstructor()
->getMock();
$this->fieldRepository->method('getAliases')->willReturn([
'title',
'firstname',
'lastname',
]);
$this->fieldModel->method('cleanAlias')->willReturnCallback(fn () => func_get_args()[0]);
$this->fieldModel->method('getRepository')->willReturn($this->fieldRepository);
$this->helper = new FieldAliasHelper($this->fieldModel);
}
public function testDuplicatedAliasWithAliasSet(): void
{
$field = new LeadField();
$field->setAlias('title');
$field = $this->helper->makeAliasUnique($field);
$this->assertEquals('title1', $field->getAlias());
}
public function testDuplicatedAliasWithAliasEmpty(): void
{
$field = new LeadField();
$field->setName('title');
$field = $this->helper->makeAliasUnique($field);
$this->assertEquals('title1', $field->getAlias());
}
public function testUniqueAliasWithAliasEmpty(): void
{
$field = new LeadField();
$field->setName('phone');
$field = $this->helper->makeAliasUnique($field);
$this->assertEquals('phone', $field->getAlias());
}
}

View File

@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Tests\Helper;
use Mautic\LeadBundle\Helper\FormFieldHelper;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\TestCase;
final class FormFieldHelperTest extends TestCase
{
private ?string $defaultUploadDir;
protected function setUp(): void
{
$this->defaultUploadDir = $_ENV['MAUTIC_UPLOAD_DIR'] ?? null;
$_ENV['MAUTIC_UPLOAD_DIR'] = __DIR__; // may not be set unless Symfony is booted
}
protected function tearDown(): void
{
$_ENV['MAUTIC_UPLOAD_DIR'] = $this->defaultUploadDir;
}
public function testDefaultCountryList(): void
{
$list = FormFieldHelper::getCountryChoices();
$first = array_shift($list);
$last = array_pop($list);
Assert::assertEquals('Afghanistan', $first);
Assert::assertEquals('Zimbabwe', $last);
}
public function testCustomCountryList(): void
{
$_ENV['MAUTIC_UPLOAD_DIR'] = __DIR__.'/files';
$list = FormFieldHelper::getCountryChoices();
$first = array_shift($list);
$last = array_pop($list);
Assert::assertEquals('Middle Earth', $first);
Assert::assertEquals('Fillory', $last);
}
public function testDefaultRegionList(): void
{
$list = FormFieldHelper::getRegionChoices();
$firstCountry = array_shift($list);
$firstCountryRegion = array_shift($firstCountry);
$lastCountry = array_pop($list);
$lastCountryRegion = array_pop($lastCountry);
Assert::assertEquals('Alabama', $firstCountryRegion);
Assert::assertEquals('St. Maarten', $lastCountryRegion);
}
public function testCustomRegionList(): void
{
$_ENV['MAUTIC_UPLOAD_DIR'] = __DIR__.'/files';
$list = FormFieldHelper::getRegionChoices();
$firstCountry = array_shift($list);
$firstCountryRegion = array_shift($firstCountry);
$lastCountry = array_pop($list);
$lastCountryRegion = array_pop($lastCountry);
Assert::assertEquals('The Westlands', $firstCountryRegion);
Assert::assertEquals('Darkling Woods', $lastCountryRegion);
}
}

View File

@@ -0,0 +1,125 @@
<?php
namespace Mautic\LeadBundle\Tests\Helper;
use Mautic\LeadBundle\Helper\IdentifyCompanyHelper;
use Mautic\LeadBundle\Model\CompanyModel;
class IdentifyCompanyHelperTest extends \PHPUnit\Framework\TestCase
{
public function testDomainExistsRealDomain(): void
{
$helper = new IdentifyCompanyHelper();
$reflection = new \ReflectionClass(IdentifyCompanyHelper::class);
$method = $reflection->getMethod('domainExists');
$method->setAccessible(true);
$result = $method->invokeArgs($helper, ['hello@mautic.org']);
$this->assertTrue(is_string($result));
$this->assertGreaterThan(0, strlen($result));
}
public function testDomainExistsWithFakeDomain(): void
{
$helper = new IdentifyCompanyHelper();
$reflection = new \ReflectionClass(IdentifyCompanyHelper::class);
$method = $reflection->getMethod('domainExists');
$method->setAccessible(true);
$result = $method->invokeArgs($helper, ['hello@domain.fake']);
$this->assertFalse($result);
}
public function testFindCompanyByName(): void
{
$company = [
'company' => 'Mautic',
];
$expected = [
'companyname' => 'Mautic',
];
$model = $this->createMock(CompanyModel::class);
$model->expects($this->once())
->method('checkForDuplicateCompanies')
->willReturn([]);
$model->expects($this->any())
->method('fetchCompanyFields')
->willReturn([['alias' => 'companyname']]);
$helper = new IdentifyCompanyHelper();
$reflection = new \ReflectionClass(IdentifyCompanyHelper::class);
$method = $reflection->getMethod('findCompany');
$method->setAccessible(true);
[$resultCompany, $entities] = $method->invokeArgs($helper, [$company, $model]);
$this->assertEquals($expected, $resultCompany);
}
public function testFindCompanyByNameWithValidEmail(): void
{
$company = [
'company' => 'Mautic',
'companyemail' => 'hello@mautic.org',
];
$expected = [
'companyname' => 'Mautic',
'companyemail' => 'hello@mautic.org',
];
$model = $this->createMock(CompanyModel::class);
$model->expects($this->once())
->method('checkForDuplicateCompanies')
->willReturn([]);
$model->expects($this->any())
->method('fetchCompanyFields')
->willReturn([['alias' => 'companyname']]);
$helper = new IdentifyCompanyHelper();
$reflection = new \ReflectionClass(IdentifyCompanyHelper::class);
$method = $reflection->getMethod('findCompany');
$method->setAccessible(true);
[$resultCompany, $entities] = $method->invokeArgs($helper, [$company, $model]);
$this->assertEquals($expected, $resultCompany);
}
public function testFindCompanyByNameWithValidEmailAndCustomWebsite(): void
{
$company = [
'company' => 'Mautic',
'companyemail' => 'hello@mautic.org',
'companywebsite' => 'https://mautic.org',
];
$expected = [
'companyname' => 'Mautic',
'companywebsite' => 'https://mautic.org',
'companyemail' => 'hello@mautic.org',
];
$model = $this->createMock(CompanyModel::class);
$model->expects($this->once())
->method('checkForDuplicateCompanies')
->willReturn([]);
$model->expects($this->any())
->method('fetchCompanyFields')
->willReturn([['alias' => 'companyname']]);
$helper = new IdentifyCompanyHelper();
$reflection = new \ReflectionClass(IdentifyCompanyHelper::class);
$method = $reflection->getMethod('findCompany');
$method->setAccessible(true);
[$resultCompany, $entities] = $method->invokeArgs($helper, [$company, $model]);
$this->assertEquals($expected, $resultCompany);
}
}

View File

@@ -0,0 +1,168 @@
<?php
namespace Mautic\LeadBundle\Tests\Helper;
use Mautic\LeadBundle\Entity\DoNotContact;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Event\ChannelSubscriptionChange;
use Mautic\LeadBundle\Event\LeadEvent;
use Mautic\LeadBundle\Event\LeadUtmTagsEvent;
use Mautic\LeadBundle\Event\PointsChangeEvent;
use Mautic\LeadBundle\Helper\LeadChangeEventDispatcher;
use Mautic\LeadBundle\LeadEvents;
use Symfony\Component\EventDispatcher\EventDispatcher;
class LeadChangeEventDispatcherTest extends \PHPUnit\Framework\TestCase
{
#[\PHPUnit\Framework\Attributes\TestDox('Test that date identified change dispatches correct event')]
public function testDateIdentifiedEventIsDispatched(): void
{
$dispatcher = $this->createMock(EventDispatcher::class);
$lead = new Lead();
$event = new LeadEvent($lead);
$dispatcher->expects($this->once())
->method('dispatch')
->with(
$event,
LeadEvents::LEAD_IDENTIFIED
);
$leadEventDispatcher = new LeadChangeEventDispatcher($dispatcher);
$leadEventDispatcher->dispatchEvents($event, ['dateIdentified' => ['foo', 'bar']]);
}
#[\PHPUnit\Framework\Attributes\TestDox('Test that point changes dispatches correct event')]
public function testPointChangeEventIsDispatched(): void
{
$dispatcher = $this->createMock(EventDispatcher::class);
$lead = new Lead();
$event = new LeadEvent($lead);
$pointsEvent = new PointsChangeEvent($lead, 10, 20);
$dispatcher->expects($this->once())
->method('dispatch')
->with(
$pointsEvent,
LeadEvents::LEAD_POINTS_CHANGE
);
$leadEventDispatcher = new LeadChangeEventDispatcher($dispatcher);
$leadEventDispatcher->dispatchEvents($event, ['points' => [10, 20]]);
}
#[\PHPUnit\Framework\Attributes\TestDox('Test that points change event is not dispatched if we did an import')]
public function testPointChangeEventIsNotDispatchedWithImport(): void
{
$dispatcher = $this->createMock(EventDispatcher::class);
$lead = new Lead();
$lead->imported = true;
$event = new LeadEvent($lead);
$dispatcher->expects($this->never())
->method('dispatch');
$leadEventDispatcher = new LeadChangeEventDispatcher($dispatcher);
$leadEventDispatcher->dispatchEvents($event, ['points' => [10, 20]]);
}
#[\PHPUnit\Framework\Attributes\TestDox('Test that points change event is not dispatched if points are empty (false positive)')]
public function testPointChangeEventIsNotDispatchedWithEmptyPoints(): void
{
$dispatcher = $this->createMock(EventDispatcher::class);
$lead = new Lead();
$event = new LeadEvent($lead);
$dispatcher->expects($this->never())
->method('dispatch');
$leadEventDispatcher = new LeadChangeEventDispatcher($dispatcher);
$leadEventDispatcher->dispatchEvents($event, ['points' => [0, 0]]);
}
#[\PHPUnit\Framework\Attributes\TestDox('Test that points change event is dispatched if points are changed from something to nothing')]
public function testPointChangeEventIsDispatchedWithPointsChangedToZero(): void
{
$dispatcher = $this->createMock(EventDispatcher::class);
$lead = new Lead();
$event = new LeadEvent($lead);
$pointsEvent = new PointsChangeEvent($lead, 10, 0);
$dispatcher->expects($this->once())
->method('dispatch')
->with(
$pointsEvent,
LeadEvents::LEAD_POINTS_CHANGE
);
$leadEventDispatcher = new LeadChangeEventDispatcher($dispatcher);
$leadEventDispatcher->dispatchEvents($event, ['points' => [10, 0]]);
}
#[\PHPUnit\Framework\Attributes\TestDox('Test that points change event is not dispatched if this is a new Lead')]
public function testPointChangeEventIsNotDispatchedWithNewContact(): void
{
$dispatcher = $this->createMock(EventDispatcher::class);
$lead = new Lead();
$event = new LeadEvent($lead, true);
$dispatcher->expects($this->never())
->method('dispatch');
$leadEventDispatcher = new LeadChangeEventDispatcher($dispatcher);
$leadEventDispatcher->dispatchEvents($event, ['points' => [10, 0]]);
}
#[\PHPUnit\Framework\Attributes\TestDox('Test that utm event is dispatched')]
public function testUtmTagsChangeEventIsDispatched(): void
{
$dispatcher = $this->createMock(EventDispatcher::class);
$lead = new Lead();
$event = new LeadEvent($lead);
$changes = ['utmtags' => ['foo', 'bar']];
$utmTagsEvent = new LeadUtmTagsEvent($lead, $changes['utmtags']);
$dispatcher->expects($this->once())
->method('dispatch')
->with(
$utmTagsEvent,
LeadEvents::LEAD_UTMTAGS_ADD
);
$leadEventDispatcher = new LeadChangeEventDispatcher($dispatcher);
$leadEventDispatcher->dispatchEvents($event, $changes);
}
#[\PHPUnit\Framework\Attributes\TestDox('Test that channel subscription changes are dispatched')]
public function testChannelSubscriptionChangeEventIsDispatched(): void
{
$dispatcher = $this->createMock(EventDispatcher::class);
$lead = new Lead();
$event = new LeadEvent($lead);
$changes = ['dnc_channel_status' => ['email' => ['old_reason' => DoNotContact::IS_CONTACTABLE, 'reason' => DoNotContact::UNSUBSCRIBED]]];
$dncEvent = new ChannelSubscriptionChange($lead, 'email', DoNotContact::IS_CONTACTABLE, DoNotContact::UNSUBSCRIBED);
$dispatcher->expects($this->once())
->method('dispatch')
->with(
$dncEvent,
LeadEvents::CHANNEL_SUBSCRIPTION_CHANGED
);
$leadEventDispatcher = new LeadChangeEventDispatcher($dispatcher);
$leadEventDispatcher->dispatchEvents($event, $changes);
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace Mautic\LeadBundle\Tests\Helper;
use Mautic\LeadBundle\Entity\CompanyLeadRepository;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Helper\PrimaryCompanyHelper;
use PHPUnit\Framework\Exception;
class PrimaryCompanyHelperTest extends \PHPUnit\Framework\TestCase
{
/**
* @var CompanyLeadRepository|Exception
*/
private \PHPUnit\Framework\MockObject\MockObject $leadRepository;
protected function setUp(): void
{
$this->leadRepository = $this->createMock(CompanyLeadRepository::class);
$this->leadRepository->expects($this->once())
->method('getCompaniesByLeadId')
->willReturn(
[
[
'score' => 0,
'date_added' => '2018-06-02 00:00:00',
'date_associated' => '2018-06-02 00:00:00',
'is_primary' => 1,
'companywebsite' => 'https://foo.com',
],
[
'score' => 0,
'date_added' => '2018-06-02 00:00:00',
'date_associated' => '2018-06-02 00:00:00',
'is_primary' => 0,
'companywebsite' => 'https://bar.com',
],
]
);
}
public function testProfileFieldsReturnedWithPrimaryCompany(): void
{
$lead = $this->createMock(Lead::class);
$lead->expects($this->once())
->method('getProfileFields')
->willReturn(
[
'email' => 'test@test.com',
]
);
$profileFields = $this->getPrimaryCompanyHelper()->getProfileFieldsWithPrimaryCompany($lead);
$this->assertEquals(['email' => 'test@test.com', 'companywebsite' => 'https://foo.com'], $profileFields);
}
public function testPrimaryCompanyMergedIntoProfileFields(): void
{
$leadFields = [
'email' => 'test@test.com',
];
$profileFields = $this->getPrimaryCompanyHelper()->mergePrimaryCompanyWithProfileFields(1, $leadFields);
$this->assertEquals(['email' => 'test@test.com', 'companywebsite' => 'https://foo.com'], $profileFields);
}
/**
* @return PrimaryCompanyHelper
*/
private function getPrimaryCompanyHelper()
{
return new PrimaryCompanyHelper($this->leadRepository);
}
}

View File

@@ -0,0 +1,241 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Tests\Helper;
use Mautic\CacheBundle\Cache\CacheProviderInterface;
use Mautic\LeadBundle\Helper\SegmentCountCacheHelper;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\CacheItem;
class SegmentCountCacheHelperTest extends TestCase
{
private MockObject&CacheProviderInterface $cacheProviderMock;
private SegmentCountCacheHelper $segmentCountCacheHelper;
protected function setUp(): void
{
$this->cacheProviderMock = $this->createMock(CacheProviderInterface::class);
$this->segmentCountCacheHelper = new SegmentCountCacheHelper($this->cacheProviderMock);
}
/**
* Create a CacheItem instance using reflection since the constructor is private.
*/
private function createCacheItem(string $key, mixed $value = null, bool $isHit = false): CacheItem
{
$item = (new \ReflectionClass(CacheItem::class))->newInstanceWithoutConstructor();
$keyProperty = new \ReflectionProperty(CacheItem::class, 'key');
$keyProperty->setValue($item, $key);
$valueProperty = new \ReflectionProperty(CacheItem::class, 'value');
$valueProperty->setValue($item, $value);
$isHitProperty = new \ReflectionProperty(CacheItem::class, 'isHit');
$isHitProperty->setValue($item, $isHit);
return $item;
}
public function testGetSegmentContactCount(): void
{
$segmentId = 1;
$cacheItem = $this->createCacheItem('segment.'.$segmentId.'.lead', 1, true);
$this->cacheProviderMock
->method('getItem')
->with('segment.'.$segmentId.'.lead')
->willReturn($cacheItem);
$count = $this->segmentCountCacheHelper->getSegmentContactCount($segmentId);
Assert::assertSame(1, $count);
}
public function testSetSegmentContactCount(): void
{
$segmentId = 1;
$count = 2;
$cacheItem = $this->createCacheItem('segment.'.$segmentId.'.lead');
$this->cacheProviderMock
->method('getItem')
->with('segment.'.$segmentId.'.lead')
->willReturn($cacheItem);
$this->cacheProviderMock
->method('hasItem')
->with('segment.'.$segmentId.'.lead.recount')
->willReturn(false);
$this->cacheProviderMock
->expects(self::never())
->method('deleteItem')
->with('segment.'.$segmentId.'.lead.recount');
$this->segmentCountCacheHelper->setSegmentContactCount($segmentId, $count);
}
public function testSetSegmentContactCountIfRecountExist(): void
{
$segmentId = 1;
$count = 2;
$cacheItem = $this->createCacheItem('segment.'.$segmentId.'.lead');
$this->cacheProviderMock
->method('getItem')
->with('segment.'.$segmentId.'.lead')
->willReturn($cacheItem);
$this->cacheProviderMock
->expects(self::exactly(1))
->method('hasItem')
->with('segment.'.$segmentId.'.lead.recount')
->willReturn(true);
$this->cacheProviderMock
->expects(self::exactly(1))
->method('deleteItem')
->with('segment.'.$segmentId.'.lead.recount')
->willReturn(true);
$this->segmentCountCacheHelper->setSegmentContactCount($segmentId, $count);
}
public function testSetSegmentContactCountWithInvalidatedSegment(): void
{
$segmentId = 1;
$cacheItem = $this->createCacheItem('segment.'.$segmentId.'.lead.recount');
$this->cacheProviderMock
->expects(self::once())
->method('getItem')
->with('segment.'.$segmentId.'.lead.recount')
->willReturn($cacheItem);
$this->cacheProviderMock
->expects(self::once())
->method('save')
->with($cacheItem);
$this->segmentCountCacheHelper->invalidateSegmentContactCount($segmentId);
}
public function testDecrementSegmentContactCountHasNoCache(): void
{
$segmentId = 1;
$this->cacheProviderMock
->expects(self::exactly(1))
->method('hasItem')
->with('segment.'.$segmentId.'.lead')
->willReturn(false);
$this->segmentCountCacheHelper->decrementSegmentContactCount($segmentId);
}
public function testDeleteSegmentContactCountIfNotExist(): void
{
$segmentId = 1;
$this->cacheProviderMock
->expects(self::exactly(1))
->method('hasItem')
->with('segment.'.$segmentId.'.lead')
->willReturn(false);
$this->segmentCountCacheHelper->deleteSegmentContactCount($segmentId);
}
public function testDeleteSegmentContactCountIfExist(): void
{
$segmentId = 1;
$this->cacheProviderMock
->expects(self::exactly(1))
->method('hasItem')
->with('segment.'.$segmentId.'.lead')
->willReturn(true);
$this->cacheProviderMock
->expects(self::exactly(1))
->method('deleteItem')
->with('segment.'.$segmentId.'.lead')
->willReturn(true);
$this->segmentCountCacheHelper->deleteSegmentContactCount($segmentId);
}
public function testDecrementSegmentContactCount(): void
{
$segmentId = 1;
$cacheItem = $this->createCacheItem('segment.'.$segmentId.'.lead', 5, true);
$this->cacheProviderMock
->method('hasItem')
->willReturnCallback(function ($key) use ($segmentId) {
if ($key === 'segment.'.$segmentId.'.lead') {
return true;
}
if ($key === 'segment.'.$segmentId.'.lead.recount') {
return false;
}
return false;
});
$this->cacheProviderMock
->method('getItem')
->willReturnCallback(function ($key) use ($segmentId, $cacheItem) {
if ($key === 'segment.'.$segmentId.'.lead') {
return $cacheItem;
}
return null;
});
$this->cacheProviderMock
->expects(self::once())
->method('save')
->with($cacheItem);
$this->segmentCountCacheHelper->decrementSegmentContactCount($segmentId);
// Verify the count was decremented from 5 to 4
Assert::assertSame(4, $cacheItem->get());
}
public function testDecrementSegmentCountIsNotNegative(): void
{
$segmentId = 1;
$cacheItem = $this->createCacheItem('segment.'.$segmentId.'.lead', 0, true);
$this->cacheProviderMock
->expects(self::exactly(2))
->method('hasItem')
->willReturnCallback(function ($key) use ($segmentId) {
if ($key === 'segment.'.$segmentId.'.lead') {
return true;
}
if ($key === 'segment.'.$segmentId.'.lead.recount') {
return false;
}
return false;
});
$this->cacheProviderMock
->method('getItem')
->willReturnCallback(function ($key) use ($segmentId, $cacheItem) {
if (in_array($key, ['segment.'.$segmentId.'.lead', 'segment.'.$segmentId.'.lead.recount'])) {
return $cacheItem;
}
return null;
});
// Edge case. Should not decrement below 0.
$this->segmentCountCacheHelper->decrementSegmentContactCount($segmentId);
// Assert that the cache item value is still 0 (not negative)
Assert::assertSame(0, $cacheItem->get());
}
}

View File

@@ -0,0 +1,255 @@
<?php
namespace Mautic\LeadBundle\Tests\Helper;
use Mautic\LeadBundle\Entity\LeadFieldRepository;
use Mautic\LeadBundle\Entity\LeadRepository;
use Mautic\LeadBundle\Helper\TokenHelper;
class TokenHelperTest extends \PHPUnit\Framework\TestCase
{
private $lead = [
'firstname' => 'Bob',
'lastname' => 'Smith',
'country' => '',
'date' => '2000-05-05 12:45:50',
'select' => 'first',
'bool' => 1,
'companies' => [
[
'companyzip' => '77008',
],
],
];
protected function setUp(): void
{
$reflectionProperty = new \ReflectionProperty(TokenHelper::class, 'parameters');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, [
'date_format_dateonly' => 'F j, Y',
'date_format_timeonly' => 'g:i a',
]);
$fields = [
'select' => [
'type' => 'select',
'properties' => 'a:1:{s:4:"list";a:2:{i:0;a:2:{s:5:"label";s:12:"First option";s:5:"value";s:5:"first";}i:1;a:2:{s:5:"label";s:13:"Second option";s:5:"value";s:6:"second";}}}',
],
'bool' => [
'type' => 'boolean',
'properties' => 'a:2:{s:2:"no";s:2:"No";s:3:"yes";s:3:"Yes";}',
],
];
$leadFieldRepository = $this->createMock(LeadFieldRepository::class);
$leadFieldRepository
->method('getFields')
->willReturn($fields);
$reflectionProperty = new \ReflectionProperty(LeadRepository::class, 'leadFieldRepository');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, $leadFieldRepository);
parent::setUp();
}
public function testContactTokensAreReplaced(): void
{
$lead = [
'firstname' => 'Bob',
'lastname' => 'Smith',
'country' => 'USA',
'companies' => [
[
'companyzip' => '77008',
],
],
];
$token = '{contactfield=country}';
$tokenList = TokenHelper::findLeadTokens($token, $lead);
$this->assertEquals([$token => 'USA'], $tokenList);
}
public function testCompanyTokensAreReplaced(): void
{
$leads = [
[
'firstname' => 'Bob',
'lastname' => 'Smith',
'companies' => [
[
'companyzip' => '77009',
'is_primary' => 0,
],
[
'companyzip' => '77008',
'is_primary' => 1,
],
],
],
[
'firstname' => 'Jane',
'lastname' => 'Smith',
],
[
'firstname' => 'Joey',
'lastname' => 'Smith',
'companies' => [],
],
];
$token = '{contactfield=companyzip}';
$tokenList = TokenHelper::findLeadTokens($token, $leads[0]);
$this->assertEquals([$token => '77008'], $tokenList);
$tokenList = TokenHelper::findLeadTokens($token, $leads[1]);
$this->assertEquals([$token => ''], $tokenList);
$tokenList = TokenHelper::findLeadTokens($token, $leads[2]);
$this->assertEquals([$token => ''], $tokenList);
}
public function testDefaultValueIsUsed(): void
{
$lead = [
'firstname' => 'Bob',
'lastname' => 'Smith',
'country' => '',
'companies' => [
[
'companyzip' => '77008',
],
],
];
$token = '{contactfield=country|USA}';
$tokenList = TokenHelper::findLeadTokens($token, $lead);
$this->assertEquals([$token => 'USA'], $tokenList);
}
public function testValueIsUrlEncoded(): void
{
$lead = [
'firstname' => 'Bob',
'lastname' => 'Smith',
'country' => 'Somewhere&Else',
'companies' => [
[
'companyzip' => '77008',
],
],
];
$token = '{contactfield=country|true}';
$tokenList = TokenHelper::findLeadTokens($token, $lead);
$this->assertEquals([$token => 'Somewhere%26Else'], $tokenList);
}
public function testGetValueFromTokensWhenSomeValue(): void
{
$token = '{contactfield=website}';
$tokens = [
'{contactfield=website}' => 'https://mautic.org',
];
$this->assertEquals(
'https://mautic.org',
TokenHelper::getValueFromTokens($tokens, $token)
);
}
public function testGetValueFromTokensWhenSomeValueWithDefaultValue(): void
{
$token = '{contactfield=website|ftp://default.url}';
$tokens = [
'{contactfield=website}' => 'https://mautic.org',
];
$this->assertEquals(
'https://mautic.org',
TokenHelper::getValueFromTokens($tokens, $token)
);
}
public function testGetValueFromTokensWhenNoValueWithDefaultValue(): void
{
$token = '{contactfield=website|ftp://default.url}';
$tokens = [
'{contactfield=website}' => '',
];
$this->assertEquals(
'ftp://default.url',
TokenHelper::getValueFromTokens($tokens, $token)
);
}
public function testGetValueFromTokensWhenNoValueWithoutDefaultValue(): void
{
$token = '{contactfield=website}';
$tokens = [
'{contactfield=website}' => '',
];
$this->assertEquals(
'',
TokenHelper::getValueFromTokens($tokens, $token)
);
}
public function testDateTimeFormatValue(): void
{
$token = '{contactfield=date|datetime}';
$tokenList = TokenHelper::findLeadTokens($token, $this->lead);
$this->assertNotSame($this->lead['date'], $tokenList[$token]);
}
public function testDateFormatValue(): void
{
$token = '{contactfield=date|date}';
$tokenList = TokenHelper::findLeadTokens($token, $this->lead);
$this->assertNotSame($this->lead['date'], $tokenList[$token]);
}
public function testTimeFormatValue(): void
{
$token = '{contactfield=date|time}';
$tokenList = TokenHelper::findLeadTokens($token, $this->lead);
$this->assertNotSame($this->lead['date'], $tokenList[$token]);
}
public function testDateFormatForEmptyValue(): void
{
$lead = $this->lead;
$lead['date'] = '';
$token = '{contactfield=date|time}';
$tokenList = TokenHelper::findLeadTokens($token, $lead);
$this->assertEmpty($tokenList[$token]);
}
/**
* @param string|int $result
*/
#[\PHPUnit\Framework\Attributes\DataProvider('dataLabelProvider')]
public function testLabelFormatForSelect(string $token, $result): void
{
$lead = $this->lead;
$tokenList = TokenHelper::findLeadTokens($token, $lead);
$this->assertEquals($result, $tokenList[$token]);
}
/**
* @return array<int, array<int, int|string>>
*/
public static function dataLabelProvider(): array
{
return
[
['{contactfield=select}', 'first'],
['{contactfield=select|label}', 'First option'],
['{contactfield=bool}', 1],
['{contactfield=bool|label}', 'Yes'],
];
}
}

View File

@@ -0,0 +1,4 @@
[
"Middle Earth",
"Fillory"
]

View File

@@ -0,0 +1,8 @@
{
"Middle Earth": [
"The Westlands"
],
"Fillory": [
"Darkling Woods"
]
}