snapshot of https://github.com/espocrm/espocrm.git (master, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Test / Test on PHP 8.3 (push) Failing after 5s
Test / Test on PHP 8.4 (push) Failing after 4s
Test / Test on PHP 8.5 (push) Failing after 3s
TypeScript static analysis / TypeScript check (push) Failing after 14s
Test Integration on MySQL / Test on PHP 8.3 (push) Failing after 2s
Test Integration on MySQL / Test on PHP 8.5 (push) Failing after 0s
Test Integration on PostgreSQL / Test on PHP 8.4 fix (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 master (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-18 04:19:15 +05:00
commit 7cc7e6b4f3
10077 changed files with 900756 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\DashboardTemplate;
use Espo\Classes\FieldDuplicators\DashboardTemplate\Layout as LayoutFieldDuplicator;
use Espo\Entities\DashboardTemplate;
use PHPUnit\Framework\TestCase;
class DuplicateTest extends TestCase
{
public function testDuplicate(): void
{
$entity = $this->createMock(DashboardTemplate::class);
$original = [
(object) [
'id' => 'tab-01',
'layout' => [
(object) [
'id' => 'd-01',
]
],
],
];
$originalOptions = (object) [
'd-01' => (object) ['k' => 'v'],
];
$entity->method('getLayoutRaw')
->willReturn($original);
$entity->method('getDashletsOptionsRaw')
->willReturn($originalOptions);
$duplicator = new LayoutFieldDuplicator();
$values = $duplicator->duplicate($entity, DashboardTemplate::FIELD_LAYOUT);
$copy = $values->{DashboardTemplate::FIELD_LAYOUT} ?? null;
$copyOptions = $values->{DashboardTemplate::FIELD_DASHLETS_OPTIONS} ?? null;
$this->assertIsArray($copy);
$this->assertIsString($copy[0]->id);
$this->assertNotEquals($original[0]->id, $copy[0]->id);
$this->assertNotEquals($original[0]->layout[0]->id, $copy[0]->layout[0]->id);
$this->assertIsString($copy[0]->layout[0]->id);
$this->assertFalse(property_exists($copyOptions, 'd-01'));
$this->assertCount(1, get_object_vars($copyOptions));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\Export;
use Espo\Tools\Export\Params;
use PHPUnit\Framework\TestCase;
class ParamsTest extends TestCase
{
public function testSerialize(): void
{
$params = new Params('Test');
$params = Params::fromSerializedRaw(base64_encode(serialize($params)));
$this->assertEquals('Test', $params->getEntityType());
}
}

View File

@@ -0,0 +1,378 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools;
use Espo\Core\Exceptions\Conflict;
use Espo\Core\Utils\Language;
use Espo\Core\Utils\Metadata;
use Espo\Tools\EntityManager\NameUtil;
use Espo\Tools\FieldManager\FieldManager;
use Espo\Core\InjectableFactory;
use PHPUnit\Framework\TestCase;
class FieldManagerTest extends TestCase
{
private ?FieldManager $fieldManager = null;
private ?NameUtil $nameUtil = null;
private $metadataHelper;
private $language;
protected $defaultLanguage;
protected $metadata;
protected function setUp() : void
{
$this->metadata = $this->createMock(Metadata::class);
$this->language = $this->createMock(Language::class);
$baseLanguage = $this->createMock(Language::class);
$this->defaultLanguage = $this->createMock(Language::class);
$this->metadataHelper = $this->createMock(Metadata\Helper::class);
$this->nameUtil = $this->createMock(NameUtil::class);
$this->nameUtil->expects($this->any())
->method('addCustomPrefix')
->willReturnCallback(fn ($it) => $it);
$this->fieldManager = new FieldManager(
$this->createMock(InjectableFactory::class),
$this->metadata,
$this->language,
$baseLanguage,
$this->metadataHelper,
$this->nameUtil
);
}
public function testCreateExistingField(): void
{
$this->expectException(Conflict::class);
$data = [
"type" => "varchar",
"maxLength" => "50",
];
$this->nameUtil
->expects($this->once())
->method('fieldExists')
->willReturn(true);
$this->metadata
->expects($this->any())
->method('get')
->willReturnMap([
["scopes.CustomEntity.customizable", null, true],
]);
$this->fieldManager->create('CustomEntity', 'varName', $data);
}
public function testUpdateCoreField(): void
{
$data = [
"type" => "varchar",
"maxLength" => 100,
"label" => "Modified Name",
];
$existingData = (object) [
"type" => "varchar",
"maxLength" => 50,
"label" => "Name",
];
$map = [
['entityDefs.Account.fields.name.type', null, $data['type']],
['fields.varchar', null, null],
[['fields', 'varchar', 'hookClassName'], null, null],
["scopes.Account.customizable", null, true],
];
$this->language
->expects($this->once())
->method('save')
->willReturn(true);
$this->metadata
->expects($this->any())
->method('get')
->willReturnMap($map);
$this->metadata
->expects($this->exactly(2))
->method('getObjects')
->willReturn($existingData);
$this->metadataHelper
->expects($this->once())
->method('getFieldDefsByType')
->willReturn(json_decode('{
"params":[
{
"name":"required",
"type":"bool",
"default":false
},
{
"name":"default",
"type":"varchar"
},
{
"name":"maxLength",
"type":"int"
},
{
"name":"trim",
"type":"bool",
"default": true
},
{
"name": "options",
"type": "multiEnum"
},
{
"name":"audited",
"type":"bool"
},
{
"name":"readOnly",
"type":"bool"
}
],
"filter": true,
"personalData": true,
"textFilter": true,
"fullTextSearch": true
}', true));
$this->metadata
->expects($this->exactly(2))
->method('getCustom')
->willReturn((object) []);
$this->fieldManager->update('Account', 'name', $data);
}
public function testUpdateCoreFieldWithNoChanges(): void
{
$data = [
"type" => "varchar",
"maxLength" => 50,
"label" => "Name",
];
$map = [
['entityDefs.Account.fields.name.type', null, $data['type']],
['fields.varchar', null, null],
[['fields', 'varchar', 'hookClassName'], null, null],
["scopes.Account.customizable", null, true],
];
$this->metadata
->expects($this->never())
->method('set');
$this->language
->expects($this->once())
->method('save');
$this->metadataHelper
->expects($this->once())
->method('getFieldDefsByType')
->willReturn(json_decode('{
"params":[
{
"name":"required",
"type":"bool",
"default":false
},
{
"name":"default",
"type":"varchar"
},
{
"name":"maxLength",
"type":"int"
},
{
"name":"trim",
"type":"bool",
"default": true
},
{
"name": "options",
"type": "multiEnum"
},
{
"name":"audited",
"type":"bool"
},
{
"name":"readOnly",
"type":"bool"
}
],
"filter": true,
"personalData": true,
"textFilter": true,
"fullTextSearch": true
}', true));
$this->metadata
->expects($this->any())
->method('get')
->willReturnMap($map);
$this->metadata
->expects($this->exactly(2))
->method('getObjects')
->willReturn((object) $data);
$this->metadata
->expects($this->exactly(1))
->method('getCustom')
->willReturn((object) []);
$this->metadata
->expects($this->never())
->method('saveCustom');
$this->fieldManager->update('Account', 'name', $data);
}
public function testUpdateCustomField(): void
{
$data = [
"type" => "varchar",
"maxLength" => "50",
"isCustom" => true,
];
$map = [
['entityDefs.CustomEntity.fields.varName.type', null, $data['type']],
[['entityDefs', 'CustomEntity', 'fields', 'varName'], null, $data],
['fields.varchar', null, null],
[['fields', 'varchar', 'hookClassName'], null, null],
["scopes.CustomEntity.customizable", null, true],
];
$this->metadata
->expects($this->any())
->method('get')
->willReturnMap($map);
$this->metadata
->expects($this->exactly(2))
->method('getObjects')
->willReturn((object) $data);
$this->metadata
->expects($this->once())
->method('saveCustom');
$this->metadataHelper
->expects($this->once())
->method('getFieldDefsByType')
->willReturn(json_decode('{
"params":[
{
"name":"required",
"type":"bool",
"default":false
},
{
"name":"default",
"type":"varchar"
},
{
"name":"maxLength",
"type":"int"
},
{
"name":"trim",
"type":"bool",
"default": true
},
{
"name": "options",
"type": "multiEnum"
},
{
"name":"audited",
"type":"bool"
},
{
"name":"readOnly",
"type":"bool"
}
],
"filter": true,
"personalData": true,
"textFilter": true,
"fullTextSearch": true
}', true));
$data = [
"type" => "varchar",
"maxLength" => "150",
"required" => true,
"isCustom" => true,
];
$this->metadata
->expects($this->exactly(2))
->method('getCustom')
->willReturn((object) []);
$this->fieldManager->update('CustomEntity', 'varName', $data);
}
public function testRead(): void
{
$data = [
"type" => "varchar",
"maxLength" => "50",
"isCustom" => true,
"label" => 'Var Name',
];
$this->metadata
->expects($this->once())
->method('getObjects')
->willReturn((object) $data);
$this->language
->expects($this->once())
->method('translate')
->willReturn('Var Name');
$this->assertEquals($data, $this->fieldManager->read('Account', 'varName'));
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace tests\unit\Espo\Tools\LeadCapture;
use Espo\Core\Utils\Language;
use Espo\Core\Utils\Theme\Direction;
use Espo\Entities\LeadCapture;
use Espo\Tools\LeadCapture\ThemeDirectionDetector;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class ThemeDirectionDetectorTest extends TestCase
{
/**
* @return iterable<string, array{string, Direction}>
*/
public static function directionProvider(): iterable
{
yield ['ar_AR', Direction::Rtl];
yield ['fa_IR', Direction::Rtl];
yield ['he_IL', Direction::Rtl];
yield ['ur_IN', Direction::Rtl];
yield ['en_US', Direction::Ltr];
yield ['tr_TR', Direction::Ltr];
}
#[DataProvider('directionProvider')]
public function testDirectionFromFormLanguage(string $language, Direction $expected): void
{
$leadCapture = $this->createMock(LeadCapture::class);
$leadCapture
->method('getFormLanguage')
->willReturn($language);
$language = $this->createMock(Language::class);
$language
->method('getLanguage')
->willReturn('en_US');
$detector = new ThemeDirectionDetector(
language: $language,
);
$this->assertEquals($expected, $detector->detect($leadCapture));
}
}

View File

@@ -0,0 +1,131 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\MassUpdate;
use Espo\Core\MassAction\Data as MassActionData;
use Espo\Tools\MassUpdate\Data;
use Espo\Tools\MassUpdate\Action;
class DataTest extends \PHPUnit\Framework\TestCase
{
public function testData1(): void
{
$massActionData = MassActionData::fromRaw(
(object) [
'values' => (object) [
'a1' => '1',
'a2' => '2',
'a3' => '3',
],
'actions' => (object) [
'a1' => 'update',
'a2' => 'add',
'a3' => 'remove',
],
],
);
$data = Data::fromMassActionData($massActionData);
$this->assertEquals('1', $data->getValue('a1'));
$this->assertEquals(null, $data->getValue('a0'));
$this->assertEquals(true, $data->has('a1'));
$this->assertEquals(false, $data->has('a0'));
$this->assertEquals(['a1', 'a2', 'a3'], $data->getAttributeList());
$this->assertEquals(
(object) [
'a1' => '1',
'a2' => '2',
'a3' => '3',
],
$data->getValues()
);
$this->assertEquals(Action::UPDATE, $data->getAction('a1'));
$this->assertEquals(Action::ADD, $data->getAction('a2'));
$this->assertEquals(Action::REMOVE, $data->getAction('a3'));
$this->assertEquals('1m', $data->with('a1', '1m')->getValue('a1'));
$this->assertEquals(false, $data->without('a1')->has('a1'));
$massActionDataModified = $data
->with('a1', '1m', Action::ADD)
->without('a2')
->toMassActionData();
$values = $massActionDataModified->get('values');
$actions = $massActionDataModified->get('actions');
$this->assertEquals('1m', $values->a1);
$this->assertFalse(property_exists($values, 'a2'));
$this->assertEquals(Action::ADD, $actions->a1);
$this->assertFalse(property_exists($actions, 'a2'));
}
public function testCreate(): void
{
$data = Data::create()
->with('a1', null, Action::UPDATE)
->with('a2', ['1'], Action::ADD);
$this->assertEquals(null, $data->getValue('a1'));
$this->assertEquals(['1'], $data->getValue('a2'));
$this->assertEquals(Action::ADD, $data->getAction('a2'));
}
public function testWith(): void
{
$data = Data::create()
->with('a1', '1', Action::ADD)
->with('a1', '2')
->with('a2', '2');
$this->assertEquals(Action::ADD, $data->getAction('a1'));
$this->assertEquals(Action::UPDATE, $data->getAction('a2'));
}
public function testBc(): void
{
$massActionData = MassActionData::fromRaw(
(object) [
'a1' => '1',
'a2' => '2',
'a3' => '3',
],
);
$data = Data::fromMassActionData($massActionData);
$this->assertEquals('1', $data->getValue('a1'));
$this->assertEquals(Action::UPDATE, $data->getAction('a1'));
}
}

View File

@@ -0,0 +1,109 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\MassUpdate;
use Espo\Tools\MassUpdate\Data;
use Espo\Tools\MassUpdate\ValueMapPreparator;
use Espo\Tools\MassUpdate\Action;
use Espo\ORM\Entity;
use Espo\ORM\Defs as OrmDefs;
use PHPUnit\Framework\TestCase;
class ValueMapPreparatorTest extends TestCase
{
public function testPrepare1(): void
{
$preparator = new ValueMapPreparator(
$this->createMock(OrmDefs::class)
);
$data = Data::create()
->with('a1', ['1', '2'], Action::ADD)
->with('a2', ['1', '2', '3'], Action::REMOVE)
->with('a3', ['1', '2'], Action::UPDATE)
->with('a4', ['1'], Action::REMOVE)
->with('a5', [], Action::ADD)
->with('a6', [], Action::REMOVE)
->with('a7', ['1'], Action::ADD)
->with('a8', ['1'], Action::REMOVE)
->with('a9', null, Action::REMOVE)
->with('a10', null, Action::ADD)
->with('a11', null, Action::UPDATE)
->with('a12', (object) ['k2' => 'v2'], Action::ADD)
->with('a13', (object) ['k2' => 'v2'], Action::REMOVE);
$entity = $this->createMock(Entity::class);
$entity
->expects($this->any())
->method('has')
->willReturn(true);
$entity
->expects($this->any())
->method('get')
->willReturnCallback(
function ($attribute) {
$map = [
'a1' => ['0'],
'a2' => ['0', '1', '2'],
'a3' => ['0'],
'a4' => ['1'],
'a5' => ['1'],
'a6' => ['1'],
'a7' => null,
'a8' => null,
'a12' => (object) ['k1' => 'v1'],
'a13' => (object) ['k1' => 'v1', 'k2' => 'v2'],
];
return $map[$attribute] ?? null;
}
);
$values = $preparator->prepare($entity, $data);
$this->assertEquals(['0', '1', '2'], $values->a1);
$this->assertEquals(['0'], $values->a2);
$this->assertEquals(['1', '2'], $values->a3);
$this->assertEquals([], $values->a4);
$this->assertEquals(['1'], $values->a5);
$this->assertEquals(['1'], $values->a6);
$this->assertEquals(['1'], $values->a7);
$this->assertEquals([], $values->a8);
$this->assertFalse(property_exists($values, 'a9'));
$this->assertFalse(property_exists($values, 'a10'));
$this->assertEquals(null, $values->a11);
$this->assertEquals((object) ['k1' => 'v1', 'k2' => 'v2'], $values->a12);
$this->assertEquals((object) ['k1' => 'v1'], $values->a13);
}
}

View File

@@ -0,0 +1,77 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\Meeting;
use Espo\Modules\Crm\Business\Event\Ics;
use PHPUnit\Framework\TestCase;
class IcsTest extends TestCase
{
public function testIcs1(): void
{
$ics = new Ics('//EspoCRM//EspoCRM Calendar//EN', [
'method' => Ics::METHOD_REQUEST,
'status' => Ics::STATUS_CONFIRMED,
'startDate' => strtotime('2025-01-01 10:00:00'),
'endDate' => strtotime('2025-01-01 11:00:00'),
'uid' => 'test-id',
'summary' => 'Test',
'organizer' => ['hello@test.com', 'Hello Test'],
'description' => 'Test.',
'stamp' => strtotime('2025-01-01 09:00:00'),
'attendees' => [
['att1@test.com', 'Att 1', 'TENTATIVE'],
['att2@test.com', 'Att 2'],
],
]);
$expected =
"BEGIN:VCALENDAR\r\n".
"VERSION:2.0\r\n".
"PRODID:-//EspoCRM//EspoCRM Calendar//EN\r\n".
"METHOD:REQUEST\r\n".
"BEGIN:VEVENT\r\n".
"DTSTART:20250101T100000Z\r\n".
"DTEND:20250101T110000Z\r\n".
"SUMMARY:Test\r\n".
"ORGANIZER;CN=Hello Test:MAILTO:hello@test.com\r\n".
"DESCRIPTION:Test.\r\n".
"UID:test-id\r\n".
"SEQUENCE:0\r\n".
"DTSTAMP:20250101T090000Z\r\n".
"STATUS:CONFIRMED\r\n".
"ATTENDEE;PARTSTAT=TENTATIVE;CN=Att 1:MAILTO:att1@test.com\r\n".
"ATTENDEE;CN=Att 2:MAILTO:att2@test.com\r\n".
"END:VEVENT\r\n".
"END:VCALENDAR";
$this->assertEquals($expected, $ics->get());
}
}

View File

@@ -0,0 +1,58 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\OAuthServer\Scope;
use Espo\Core\Acl\Scope;
use Espo\Modules\Crm\Entities\Account;
use Espo\Modules\Crm\Entities\Lead;
use Espo\Tools\OAuthServer\Scope\ScopeSorter;
use PHPUnit\Framework\TestCase;
class ScopeSorterTest extends TestCase
{
public function testSort(): void
{
$sorted = (new ScopeSorter())->sort([
Lead::ENTITY_TYPE,
Account::ENTITY_TYPE,
Scope::ADMIN,
Scope::GLOBAL,
]);
$expected = [
Scope::GLOBAL,
Scope::ADMIN,
Account::ENTITY_TYPE,
Lead::ENTITY_TYPE,
];
$this->assertEquals($expected, $sorted);
}
}

View File

@@ -0,0 +1,86 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\Stream;
use Espo\Core\Utils\Config;
use Espo\Entities\Note;
use Espo\Tools\Stream\NoteUtil;
use PHPUnit\Framework\TestCase;
class NoteUtilTest extends TestCase
{
public function testLink(): void
{
$post = "https://site.com/#Account/view/100 https://site.com/#Account/view/100";
$newPost = "[Account/100](#Account/view/100) [Account/100](#Account/view/100)";
$this->initText($post, $newPost);
$post = " https://site.com/#Account/view/100";
$newPost = " [Account/100](#Account/view/100)";
$this->initText($post, $newPost);
$post = "\nhttps://site.com/#Account/view/100";
$newPost = "\n[Account/100](#Account/view/100)";
$this->initText($post, $newPost);
}
public function testLinkWrapped(): void
{
$post = "[Test](https://site.com/#Account/view/100) https://site.com/#Account/view/100";
$newPost = "[Test](https://site.com/#Account/view/100) [Account/100](#Account/view/100)";
$this->initText($post, $newPost);
}
private function initText(string $post, string $newPost): void
{
$config = $this->createMock(Config\ApplicationConfig::class);
$note = $this->createMock(Note::class);
$config->expects($this->once())
->method('getSiteUrl')
->willReturn('https://site.com');
$util = new NoteUtil($config);
$note->expects($this->once())
->method('getPost')
->willReturn($post);
$note->expects($this->once())
->method('setPost')
->with($newPost);
$util->handlePostText($note);
}
}

View File

@@ -0,0 +1,76 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\UserSecurity\Password;
use Espo\Tools\UserSecurity\Password\Checker;
use Espo\Tools\UserSecurity\Password\ConfigProvider;
use PHPUnit\Framework\TestCase;
class CheckerTest extends TestCase
{
public function testCheck(): void
{
$configProvider = $this->createMock(ConfigProvider::class);
$configProvider
->expects($this->any())
->method('getStrengthLength')
->willReturn(6);
$configProvider
->expects($this->any())
->method('getStrengthLetterCount')
->willReturn(2);
$configProvider
->expects($this->any())
->method('getStrengthNumberCount')
->willReturn(1);
$configProvider
->expects($this->any())
->method('getStrengthBothCases')
->willReturn(true);
$configProvider
->expects($this->any())
->method('getStrengthSpecialCharacterCount')
->willReturn(1);
$checker = new Checker($configProvider);
$this->assertTrue($checker->checkStrength("Aa1:aaaaaaaaa"));
$this->assertFalse($checker->checkStrength("Aa1aaaaaaaaa"));
$this->assertFalse($checker->checkStrength("aa1:aaaaaaaaa"));
$this->assertFalse($checker->checkStrength("aaa:aaaaaaaaa"));
$this->assertFalse($checker->checkStrength("11:11111111"));
$this->assertFalse($checker->checkStrength("Aa:1"));
}
}

View File

@@ -0,0 +1,78 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\UserSecurity\Password;
use Espo\Tools\UserSecurity\Password\ConfigProvider;
use Espo\Tools\UserSecurity\Password\Generator;
use PHPUnit\Framework\TestCase;
class GeneratorTest extends TestCase
{
public function testGenerate(): void
{
$configProvider = $this->createMock(ConfigProvider::class);
$configProvider
->expects($this->any())
->method('getGenerateLength')
->willReturn(8);
$configProvider
->expects($this->any())
->method('getStrengthLength')
->willReturn(6);
$configProvider
->expects($this->any())
->method('getStrengthLetterCount')
->willReturn(2);
$configProvider
->expects($this->any())
->method('getStrengthNumberCount')
->willReturn(1);
$configProvider
->expects($this->any())
->method('getStrengthBothCases')
->willReturn(true);
$configProvider
->expects($this->any())
->method('getStrengthSpecialCharacterCount')
->willReturn(1);
$generator = new Generator($configProvider);
$password = $generator->generate();
$this->assertEquals(8, strlen($password));
}
}

View File

@@ -0,0 +1,59 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\UserSecurity\Password;
use Espo\Tools\UserSecurity\Password\Recovery\UrlValidatorUtil;
use PHPUnit\Framework\TestCase;
class UrlValidatorUtilTest extends TestCase
{
public function testValidate(): void
{
$this->assertTrue(
UrlValidatorUtil::validate('https://test.com', 'https://test.com')
);
$this->assertTrue(
UrlValidatorUtil::validate('https://test.com/test', 'https://test.com')
);
$this->assertTrue(
UrlValidatorUtil::validate('https://test.com/test', 'https://test.com/test')
);
$this->assertFalse(
UrlValidatorUtil::validate('https://test.com.test', 'https://test.com')
);
$this->assertFalse(
UrlValidatorUtil::validate('https://test.com.test<test', 'https://test.com')
);
}
}

View File

@@ -0,0 +1,284 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\WorkingTime;
use Espo\Core\Field\DateTime;
use Espo\Tools\WorkingTime\Calendar;
use Espo\Tools\WorkingTime\CalendarUtility;
use Espo\Tools\WorkingTime\Extractor;
use PHPUnit\Framework\TestCase;
use RuntimeException;
class CalendarUtilityTest extends TestCase
{
protected Calendar $calendar;
protected Extractor $extractor;
protected CalendarUtility $calendarUtility;
protected function setUp(): void
{
$this->calendar = $this->createMock(Calendar::class);
$this->extractor = $this->createMock(Extractor::class);
$this->calendarUtility = new CalendarUtility($this->calendar, $this->extractor);
}
public function testHasWorkingDay1(): void
{
$time = DateTime::fromString('2023-01-01 01:01:01');
$from = DateTime::fromString('2023-01-01 00:00:00');
$to = DateTime::fromString('2023-01-01 00:00:00');
$this->extractor
->expects($this->any())
->method('extractAllDay')
->with($this->calendar, $from, $to)
->willReturn([
[
$from,
$to
]
]);
$this->assertTrue($this->calendarUtility->isWorkingDay($time));
}
public function testHasWorkingTime1(): void
{
$from = DateTime::fromString('2023-01-01 00:00:00');
$to = DateTime::fromString('2023-01-02 00:00:00');
$this->extractor
->expects($this->any())
->method('extract')
->with($this->calendar, $from, $to)
->willReturn([
[
DateTime::fromString('2023-01-01 05:00:00'),
DateTime::fromString('2023-01-01 06:00:00')
]
]);
$this->assertTrue($this->calendarUtility->hasWorkingTime($from, $to));
}
public function testHasWorkingTime2(): void
{
$from = DateTime::fromString('2023-01-01 00:00:00');
$to = DateTime::fromString('2023-01-02 00:00:00');
$this->extractor
->expects($this->any())
->method('extract')
->with($this->calendar, $from, $to)
->willReturn([]);
$this->assertFalse($this->calendarUtility->hasWorkingTime($from, $to));
}
public function testGetSummedWorkingHours1(): void
{
$from = DateTime::fromString('2023-01-01 00:00:00');
$to = DateTime::fromString('2023-01-02 00:00:00');
$this->extractor
->expects($this->any())
->method('extract')
->with($this->calendar, $from, $to)
->willReturn([
[
DateTime::fromString('2023-01-01 05:00:00'),
DateTime::fromString('2023-01-01 06:00:00')
],
[
DateTime::fromString('2023-01-01 07:00:00'),
DateTime::fromString('2023-01-01 08:00:00')
]
]);
$this->assertEquals(2.0, $this->calendarUtility->getSummedWorkingHours($from, $to));
}
public function testGetWorkingDays1(): void
{
$from = DateTime::fromString('2023-01-01 00:00:00');
$to = DateTime::fromString('2023-01-07 00:00:00');
$this->extractor
->expects($this->any())
->method('extractAllDay')
->with($this->calendar, $from, $to)
->willReturn([
[
DateTime::fromString('2023-01-01 00:00:00'),
DateTime::fromString('2023-01-02 00:00:00')
],
[
DateTime::fromString('2023-01-04 00:00:00'),
DateTime::fromString('2023-01-05 00:00:00')
]
]);
$this->assertEquals(2, $this->calendarUtility->getWorkingDays($from, $to));
}
public function testFindClosestWorkingTime1(): void
{
$point = DateTime::fromString('2023-01-01 00:00:00');
$invokedCount = $this->exactly(2);
$this->extractor
->expects($invokedCount)
->method('extract')
->willReturnCallback(function ($calendar, $a, $b) use ($invokedCount, $point) {
if ($invokedCount->numberOfInvocations() === 1) {
$this->assertEquals($this->calendar, $calendar);
$this->assertEquals($point, $a);
$this->assertEquals($point->modify('+10 days'), $b);
return [];
}
if ($invokedCount->numberOfInvocations() === 2) {
$this->assertEquals($this->calendar, $calendar);
$this->assertEquals($point->modify('+10 days'), $a);
$this->assertEquals($point->modify('+20 days'), $b);
return [
[
DateTime::fromString('2023-01-11 01:00:00'),
DateTime::fromString('2023-01-11 02:00:00')
],
];
}
throw new RuntimeException();
});
$found = $this->calendarUtility->findClosestWorkingTime($point);
$this->assertEquals(DateTime::fromString('2023-01-11 01:00:00'), $found);
}
public function testFindClosestWorkingTime2(): void
{
$time = DateTime::fromString('2023-01-01 00:00:00');
$this->extractor
->expects($this->exactly(20))
->method('extract')
->willReturn([]);
$found = $this->calendarUtility->findClosestWorkingTime($time);
$this->assertEquals(null, $found);
}
public function testAddWorkingDays1(): void
{
$time = DateTime::fromString('2023-01-01 01:00:00');
$point = $time->withTime(0, 0, 0)->modify('+1 day');
$invokedCount = $this->exactly(2);
$this->extractor
->expects($invokedCount)
->method('extractAllDay')
->willReturnCallback(function ($calendar, $a, $b) use ($invokedCount, $point) {
if ($invokedCount->numberOfInvocations() === 1) {
$this->assertEquals($this->calendar, $calendar);
$this->assertEquals($point, $a);
$this->assertEquals($point->modify('+30 days'), $b);
return [];
}
if ($invokedCount->numberOfInvocations() === 2) {
$this->assertEquals($this->calendar, $calendar);
$this->assertEquals($point->modify('+30 days'), $a);
$this->assertEquals($point->modify('+60 days'), $b);
return [
[
DateTime::fromString('2023-04-01 00:00:00'),
DateTime::fromString('2023-04-01 00:00:00')
],
];
}
throw new RuntimeException();
});
$found = $this->calendarUtility->addWorkingDays($time, 1);
$this->assertEquals(DateTime::fromString('2023-04-01 00:00:00'), $found);
}
public function testAddWorkingDays2(): void
{
$time = DateTime::fromString('2023-01-01 01:00:00');
$point = $time->withTime(0, 0, 0)->modify('+1 day');
$invokedCount = $this->exactly(1);
$this->extractor
->expects($invokedCount)
->method('extractAllDay')
->willReturnCallback(function ($calendar, $a, $b) use ($invokedCount, $point) {
if ($invokedCount->numberOfInvocations() === 1) {
$this->assertEquals($this->calendar, $calendar);
$this->assertEquals($point, $a);
$this->assertEquals($point->modify('+30 days'), $b);
return [
[
DateTime::fromString('2023-01-02 00:00:00'),
DateTime::fromString('2023-01-03 00:00:00')
],
[
DateTime::fromString('2023-01-03 00:00:00'),
DateTime::fromString('2023-01-04 00:00:00')
],
];
}
throw new RuntimeException();
});
$found = $this->calendarUtility->addWorkingDays($time, 2);
$this->assertEquals(DateTime::fromString('2023-01-03 00:00:00'), $found);
}
}

View File

@@ -0,0 +1,267 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\unit\Espo\Tools\WorkingTime;
use Espo\Tools\WorkingTime\Calendar;
use Espo\Tools\WorkingTime\Calendar\Time;
use Espo\Tools\WorkingTime\Calendar\TimeRange;
use Espo\Tools\WorkingTime\Calendar\WorkingDate;
use Espo\Tools\WorkingTime\Calendar\WorkingWeekday;
use Espo\Tools\WorkingTime\Extractor;
use Espo\Core\Field\DateTime;
use Espo\Core\Field\Date;
use DateTimeZone;
class ExtractorTest extends \PHPUnit\Framework\TestCase
{
protected Calendar $calendar;
protected function setUp(): void
{
$this->calendar = $this->createMock(Calendar::class);
}
private function initCalendar1(): void
{
$this->calendar
->expects($this->any())
->method('getTimeZone')
->willReturn(new DateTimeZone('UTC'));
$ranges = [
new TimeRange(new Time(9, 0), new Time(13, 0)),
new TimeRange(new Time(14, 0), new Time(17, 0)),
];
$this->calendar
->expects($this->any())
->method('getWorkingDates')
->willReturn([
new WorkingDate(
new Date('2022-01-05'),
[
new TimeRange(new Time(10, 30), new Time(15, 30)),
]
),
new WorkingDate(
new Date('2022-01-09'),
[
new TimeRange(new Time(10, 30), new Time(15, 30)),
]
)
]);
$this->calendar
->expects($this->any())
->method('getNonWorkingDates')
->willReturn([
new WorkingDate(new Date('2022-01-06')),
new WorkingDate(new Date('2022-01-10')),
]);
$this->calendar
->expects($this->any())
->method('getWorkingWeekdays')
->willReturn([
new WorkingWeekday(1, $ranges),
new WorkingWeekday(2, $ranges),
new WorkingWeekday(3, $ranges),
new WorkingWeekday(4, $ranges),
new WorkingWeekday(5, $ranges),
]);
}
public function testExtract1(): void
{
$this->initCalendar1();
$extractor = new Extractor();
$list = $extractor->extract(
$this->calendar,
DateTime::fromString('2022-01-02 00:00:00'), // sun
DateTime::fromString('2022-01-17 00:00:00') // sun
);
// mon
$this->assertEquals('2022-01-03 09:00:00', $list[0][0]->getString());
$this->assertEquals('2022-01-03 13:00:00', $list[0][1]->getString());
$this->assertEquals('2022-01-03 14:00:00', $list[1][0]->getString());
$this->assertEquals('2022-01-03 17:00:00', $list[1][1]->getString());
// tue
$this->assertEquals('2022-01-04 09:00:00', $list[2][0]->getString());
$this->assertEquals('2022-01-04 13:00:00', $list[2][1]->getString());
$this->assertEquals('2022-01-04 14:00:00', $list[3][0]->getString());
$this->assertEquals('2022-01-04 17:00:00', $list[3][1]->getString());
// wed working-date
$this->assertEquals('2022-01-05 10:30:00', $list[4][0]->getString());
$this->assertEquals('2022-01-05 15:30:00', $list[4][1]->getString());
// thu non-working-date
// fri
$this->assertEquals('2022-01-07 09:00:00', $list[5][0]->getString());
$this->assertEquals('2022-01-07 13:00:00', $list[5][1]->getString());
$this->assertEquals('2022-01-07 14:00:00', $list[6][0]->getString());
$this->assertEquals('2022-01-07 17:00:00', $list[6][1]->getString());
// sat
// sun working-day
$this->assertEquals('2022-01-09 10:30:00', $list[7][0]->getString());
$this->assertEquals('2022-01-09 15:30:00', $list[7][1]->getString());
// mon non-working-day
// tue
$this->assertEquals('2022-01-11 09:00:00', $list[8][0]->getString());
$this->assertEquals('2022-01-11 13:00:00', $list[8][1]->getString());
$this->assertEquals('2022-01-11 14:00:00', $list[9][0]->getString());
$this->assertEquals('2022-01-11 17:00:00', $list[9][1]->getString());
}
public function testExtractInversion1(): void
{
$this->initCalendar1();
$extractor = new Extractor();
$listInversion = $extractor->extractInversion(
$this->calendar,
DateTime::fromString('2022-01-02 00:00:00'), // sun
DateTime::fromString('2022-01-17 00:00:00') // sun
);
$this->assertEquals('2022-01-02 00:00:00', $listInversion[0][0]->getString());
$this->assertEquals('2022-01-03 09:00:00', $listInversion[0][1]->getString());
$this->assertEquals('2022-01-14 13:00:00', $listInversion[15][0]->getString());
$this->assertEquals('2022-01-14 14:00:00', $listInversion[15][1]->getString());
$this->assertEquals('2022-01-14 17:00:00', $listInversion[16][0]->getString());
$this->assertEquals('2022-01-17 00:00:00', $listInversion[16][1]->getString());
$listAllDayInversion = $extractor->extractAllDayInversion(
$this->calendar,
DateTime::fromString('2022-01-02 00:00:00'), // sun
DateTime::fromString('2022-01-17 00:00:00') // sun
);
$this->assertEquals('2022-01-02 00:00:00', $listAllDayInversion[0][0]->getString());
$this->assertEquals('2022-01-03 00:00:00', $listAllDayInversion[0][1]->getString());
$this->assertEquals('2022-01-14 00:00:00', $listAllDayInversion[8][0]->getString());
$this->assertEquals('2022-01-14 00:00:00', $listAllDayInversion[8][1]->getString());
$this->assertEquals('2022-01-15 00:00:00', $listAllDayInversion[9][0]->getString());
$this->assertEquals('2022-01-17 00:00:00', $listAllDayInversion[9][1]->getString());
}
public function testExtractAllDay1(): void
{
$this->initCalendar1();
$extractor = new Extractor();
$listAllDay = $extractor->extractAllDay(
$this->calendar,
DateTime::fromString('2022-01-02 00:00:00'), // sun
DateTime::fromString('2022-01-17 00:00:00') // sun
);
// mon
$this->assertEquals('2022-01-03 00:00:00', $listAllDay[0][0]->getString());
$this->assertEquals('2022-01-04 00:00:00', $listAllDay[0][1]->getString());
// tue
$this->assertEquals('2022-01-04 00:00:00', $listAllDay[1][0]->getString());
$this->assertEquals('2022-01-05 00:00:00', $listAllDay[1][1]->getString());
// wed
$this->assertEquals('2022-01-05 00:00:00', $listAllDay[2][0]->getString());
$this->assertEquals('2022-01-06 00:00:00', $listAllDay[2][1]->getString());
// thu non-working-date
// fri
$this->assertEquals('2022-01-07 00:00:00', $listAllDay[3][0]->getString());
$this->assertEquals('2022-01-08 00:00:00', $listAllDay[3][1]->getString());
// sat
// sun working-day
$this->assertEquals('2022-01-09 00:00:00', $listAllDay[4][0]->getString());
$this->assertEquals('2022-01-10 00:00:00', $listAllDay[4][1]->getString());
// mon non-working-day
// tue
$this->assertEquals('2022-01-11 00:00:00', $listAllDay[5][0]->getString());
$this->assertEquals('2022-01-12 00:00:00', $listAllDay[5][1]->getString());
}
public function testExtract2(): void
{
$this->initCalendar1();
$extractor = new Extractor();
$list = $extractor->extract(
$this->calendar,
DateTime::fromString('2022-01-03 10:00:00'),
DateTime::fromString('2022-01-14 15:00:00')
);
$this->assertEquals('2022-01-03 10:00:00', $list[0][0]->getString());
$this->assertEquals('2022-01-14 15:00:00', $list[count($list) - 1][1]->getString());
}
public function testExtract3(): void
{
$this->initCalendar1();
$extractor = new Extractor();
$list = $extractor->extract(
$this->calendar,
DateTime::fromString('2022-01-03 16:00:00'),
DateTime::fromString('2022-01-14 15:00:00')
);
$this->assertEquals('2022-01-03 16:00:00', $list[0][0]->getString());
$this->assertEquals('2022-01-03 17:00:00', $list[0][1]->getString());
$this->assertEquals('2022-01-14 15:00:00', $list[count($list) - 1][1]->getString());
}
}