-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Check for support of 4Byte in database and existence of IntlBreakIter…
…ator class Signed-off-by: Georg Ehrke <[email protected]>
- Loading branch information
1 parent
e6d8b70
commit 32dd658
Showing
6 changed files
with
299 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/** | ||
* @copyright Copyright (c) 2020, Georg Ehrke | ||
* | ||
* @author Georg Ehrke <[email protected]> | ||
* | ||
* @license AGPL-3.0 | ||
* | ||
* This code is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License, version 3, | ||
* as published by the Free Software Foundation. | ||
* | ||
* 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, version 3, | ||
* along with this program. If not, see <http://www.gnu.org/licenses/> | ||
* | ||
*/ | ||
|
||
namespace OCA\UserStatus\Service; | ||
|
||
use OCP\IDBConnection; | ||
|
||
/** | ||
* Class EmojiService | ||
* | ||
* @package OCA\UserStatus\Service | ||
*/ | ||
class EmojiService { | ||
|
||
/** @var IDBConnection */ | ||
private $db; | ||
|
||
/** | ||
* EmojiService constructor. | ||
* | ||
* @param IDBConnection $db | ||
*/ | ||
public function __construct(IDBConnection $db) { | ||
$this->db = $db; | ||
} | ||
|
||
/** | ||
* @return bool | ||
*/ | ||
public function doesPlatformSupportEmoji(): bool { | ||
return $this->db->supports4ByteText() && | ||
\class_exists(\IntlBreakIterator::class); | ||
} | ||
|
||
/** | ||
* @param string $emoji | ||
* @return bool | ||
*/ | ||
public function isValidEmoji(string $emoji): bool { | ||
$intlBreakIterator = \IntlBreakIterator::createCharacterInstance(); | ||
$intlBreakIterator->setText($emoji); | ||
|
||
$characterCount = 0; | ||
while ($intlBreakIterator->next() !== \IntlBreakIterator::DONE) { | ||
$characterCount++; | ||
} | ||
|
||
if ($characterCount !== 1) { | ||
return false; | ||
} | ||
|
||
$codePointIterator = \IntlBreakIterator::createCodePointInstance(); | ||
$codePointIterator->setText($emoji); | ||
|
||
foreach ($codePointIterator->getPartsIterator() as $codePoint) { | ||
$codePointType = \IntlChar::charType($codePoint); | ||
|
||
// If the current code-point is an emoji or a modifier (like a skin-tone) | ||
// just continue and check the next character | ||
if ($codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_SYMBOL || | ||
$codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_LETTER || | ||
$codePointType === \IntlChar::CHAR_CATEGORY_OTHER_SYMBOL) { | ||
continue; | ||
} | ||
|
||
// If it's neither a modifier nor an emoji, we only allow | ||
// a zero-width-joiner or a variation selector 16 | ||
$codePointValue = \IntlChar::ord($codePoint); | ||
if ($codePointValue === 8205 || $codePointValue === 65039) { | ||
continue; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
apps/user_status/tests/Unit/Service/EmojiServiceTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/** | ||
* @copyright Copyright (c) 2020, Georg Ehrke | ||
* | ||
* @author Georg Ehrke <[email protected]> | ||
* | ||
* @license AGPL-3.0 | ||
* | ||
* This code is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License, version 3, | ||
* as published by the Free Software Foundation. | ||
* | ||
* 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, version 3, | ||
* along with this program. If not, see <http://www.gnu.org/licenses/> | ||
* | ||
*/ | ||
|
||
namespace OCA\UserStatus\Tests\Service; | ||
|
||
use OCA\UserStatus\Service\EmojiService; | ||
use OCP\IDBConnection; | ||
use Test\TestCase; | ||
|
||
class EmojiServiceTest extends TestCase { | ||
|
||
/** @var IDBConnection|\PHPUnit\Framework\MockObject\MockObject */ | ||
private $db; | ||
|
||
/** @var EmojiService */ | ||
private $service; | ||
|
||
protected function setUp(): void { | ||
parent::setUp(); | ||
|
||
$this->db = $this->createMock(IDBConnection::class); | ||
$this->service = new EmojiService($this->db); | ||
} | ||
|
||
/** | ||
* @param bool $supports4ByteText | ||
* @param bool $expected | ||
* | ||
* @dataProvider doesPlatformSupportEmojiDataProvider | ||
*/ | ||
public function testDoesPlatformSupportEmoji(bool $supports4ByteText, bool $expected): void { | ||
$this->db->expects($this->once()) | ||
->method('supports4ByteText') | ||
->willReturn($supports4ByteText); | ||
|
||
$this->assertEquals($expected, $this->service->doesPlatformSupportEmoji()); | ||
} | ||
|
||
/** | ||
* @return array | ||
*/ | ||
public function doesPlatformSupportEmojiDataProvider(): array { | ||
return [ | ||
[true, true], | ||
[false, false], | ||
]; | ||
} | ||
|
||
/** | ||
* @param string $emoji | ||
* @param bool $expected | ||
* | ||
* @dataProvider isValidEmojiDataProvider | ||
*/ | ||
public function testIsValidEmoji(string $emoji, bool $expected): void { | ||
$actual = $this->service->isValidEmoji($emoji); | ||
|
||
$this->assertEquals($expected, $actual); | ||
} | ||
|
||
public function isValidEmojiDataProvider(): array { | ||
return [ | ||
['🏝', true], | ||
['📱', true], | ||
['🏢', true], | ||
['📱📠', false], | ||
['a', false], | ||
['0', false], | ||
['$', false], | ||
// Test some more complex emojis with modifiers and zero-width-joiner | ||
['👩🏿💻', true], | ||
['🤷🏼♀️', true], | ||
['🏳️🌈', true], | ||
['👨👨👦👦', true], | ||
['👩❤️👩', true] | ||
]; | ||
} | ||
} |
Oops, something went wrong.