at the end of the day, it was inevitable

This commit is contained in:
Mo Elzubeir
2022-12-09 08:36:26 -06:00
commit 1218570914
1768 changed files with 887087 additions and 0 deletions
@@ -0,0 +1,271 @@
<?php
namespace AppBundle\AdvancedFilters\Elasticsearch;
use AppBundle\AdvancedFilters\AdvancedFiltersConfig;
use AppBundle\AdvancedFilters\AFResolver;
use AppBundle\Form\Type\AdvancedFilter\AdvancedFilterParameters;
use Common\Enum\AFSourceEnum;
use Common\Enum\DocumentsAFNameEnum;
use Common\Enum\FieldNameEnum;
use Common\Enum\LanguageEnum;
use Faker\Factory;
use Faker\Generator;
use IndexBundle\Filter\Factory\FilterFactory;
use IndexBundle\Filter\Filters\AndFilter;
use IndexBundle\Filter\Filters\EqFilter;
use IndexBundle\Filter\Filters\GteFilter;
use IndexBundle\Filter\Filters\LteFilter;
use IndexBundle\Filter\Filters\OrFilter;
use IndexBundle\SearchRequest\SearchRequest;
use Tests\AppBundle\AdvancedFilters\TestAFAggregator;
use Tests\AppTestCase;
/**
* Class ElasticsearchAFResolverTest
* @package AppBundle\AdvancedFilters\Elasticsearch
*/
class ElasticsearchAFResolverTest extends AppTestCase
{
/**
* Fixtures for 'articleLanguage' advanced filter.
*
* @var array
*/
private static $languages = [
[
'value' => LanguageEnum::BENGALI,
'count' => 44,
],
[
'value' => LanguageEnum::VIETNAMESE,
'count' => 40,
],
[
'value' => LanguageEnum::DUTCH,
'count' => 35,
],
[
'value' => LanguageEnum::GERMAN,
'count' => 20,
],
[
'value' => LanguageEnum::GREEK,
'count' => 21,
],
[
'value' => LanguageEnum::FINNISH,
'count' => 14,
],
[
'value' => LanguageEnum::RUSSIAN,
'count' => 10,
],
[
'value' => LanguageEnum::ESTONIAN,
'count' => 7,
],
[
'value' => LanguageEnum::AFRIKAANS,
'count' => 5,
],
[
'value' => LanguageEnum::ARABIC,
'count' => 1,
],
[
'value' => LanguageEnum::BULGARIAN,
'count' => 1,
],
[
'value' => LanguageEnum::NORWEGIAN,
'count' => 1,
],
];
/**
* Fixtures for 'articleDate' advanced filter.
*
* @var array
*/
private static $dates = [
[
'value' => '1 Hour',
'count' => 20,
],
[
'value' => '24 Hour',
'count' => 45,
],
[
'value' => '7 Days',
'count' => 124,
],
[
'values' => '31 Days',
'count' => 2355,
],
[
'values' => '60 Days',
'count' => 1254151,
],
];
/**
* @var AFResolver
*/
private $resolver;
/**
* @var Generator
*/
private $faker;
/**
* @return void
*/
public function testGetAllAvailable()
{
/** @var SearchRequest $request */
$request = $this->getMockBuilder(SearchRequest::class)
->disableOriginalConstructor()
->getMock();
$values = $this->resolver->getAvailables($request);
self::assertArrayHasKey(DocumentsAFNameEnum::ARTICLE_LANGUAGE, $values);
self::assertArrayHasKey(DocumentsAFNameEnum::ARTICLE_DATE, $values);
self::assertMatch(
$values[DocumentsAFNameEnum::ARTICLE_LANGUAGE],
[
'data' => '@array@',
]
);
self::assertMatch(
$values[DocumentsAFNameEnum::ARTICLE_DATE],
[
'data' => '@array@',
]
);
}
/**
* @return void
*/
public function testGenerateFilterForLanguage()
{
/** @var OrFilter $filter */
$filter = $this->resolver->generateFilter(
AdvancedFiltersConfig::getConfig(AFSourceEnum::FEED),
DocumentsAFNameEnum::ARTICLE_LANGUAGE,
new AdvancedFilterParameters(LanguageEnum::DUTCH, [])
);
/** @var EqFilter $eqFilter */
$eqFilter = $filter->getFilters()[0];
self::assertInstanceOf(OrFilter::class, $filter);
self::assertInstanceOf(EqFilter::class, $eqFilter);
self::assertSame(FieldNameEnum::LANG, $eqFilter->getFieldName());
self::assertSame(LanguageEnum::DUTCH, $eqFilter->getValue());
}
/**
* @return void
*/
public function testGenerateFilterForDateWithTwoBounds()
{
/** @var AndFilter $filter */
$filter = $this->resolver->generateFilter(
AdvancedFiltersConfig::getConfig(AFSourceEnum::FEED),
DocumentsAFNameEnum::ARTICLE_DATE,
AdvancedFilterParameters::queryFilterParameters('24 Hour')
);
self::assertInstanceOf(AndFilter::class, $filter);
$filters = $filter->getFilters();
self::assertCount(2, $filters);
self::assertInstanceOf(GteFilter::class, $filters[0]);
self::assertInstanceOf(LteFilter::class, $filters[1]);
/** @var GteFilter $gteFilter */
$gteFilter = $filters[0];
self::assertSame(FieldNameEnum::PUBLISHED, $gteFilter->getFieldName());
self::assertSame('now-1d', $gteFilter->getValue());
/** @var LteFilter $lteFilter */
$lteFilter = $filters[1];
self::assertSame(FieldNameEnum::PUBLISHED, $lteFilter->getFieldName());
self::assertSame('now-2H', $lteFilter->getValue());
}
/**
* @return void
*/
public function testGenerateFilterForDateWithOneBound()
{
/** @var GteFilter $filter */
$filter = $this->resolver->generateFilter(
AdvancedFiltersConfig::getConfig(AFSourceEnum::FEED),
DocumentsAFNameEnum::ARTICLE_DATE,
AdvancedFilterParameters::queryFilterParameters('1 Hour')
);
self::assertInstanceOf(GteFilter::class, $filter);
self::assertSame(FieldNameEnum::PUBLISHED, $filter->getFieldName());
self::assertSame('now-1H', $filter->getValue());
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Unknown filter 'unknown'.
*
* @return void
*/
public function testGenerateFilterNameException()
{
$this->resolver->generateFilter(
AdvancedFiltersConfig::getConfig(AFSourceEnum::FEED),
'unknown',
new AdvancedFilterParameters('1 Hour', [])
);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Invalid value 'invalid'. Expects one of 1 Hour, 24 Hour, 7 Days, 31 Days, 60 Days.
*
* @return void
*/
public function testGenerateFilterForDateInvalidValueException()
{
$this->resolver->generateFilter(
AdvancedFiltersConfig::getConfig(AFSourceEnum::FEED),
DocumentsAFNameEnum::ARTICLE_DATE,
new AdvancedFilterParameters('invalid', [])
);
}
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*
* @return void
*/
protected function setUp()
{
$this->faker = Factory::create();
$aggregator = new TestAFAggregator([
DocumentsAFNameEnum::ARTICLE_LANGUAGE => self::$languages,
DocumentsAFNameEnum::ARTICLE_DATE => self::$dates,
]);
$factory = new FilterFactory();
$this->resolver = new AFResolver($aggregator, $factory);
}
}
@@ -0,0 +1,41 @@
<?php
namespace Tests\AppBundle\AdvancedFilters;
use AppBundle\AdvancedFilters\Aggregator\AFAggregatorInterface;
use IndexBundle\SearchRequest\SearchRequestInterface;
/**
* Class TestAFAggregator
* @package AppBundle\AdvancedFilters
*/
class TestAFAggregator implements AFAggregatorInterface
{
/**
* @var array
*/
private $values;
/**
* TestAFAggregator constructor.
*
* @param array $values Aggregator values.
*/
public function __construct(array $values)
{
$this->values = $values;
}
/**
* Return available filters values for specified request.
*
* @param SearchRequestInterface $request A SearchRequestInterface instance.
*
* @return array
*/
public function getValues(SearchRequestInterface $request)
{
return $this->values;
}
}
+144
View File
@@ -0,0 +1,144 @@
<?php
namespace app\a;
use IndexBundle\Index\Strategy\IndexStrategyInterface;
use IndexBundle\Model\ArticleDocument;
use Tests\AppTestCase;
/**
* Class ArrayTest
* @package AppFunctional
*/
class ArrayTest extends AppTestCase
{
/**
* @return void
*/
public function testBinarySearchForCollectionWithOddItemsNumber()
{
$collection = [ 1, 2, 3, 4, 5 ];
$this->assertSame(2, binarySearch($collection, 3));
$this->assertSame(0, binarySearch($collection, 1));
$this->assertSame(1, binarySearch($collection, 2));
$this->assertSame(4, binarySearch($collection, 5));
}
/**
* @return void
*/
public function testBinarySearchForCollectionWithEvenItemsNumber()
{
$collection = [ 1, 2, 3, 4, 5, 6];
$this->assertSame(2, binarySearch($collection, 3));
$this->assertSame(0, binarySearch($collection, 1));
$this->assertSame(1, binarySearch($collection, 2));
$this->assertSame(5, binarySearch($collection, 6));
}
/**
* @return void
*/
public function testBinarySearchSearchUnknownItem()
{
$collection = [ 1, 2, 3, 4, 5, 6];
$this->assertFalse(binarySearch($collection, 0));
$this->assertFalse(binarySearch($collection, 7));
$this->assertFalse(binarySearch($collection, -10));
$this->assertFalse(binarySearch($collection, 20));
}
/**
* @return void
*/
public function testBinarySearchInObject()
{
$collection = [
(object) [ 'id' => 1 ],
(object) [ 'id' => 2 ],
(object) [ 'id' => 3 ],
(object) [ 'id' => 4 ],
(object) [ 'id' => 5 ],
];
$this->assertSame(2, binarySearch($collection, 3, 'id'));
$this->assertSame(0, binarySearch($collection, 1, 'id'));
$this->assertSame(1, binarySearch($collection, 2, 'id'));
$this->assertSame(4, binarySearch($collection, 5, 'id'));
}
/**
* @return void
*/
public function testBinarySearchInObjectWithGetter()
{
$collection = [
new TestFixture(1),
new TestFixture(2),
new TestFixture(3),
new TestFixture(4),
new TestFixture(5),
];
$this->assertSame(2, binarySearch($collection, 3, \nspl\op\methodCaller('getId')));
$this->assertSame(0, binarySearch($collection, 1, \nspl\op\methodCaller('getId')));
$this->assertSame(1, binarySearch($collection, 2, \nspl\op\methodCaller('getId')));
$this->assertSame(4, binarySearch($collection, 5, \nspl\op\methodCaller('getId')));
}
/**
* @return void
*/
public function testBinarySearchInDocument()
{
/** @var IndexStrategyInterface $strategy */
$strategy = $this->getMockForInterface(IndexStrategyInterface::class);
$collection = [
new ArticleDocument($strategy, ['sequence' => 1]),
new ArticleDocument($strategy, ['sequence' => 2]),
new ArticleDocument($strategy, ['sequence' => 3]),
new ArticleDocument($strategy, ['sequence' => 4]),
new ArticleDocument($strategy, ['sequence' => 5]),
];
$this->assertSame(2, binarySearch($collection, 3, 'sequence'));
$this->assertSame(0, binarySearch($collection, 1, 'sequence'));
$this->assertSame(1, binarySearch($collection, 2, 'sequence'));
$this->assertSame(4, binarySearch($collection, 5, 'sequence'));
}
}
/**
* Class TestFixture
* @package AppFunctional
*/
class TestFixture
{
/**
* @var integer
*/
private $id;
/**
* TestFixture constructor.
*
* @param integer $id Identifier.
*/
public function __construct($id)
{
$this->id = $id;
}
/**
* @return integer
*/
public function getId()
{
return $this->id;
}
}
+15
View File
@@ -0,0 +1,15 @@
<?php
namespace Tests;
use PHPUnit\Framework\TestCase;
/**
* Class AppTestCase
* @package Tests
*/
class AppTestCase extends TestCase
{
use AppTestCaseTrait;
}
+94
View File
@@ -0,0 +1,94 @@
<?php
namespace Tests;
use Common\Util\Matcher\AppMatcher;
use PHPUnit\Framework\TestCase;
/**
* Trait AppTestCaseTrait
* @package Tests
*/
trait AppTestCaseTrait
{
/**
* Call public, protected or private specified object method.
*
* @param object $object Object on which we should call method.
* @param string $method Called method.
* @param array $params Called method parameters.
*
* @return mixed
*/
protected function call($object, $method, array $params = [])
{
$methodReflection = new \ReflectionMethod($object, $method);
$methodReflection->setAccessible(true);
return $methodReflection->invokeArgs($object, $params);
}
/**
* Get public, protected or private property of specified object.
*
* @param object $object Object from which we should get property.
* @param string $property Required property name.
*
* @return mixed
*/
protected function getProperty($object, $property)
{
$propertyReflection = new \ReflectionProperty($object, $property);
$propertyReflection->setAccessible(true);
return $propertyReflection->getValue($object);
}
/**
* Assert that specified value matched to given pattern.
* Uses coduo/php-matcher.
*
* @param mixed $value Matched value.
* @param mixed $pattern Expected pattern.
* @param string $message Custom error message.
*
* @return void
*/
protected static function assertMatch($value, $pattern, $message = null)
{
self::assertTrue(
AppMatcher::match($value, $pattern, $error),
$message ? $message . PHP_EOL . $error : $error
);
}
/**
* @param string $className Interface fqcn.
*
* @return \PHPUnit_Framework_MockObject_MockObject
*/
protected function getMockForInterface($className)
{
if (! $this instanceof TestCase) {
throw new \LogicException('AppTestCaseTrait should be used by subclasses od TestCase');
}
return $this->getMockBuilder($className)
->disableOriginalConstructor()
->setMethods($this->getClassMethods($className))
->getMock();
}
/**
* @param string $class A abstract class fqcn.
*
* @return string[]
*/
protected function getClassMethods($class)
{
$reflection = new \ReflectionClass($class);
return \nspl\a\map(\nspl\op\methodCaller('getName'), $reflection->getMethods());
}
}
@@ -0,0 +1,325 @@
<?php
namespace CacheBundle\Document\Extractor;
use PHPUnit\Framework\TestCase;
use UserBundle\Enum\ThemeOptionExtractEnum;
/**
* Class BasicDocumentContentExtractorTest
* @package CacheBundle\Document\Extractor
*/
class BasicDocumentContentExtractorTest extends TestCase
{
const SIMPLE_TEXT = <<<EOT
Outside a character class, in the default matching mode, the circumflex character (^) is an assertion which is true only if the current matching point is at the start of the subject string. Inside a character class, circumflex (^) has an entirely different meaning (see below).
Circumflex (^) need not be the first character of the pattern if a number of alternatives are involved, but it should be the first thing in each alternative in which it appears if the pattern is ever to match that branch. If all possible alternatives start with a circumflex (^), that is, if the pattern is constrained to match only at the start of the subject, it is said to be an "anchored" pattern. (There are also other constructs that can cause a pattern to be anchored.)
A dollar character ($) is an assertion which is TRUE only if the current matching point is at the end of the subject string, or immediately before a newline character that is the last character in the string (by default). Dollar ($) need not be the last character of the pattern if a number of alternatives are involved, but it should be the last item in any branch in which it appears. Dollar has no special meaning in a character class.
The meaning of dollar can be changed so that it matches only at the very end of the string, by setting the PCRE_DOLLAR_ENDONLY option at compile or matching time. This does not affect the \Z assertion.
The meanings of the circumflex and dollar characters are changed if the PCRE_MULTILINE option is set. When this is the case, they match immediately after and immediately before an internal "\n" character, respectively, in addition to matching at the start and end of the subject string. For example, the pattern /^abc$/ matches the subject string "def\nabc" in multiline mode, but not otherwise. Consequently, patterns that are anchored in single line mode because all branches start with "^" are not anchored in multiline mode. The PCRE_DOLLAR_ENDONLY option is ignored if PCRE_MULTILINE is set.
Note that the sequences \A, \Z, and \z can be used to match the start and end of the subject in both modes, and if all branches of a pattern start with \A is it always anchored, whether PCRE_MULTILINE is set or not. Cat also been here.
EOT;
const ARABIC_TEXT = <<<EOT
مع مدن يرتبط المؤلّفة, حين تونس تحرّكت في. بعض لعملة استعملت الخارجية مع, حلّت تعديل كثيرة دون إذ, شيء ما وأكثرها الأوروبي. ما أضف وبحلول الإتحاد والنفيس, أم الخطّة المشترك بالمحور بين. لهذه والحزب معاملة وتم و, أضف أي إبّان يتمكن المتحدة. بسبب مسارح بعد ثم, هناك إتفاقية دون كل. مرجع سكان الأمور ان ضرب.
التاريخ، بالمطالبة لمّ هو, إذ حدى العدّ المشترك الإيطالية. عرفها يعادل والكساد بحق ٣٠, في قامت ميناء أطراف حول. ذلك المزيفة ويكيبيديا، من, قد وبعدما العالم المتحدة حدى. كلّ تم حقول قدما مقاومة. الشتاء، اليابان عل وصل, انه بـ ٠٨٠٤ تحرّك مدينة. سابق أثره، كلّ ٣٠.
و للجزر السادس وفنلندا دون, مئات الخطّة الأبرياء من قبل, كل لان نهاية فهرست الإحتفاظ. و بحق الشتوية اليابانية, بوابة والفلبين الإمتعاض تم ولم, اتّجة الصعداء باستحداث عدد قد. ذات تم نهاية كانتا. بينما المسرح إذ أخر, بداية اقتصادية ما ومن. أخذ لعدم ويكيبيديا، في.
مع قِبل لإعادة الحدود بها. من شيء انتهت الصينية, أمدها وقامت مع بال, هو قدما احداث وقوعها، غير. قد مما مقاومة الأثنان, هو وحتى واستمر وفنلندا أخذ. ثم حول الجوي وبدأت.
في وقد اللا لأداء وتتحمّل, تم وفي واتّجه الخاسرة. ولاتّساع الانجليزية هو لها. أما أن تونس عقبت, في بلا اعلان قبضتهم. قد أهّل للإتحاد قام, هو لمّ أواخر لليابان. ان كان يذكر الوزراء.
لها بهيئة أعمال ديسمبر أم. أسر عقبت بالرّد ان. الجنوب السادس الشهيرة لم قام. مايو أعمال باستحداث وفي ان, أخر أطراف حاملات من. عل أحكم المشترك حتى, قد ببعض الثقيلة واعتلاء فعل.
للجزر المعاهدات أن تلك, أخر هو وبدأت بشرية والنفيس. تم على الجنود الإحتفاظ. ميناء العالمي لبولندا، ثم كما, وجهان للحكومة حدى في. كما أم تجهيز إختار. دنو جيما إعلان بـ, جهة ٣٠ فاتّبع موالية.
فقد أم يونيو لإعلان مساعدة, عدم ان الحيلولة الولايات. لم به، قررت وقدّموا الأراضي, دخول تاريخ بالسيطرة حدى من. ٣٠ الآخر وعُرفت واتّجه مكن, عن دار أمّا البرية, والقرى لمحاكم أن على. وقوعها، اليميني و تعد. لكل مع سقوط نتيجة, الشتاء
EOT;
const HIEROGLYPHIC_TEXT = <<<EOT
絵列個列氏。さおひまきんせふこ二「夜等鵜もぬねゃ舳カ」ラュャコ。ほゅ。るたろの模他舳無るゆめぬへッウウほこお派譜もれふやモカホルーちあしゆゃひく他樹御以擢魔やセノきぬ離日みとゃゆしやねく津鵜ろ絵サハルウまはおこれと列。そ雲瀬手たとふえお。
夜手屋根離留二区くそまへャタ。シツコ個等派以露やと。派阿ヌヤハみのは無二っれすラヘリオゆるは、個保津れなのゆ差津阿樹舳屋模御擢擢瀬かそく、ょちとは。擢他舳差夜津離以よよてほちみっみたきらむき素鵜もおんほさけむちむとかもへねよい日へ課雲い津区まに。毛名区手ふねへみ鵜野屋すけたやのちこはよけら屋阿いきょ知野みれくオヘートヒ手津むすねひうつ根つらぬ舳魔。
やっ樹屋絵尾いとひすらろさめめっよふ阿ぬそ夜絵くは、差派留保個へそミヒケコそふららこほるめむひひ素、絵他いゃつうよほョケャヌョヌこねと瀬留尾野名夜無は尾オャエュ離擢う絵瀬氏素素雲都遊。
け等等ヤッえょ留保雲、けにねせえけまねひすうのちん保知おねやのきゃょしんうこよょエケそょいタスッタゅ雲氏クエ尾個な以鵜模手しっけ留ぬけっむ雲遊魔ん模樹都あまさとさ露阿都留離屋クヨツアおすよ以個れかゅりせくんゆ。の差個よる。とユシイてゃむ、ゆほよら個都個よやま。
阿ゃえ雲素鵜ウタャヤサ譜等譜模氏野列瀬列夜目る個樹夜つよっみ野名根絵擢鵜ツロリムタフキム。え阿二なたさもは露ね。ほに、露留とむ区くゃまん目阿ろて二御保露課屋よのっうな都とはゅ以樹野巣まむけカオリサむ。遊留野絵樹毛ちへ擢にねろれるれあこらねたゃま。ゃさゆろうゃカムマクヒケつとへけ模るてらかのえ。
ゅちくく、。ぬ、離あおへひ課保以等すほゆよ派尾樹ケコヨョるゃ保派クエコセ、ねまゅいひュメカ津二ホハヨスミ阿保雲屋舳他れ譜これめてん個等るしもょけまちるむめ毛氏派無離ゆかぬょふ課模っあせっこ巣あゆそもち。ひ、区絵せありきけユサネメ手個日擢目。
雲都はひか根鵜んまなミホチソ名個阿無津魔きりさもかへううもぬそすととか根根。留等るこすひ樹舳留差うすまっにムーユゆ無鵜いつゆくイツイスウヨユエソ、露派くむゅる樹野よけかほりホヘョ魔ひたん列毛、あこほし。野差保都舳。あぬ区留あ模名コヨン都列列りな等根ちんゃたゃすもいくあてオャサリかろ瀬模保野鵜名ういろゅ。た雲模、おかこ、ろろほ魔区離屋ゃしな。
列ち鵜模。区津保雲都た模区ょ知以離無夜いへてつ舳瀬っリシトサコル尾ゅ、く遊区あねぬ譜個ヤメモケんほなゆにり舳氏サソヤメスたか根他根絵露個、さ手御シンヒ尾瀬おすっっ阿等差そらやはのえもゆぬつ留模手雲ょいけあ留差おたぬろう樹屋ももゅつふえレッネツにすつはむ「知他知列ユ」ハスーロヒひものん素みこはゆふぬ列留樹課るゃか夜以ろ列列名擢。
たていつにに。よな個魔舳りのゅおふらら模擢の尾毛名課へろこむ手二手、譜つ素以おに差御課樹ぬスラオレコ野根なめゃ野氏。お名課無等津、ふっめゃせう屋「離屋。」はよそき保模尾阿都差かけちやゃつ区二屋魔擢尾しょとょ知手等氏れ無巣根御ゅろ以擢二魔以ふぬめりあ区遊擢よよちけ。
課絵はやすん樹鵜夜手魔他屋毛列保目屋尾野か課素擢日譜目他毛雲雲離差なれた、た毛差めそ。すんロニム。留屋れこせてへみっけ手、こおやつま屋瀬ヤウナフネロ名瀬二名すいるまさ保屋譜。
EOT;
/**
* @return void
*/
public function testExtractNo()
{
$extractor = new BasicDocumentContentExtractor(100, 100);
$queries = [
'saw',
'Note',
'sequences',
];
foreach ($queries as $query) {
$actual = $extractor->extract(
self::SIMPLE_TEXT,
$query,
ThemeOptionExtractEnum::no()
);
$this->assertEquals('', $actual->getText());
}
$queries = [
'فنلندا',
'ويكيبيديا',
'مسارح',
];
foreach ($queries as $query) {
$actual = $extractor->extract(
self::ARABIC_TEXT,
$query,
ThemeOptionExtractEnum::no()
);
$this->assertEquals('', $actual->getText());
}
$queries = [
'ひすう',
'列りな',
'留屋れこ',
];
foreach ($queries as $query) {
$actual = $extractor->extract(
self::HIEROGLYPHIC_TEXT,
$query,
ThemeOptionExtractEnum::no()
);
$this->assertEquals('', $actual->getText());
}
}
/**
* @dataProvider startExtractProvider
*
* @param string $text Document content text.
* @param string $query Search query.
* @param integer $startExtractLen How many characters extract from beginning
* of content.
* @param string $expected Expected result.
*
* @return void
*/
public function testExtractStart($text, $query, $startExtractLen, $expected)
{
$extractor = new BasicDocumentContentExtractor($startExtractLen, random_int(0, 100));
$actual = $extractor->extract($text, $query, ThemeOptionExtractEnum::start());
$this->assertEquals($expected, $actual->getText());
}
/**
* @return array
*/
public function startExtractProvider()
{
return [
[
self::SIMPLE_TEXT,
'cat',
20,
'Outside a character ',
],
[
self::SIMPLE_TEXT,
'some',
1,
'O',
],
[
self::SIMPLE_TEXT,
'',
100000000,
self::SIMPLE_TEXT,
],
[
self::SIMPLE_TEXT,
'long query',
0,
'',
],
[
self::ARABIC_TEXT,
'',
25,
'مع مدن يرتبط المؤلّفة, حي',
],
[
self::ARABIC_TEXT,
'',
1,
'م',
],
[
self::ARABIC_TEXT,
'',
10000000,
self::ARABIC_TEXT,
],
[
self::HIEROGLYPHIC_TEXT,
'',
25,
'絵列個列氏。さおひまきんせふこ二「夜等鵜もぬねゃ舳',
],
[
self::HIEROGLYPHIC_TEXT,
'',
1,
'絵',
],
[
self::HIEROGLYPHIC_TEXT,
'',
10000000,
self::HIEROGLYPHIC_TEXT,
],
];
}
/**
* @dataProvider contextExtractProvider
*
* @param string $text Document content text.
* @param string $query Search query.
* @param integer $contextExtractLen How many characters extract before and
* after search keyword.
* @param string $expected Expected result.
*
* @return void
*/
public function testExtractContext($text, $query, $contextExtractLen, $expected)
{
$extractor = new BasicDocumentContentExtractor(random_int(0, 100), $contextExtractLen);
$actual = $extractor->extract($text, $query, ThemeOptionExtractEnum::context());
$this->assertEquals($expected, $actual->getText());
}
/**
* @return array
*/
public function contextExtractProvider()
{
return [
[
self::SIMPLE_TEXT,
'mode',
5,
'hing mode, the',
],
[
self::SIMPLE_TEXT,
'mode',
0,
'mode',
],
[
self::SIMPLE_TEXT,
'character mode',
25,
'Outside a character class, in the default ma',
],
[
self::SIMPLE_TEXT,
'cat PCRE_MULTILINE dog',
7,
'if the PCRE_MULTILINE option',
],
[
self::SIMPLE_TEXT,
'mode Outside PCRE_MULTILINE',
1000000000,
self::SIMPLE_TEXT,
],
[
self::SIMPLE_TEXT,
'cat',
25,
'MULTILINE is set or not. Cat also been here.',
],
[
self::ARABIC_TEXT,
'المؤلّفة حين',
25,
'مع مدن يرتبط المؤلّفة, حين تونس تحرّكت في. بعض',
],
[
self::ARABIC_TEXT,
'المؤلّفة',
0,
'المؤلّفة',
],
[
self::ARABIC_TEXT,
'المؤلّفة',
10000000,
self::ARABIC_TEXT,
],
[
self::HIEROGLYPHIC_TEXT,
'派阿ヌ ノきぬ離日み さおひまき',
25,
'絵列個列氏。さおひまきんせふこ二「夜等鵜もぬねゃ舳カ」ラュャコ。ほゅ。る',
],
[
self::HIEROGLYPHIC_TEXT,
'ラュャ',
0,
'ラュャ',
],
[
self::HIEROGLYPHIC_TEXT,
'派阿ヌ ノきぬ離日み',
10000000,
self::HIEROGLYPHIC_TEXT,
],
];
}
/**
* @return void
*/
public function testExtractEmptyContent()
{
$extractor = new BasicDocumentContentExtractor(100, 100);
$this->assertEquals('', $extractor->extract('', 'mode', ThemeOptionExtractEnum::no())->getText());
$this->assertEquals('', $extractor->extract('', 'mode', ThemeOptionExtractEnum::start())->getText());
$this->assertEquals('', $extractor->extract('', 'mode', ThemeOptionExtractEnum::context())->getText());
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace Tests\Helper;
/**
* Class AccessorTrait
* @package Tests\Helper
*/
trait AccessorTrait
{
/**
* Call specified method of given object.
*
* @param object $object Some object.
* @param string $method Called method name.
* @param array $arguments Method parameters.
*
* @return mixed
*/
public function call($object, $method, array $arguments = [])
{
$caller = function () use ($method, $arguments) {
return call_user_func_array([ $this, $method ], $arguments);
};
$caller = $caller->bindTo($object, $object);
return $caller();
}
}
+261
View File
@@ -0,0 +1,261 @@
<?php
namespace Tests\Helper;
use PHPUnit\Framework\TestCase;
use UserBundle\Entity\Notification\ThemeOption\ThemeOptionFont;
/**
* Class CssAssertBuilder
*
* @package Helper
*/
class CssAssertBuilder
{
const PROPERTY_WITH_VALUE_PATTERN_TPL = '/%s[^\{]*?\{[^\}]*%s:\s*%s[^\}]*\}/i';
const PROPERTY_PATTERN_TPL = '/%s[^\{]*?\{[^\}]*%s:[^\}]*\}/i';
private static $searchedCharacters = [
'.',
'[',
']',
'(',
')',
'{',
'}',
'/',
];
private static $replaceCharacters = [
'\.',
'\[',
'\]',
'\(',
'\)',
'\{',
'\}',
'\/',
];
/**
* @var string
*/
private $selector;
/**
* @var boolean
*/
private $shouldExists = true;
/**
* @var array
*/
private $asserts = [];
/**
* CssAssertBuilder constructor.
*
* @param string $selector A base css element selector.
* @param boolean $escape Should escape specific pattern symbols or not.
*/
public function __construct($selector, $escape = true)
{
if ($escape) {
$selector = str_replace(self::$searchedCharacters, self::$replaceCharacters, $selector);
}
$this->selector = $selector;
}
/**
* @return CssAssertBuilder
*/
public function shouldExists()
{
$this->shouldExists = true;
return $this;
}
/**
* @return CssAssertBuilder
*/
public function shouldNotExists()
{
$this->shouldExists = false;
return $this;
}
/**
* @param string $selector A base css element selector.
*
* @return CssAssertBuilder
*/
public static function create($selector)
{
return new CssAssertBuilder($selector);
}
/**
* @param ThemeOptionFont $font Font which should be rendered.
*
* @return CssAssertBuilder
*/
public function hasFont(ThemeOptionFont $font)
{
$this
->propertyShouldBe('font-family', $font->getFamily()->getCss())
->propertyShouldBe('font-size', $font->getSize());
$style = $font->getStyle();
if ($style->isBold()) {
$this->propertyShouldBe('font-weight', 'bold');
} else {
$this->propertyShouldNotBe('font-weight', 'bold');
}
if ($style->isItalic()) {
$this->propertyShouldBe('font-style', 'italic');
} else {
$this->propertyShouldNotBe('font-style', 'italic');
}
if ($style->isUnderline()) {
$this->propertyShouldBe('text-decoration', 'underline');
} else {
$this->propertyShouldNotBe('text-decoration', 'underline');
}
return $this;
}
/**
* @return static
*/
public function hasNotAnyFonts()
{
return $this
->propertyShouldNotExists('font-family')
->propertyShouldNotExists('font-size')
->propertyShouldNotExists('font-weight')
->propertyShouldNotExists('font-style')
->propertyShouldNotExists('text-decoration');
}
/**
* @param string $name Property name.
* @param string $message Error message.
*
* @return static
*/
public function propertyShouldExists($name, $message = '')
{
$this->asserts[] = [
'method' => 'assertRegExp',
'arguments' => [
sprintf(self::PROPERTY_PATTERN_TPL, $this->selector, $name),
'___',
$message,
],
];
return $this;
}
/**
* @param string $name Property name.
* @param string $message Error message.
*
* @return static
*/
public function propertyShouldNotExists($name, $message = '')
{
$this->asserts[] = [
'method' => 'assertNotRegExp',
'arguments' => [
sprintf(self::PROPERTY_PATTERN_TPL, $this->selector, $name),
'___',
$message,
],
];
return $this;
}
/**
* @param string $name Property name.
* @param string $value Expected property value.
* @param string $message Error message.
*
* @return static
*/
public function propertyShouldBe($name, $value, $message = '')
{
$name = str_replace(self::$searchedCharacters, self::$replaceCharacters, $name);
$value = str_replace(self::$searchedCharacters, self::$replaceCharacters, $value);
$this->asserts[] = [
'method' => 'assertRegExp',
'arguments' => [
sprintf(self::PROPERTY_WITH_VALUE_PATTERN_TPL, $this->selector, $name, $value),
'___',
$message,
],
];
return $this;
}
/**
* @param string $name Property name.
* @param string $value Expected property value.
* @param string $message Error message.
*
* @return static
*/
public function propertyShouldNotBe($name, $value = '', $message = '')
{
$name = str_replace(self::$searchedCharacters, self::$replaceCharacters, $name);
$value = str_replace(self::$searchedCharacters, self::$replaceCharacters, $value);
$this->asserts[] = [
'method' => 'assertNotRegExp',
'arguments' => [
sprintf(self::PROPERTY_WITH_VALUE_PATTERN_TPL, $this->selector, $name, $value),
'___',
$message,
],
];
return $this;
}
/**
* @param string $html HTML content.
*
* @return void
*/
public function assert($html)
{
if (! $this->shouldExists) {
TestCase::assertNotRegExp("/{$this->selector}/", $html);
// Don't assert property 'cause it's not necessary.
return;
}
foreach ($this->asserts as $config) {
$arguments = \nspl\a\map(function ($argument) use ($html) {
if (is_string($argument) && ($argument === '___')) {
$argument = $html;
}
return $argument;
}, $config['arguments']);
call_user_func_array([ TestCase::class, $config['method'] ], $arguments);
}
}
}
+67
View File
@@ -0,0 +1,67 @@
<?php
namespace Tests\Helper;
use PHPUnit\Framework\TestCase;
/**
* Class CssAsserter
*
* @package Helper
*/
class CssAsserter
{
/**
* @var string
*/
private $styles;
/**
* CssAsserter constructor.
*
* @param string $styles Raw css style text.
*/
public function __construct($styles)
{
$this->styles = $styles;
}
/**
* @param string $html Raw html.
*
* @return CssAsserter
*/
public static function createFromHtml($html)
{
$matches = [];
preg_match('#<style>([^<]*)</style>#i', $html, $matches);
array_shift($matches);
return new CssAsserter(implode("\n", $matches));
}
/**
* @param string $selector Css selector.
*
* @return CssAsserter
*/
public function hasSelector($selector)
{
TestCase::assertRegExp('/'.$selector.'/i', $this->styles);
return $this;
}
/**
* @param string $selector Css selector.
*
* @return CssPropertiesAsserter
*/
public function with($selector)
{
$this->hasSelector($selector);
return new CssPropertiesAsserter(preg_replace('/%s[^\{]*?\{([^\}]*?)\}/i', '$1', $this->styles), $this);
}
}
+130
View File
@@ -0,0 +1,130 @@
<?php
namespace Tests\Helper;
use PHPUnit\Framework\TestCase;
use UserBundle\Entity\Notification\ThemeOption\ThemeOptionFont;
/**
* Class CssPropertiesAsserter
*
* @package Helper
*/
class CssPropertiesAsserter
{
/**
* @var string
*/
private $properties;
/**
* @var CssAsserter
*/
private $cssAsserter;
/**
* CssAsserter constructor.
*
* @param string $properties Css properties.
* @param CssAsserter|null $cssAsserter A parent CssAsserter instance.
*/
public function __construct($properties, CssAsserter $cssAsserter)
{
$this->properties = $properties;
$this->cssAsserter = $cssAsserter;
}
/**
* @param string $name Property name.
* @param string|null $value Property value.
*
* @return CssPropertiesAsserter
*/
public function has($name, $value = null)
{
if ($value !== null) {
$value = str_replace([ '(', ')' ], [ '\(', '\)' ], $value);
}
$pattern = $value === null
? sprintf('/%s:\s*[^;];/i', $name)
: sprintf('/%s:\s*%s;/i', $name, $value);
TestCase::assertRegExp($pattern, $this->properties);
return $this;
}
/**
* @param string $name Property name.
* @param string|null $value Property value.
*
* @return CssPropertiesAsserter
*/
public function hasNot($name, $value = null)
{
$pattern = $value === null
? sprintf('/%s:\s*[^;];/i', $name)
: sprintf('/%s:\s*%s;/i', $name, $value);
TestCase::assertNotRegExp($pattern, $this->properties);
return $this;
}
/**
* @param ThemeOptionFont $font A ThemeOptionFont instance.
*
* @return CssPropertiesAsserter
*/
public function hasFont(ThemeOptionFont $font)
{
$this
->has('font-family', $font->getFamily()->getCss())
->has('font-size', $font->getSize());
$style = $font->getStyle();
if ($style->isBold()) {
$this->has('font-weight', 'bold');
} else {
$this->hasNot('font-weight');
}
if ($style->isItalic()) {
$this->has('font-style', 'italic');
} else {
$this->hasNot('font-style');
}
if ($style->isUnderline()) {
$this->has('text-decoration', 'underline');
} else {
$this->hasNot('text-decoration');
}
return $this;
}
/**
* @return CssPropertiesAsserter
*/
public function hasNotFontAtAll()
{
return $this
->hasNot('font-family')
->hasNot('font-size')
->hasNot('font-weight')
->hasNot('font-style')
->hasNot('text-decoration');
}
/**
* @return null|CssAsserter
*/
public function end()
{
return $this->cssAsserter;
}
}
+226
View File
@@ -0,0 +1,226 @@
<?php
namespace Tests\Helper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DomCrawler\Crawler;
/**
* Class HtmlAsserter
*
* @package Helper
*/
class HtmlAsserter
{
/**
* @var Crawler
*/
private $root;
/**
* @var HtmlAsserter|null
*/
private $parent;
/**
* HtmlAsserter constructor.
*
* @param Crawler $root A Crawler instance.
* @param HtmlAsserter $parent A parent Crawler instance.
*/
public function __construct(Crawler $root, HtmlAsserter $parent = null)
{
$this->root = $root;
$this->parent = $parent;
}
/**
* @param string $selector Node selector.
* @param integer $count Expected node numbers. Check that at least one
* exists if -1.
*
* @return HtmlAsserter
*/
public function hasNode($selector, $count = 1)
{
$nodes = $this->root->filter($selector);
if ($count === -1) {
TestCase::assertGreaterThan(0, count($nodes), sprintf(
'Expects at least one node \'%s\' but got zero',
$selector
));
} else {
TestCase::assertCount($count, $nodes, sprintf(
'Expects %d of \'%s\' nodes but got another count',
$count,
$selector
));
}
return $this;
}
/**
* @param string $selector Node selector.
*
* @return HtmlAsserter
*/
public function hasNotNode($selector)
{
TestCase::assertCount(0, $this->root->filter($selector), sprintf(
'Node \'%s\' is exists but should\'nt',
$selector
));
return $this;
}
/**
* @param string $class Expected node class.
*
* @return HtmlAsserter
*/
public function hasClass($class)
{
TestCase::assertContains($class, $this->root->attr('class'), sprintf(
'Current node should has \'%s\' class but it has not',
$class
));
return $this;
}
/**
* @param string $name HTML node attribute name.
* @param string $value Expected value.
*
* @return HtmlAsserter
*/
public function hasAttr($name, $value = null)
{
$nodeValue = $this->root->attr($name);
if ($value === null) {
TestCase::assertNotNull($nodeValue, sprintf(
'Node attribute \'%s\' should exists but it has not',
$name
));
} else {
TestCase::assertEquals($value, $nodeValue, sprintf(
'Node attribute \'%s\' should match to \'%s\' but it has \'%s\'',
$name,
$value,
$nodeValue
));
}
return $this;
}
/**
* @param string $content Expected text content.
* @param boolean $strict Should content only specified values or not.
*
* @return HtmlAsserter
*/
public function contains($content, $strict = false)
{
$nodeContent = $this->root->getNode(0)->textContent;
if ($strict) {
TestCase::assertEquals($content, $nodeContent, sprintf(
'Node should contains only \'%s\' but it has not',
$content
));
} else {
TestCase::assertContains($content, $nodeContent, sprintf(
'Node should contains \'%s\' but it has not',
$content
));
}
return $this;
}
/**
* @param string $content Unexpected text content.
* @param boolean $strict Should content only specified values or not.
*
* @return $this
*/
public function notContains($content, $strict = false)
{
$nodeContent = $this->root->getNode(0)->textContent;
if ($strict) {
TestCase::assertNotEquals($content, $nodeContent, sprintf(
'Node should\'nt contains \'%s\' but it has',
$content
));
} else {
TestCase::assertNotContains($content, $nodeContent, sprintf(
'Node should\'nt contains \'%s\' but it has',
$content
));
}
return $this;
}
/**
* @param string $regex Regular expression.
*
* @return HtmlAsserter
*/
public function regexContent($regex)
{
TestCase::assertRegExp($regex, $this->root->getNode(0)->textContent, sprintf(
'Content of node should match to \'%s\' but it has not',
$regex
));
return $this;
}
/**
* @param string $selector Node selector.
*
* @return HtmlAsserter
*/
public function with($selector)
{
$this->hasNode($selector, -1);
return new static($this->root->filter($selector), $this);
}
/**
* @param integer $idx Child node index.
*
* @return HtmlAsserter
*/
public function child($idx)
{
return new static(new Crawler($this->root->getNode($idx)), $this);
}
/**
* @return HtmlAsserter
*/
public function end()
{
return $this->parent !== null ? $this->parent : $this;
}
/**
* @return HtmlAsserter
*/
public function dump()
{
echo $this->root->html();
return $this;
}
}
@@ -0,0 +1,205 @@
<?php
namespace IndexBundle\Filter\Filters;
use IndexBundle\Filter\AbstractGroupFilter;
use Tests\AppTestCase;
/**
* Class GroupFilterTest
*
* @package IndexBundle\Filter\Filters
*/
class GroupFilterTest extends AppTestCase
{
/**
* @return void
*/
public function testCreate()
{
$this->getMockForAbstractClass(AbstractGroupFilter::class, [ [ new GteFilter('foo', 10), new AndFilter() ]]);
$this->getMockForAbstractClass(AbstractGroupFilter::class, [ new GteFilter('foo', 10) ]);
$this->getMockForAbstractClass(AbstractGroupFilter::class, [ new AndFilter() ]);
$this->getMockForAbstractClass(AbstractGroupFilter::class);
$this->getMockForAbstractClass(AbstractGroupFilter::class);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage '$filters' should be array of FilterInterface instances or single instance
*
* @return void
*/
public function testCreateWithArrayOfInvalid()
{
$this->getMockForAbstractClass(AbstractGroupFilter::class, [ [ new GteFilter('foo', 10), 10 ] ]);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage '$filters' should be array of FilterInterface instances or single instance
*
* @return void
*/
public function testCreateWithSingleInvalid()
{
$this->getMockForAbstractClass(AbstractGroupFilter::class, [ 1 ]);
}
/**
* @return void
*/
public function testSerialize()
{
$date = new \DateTime();
$filter1 = new EqFilter('some', 10);
$filter21 = new EqFilter('another', 'foo');
$filter22 = new NotFilter(new GteFilter('bar', $date));
$filter2 = $this->getMockForAbstractClass(AbstractGroupFilter::class, [ [ $filter21, $filter22 ] ]);
$filter = $this->getMockForAbstractClass(AbstractGroupFilter::class, [ [ $filter1, $filter2 ] ]);
/** @var AbstractGroupFilter $unserializedFilter */
$unserializedFilter = unserialize(serialize($filter));
$this->assertInstanceOf(AbstractGroupFilter::class, $unserializedFilter);
$this->assertCount(2, $unserializedFilter->getFilters());
/** @var EqFilter $unserializedInnerFilter1 */
$unserializedInnerFilter1 = $unserializedFilter->getFilters()[0];
/** @var AbstractGroupFilter $unserializedInnerFilter2 */
$unserializedInnerFilter2 = $unserializedFilter->getFilters()[1];
$this->assertInstanceOf(EqFilter::class, $unserializedInnerFilter1);
$this->assertSame('some', $unserializedInnerFilter1->getFieldName());
$this->assertSame(10, $unserializedInnerFilter1->getValue());
$this->assertInstanceOf(AbstractGroupFilter::class, $unserializedInnerFilter2);
$this->assertCount(2, $unserializedInnerFilter2->getFilters());
/** @var EqFilter $unserializedInnerFilter21 */
$unserializedInnerFilter21 = $unserializedInnerFilter2->getFilters()[0];
/** @var NotFilter $unserializedInnerFilter22 */
$unserializedInnerFilter22 = $unserializedInnerFilter2->getFilters()[1];
$this->assertInstanceOf(EqFilter::class, $unserializedInnerFilter21);
$this->assertSame('another', $unserializedInnerFilter21->getFieldName());
$this->assertSame('foo', $unserializedInnerFilter21->getValue());
$this->assertInstanceOf(NotFilter::class, $unserializedInnerFilter22);
/** @var GteFilter $unserializedInnerFilter22Inner */
$unserializedInnerFilter22Inner = $unserializedInnerFilter22->getFilter();
$this->assertInstanceOf(GteFilter::class, $unserializedInnerFilter22Inner);
$this->assertSame('bar', $unserializedInnerFilter22Inner->getFieldName());
$this->assertEquals(
$date->format('c'),
$unserializedInnerFilter22Inner->getValue()->format('c')
);
}
/**
* @return void
*/
public function testSort()
{
$date = new \DateTime();
$filter1 = new EqFilter('some', 10);
$filter21 = new EqFilter('another', 'foo');
$filter22 = new NotFilter(new GteFilter('bar', $date));
$filter2 = new AndFilter([ $filter22, $filter21 ]);
$filter = new OrFilter([ $filter2, $filter1 ]);
$filter->sort();
$this->assertSame([ $filter1, $filter2 ], $filter->getFilters());
$this->assertSame([ $filter21, $filter22 ], $filter2->getFilters());
}
/**
* @return void
*/
public function testCompareValueFilters()
{
$filter = $this->getMockForAbstractClass(AbstractGroupFilter::class);
$this->assertGreaterThan(0, $this->call($filter, 'compareValueFilters', [
new EqFilter('b', 10),
new EqFilter('a', 10),
]));
$this->assertLessThan(0, $this->call($filter, 'compareValueFilters', [
new EqFilter('a', 9),
new EqFilter('a', 10),
]));
$this->assertEquals(0, $this->call($filter, 'compareValueFilters', [
new GteFilter('a', 10),
new LteFilter('a', 10),
]));
}
/**
* @return void
*/
public function testCompareInFilters()
{
$filter = $this->getMockForAbstractClass(AbstractGroupFilter::class);
$this->assertGreaterThan(0, $this->call($filter, 'compareInFilters', [
new InFilter('b', [ 10 ]),
new InFilter('a', [ 10 ]),
]));
$this->assertLessThan(0, $this->call($filter, 'compareInFilters', [
new InFilter('a', [ 9 ]),
new InFilter('a', [ 10 ]),
]));
$this->assertEquals(0, $this->call($filter, 'compareInFilters', [
new InFilter('a', [ 10 ]),
new InFilter('a', [ 10 ]),
]));
$this->assertLessThan(0, $this->call($filter, 'compareInFilters', [
new InFilter('a', [ 10 ]),
new InFilter('a', [ 10, 10 ]),
]));
}
/**
* @return void
*/
public function testCompareGroupFilters()
{
$filter = $this->getMockForAbstractClass(AbstractGroupFilter::class);
$this->assertEquals(0, $this->call($filter, 'compareGroupFilters', [
new AndFilter(),
new AndFilter(),
]));
$this->assertEquals(0, $this->call($filter, 'compareGroupFilters', [
new AndFilter([ new AndFilter([ new EqFilter('a', 10) ]) ]),
new AndFilter([ new AndFilter([ new GteFilter('a', 10) ]) ]),
]));
$this->assertGreaterThan(0, $this->call($filter, 'compareGroupFilters', [
new AndFilter([ new EqFilter('a', 10) ]),
new AndFilter([ new EqFilter('a', 9) ]),
]));
$this->assertLessThan(0, $this->call($filter, 'compareGroupFilters', [
new AndFilter([ new EqFilter('a', 10) ]),
new AndFilter([ new AndFilter() ]),
]));
$this->assertLessThan(0, $this->call($filter, 'compareGroupFilters', [
new AndFilter(),
new AndFilter([ new AndFilter() ]),
]));
}
}
@@ -0,0 +1,106 @@
<?php
namespace IndexBundle\Filter\Filters;
use Common\Enum\PublisherTypeEnum;
use Tests\AppTestCase;
/**
* Class InFilterTest
*
* @package IndexBundle\Filter\Filters
*/
class InFilterTest extends AppTestCase
{
/**
* @return void
*/
public function testCreate()
{
$filter = new InFilter('foo', []);
$this->assertEquals('foo', $filter->getFieldName());
$this->assertEquals([], $filter->getValue());
$dateMut = date_create();
$dateImm = date_create_immutable(' + 1 day');
$filter = new InFilter('bar', [
12,
true,
2.3,
'string',
$dateMut,
$dateImm,
PublisherTypeEnum::unknown(),
]);
$this->assertEquals('bar', $filter->getFieldName());
$this->assertEquals([
12,
true,
2.3,
'string',
$dateMut,
$dateImm,
PublisherTypeEnum::UNKNOWN,
], $filter->getValue());
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage '$field' should be string
*
* @return void
*/
public function testCreateInvalidField()
{
new InFilter(1, []);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage '$values' should be an array of scalar values, AbstractEnum or \DateTimeInterface instances
*
* @return void
*/
public function testCreateInvalidValues()
{
new InFilter('foo', [ [ 1 ] ]);
}
/**
* @return void
*/
public function testSerialize()
{
$values = [ 10, 20, 100 ];
$filter = new InFilter('foo', $values);
/** @var InFilter $unserializedFilter */
$unserializedFilter = unserialize(serialize($filter));
$this->assertInstanceOf(InFilter::class, $unserializedFilter);
$this->assertSame('foo', $unserializedFilter->getFieldName());
$this->assertSame($values, $unserializedFilter->getValue());
}
/**
* @return void
*/
public function testSort()
{
$filter = new InFilter('foo', [ 11, -3, 30]);
$filter->sort();
$this->assertSame([-3, 11, 30], $filter->getValue());
$date1 = new \DateTime('+ 1 day');
$date2 = new \DateTime();
$date3 = new \DateTime('- 1 month');
$filter = new InFilter('some', [ $date1, $date2, $date3 ]);
$filter->sort();
$this->assertSame([ $date3, $date2, $date1 ], $filter->getValue());
}
}
@@ -0,0 +1,102 @@
<?php
namespace IndexBundle\Filter\Filters;
use Common\Enum\PublisherTypeEnum;
use IndexBundle\Filter\AbstractValueFilter;
use Tests\AppTestCase;
/**
* Class ValueFilterTest
*
* @package IndexBundle\Filter\Filters
*/
class ValueFilterTest extends AppTestCase
{
/**
* @return void
*/
public function testCreate()
{
$mock = $this->getMockForAbstractClass(AbstractValueFilter::class, [ 'foo', 10 ]);
$this->assertEquals('foo', $mock->getFieldName());
$this->assertEquals(10, $mock->getValue());
$mock = $this->getMockForAbstractClass(AbstractValueFilter::class, [ 'foo', 'string' ]);
$this->assertEquals('foo', $mock->getFieldName());
$this->assertEquals('string', $mock->getValue());
$mock = $this->getMockForAbstractClass(AbstractValueFilter::class, [ 'foo', 2.4 ]);
$this->assertEquals('foo', $mock->getFieldName());
$this->assertEquals(2.4, $mock->getValue());
$mock = $this->getMockForAbstractClass(AbstractValueFilter::class, [ 'foo', true ]);
$this->assertEquals('foo', $mock->getFieldName());
$this->assertEquals(true, $mock->getValue());
$date = date_create();
$mock = $this->getMockForAbstractClass(AbstractValueFilter::class, [ 'foo', $date ]);
$this->assertEquals('foo', $mock->getFieldName());
$this->assertEquals($date, $mock->getValue());
$date = date_create_immutable();
$mock = $this->getMockForAbstractClass(AbstractValueFilter::class, [ 'foo', $date ]);
$this->assertEquals('foo', $mock->getFieldName());
$this->assertEquals($date, $mock->getValue());
$mock = $this->getMockForAbstractClass(AbstractValueFilter::class, [ 'foo', PublisherTypeEnum::blogs() ]);
$this->assertEquals('foo', $mock->getFieldName());
$this->assertEquals(PublisherTypeEnum::BLOGS, $mock->getValue());
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage '$field' should be string
*
* @return void
*/
public function testCreateInvalidField()
{
$this->getMockForAbstractClass(AbstractValueFilter::class, [ 1, 10 ]);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage '$value' should be scalar, AbstractEnum or \DateTimeInterface instance
*
* @return void
*/
public function testCreateInvalidValues()
{
$this->getMockForAbstractClass(AbstractValueFilter::class, [ 'foo', [ 1 ] ]);
}
/**
* @return void
*/
public function testSerialize()
{
$filter = $this->getMockForAbstractClass(AbstractValueFilter::class, [
'foo',
20,
]);
/** @var AbstractValueFilter $unserializedFilter */
$unserializedFilter = unserialize(serialize($filter));
$this->assertInstanceOf(AbstractValueFilter::class, $unserializedFilter);
$this->assertSame('foo', $unserializedFilter->getFieldName());
$this->assertSame(20, $unserializedFilter->getValue());
}
/**
* @return void
*/
public function testSort()
{
$filter = $this->getMockForAbstractClass(AbstractValueFilter::class, [ 'foo', 10 ]);
$filter->sort();
$this->assertSame(10, $filter->getValue());
}
}
+163
View File
@@ -0,0 +1,163 @@
<?php
namespace IndexBundle\Index\External;
use Psr\Log\NullLogger;
use Symfony\Component\Cache\Adapter\NullAdapter;
use Tests\AppTestCase;
/**
* Class HoseIndexTest
*
* @package IndexBundle\Index\External
*/
class HoseIndexTest extends AppTestCase
{
/**
* @var HoseIndex
*/
private $index;
/**
* @return void
*/
public function testBeforeSearch()
{
$parameters = [
'body' => [ 'query' => [ 'query_string' => [ 'query' => sprintf(
'published:[%s TO *]',
date_create('+ 36 days')->format('c')
), ], ], ],
];
$parameters = $this->call($this->index, 'beforeSearch', [ $parameters ]);
$this->assertArrayHasKey('index', $parameters);
$this->assertEquals(
implode(',', [ HoseIndex::HOT, HoseIndex::WARM ]),
$parameters['index']
);
}
/**
* @dataProvider getQueryRangeEndProvider
*
* @param \DateTime|null $expected Expected result.
* @param string $query ES query string.
*
* @return void
*/
public function testGetQueryRangeEnd(\DateTime $expected = null, $query)
{
$this->assertEquals(
$expected,
$this->call($this->index, 'getQueryRangeEnd', [ $query ])
);
}
/**
* @return array
*/
public function getQueryRangeEndProvider()
{
$date1 = date_create('+ 36 days 00:00:00');
return [
[
$date1,
sprintf('published:[%s TO *]', $date1->format('c')),
],
[
date_create('2017-11-27T00:00:00+07:00'),
'{"body":{"query":{"query_string":{"query":"(main:("Clarion School" -"North Clarion") OR title:("Clarion School" -"North Clarion")) AND ((source_publisher_type:(MAINSTREAM_NEWS OR REVIEW OR CLASSIFIED OR UNKNOWN OR WEBLOG OR MICROBLOG OR UNKNOWN OR SOCIAL_MEDIA OR UNKNOWN OR VIDEO OR UNKNOWN OR FORUM OR MEMETRACKER OR UNKNOWN OR PHOTO OR UNKNOWN)) AND ((published:[2017-11-27T00:00:00+07:00 TO *]) AND (published:[* TO 2018-01-26T23:59:59+07:00])) AND (published:[* TO 2018-01-26T19:20:26+07:00]))"}},"sort":{"published":{"order":"desc"}}},"index":"content_*","type":"","size":100,"from":0}',
],
[
null,
'',
],
[
null,
'{"body":{"query":{"query_string":{"query":"(main:("Clarion School" -"North Clarion") OR title:("Clarion School" -"North Clarion")) AND ((source_publisher_type:(MAINSTREAM_NEWS OR REVIEW OR CLASSIFIED OR UNKNOWN OR WEBLOG OR MICROBLOG OR UNKNOWN OR SOCIAL_MEDIA OR UNKNOWN OR VIDEO OR UNKNOWN OR FORUM OR MEMETRACKER OR UNKNOWN OR PHOTO OR UNKNOWN)))"}},"sort":{"published":{"order":"desc"}}},"index":"content_*","type":"","size":100,"from":0}',
],
];
}
/**
* @dataProvider determineIndexProvider
*
* @param array $expected Expected hose indices.
* @param array $arguments Tested method arguments.
*
* @return void
*/
public function testDetermineIndex(array $expected, array $arguments)
{
$this->assertEquals(
implode(',', $expected),
$this->call($this->index, 'determineIndex', $arguments)
);
}
/**
* @return array
*/
public function determineIndexProvider()
{
return [
'without date' => [
[ HoseIndex::HOT, HoseIndex::WARM, HoseIndex::COLD ],
[],
],
'72 days ahead' => [
[ HoseIndex::HOT, HoseIndex::WARM, HoseIndex::COLD ],
[ date_create('+ 72 days') ],
],
'60 days and 1 hour ahead' => [
[ HoseIndex::HOT, HoseIndex::WARM, HoseIndex::COLD ],
[ date_create('+ 60 days 01:00:00') ],
],
'60 days ahead' => [
[ HoseIndex::HOT, HoseIndex::WARM ],
[ date_create('+ 60 days 00:00:00') ],
],
'36 days ahead' => [
[ HoseIndex::HOT, HoseIndex::WARM ],
[ date_create('+ 36 days') ],
],
'30 days and 1 hour ahead' => [
[ HoseIndex::HOT, HoseIndex::WARM ],
[ date_create('+ 30 days 01:00:00') ],
],
'30 days ahead' => [
[ HoseIndex::HOT ],
[ date_create('+ 30 days 00:00:00') ],
],
'21 days ahead' => [
[ HoseIndex::HOT ],
[ date_create('+ 21 days') ],
],
'current date' => [
[ HoseIndex::HOT ],
[ date_create() ],
],
];
}
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*
* @return void
*/
protected function setUp()
{
$this->index = new HoseIndex(
new NullLogger(),
new NullAdapter(),
'host',
'vendor',
'auth'
);
}
}
@@ -0,0 +1,169 @@
<?php
namespace Tests\IndexBundle\Model;
use IndexBundle\Index\Strategy\IndexStrategyInterface;
use Tests\AppTestCase;
/**
* Class TestModel
* @package Tests\IndexBundle\Model
*/
class AbstractIndexDocumentTest extends AppTestCase
{
/**
* Array of available document properties.
*
* @var string[]
*/
protected $available = [
'first',
'second',
'third',
];
/**
* @var TestModel
*/
private $model;
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*
* @return void
*/
protected function setUp()
{
/** @var IndexStrategyInterface|\PHPUnit_Framework_MockObject_MockObject $strategy */
$strategy = $this->getMockForInterface(IndexStrategyInterface::class);
$strategy
->method('normalizeDocumentData')
->willReturnCallback(function (array $data) {
return $data;
});
$strategy
->method('getIndexableData')
->willReturnCallback(function (array $data) {
return $data;
});
$strategy
->method('normalizeFieldName')
->willReturnCallback(function ($fieldName) {
return $fieldName;
});
$strategy
->method('denormalizeFieldName')
->willReturnCallback(function ($fieldName) {
return $fieldName;
});
$strategy
->method('normalizePublisherType')
->willReturnCallback(function ($type) {
return $type;
});
$strategy
->method('denormalizePublisherType')
->willReturnCallback(function ($type) {
return $type;
});
$this->model = new TestModel($strategy, [
'first' => 1,
'second' => 'two',
'third' => [ 3, 2, 1 ],
]);
}
/**
* @return void
*/
public function testAccessAsArray()
{
$this->assertSame(1, $this->model['first']);
$this->assertSame('two', $this->model['second']);
$this->assertSame([ 3, 2, 1], $this->model['third']);
$this->model['first'] = 2;
$this->model['second'] = 'third';
$this->model['third'] = [ 1, 2, 3 ];
$this->assertSame(2, $this->model['first']);
$this->assertSame('third', $this->model['second']);
$this->assertSame([ 1, 2, 3], $this->model['third']);
}
/**
* @return void
*/
public function testIterate()
{
$expected = [
'first' => 1,
'second' => 'two',
'third' => [ 3, 2, 1 ],
];
reset($expected);
foreach ($this->model as $name => $value) {
$this->assertSame(key($expected), $name);
$this->assertSame(current($expected), $value);
next($expected);
}
$this->model['first'] = 2;
$this->model['second'] = 'third';
$this->model['third'] = [ 1, 2, 3 ];
$expected = [
'first' => 2,
'second' => 'third',
'third' => [ 1, 2, 3 ],
];
reset($expected);
foreach ($this->model as $name => $value) {
$this->assertSame(key($expected), $name);
$this->assertSame(current($expected), $value);
next($expected);
}
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Unknown property 'fourth'
*
* @return void
*/
public function testAccessAsArrayInvalidProperty()
{
$this->model['fourth'];
}
/**
* @return void
*/
public function testAccessAsProperty()
{
$this->assertSame(1, $this->model->first);
$this->assertSame('two', $this->model->second);
$this->assertSame([ 3, 2, 1], $this->model->third);
$this->model->first = 2;
$this->model->second = 'third';
$this->model->third = [ 1, 2, 3 ];
$this->assertSame(2, $this->model->first);
$this->assertSame('third', $this->model->second);
$this->assertSame([ 1, 2, 3], $this->model->third);
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace Tests\IndexBundle\Model;
use IndexBundle\Model\AbstractDocument;
/**
* Class TestModel
* @package Tests\IndexBundle\Model
*
* @property integer $first
* @property string $second
* @property array $third
*/
class TestModel extends AbstractDocument
{
/**
* Check that this document is normalized or not.
*
* @return boolean
*/
public function isNormalized()
{
return true;
}
}
@@ -0,0 +1,252 @@
<?php
namespace IndexBundle\Normalizer\Query;
use Tests\AppTestCase;
/**
* Class QueryNormalizerTest
* @package AppBundle\Search\Request\Normalizer
*/
class QueryNormalizerTest extends AppTestCase
{
/**
* @var QueryNormalizer
*/
private $normalizer;
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*
* @return void
*/
protected function setUp()
{
$this->normalizer = new QueryNormalizer();
}
/**
* @dataProvider queriesProvider
*
* @param string $query1 First search query.
* @param string $query2 Second search query.
* @param boolean $expects Match or don't.
*
* @return void
*/
public function testGenerateUniqueKey($query1, $query2, $expects)
{
$query1 = $this->normalizer->normalize($query1);
$query2 = $this->normalizer->normalize($query2);
$message = "Key's must be ". ($expects ? 'same' : 'differ')
.', but first query is '. $query1 .' and second is '. $query2;
$this->assertEquals($query1 === $query2, $expects, $message);
}
/**
* @return array
*/
public function queriesProvider()
{
return [
'cat dog === dog cat' => [
'cat dog',
'dog cat',
true,
],
'cat~ dog~0.8 === dog~0.8 cat~' => [
'cat~ dog~0.8',
'dog~0.8 cat~',
true,
],
'cat~ dog~0.7 !== dog~0.8 cat~' => [
'cat~ dog~0.7',
'dog~0.8 cat~',
false,
],
'ca?t dog === dog ca?t' => [
'ca?t dog',
'dog ca?t',
true,
],
'c?at dog !== dog ca?t' => [
'c?at dog',
'dog ca?t',
false,
],
'cat^4 dog === dog cat^4' => [
'cat^4 dog',
'dog cat^4',
true,
],
'cat^3 dog !== dog cat^4' => [
'cat^3 dog',
'dog cat^4',
false,
],
'* dog === dog *' => [
'* dog',
'dog *',
true,
],
'+cat dog === dog +cat' => [
'+cat dog',
'dog +cat',
true,
],
'NOT cat AND dog === dog AND NOT cat' => [
'NOT cat AND dog',
'dog AND NOT cat',
true,
],
'NOT (cat AND (dog OR fish)) === NOT ((fish OR dog) AND cat)' => [
'NOT (cat AND (dog OR fish))',
'NOT ((fish OR dog) AND cat)',
true,
],
' AND or NOT !== NOT or AND' => [
' AND or NOT',
'NOT or AND',
false,
],
'OR AND NOT === NOT OR AND' => [
'OR AND NOT',
'NOT OR AND',
true,
],
'NOT cat !== cat NOT' => [
'NOT cat',
'cat NOT',
false,
],
'cat AND dog !== cat and dog' => [
'cat AND dog',
'cat and dog',
false,
],
'"cat fly" AND dog === dog AND "cat fly"' => [
'"cat fly" AND dog',
'dog AND "cat fly"',
true,
],
'"cat fly"^3 AND dog === dog AND "cat fly"^3' => [
'"cat fly"^3 AND dog',
'dog AND "cat fly"^3',
true,
],
'"cat fly"^4 AND dog !== dog AND "cat fly"^3' => [
'"cat fly"^4 AND dog',
'dog AND "cat fly"^3',
false,
],
'"cat fly"~0.4 AND dog === dog AND "cat fly"~0.4' => [
'"cat fly"~0.4 AND dog',
'dog AND "cat fly"~0.4',
true,
],
'"cat fly"~0.3 AND dog !== dog AND "cat fly"~0.4' => [
'"cat fly"~0.3 AND dog',
'dog AND "cat fly"~0.4',
false,
],
'"cat fly"+ AND dog !== dog AND "cat fly"' => [
'"cat fly"+ AND dog',
'dog AND "cat fly"',
false,
],
'"cat fly"+ AND dog === dog AND "cat fly"+' => [
'"cat fly"+ AND dog',
'dog AND "cat fly"+',
true,
],
'cat AND dog !== cat dog' => [
'cat AND dog',
'cat dog',
false,
],
'cat OR dog === cat dog' => [
'cat OR dog',
'cat dog',
true,
],
'(cat) dog === cat dog' => [
'(cat) dog',
'cat dog',
true,
],
'(cat AND dog) === cat AND dog' => [
'(cat AND dog)',
'cat AND dog',
true,
],
'(cat dog) === dog cat' => [
'(cat dog)',
'dog cat',
true,
],
'(((cat OR dog))) === cat dog' => [
'(((cat OR dog)))',
'cat dog',
true,
],
'(cat AND dog) OR fish === cat AND dog OR fish' => [
'(cat AND dog) OR fish',
'cat AND dog OR fish',
true,
],
'cat AND (dog OR fish) !== cat AND dog OR fish' => [
'cat AND (dog OR fish)',
'cat AND dog OR fish',
false,
],
'(cat AND dog) (fish AND bird) === (cAt AND dog) (fish AND BIRd)' => [
'(cat AND dog) (fish AND bird)',
'(cAt AND dog) (fish AND BIRd)',
true,
],
'(cat AND dog) AND bird === cAt AND BIRD AND dOg' => [
'(cat AND dog) AND bird',
'cAt AND BIRD AND dOg',
true,
],
'(cat OR dog) bird === cAt bird doG' => [
'(cat OR dog) bird',
'cAt bird doG',
true,
],
'(dog OR dog) AND cat === cat AND doG' => [
'(dog OR dog) AND cat',
'cat AND doG',
true,
],
'(dog AND dog) AND cat === cat AND doG' => [
'(dog AND dog) AND cat',
'cat AND doG',
true,
],
'(dog AND dog) AND cat AND (fish OR fish) === fish AND cat AND doG' => [
'(dog AND dog) AND cat AND (fish OR fish)',
'fish AND cat AND doG',
true,
],
'(dog AND dog) OR (cat AND cat) === dog OR (cat)' => [
'(dog AND dog) OR (cat AND cat)',
'dog OR (cat)',
true,
],
'"NOT ("dog cat"^3 AND (Alice OR "fish"~0.3)) OR NOT ("dog cat fish"~ AND NOT (+"Alice" OR dog~0.3 OR man^3))' => [
'NOT ("dog cat"^3 AND (Alice OR "fish"~0.3)) OR NOT ("dog cat fish"~ AND NOT (+"Alice" OR dog~0.3 OR man^3))',
'NOT (NOT (man^3 OR +"Alice" OR dog~0.3) AND "dog cat fish"~) OR NOT ("dog cat"^3 AND ("fish"~0.3 OR Alice))',
true,
],
'+Ethiopia +Sudan -”South Africa” === -”South Africa” +Ethiopia +Sudan' => [
'+Ethiopia +Sudan -”South Africa”',
'-”South Africa” +Ethiopia +Sudan',
true,
],
];
}
}
@@ -0,0 +1,119 @@
<?php
namespace UserBundle\Entity\Notification\Schedule;
use Doctrine\ORM\Mapping as ORM;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class DailyNotificationScheduleTest
*/
class DailyNotificationScheduleTest extends TestCase
{
/**
* @return void
*/
public function testComputeDate()
{
$schedule = DailyNotificationSchedule::create()
->setDays(DailyNotificationSchedule::DAYS_ALL)
->setTime(DailyNotificationSchedule::TIME_30_M);
$start = new \DateTime();
$start->setTime($start->format('H'), $start->format('i'), 0);
$end = clone $start;
$end->modify('+ 1 day');
$dates = $schedule->computeDates($start, $end);
/** @var \DateTime $date */
$checkStart = clone $start;
foreach ($dates as $date) {
$this->assertSame(
$checkStart->modify('+ 30 minute')->format('c'),
$date->format('c')
);
}
}
/**
* @return void
*/
public function testComputeDateWeekends()
{
$schedule = DailyNotificationSchedule::create()
->setDays(DailyNotificationSchedule::DAYS_WEEKENDS)
->setTime(DailyNotificationSchedule::TIME_4_H);
$start = new \DateTime();
$start->modify('first friday');
$start->setTime(23, 0, 0);
$end = clone $start;
$end->modify('+ 1 day');
$dates = $schedule->computeDates($start, $end);
/** @var \DateTime $date */
$checkStart = clone $start;
foreach ($dates as $date) {
$this->assertSame(
$checkStart->modify('+ 4 hour')->format('c'),
$date->format('c')
);
$this->assertLessThanOrEqual((int) $date->format('N'), 5);
}
}
/**
* @return void
*/
public function testComputeDateWeekdays()
{
$schedule = DailyNotificationSchedule::create()
->setDays(DailyNotificationSchedule::DAYS_WEEKDAYS)
->setTime(DailyNotificationSchedule::TIME_1_H);
$start = new \DateTime();
$start->modify('first sunday');
$start->setTime(23, 0, 0);
$end = clone $start;
$end->modify('+ 1 day');
$dates = $schedule->computeDates($start, $end);
/** @var \DateTime $date */
$checkStart = clone $start;
foreach ($dates as $date) {
$this->assertSame(
$checkStart->modify('+ 1 hour')->format('c'),
$date->format('c')
);
$this->assertGreaterThan((int) $date->format('N'), 5);
}
}
/**
* @return void
*/
public function testComputeDateWithSpecifiedDates()
{
$schedule = DailyNotificationSchedule::create()
->setDays(DailyNotificationSchedule::DAYS_ALL)
->setTime(DailyNotificationSchedule::TIME_15_M);
$start = new \DateTime();
$start
->setDate(2017, 6, 9)
->setTime(0, 0, 0);
$end = clone $start;
$end->modify('+ 30 minutes');
$dates = $schedule->computeDates($start, $end);
$this->assertCount(2, $dates);
$this->assertSame('2017-06-09 00:15:00', $dates[0]->format('Y-m-d H:i:s'));
$this->assertSame('2017-06-09 00:30:00', $dates[1]->format('Y-m-d H:i:s'));
}
}
@@ -0,0 +1,109 @@
<?php
namespace UserBundle\Entity\Notification\Schedule;
use Doctrine\ORM\Mapping as ORM;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class MonthlyNotificationScheduleTest
*
* @ORM\Entity
*/
class MonthlyNotificationScheduleTest extends TestCase
{
/**
* @return void
*/
public function testComputeDate()
{
$schedule = MonthlyNotificationSchedule::create()
->setDay(5)
->setHour(12)
->setMinute(35);
$start = date_create()->modify('first day of this month')->setTime(0, 0, 0);
$end = date_create()->modify('last day of next month')->setTime(0, 0, 0);
$dates = $schedule->computeDates($start, $end);
$this->assertCount(2, $dates);
$this->assertSame($dates[0]->format('Y-m-d'), date_create()->modify('first day of this month')->modify('4 day')->format('Y-m-d'));
$this->assertSame(5, (int) $dates[0]->format('j'));
$this->assertSame(12, (int) $dates[0]->format('H'));
$this->assertSame(35, (int) $dates[0]->format('i'));
$this->assertSame($dates[1]->format('Y-m-d'), date_create()->modify('first day of next month')->modify('4 day')->format('Y-m-d'));
$this->assertSame(5, (int) $dates[1]->format('j'));
$this->assertSame(12, (int) $dates[1]->format('H'));
$this->assertSame(35, (int) $dates[1]->format('i'));
$schedule = MonthlyNotificationSchedule::create()
->setDay(2)
->setHour(8)
->setMinute(50);
$start = date_create()->modify('first day of this month')->modify('1 day')->setTime(0, 0, 0);
$end = date_create()->modify('next month')->modify('first day of next month')->modify('1 day')->setTime(0, 0, 0);
$dates = $schedule->computeDates($start, $end);
$this->assertCount(3, $dates);
$this->assertSame($dates[0]->format('Y-m-d'), date_create()->modify('first day of this month')->modify('1 day')->format('Y-m-d'));
$this->assertSame(2, (int) $dates[0]->format('j'));
$this->assertSame(8, (int) $dates[0]->format('H'));
$this->assertSame(50, (int) $dates[0]->format('i'));
$this->assertSame($dates[1]->format('Y-m-d'), date_create()->modify('first day of next month')->modify('1 day')->format('Y-m-d'));
$this->assertSame(2, (int) $dates[1]->format('j'));
$this->assertSame(8, (int) $dates[1]->format('H'));
$this->assertSame(50, (int) $dates[1]->format('i'));
$this->assertSame($dates[2]->format('Y-m-d'), date_create()->modify('next month')->modify('first day of next month')->modify('1 day')->format('Y-m-d'));
$this->assertSame(2, (int) $dates[2]->format('j'));
$this->assertSame(8, (int) $dates[2]->format('H'));
$this->assertSame(50, (int) $dates[2]->format('i'));
}
/**
* @return void
*/
public function testComputeDateLast()
{
$schedule = MonthlyNotificationSchedule::create()
->setDay(MonthlyNotificationSchedule::DAY_LAST)
->setHour(12)
->setMinute(35);
$start = date_create()->modify('first day of this month')->setTime(0, 0, 0);
$end = date_create()->modify('last day of next month')->setTime(0, 0, 0);
$dates = $schedule->computeDates($start, $end);
$this->assertCount(2, $dates);
$this->assertSame($dates[0]->format('Y-m-d'), date_create()->modify('last day of this month')->format('Y-m-d'));
$this->assertSame(12, (int) $dates[0]->format('H'));
$this->assertSame(35, (int) $dates[0]->format('i'));
$this->assertSame($dates[1]->format('Y-m-d'), date_create()->modify('last day of next month')->format('Y-m-d'));
$this->assertSame(12, (int) $dates[1]->format('H'));
$this->assertSame(35, (int) $dates[1]->format('i'));
$schedule = MonthlyNotificationSchedule::create()
->setDay(MonthlyNotificationSchedule::DAY_LAST)
->setHour(2)
->setMinute(15);
$start = date_create()->modify('last day of this month')->setTime(0, 0, 0);
$end = date_create()->modify('first day of next month')->setTime(0, 0, 0);
$dates = $schedule->computeDates($start, $end);
$this->assertCount(1, $dates);
$this->assertSame($dates[0]->format('Y-m-d'), date_create()->modify('last day of this month')->format('Y-m-d'));
$this->assertSame(2, (int) $dates[0]->format('H'));
$this->assertSame(15, (int) $dates[0]->format('i'));
}
}
@@ -0,0 +1,117 @@
<?php
namespace UserBundle\Entity\Notification\Schedule;
use Doctrine\ORM\Mapping as ORM;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class WeeklyNotificationSchedule
*
* @ORM\Entity
*/
class WeeklyNotificationScheduleTest extends TestCase
{
/**
* @return void
*/
public function testComputeDate()
{
$schedule = WeeklyNotificationSchedule::create()
->setPeriod(WeeklyNotificationSchedule::PERIOD_SECOND)
->setDay(WeeklyNotificationSchedule::DAY_FRIDAY)
->setHour(12)
->setMinute(35);
$start = date_create()->modify('first day of this month')->setTime(0, 0, 0);
$end = date_create()->modify('second friday of next month')->setTime(0, 0, 0);
$dates = $schedule->computeDates($start, $end);
$this->assertCount(2, $dates);
$this->assertSame($dates[0]->format('Y-m-d'), date_create()->modify('second friday of this month')->format('Y-m-d'));
$this->assertSame(12, (int) $dates[0]->format('H'));
$this->assertSame(35, (int) $dates[0]->format('i'));
$this->assertSame($dates[1]->format('Y-m-d'), date_create()->modify('second friday of next month')->format('Y-m-d'));
$this->assertSame(12, (int) $dates[1]->format('H'));
$this->assertSame(35, (int) $dates[1]->format('i'));
$schedule = WeeklyNotificationSchedule::create()
->setPeriod(WeeklyNotificationSchedule::PERIOD_FIRST)
->setDay(WeeklyNotificationSchedule::DAY_TUESDAY);
$start = date_create()->modify('first day of this month')->setTime(0, 0, 0);
$end = date_create()->modify('second friday of next month')->setTime(0, 0, 0);
$dates = $schedule->computeDates($start, $end);
$this->assertCount(2, $dates);
$this->assertSame($dates[0]->format('Y-m-d'), date_create()->modify('first tuesday of this month')->format('Y-m-d'));
$this->assertSame(0, (int) $dates[0]->format('H'));
$this->assertSame(0, (int) $dates[0]->format('i'));
$this->assertSame($dates[1]->format('Y-m-d'), date_create()->modify('first tuesday of next month')->format('Y-m-d'));
$this->assertSame(0, (int) $dates[1]->format('H'));
$this->assertSame(0, (int) $dates[1]->format('i'));
}
/**
* @return void
*/
public function testComputeDateEvery()
{
$schedule = WeeklyNotificationSchedule::create()
->setPeriod(WeeklyNotificationSchedule::PERIOD_EVERY)
->setDay(WeeklyNotificationSchedule::DAY_MONDAY)
->setHour(10)
->setMinute(45);
$start = date_create()->modify('first day of this month')->setTime(0, 0, 0);
$end = date_create()->modify('last day of next month')->setTime(0, 0, 0);
$dates = $schedule->computeDates($start, $end);
/** @var \DateTime $date */
foreach ($dates as $date) {
$this->assertSame(
1,
(int) $date->format('N')
);
$this->assertSame(10, (int) $date->format('H'));
$this->assertSame(45, (int) $date->format('i'));
}
}
/**
* @return void
*/
public function testComputeDateLast()
{
$schedule = WeeklyNotificationSchedule::create()
->setPeriod(WeeklyNotificationSchedule::PERIOD_LAST)
->setDay(WeeklyNotificationSchedule::DAY_SUNDAY)
->setHour(10)
->setMinute(45);
$start = date_create()->modify('first day of this month')->setTime(0, 0, 0);
$end = date_create()->modify('next month')->modify('last day of next month')->setTime(0, 0, 0);
$dates = $schedule->computeDates($start, $end);
$this->assertCount(3, $dates);
$this->assertSame($dates[0]->format('Y-m-d'), date_create()->modify('last sunday of this month')->format('Y-m-d'));
$this->assertSame(10, (int) $dates[0]->format('H'));
$this->assertSame(45, (int) $dates[0]->format('i'));
$this->assertSame($dates[1]->format('Y-m-d'), date_create()->modify('last sunday of next month')->format('Y-m-d'));
$this->assertSame(10, (int) $dates[1]->format('H'));
$this->assertSame(45, (int) $dates[1]->format('i'));
$this->assertSame($dates[2]->format('Y-m-d'), date_create()->modify('next month')->modify('last sunday of next month')->format('Y-m-d'));
$this->assertSame(10, (int) $dates[2]->format('H'));
$this->assertSame(45, (int) $dates[2]->format('i'));
}
}
@@ -0,0 +1,103 @@
<?php
namespace UserBundle\Entity\Recipient;
use Tests\AppTestCase;
use UserBundle\Entity\User;
/**
* Class PersonRecipientTest
*
* @package UserBundle\Entity
*/
class PersonRecipientTest extends AppTestCase
{
/**
* @var PersonRecipient
*/
private $recipient;
/**
* @return void
*/
public function testSetFirstNameWithoutAssignedUser()
{
$this->recipient->setFirstName('first name');
$this->assertEquals('first name', $this->recipient->getFirstName());
}
/**
* @return void
*/
public function testSetFirstNameWithAssignedUser()
{
$user = new User();
$this->recipient
->setAssociatedUser($user)
->setFirstName('first name');
$this->assertEquals('first name', $this->recipient->getFirstName());
$this->assertEquals('first name', $user->getFirstName());
}
/**
* @return void
*/
public function testSetLastNameWithoutAssignedUser()
{
$this->recipient->setLastName('last name');
$this->assertEquals('last name', $this->recipient->getLastName());
}
/**
* @return void
*/
public function testSetLastNameWithAssignedUser()
{
$user = new User();
$this->recipient
->setAssociatedUser($user)
->setLastName('last name');
$this->assertEquals('last name', $this->recipient->getLastName());
$this->assertEquals('last name', $user->getLastName());
}
/**
* @return void
*/
public function testSetEmailWithoutAssignedUser()
{
$this->recipient->setEmail('test@test.test');
$this->assertEquals('test@test.test', $this->recipient->getEmail());
}
/**
* @return void
*/
public function testSetEmailWithAssignedUser()
{
$user = new User();
$this->recipient
->setAssociatedUser($user)
->setEmail('test@test.test');
$this->assertEquals('test@test.test', $this->recipient->getEmail());
$this->assertEquals('test@test.test', $user->getEmail());
}
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*
* @return void
*/
protected function setUp()
{
$this->recipient = new PersonRecipient();
}
}
@@ -0,0 +1,43 @@
<?php
namespace UserBundle\Entity\Traits;
use Tests\AppTestCase;
use UserBundle\Enum\AppLimitEnum;
/**
* Class LimitAwareTraitTest
*
* @package UserBundle\Entity\Traits
*/
class LimitAwareTraitTest extends AppTestCase
{
/**
* @var LimitAwareTrait
*/
private $trait;
/**
* @return void
*/
public function testLimitValue()
{
/** @var AppLimitEnum $value */
foreach (AppLimitEnum::getValues() as $value) {
$this->trait->setLimitValue($value, 1);
$this->assertEquals(1, $this->trait->getLimitValue($value));
}
}
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*
* @return void
*/
protected function setUp()
{
$this->trait = $this->getMockForTrait(LimitAwareTrait::class);
}
}
+221
View File
@@ -0,0 +1,221 @@
<?php
namespace UserBundle\Entity;
use Tests\AppTestCase;
use UserBundle\Entity\Recipient\PersonRecipient;
use UserBundle\Entity\Subscription\AbstractSubscription;
use UserBundle\Entity\Subscription\PersonalSubscription;
use UserBundle\Enum\AppLimitEnum;
use UserBundle\Enum\AppPermissionEnum;
/**
* Class UserTest
*
* @package UserBundle\Entity
*/
class UserTest extends AppTestCase
{
/**
* @var Plan|\PHPUnit_Framework_MockObject_MockObject
*/
private $plan;
/**
* @var AbstractSubscription|\PHPUnit_Framework_MockObject_MockObject
*/
private $subscription;
/**
* @var User|\PHPUnit_Framework_MockObject_MockObject
*/
private $user;
/**
* @return void
*/
public function testIsAllowedTo()
{
$this->plan->setAnalytics(true);
$this->assertTrue($this->user->isAllowedTo(AppPermissionEnum::analytics()));
$this->plan->setAnalytics(false);
$this->assertFalse($this->user->isAllowedTo(AppPermissionEnum::analytics()));
}
/**
* @return void
*/
public function testUseLimit()
{
/** @var AppLimitEnum $value */
foreach (AppLimitEnum::getValues() as $value) {
$this->plan->setLimitValue($value, 4);
$this->subscription->setLimitValue($value, 1);
$this->user->useLimit($value);
$this->assertEquals(2, $this->user->getUsedLimit($value));
$this->user->useLimit($value, 2);
$this->assertEquals(4, $this->user->getUsedLimit($value));
}
}
/**
* @return void
*/
public function testReleaseLimit()
{
/** @var AppLimitEnum $value */
foreach (AppLimitEnum::getValues() as $value) {
$this->subscription->setLimitValue($value, 4);
$this->user->releaseLimit($value);
$this->assertEquals(3, $this->user->getUsedLimit($value));
$this->user->releaseLimit($value, 2);
$this->assertEquals(1, $this->user->getUsedLimit($value));
}
}
/**
* @expectedException \AppBundle\Exception\LimitExceedException
*
* @return void
*/
public function testUseLimitExceed()
{
$this->plan->setSearchesPerDay(4);
$this->subscription->setSearchesPerDay(3);
$this->user->useLimit(AppLimitEnum::searches(), 2);
}
/**
* @return void
*/
public function testGetRestrictions()
{
$limits = [];
/** @var AppLimitEnum $value */
foreach (AppLimitEnum::getValues() as $value) {
$limit = mt_rand(5, 10);
$current = mt_rand(0, $limit);
$limits[$value->getValue()] = [
'limit' => $limit,
'current' => $current,
];
$this->plan->setLimitValue($value, $limit);
$this->subscription->setLimitValue($value, $current);
}
$permissions = [];
/** @var AppPermissionEnum $value */
foreach (AppPermissionEnum::getValues() as $value) {
$allow = (boolean) mt_rand(0, 1);
$permissions[$value->getValue()] = $allow;
$this->plan->setPermission($value, $allow);
}
$restrictions = $this->user->getRestrictions();
$this->assertCount(2, $restrictions);
$this->assertArrayHasKey('limits', $restrictions);
$this->assertArrayHasKey('permissions', $restrictions);
$this->assertEquals($limits, $restrictions['limits']);
$this->assertEquals($permissions, $restrictions['permissions']);
}
/**
* @return void
*/
public function setFirstNameWithoutRecipient()
{
$this->user->setFirstName('first name');
$this->assertEquals('first name', $this->user->getFirstName());
}
/**
* @return void
*/
public function setFirstNameWithRecipient()
{
$recipient = new PersonRecipient();
$this->user
->setRecipient($recipient)
->setFirstName('first name');
$this->assertEquals('first name', $this->user->getFirstName());
$this->assertEquals('first name', $recipient->getFirstName());
}
/**
* @return void
*/
public function setLastNameWithoutRecipient()
{
$this->user->setLastName('last name');
$this->assertEquals('last name', $this->user->getLastName());
}
/**
* @return void
*/
public function setLastNameWithRecipient()
{
$recipient = new PersonRecipient();
$this->user
->setRecipient($recipient)
->setLastName('last name');
$this->assertEquals('last name', $this->user->getLastName());
$this->assertEquals('last name', $recipient->getLastName());
}
/**
* @return void
*/
public function setEmailWithoutRecipient()
{
$this->user->setEmail('test@test.test');
$this->assertEquals('test@test.test', $this->user->getEmail());
}
/**
* @return void
*/
public function setEmailWithRecipient()
{
$recipient = new PersonRecipient();
$this->user
->setRecipient($recipient)
->setEmail('test@test.test');
$this->assertEquals('test@test.test', $this->user->getEmail());
$this->assertEquals('test@test.test', $recipient->getEmail());
}
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*
* @return void
*/
protected function setUp()
{
$this->plan = new Plan();
$this->subscription = new PersonalSubscription();
$this->subscription->setPlan($this->plan);
$this->user = new User();
$this->user->setBillingSubscription($this->subscription);
}
}
@@ -0,0 +1,126 @@
<?php
namespace UserBundle\Form\Type;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Context\ExecutionContext;
use Symfony\Component\Validator\Violation\ConstraintViolationBuilder;
/**
* Class ColorTypeTest
*
* @package UserBundle\Form\Type
*/
class ColorTypeTest extends TestCase
{
/**
* @var ColorType
*/
private $type;
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*
* @return void
*/
protected function setUp()
{
$this->type = new ColorType();
}
/**
* @dataProvider validProvider
*
* @param mixed $color Validated color.
*
* @return void
*/
public function testValidateSuccess($color)
{
$context = $this->getMockBuilder(ExecutionContext::class)
->disableOriginalConstructor()
->setMethods([ 'buildViolation' ])
->getMock();
$context->expects($this->never())
->method('buildViolation')
->willReturnCallback(function () {
$mock = $this->getMockBuilder(ConstraintViolationBuilder::class)
->disableOriginalConstructor()
->setMethods([ 'addViolation' ])
->getMock();
$mock->expects($this->never())
->method('addViolation');
return $mock;
});
$this->type->validate($color, $context);
}
/**
* @dataProvider notValidProvider
*
* @param mixed $color Validated color.
*
* @return void
*/
public function testValidateFail($color)
{
$context = $this->getMockBuilder(ExecutionContext::class)
->disableOriginalConstructor()
->setMethods([ 'buildViolation' ])
->getMock();
$context->expects($this->once())
->method('buildViolation')
->willReturnCallback(function () {
$mock = $this->getMockBuilder(ConstraintViolationBuilder::class)
->disableOriginalConstructor()
->setMethods([ 'addViolation' ])
->getMock();
$mock->expects($this->once())
->method('addViolation');
return $mock;
});
$this->type->validate($color, $context);
}
/**
* @return array
*/
public function validProvider()
{
return [
[ 'rgba(100, 100, 100, .0)' ],
[ 'rgba(125, 100, 100, 1.0)' ],
[ 'rgba(255, 255, 255, 1)' ],
[ 'rgba(1, 12, 123, .0000034)' ],
[ 'rgba(43, 234, 23, .2)' ],
[ 'rgba(0, 0, 0, .1)' ],
];
}
/**
* @return array
*/
public function notValidProvider()
{
return [
[ 'rgba(100, 100, 100, .0' ],
[ 'rgba(125, 256, 100, 1.0)' ],
[ 'rgba(255, 255, 255)' ],
[ 'rgba(1, 12, 123, -1)' ],
[ 'rgba(43, 234, -23, .2)' ],
[ 'rgba(0, 0, 0, 1.001)' ],
[ 'rgba(0, 20, 0, 100%)' ],
];
}
}
@@ -0,0 +1,88 @@
<?php
namespace UserBundle\Manager\Notification;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Tests\AppTestCaseTrait;
use UserBundle\Entity\Notification\Notification;
use UserBundle\Entity\Notification\NotificationTheme;
use UserBundle\Entity\Notification\NotificationThemeOptions;
use UserBundle\Enum\ThemeTypeEnum;
use UserBundle\Manager\Notification\Model\FeedData;
/**
* Class AbstractSendableNotificationTest
*
* @package UserBundle\Manager\Notification
*/
abstract class AbstractSendableNotificationTest extends KernelTestCase
{
use AppTestCaseTrait;
const PATTERN_TPL = '/%s[^\{]*?\{[^\}]*%s[^\}]*\}/i';
/**
* @var EngineInterface
*/
private static $templating;
/**
* @beforeClass
*
* @return void
*/
public static function getServices()
{
self::bootKernel();
self::$templating = self::$kernel->getContainer()->get('templating');
}
/**
* @param ThemeTypeEnum $themeType A ThemeTypeEnum instance.
* @param array $diffs Notification theme diffs.
* @param FeedData[] $data Array of feed data.
*
* @return string
*/
protected function render(ThemeTypeEnum $themeType, array $diffs = [], array $data = [])
{
$notification = Notification::create()
->setTheme(
NotificationTheme::create()
->setEnhanced(NotificationThemeOptions::createDefault())
->setPlain(NotificationThemeOptions::createDefault())
)
->setThemeType($themeType);
switch ($themeType->getValue()) {
case ThemeTypeEnum::ENHANCED:
$notification->setEnhancedThemeOptionsDiff($diffs);
break;
case ThemeTypeEnum::PLAIN:
$notification->setPlainThemeOptionsDiff($diffs);
break;
default:
throw new \DomainException('Unhandled theme type: '. $themeType->getValue());
}
$sendableNotification = new SendableNotification(
new SendableNotificationConfig(
0,
0,
0,
0,
'<p>empty</p>',
0
),
$notification,
$data
);
return $sendableNotification->render(self::$templating);
}
}
@@ -0,0 +1,862 @@
<?php
namespace UserBundle\Manager\Notification;
use CacheBundle\Entity\Comment;
use IndexBundle\Index\Strategy\IndexStrategyInterface;
use Symfony\Component\DomCrawler\Crawler;
use Tests\Helper\HtmlAsserter;
use UserBundle\Entity\User;
use UserBundle\Enum\ThemeOptionsTableOfContentsEnum;
use UserBundle\Enum\ThemeOptionsUserCommentsEnum;
use UserBundle\Enum\ThemeTypeEnum;
use UserBundle\Manager\Notification\Model\FeedData;
use IndexBundle\Model\ArticleDocument;
/**
* Class NotificationContentRenderTest
*
* @package UserBundle\Manager\Notification
*/
class NotificationContentRenderTest extends AbstractSendableNotificationTest
{
const FIRST_FEED_COUNT = 1;
const SECOND_FEED_COUNT = 1;
const THIRD_FEED_COUNT = 0;
/**
* @return void
*/
public function testSummaryAndConclusion()
{
//
// Plain
//
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::simple(),
])
->hasNotNode('.email-summary')
->hasNotNode('.email-conclusion');
$this->createAsserter(ThemeTypeEnum::plain(), [
'summary' => 'summary text',
'conclusion' => 'conclusion text',
])
->with('.email-summary')->contains('summary text')->end()
->with('.email-conclusion')->contains('conclusion text')->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'conclusion' => 'conclusion text',
])
->hasNotNode('.email-summary')
->with('.email-conclusion')->contains('conclusion text')->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'summary' => 'summary text',
])
->with('.email-summary')->contains('summary text')->end()
->hasNotNode('.email-conclusion');
//
// Enhanced
//
$this->createAsserter(ThemeTypeEnum::enhanced())
->hasNotNode('.email-summary')
->hasNotNode('.email-conclusion');
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'summary' => 'summary text',
'conclusion' => 'conclusion text',
])
->with('.email-summary')->contains('summary text')->end()
->with('.email-conclusion')->contains('conclusion text')->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'conclusion' => 'conclusion text',
])
->hasNotNode('.email-summary')
->with('.email-conclusion')->contains('conclusion text')->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'summary' => 'summary text',
])
->with('.email-summary')->contains('summary text')->end()
->hasNotNode('.email-conclusion');
}
/**
* @return void
*/
public function testTableOfContentsPlain()
{
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::no(),
'content:showInfo:articleCount' => true,
])
->hasNotNode('.table-of-contents')->end()
->hasNotNode('.table-of-contents .feed-document-count')->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::no(),
'content:showInfo:articleCount' => false,
])
->hasNotNode('.table-of-contents')->end()
->hasNotNode('.table-of-contents .feed-document-count')->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::simple(),
'content:showInfo:articleCount' => true,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->with('.feed-document-count')
->child(0)->contains(sprintf('(%d articles)', self::FIRST_FEED_COUNT))->end()
->child(1)->contains(sprintf('(%d articles)', self::SECOND_FEED_COUNT))->end()
->child(2)->contains(sprintf('(%d articles)', self::THIRD_FEED_COUNT))->end()
->end()
->hasNotNode('.documents .document')
->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::simple(),
'content:showInfo:articleCount' => false,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->hasNotNode('.feed-document-count')
->hasNotNode('.documents .document')
->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::headline(),
'content:showInfo:articleCount' => true,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->with('.feed-document-count')
->child(0)->contains(sprintf('(%d articles)', self::FIRST_FEED_COUNT))->end()
->child(1)->contains(sprintf('(%d articles)', self::SECOND_FEED_COUNT))->end()
->child(2)->contains(sprintf('(%d articles)', self::THIRD_FEED_COUNT))->end()
->end()
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1', true)
->end()
->end()
->end()
->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::headline(),
'content:showInfo:articleCount' => false,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->hasNotNode('.feed-document-count')
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1', true)
->end()
->end()
->end()
->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::headlineSourceDate(),
'content:showInfo:articleCount' => true,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->with('.feed-document-count')
->child(0)->contains(sprintf('(%d articles)', self::FIRST_FEED_COUNT))->end()
->child(1)->contains(sprintf('(%d articles)', self::SECOND_FEED_COUNT))->end()
->child(2)->contains(sprintf('(%d articles)', self::THIRD_FEED_COUNT))->end()
->end()
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1 | CNN | January 01, 2017')
->end()
->end()
->end()
->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::headlineSourceDate(),
'content:showInfo:articleCount' => false,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->hasNotNode('.feed-document-count')
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1 | CNN | January 01, 2017')
->end()
->end()
->end()
->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::sourceHeadlineDate(),
'content:showInfo:articleCount' => true,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->with('.feed-document-count')
->child(0)->contains(sprintf('(%d articles)', self::FIRST_FEED_COUNT))->end()
->child(1)->contains(sprintf('(%d articles)', self::SECOND_FEED_COUNT))->end()
->child(2)->contains(sprintf('(%d articles)', self::THIRD_FEED_COUNT))->end()
->end()
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('CNN | Feed1 Document1 | January 01, 2017')
->end()
->end()
->end()
->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::sourceHeadlineDate(),
'content:showInfo:articleCount' => false,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->hasNotNode('.feed-document-count')
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('CNN | Feed1 Document1 | January 01, 2017')
->end()
->end()
->end()
->end();
}
/**
* @return void
*/
public function testTableOfContainsEnhanced()
{
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::no(),
'content:showInfo:articleCount' => true,
])
->hasNotNode('.table-of-contents')->end()
->hasNotNode('.table-of-contents .feed-document-count')->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::no(),
'content:showInfo:articleCount' => false,
])
->hasNotNode('.table-of-contents')->end()
->hasNotNode('.table-of-contents .feed-document-count')->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::simple(),
'content:showInfo:articleCount' => true,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->with('.feed-document-count')
->child(0)->contains(sprintf('%d articles', self::FIRST_FEED_COUNT))->end()
->child(1)->contains(sprintf('%d articles', self::SECOND_FEED_COUNT))->end()
->child(2)->contains(sprintf('%d articles', self::THIRD_FEED_COUNT))->end()
->end()
->hasNotNode('.documents .document')
->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::simple(),
'content:showInfo:articleCount' => false,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->hasNotNode('.feed-document-count')
->hasNotNode('.documents .document')
->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::headline(),
'content:showInfo:articleCount' => true,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->with('.feed-document-count')
->child(0)->contains(sprintf('%d articles', self::FIRST_FEED_COUNT))->end()
->child(1)->contains(sprintf('%d articles', self::SECOND_FEED_COUNT))->end()
->child(2)->contains(sprintf('%d articles', self::THIRD_FEED_COUNT))->end()
->end()
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1', true)
->end()
->end()
->end()
->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::headline(),
'content:showInfo:articleCount' => false,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->hasNotNode('.feed-document-count')
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1', true)
->end()
->end()
->end()
->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::headlineSourceDate(),
'content:showInfo:articleCount' => true,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->with('.feed-document-count')
->child(0)->contains(sprintf('%d articles', self::FIRST_FEED_COUNT))->end()
->child(1)->contains(sprintf('%d articles', self::SECOND_FEED_COUNT))->end()
->child(2)->contains(sprintf('%d articles', self::THIRD_FEED_COUNT))->end()
->end()
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1 | CNN | January 01, 2017')
->end()
->end()
->end()
->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::headlineSourceDate(),
'content:showInfo:articleCount' => false,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->hasNotNode('.feed-document-count')
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1 | CNN | January 01, 2017')
->end()
->end()
->end()
->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::sourceHeadlineDate(),
'content:showInfo:articleCount' => true,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->with('.feed-document-count')
->child(0)->contains(sprintf('%d articles', self::FIRST_FEED_COUNT))->end()
->child(1)->contains(sprintf('%d articles', self::SECOND_FEED_COUNT))->end()
->child(2)->contains(sprintf('%d articles', self::THIRD_FEED_COUNT))->end()
->end()
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('CNN | Feed1 Document1 | January 01, 2017')
->end()
->end()
->end()
->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:tableOfContents' => ThemeOptionsTableOfContentsEnum::sourceHeadlineDate(),
'content:showInfo:articleCount' => false,
])
->with('.table-of-contents')
->with('.feed-name')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->hasNotNode('.feed-document-count')
->with('.documents .document')
->child(0)
->with('a')
->hasAttr('href', 'http://permalink')
->contains('CNN | Feed1 Document1 | January 01, 2017')
->end()
->end()
->end()
->end();
}
/**
* @return void
*/
public function testContentPlain()
{
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:sectionDivider' => false,
'content:showInfo:sourceCountry' => false,
'content:showInfo:userComments' => ThemeOptionsUserCommentsEnum::no(),
'content:showInfo:images' => false,
])
->with('.content')
->with('.feed-title')
->child(0)->contains('feed1:')->end()
->child(1)->contains('feed2:')->end()
->child(2)->contains('feed3:')->end()
->end()
->hasNotNode('.feed-title img')
->notContains('<b>Comments</b>')
->with('.documents')
->hasNotNode('.document-aside')
->with('.document')
->child(0)
->with('.document-headline a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1')
->end()
->with('.document-source')
->contains('CNN')
->notContains('(Russian)')
->end()
->with('.document-author')->contains('John Smith')->end()
->with('.document-date')
->contains('-')
->contains(date_create('2017-01-01 10:00:00')->format('F d, Y H:i'))
->end()
->with('.document-content')->contains('Feed1 Document1 Main')->end()
->hasNotNode('.comments')
->hasNotNode('.document-image')
->end()
->child(1)
->with('.document-headline a')
->hasAttr('href', 'http://permalink_next')
->contains('Feed2 Document1')
->end()
->with('.document-source')
->contains('Test')
->notContains('(USA)')
->end()
->hasNotNode('.document-author')
->with('.document-date')
->contains('-')
->contains(date_create('2017-01-10 10:00:00')->format('F d, Y H:i'))
->end()
->with('.document-content')->contains('Feed2 Document1 Main')->end()
->hasNotNode('.comments')
->hasNotNode('.document-image')
->end()
->end()
->end()
->hasNotNode('.feed-divider')
->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:sectionDivider' => true,
'content:showInfo:sourceCountry' => true,
'content:showInfo:userComments' => ThemeOptionsUserCommentsEnum::withAuthorDate(),
'content:showInfo:images' => true,
])
->with('.content')
->with('.feed-title')
->child(0)->contains('feed1:')->end()
->child(1)->contains('feed2:')->end()
->child(2)->contains('feed3:')->end()
->end()
->hasNotNode('.feed-title img')
->notContains('<b>Comments</b>')
->with('.documents')
->hasNotNode('.document-aside')
->with('.document')
->child(0)
->with('.document-headline a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1')
->end()
->with('.document-source')
->contains('CNN')
->contains('(Russian)')
->end()
->with('.document-author')->contains('John Smith')->end()
->with('.document-date')
->contains('-')
->contains(date_create('2017-01-01 10:00:00')->format('F d, Y H:i'))
->end()
->with('.document-content')->contains('Feed1 Document1 Main')->end()
->hasNotNode('.comments')
->hasNotNode('.document-image')
->end()
->child(1)
->with('.document-headline a')
->hasAttr('href', 'http://permalink_next')
->contains('Feed2 Document1')
->end()
->with('.document-source')->contains('Test')->end()
->hasNotNode('.document-author')
->with('.document-date')
->contains('-')
->contains(date_create('2017-01-10 10:00:00')->format('F d, Y H:i'))
->end()
->with('.document-content')->contains('Feed2 Document1 Main')->end()
->with('.comments .comment')
->child(0)
->with('.comment-title')->contains('Feed2 Document1 comment1 title')->end()
->with('.comment-author')
->contains('User1 first name')
->contains('User1 last name')
->end()
->with('.comment-date')
->contains(date_create('2017-01-02 10:00:00')->format('F d, Y H:i'))
->end()
->with('.comment-body')->contains('Feed2 Document1 comment1')->end()
->end()
->child(1)
->hasNotNode('.comment-title')
->with('.comment-author')
->contains('User2 first name')
->contains('User2 last name')
->end()
->with('.comment-date')
->contains(date_create('2017-01-03 10:00:00')->format('F d, Y H:i'))
->end()
->with('.comment-body')->contains('Feed2 Document1 comment2')->end()
->end()
->end()
->hasNotNode('.document-image')
->end()
->end()
->end()
->hasNode('.feed-divider', 2)
->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'content:showInfo:userComments' => ThemeOptionsUserCommentsEnum::withoutAuthorDate(),
])
->with('.content')
->with('.document')
->child(1)
->with('.comments')
->hasNotNode('.comment-date')
->end()
->end()
->end()
->end();
}
/**
* @return void
*/
public function testContentEnhanced()
{
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:sectionDivider' => false,
'content:showInfo:sourceCountry' => false,
'content:showInfo:userComments' => ThemeOptionsUserCommentsEnum::no(),
'content:showInfo:images' => false,
])
->with('.content')
->with('.feed-title')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->hasNode('.feed-title img', 3)
->with('.documents')
->hasNode('.document-aside', 2)
->with('.document')
->child(0)
->with('.document-headline a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1')
->end()
->with('.document-source')
->contains('CNN')
->notContains('(Russian)')
->end()
->with('.document-author')->contains('John Smith')->end()
->with('.document-date')
->contains('|')
->contains(date_create('2017-01-01 10:00:00')->format('F d, Y H:i'))
->end()
->with('.document-content')->contains('Feed1 Document1 Main')->end()
->hasNotNode('.comments')
->hasNotNode('.document-image')
->end()
->child(1)
->with('.document-headline a')
->hasAttr('href', 'http://permalink_next')
->contains('Feed2 Document1')
->end()
->with('.document-source')
->contains('Test')
->notContains('(USA)')
->end()
->hasNotNode('.document-author')
->with('.document-date')
->contains('|')
->contains(date_create('2017-01-10 10:00:00')->format('F d, Y H:i'))
->end()
->with('.document-content')->contains('Feed2 Document1 Main')->end()
->hasNotNode('.comments')
->hasNotNode('.document-image')
->end()
->end()
->end()
->hasNotNode('.feed-divider')
->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:sectionDivider' => true,
'content:showInfo:sourceCountry' => true,
'content:showInfo:userComments' => ThemeOptionsUserCommentsEnum::withAuthorDate(),
'content:showInfo:images' => true,
])
->with('.content')
->with('.feed-title')
->child(0)->contains('feed1')->end()
->child(1)->contains('feed2')->end()
->child(2)->contains('feed3')->end()
->end()
->hasNode('.feed-title img', 3)
->with('.documents')
->hasNode('.document-aside', 2)
->with('.document')
->child(0)
->with('.document-headline a')
->hasAttr('href', 'http://permalink')
->contains('Feed1 Document1')
->end()
->with('.document-source')
->contains('CNN')
->contains('(Russian)')
->end()
->with('.document-author')->contains('John Smith')->end()
->with('.document-date')
->contains('|')
->contains(date_create('2017-01-01 10:00:00')->format('F d, Y H:i'))
->end()
->with('.document-content')->contains('Feed1 Document1 Main')->end()
->hasNotNode('.comments')
->hasNode('.document-image')
->end()
->child(1)
->with('.document-headline a')
->hasAttr('href', 'http://permalink_next')
->contains('Feed2 Document1')
->end()
->with('.document-source')->contains('Test')->end()
->hasNotNode('.document-author')
->with('.document-date')
->contains('|')
->contains(date_create('2017-01-10 10:00:00')->format('F d, Y H:i'))
->end()
->with('.document-content')->contains('Feed2 Document1 Main')->end()
->with('.comments .comment')
->child(0)
->with('.comment-title')->contains('Feed2 Document1 comment1 title')->end()
->with('.comment-author')
->contains('User1 first name')
->contains('User1 last name')
->end()
->with('.comment-date')
->contains(date_create('2017-01-02 10:00:00')->format('F d, Y H:i'))
->end()
->with('.comment-body')->contains('Feed2 Document1 comment1')->end()
->end()
->child(1)
->hasNotNode('.comment-title')
->with('.comment-author')
->contains('User2 first name')
->contains('User2 last name')
->end()
->with('.comment-date')
->contains(date_create('2017-01-03 10:00:00')->format('F d, Y H:i'))
->end()
->with('.comment-body')->contains('Feed2 Document1 comment2')->end()
->end()
->end()
->hasNotNode('.document-image')
->end()
->end()
->end()
->hasNotNode('.feed-divider')
->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'content:showInfo:userComments' => ThemeOptionsUserCommentsEnum::withoutAuthorDate(),
])
->with('.content')
->with('.document')
->child(1)
->with('.comments')
->hasNotNode('.comment-date')
->end()
->end()
->end()
->end();
}
/**
* @param ThemeTypeEnum $themeType A ThemeTypeEnum instance.
* @param array $diffs Notification theme diffs.
*
* @return HtmlAsserter
*/
private function createAsserter(ThemeTypeEnum $themeType, array $diffs = [])
{
$comment1 = new Comment(
User::create('some@main.com')
->setFirstName('User1 first name')
->setLastName('User1 last name'),
'Feed2 Document1 comment1',
'Feed2 Document1 comment1 title'
);
$comment1->setCreatedAt(date_create('2017-01-02 10:00:00'));
$comment2 = new Comment(
User::create('some@main.com')
->setFirstName('User2 first name')
->setLastName('User2 last name'),
'Feed2 Document1 comment2'
);
$comment2->setCreatedAt(date_create('2017-01-03 10:00:00'));
/** @var IndexStrategyInterface|\PHPUnit_Framework_MockObject_MockObject $strategy */
$strategy = $this->getMockForInterface(IndexStrategyInterface::class);
$strategy
->method('normalizeDocumentData')
->willReturnCallback(function (array $data) {
return $data;
});
$strategy
->method('normalizeFieldName')
->willReturnCallback(function ($fieldName) {
return $fieldName;
});
$strategy
->method('normalizePublisherType')
->willReturnCallback(function ($type) {
return $type;
});
$crawler = new Crawler($this->render($themeType, $diffs, [
new FeedData('feed1', [
new ArticleDocument($strategy, [
'title' => 'Feed1 Document1',
'permalink' => 'http://permalink',
'content' => 'Feed1 Document1 Main',
'published' => date_create('2017-01-01 10:00:00'),
'source' => [
'title' => 'CNN',
'country' => 'Russian',
],
'author' => [
'name' => 'John Smith',
],
'image' => 'http://image.dev',
]),
]),
new FeedData('feed2', [
new ArticleDocument($strategy, [
'title' => 'Feed2 Document1',
'permalink' => 'http://permalink_next',
'content' => 'Feed2 Document1 Main',
'published' => date_create('2017-01-10 10:00:00'),
'source' => [
'title' => 'Test',
'country' => 'USA',
],
'comments' => [
$comment1,
$comment2,
],
]),
]),
new FeedData('feed3', []),
]));
return new HtmlAsserter($crawler);
}
}
@@ -0,0 +1,502 @@
<?php
namespace UserBundle\Manager\Notification;
use AppBundle\Configuration\ConfigurationImmutableInterface;
use CacheBundle\Document\Extractor\DocumentContentExtractorInterface;
use CacheBundle\Feed\Fetcher\Factory\FeedFetcherFactoryInterface;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\EntityManagerInterface;
use Tests\AppTestCase;
use Tests\UserBundle\Manager\Notification\RecipientFixture;
use UserBundle\Entity\Notification\Notification;
use UserBundle\Entity\Recipient\AbstractRecipient;
/**
* Class NotificationManagerTest
* @package UserBundle\Manager\Notification
*/
class NotificationManagerTest extends AppTestCase
{
/**
* @var Connection|\PHPUnit_Framework_MockObject_MockObject
*/
private $conn;
/**
* @var EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $em;
/**
* @var FeedFetcherFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $feedFetcherFactory;
/**
* @var ConfigurationImmutableInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $configuration;
/**
* @var DocumentContentExtractorInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $extractor;
/**
* @var NotificationManager
*/
private $manager;
/**
* @return void
*/
public function testNormalizeNotificationsSingle()
{
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder(Notification::class)->getMock();
$this->assertEquals([ $notification ], $this->call($this->manager, 'normalizeNotifications', [ $notification ]));
}
/**
* @return void
*/
public function testNormalizeNotificationsMany()
{
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification1 */
$notification1 = $this->getMockBuilder(Notification::class)->getMock();
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification2 */
$notification2 = $this->getMockBuilder(Notification::class)->getMock();
$notifications = [ $notification1, $notification2 ];
$this->assertEquals($notifications, $this->call($this->manager, 'normalizeNotifications', [ $notifications ]));
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Expects single
*
* @return void
*/
public function testNormalizeNotificationsManyFail()
{
$notifications = [ 'invalid', 123 ];
$this->assertEquals($notifications, $this->call($this->manager, 'normalizeNotifications', [ $notifications ]));
}
/**
* @return void
*/
public function testActivatedToggleSingleTrue()
{
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder(Notification::class)
->setMethods([ 'setActive' ])
->getMock();
$notification
->expects($this->once())
->method('setActive')
->with($this->equalTo(true));
$this->em
->expects($this->once())
->method('persist')
->with($this->equalTo($notification));
$this->em
->expects($this->once())
->method('flush');
$this->manager->activatedToggle($notification);
}
/**
* @return void
*/
public function testActivatedToggleSingleFalse()
{
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder(Notification::class)
->setMethods([ 'setActive' ])
->getMock();
$notification
->expects($this->once())
->method('setActive')
->with($this->equalTo(false));
$this->em
->expects($this->once())
->method('persist')
->with($this->equalTo($notification));
$this->em
->expects($this->once())
->method('flush');
$this->manager->activatedToggle($notification, false);
}
/**
* @return void
*/
public function testActivatedToggleMany()
{
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification1 = $this->getMockBuilder(Notification::class)
->setMethods([ 'setActive' ])
->getMock();
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification2 = $this->getMockBuilder(Notification::class)
->setMethods([ 'setActive' ])
->getMock();
$notification1
->expects($this->once())
->method('setActive')
->with($this->equalTo(false));
$notification2
->expects($this->once())
->method('setActive')
->with($this->equalTo(false));
$this->em
->expects($this->at(0))
->method('persist')
->with($this->equalTo($notification1));
$this->em
->expects($this->at(1))
->method('persist')
->with($this->equalTo($notification2));
$this->em
->expects($this->once())
->method('flush');
$this->manager->activatedToggle([ $notification1, $notification2 ], false);
}
/**
* @return void
*/
public function testPublishedToggleSingleTrue()
{
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder(Notification::class)
->setMethods([ 'setPublished' ])
->getMock();
$notification
->expects($this->once())
->method('setPublished')
->with($this->equalTo(true));
$this->em
->expects($this->once())
->method('persist')
->with($this->equalTo($notification));
$this->em
->expects($this->once())
->method('flush');
$this->manager->publishedToggle($notification);
}
/**
* @return void
*/
public function testPublishedToggleSingleFalse()
{
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder(Notification::class)
->setMethods([ 'setPublished' ])
->getMock();
$notification
->expects($this->once())
->method('setPublished')
->with($this->equalTo(false));
$this->em
->expects($this->once())
->method('persist')
->with($this->equalTo($notification));
$this->em
->expects($this->once())
->method('flush');
$this->manager->publishedToggle($notification, false);
}
/**
* @return void
*/
public function testPublishedToggleManyFalse()
{
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification1 = $this->getMockBuilder(Notification::class)
->setMethods([ 'setPublished' ])
->getMock();
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification2 = $this->getMockBuilder(Notification::class)
->setMethods([ 'setPublished' ])
->getMock();
$notification1
->expects($this->once())
->method('setPublished')
->with($this->equalTo(false));
$notification2
->expects($this->once())
->method('setPublished')
->with($this->equalTo(false));
$this->em
->expects($this->at(0))
->method('persist')
->with($this->equalTo($notification1));
$this->em
->expects($this->at(1))
->method('persist')
->with($this->equalTo($notification2));
$this->em
->expects($this->once())
->method('flush');
$this->manager->publishedToggle([ $notification1, $notification2 ], false);
}
/**
* @return void
*/
public function testSubscriptionToggleTrue()
{
$recipient = $this->getMockForAbstractClass(AbstractRecipient::class);
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder(Notification::class)
->setMethods([ 'getRecipients', 'addRecipient' ])
->getMock();
$notification
->expects($this->once())
->method('getRecipients')
->willReturn([]);
$notification
->expects($this->once())
->method('addRecipient')
->with($this->equalTo($recipient));
$this->em
->expects($this->once())
->method('persist')
->with($this->equalTo($notification));
$this->em
->expects($this->once())
->method('flush');
$this->manager->subscriptionToggle($recipient, $notification);
}
/**
* @return void
*/
public function testSubscriptionToggleTrueWithExists()
{
$recipient1 = new RecipientFixture(1);
$recipient2 = new RecipientFixture(2);
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification1 */
$notification1 = $this->getMockBuilder(Notification::class)
->setMethods([ 'getRecipients', 'addRecipient' ])
->getMock();
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification2 */
$notification2 = $this->getMockBuilder(Notification::class)
->setMethods([ 'getRecipients', 'addRecipient' ])
->getMock();
$notification1
->expects($this->once())
->method('getRecipients')
->willReturn([ $recipient1, $recipient2 ]);
$notification1
->expects($this->never())
->method('addRecipient');
$notification2
->expects($this->once())
->method('getRecipients')
->willReturn([ $recipient2 ]);
$notification2
->expects($this->once())
->method('addRecipient')
->with($this->equalTo($recipient1));
$this->em
->expects($this->once())
->method('persist')
->with($this->equalTo($notification2));
$this->em
->expects($this->once())
->method('flush');
$this->manager->subscriptionToggle($recipient1, [ $notification1, $notification2 ]);
}
/**
* @return void
*/
public function testSubscriptionToggleFalse()
{
$recipient = $this->getMockForAbstractClass(AbstractRecipient::class);
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder(Notification::class)
->setMethods([ 'getRecipients', 'removeRecipient' ])
->getMock();
$notification
->expects($this->never())
->method('getRecipients');
$notification
->expects($this->once())
->method('removeRecipient')
->with($this->equalTo($recipient));
$this->em
->expects($this->once())
->method('persist')
->with($this->equalTo($notification));
$this->em
->expects($this->once())
->method('flush');
$this->manager->subscriptionToggle($recipient, $notification, false);
}
/**
* @return void
*/
public function testRemoveSingle()
{
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder(Notification::class)
->setMethods([ 'getId' ])
->getMock();
$notification
->expects($this->once())
->method('getId')
->willReturn(1);
$this->em
->expects($this->once())
->method('remove')
->with($this->equalTo($notification));
$this->em
->expects($this->once())
->method('flush');
$this->conn
->expects($this->once())
->method('executeQuery')
->with($this->stringContains('WHERE notification_id in (1)'));
$this->manager->remove($notification);
}
/**
* @return void
*/
public function testRemoveMany()
{
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification1 */
$notification1 = $this->getMockBuilder(Notification::class)
->setMethods([ 'getId' ])
->getMock();
/** @var Notification|\PHPUnit_Framework_MockObject_MockObject $notification2 */
$notification2 = $this->getMockBuilder(Notification::class)
->setMethods([ 'getId' ])
->getMock();
$notification1
->expects($this->once())
->method('getId')
->willReturn(1);
$notification2
->expects($this->once())
->method('getId')
->willReturn(2);
$this->em
->expects($this->at(0))
->method('remove')
->with($this->equalTo($notification1));
$this->em
->expects($this->at(1))
->method('remove')
->with($this->equalTo($notification2));
$this->em
->expects($this->once())
->method('flush');
$this->conn
->expects($this->once())
->method('executeQuery')
->with($this->stringContains('WHERE notification_id in (1,2)'));
$this->manager->remove([ $notification1, $notification2 ]);
}
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*
* @return void
*/
protected function setUp()
{
$this->conn = $this->getMockForInterface(Connection::class);
$this->em = $this->getMockForInterface(EntityManagerInterface::class);
$this->feedFetcherFactory = $this->getMockForInterface(FeedFetcherFactoryInterface::class);
$this->configuration = $this->getMockForInterface(ConfigurationImmutableInterface::class);
$this->extractor = $this->getMockForInterface(DocumentContentExtractorInterface::class);
$this->em
->expects($this->any())
->method('getConnection')
->willReturn($this->conn);
$this->manager = new NotificationManager(
$this->em,
$this->feedFetcherFactory,
$this->configuration,
$this->extractor
);
}
}
@@ -0,0 +1,756 @@
<?php
namespace UserBundle\Manager\Notification;
use Tests\Helper\CssAssertBuilder;
use Tests\Helper\CssAsserter;
use UserBundle\Entity\Notification\NotificationThemeOptions;
use UserBundle\Entity\Notification\ThemeOption\ThemeOptionColorsBackground;
use UserBundle\Entity\Notification\ThemeOption\ThemeOptionColorsText;
use UserBundle\Entity\Notification\ThemeOption\ThemeOptionFont;
use UserBundle\Entity\Notification\ThemeOption\ThemeOptionFontStyle;
use UserBundle\Enum\FontFamilyEnum;
use UserBundle\Enum\ThemeTypeEnum;
use UserBundle\Manager\Notification\Model\FeedData;
/**
* Class NotificationStylesRenderTest
*
* @package UserBundle\Manager\Notification
*/
class NotificationStylesRenderTest extends AbstractSendableNotificationTest
{
/**
* @return void
*/
public function testLayout()
{
$defaultEmailBodyBG = ThemeOptionColorsBackground::DEFAULT_EMAIL_BODY;
$defaultAccentBG = ThemeOptionColorsBackground::DEFAULT_ACCENT;
$defaultArticleContentFG = ThemeOptionColorsText::DEFAULT_ARTICLE_CONTENT;
$customEmailBodyBG = 'rgba(123, 44, 55, 0.32)';
$customAccentBG = 'rgba(124, 45, 56, 0.33)';
$customArticleContentFG = 'rgba(125, 46, 57, 0.34)';
$this->createAsserter(ThemeTypeEnum::plain())
->with('.email')->hasNot('border')->end()
->with('html')->hasNot('background')->end()
->with('body')->hasNot('background')->end()
->with('.email-body-content')->has('color', $defaultArticleContentFG)->end();
$this->createAsserter(ThemeTypeEnum::plain(), [
'colors:background:emailBody' => $customEmailBodyBG,
'colors:background:accent' => $customAccentBG,
'colors:text:articleContent' => $customArticleContentFG,
])
->with('.email')->hasNot('border')->end()
->with('html')->hasNot('background')->end()
->with('body')->hasNot('background')->end()
->with('.email-body-content')->has('color', $customArticleContentFG)->end();
$this->createAsserter(ThemeTypeEnum::enhanced())
->with('.email')->has('border', '4px solid '. $defaultAccentBG)->end()
->with('html')->has('background', $defaultEmailBodyBG)->end()
->with('body')->has('background', $defaultEmailBodyBG)->end()
->with('.email-body-content')->has('color', $defaultArticleContentFG)->end();
$this->createAsserter(ThemeTypeEnum::enhanced(), [
'colors:background:emailBody' => $customEmailBodyBG,
'colors:background:accent' => $customAccentBG,
'colors:text:articleContent' => $customArticleContentFG,
])
->with('.email')->has('border', '4px solid '. $customAccentBG)->end()
->with('html')->has('background', $customEmailBodyBG)->end()
->with('body')->has('background', $customEmailBodyBG)->end()
->with('.email-body-content')->has('color', $customArticleContentFG)->end();
}
/**
* @return void
*/
public function testHeader()
{
$this->assertCssRender(ThemeTypeEnum::plain(), [
$this->createCssAssertBuilder('.email-header')
->propertyShouldBe('color', 'white')
->propertyShouldNotBe('height', '105px'),
$this->createCssAssertBuilder('.email-header-info-title')
->hasFont(new ThemeOptionFont(
FontFamilyEnum::arial(),
NotificationThemeOptions::DEFAULT_HEADER_SIZE
))
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_HEADER),
$this->createCssAssertBuilder('.email-header-info-date')
->propertyShouldBe('color', ThemeOptionColorsBackground::DEFAULT_ACCENT),
]);
$this->assertCssRender(ThemeTypeEnum::plain(), [
$this->createCssAssertBuilder('.email-header')
->propertyShouldBe('color', 'white')
->propertyShouldBe('height', '105px'),
$this->createCssAssertBuilder('.email-header-info-title')
->hasFont(new ThemeOptionFont(
FontFamilyEnum::calibri(),
10,
new ThemeOptionFontStyle(true, true, true)
))
->propertyShouldBe('color', 'rgba(124, 45, 56, 0.33)'),
$this->createCssAssertBuilder('.email-header-info-date')
->propertyShouldBe('color', 'rgba(123, 44, 55, 0.32)'),
], [
'header:imageUrl' => 'http://pic.com',
'colors:background:accent' => 'rgba(123, 44, 55, 0.32)',
'colors:text:header' => 'rgba(124, 45, 56, 0.33)',
'fonts:header:family' => FontFamilyEnum::calibri(),
'fonts:header:size' => 10,
'fonts:header:style:bold' => true,
'fonts:header:style:italic' => true,
'fonts:header:style:underline' => true,
]);
}
/**
* @return void
*/
public function testTableOfContents()
{
$this->tableOfContentsDefault();
$this->tableOfContentsCustom();
}
/**
* @return void
*/
public function testContents()
{
$this->contentsDefault();
$this->contentsCustom();
}
/**
* @return void
*/
public function testFooter()
{
$this->createAsserter(ThemeTypeEnum::plain())
->with('footer')
->has('border-top', '3px double #fff')
->end();
$this->createAsserter(ThemeTypeEnum::plain())
->with('footer')
->hasNot('border-top')
->end();
}
/**
* @return void
*/
private function tableOfContentsDefault()
{
$defaultFont = new ThemeOptionFont(
FontFamilyEnum::arial(),
NotificationThemeOptions::DEFAULT_TABLE_OF_CONTENTS_SIZE
);
$this->assertCssRender(ThemeTypeEnum::plain(), [
// .table-of-contents
$this->createCssAssertBuilder('.table-of-contents .feeds li')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents .feeds > li')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents .feeds > li:before')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents .documents > li:before')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents li:before')
->propertyShouldBe('font-size', NotificationThemeOptions::DEFAULT_TABLE_OF_CONTENTS_SIZE)
->propertyShouldNotBe('font-weight', 'bold')
->propertyShouldNotBe('font-style', 'italic')
->propertyShouldBe('text-decoration', 'none'),
// .feed-name
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-name')
->propertyShouldNotBe('width', '48%')
->propertyShouldNotBe('display', 'inline-block')
->propertyShouldNotBe('margin-left', '20px')
->hasFont($defaultFont),
// .feed-document-count
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-document-count')
->propertyShouldNotBe('width', '48%')
->propertyShouldNotBe('display', 'inline-block')
->hasFont($defaultFont),
// Document link
$this->createCssAssertBuilder('.table-of-contents .documents .document a')
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_ARTICLE_HEADLINE)
->hasFont($defaultFont),
// Misc
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-document-count:before')
->propertyShouldBe('content', ' '),
$this->createCssAssertBuilder('.table-of-contents .documents .document a:after')
->propertyShouldBe('content', 'url(data:image')
->propertyShouldBe('padding-left', '3px'),
$this->createCssAssertBuilder('.table-of-contents .documents .document .source')
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_SOURCE),
]);
$this->assertCssRender(ThemeTypeEnum::enhanced(), [
// .table-of-contents
$this->createCssAssertBuilder('.table-of-contents .feeds li')
->propertyShouldBe('background', 'white')
->propertyShouldBe('display', 'block')
->propertyShouldBe('padding', '5px 10px'),
$this->createCssAssertBuilder('.table-of-contents .feeds > li')
->propertyShouldBe('margin-bottom', '1px')
->propertyShouldBe('border-bottom', '1px solid #e6e6e6'),
$this->createCssAssertBuilder('.table-of-contents .feeds > li:before')
->propertyShouldBe('width', '6px')
->propertyShouldBe('height', '8px')
->propertyShouldBe('content', 'url(data:image'),
$this->createCssAssertBuilder('.table-of-contents .documents > li:before')
->propertyShouldBe('font-size', NotificationThemeOptions::DEFAULT_ARTICLE_CONTENT_SIZE)
->propertyShouldNotBe('font-weight', 'bold')
->propertyShouldNotBe('font-style', 'italic')
->propertyShouldBe('text-decoration', 'none'),
$this->createCssAssertBuilder('.table-of-contents li:before')->shouldNotExists(),
// .feed-name
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-name')
->propertyShouldBe('width', '48%')
->propertyShouldBe('display', 'inline-block')
->propertyShouldBe('margin-left', '20px')
->hasFont($defaultFont),
// .feed-document-count
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-document-count')
->propertyShouldBe('width', '48%')
->propertyShouldBe('display', 'inline-block')
->hasFont($defaultFont),
// Document link
$this->createCssAssertBuilder('.table-of-contents .documents .document a')
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_ARTICLE_CONTENT)
->hasFont(new ThemeOptionFont(
FontFamilyEnum::arial(),
NotificationThemeOptions::DEFAULT_ARTICLE_CONTENT_SIZE
)),
// Misc
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-document-count:before')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents .documents .document a:after')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents .documents .document .source')
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_SOURCE),
]);
}
/**
* @return void
*/
private function tableOfContentsCustom()
{
$customFont = new ThemeOptionFont(
FontFamilyEnum::calibri(),
10,
new ThemeOptionFontStyle(true, true, true)
);
$this->assertCssRender(ThemeTypeEnum::plain(), [
// .table-of-contents
$this->createCssAssertBuilder('.table-of-contents .feeds li')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents .feeds > li')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents .feeds > li:before')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents .documents > li:before')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents li:before')
->propertyShouldBe('font-size', 10)
->propertyShouldBe('font-weight', 'bold')
->propertyShouldBe('font-style', 'italic')
->propertyShouldBe('text-decoration', 'none'),
// .feed-name
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-name')
->propertyShouldNotBe('width', '48%')
->propertyShouldNotBe('display', 'inline-block')
->propertyShouldNotBe('margin-left', '20px')
->hasFont($customFont),
// .feed-document-count
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-document-count')
->propertyShouldNotBe('width', '48%')
->propertyShouldNotBe('display', 'inline-block')
->hasFont($customFont),
// Document link
$this->createCssAssertBuilder('.table-of-contents .documents .document a')
->propertyShouldBe('color', 'rgba(123, 44, 55, 0.32)')
->hasFont($customFont),
// Misc
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-document-count:before')
->propertyShouldBe('content', ' '),
$this->createCssAssertBuilder('.table-of-contents .documents .document a:after')
->propertyShouldBe('content', 'url(data:image')
->propertyShouldBe('padding-left', '3px'),
$this->createCssAssertBuilder('.table-of-contents .documents .document .source')
->propertyShouldBe('color', 'rgba(124, 45, 56, 0.33)'),
], [
'colors:text:articleHeadline' => 'rgba(123, 44, 55, 0.32)',
'colors:text:source' => 'rgba(124, 45, 56, 0.33)',
'fonts:tableOfContents:family' => $customFont->getFamily(),
'fonts:tableOfContents:size' => $customFont->getSize(),
'fonts:tableOfContents:style:bold' => $customFont->getStyle()->isBold(),
'fonts:tableOfContents:style:italic' => $customFont->getStyle()->isItalic(),
'fonts:tableOfContents:style:underline' => $customFont->getStyle()->isUnderline(),
]);
$this->assertCssRender(ThemeTypeEnum::enhanced(), [
// .table-of-contents
$this->createCssAssertBuilder('.table-of-contents .feeds li')
->propertyShouldBe('background', 'white')
->propertyShouldBe('display', 'block')
->propertyShouldBe('padding', '5px 10px'),
$this->createCssAssertBuilder('.table-of-contents .feeds > li')
->propertyShouldBe('margin-bottom', '1px')
->propertyShouldBe('border-bottom', '1px solid #e6e6e6'),
$this->createCssAssertBuilder('.table-of-contents .feeds > li:before')
->propertyShouldBe('width', '6px')
->propertyShouldBe('height', '8px')
->propertyShouldBe('content', 'url(data:image'),
$this->createCssAssertBuilder('.table-of-contents .documents > li:before')
->propertyShouldBe('font-size', 11)
->propertyShouldNotBe('font-weight', 'bold')
->propertyShouldBe('font-style', 'italic')
->propertyShouldBe('text-decoration', 'none'),
$this->createCssAssertBuilder('.table-of-contents li:before')->shouldNotExists(),
// .feed-name
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-name')
->propertyShouldBe('width', '48%')
->propertyShouldBe('display', 'inline-block')
->propertyShouldBe('margin-left', '20px')
->hasFont($customFont),
// .feed-document-count
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-document-count')
->propertyShouldBe('width', '48%')
->propertyShouldBe('display', 'inline-block')
->hasFont($customFont),
// Document link
$this->createCssAssertBuilder('.table-of-contents .documents .document a')
->propertyShouldBe('color', 'rgba(123, 44, 55, 0.32)')
->hasFont(new ThemeOptionFont(
FontFamilyEnum::courierNew(),
11,
new ThemeOptionFontStyle(false, true, true)
)),
// Misc
$this->createCssAssertBuilder('.table-of-contents .feeds .feed .feed-document-count:before')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents .documents .document a:after')->shouldNotExists(),
$this->createCssAssertBuilder('.table-of-contents .documents .document .source')
->propertyShouldBe('color', 'rgba(124, 45, 56, 0.33)'),
], [
'colors:text:articleContent' => 'rgba(123, 44, 55, 0.32)',
'colors:text:source' => 'rgba(124, 45, 56, 0.33)',
'fonts:tableOfContents:family' => $customFont->getFamily(),
'fonts:tableOfContents:size' => $customFont->getSize(),
'fonts:tableOfContents:style:bold' => $customFont->getStyle()->isBold(),
'fonts:tableOfContents:style:italic' => $customFont->getStyle()->isItalic(),
'fonts:tableOfContents:style:underline' => $customFont->getStyle()->isUnderline(),
'fonts:articleContent:family' => FontFamilyEnum::courierNew(),
'fonts:articleContent:size' => 11,
'fonts:articleContent:style:bold' => false,
'fonts:articleContent:style:italic' => true,
'fonts:articleContent:style:underline' => true,
]);
}
/**
* @return void
*/
private function contentsDefault()
{
//
// Plain
//
$feedTitleFont = new ThemeOptionFont(
FontFamilyEnum::arial(),
NotificationThemeOptions::DEFAULT_FEED_TITLE_SIZE
);
$dateFont = new ThemeOptionFont(
FontFamilyEnum::arial(),
NotificationThemeOptions::DEFAULT_DATE_SIZE
);
$articleContentFont = new ThemeOptionFont(
FontFamilyEnum::arial(),
NotificationThemeOptions::DEFAULT_ARTICLE_CONTENT_SIZE
);
$articleHeadlineFont = new ThemeOptionFont(
FontFamilyEnum::arial(),
NotificationThemeOptions::DEFAULT_ARTICLE_HEADLINE_SIZE
);
$sourceFont = new ThemeOptionFont(
FontFamilyEnum::arial(),
NotificationThemeOptions::DEFAULT_SOURCE_SIZE
);
$authorFont = new ThemeOptionFont(
FontFamilyEnum::arial(),
NotificationThemeOptions::DEFAULT_AUTHOR_SIZE
);
$this->assertCssRender(ThemeTypeEnum::plain(), [
// .feed-title
$this->createCssAssertBuilder('.content .feed-title')
->hasFont($feedTitleFont)
->propertyShouldNotExists('background')
->propertyShouldNotExists('color'),
// .document
$this->createCssAssertBuilder('.content .documents .document')
->propertyShouldBe('margin-top', '10px')
->propertyShouldBe('margin-left', '5px')
->propertyShouldNotExists('display')
->propertyShouldNotExists('flex'),
$this->createCssAssertBuilder('.content .documents .document:last-child'),
$this->createCssAssertBuilder('.content .documents .document-aside')->shouldNotExists(),
$this->createCssAssertBuilder('.content .documents .document-main')->shouldNotExists(),
$this->createCssAssertBuilder('.content .documents .document-body')->shouldNotExists(),
$this->createCssAssertBuilder('.content .documents .document-image')->shouldNotExists(),
$this->createCssAssertBuilder('.content .documents .document-image img')->shouldNotExists(),
// .document-headline link
$this->createCssAssertBuilder('.content .documents .document-headline a')
->hasFont($articleHeadlineFont)
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_ARTICLE_HEADLINE),
// .document-source
$this->createCssAssertBuilder('.content .documents .document-source')
->hasFont($sourceFont)
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_SOURCE),
// .document-author
$this->createCssAssertBuilder('.content .documents .document-author')
->hasFont($authorFont)
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_AUTHOR),
// .document-date
$this->createCssAssertBuilder('.content .documents .document-date')
->hasFont($dateFont)
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_PUBLISH_DATE),
// .document-content
$this->createCssAssertBuilder('.content .document .document-content')
->hasFont($articleContentFont),
// Comments
$this->createCssAssertBuilder('.content .comments .comment-title')->shouldNotExists(),
$this->createCssAssertBuilder('.content .comments .comment-author')
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_AUTHOR)
->hasFont($authorFont),
$this->createCssAssertBuilder('.content .comments .comment-date')
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_PUBLISH_DATE)
->hasFont($dateFont),
]);
//
// Enhanced
//
$this->assertCssRender(ThemeTypeEnum::enhanced(), [
// .feed-title
$this->createCssAssertBuilder('.content .feed-title')
->hasFont($feedTitleFont)
->propertyShouldBe('background', ThemeOptionColorsBackground::DEFAULT_ACCENT)
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_HEADER),
// .document
$this->createCssAssertBuilder('.content .documents .document')
->propertyShouldBe('margin-top', '5px')
->propertyShouldNotExists('margin-left', '5px')
->propertyShouldExists('display')
->propertyShouldExists('flex'),
$this->createCssAssertBuilder('.content .documents .document:last-child')->shouldNotExists(),
$this->createCssAssertBuilder('.content .documents .document-aside'),
$this->createCssAssertBuilder('.content .documents .document-main'),
$this->createCssAssertBuilder('.content .documents .document-body'),
$this->createCssAssertBuilder('.content .documents .document-image'),
$this->createCssAssertBuilder('.content .documents .document-image img'),
// .document-headline link
$this->createCssAssertBuilder('.content .documents .document-headline a')
->hasFont($articleHeadlineFont)
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_ARTICLE_HEADLINE),
// .document-source
$this->createCssAssertBuilder('.content .documents .document-source')
->hasFont($sourceFont)
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_SOURCE),
// .document-author
$this->createCssAssertBuilder('.content .documents .document-author')
->hasFont($authorFont)
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_AUTHOR),
// .document-date
$this->createCssAssertBuilder('.content .documents .document-date')
->hasFont($articleContentFont)
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_ARTICLE_CONTENT),
// .document-content
$this->createCssAssertBuilder('.content .document .document-content')
->hasFont($articleContentFont),
// Comments
$this->createCssAssertBuilder('.content .comments .comment-title'),
$this->createCssAssertBuilder('.content .comments .comment-author')
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_AUTHOR)
->hasNotAnyFonts(),
$this->createCssAssertBuilder('.content .comments .comment-date')
->propertyShouldBe('color', ThemeOptionColorsText::DEFAULT_ARTICLE_CONTENT)
->hasNotAnyFonts(),
]);
}
/**
* @return void
*/
private function contentsCustom()
{
$feedTitleFont = new ThemeOptionFont(
FontFamilyEnum::calibri(),
11,
new ThemeOptionFontStyle(true, true, true)
);
$dateFont = new ThemeOptionFont(
FontFamilyEnum::centuryGothic(),
12,
new ThemeOptionFontStyle(true, false, true)
);
$articleContentFont = new ThemeOptionFont(
FontFamilyEnum::georgia(),
13,
new ThemeOptionFontStyle(true, true, false)
);
$articleHeadlineFont = new ThemeOptionFont(
FontFamilyEnum::lucidaSansUnicode(),
14,
new ThemeOptionFontStyle(false, true, true)
);
$sourceFont = new ThemeOptionFont(
FontFamilyEnum::courierNew(),
15,
new ThemeOptionFontStyle(false, true, false)
);
$authorFont = new ThemeOptionFont(
FontFamilyEnum::tahoma(),
16,
new ThemeOptionFontStyle(true, true, false)
);
$diffs = [
'colors:background:accent' => 'rgba(123, 44, 55, 0.32)',
'colors:text:header' => 'rgba(124, 45, 56, 0.33)',
'colors:text:publishDate' => 'rgba(125, 46, 57, 0.34)',
'colors:text:articleContent' => 'rgba(126, 47, 58, 0.35)',
'colors:text:articleHeadline' => 'rgba(127, 48, 59, 0.36)',
'colors:text:source' => 'rgba(128, 49, 60, 0.37)',
'colors:text:author' => 'rgba(129, 50, 61, 0.38)',
'fonts:feedTitle:family' => $feedTitleFont->getFamily(),
'fonts:feedTitle:size' => $feedTitleFont->getSize(),
'fonts:feedTitle:style:bold' => $feedTitleFont->getStyle()->isBold(),
'fonts:feedTitle:style:italic' => $feedTitleFont->getStyle()->isItalic(),
'fonts:feedTitle:style:underline' => $feedTitleFont->getStyle()->isUnderline(),
'fonts:date:family' => $dateFont->getFamily(),
'fonts:date:size' => $dateFont->getSize(),
'fonts:date:style:bold' => $dateFont->getStyle()->isBold(),
'fonts:date:style:italic' => $dateFont->getStyle()->isItalic(),
'fonts:date:style:underline' => $dateFont->getStyle()->isUnderline(),
'fonts:articleContent:family' => $articleContentFont->getFamily(),
'fonts:articleContent:size' => $articleContentFont->getSize(),
'fonts:articleContent:style:bold' => $articleContentFont->getStyle()->isBold(),
'fonts:articleContent:style:italic' => $articleContentFont->getStyle()->isItalic(),
'fonts:articleContent:style:underline' => $articleContentFont->getStyle()->isUnderline(),
'fonts:articleHeadline:family' => $articleHeadlineFont->getFamily(),
'fonts:articleHeadline:size' => $articleHeadlineFont->getSize(),
'fonts:articleHeadline:style:bold' => $articleHeadlineFont->getStyle()->isBold(),
'fonts:articleHeadline:style:italic' => $articleHeadlineFont->getStyle()->isItalic(),
'fonts:articleHeadline:style:underline' => $articleHeadlineFont->getStyle()->isUnderline(),
'fonts:source:family' => $sourceFont->getFamily(),
'fonts:source:size' => $sourceFont->getSize(),
'fonts:source:style:bold' => $sourceFont->getStyle()->isBold(),
'fonts:source:style:italic' => $sourceFont->getStyle()->isItalic(),
'fonts:source:style:underline' => $sourceFont->getStyle()->isUnderline(),
'fonts:author:family' => $authorFont->getFamily(),
'fonts:author:size' => $authorFont->getSize(),
'fonts:author:style:bold' => $authorFont->getStyle()->isBold(),
'fonts:author:style:italic' => $authorFont->getStyle()->isItalic(),
'fonts:author:style:underline' => $authorFont->getStyle()->isUnderline(),
];
//
// Plain
//
$this->assertCssRender(ThemeTypeEnum::plain(), [
// .feed-title
$this->createCssAssertBuilder('.content .feed-title')
->hasFont($feedTitleFont)
->propertyShouldNotExists('background')
->propertyShouldNotExists('color'),
// .document
$this->createCssAssertBuilder('.content .documents .document')
->propertyShouldBe('margin-top', '10px')
->propertyShouldBe('margin-left', '5px')
->propertyShouldNotExists('display')
->propertyShouldNotExists('flex'),
$this->createCssAssertBuilder('.content .documents .document:last-child'),
$this->createCssAssertBuilder('.content .documents .document-aside')->shouldNotExists(),
$this->createCssAssertBuilder('.content .documents .document-main')->shouldNotExists(),
$this->createCssAssertBuilder('.content .documents .document-body')->shouldNotExists(),
$this->createCssAssertBuilder('.content .documents .document-image')->shouldNotExists(),
$this->createCssAssertBuilder('.content .documents .document-image img')->shouldNotExists(),
// .document-headline link
$this->createCssAssertBuilder('.content .documents .document-headline a')
->hasFont($articleHeadlineFont)
->propertyShouldBe('color', 'rgba(127, 48, 59, 0.36)'),
// .document-source
$this->createCssAssertBuilder('.content .documents .document-source')
->hasFont($sourceFont)
->propertyShouldBe('color', 'rgba(128, 49, 60, 0.37)'),
// .document-author
$this->createCssAssertBuilder('.content .documents .document-author')
->hasFont($authorFont)
->propertyShouldBe('color', 'rgba(129, 50, 61, 0.38)'),
// .document-date
$this->createCssAssertBuilder('.content .documents .document-date')
->hasFont($dateFont)
->propertyShouldBe('color', 'rgba(125, 46, 57, 0.34)'),
// .document-content
$this->createCssAssertBuilder('.content .document .document-content')
->hasFont($articleContentFont),
// Comments
$this->createCssAssertBuilder('.content .comments .comment-title')->shouldNotExists(),
$this->createCssAssertBuilder('.content .comments .comment-author')
->propertyShouldBe('color', 'rgba(129, 50, 61, 0.38)')
->hasFont($authorFont),
$this->createCssAssertBuilder('.content .comments .comment-date')
->propertyShouldBe('color', 'rgba(125, 46, 57, 0.34)')
->hasFont($dateFont),
], $diffs);
//
// Enhanced
//
$this->assertCssRender(ThemeTypeEnum::enhanced(), [
// .feed-title
$this->createCssAssertBuilder('.content .feed-title')
->hasFont($feedTitleFont)
->propertyShouldBe('background', 'rgba(123, 44, 55, 0.32)')
->propertyShouldBe('color', 'rgba(124, 45, 56, 0.33)'),
// .document
$this->createCssAssertBuilder('.content .documents .document')
->propertyShouldBe('margin-top', '5px')
->propertyShouldNotExists('margin-left', '5px')
->propertyShouldExists('display')
->propertyShouldExists('flex'),
$this->createCssAssertBuilder('.content .documents .document:last-child')->shouldNotExists(),
$this->createCssAssertBuilder('.content .documents .document-aside'),
$this->createCssAssertBuilder('.content .documents .document-main'),
$this->createCssAssertBuilder('.content .documents .document-body'),
$this->createCssAssertBuilder('.content .documents .document-image'),
$this->createCssAssertBuilder('.content .documents .document-image img'),
// .document-headline link
$this->createCssAssertBuilder('.content .documents .document-headline a')
->hasFont($articleHeadlineFont)
->propertyShouldBe('color', 'rgba(127, 48, 59, 0.36)'),
// .document-source
$this->createCssAssertBuilder('.content .documents .document-source')
->hasFont($sourceFont)
->propertyShouldBe('color', 'rgba(128, 49, 60, 0.37)'),
// .document-author
$this->createCssAssertBuilder('.content .documents .document-author')
->hasFont($authorFont)
->propertyShouldBe('color', 'rgba(129, 50, 61, 0.38)'),
// .document-date
$this->createCssAssertBuilder('.content .documents .document-date')
->hasFont($dateFont)
->propertyShouldBe('color', 'rgba(126, 47, 58, 0.35)'),
// .document-content
$this->createCssAssertBuilder('.content .document .document-content')
->hasFont($articleContentFont),
// Comments
$this->createCssAssertBuilder('.content .comments .comment-title'),
$this->createCssAssertBuilder('.content .comments .comment-author')
->propertyShouldBe('color', 'rgba(129, 50, 61, 0.38)')
->hasNotAnyFonts(),
$this->createCssAssertBuilder('.content .comments .comment-date')
->propertyShouldBe('color', 'rgba(126, 47, 58, 0.35)')
->hasNotAnyFonts(),
], $diffs);
}
/**
* @param string $selector A base css element selector.
* @param boolean $escape Should escape specific pattern symbols or not.
*
* @return CssAssertBuilder
*/
private function createCssAssertBuilder($selector, $escape = true)
{
return new CssAssertBuilder($selector, $escape);
}
/**
* @param ThemeTypeEnum $themeType A ThemeTypeEnum instance.
* @param CssAssertBuilder[] $asserts Array of css assert builders.
*
* @param array $diffs Notification theme diffs.
*
* @return void
*/
private function assertCssRender(ThemeTypeEnum $themeType, array $asserts, array $diffs = [])
{
$html = $this->render($themeType, $diffs, [ new FeedData('test', []) ]);
/** @var CssAssertBuilder $assert */
foreach ($asserts as $assert) {
$assert->assert($html);
}
}
/**
* @param ThemeTypeEnum $themeType A ThemeTypeEnum instance.
* @param array $diffs Notification theme diffs.
*
* @return CssAsserter
*/
private function createAsserter(ThemeTypeEnum $themeType, array $diffs = [])
{
return CssAsserter::createFromHtml($this->render($themeType, $diffs, [ new FeedData('test', []) ]));
}
}
@@ -0,0 +1,55 @@
<?php
namespace Tests\UserBundle\Manager\Notification;
use ApiBundle\Serializer\Metadata\Metadata;
use UserBundle\Entity\Recipient\AbstractRecipient;
/**
* Class NotificationManagerTest
* @package UserBundle\Manager\Notification
*/
class RecipientFixture extends AbstractRecipient
{
/**
* RecipientFixture constructor.
*
* @param string|integer $id Entity id.
*/
public function __construct($id)
{
parent::__construct();
$this->id = $id;
}
/**
* Return fqcn of form used for creating this entity.
*
* @return string
*/
public function getCreateFormClass()
{
return '';
}
/**
* Return fqcn of form used for updating this entity.
*
* @return string
*/
public function getUpdateFormClass()
{
return '';
}
/**
* Return metadata for current entity.
*
* @return \ApiBundle\Serializer\Metadata\Metadata
*/
public function getMetadata()
{
return new Metadata(static::class);
}
}