', 'text/html; charset=UTF-8; dir=RTL');
+ $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an HTML string with extended content type');
+
+ $crawler = new Crawler();
+ $crawler->addContent('
');
+ $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() uses text/html as the default type');
+
+ $crawler = new Crawler();
+ $crawler->addContent('
', 'text/xml; charset=UTF-8');
+ $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an XML string');
+
+ $crawler = new Crawler();
+ $crawler->addContent('
', 'text/xml');
+ $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an XML string');
+
+ $crawler = new Crawler();
+ $crawler->addContent('foo bar', 'text/plain');
+ $this->assertCount(0, $crawler, '->addContent() does nothing if the type is not (x|ht)ml');
+
+ $crawler = new Crawler();
+ $crawler->addContent('
ä¸æ–‡ ');
+ $this->assertEquals('ä¸æ–‡', $crawler->filterXPath('//span')->text(), '->addContent() guess wrong charset');
+
+ $crawler = new Crawler();
+ $crawler->addContent(mb_convert_encoding('
日本語', 'SJIS', 'UTF-8'));
+ $this->assertEquals('日本語', $crawler->filterXPath('//body')->text(), '->addContent() can recognize "Shift_JIS" in html5 meta charset tag');
+ }
+
+ /**
+ * @covers Symfony\Component\DomCrawler\Crawler::addDocument
+ */
+ public function testAddDocument()
+ {
+ $crawler = new Crawler();
+ $crawler->addDocument($this->createDomDocument());
+
+ $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addDocument() adds nodes from a \DOMDocument');
+ }
+
+ /**
+ * @covers Symfony\Component\DomCrawler\Crawler::addNodeList
+ */
+ public function testAddNodeList()
+ {
+ $crawler = new Crawler();
+ $crawler->addNodeList($this->createNodeList());
+
+ $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNodeList() adds nodes from a \DOMNodeList');
+ }
+
+ /**
+ * @covers Symfony\Component\DomCrawler\Crawler::addNodes
+ */
+ public function testAddNodes()
+ {
+ foreach ($this->createNodeList() as $node) {
+ $list[] = $node;
+ }
+
+ $crawler = new Crawler();
+ $crawler->addNodes($list);
+
+ $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNodes() adds nodes from an array of nodes');
+ }
+
+ /**
+ * @covers Symfony\Component\DomCrawler\Crawler::addNode
+ */
+ public function testAddNode()
+ {
+ $crawler = new Crawler();
+ $crawler->addNode($this->createNodeList()->item(0));
+
+ $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNode() adds nodes from a \DOMElement');
+ }
+
+ public function testClear()
+ {
+ $crawler = new Crawler(new \DOMNode());
+ $crawler->clear();
+ $this->assertCount(0, $crawler, '->clear() removes all the nodes from the crawler');
+ }
+
+ public function testEq()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//li');
+ $this->assertNotSame($crawler, $crawler->eq(0), '->eq() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->eq() returns a new instance of a crawler');
+
+ $this->assertEquals('Two', $crawler->eq(1)->text(), '->eq() returns the nth node of the list');
+ $this->assertCount(0, $crawler->eq(100), '->eq() returns an empty crawler if the nth node does not exist');
+ }
+
+ public function testEach()
+ {
+ $data = $this->createTestCrawler()->filterXPath('//ul[1]/li')->each(function ($node, $i) {
+ return $i.'-'.$node->text();
+ });
+
+ $this->assertEquals(array('0-One', '1-Two', '2-Three'), $data, '->each() executes an anonymous function on each node of the list');
+ }
+
+ public function testSlice()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li');
+ $this->assertNotSame($crawler->slice(), $crawler, '->slice() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler->slice(), '->slice() returns a new instance of a crawler');
+
+ $this->assertCount(3, $crawler->slice(), '->slice() does not slice the nodes in the list if any param is entered');
+ $this->assertCount(1, $crawler->slice(1, 1), '->slice() slices the nodes in the list');
+ }
+
+ public function testReduce()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li');
+ $nodes = $crawler->reduce(function ($node, $i) {
+ return $i == 1 ? false : true;
+ });
+ $this->assertNotSame($nodes, $crawler, '->reduce() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $nodes, '->reduce() returns a new instance of a crawler');
+
+ $this->assertCount(2, $nodes, '->reduce() filters the nodes in the list');
+ }
+
+ public function testAttr()
+ {
+ $this->assertEquals('first', $this->createTestCrawler()->filterXPath('//li')->attr('class'), '->attr() returns the attribute of the first element of the node list');
+
+ try {
+ $this->createTestCrawler()->filterXPath('//ol')->attr('class');
+ $this->fail('->attr() throws an \InvalidArgumentException if the node list is empty');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->attr() throws an \InvalidArgumentException if the node list is empty');
+ }
+ }
+
+ public function testMissingAttrValueIsNull()
+ {
+ $crawler = new Crawler();
+ $crawler->addContent('
', 'text/html; charset=UTF-8');
+ $div = $crawler->filterXPath('//div');
+
+ $this->assertEquals('sample value', $div->attr('non-empty-attr'), '->attr() reads non-empty attributes correctly');
+ $this->assertEquals('', $div->attr('empty-attr'), '->attr() reads empty attributes correctly');
+ $this->assertNull($div->attr('missing-attr'), '->attr() reads missing attributes correctly');
+ }
+
+ public function testNodeName()
+ {
+ $this->assertEquals('li', $this->createTestCrawler()->filterXPath('//li')->nodeName(), '->nodeName() returns the node name of the first element of the node list');
+
+ try {
+ $this->createTestCrawler()->filterXPath('//ol')->nodeName();
+ $this->fail('->nodeName() throws an \InvalidArgumentException if the node list is empty');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->nodeName() throws an \InvalidArgumentException if the node list is empty');
+ }
+ }
+
+ public function testText()
+ {
+ $this->assertEquals('One', $this->createTestCrawler()->filterXPath('//li')->text(), '->text() returns the node value of the first element of the node list');
+
+ try {
+ $this->createTestCrawler()->filterXPath('//ol')->text();
+ $this->fail('->text() throws an \InvalidArgumentException if the node list is empty');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->text() throws an \InvalidArgumentException if the node list is empty');
+ }
+ }
+
+ public function testHtml()
+ {
+ $this->assertEquals('
', $this->createTestCrawler()->filterXPath('//a[5]')->html());
+ $this->assertEquals('
', trim($this->createTestCrawler()->filterXPath('//form[@id="FooFormId"]')->html()));
+
+ try {
+ $this->createTestCrawler()->filterXPath('//ol')->html();
+ $this->fail('->html() throws an \InvalidArgumentException if the node list is empty');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->html() throws an \InvalidArgumentException if the node list is empty');
+ }
+ }
+
+ public function testExtract()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li');
+
+ $this->assertEquals(array('One', 'Two', 'Three'), $crawler->extract('_text'), '->extract() returns an array of extracted data from the node list');
+ $this->assertEquals(array(array('One', 'first'), array('Two', ''), array('Three', '')), $crawler->extract(array('_text', 'class')), '->extract() returns an array of extracted data from the node list');
+
+ $this->assertEquals(array(), $this->createTestCrawler()->filterXPath('//ol')->extract('_text'), '->extract() returns an empty array if the node list is empty');
+ }
+
+ public function testFilterXpathComplexQueries()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//body');
+
+ $this->assertCount(0, $crawler->filterXPath('/input'));
+ $this->assertCount(0, $crawler->filterXPath('/body'));
+ $this->assertCount(1, $crawler->filterXPath('/_root/body'));
+ $this->assertCount(1, $crawler->filterXPath('./body'));
+ $this->assertCount(1, $crawler->filterXPath('.//body'));
+ $this->assertCount(5, $crawler->filterXPath('.//input'));
+ $this->assertCount(4, $crawler->filterXPath('//form')->filterXPath('//button | //input'));
+ $this->assertCount(1, $crawler->filterXPath('body'));
+ $this->assertCount(6, $crawler->filterXPath('//button | //input'));
+ $this->assertCount(1, $crawler->filterXPath('//body'));
+ $this->assertCount(1, $crawler->filterXPath('descendant-or-self::body'));
+ $this->assertCount(1, $crawler->filterXPath('//div[@id="parent"]')->filterXPath('./div'), 'A child selection finds only the current div');
+ $this->assertCount(3, $crawler->filterXPath('//div[@id="parent"]')->filterXPath('descendant::div'), 'A descendant selector matches the current div and its child');
+ $this->assertCount(3, $crawler->filterXPath('//div[@id="parent"]')->filterXPath('//div'), 'A descendant selector matches the current div and its child');
+ $this->assertCount(5, $crawler->filterXPath('(//a | //div)//img'));
+ $this->assertCount(7, $crawler->filterXPath('((//a | //div)//img | //ul)'));
+ $this->assertCount(7, $crawler->filterXPath('( ( //a | //div )//img | //ul )'));
+ }
+
+ /**
+ * @covers Symfony\Component\DomCrawler\Crawler::filterXPath
+ */
+ public function testFilterXPath()
+ {
+ $crawler = $this->createTestCrawler();
+ $this->assertNotSame($crawler, $crawler->filterXPath('//li'), '->filterXPath() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->filterXPath() returns a new instance of a crawler');
+
+ $crawler = $this->createTestCrawler()->filterXPath('//ul');
+ $this->assertCount(6, $crawler->filterXPath('//li'), '->filterXPath() filters the node list with the XPath expression');
+
+ $crawler = $this->createTestCrawler();
+ $this->assertCount(3, $crawler->filterXPath('//body')->filterXPath('//button')->parents(), '->filterXpath() preserves parents when chained');
+ }
+
+ public function testFilterXPathWithDefaultNamespace()
+ {
+ $crawler = $this->createTestXmlCrawler()->filterXPath('//default:entry/default:id');
+ $this->assertCount(1, $crawler, '->filterXPath() automatically registers a namespace');
+ $this->assertSame('tag:youtube.com,2008:video:kgZRZmEc9j4', $crawler->text());
+ }
+
+ public function testFilterXPathWithCustomDefaultNamespace()
+ {
+ $crawler = $this->createTestXmlCrawler();
+ $crawler->setDefaultNamespacePrefix('x');
+ $crawler = $crawler->filterXPath('//x:entry/x:id');
+
+ $this->assertCount(1, $crawler, '->filterXPath() lets to override the default namespace prefix');
+ $this->assertSame('tag:youtube.com,2008:video:kgZRZmEc9j4', $crawler->text());
+ }
+
+ public function testFilterXPathWithNamespace()
+ {
+ $crawler = $this->createTestXmlCrawler()->filterXPath('//yt:accessControl');
+ $this->assertCount(2, $crawler, '->filterXPath() automatically registers a namespace');
+ }
+
+ public function testFilterXPathWithMultipleNamespaces()
+ {
+ $crawler = $this->createTestXmlCrawler()->filterXPath('//media:group/yt:aspectRatio');
+ $this->assertCount(1, $crawler, '->filterXPath() automatically registers multiple namespaces');
+ $this->assertSame('widescreen', $crawler->text());
+ }
+
+ public function testFilterXPathWithManuallyRegisteredNamespace()
+ {
+ $crawler = $this->createTestXmlCrawler();
+ $crawler->registerNamespace('m', 'http://search.yahoo.com/mrss/');
+
+ $crawler = $crawler->filterXPath('//m:group/yt:aspectRatio');
+ $this->assertCount(1, $crawler, '->filterXPath() uses manually registered namespace');
+ $this->assertSame('widescreen', $crawler->text());
+ }
+
+ public function testFilterXPathWithAnUrl()
+ {
+ $crawler = $this->createTestXmlCrawler();
+
+ $crawler = $crawler->filterXPath('//media:category[@scheme="http://gdata.youtube.com/schemas/2007/categories.cat"]');
+ $this->assertCount(1, $crawler);
+ $this->assertSame('Music', $crawler->text());
+ }
+
+ public function testFilterXPathWithFakeRoot()
+ {
+ $crawler = $this->createTestCrawler();
+ $this->assertCount(0, $crawler->filterXPath('.'), '->filterXPath() returns an empty result if the XPath references the fake root node');
+ $this->assertCount(0, $crawler->filterXPath('/_root'), '->filterXPath() returns an empty result if the XPath references the fake root node');
+ $this->assertCount(0, $crawler->filterXPath('self::*'), '->filterXPath() returns an empty result if the XPath references the fake root node');
+ $this->assertCount(0, $crawler->filterXPath('self::_root'), '->filterXPath() returns an empty result if the XPath references the fake root node');
+ }
+
+ public function testFilterXPathWithAncestorAxis()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//form');
+
+ $this->assertCount(0, $crawler->filterXPath('ancestor::*'), 'The fake root node has no ancestor nodes');
+ }
+
+ public function testFilterXPathWithAncestorOrSelfAxis()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//form');
+
+ $this->assertCount(0, $crawler->filterXPath('ancestor-or-self::*'), 'The fake root node has no ancestor nodes');
+ }
+
+ public function testFilterXPathWithAttributeAxis()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//form');
+
+ $this->assertCount(0, $crawler->filterXPath('attribute::*'), 'The fake root node has no attribute nodes');
+ }
+
+ public function testFilterXPathWithAttributeAxisAfterElementAxis()
+ {
+ $this->assertCount(3, $this->createTestCrawler()->filterXPath('//form/button/attribute::*'), '->filterXPath() handles attribute axes properly when they are preceded by an element filtering axis');
+ }
+
+ public function testFilterXPathWithChildAxis()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//div[@id="parent"]');
+
+ $this->assertCount(1, $crawler->filterXPath('child::div'), 'A child selection finds only the current div');
+ }
+
+ public function testFilterXPathWithFollowingAxis()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//a');
+
+ $this->assertCount(0, $crawler->filterXPath('following::div'), 'The fake root node has no following nodes');
+ }
+
+ public function testFilterXPathWithFollowingSiblingAxis()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//a');
+
+ $this->assertCount(0, $crawler->filterXPath('following-sibling::div'), 'The fake root node has no following nodes');
+ }
+
+ public function testFilterXPathWithNamespaceAxis()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//button');
+
+ $this->assertCount(0, $crawler->filterXPath('namespace::*'), 'The fake root node has no namespace nodes');
+ }
+
+ public function testFilterXPathWithNamespaceAxisAfterElementAxis()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//div[@id="parent"]/namespace::*');
+
+ $this->assertCount(0, $crawler->filterXPath('namespace::*'), 'Namespace axes cannot be requested');
+ }
+
+ public function testFilterXPathWithParentAxis()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//button');
+
+ $this->assertCount(0, $crawler->filterXPath('parent::*'), 'The fake root node has no parent nodes');
+ }
+
+ public function testFilterXPathWithPrecedingAxis()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//form');
+
+ $this->assertCount(0, $crawler->filterXPath('preceding::*'), 'The fake root node has no preceding nodes');
+ }
+
+ public function testFilterXPathWithPrecedingSiblingAxis()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//form');
+
+ $this->assertCount(0, $crawler->filterXPath('preceding-sibling::*'), 'The fake root node has no preceding nodes');
+ }
+
+ public function testFilterXPathWithSelfAxes()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//a');
+
+ $this->assertCount(0, $crawler->filterXPath('self::a'), 'The fake root node has no "real" element name');
+ $this->assertCount(0, $crawler->filterXPath('self::a/img'), 'The fake root node has no "real" element name');
+ $this->assertCount(9, $crawler->filterXPath('self::*/a'));
+ }
+
+ /**
+ * @covers Symfony\Component\DomCrawler\Crawler::filter
+ */
+ public function testFilter()
+ {
+ $crawler = $this->createTestCrawler();
+ $this->assertNotSame($crawler, $crawler->filter('li'), '->filter() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->filter() returns a new instance of a crawler');
+
+ $crawler = $this->createTestCrawler()->filter('ul');
+
+ $this->assertCount(6, $crawler->filter('li'), '->filter() filters the node list with the CSS selector');
+ }
+
+ public function testFilterWithDefaultNamespace()
+ {
+ $crawler = $this->createTestXmlCrawler()->filter('default|entry default|id');
+ $this->assertCount(1, $crawler, '->filter() automatically registers namespaces');
+ $this->assertSame('tag:youtube.com,2008:video:kgZRZmEc9j4', $crawler->text());
+ }
+
+ public function testFilterWithNamespace()
+ {
+ CssSelector::disableHtmlExtension();
+
+ $crawler = $this->createTestXmlCrawler()->filter('yt|accessControl');
+ $this->assertCount(2, $crawler, '->filter() automatically registers namespaces');
+ }
+
+ public function testFilterWithMultipleNamespaces()
+ {
+ CssSelector::disableHtmlExtension();
+
+ $crawler = $this->createTestXmlCrawler()->filter('media|group yt|aspectRatio');
+ $this->assertCount(1, $crawler, '->filter() automatically registers namespaces');
+ $this->assertSame('widescreen', $crawler->text());
+ }
+
+ public function testFilterWithDefaultNamespaceOnly()
+ {
+ $crawler = new Crawler('
+
+
+ http://localhost/foo
+ weekly
+ 0.5
+ 2012-11-16
+
+
+ http://localhost/bar
+ weekly
+ 0.5
+ 2012-11-16
+
+
+ ');
+
+ $this->assertEquals(2, $crawler->filter('url')->count());
+ }
+
+ public function testSelectLink()
+ {
+ $crawler = $this->createTestCrawler();
+ $this->assertNotSame($crawler, $crawler->selectLink('Foo'), '->selectLink() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->selectLink() returns a new instance of a crawler');
+
+ $this->assertCount(1, $crawler->selectLink('Fabien\'s Foo'), '->selectLink() selects links by the node values');
+ $this->assertCount(1, $crawler->selectLink('Fabien\'s Bar'), '->selectLink() selects links by the alt attribute of a clickable image');
+
+ $this->assertCount(2, $crawler->selectLink('Fabien"s Foo'), '->selectLink() selects links by the node values');
+ $this->assertCount(2, $crawler->selectLink('Fabien"s Bar'), '->selectLink() selects links by the alt attribute of a clickable image');
+
+ $this->assertCount(1, $crawler->selectLink('\' Fabien"s Foo'), '->selectLink() selects links by the node values');
+ $this->assertCount(1, $crawler->selectLink('\' Fabien"s Bar'), '->selectLink() selects links by the alt attribute of a clickable image');
+
+ $this->assertCount(4, $crawler->selectLink('Foo'), '->selectLink() selects links by the node values');
+ $this->assertCount(4, $crawler->selectLink('Bar'), '->selectLink() selects links by the node values');
+ }
+
+ public function testSelectButton()
+ {
+ $crawler = $this->createTestCrawler();
+ $this->assertNotSame($crawler, $crawler->selectButton('FooValue'), '->selectButton() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->selectButton() returns a new instance of a crawler');
+
+ $this->assertEquals(1, $crawler->selectButton('FooValue')->count(), '->selectButton() selects buttons');
+ $this->assertEquals(1, $crawler->selectButton('FooName')->count(), '->selectButton() selects buttons');
+ $this->assertEquals(1, $crawler->selectButton('FooId')->count(), '->selectButton() selects buttons');
+
+ $this->assertEquals(1, $crawler->selectButton('BarValue')->count(), '->selectButton() selects buttons');
+ $this->assertEquals(1, $crawler->selectButton('BarName')->count(), '->selectButton() selects buttons');
+ $this->assertEquals(1, $crawler->selectButton('BarId')->count(), '->selectButton() selects buttons');
+
+ $this->assertEquals(1, $crawler->selectButton('FooBarValue')->count(), '->selectButton() selects buttons with form attribute too');
+ $this->assertEquals(1, $crawler->selectButton('FooBarName')->count(), '->selectButton() selects buttons with form attribute too');
+ }
+
+ public function testSelectButtonWithSingleQuotesInNameAttribute()
+ {
+ $html = <<
+
+
+
+
+
+
+HTML;
+
+ $crawler = new Crawler($html);
+
+ $this->assertCount(1, $crawler->selectButton('Click \'Here\''));
+ }
+
+ public function testSelectButtonWithDoubleQuotesInNameAttribute()
+ {
+ $html = <<
+
+
+
+
+
+
+HTML;
+
+ $crawler = new Crawler($html);
+
+ $this->assertCount(1, $crawler->selectButton('Click "Here"'));
+ }
+
+ public function testLink()
+ {
+ $crawler = $this->createTestCrawler('http://example.com/bar/')->selectLink('Foo');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Link', $crawler->link(), '->link() returns a Link instance');
+
+ $this->assertEquals('POST', $crawler->link('post')->getMethod(), '->link() takes a method as its argument');
+
+ $crawler = $this->createTestCrawler('http://example.com/bar')->selectLink('GetLink');
+ $this->assertEquals('http://example.com/bar?get=param', $crawler->link()->getUri(), '->link() returns a Link instance');
+
+ try {
+ $this->createTestCrawler()->filterXPath('//ol')->link();
+ $this->fail('->link() throws an \InvalidArgumentException if the node list is empty');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->link() throws an \InvalidArgumentException if the node list is empty');
+ }
+ }
+
+ public function testSelectLinkAndLinkFiltered()
+ {
+ $html = <<
+
+
+
+
+
+
+HTML;
+
+ $crawler = new Crawler($html);
+ $filtered = $crawler->filterXPath("descendant-or-self::*[@id = 'login-form']");
+
+ $this->assertCount(0, $filtered->selectLink('Login'));
+ $this->assertCount(1, $filtered->selectButton('Submit'));
+
+ $filtered = $crawler->filterXPath("descendant-or-self::*[@id = 'action']");
+
+ $this->assertCount(1, $filtered->selectLink('Login'));
+ $this->assertCount(0, $filtered->selectButton('Submit'));
+
+ $this->assertCount(1, $crawler->selectLink('Login')->selectLink('Login'));
+ $this->assertCount(1, $crawler->selectButton('Submit')->selectButton('Submit'));
+ }
+
+ public function testChaining()
+ {
+ $crawler = new Crawler('
');
+
+ $this->assertEquals('a', $crawler->filterXPath('//div')->filterXPath('div')->filterXPath('div')->attr('name'));
+ }
+
+ public function testLinks()
+ {
+ $crawler = $this->createTestCrawler('http://example.com/bar/')->selectLink('Foo');
+ $this->assertInternalType('array', $crawler->links(), '->links() returns an array');
+
+ $this->assertCount(4, $crawler->links(), '->links() returns an array');
+ $links = $crawler->links();
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Link', $links[0], '->links() returns an array of Link instances');
+
+ $this->assertEquals(array(), $this->createTestCrawler()->filterXPath('//ol')->links(), '->links() returns an empty array if the node selection is empty');
+ }
+
+ public function testForm()
+ {
+ $testCrawler = $this->createTestCrawler('http://example.com/bar/');
+ $crawler = $testCrawler->selectButton('FooValue');
+ $crawler2 = $testCrawler->selectButton('FooBarValue');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Form', $crawler->form(), '->form() returns a Form instance');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Form', $crawler2->form(), '->form() returns a Form instance');
+
+ $this->assertEquals($crawler->form()->getFormNode()->getAttribute('id'), $crawler2->form()->getFormNode()->getAttribute('id'), '->form() works on elements with form attribute');
+
+ $this->assertEquals(array('FooName' => 'FooBar', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler->form(array('FooName' => 'FooBar'))->getValues(), '->form() takes an array of values to submit as its first argument');
+ $this->assertEquals(array('FooName' => 'FooValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler->form()->getValues(), '->getValues() returns correct form values');
+ $this->assertEquals(array('FooBarName' => 'FooBarValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler2->form()->getValues(), '->getValues() returns correct form values');
+
+ try {
+ $this->createTestCrawler()->filterXPath('//ol')->form();
+ $this->fail('->form() throws an \InvalidArgumentException if the node list is empty');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->form() throws an \InvalidArgumentException if the node list is empty');
+ }
+ }
+
+ public function testLast()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li');
+ $this->assertNotSame($crawler, $crawler->last(), '->last() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->last() returns a new instance of a crawler');
+
+ $this->assertEquals('Three', $crawler->last()->text());
+ }
+
+ public function testFirst()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//li');
+ $this->assertNotSame($crawler, $crawler->first(), '->first() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->first() returns a new instance of a crawler');
+
+ $this->assertEquals('One', $crawler->first()->text());
+ }
+
+ public function testSiblings()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//li')->eq(1);
+ $this->assertNotSame($crawler, $crawler->siblings(), '->siblings() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->siblings() returns a new instance of a crawler');
+
+ $nodes = $crawler->siblings();
+ $this->assertEquals(2, $nodes->count());
+ $this->assertEquals('One', $nodes->eq(0)->text());
+ $this->assertEquals('Three', $nodes->eq(1)->text());
+
+ $nodes = $this->createTestCrawler()->filterXPath('//li')->eq(0)->siblings();
+ $this->assertEquals(2, $nodes->count());
+ $this->assertEquals('Two', $nodes->eq(0)->text());
+ $this->assertEquals('Three', $nodes->eq(1)->text());
+
+ try {
+ $this->createTestCrawler()->filterXPath('//ol')->siblings();
+ $this->fail('->siblings() throws an \InvalidArgumentException if the node list is empty');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->siblings() throws an \InvalidArgumentException if the node list is empty');
+ }
+ }
+
+ public function testNextAll()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//li')->eq(1);
+ $this->assertNotSame($crawler, $crawler->nextAll(), '->nextAll() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->nextAll() returns a new instance of a crawler');
+
+ $nodes = $crawler->nextAll();
+ $this->assertEquals(1, $nodes->count());
+ $this->assertEquals('Three', $nodes->eq(0)->text());
+
+ try {
+ $this->createTestCrawler()->filterXPath('//ol')->nextAll();
+ $this->fail('->nextAll() throws an \InvalidArgumentException if the node list is empty');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->nextAll() throws an \InvalidArgumentException if the node list is empty');
+ }
+ }
+
+ public function testPreviousAll()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//li')->eq(2);
+ $this->assertNotSame($crawler, $crawler->previousAll(), '->previousAll() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->previousAll() returns a new instance of a crawler');
+
+ $nodes = $crawler->previousAll();
+ $this->assertEquals(2, $nodes->count());
+ $this->assertEquals('Two', $nodes->eq(0)->text());
+
+ try {
+ $this->createTestCrawler()->filterXPath('//ol')->previousAll();
+ $this->fail('->previousAll() throws an \InvalidArgumentException if the node list is empty');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->previousAll() throws an \InvalidArgumentException if the node list is empty');
+ }
+ }
+
+ public function testChildren()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//ul');
+ $this->assertNotSame($crawler, $crawler->children(), '->children() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->children() returns a new instance of a crawler');
+
+ $nodes = $crawler->children();
+ $this->assertEquals(3, $nodes->count());
+ $this->assertEquals('One', $nodes->eq(0)->text());
+ $this->assertEquals('Two', $nodes->eq(1)->text());
+ $this->assertEquals('Three', $nodes->eq(2)->text());
+
+ try {
+ $this->createTestCrawler()->filterXPath('//ol')->children();
+ $this->fail('->children() throws an \InvalidArgumentException if the node list is empty');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->children() throws an \InvalidArgumentException if the node list is empty');
+ }
+
+ try {
+ $crawler = new Crawler('
');
+ $crawler->filter('p')->children();
+ $this->assertTrue(true, '->children() does not trigger a notice if the node has no children');
+ } catch (\PHPUnit_Framework_Error_Notice $e) {
+ $this->fail('->children() does not trigger a notice if the node has no children');
+ }
+ }
+
+ public function testParents()
+ {
+ $crawler = $this->createTestCrawler()->filterXPath('//li[1]');
+ $this->assertNotSame($crawler, $crawler->parents(), '->parents() returns a new instance of a crawler');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->parents() returns a new instance of a crawler');
+
+ $nodes = $crawler->parents();
+ $this->assertEquals(3, $nodes->count());
+
+ $nodes = $this->createTestCrawler()->filterXPath('//html')->parents();
+ $this->assertEquals(0, $nodes->count());
+
+ try {
+ $this->createTestCrawler()->filterXPath('//ol')->parents();
+ $this->fail('->parents() throws an \InvalidArgumentException if the node list is empty');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->parents() throws an \InvalidArgumentException if the node list is empty');
+ }
+ }
+
+ /**
+ * @dataProvider getBaseTagData
+ */
+ public function testBaseTag($baseValue, $linkValue, $expectedUri, $currentUri = null, $description = null)
+ {
+ $crawler = new Crawler('
', $currentUri);
+ $this->assertEquals($expectedUri, $crawler->filterXPath('//a')->link()->getUri(), $description);
+ }
+
+ public function getBaseTagData()
+ {
+ return array(
+ array('http://base.com', 'link', 'http://base.com/link'),
+ array('//base.com', 'link', 'https://base.com/link', 'https://domain.com', '
tag can use a schema-less URL'),
+ array('path/', 'link', 'https://domain.com/path/link', 'https://domain.com', '
tag can set a path'),
+ array('http://base.com', '#', 'http://base.com#', 'http://domain.com/path/link', '
tag does work with links to an anchor'),
+ array('http://base.com', '', 'http://base.com', 'http://domain.com/path/link', '
tag does work with empty links'),
+ );
+ }
+
+ /**
+ * @dataProvider getBaseTagWithFormData
+ */
+ public function testBaseTagWithForm($baseValue, $actionValue, $expectedUri, $currentUri = null, $description = null)
+ {
+ $crawler = new Crawler('
', $currentUri);
+ $this->assertEquals($expectedUri, $crawler->filterXPath('//button')->form()->getUri(), $description);
+ }
+
+ public function getBaseTagWithFormData()
+ {
+ return array(
+ array('/basepath', '/registration', 'http://domain.com/registration', 'http://domain.com/registration', '
tag does work with a path and form action'),
+ array('/basepath', '', 'http://domain.com/registration', 'http://domain.com/registration', '
tag does work with a path and empty form action'),
+ array('http://base.com', '', 'http://domain.com/path/form', 'http://domain.com/path/form', '
tag does work with a URL and an empty form action'),
+ );
+ }
+
+ public function createTestCrawler($uri = null)
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
+
+
+
Foo
+
Fabien\'s Foo
+
Fabien"s Foo
+
\' Fabien"s Foo
+
+
+
+
+
+
+
GetLink
+
+
+
+
+
+
+
+
+ One Bis
+ Two Bis
+ Three Bis
+
+
+
+
+
+ ');
+
+ return new Crawler($dom, $uri);
+ }
+
+ protected function createTestXmlCrawler($uri = null)
+ {
+ $xml = '
+
+ tag:youtube.com,2008:video:kgZRZmEc9j4
+
+
+
+ Chordates - CrashCourse Biology #24
+ widescreen
+
+ Music
+ ';
+
+ return new Crawler($xml, $uri);
+ }
+
+ protected function createDomDocument()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadXML('
');
+
+ return $dom;
+ }
+
+ protected function createNodeList()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadXML('
');
+ $domxpath = new \DOMXPath($dom);
+
+ return $domxpath->query('//div');
+ }
+}
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php
new file mode 100644
index 0000000..9b31945
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php
@@ -0,0 +1,388 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DomCrawler\Tests\Field;
+
+use Symfony\Component\DomCrawler\Field\ChoiceFormField;
+
+class ChoiceFormFieldTest extends FormFieldTestCase
+{
+ public function testInitialize()
+ {
+ $node = $this->createNode('textarea', '');
+ try {
+ $field = new ChoiceFormField($node);
+ $this->fail('->initialize() throws a \LogicException if the node is not an input or a select');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input or a select');
+ }
+
+ $node = $this->createNode('input', '', array('type' => 'text'));
+ try {
+ $field = new ChoiceFormField($node);
+ $this->fail('->initialize() throws a \LogicException if the node is an input with a type different from checkbox or radio');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '->initialize() throws a \LogicException if the node is an input with a type different from checkbox or radio');
+ }
+ }
+
+ public function testGetType()
+ {
+ $node = $this->createNode('input', '', array('type' => 'radio', 'name' => 'name', 'value' => 'foo'));
+ $field = new ChoiceFormField($node);
+
+ $this->assertEquals('radio', $field->getType(), '->getType() returns radio for radio buttons');
+
+ $node = $this->createNode('input', '', array('type' => 'checkbox', 'name' => 'name', 'value' => 'foo'));
+ $field = new ChoiceFormField($node);
+
+ $this->assertEquals('checkbox', $field->getType(), '->getType() returns radio for a checkbox');
+
+ $node = $this->createNode('select', '');
+ $field = new ChoiceFormField($node);
+
+ $this->assertEquals('select', $field->getType(), '->getType() returns radio for a select');
+ }
+
+ public function testIsMultiple()
+ {
+ $node = $this->createNode('input', '', array('type' => 'radio', 'name' => 'name', 'value' => 'foo'));
+ $field = new ChoiceFormField($node);
+
+ $this->assertFalse($field->isMultiple(), '->isMultiple() returns false for radio buttons');
+
+ $node = $this->createNode('input', '', array('type' => 'checkbox', 'name' => 'name', 'value' => 'foo'));
+ $field = new ChoiceFormField($node);
+
+ $this->assertFalse($field->isMultiple(), '->isMultiple() returns false for checkboxes');
+
+ $node = $this->createNode('select', '');
+ $field = new ChoiceFormField($node);
+
+ $this->assertFalse($field->isMultiple(), '->isMultiple() returns false for selects without the multiple attribute');
+
+ $node = $this->createNode('select', '', array('multiple' => 'multiple'));
+ $field = new ChoiceFormField($node);
+
+ $this->assertTrue($field->isMultiple(), '->isMultiple() returns true for selects with the multiple attribute');
+
+ $node = $this->createNode('select', '', array('multiple' => ''));
+ $field = new ChoiceFormField($node);
+
+ $this->assertTrue($field->isMultiple(), '->isMultiple() returns true for selects with an empty multiple attribute');
+ }
+
+ public function testSelects()
+ {
+ $node = $this->createSelectNode(array('foo' => false, 'bar' => false));
+ $field = new ChoiceFormField($node);
+
+ $this->assertTrue($field->hasValue(), '->hasValue() returns true for selects');
+ $this->assertEquals('foo', $field->getValue(), '->getValue() returns the first option if none are selected');
+ $this->assertFalse($field->isMultiple(), '->isMultiple() returns false when no multiple attribute is defined');
+
+ $node = $this->createSelectNode(array('foo' => false, 'bar' => true));
+ $field = new ChoiceFormField($node);
+
+ $this->assertEquals('bar', $field->getValue(), '->getValue() returns the selected option');
+
+ $field->setValue('foo');
+ $this->assertEquals('foo', $field->getValue(), '->setValue() changes the selected option');
+
+ try {
+ $field->setValue('foobar');
+ $this->fail('->setValue() throws an \InvalidArgumentException if the value is not one of the selected options');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->setValue() throws an \InvalidArgumentException if the value is not one of the selected options');
+ }
+
+ try {
+ $field->setValue(array('foobar'));
+ $this->fail('->setValue() throws an \InvalidArgumentException if the value is an array');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->setValue() throws an \InvalidArgumentException if the value is an array');
+ }
+ }
+
+ public function testSelectWithEmptyBooleanAttribute()
+ {
+ $node = $this->createSelectNode(array('foo' => false, 'bar' => true), array(), '');
+ $field = new ChoiceFormField($node);
+
+ $this->assertEquals('bar', $field->getValue());
+ }
+
+ public function testMultipleSelects()
+ {
+ $node = $this->createSelectNode(array('foo' => false, 'bar' => false), array('multiple' => 'multiple'));
+ $field = new ChoiceFormField($node);
+
+ $this->assertEquals(array(), $field->getValue(), '->setValue() returns an empty array if multiple is true and no option is selected');
+
+ $field->setValue('foo');
+ $this->assertEquals(array('foo'), $field->getValue(), '->setValue() returns an array of options if multiple is true');
+
+ $field->setValue('bar');
+ $this->assertEquals(array('bar'), $field->getValue(), '->setValue() returns an array of options if multiple is true');
+
+ $field->setValue(array('foo', 'bar'));
+ $this->assertEquals(array('foo', 'bar'), $field->getValue(), '->setValue() returns an array of options if multiple is true');
+
+ $node = $this->createSelectNode(array('foo' => true, 'bar' => true), array('multiple' => 'multiple'));
+ $field = new ChoiceFormField($node);
+
+ $this->assertEquals(array('foo', 'bar'), $field->getValue(), '->getValue() returns the selected options');
+
+ try {
+ $field->setValue(array('foobar'));
+ $this->fail('->setValue() throws an \InvalidArgumentException if the value is not one of the options');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->setValue() throws an \InvalidArgumentException if the value is not one of the options');
+ }
+ }
+
+ public function testRadioButtons()
+ {
+ $node = $this->createNode('input', '', array('type' => 'radio', 'name' => 'name', 'value' => 'foo'));
+ $field = new ChoiceFormField($node);
+ $node = $this->createNode('input', '', array('type' => 'radio', 'name' => 'name', 'value' => 'bar'));
+ $field->addChoice($node);
+
+ $this->assertFalse($field->hasValue(), '->hasValue() returns false when no radio button is selected');
+ $this->assertNull($field->getValue(), '->getValue() returns null if no radio button is selected');
+ $this->assertFalse($field->isMultiple(), '->isMultiple() returns false for radio buttons');
+
+ $node = $this->createNode('input', '', array('type' => 'radio', 'name' => 'name', 'value' => 'foo'));
+ $field = new ChoiceFormField($node);
+ $node = $this->createNode('input', '', array('type' => 'radio', 'name' => 'name', 'value' => 'bar', 'checked' => 'checked'));
+ $field->addChoice($node);
+
+ $this->assertTrue($field->hasValue(), '->hasValue() returns true when a radio button is selected');
+ $this->assertEquals('bar', $field->getValue(), '->getValue() returns the value attribute of the selected radio button');
+
+ $field->setValue('foo');
+ $this->assertEquals('foo', $field->getValue(), '->setValue() changes the selected radio button');
+
+ try {
+ $field->setValue('foobar');
+ $this->fail('->setValue() throws an \InvalidArgumentException if the value is not one of the radio button values');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->setValue() throws an \InvalidArgumentException if the value is not one of the radio button values');
+ }
+ }
+
+ public function testRadioButtonsWithEmptyBooleanAttribute()
+ {
+ $node = $this->createNode('input', '', array('type' => 'radio', 'name' => 'name', 'value' => 'foo'));
+ $field = new ChoiceFormField($node);
+ $node = $this->createNode('input', '', array('type' => 'radio', 'name' => 'name', 'value' => 'bar', 'checked' => ''));
+ $field->addChoice($node);
+
+ $this->assertTrue($field->hasValue(), '->hasValue() returns true when a radio button is selected');
+ $this->assertEquals('bar', $field->getValue(), '->getValue() returns the value attribute of the selected radio button');
+ }
+
+ public function testRadioButtonIsDisabled()
+ {
+ $node = $this->createNode('input', '', array('type' => 'radio', 'name' => 'name', 'value' => 'foo', 'disabled' => 'disabled'));
+ $field = new ChoiceFormField($node);
+ $node = $this->createNode('input', '', array('type' => 'radio', 'name' => 'name', 'value' => 'bar'));
+ $field->addChoice($node);
+ $node = $this->createNode('input', '', array('type' => 'radio', 'name' => 'name', 'value' => 'baz', 'disabled' => ''));
+ $field->addChoice($node);
+
+ $field->select('foo');
+ $this->assertEquals('foo', $field->getValue(), '->getValue() returns the value attribute of the selected radio button');
+ $this->assertTrue($field->isDisabled());
+
+ $field->select('bar');
+ $this->assertEquals('bar', $field->getValue(), '->getValue() returns the value attribute of the selected radio button');
+ $this->assertFalse($field->isDisabled());
+
+ $field->select('baz');
+ $this->assertEquals('baz', $field->getValue(), '->getValue() returns the value attribute of the selected radio button');
+ $this->assertTrue($field->isDisabled());
+ }
+
+ public function testCheckboxes()
+ {
+ $node = $this->createNode('input', '', array('type' => 'checkbox', 'name' => 'name'));
+ $field = new ChoiceFormField($node);
+
+ $this->assertFalse($field->hasValue(), '->hasValue() returns false when the checkbox is not checked');
+ $this->assertNull($field->getValue(), '->getValue() returns null if the checkbox is not checked');
+ $this->assertFalse($field->isMultiple(), '->hasValue() returns false for checkboxes');
+ try {
+ $field->addChoice(new \DOMElement('input'));
+ $this->fail('->addChoice() throws a \LogicException for checkboxes');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '->initialize() throws a \LogicException for checkboxes');
+ }
+
+ $node = $this->createNode('input', '', array('type' => 'checkbox', 'name' => 'name', 'checked' => 'checked'));
+ $field = new ChoiceFormField($node);
+
+ $this->assertTrue($field->hasValue(), '->hasValue() returns true when the checkbox is checked');
+ $this->assertEquals('on', $field->getValue(), '->getValue() returns 1 if the checkbox is checked and has no value attribute');
+
+ $node = $this->createNode('input', '', array('type' => 'checkbox', 'name' => 'name', 'checked' => 'checked', 'value' => 'foo'));
+ $field = new ChoiceFormField($node);
+
+ $this->assertEquals('foo', $field->getValue(), '->getValue() returns the value attribute if the checkbox is checked');
+
+ $node = $this->createNode('input', '', array('type' => 'checkbox', 'name' => 'name', 'checked' => 'checked', 'value' => 'foo'));
+ $field = new ChoiceFormField($node);
+
+ $field->setValue(false);
+ $this->assertNull($field->getValue(), '->setValue() unchecks the checkbox is value is false');
+
+ $field->setValue(true);
+ $this->assertEquals('foo', $field->getValue(), '->setValue() checks the checkbox is value is true');
+
+ try {
+ $field->setValue('bar');
+ $this->fail('->setValue() throws an \InvalidArgumentException if the value is not one from the value attribute');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->setValue() throws an \InvalidArgumentException if the value is not one from the value attribute');
+ }
+ }
+
+ public function testCheckboxWithEmptyBooleanAttribute()
+ {
+ $node = $this->createNode('input', '', array('type' => 'checkbox', 'name' => 'name', 'value' => 'foo', 'checked' => ''));
+ $field = new ChoiceFormField($node);
+
+ $this->assertTrue($field->hasValue(), '->hasValue() returns true when the checkbox is checked');
+ $this->assertEquals('foo', $field->getValue());
+ }
+
+ public function testTick()
+ {
+ $node = $this->createSelectNode(array('foo' => false, 'bar' => false));
+ $field = new ChoiceFormField($node);
+
+ try {
+ $field->tick();
+ $this->fail('->tick() throws a \LogicException for select boxes');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '->tick() throws a \LogicException for select boxes');
+ }
+
+ $node = $this->createNode('input', '', array('type' => 'checkbox', 'name' => 'name'));
+ $field = new ChoiceFormField($node);
+ $field->tick();
+ $this->assertEquals('on', $field->getValue(), '->tick() ticks checkboxes');
+ }
+
+ public function testUntick()
+ {
+ $node = $this->createSelectNode(array('foo' => false, 'bar' => false));
+ $field = new ChoiceFormField($node);
+
+ try {
+ $field->untick();
+ $this->fail('->untick() throws a \LogicException for select boxes');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '->untick() throws a \LogicException for select boxes');
+ }
+
+ $node = $this->createNode('input', '', array('type' => 'checkbox', 'name' => 'name', 'checked' => 'checked'));
+ $field = new ChoiceFormField($node);
+ $field->untick();
+ $this->assertNull($field->getValue(), '->untick() unticks checkboxes');
+ }
+
+ public function testSelect()
+ {
+ $node = $this->createNode('input', '', array('type' => 'checkbox', 'name' => 'name', 'checked' => 'checked'));
+ $field = new ChoiceFormField($node);
+ $field->select(true);
+ $this->assertEquals('on', $field->getValue(), '->select() changes the value of the field');
+ $field->select(false);
+ $this->assertNull($field->getValue(), '->select() changes the value of the field');
+
+ $node = $this->createSelectNode(array('foo' => false, 'bar' => false));
+ $field = new ChoiceFormField($node);
+ $field->select('foo');
+ $this->assertEquals('foo', $field->getValue(), '->select() changes the selected option');
+ }
+
+ public function testOptionWithNoValue()
+ {
+ $node = $this->createSelectNodeWithEmptyOption(array('foo' => false, 'bar' => false));
+ $field = new ChoiceFormField($node);
+ $this->assertEquals('foo', $field->getValue());
+
+ $node = $this->createSelectNodeWithEmptyOption(array('foo' => false, 'bar' => true));
+ $field = new ChoiceFormField($node);
+ $this->assertEquals('bar', $field->getValue());
+ $field->select('foo');
+ $this->assertEquals('foo', $field->getValue(), '->select() changes the selected option');
+ }
+
+ public function testDisableValidation()
+ {
+ $node = $this->createSelectNode(array('foo' => false, 'bar' => false));
+ $field = new ChoiceFormField($node);
+ $field->disableValidation();
+ $field->setValue('foobar');
+ $this->assertEquals('foobar', $field->getValue(), '->disableValidation() allows to set a value which is not in the selected options.');
+
+ $node = $this->createSelectNode(array('foo' => false, 'bar' => false), array('multiple' => 'multiple'));
+ $field = new ChoiceFormField($node);
+ $field->disableValidation();
+ $field->setValue(array('foobar'));
+ $this->assertEquals(array('foobar'), $field->getValue(), '->disableValidation() allows to set a value which is not in the selected options.');
+ }
+
+ protected function createSelectNode($options, $attributes = array(), $selectedAttrText = 'selected')
+ {
+ $document = new \DOMDocument();
+ $node = $document->createElement('select');
+
+ foreach ($attributes as $name => $value) {
+ $node->setAttribute($name, $value);
+ }
+ $node->setAttribute('name', 'name');
+
+ foreach ($options as $value => $selected) {
+ $option = $document->createElement('option', $value);
+ $option->setAttribute('value', $value);
+ if ($selected) {
+ $option->setAttribute('selected', $selectedAttrText);
+ }
+ $node->appendChild($option);
+ }
+
+ return $node;
+ }
+
+ protected function createSelectNodeWithEmptyOption($options, $attributes = array())
+ {
+ $document = new \DOMDocument();
+ $node = $document->createElement('select');
+
+ foreach ($attributes as $name => $value) {
+ $node->setAttribute($name, $value);
+ }
+ $node->setAttribute('name', 'name');
+
+ foreach ($options as $value => $selected) {
+ $option = $document->createElement('option', $value);
+ if ($selected) {
+ $option->setAttribute('selected', 'selected');
+ }
+ $node->appendChild($option);
+ }
+
+ return $node;
+ }
+}
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/FileFormFieldTest.php b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/FileFormFieldTest.php
new file mode 100644
index 0000000..3ce49a4
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/FileFormFieldTest.php
@@ -0,0 +1,114 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DomCrawler\Tests\Field;
+
+use Symfony\Component\DomCrawler\Field\FileFormField;
+
+class FileFormFieldTest extends FormFieldTestCase
+{
+ public function testInitialize()
+ {
+ $node = $this->createNode('input', '', array('type' => 'file'));
+ $field = new FileFormField($node);
+
+ $this->assertEquals(array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => UPLOAD_ERR_NO_FILE, 'size' => 0), $field->getValue(), '->initialize() sets the value of the field to no file uploaded');
+
+ $node = $this->createNode('textarea', '');
+ try {
+ $field = new FileFormField($node);
+ $this->fail('->initialize() throws a \LogicException if the node is not an input field');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input field');
+ }
+
+ $node = $this->createNode('input', '', array('type' => 'text'));
+ try {
+ $field = new FileFormField($node);
+ $this->fail('->initialize() throws a \LogicException if the node is not a file input field');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '->initialize() throws a \LogicException if the node is not a file input field');
+ }
+ }
+
+ /**
+ * @dataProvider getSetValueMethods
+ */
+ public function testSetValue($method)
+ {
+ $node = $this->createNode('input', '', array('type' => 'file'));
+ $field = new FileFormField($node);
+
+ $field->$method(null);
+ $this->assertEquals(array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => UPLOAD_ERR_NO_FILE, 'size' => 0), $field->getValue(), "->$method() clears the uploaded file if the value is null");
+
+ $field->$method(__FILE__);
+ $value = $field->getValue();
+
+ $this->assertEquals(basename(__FILE__), $value['name'], "->$method() sets the name of the file field");
+ $this->assertEquals('', $value['type'], "->$method() sets the type of the file field");
+ $this->assertInternalType('string', $value['tmp_name'], "->$method() sets the tmp_name of the file field");
+ $this->assertFileExists($value['tmp_name'], "->$method() creates a copy of the file at the tmp_name path");
+ $this->assertEquals(0, $value['error'], "->$method() sets the error of the file field");
+ $this->assertEquals(filesize(__FILE__), $value['size'], "->$method() sets the size of the file field");
+
+ $origInfo = pathinfo(__FILE__);
+ $tmpInfo = pathinfo($value['tmp_name']);
+ $this->assertEquals(
+ $origInfo['extension'],
+ $tmpInfo['extension'],
+ "->$method() keeps the same file extension in the tmp_name copy"
+ );
+
+ $field->$method(__DIR__.'/../Fixtures/no-extension');
+ $value = $field->getValue();
+
+ $this->assertArrayNotHasKey(
+ 'extension',
+ pathinfo($value['tmp_name']),
+ "->$method() does not add a file extension in the tmp_name copy"
+ );
+ }
+
+ public function getSetValueMethods()
+ {
+ return array(
+ array('setValue'),
+ array('upload'),
+ );
+ }
+
+ public function testSetErrorCode()
+ {
+ $node = $this->createNode('input', '', array('type' => 'file'));
+ $field = new FileFormField($node);
+
+ $field->setErrorCode(UPLOAD_ERR_FORM_SIZE);
+ $value = $field->getValue();
+ $this->assertEquals(UPLOAD_ERR_FORM_SIZE, $value['error'], '->setErrorCode() sets the file input field error code');
+
+ try {
+ $field->setErrorCode('foobar');
+ $this->fail('->setErrorCode() throws a \InvalidArgumentException if the error code is not valid');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->setErrorCode() throws a \InvalidArgumentException if the error code is not valid');
+ }
+ }
+
+ public function testSetRawFilePath()
+ {
+ $node = $this->createNode('input', '', array('type' => 'file'));
+ $field = new FileFormField($node);
+ $field->setFilePath(__FILE__);
+
+ $this->assertEquals(__FILE__, $field->getValue());
+ }
+}
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/FormFieldTest.php b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/FormFieldTest.php
new file mode 100644
index 0000000..510f762
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/FormFieldTest.php
@@ -0,0 +1,38 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DomCrawler\Tests\Field;
+
+use Symfony\Component\DomCrawler\Field\InputFormField;
+
+class FormFieldTest extends FormFieldTestCase
+{
+ public function testGetName()
+ {
+ $node = $this->createNode('input', '', array('type' => 'text', 'name' => 'name', 'value' => 'value'));
+ $field = new InputFormField($node);
+
+ $this->assertEquals('name', $field->getName(), '->getName() returns the name of the field');
+ }
+
+ public function testGetSetHasValue()
+ {
+ $node = $this->createNode('input', '', array('type' => 'text', 'name' => 'name', 'value' => 'value'));
+ $field = new InputFormField($node);
+
+ $this->assertEquals('value', $field->getValue(), '->getValue() returns the value of the field');
+
+ $field->setValue('foo');
+ $this->assertEquals('foo', $field->getValue(), '->setValue() sets the value of the field');
+
+ $this->assertTrue($field->hasValue(), '->hasValue() always returns true');
+ }
+}
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/FormFieldTestCase.php b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/FormFieldTestCase.php
new file mode 100644
index 0000000..26b1b0e
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/FormFieldTestCase.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DomCrawler\Tests\Field;
+
+class FormFieldTestCase extends \PHPUnit_Framework_TestCase
+{
+ protected function createNode($tag, $value, $attributes = array())
+ {
+ $document = new \DOMDocument();
+ $node = $document->createElement($tag, $value);
+
+ foreach ($attributes as $name => $value) {
+ $node->setAttribute($name, $value);
+ }
+
+ return $node;
+ }
+}
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/InputFormFieldTest.php b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/InputFormFieldTest.php
new file mode 100644
index 0000000..193d301
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/InputFormFieldTest.php
@@ -0,0 +1,49 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DomCrawler\Tests\Field;
+
+use Symfony\Component\DomCrawler\Field\InputFormField;
+
+class InputFormFieldTest extends FormFieldTestCase
+{
+ public function testInitialize()
+ {
+ $node = $this->createNode('input', '', array('type' => 'text', 'name' => 'name', 'value' => 'value'));
+ $field = new InputFormField($node);
+
+ $this->assertEquals('value', $field->getValue(), '->initialize() sets the value of the field to the value attribute value');
+
+ $node = $this->createNode('textarea', '');
+ try {
+ $field = new InputFormField($node);
+ $this->fail('->initialize() throws a \LogicException if the node is not an input');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input');
+ }
+
+ $node = $this->createNode('input', '', array('type' => 'checkbox'));
+ try {
+ $field = new InputFormField($node);
+ $this->fail('->initialize() throws a \LogicException if the node is a checkbox');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '->initialize() throws a \LogicException if the node is a checkbox');
+ }
+
+ $node = $this->createNode('input', '', array('type' => 'file'));
+ try {
+ $field = new InputFormField($node);
+ $this->fail('->initialize() throws a \LogicException if the node is a file');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '->initialize() throws a \LogicException if the node is a file');
+ }
+ }
+}
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/TextareaFormFieldTest.php b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/TextareaFormFieldTest.php
new file mode 100644
index 0000000..5d4d003
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Field/TextareaFormFieldTest.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DomCrawler\Tests\Field;
+
+use Symfony\Component\DomCrawler\Field\TextareaFormField;
+
+class TextareaFormFieldTest extends FormFieldTestCase
+{
+ public function testInitialize()
+ {
+ $node = $this->createNode('textarea', 'foo bar');
+ $field = new TextareaFormField($node);
+
+ $this->assertEquals('foo bar', $field->getValue(), '->initialize() sets the value of the field to the textarea node value');
+
+ $node = $this->createNode('input', '');
+ try {
+ $field = new TextareaFormField($node);
+ $this->fail('->initialize() throws a \LogicException if the node is not a textarea');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '->initialize() throws a \LogicException if the node is not a textarea');
+ }
+
+ // Ensure that valid HTML can be used on a textarea.
+ $node = $this->createNode('textarea', 'foo bar
Baz ');
+ $field = new TextareaFormField($node);
+
+ $this->assertEquals('foo bar
Baz ', $field->getValue(), '->initialize() sets the value of the field to the textarea node value');
+
+ // Ensure that we don't do any DOM manipulation/validation by passing in
+ // "invalid" HTML.
+ $node = $this->createNode('textarea', 'foo bar
Baz');
+ $field = new TextareaFormField($node);
+
+ $this->assertEquals('foo bar Baz', $field->getValue(), '->initialize() sets the value of the field to the textarea node value');
+ }
+}
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Fixtures/no-extension b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Fixtures/no-extension
new file mode 100644
index 0000000..345e6ae
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Fixtures/no-extension
@@ -0,0 +1 @@
+Test
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Fixtures/windows-1250.html b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Fixtures/windows-1250.html
new file mode 100644
index 0000000..c26dc77
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/Fixtures/windows-1250.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+ Žèýù
+
+
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/FormTest.php b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/FormTest.php
new file mode 100644
index 0000000..5fd2b18
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/FormTest.php
@@ -0,0 +1,943 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DomCrawler\Tests;
+
+use Symfony\Component\DomCrawler\Form;
+use Symfony\Component\DomCrawler\FormFieldRegistry;
+use Symfony\Component\DomCrawler\Field;
+
+class FormTest extends \PHPUnit_Framework_TestCase
+{
+ public static function setUpBeforeClass()
+ {
+ // Ensure that the private helper class FormFieldRegistry is loaded
+ class_exists('Symfony\\Component\\DomCrawler\\Form');
+ }
+
+ public function testConstructorThrowsExceptionIfTheNodeHasNoFormAncestor()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
+
+
+
+
+
+ ');
+
+ $nodes = $dom->getElementsByTagName('input');
+
+ try {
+ $form = new Form($nodes->item(0), 'http://example.com');
+ $this->fail('__construct() throws a \\LogicException if the node has no form ancestor');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '__construct() throws a \\LogicException if the node has no form ancestor');
+ }
+
+ try {
+ $form = new Form($nodes->item(1), 'http://example.com');
+ $this->fail('__construct() throws a \\LogicException if the input type is not submit, button, or image');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '__construct() throws a \\LogicException if the input type is not submit, button, or image');
+ }
+
+ $nodes = $dom->getElementsByTagName('button');
+
+ try {
+ $form = new Form($nodes->item(0), 'http://example.com');
+ $this->fail('__construct() throws a \\LogicException if the node has no form ancestor');
+ } catch (\LogicException $e) {
+ $this->assertTrue(true, '__construct() throws a \\LogicException if the node has no form ancestor');
+ }
+ }
+
+ /**
+ * __construct() should throw \\LogicException if the form attribute is invalid.
+ *
+ * @expectedException \LogicException
+ */
+ public function testConstructorThrowsExceptionIfNoRelatedForm()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
+
+
+
+
+
+ ');
+
+ $nodes = $dom->getElementsByTagName('input');
+
+ $form = new Form($nodes->item(0), 'http://example.com');
+ $form = new Form($nodes->item(1), 'http://example.com');
+ }
+
+ public function testConstructorLoadsOnlyFieldsOfTheRightForm()
+ {
+ $dom = $this->createTestMultipleForm();
+
+ $nodes = $dom->getElementsByTagName('form');
+ $buttonElements = $dom->getElementsByTagName('button');
+
+ $form = new Form($nodes->item(0), 'http://example.com');
+ $this->assertCount(3, $form->all());
+
+ $form = new Form($buttonElements->item(1), 'http://example.com');
+ $this->assertCount(5, $form->all());
+ }
+
+ public function testConstructorHandlesFormAttribute()
+ {
+ $dom = $this->createTestHtml5Form();
+
+ $inputElements = $dom->getElementsByTagName('input');
+ $buttonElements = $dom->getElementsByTagName('button');
+
+ // Tests if submit buttons are correctly assigned to forms
+ $form1 = new Form($buttonElements->item(1), 'http://example.com');
+ $this->assertSame($dom->getElementsByTagName('form')->item(0), $form1->getFormNode(), 'HTML5-compliant form attribute handled incorrectly');
+
+ $form1 = new Form($inputElements->item(3), 'http://example.com');
+ $this->assertSame($dom->getElementsByTagName('form')->item(0), $form1->getFormNode(), 'HTML5-compliant form attribute handled incorrectly');
+
+ $form2 = new Form($buttonElements->item(0), 'http://example.com');
+ $this->assertSame($dom->getElementsByTagName('form')->item(1), $form2->getFormNode(), 'HTML5-compliant form attribute handled incorrectly');
+ }
+
+ public function testConstructorHandlesFormValues()
+ {
+ $dom = $this->createTestHtml5Form();
+
+ $inputElements = $dom->getElementsByTagName('input');
+ $buttonElements = $dom->getElementsByTagName('button');
+
+ $form1 = new Form($inputElements->item(3), 'http://example.com');
+ $form2 = new Form($buttonElements->item(0), 'http://example.com');
+
+ // Tests if form values are correctly assigned to forms
+ $values1 = array(
+ 'apples' => array('1', '2'),
+ 'form_name' => 'form-1',
+ 'button_1' => 'Capture fields',
+ 'outer_field' => 'success',
+ );
+ $values2 = array(
+ 'oranges' => array('1', '2', '3'),
+ 'form_name' => 'form_2',
+ 'button_2' => '',
+ 'app_frontend_form_type_contact_form_type' => array('contactType' => '', 'firstName' => 'John'),
+ );
+
+ $this->assertEquals($values1, $form1->getPhpValues(), 'HTML5-compliant form attribute handled incorrectly');
+ $this->assertEquals($values2, $form2->getPhpValues(), 'HTML5-compliant form attribute handled incorrectly');
+ }
+
+ public function testMultiValuedFields()
+ {
+ $form = $this->createForm('
+ ');
+
+ $this->assertEquals(
+ array_keys($form->all()),
+ array('foo[2]', 'foo[3]', 'bar[foo][0]', 'bar[foo][foobar]')
+ );
+
+ $this->assertEquals($form->get('foo[2]')->getValue(), 'foo');
+ $this->assertEquals($form->get('foo[3]')->getValue(), 'foo');
+ $this->assertEquals($form->get('bar[foo][0]')->getValue(), 'foo');
+ $this->assertEquals($form->get('bar[foo][foobar]')->getValue(), 'foo');
+
+ $form['foo[2]'] = 'bar';
+ $form['foo[3]'] = 'bar';
+
+ $this->assertEquals($form->get('foo[2]')->getValue(), 'bar');
+ $this->assertEquals($form->get('foo[3]')->getValue(), 'bar');
+
+ $form['bar'] = array('foo' => array('0' => 'bar', 'foobar' => 'foobar'));
+
+ $this->assertEquals($form->get('bar[foo][0]')->getValue(), 'bar');
+ $this->assertEquals($form->get('bar[foo][foobar]')->getValue(), 'foobar');
+ }
+
+ /**
+ * @dataProvider provideInitializeValues
+ */
+ public function testConstructor($message, $form, $values)
+ {
+ $form = $this->createForm('
');
+ $this->assertEquals(
+ $values,
+ array_map(function ($field) {
+ $class = get_class($field);
+
+ return array(substr($class, strrpos($class, '\\') + 1), $field->getValue());
+ },
+ $form->all()
+ ),
+ '->getDefaultValues() '.$message
+ );
+ }
+
+ public function provideInitializeValues()
+ {
+ return array(
+ array(
+ 'does not take into account input fields without a name attribute',
+ '
+
',
+ array(),
+ ),
+ array(
+ 'does not take into account input fields with an empty name attribute value',
+ '
+
',
+ array(),
+ ),
+ array(
+ 'takes into account disabled input fields',
+ '
+
',
+ array('foo' => array('InputFormField', 'foo')),
+ ),
+ array(
+ 'appends the submitted button value',
+ '
',
+ array('bar' => array('InputFormField', 'bar')),
+ ),
+ array(
+ 'appends the submitted button value for Button element',
+ '
Bar ',
+ array('bar' => array('InputFormField', 'bar')),
+ ),
+ array(
+ 'appends the submitted button value but not other submit buttons',
+ '
+
',
+ array('foobar' => array('InputFormField', 'foobar')),
+ ),
+ array(
+ 'turns an image input into x and y fields',
+ '
',
+ array('bar.x' => array('InputFormField', '0'), 'bar.y' => array('InputFormField', '0')),
+ ),
+ array(
+ 'returns textareas',
+ '
+
',
+ array('foo' => array('TextareaFormField', 'foo')),
+ ),
+ array(
+ 'returns inputs',
+ '
+
',
+ array('foo' => array('InputFormField', 'foo')),
+ ),
+ array(
+ 'returns checkboxes',
+ '
+
',
+ array('foo' => array('ChoiceFormField', 'foo')),
+ ),
+ array(
+ 'returns not-checked checkboxes',
+ '
+
',
+ array('foo' => array('ChoiceFormField', false)),
+ ),
+ array(
+ 'returns radio buttons',
+ '
+
+
',
+ array('foo' => array('ChoiceFormField', 'bar')),
+ ),
+ array(
+ 'returns file inputs',
+ '
+
',
+ array('foo' => array('FileFormField', array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => 4, 'size' => 0))),
+ ),
+ );
+ }
+
+ public function testGetFormNode()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
');
+
+ $form = new Form($dom->getElementsByTagName('input')->item(0), 'http://example.com');
+
+ $this->assertSame($dom->getElementsByTagName('form')->item(0), $form->getFormNode(), '->getFormNode() returns the form node associated with this form');
+ }
+
+ public function testGetFormNodeFromNamedForm()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
');
+
+ $form = new Form($dom->getElementsByTagName('form')->item(0), 'http://example.com');
+
+ $this->assertSame($dom->getElementsByTagName('form')->item(0), $form->getFormNode(), '->getFormNode() returns the form node associated with this form');
+ }
+
+ public function testGetMethod()
+ {
+ $form = $this->createForm('
');
+ $this->assertEquals('GET', $form->getMethod(), '->getMethod() returns get if no method is defined');
+
+ $form = $this->createForm('
');
+ $this->assertEquals('POST', $form->getMethod(), '->getMethod() returns the method attribute value of the form');
+
+ $form = $this->createForm('
', 'put');
+ $this->assertEquals('PUT', $form->getMethod(), '->getMethod() returns the method defined in the constructor if provided');
+
+ $form = $this->createForm('
', 'delete');
+ $this->assertEquals('DELETE', $form->getMethod(), '->getMethod() returns the method defined in the constructor if provided');
+
+ $form = $this->createForm('
', 'patch');
+ $this->assertEquals('PATCH', $form->getMethod(), '->getMethod() returns the method defined in the constructor if provided');
+ }
+
+ public function testGetSetValue()
+ {
+ $form = $this->createForm('
');
+
+ $this->assertEquals('foo', $form['foo']->getValue(), '->offsetGet() returns the value of a form field');
+
+ $form['foo'] = 'bar';
+
+ $this->assertEquals('bar', $form['foo']->getValue(), '->offsetSet() changes the value of a form field');
+
+ try {
+ $form['foobar'] = 'bar';
+ $this->fail('->offsetSet() throws an \InvalidArgumentException exception if the field does not exist');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->offsetSet() throws an \InvalidArgumentException exception if the field does not exist');
+ }
+
+ try {
+ $form['foobar'];
+ $this->fail('->offsetSet() throws an \InvalidArgumentException exception if the field does not exist');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->offsetSet() throws an \InvalidArgumentException exception if the field does not exist');
+ }
+ }
+
+ public function testSetValueOnMultiValuedFieldsWithMalformedName()
+ {
+ $form = $this->createForm('
');
+
+ try {
+ $form['foo[bar'] = 'bar';
+ $this->fail('->offsetSet() throws an \InvalidArgumentException exception if the name is malformed.');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->offsetSet() throws an \InvalidArgumentException exception if the name is malformed.');
+ }
+ }
+
+ public function testDisableValidation()
+ {
+ $form = $this->createForm('
');
+
+ $form->disableValidation();
+
+ $form['foo[bar]']->select('foo');
+ $form['foo[baz]']->select('bar');
+ $this->assertEquals('foo', $form['foo[bar]']->getValue(), '->disableValidation() disables validation of all ChoiceFormField.');
+ $this->assertEquals('bar', $form['foo[baz]']->getValue(), '->disableValidation() disables validation of all ChoiceFormField.');
+ }
+
+ public function testOffsetUnset()
+ {
+ $form = $this->createForm('
');
+ unset($form['foo']);
+ $this->assertFalse(isset($form['foo']), '->offsetUnset() removes a field');
+ }
+
+ public function testOffsetExists()
+ {
+ $form = $this->createForm('
');
+
+ $this->assertTrue(isset($form['foo']), '->offsetExists() return true if the field exists');
+ $this->assertFalse(isset($form['bar']), '->offsetExists() return false if the field does not exist');
+ }
+
+ public function testGetValues()
+ {
+ $form = $this->createForm('
');
+ $this->assertEquals(array('foo[bar]' => 'foo', 'bar' => 'bar', 'baz' => array()), $form->getValues(), '->getValues() returns all form field values');
+
+ $form = $this->createForm('
');
+ $this->assertEquals(array('bar' => 'bar'), $form->getValues(), '->getValues() does not include not-checked checkboxes');
+
+ $form = $this->createForm('
');
+ $this->assertEquals(array('bar' => 'bar'), $form->getValues(), '->getValues() does not include file input fields');
+
+ $form = $this->createForm('
');
+ $this->assertEquals(array('bar' => 'bar'), $form->getValues(), '->getValues() does not include disabled fields');
+ }
+
+ public function testSetValues()
+ {
+ $form = $this->createForm('
');
+ $form->setValues(array('foo' => false, 'bar' => 'foo'));
+ $this->assertEquals(array('bar' => 'foo'), $form->getValues(), '->setValues() sets the values of fields');
+ }
+
+ public function testMultiselectSetValues()
+ {
+ $form = $this->createForm('
');
+ $form->setValues(array('multi' => array("foo", "bar")));
+ $this->assertEquals(array('multi' => array('foo', 'bar')), $form->getValues(), '->setValue() sets the values of select');
+ }
+
+ public function testGetPhpValues()
+ {
+ $form = $this->createForm('
');
+ $this->assertEquals(array('foo' => array('bar' => 'foo'), 'bar' => 'bar'), $form->getPhpValues(), '->getPhpValues() converts keys with [] to arrays');
+
+ $form = $this->createForm('
');
+ $this->assertEquals(array('fo.o' => array('ba.r' => 'foo'), 'ba r' => 'bar'), $form->getPhpValues(), '->getPhpValues() preserves periods and spaces in names');
+
+ $form = $this->createForm('
');
+ $this->assertEquals(array('fo.o' => array('ba.r' => array('foo', 'ba.z' => 'bar'))), $form->getPhpValues(), '->getPhpValues() preserves periods and spaces in names recursively');
+
+ $form = $this->createForm('
');
+ $this->assertEquals(array('foo' => array('bar' => 'foo'), 'bar' => 'bar'), $form->getPhpValues(), "->getPhpValues() doesn't return empty values");
+ }
+
+ public function testGetFiles()
+ {
+ $form = $this->createForm('
');
+ $this->assertEquals(array(), $form->getFiles(), '->getFiles() returns an empty array if method is get');
+
+ $form = $this->createForm('
');
+ $this->assertEquals(array('foo[bar]' => array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => 4, 'size' => 0)), $form->getFiles(), '->getFiles() only returns file fields for POST');
+
+ $form = $this->createForm('
', 'put');
+ $this->assertEquals(array('foo[bar]' => array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => 4, 'size' => 0)), $form->getFiles(), '->getFiles() only returns file fields for PUT');
+
+ $form = $this->createForm('
', 'delete');
+ $this->assertEquals(array('foo[bar]' => array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => 4, 'size' => 0)), $form->getFiles(), '->getFiles() only returns file fields for DELETE');
+
+ $form = $this->createForm('
', 'patch');
+ $this->assertEquals(array('foo[bar]' => array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => 4, 'size' => 0)), $form->getFiles(), '->getFiles() only returns file fields for PATCH');
+
+ $form = $this->createForm('
');
+ $this->assertEquals(array(), $form->getFiles(), '->getFiles() does not include disabled file fields');
+ }
+
+ public function testGetPhpFiles()
+ {
+ $form = $this->createForm('
');
+ $this->assertEquals(array('foo' => array('bar' => array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => 4, 'size' => 0))), $form->getPhpFiles(), '->getPhpFiles() converts keys with [] to arrays');
+
+ $form = $this->createForm('
');
+ $this->assertEquals(array('f.o o' => array('bar' => array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => 4, 'size' => 0))), $form->getPhpFiles(), '->getPhpFiles() preserves periods and spaces in names');
+
+ $form = $this->createForm('
');
+ $this->assertEquals(array('f.o o' => array('bar' => array('ba.z' => array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => 4, 'size' => 0), array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => 4, 'size' => 0)))), $form->getPhpFiles(), '->getPhpFiles() preserves periods and spaces in names recursively');
+ }
+
+ /**
+ * @dataProvider provideGetUriValues
+ */
+ public function testGetUri($message, $form, $values, $uri, $method = null)
+ {
+ $form = $this->createForm($form, $method);
+ $form->setValues($values);
+
+ $this->assertEquals('http://example.com'.$uri, $form->getUri(), '->getUri() '.$message);
+ }
+
+ public function testGetBaseUri()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
');
+
+ $nodes = $dom->getElementsByTagName('input');
+ $form = new Form($nodes->item($nodes->length - 1), 'http://www.foo.com/');
+ $this->assertEquals('http://www.foo.com/foo.php', $form->getUri());
+ }
+
+ public function testGetUriWithAnchor()
+ {
+ $form = $this->createForm('
', null, 'http://example.com/id/123');
+
+ $this->assertEquals('http://example.com/id/123#foo', $form->getUri());
+ }
+
+ public function testGetUriActionAbsolute()
+ {
+ $formHtml = '
';
+
+ $form = $this->createForm($formHtml);
+ $this->assertEquals('https://login.foo.com/login.php?login_attempt=1', $form->getUri(), '->getUri() returns absolute URIs set in the action form');
+
+ $form = $this->createForm($formHtml, null, 'https://login.foo.com');
+ $this->assertEquals('https://login.foo.com/login.php?login_attempt=1', $form->getUri(), '->getUri() returns absolute URIs set in the action form');
+
+ $form = $this->createForm($formHtml, null, 'https://login.foo.com/bar/');
+ $this->assertEquals('https://login.foo.com/login.php?login_attempt=1', $form->getUri(), '->getUri() returns absolute URIs set in the action form');
+
+ // The action URI haven't the same domain Host have an another domain as Host
+ $form = $this->createForm($formHtml, null, 'https://www.foo.com');
+ $this->assertEquals('https://login.foo.com/login.php?login_attempt=1', $form->getUri(), '->getUri() returns absolute URIs set in the action form');
+
+ $form = $this->createForm($formHtml, null, 'https://www.foo.com/bar/');
+ $this->assertEquals('https://login.foo.com/login.php?login_attempt=1', $form->getUri(), '->getUri() returns absolute URIs set in the action form');
+ }
+
+ public function testGetUriAbsolute()
+ {
+ $form = $this->createForm('
', null, 'http://localhost/foo/');
+ $this->assertEquals('http://localhost/foo/foo', $form->getUri(), '->getUri() returns absolute URIs');
+
+ $form = $this->createForm('
', null, 'http://localhost/foo/');
+ $this->assertEquals('http://localhost/foo', $form->getUri(), '->getUri() returns absolute URIs');
+ }
+
+ public function testGetUriWithOnlyQueryString()
+ {
+ $form = $this->createForm('
', null, 'http://localhost/foo/bar');
+ $this->assertEquals('http://localhost/foo/bar?get=param', $form->getUri(), '->getUri() returns absolute URIs only if the host has been defined in the constructor');
+ }
+
+ public function testGetUriWithoutAction()
+ {
+ $form = $this->createForm('
', null, 'http://localhost/foo/bar');
+ $this->assertEquals('http://localhost/foo/bar', $form->getUri(), '->getUri() returns path if no action defined');
+ }
+
+ public function provideGetUriValues()
+ {
+ return array(
+ array(
+ 'returns the URI of the form',
+ '
',
+ array(),
+ '/foo',
+ ),
+ array(
+ 'appends the form values if the method is get',
+ '
',
+ array(),
+ '/foo?foo=foo',
+ ),
+ array(
+ 'appends the form values and merges the submitted values',
+ '
',
+ array('foo' => 'bar'),
+ '/foo?foo=bar',
+ ),
+ array(
+ 'does not append values if the method is post',
+ '
',
+ array(),
+ '/foo',
+ ),
+ array(
+ 'does not append values if the method is patch',
+ '
',
+ array(),
+ '/foo',
+ 'PUT',
+ ),
+ array(
+ 'does not append values if the method is delete',
+ '
',
+ array(),
+ '/foo',
+ 'DELETE',
+ ),
+ array(
+ 'does not append values if the method is put',
+ '
',
+ array(),
+ '/foo',
+ 'PATCH',
+ ),
+ array(
+ 'appends the form values to an existing query string',
+ '
',
+ array(),
+ '/foo?bar=bar&foo=foo',
+ ),
+ array(
+ 'returns an empty URI if the action is empty',
+ '
',
+ array(),
+ '/',
+ ),
+ array(
+ 'appends the form values even if the action is empty',
+ '
',
+ array(),
+ '/?foo=foo',
+ ),
+ array(
+ 'chooses the path if the action attribute value is a sharp (#)',
+ '
',
+ array(),
+ '/#',
+ ),
+ );
+ }
+
+ public function testHas()
+ {
+ $form = $this->createForm('
');
+
+ $this->assertFalse($form->has('foo'), '->has() returns false if a field is not in the form');
+ $this->assertTrue($form->has('bar'), '->has() returns true if a field is in the form');
+ }
+
+ public function testRemove()
+ {
+ $form = $this->createForm('
');
+ $form->remove('bar');
+ $this->assertFalse($form->has('bar'), '->remove() removes a field');
+ }
+
+ public function testGet()
+ {
+ $form = $this->createForm('
');
+
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Field\\InputFormField', $form->get('bar'), '->get() returns the field object associated with the given name');
+
+ try {
+ $form->get('foo');
+ $this->fail('->get() throws an \InvalidArgumentException if the field does not exist');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertTrue(true, '->get() throws an \InvalidArgumentException if the field does not exist');
+ }
+ }
+
+ public function testAll()
+ {
+ $form = $this->createForm('
');
+
+ $fields = $form->all();
+ $this->assertCount(1, $fields, '->all() return an array of form field objects');
+ $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Field\\InputFormField', $fields['bar'], '->all() return an array of form field objects');
+ }
+
+ public function testSubmitWithoutAFormButton()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
+
+
+
+ ');
+
+ $nodes = $dom->getElementsByTagName('form');
+ $form = new Form($nodes->item(0), 'http://example.com');
+ $this->assertSame($nodes->item(0), $form->getFormNode(), '->getFormNode() returns the form node associated with this form');
+ }
+
+ public function testTypeAttributeIsCaseInsensitive()
+ {
+ $form = $this->createForm('
');
+ $this->assertTrue($form->has('example.x'), '->has() returns true if the image input was correctly turned into an x and a y fields');
+ $this->assertTrue($form->has('example.y'), '->has() returns true if the image input was correctly turned into an x and a y fields');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testFormFieldRegistryAddThrowAnExceptionWhenTheNameIsMalformed()
+ {
+ $registry = new FormFieldRegistry();
+ $registry->add($this->getFormFieldMock('[foo]'));
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testFormFieldRegistryRemoveThrowAnExceptionWhenTheNameIsMalformed()
+ {
+ $registry = new FormFieldRegistry();
+ $registry->remove('[foo]');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testFormFieldRegistryGetThrowAnExceptionWhenTheNameIsMalformed()
+ {
+ $registry = new FormFieldRegistry();
+ $registry->get('[foo]');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testFormFieldRegistryGetThrowAnExceptionWhenTheFieldDoesNotExist()
+ {
+ $registry = new FormFieldRegistry();
+ $registry->get('foo');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testFormFieldRegistrySetThrowAnExceptionWhenTheNameIsMalformed()
+ {
+ $registry = new FormFieldRegistry();
+ $registry->set('[foo]', null);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testFormFieldRegistrySetThrowAnExceptionWhenTheFieldDoesNotExist()
+ {
+ $registry = new FormFieldRegistry();
+ $registry->set('foo', null);
+ }
+
+ public function testFormFieldRegistryHasReturnsTrueWhenTheFQNExists()
+ {
+ $registry = new FormFieldRegistry();
+ $registry->add($this->getFormFieldMock('foo[bar]'));
+
+ $this->assertTrue($registry->has('foo'));
+ $this->assertTrue($registry->has('foo[bar]'));
+ $this->assertFalse($registry->has('bar'));
+ $this->assertFalse($registry->has('foo[foo]'));
+ }
+
+ public function testFormRegistryFieldsCanBeRemoved()
+ {
+ $registry = new FormFieldRegistry();
+ $registry->add($this->getFormFieldMock('foo'));
+ $registry->remove('foo');
+ $this->assertFalse($registry->has('foo'));
+ }
+
+ public function testFormRegistrySupportsMultivaluedFields()
+ {
+ $registry = new FormFieldRegistry();
+ $registry->add($this->getFormFieldMock('foo[]'));
+ $registry->add($this->getFormFieldMock('foo[]'));
+ $registry->add($this->getFormFieldMock('bar[5]'));
+ $registry->add($this->getFormFieldMock('bar[]'));
+ $registry->add($this->getFormFieldMock('bar[baz]'));
+
+ $this->assertEquals(
+ array('foo[0]', 'foo[1]', 'bar[5]', 'bar[6]', 'bar[baz]'),
+ array_keys($registry->all())
+ );
+ }
+
+ public function testFormRegistrySetValues()
+ {
+ $registry = new FormFieldRegistry();
+ $registry->add($f2 = $this->getFormFieldMock('foo[2]'));
+ $registry->add($f3 = $this->getFormFieldMock('foo[3]'));
+ $registry->add($fbb = $this->getFormFieldMock('foo[bar][baz]'));
+
+ $f2
+ ->expects($this->exactly(2))
+ ->method('setValue')
+ ->with(2)
+ ;
+
+ $f3
+ ->expects($this->exactly(2))
+ ->method('setValue')
+ ->with(3)
+ ;
+
+ $fbb
+ ->expects($this->exactly(2))
+ ->method('setValue')
+ ->with('fbb')
+ ;
+
+ $registry->set('foo[2]', 2);
+ $registry->set('foo[3]', 3);
+ $registry->set('foo[bar][baz]', 'fbb');
+
+ $registry->set('foo', array(
+ 2 => 2,
+ 3 => 3,
+ 'bar' => array(
+ 'baz' => 'fbb',
+ ),
+ ));
+ }
+
+ public function testDifferentFieldTypesWithSameName()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
+
+
+
+
+
+ ');
+ $form = new Form($dom->getElementsByTagName('form')->item(0), 'http://example.com');
+
+ $this->assertInstanceOf('Symfony\Component\DomCrawler\Field\ChoiceFormField', $form->get('option'));
+ }
+
+ protected function getFormFieldMock($name, $value = null)
+ {
+ $field = $this
+ ->getMockBuilder('Symfony\\Component\\DomCrawler\\Field\\FormField')
+ ->setMethods(array('getName', 'getValue', 'setValue', 'initialize'))
+ ->disableOriginalConstructor()
+ ->getMock()
+ ;
+
+ $field
+ ->expects($this->any())
+ ->method('getName')
+ ->will($this->returnValue($name))
+ ;
+
+ $field
+ ->expects($this->any())
+ ->method('getValue')
+ ->will($this->returnValue($value))
+ ;
+
+ return $field;
+ }
+
+ protected function createForm($form, $method = null, $currentUri = null)
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML(''.$form.'');
+
+ $xPath = new \DOMXPath($dom);
+ $nodes = $xPath->query('//input | //button');
+
+ if (null === $currentUri) {
+ $currentUri = 'http://example.com/';
+ }
+
+ return new Form($nodes->item($nodes->length - 1), $currentUri, $method);
+ }
+
+ protected function createTestHtml5Form()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
+
+
Hello form
+
+
+
+
+ ');
+
+ return $dom;
+ }
+
+ protected function createTestMultipleForm()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
+
+
Hello form
+
+
+
+ ');
+
+ return $dom;
+ }
+
+ public function testgetPhpValuesWithEmptyTextarea()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
+
+
+
+ ');
+
+ $nodes = $dom->getElementsByTagName('form');
+ $form = new Form($nodes->item(0), 'http://example.com');
+ $this->assertEquals($form->getPhpValues(), array('example' => ''));
+ }
+}
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/LinkTest.php b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/LinkTest.php
new file mode 100644
index 0000000..98a45a3
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Tests/LinkTest.php
@@ -0,0 +1,160 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DomCrawler\Tests;
+
+use Symfony\Component\DomCrawler\Link;
+
+class LinkTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @expectedException \LogicException
+ */
+ public function testConstructorWithANonATag()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
');
+
+ new Link($dom->getElementsByTagName('div')->item(0), 'http://www.example.com/');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testConstructorWithAnInvalidCurrentUri()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
foo ');
+
+ new Link($dom->getElementsByTagName('a')->item(0), 'example.com');
+ }
+
+ public function testGetNode()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
foo ');
+
+ $node = $dom->getElementsByTagName('a')->item(0);
+ $link = new Link($node, 'http://example.com/');
+
+ $this->assertEquals($node, $link->getNode(), '->getNode() returns the node associated with the link');
+ }
+
+ public function testGetMethod()
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML('
foo ');
+
+ $node = $dom->getElementsByTagName('a')->item(0);
+ $link = new Link($node, 'http://example.com/');
+
+ $this->assertEquals('GET', $link->getMethod(), '->getMethod() returns the method of the link');
+
+ $link = new Link($node, 'http://example.com/', 'post');
+ $this->assertEquals('POST', $link->getMethod(), '->getMethod() returns the method of the link');
+ }
+
+ /**
+ * @dataProvider getGetUriTests
+ */
+ public function testGetUri($url, $currentUri, $expected)
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML(sprintf('
foo ', $url));
+ $link = new Link($dom->getElementsByTagName('a')->item(0), $currentUri);
+
+ $this->assertEquals($expected, $link->getUri());
+ }
+
+ /**
+ * @dataProvider getGetUriTests
+ */
+ public function testGetUriOnArea($url, $currentUri, $expected)
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML(sprintf('
', $url));
+ $link = new Link($dom->getElementsByTagName('area')->item(0), $currentUri);
+
+ $this->assertEquals($expected, $link->getUri());
+ }
+
+ /**
+ * @dataProvider getGetUriTests
+ */
+ public function testGetUriOnLink($url, $currentUri, $expected)
+ {
+ $dom = new \DOMDocument();
+ $dom->loadHTML(sprintf('
', $url));
+ $link = new Link($dom->getElementsByTagName('link')->item(0), $currentUri);
+
+ $this->assertEquals($expected, $link->getUri());
+ }
+
+ public function getGetUriTests()
+ {
+ return array(
+ array('/foo', 'http://localhost/bar/foo/', 'http://localhost/foo'),
+ array('/foo', 'http://localhost/bar/foo', 'http://localhost/foo'),
+ array('
+ /foo', 'http://localhost/bar/foo/', 'http://localhost/foo'),
+ array('/foo
+ ', 'http://localhost/bar/foo', 'http://localhost/foo'),
+
+ array('foo', 'http://localhost/bar/foo/', 'http://localhost/bar/foo/foo'),
+ array('foo', 'http://localhost/bar/foo', 'http://localhost/bar/foo'),
+
+ array('', 'http://localhost/bar/', 'http://localhost/bar/'),
+ array('#', 'http://localhost/bar/', 'http://localhost/bar/#'),
+ array('#bar', 'http://localhost/bar?a=b', 'http://localhost/bar?a=b#bar'),
+ array('#bar', 'http://localhost/bar/#foo', 'http://localhost/bar/#bar'),
+ array('?a=b', 'http://localhost/bar#foo', 'http://localhost/bar?a=b'),
+ array('?a=b', 'http://localhost/bar/', 'http://localhost/bar/?a=b'),
+
+ array('http://login.foo.com/foo', 'http://localhost/bar/', 'http://login.foo.com/foo'),
+ array('https://login.foo.com/foo', 'https://localhost/bar/', 'https://login.foo.com/foo'),
+ array('mailto:foo@bar.com', 'http://localhost/foo', 'mailto:foo@bar.com'),
+
+ // tests schema relative URL (issue #7169)
+ array('//login.foo.com/foo', 'http://localhost/bar/', 'http://login.foo.com/foo'),
+ array('//login.foo.com/foo', 'https://localhost/bar/', 'https://login.foo.com/foo'),
+
+ array('?foo=2', 'http://localhost?foo=1', 'http://localhost?foo=2'),
+ array('?foo=2', 'http://localhost/?foo=1', 'http://localhost/?foo=2'),
+ array('?foo=2', 'http://localhost/bar?foo=1', 'http://localhost/bar?foo=2'),
+ array('?foo=2', 'http://localhost/bar/?foo=1', 'http://localhost/bar/?foo=2'),
+ array('?bar=2', 'http://localhost?foo=1', 'http://localhost?bar=2'),
+
+ array('foo', 'http://login.foo.com/bar/baz?/query/string', 'http://login.foo.com/bar/foo'),
+
+ array('.', 'http://localhost/foo/bar/baz', 'http://localhost/foo/bar/'),
+ array('./', 'http://localhost/foo/bar/baz', 'http://localhost/foo/bar/'),
+ array('./foo', 'http://localhost/foo/bar/baz', 'http://localhost/foo/bar/foo'),
+ array('..', 'http://localhost/foo/bar/baz', 'http://localhost/foo/'),
+ array('../', 'http://localhost/foo/bar/baz', 'http://localhost/foo/'),
+ array('../foo', 'http://localhost/foo/bar/baz', 'http://localhost/foo/foo'),
+ array('../..', 'http://localhost/foo/bar/baz', 'http://localhost/'),
+ array('../../', 'http://localhost/foo/bar/baz', 'http://localhost/'),
+ array('../../foo', 'http://localhost/foo/bar/baz', 'http://localhost/foo'),
+ array('../../foo', 'http://localhost/bar/foo/', 'http://localhost/foo'),
+ array('../bar/../../foo', 'http://localhost/bar/foo/', 'http://localhost/foo'),
+ array('../bar/./../../foo', 'http://localhost/bar/foo/', 'http://localhost/foo'),
+ array('../../', 'http://localhost/', 'http://localhost/'),
+ array('../../', 'http://localhost', 'http://localhost/'),
+
+ array('/foo', 'http://localhost?bar=1', 'http://localhost/foo'),
+ array('/foo', 'http://localhost#bar', 'http://localhost/foo'),
+ array('/foo', 'file:///', 'file:///foo'),
+ array('/foo', 'file:///bar/baz', 'file:///foo'),
+ array('foo', 'file:///', 'file:///foo'),
+ array('foo', 'file:///bar/baz', 'file:///bar/foo'),
+ );
+ }
+}
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/composer.json b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/composer.json
new file mode 100644
index 0000000..5bc3192
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/composer.json
@@ -0,0 +1,37 @@
+{
+ "name": "symfony/dom-crawler",
+ "type": "library",
+ "description": "Symfony DomCrawler Component",
+ "keywords": [],
+ "homepage": "http://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "symfony/css-selector": "~2.3"
+ },
+ "suggest": {
+ "symfony/css-selector": ""
+ },
+ "autoload": {
+ "psr-0": { "Symfony\\Component\\DomCrawler\\": "" }
+ },
+ "target-dir": "Symfony/Component/DomCrawler",
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.6-dev"
+ }
+ }
+}
diff --git a/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/phpunit.xml.dist b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/phpunit.xml.dist
new file mode 100644
index 0000000..5ce15ec
--- /dev/null
+++ b/core/vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/phpunit.xml.dist
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+ ./Tests/
+
+
+
+
+
+ ./
+
+ ./Resources
+ ./Tests
+ ./vendor
+
+
+
+
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/.gitignore b/core/vendor/symfony/finder/Symfony/Component/Finder/.gitignore
new file mode 100644
index 0000000..c49a5d8
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/.gitignore
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractAdapter.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractAdapter.php
new file mode 100644
index 0000000..4ddd913
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractAdapter.php
@@ -0,0 +1,236 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Adapter;
+
+/**
+ * Interface for finder engine implementations.
+ *
+ * @author Jean-François Simon
+ */
+abstract class AbstractAdapter implements AdapterInterface
+{
+ protected $followLinks = false;
+ protected $mode = 0;
+ protected $minDepth = 0;
+ protected $maxDepth = PHP_INT_MAX;
+ protected $exclude = array();
+ protected $names = array();
+ protected $notNames = array();
+ protected $contains = array();
+ protected $notContains = array();
+ protected $sizes = array();
+ protected $dates = array();
+ protected $filters = array();
+ protected $sort = false;
+ protected $paths = array();
+ protected $notPaths = array();
+ protected $ignoreUnreadableDirs = false;
+
+ private static $areSupported = array();
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isSupported()
+ {
+ $name = $this->getName();
+
+ if (!array_key_exists($name, self::$areSupported)) {
+ self::$areSupported[$name] = $this->canBeUsed();
+ }
+
+ return self::$areSupported[$name];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFollowLinks($followLinks)
+ {
+ $this->followLinks = $followLinks;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setMode($mode)
+ {
+ $this->mode = $mode;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDepths(array $depths)
+ {
+ $this->minDepth = 0;
+ $this->maxDepth = PHP_INT_MAX;
+
+ foreach ($depths as $comparator) {
+ switch ($comparator->getOperator()) {
+ case '>':
+ $this->minDepth = $comparator->getTarget() + 1;
+ break;
+ case '>=':
+ $this->minDepth = $comparator->getTarget();
+ break;
+ case '<':
+ $this->maxDepth = $comparator->getTarget() - 1;
+ break;
+ case '<=':
+ $this->maxDepth = $comparator->getTarget();
+ break;
+ default:
+ $this->minDepth = $this->maxDepth = $comparator->getTarget();
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setExclude(array $exclude)
+ {
+ $this->exclude = $exclude;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setNames(array $names)
+ {
+ $this->names = $names;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setNotNames(array $notNames)
+ {
+ $this->notNames = $notNames;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setContains(array $contains)
+ {
+ $this->contains = $contains;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setNotContains(array $notContains)
+ {
+ $this->notContains = $notContains;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setSizes(array $sizes)
+ {
+ $this->sizes = $sizes;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDates(array $dates)
+ {
+ $this->dates = $dates;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFilters(array $filters)
+ {
+ $this->filters = $filters;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setSort($sort)
+ {
+ $this->sort = $sort;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPath(array $paths)
+ {
+ $this->paths = $paths;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setNotPath(array $notPaths)
+ {
+ $this->notPaths = $notPaths;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function ignoreUnreadableDirs($ignore = true)
+ {
+ $this->ignoreUnreadableDirs = (bool) $ignore;
+
+ return $this;
+ }
+
+ /**
+ * Returns whether the adapter is supported in the current environment.
+ *
+ * This method should be implemented in all adapters. Do not implement
+ * isSupported in the adapters as the generic implementation provides a cache
+ * layer.
+ *
+ * @see isSupported()
+ *
+ * @return bool Whether the adapter is supported
+ */
+ abstract protected function canBeUsed();
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php
new file mode 100644
index 0000000..4d73b32
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php
@@ -0,0 +1,327 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Adapter;
+
+use Symfony\Component\Finder\Exception\AccessDeniedException;
+use Symfony\Component\Finder\Iterator;
+use Symfony\Component\Finder\Shell\Shell;
+use Symfony\Component\Finder\Expression\Expression;
+use Symfony\Component\Finder\Shell\Command;
+use Symfony\Component\Finder\Comparator\NumberComparator;
+use Symfony\Component\Finder\Comparator\DateComparator;
+
+/**
+ * Shell engine implementation using GNU find command.
+ *
+ * @author Jean-François Simon
+ */
+abstract class AbstractFindAdapter extends AbstractAdapter
+{
+ /**
+ * @var Shell
+ */
+ protected $shell;
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ $this->shell = new Shell();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function searchInDirectory($dir)
+ {
+ // having "/../" in path make find fail
+ $dir = realpath($dir);
+
+ // searching directories containing or not containing strings leads to no result
+ if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode && ($this->contains || $this->notContains)) {
+ return new Iterator\FilePathsIterator(array(), $dir);
+ }
+
+ $command = Command::create();
+ $find = $this->buildFindCommand($command, $dir);
+
+ if ($this->followLinks) {
+ $find->add('-follow');
+ }
+
+ $find->add('-mindepth')->add($this->minDepth + 1);
+
+ if (PHP_INT_MAX !== $this->maxDepth) {
+ $find->add('-maxdepth')->add($this->maxDepth + 1);
+ }
+
+ if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) {
+ $find->add('-type d');
+ } elseif (Iterator\FileTypeFilterIterator::ONLY_FILES === $this->mode) {
+ $find->add('-type f');
+ }
+
+ $this->buildNamesFiltering($find, $this->names);
+ $this->buildNamesFiltering($find, $this->notNames, true);
+ $this->buildPathsFiltering($find, $dir, $this->paths);
+ $this->buildPathsFiltering($find, $dir, $this->notPaths, true);
+ $this->buildSizesFiltering($find, $this->sizes);
+ $this->buildDatesFiltering($find, $this->dates);
+
+ $useGrep = $this->shell->testCommand('grep') && $this->shell->testCommand('xargs');
+ $useSort = is_int($this->sort) && $this->shell->testCommand('sort') && $this->shell->testCommand('cut');
+
+ if ($useGrep && ($this->contains || $this->notContains)) {
+ $grep = $command->ins('grep');
+ $this->buildContentFiltering($grep, $this->contains);
+ $this->buildContentFiltering($grep, $this->notContains, true);
+ }
+
+ if ($useSort) {
+ $this->buildSorting($command, $this->sort);
+ }
+
+ $command->setErrorHandler(
+ $this->ignoreUnreadableDirs
+ // If directory is unreadable and finder is set to ignore it, `stderr` is ignored.
+ ? function ($stderr) { return; }
+ : function ($stderr) { throw new AccessDeniedException($stderr); }
+ );
+
+ $paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute());
+ $iterator = new Iterator\FilePathsIterator($paths, $dir);
+
+ if ($this->exclude) {
+ $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
+ }
+
+ if (!$useGrep && ($this->contains || $this->notContains)) {
+ $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
+ }
+
+ if ($this->filters) {
+ $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
+ }
+
+ if (!$useSort && $this->sort) {
+ $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
+ $iterator = $iteratorAggregate->getIterator();
+ }
+
+ return $iterator;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function canBeUsed()
+ {
+ return $this->shell->testCommand('find');
+ }
+
+ /**
+ * @param Command $command
+ * @param string $dir
+ *
+ * @return Command
+ */
+ protected function buildFindCommand(Command $command, $dir)
+ {
+ return $command
+ ->ins('find')
+ ->add('find ')
+ ->arg($dir)
+ ->add('-noleaf'); // the -noleaf option is required for filesystems that don't follow the '.' and '..' conventions
+ }
+
+ /**
+ * @param Command $command
+ * @param string[] $names
+ * @param bool $not
+ */
+ private function buildNamesFiltering(Command $command, array $names, $not = false)
+ {
+ if (0 === count($names)) {
+ return;
+ }
+
+ $command->add($not ? '-not' : null)->cmd('(');
+
+ foreach ($names as $i => $name) {
+ $expr = Expression::create($name);
+
+ // Find does not support expandable globs ("*.{a,b}" syntax).
+ if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
+ $expr = Expression::create($expr->getGlob()->toRegex(false));
+ }
+
+ // Fixes 'not search' and 'full path matching' regex problems.
+ // - Jokers '.' are replaced by [^/].
+ // - We add '[^/]*' before and after regex (if no ^|$ flags are present).
+ if ($expr->isRegex()) {
+ $regex = $expr->getRegex();
+ $regex->prepend($regex->hasStartFlag() ? '/' : '/[^/]*')
+ ->setStartFlag(false)
+ ->setStartJoker(true)
+ ->replaceJokers('[^/]');
+ if (!$regex->hasEndFlag() || $regex->hasEndJoker()) {
+ $regex->setEndJoker(false)->append('[^/]*');
+ }
+ }
+
+ $command
+ ->add($i > 0 ? '-or' : null)
+ ->add($expr->isRegex()
+ ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
+ : ($expr->isCaseSensitive() ? '-name' : '-iname')
+ )
+ ->arg($expr->renderPattern());
+ }
+
+ $command->cmd(')');
+ }
+
+ /**
+ * @param Command $command
+ * @param string $dir
+ * @param string[] $paths
+ * @param bool $not
+ */
+ private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false)
+ {
+ if (0 === count($paths)) {
+ return;
+ }
+
+ $command->add($not ? '-not' : null)->cmd('(');
+
+ foreach ($paths as $i => $path) {
+ $expr = Expression::create($path);
+
+ // Find does not support expandable globs ("*.{a,b}" syntax).
+ if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
+ $expr = Expression::create($expr->getGlob()->toRegex(false));
+ }
+
+ // Fixes 'not search' regex problems.
+ if ($expr->isRegex()) {
+ $regex = $expr->getRegex();
+ $regex->prepend($regex->hasStartFlag() ? preg_quote($dir).DIRECTORY_SEPARATOR : '.*')->setEndJoker(!$regex->hasEndFlag());
+ } else {
+ $expr->prepend('*')->append('*');
+ }
+
+ $command
+ ->add($i > 0 ? '-or' : null)
+ ->add($expr->isRegex()
+ ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
+ : ($expr->isCaseSensitive() ? '-path' : '-ipath')
+ )
+ ->arg($expr->renderPattern());
+ }
+
+ $command->cmd(')');
+ }
+
+ /**
+ * @param Command $command
+ * @param NumberComparator[] $sizes
+ */
+ private function buildSizesFiltering(Command $command, array $sizes)
+ {
+ foreach ($sizes as $i => $size) {
+ $command->add($i > 0 ? '-and' : null);
+
+ switch ($size->getOperator()) {
+ case '<=':
+ $command->add('-size -'.($size->getTarget() + 1).'c');
+ break;
+ case '>=':
+ $command->add('-size +'.($size->getTarget() - 1).'c');
+ break;
+ case '>':
+ $command->add('-size +'.$size->getTarget().'c');
+ break;
+ case '!=':
+ $command->add('-size -'.$size->getTarget().'c');
+ $command->add('-size +'.$size->getTarget().'c');
+ break;
+ case '<':
+ default:
+ $command->add('-size -'.$size->getTarget().'c');
+ }
+ }
+ }
+
+ /**
+ * @param Command $command
+ * @param DateComparator[] $dates
+ */
+ private function buildDatesFiltering(Command $command, array $dates)
+ {
+ foreach ($dates as $i => $date) {
+ $command->add($i > 0 ? '-and' : null);
+
+ $mins = (int) round((time()-$date->getTarget()) / 60);
+
+ if (0 > $mins) {
+ // mtime is in the future
+ $command->add(' -mmin -0');
+ // we will have no result so we don't need to continue
+ return;
+ }
+
+ switch ($date->getOperator()) {
+ case '<=':
+ $command->add('-mmin +'.($mins - 1));
+ break;
+ case '>=':
+ $command->add('-mmin -'.($mins + 1));
+ break;
+ case '>':
+ $command->add('-mmin -'.$mins);
+ break;
+ case '!=':
+ $command->add('-mmin +'.$mins.' -or -mmin -'.$mins);
+ break;
+ case '<':
+ default:
+ $command->add('-mmin +'.$mins);
+ }
+ }
+ }
+
+ /**
+ * @param Command $command
+ * @param string $sort
+ *
+ * @throws \InvalidArgumentException
+ */
+ private function buildSorting(Command $command, $sort)
+ {
+ $this->buildFormatSorting($command, $sort);
+ }
+
+ /**
+ * @param Command $command
+ * @param string $sort
+ */
+ abstract protected function buildFormatSorting(Command $command, $sort);
+
+ /**
+ * @param Command $command
+ * @param array $contains
+ * @param bool $not
+ */
+ abstract protected function buildContentFiltering(Command $command, array $contains, $not = false);
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/AdapterInterface.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/AdapterInterface.php
new file mode 100644
index 0000000..bdc3a93
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/AdapterInterface.php
@@ -0,0 +1,144 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Adapter;
+
+/**
+ * @author Jean-François Simon
+ */
+interface AdapterInterface
+{
+ /**
+ * @param bool $followLinks
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setFollowLinks($followLinks);
+
+ /**
+ * @param int $mode
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setMode($mode);
+
+ /**
+ * @param array $exclude
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setExclude(array $exclude);
+
+ /**
+ * @param array $depths
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setDepths(array $depths);
+
+ /**
+ * @param array $names
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setNames(array $names);
+
+ /**
+ * @param array $notNames
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setNotNames(array $notNames);
+
+ /**
+ * @param array $contains
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setContains(array $contains);
+
+ /**
+ * @param array $notContains
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setNotContains(array $notContains);
+
+ /**
+ * @param array $sizes
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setSizes(array $sizes);
+
+ /**
+ * @param array $dates
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setDates(array $dates);
+
+ /**
+ * @param array $filters
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setFilters(array $filters);
+
+ /**
+ * @param \Closure|int $sort
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setSort($sort);
+
+ /**
+ * @param array $paths
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setPath(array $paths);
+
+ /**
+ * @param array $notPaths
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function setNotPath(array $notPaths);
+
+ /**
+ * @param bool $ignore
+ *
+ * @return AdapterInterface Current instance
+ */
+ public function ignoreUnreadableDirs($ignore = true);
+
+ /**
+ * @param string $dir
+ *
+ * @return \Iterator Result iterator
+ */
+ public function searchInDirectory($dir);
+
+ /**
+ * Tests adapter support for current platform.
+ *
+ * @return bool
+ */
+ public function isSupported();
+
+ /**
+ * Returns adapter name.
+ *
+ * @return string
+ */
+ public function getName();
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/BsdFindAdapter.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/BsdFindAdapter.php
new file mode 100644
index 0000000..4a25bae
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/BsdFindAdapter.php
@@ -0,0 +1,103 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Adapter;
+
+use Symfony\Component\Finder\Shell\Shell;
+use Symfony\Component\Finder\Shell\Command;
+use Symfony\Component\Finder\Iterator\SortableIterator;
+use Symfony\Component\Finder\Expression\Expression;
+
+/**
+ * Shell engine implementation using BSD find command.
+ *
+ * @author Jean-François Simon
+ */
+class BsdFindAdapter extends AbstractFindAdapter
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'bsd_find';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function canBeUsed()
+ {
+ return in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::canBeUsed();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function buildFormatSorting(Command $command, $sort)
+ {
+ switch ($sort) {
+ case SortableIterator::SORT_BY_NAME:
+ $command->ins('sort')->add('| sort');
+
+ return;
+ case SortableIterator::SORT_BY_TYPE:
+ $format = '%HT';
+ break;
+ case SortableIterator::SORT_BY_ACCESSED_TIME:
+ $format = '%a';
+ break;
+ case SortableIterator::SORT_BY_CHANGED_TIME:
+ $format = '%c';
+ break;
+ case SortableIterator::SORT_BY_MODIFIED_TIME:
+ $format = '%m';
+ break;
+ default:
+ throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
+ }
+
+ $command
+ ->add('-print0 | xargs -0 stat -f')
+ ->arg($format.'%t%N')
+ ->add('| sort | cut -f 2');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function buildFindCommand(Command $command, $dir)
+ {
+ parent::buildFindCommand($command, $dir)->addAtIndex('-E', 1);
+
+ return $command;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function buildContentFiltering(Command $command, array $contains, $not = false)
+ {
+ foreach ($contains as $contain) {
+ $expr = Expression::create($contain);
+
+ // todo: avoid forking process for each $pattern by using multiple -e options
+ $command
+ ->add('| grep -v \'^$\'')
+ ->add('| xargs -I{} grep -I')
+ ->add($expr->isCaseSensitive() ? null : '-i')
+ ->add($not ? '-L' : '-l')
+ ->add('-Ee')->arg($expr->renderPattern())
+ ->add('{}')
+ ;
+ }
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/GnuFindAdapter.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/GnuFindAdapter.php
new file mode 100644
index 0000000..0fbf48f
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/GnuFindAdapter.php
@@ -0,0 +1,104 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Adapter;
+
+use Symfony\Component\Finder\Shell\Shell;
+use Symfony\Component\Finder\Shell\Command;
+use Symfony\Component\Finder\Iterator\SortableIterator;
+use Symfony\Component\Finder\Expression\Expression;
+
+/**
+ * Shell engine implementation using GNU find command.
+ *
+ * @author Jean-François Simon
+ */
+class GnuFindAdapter extends AbstractFindAdapter
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'gnu_find';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function buildFormatSorting(Command $command, $sort)
+ {
+ switch ($sort) {
+ case SortableIterator::SORT_BY_NAME:
+ $command->ins('sort')->add('| sort');
+
+ return;
+ case SortableIterator::SORT_BY_TYPE:
+ $format = '%y';
+ break;
+ case SortableIterator::SORT_BY_ACCESSED_TIME:
+ $format = '%A@';
+ break;
+ case SortableIterator::SORT_BY_CHANGED_TIME:
+ $format = '%C@';
+ break;
+ case SortableIterator::SORT_BY_MODIFIED_TIME:
+ $format = '%T@';
+ break;
+ default:
+ throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
+ }
+
+ $command
+ ->get('find')
+ ->add('-printf')
+ ->arg($format.' %h/%f\\n')
+ ->add('| sort | cut')
+ ->arg('-d ')
+ ->arg('-f2-')
+ ;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function canBeUsed()
+ {
+ return $this->shell->getType() === Shell::TYPE_UNIX && parent::canBeUsed();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function buildFindCommand(Command $command, $dir)
+ {
+ return parent::buildFindCommand($command, $dir)->add('-regextype posix-extended');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function buildContentFiltering(Command $command, array $contains, $not = false)
+ {
+ foreach ($contains as $contain) {
+ $expr = Expression::create($contain);
+
+ // todo: avoid forking process for each $pattern by using multiple -e options
+ $command
+ ->add('| xargs -I{} -r grep -I')
+ ->add($expr->isCaseSensitive() ? null : '-i')
+ ->add($not ? '-L' : '-l')
+ ->add('-Ee')->arg($expr->renderPattern())
+ ->add('{}')
+ ;
+ }
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/PhpAdapter.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/PhpAdapter.php
new file mode 100644
index 0000000..378a26a
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Adapter/PhpAdapter.php
@@ -0,0 +1,98 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Adapter;
+
+use Symfony\Component\Finder\Iterator;
+
+/**
+ * PHP finder engine implementation.
+ *
+ * @author Jean-François Simon
+ */
+class PhpAdapter extends AbstractAdapter
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function searchInDirectory($dir)
+ {
+ $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
+
+ if ($this->followLinks) {
+ $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
+ }
+
+ $iterator = new \RecursiveIteratorIterator(
+ new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs),
+ \RecursiveIteratorIterator::SELF_FIRST
+ );
+
+ if ($this->minDepth > 0 || $this->maxDepth < PHP_INT_MAX) {
+ $iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->minDepth, $this->maxDepth);
+ }
+
+ if ($this->mode) {
+ $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
+ }
+
+ if ($this->exclude) {
+ $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
+ }
+
+ if ($this->names || $this->notNames) {
+ $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
+ }
+
+ if ($this->contains || $this->notContains) {
+ $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
+ }
+
+ if ($this->sizes) {
+ $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
+ }
+
+ if ($this->dates) {
+ $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
+ }
+
+ if ($this->filters) {
+ $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
+ }
+
+ if ($this->sort) {
+ $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
+ $iterator = $iteratorAggregate->getIterator();
+ }
+
+ if ($this->paths || $this->notPaths) {
+ $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
+ }
+
+ return $iterator;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'php';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function canBeUsed()
+ {
+ return true;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/CHANGELOG.md b/core/vendor/symfony/finder/Symfony/Component/Finder/CHANGELOG.md
new file mode 100644
index 0000000..f1dd7d5
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/CHANGELOG.md
@@ -0,0 +1,34 @@
+CHANGELOG
+=========
+
+2.5.0
+-----
+ * added support for GLOB_BRACE in the paths passed to Finder::in()
+
+2.3.0
+-----
+
+ * added a way to ignore unreadable directories (via Finder::ignoreUnreadableDirs())
+ * unified the way subfolders that are not executable are handled by always throwing an AccessDeniedException exception
+
+2.2.0
+-----
+
+ * added Finder::path() and Finder::notPath() methods
+ * added finder adapters to improve performance on specific platforms
+ * added support for wildcard characters (glob patterns) in the paths passed
+ to Finder::in()
+
+2.1.0
+-----
+
+ * added Finder::sortByAccessedTime(), Finder::sortByChangedTime(), and
+ Finder::sortByModifiedTime()
+ * added Countable to Finder
+ * added support for an array of directories as an argument to
+ Finder::exclude()
+ * added searching based on the file content via Finder::contains() and
+ Finder::notContains()
+ * added support for the != operator in the Comparator
+ * [BC BREAK] filter expressions (used for file name and content) are no more
+ considered as regexps but glob patterns when they are enclosed in '*' or '?'
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Comparator/Comparator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Comparator/Comparator.php
new file mode 100644
index 0000000..4f5e1ff
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Comparator/Comparator.php
@@ -0,0 +1,98 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Comparator;
+
+/**
+ * Comparator.
+ *
+ * @author Fabien Potencier
+ */
+class Comparator
+{
+ private $target;
+ private $operator = '==';
+
+ /**
+ * Gets the target value.
+ *
+ * @return string The target value
+ */
+ public function getTarget()
+ {
+ return $this->target;
+ }
+
+ /**
+ * Sets the target value.
+ *
+ * @param string $target The target value
+ */
+ public function setTarget($target)
+ {
+ $this->target = $target;
+ }
+
+ /**
+ * Gets the comparison operator.
+ *
+ * @return string The operator
+ */
+ public function getOperator()
+ {
+ return $this->operator;
+ }
+
+ /**
+ * Sets the comparison operator.
+ *
+ * @param string $operator A valid operator
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function setOperator($operator)
+ {
+ if (!$operator) {
+ $operator = '==';
+ }
+
+ if (!in_array($operator, array('>', '<', '>=', '<=', '==', '!='))) {
+ throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
+ }
+
+ $this->operator = $operator;
+ }
+
+ /**
+ * Tests against the target.
+ *
+ * @param mixed $test A test value
+ *
+ * @return bool
+ */
+ public function test($test)
+ {
+ switch ($this->operator) {
+ case '>':
+ return $test > $this->target;
+ case '>=':
+ return $test >= $this->target;
+ case '<':
+ return $test < $this->target;
+ case '<=':
+ return $test <= $this->target;
+ case '!=':
+ return $test != $this->target;
+ }
+
+ return $test == $this->target;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Comparator/DateComparator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Comparator/DateComparator.php
new file mode 100644
index 0000000..8b7746b
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Comparator/DateComparator.php
@@ -0,0 +1,53 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Comparator;
+
+/**
+ * DateCompare compiles date comparisons.
+ *
+ * @author Fabien Potencier
+ */
+class DateComparator extends Comparator
+{
+ /**
+ * Constructor.
+ *
+ * @param string $test A comparison string
+ *
+ * @throws \InvalidArgumentException If the test is not understood
+ */
+ public function __construct($test)
+ {
+ if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
+ throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
+ }
+
+ try {
+ $date = new \DateTime($matches[2]);
+ $target = $date->format('U');
+ } catch (\Exception $e) {
+ throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
+ }
+
+ $operator = isset($matches[1]) ? $matches[1] : '==';
+ if ('since' === $operator || 'after' === $operator) {
+ $operator = '>';
+ }
+
+ if ('until' === $operator || 'before' === $operator) {
+ $operator = '<';
+ }
+
+ $this->setOperator($operator);
+ $this->setTarget($target);
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Comparator/NumberComparator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Comparator/NumberComparator.php
new file mode 100644
index 0000000..c8587dc
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Comparator/NumberComparator.php
@@ -0,0 +1,81 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Comparator;
+
+/**
+ * NumberComparator compiles a simple comparison to an anonymous
+ * subroutine, which you can call with a value to be tested again.
+ *
+ * Now this would be very pointless, if NumberCompare didn't understand
+ * magnitudes.
+ *
+ * The target value may use magnitudes of kilobytes (k, ki),
+ * megabytes (m, mi), or gigabytes (g, gi). Those suffixed
+ * with an i use the appropriate 2**n version in accordance with the
+ * IEC standard: http://physics.nist.gov/cuu/Units/binary.html
+ *
+ * Based on the Perl Number::Compare module.
+ *
+ * @author Fabien Potencier PHP port
+ * @author Richard Clamp Perl version
+ * @copyright 2004-2005 Fabien Potencier
+ * @copyright 2002 Richard Clamp
+ *
+ * @see http://physics.nist.gov/cuu/Units/binary.html
+ */
+class NumberComparator extends Comparator
+{
+ /**
+ * Constructor.
+ *
+ * @param string $test A comparison string
+ *
+ * @throws \InvalidArgumentException If the test is not understood
+ */
+ public function __construct($test)
+ {
+ if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
+ throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test));
+ }
+
+ $target = $matches[2];
+ if (!is_numeric($target)) {
+ throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
+ }
+ if (isset($matches[3])) {
+ // magnitude
+ switch (strtolower($matches[3])) {
+ case 'k':
+ $target *= 1000;
+ break;
+ case 'ki':
+ $target *= 1024;
+ break;
+ case 'm':
+ $target *= 1000000;
+ break;
+ case 'mi':
+ $target *= 1024*1024;
+ break;
+ case 'g':
+ $target *= 1000000000;
+ break;
+ case 'gi':
+ $target *= 1024*1024*1024;
+ break;
+ }
+ }
+
+ $this->setTarget($target);
+ $this->setOperator(isset($matches[1]) ? $matches[1] : '==');
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/AccessDeniedException.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/AccessDeniedException.php
new file mode 100644
index 0000000..ee195ea
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/AccessDeniedException.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Exception;
+
+/**
+ * @author Jean-François Simon
+ */
+class AccessDeniedException extends \UnexpectedValueException
+{
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/AdapterFailureException.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/AdapterFailureException.php
new file mode 100644
index 0000000..15fa221
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/AdapterFailureException.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Exception;
+
+use Symfony\Component\Finder\Adapter\AdapterInterface;
+
+/**
+ * Base exception for all adapter failures.
+ *
+ * @author Jean-François Simon
+ */
+class AdapterFailureException extends \RuntimeException implements ExceptionInterface
+{
+ /**
+ * @var \Symfony\Component\Finder\Adapter\AdapterInterface
+ */
+ private $adapter;
+
+ /**
+ * @param AdapterInterface $adapter
+ * @param string|null $message
+ * @param \Exception|null $previous
+ */
+ public function __construct(AdapterInterface $adapter, $message = null, \Exception $previous = null)
+ {
+ $this->adapter = $adapter;
+ parent::__construct($message ?: 'Search failed with "'.$adapter->getName().'" adapter.', $previous);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAdapter()
+ {
+ return $this->adapter;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/ExceptionInterface.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/ExceptionInterface.php
new file mode 100644
index 0000000..bff0214
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/ExceptionInterface.php
@@ -0,0 +1,23 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Exception;
+
+/**
+ * @author Jean-François Simon
+ */
+interface ExceptionInterface
+{
+ /**
+ * @return \Symfony\Component\Finder\Adapter\AdapterInterface
+ */
+ public function getAdapter();
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/OperationNotPermitedException.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/OperationNotPermitedException.php
new file mode 100644
index 0000000..3663112
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/OperationNotPermitedException.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Exception;
+
+/**
+ * @author Jean-François Simon
+ */
+class OperationNotPermitedException extends AdapterFailureException
+{
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/ShellCommandFailureException.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/ShellCommandFailureException.php
new file mode 100644
index 0000000..2658f6a
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Exception/ShellCommandFailureException.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Exception;
+
+use Symfony\Component\Finder\Adapter\AdapterInterface;
+use Symfony\Component\Finder\Shell\Command;
+
+/**
+ * @author Jean-François Simon
+ */
+class ShellCommandFailureException extends AdapterFailureException
+{
+ /**
+ * @var Command
+ */
+ private $command;
+
+ /**
+ * @param AdapterInterface $adapter
+ * @param Command $command
+ * @param \Exception|null $previous
+ */
+ public function __construct(AdapterInterface $adapter, Command $command, \Exception $previous = null)
+ {
+ $this->command = $command;
+ parent::__construct($adapter, 'Shell command failed: "'.$command->join().'".', $previous);
+ }
+
+ /**
+ * @return Command
+ */
+ public function getCommand()
+ {
+ return $this->command;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/Expression.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/Expression.php
new file mode 100644
index 0000000..9002607
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/Expression.php
@@ -0,0 +1,146 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Expression;
+
+/**
+ * @author Jean-François Simon
+ */
+class Expression implements ValueInterface
+{
+ const TYPE_REGEX = 1;
+ const TYPE_GLOB = 2;
+
+ /**
+ * @var ValueInterface
+ */
+ private $value;
+
+ /**
+ * @param string $expr
+ *
+ * @return Expression
+ */
+ public static function create($expr)
+ {
+ return new self($expr);
+ }
+
+ /**
+ * @param string $expr
+ */
+ public function __construct($expr)
+ {
+ try {
+ $this->value = Regex::create($expr);
+ } catch (\InvalidArgumentException $e) {
+ $this->value = new Glob($expr);
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->render();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function render()
+ {
+ return $this->value->render();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function renderPattern()
+ {
+ return $this->value->renderPattern();
+ }
+
+ /**
+ * @return bool
+ */
+ public function isCaseSensitive()
+ {
+ return $this->value->isCaseSensitive();
+ }
+
+ /**
+ * @return int
+ */
+ public function getType()
+ {
+ return $this->value->getType();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function prepend($expr)
+ {
+ $this->value->prepend($expr);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function append($expr)
+ {
+ $this->value->append($expr);
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isRegex()
+ {
+ return self::TYPE_REGEX === $this->value->getType();
+ }
+
+ /**
+ * @return bool
+ */
+ public function isGlob()
+ {
+ return self::TYPE_GLOB === $this->value->getType();
+ }
+
+ /**
+ * @throws \LogicException
+ *
+ * @return Glob
+ */
+ public function getGlob()
+ {
+ if (self::TYPE_GLOB !== $this->value->getType()) {
+ throw new \LogicException('Regex can\'t be transformed to glob.');
+ }
+
+ return $this->value;
+ }
+
+ /**
+ * @return Regex
+ */
+ public function getRegex()
+ {
+ return self::TYPE_REGEX === $this->value->getType() ? $this->value : $this->value->toRegex();
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/Glob.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/Glob.php
new file mode 100644
index 0000000..3023cee
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/Glob.php
@@ -0,0 +1,157 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Expression;
+
+/**
+ * @author Jean-François Simon
+ */
+class Glob implements ValueInterface
+{
+ /**
+ * @var string
+ */
+ private $pattern;
+
+ /**
+ * @param string $pattern
+ */
+ public function __construct($pattern)
+ {
+ $this->pattern = $pattern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function render()
+ {
+ return $this->pattern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function renderPattern()
+ {
+ return $this->pattern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getType()
+ {
+ return Expression::TYPE_GLOB;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isCaseSensitive()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function prepend($expr)
+ {
+ $this->pattern = $expr.$this->pattern;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function append($expr)
+ {
+ $this->pattern .= $expr;
+
+ return $this;
+ }
+
+ /**
+ * Tests if glob is expandable ("*.{a,b}" syntax).
+ *
+ * @return bool
+ */
+ public function isExpandable()
+ {
+ return false !== strpos($this->pattern, '{')
+ && false !== strpos($this->pattern, '}');
+ }
+
+ /**
+ * @param bool $strictLeadingDot
+ * @param bool $strictWildcardSlash
+ *
+ * @return Regex
+ */
+ public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true)
+ {
+ $firstByte = true;
+ $escaping = false;
+ $inCurlies = 0;
+ $regex = '';
+ $sizeGlob = strlen($this->pattern);
+ for ($i = 0; $i < $sizeGlob; $i++) {
+ $car = $this->pattern[$i];
+ if ($firstByte) {
+ if ($strictLeadingDot && '.' !== $car) {
+ $regex .= '(?=[^\.])';
+ }
+
+ $firstByte = false;
+ }
+
+ if ('/' === $car) {
+ $firstByte = true;
+ }
+
+ if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
+ $regex .= "\\$car";
+ } elseif ('*' === $car) {
+ $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
+ } elseif ('?' === $car) {
+ $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
+ } elseif ('{' === $car) {
+ $regex .= $escaping ? '\\{' : '(';
+ if (!$escaping) {
+ ++$inCurlies;
+ }
+ } elseif ('}' === $car && $inCurlies) {
+ $regex .= $escaping ? '}' : ')';
+ if (!$escaping) {
+ --$inCurlies;
+ }
+ } elseif (',' === $car && $inCurlies) {
+ $regex .= $escaping ? ',' : '|';
+ } elseif ('\\' === $car) {
+ if ($escaping) {
+ $regex .= '\\\\';
+ $escaping = false;
+ } else {
+ $escaping = true;
+ }
+
+ continue;
+ } else {
+ $regex .= $car;
+ }
+ $escaping = false;
+ }
+
+ return new Regex('^'.$regex.'$');
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/Regex.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/Regex.php
new file mode 100644
index 0000000..a249fc2
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/Regex.php
@@ -0,0 +1,321 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Expression;
+
+/**
+ * @author Jean-François Simon
+ */
+class Regex implements ValueInterface
+{
+ const START_FLAG = '^';
+ const END_FLAG = '$';
+ const BOUNDARY = '~';
+ const JOKER = '.*';
+ const ESCAPING = '\\';
+
+ /**
+ * @var string
+ */
+ private $pattern;
+
+ /**
+ * @var array
+ */
+ private $options;
+
+ /**
+ * @var bool
+ */
+ private $startFlag;
+
+ /**
+ * @var bool
+ */
+ private $endFlag;
+
+ /**
+ * @var bool
+ */
+ private $startJoker;
+
+ /**
+ * @var bool
+ */
+ private $endJoker;
+
+ /**
+ * @param string $expr
+ *
+ * @return Regex
+ *
+ * @throws \InvalidArgumentException
+ */
+ public static function create($expr)
+ {
+ if (preg_match('/^(.{3,}?)([imsxuADU]*)$/', $expr, $m)) {
+ $start = substr($m[1], 0, 1);
+ $end = substr($m[1], -1);
+
+ if (
+ ($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start))
+ || ($start === '{' && $end === '}')
+ || ($start === '(' && $end === ')')
+ ) {
+ return new self(substr($m[1], 1, -1), $m[2], $end);
+ }
+ }
+
+ throw new \InvalidArgumentException('Given expression is not a regex.');
+ }
+
+ /**
+ * @param string $pattern
+ * @param string $options
+ * @param string $delimiter
+ */
+ public function __construct($pattern, $options = '', $delimiter = null)
+ {
+ if (null !== $delimiter) {
+ // removes delimiter escaping
+ $pattern = str_replace('\\'.$delimiter, $delimiter, $pattern);
+ }
+
+ $this->parsePattern($pattern);
+ $this->options = $options;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->render();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function render()
+ {
+ return self::BOUNDARY
+ .$this->renderPattern()
+ .self::BOUNDARY
+ .$this->options;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function renderPattern()
+ {
+ return ($this->startFlag ? self::START_FLAG : '')
+ .($this->startJoker ? self::JOKER : '')
+ .str_replace(self::BOUNDARY, '\\'.self::BOUNDARY, $this->pattern)
+ .($this->endJoker ? self::JOKER : '')
+ .($this->endFlag ? self::END_FLAG : '');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isCaseSensitive()
+ {
+ return !$this->hasOption('i');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getType()
+ {
+ return Expression::TYPE_REGEX;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function prepend($expr)
+ {
+ $this->pattern = $expr.$this->pattern;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function append($expr)
+ {
+ $this->pattern .= $expr;
+
+ return $this;
+ }
+
+ /**
+ * @param string $option
+ *
+ * @return bool
+ */
+ public function hasOption($option)
+ {
+ return false !== strpos($this->options, $option);
+ }
+
+ /**
+ * @param string $option
+ *
+ * @return Regex
+ */
+ public function addOption($option)
+ {
+ if (!$this->hasOption($option)) {
+ $this->options .= $option;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $option
+ *
+ * @return Regex
+ */
+ public function removeOption($option)
+ {
+ $this->options = str_replace($option, '', $this->options);
+
+ return $this;
+ }
+
+ /**
+ * @param bool $startFlag
+ *
+ * @return Regex
+ */
+ public function setStartFlag($startFlag)
+ {
+ $this->startFlag = $startFlag;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasStartFlag()
+ {
+ return $this->startFlag;
+ }
+
+ /**
+ * @param bool $endFlag
+ *
+ * @return Regex
+ */
+ public function setEndFlag($endFlag)
+ {
+ $this->endFlag = (bool) $endFlag;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasEndFlag()
+ {
+ return $this->endFlag;
+ }
+
+ /**
+ * @param bool $startJoker
+ *
+ * @return Regex
+ */
+ public function setStartJoker($startJoker)
+ {
+ $this->startJoker = $startJoker;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasStartJoker()
+ {
+ return $this->startJoker;
+ }
+
+ /**
+ * @param bool $endJoker
+ *
+ * @return Regex
+ */
+ public function setEndJoker($endJoker)
+ {
+ $this->endJoker = (bool) $endJoker;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasEndJoker()
+ {
+ return $this->endJoker;
+ }
+
+ /**
+ * @param array $replacement
+ *
+ * @return Regex
+ */
+ public function replaceJokers($replacement)
+ {
+ $replace = function ($subject) use ($replacement) {
+ $subject = $subject[0];
+ $replace = 0 === substr_count($subject, '\\') % 2;
+
+ return $replace ? str_replace('.', $replacement, $subject) : $subject;
+ };
+
+ $this->pattern = preg_replace_callback('~[\\\\]*\\.~', $replace, $this->pattern);
+
+ return $this;
+ }
+
+ /**
+ * @param string $pattern
+ */
+ private function parsePattern($pattern)
+ {
+ if ($this->startFlag = self::START_FLAG === substr($pattern, 0, 1)) {
+ $pattern = substr($pattern, 1);
+ }
+
+ if ($this->startJoker = self::JOKER === substr($pattern, 0, 2)) {
+ $pattern = substr($pattern, 2);
+ }
+
+ if ($this->endFlag = (self::END_FLAG === substr($pattern, -1) && self::ESCAPING !== substr($pattern, -2, -1))) {
+ $pattern = substr($pattern, 0, -1);
+ }
+
+ if ($this->endJoker = (self::JOKER === substr($pattern, -2) && self::ESCAPING !== substr($pattern, -3, -2))) {
+ $pattern = substr($pattern, 0, -2);
+ }
+
+ $this->pattern = $pattern;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/ValueInterface.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/ValueInterface.php
new file mode 100644
index 0000000..34ce0e7
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Expression/ValueInterface.php
@@ -0,0 +1,60 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Expression;
+
+/**
+ * @author Jean-François Simon
+ */
+interface ValueInterface
+{
+ /**
+ * Renders string representation of expression.
+ *
+ * @return string
+ */
+ public function render();
+
+ /**
+ * Renders string representation of pattern.
+ *
+ * @return string
+ */
+ public function renderPattern();
+
+ /**
+ * Returns value case sensitivity.
+ *
+ * @return bool
+ */
+ public function isCaseSensitive();
+
+ /**
+ * Returns expression type.
+ *
+ * @return int
+ */
+ public function getType();
+
+ /**
+ * @param string $expr
+ *
+ * @return ValueInterface
+ */
+ public function prepend($expr);
+
+ /**
+ * @param string $expr
+ *
+ * @return ValueInterface
+ */
+ public function append($expr);
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Finder.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Finder.php
new file mode 100644
index 0000000..91a2992
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Finder.php
@@ -0,0 +1,840 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder;
+
+use Symfony\Component\Finder\Adapter\AdapterInterface;
+use Symfony\Component\Finder\Adapter\GnuFindAdapter;
+use Symfony\Component\Finder\Adapter\BsdFindAdapter;
+use Symfony\Component\Finder\Adapter\PhpAdapter;
+use Symfony\Component\Finder\Comparator\DateComparator;
+use Symfony\Component\Finder\Comparator\NumberComparator;
+use Symfony\Component\Finder\Exception\ExceptionInterface;
+use Symfony\Component\Finder\Iterator\CustomFilterIterator;
+use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
+use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
+use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
+use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
+use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
+use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
+use Symfony\Component\Finder\Iterator\SortableIterator;
+
+/**
+ * Finder allows to build rules to find files and directories.
+ *
+ * It is a thin wrapper around several specialized iterator classes.
+ *
+ * All rules may be invoked several times.
+ *
+ * All methods return the current Finder object to allow easy chaining:
+ *
+ * $finder = Finder::create()->files()->name('*.php')->in(__DIR__);
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+class Finder implements \IteratorAggregate, \Countable
+{
+ const IGNORE_VCS_FILES = 1;
+ const IGNORE_DOT_FILES = 2;
+
+ private $mode = 0;
+ private $names = array();
+ private $notNames = array();
+ private $exclude = array();
+ private $filters = array();
+ private $depths = array();
+ private $sizes = array();
+ private $followLinks = false;
+ private $sort = false;
+ private $ignore = 0;
+ private $dirs = array();
+ private $dates = array();
+ private $iterators = array();
+ private $contains = array();
+ private $notContains = array();
+ private $adapters = array();
+ private $paths = array();
+ private $notPaths = array();
+ private $ignoreUnreadableDirs = false;
+
+ private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
+
+ $this
+ ->addAdapter(new GnuFindAdapter())
+ ->addAdapter(new BsdFindAdapter())
+ ->addAdapter(new PhpAdapter(), -50)
+ ->setAdapter('php')
+ ;
+ }
+
+ /**
+ * Creates a new Finder.
+ *
+ * @return Finder A new Finder instance
+ *
+ * @api
+ */
+ public static function create()
+ {
+ return new static();
+ }
+
+ /**
+ * Registers a finder engine implementation.
+ *
+ * @param AdapterInterface $adapter An adapter instance
+ * @param int $priority Highest is selected first
+ *
+ * @return Finder The current Finder instance
+ */
+ public function addAdapter(AdapterInterface $adapter, $priority = 0)
+ {
+ $this->adapters[$adapter->getName()] = array(
+ 'adapter' => $adapter,
+ 'priority' => $priority,
+ 'selected' => false,
+ );
+
+ return $this->sortAdapters();
+ }
+
+ /**
+ * Sets the selected adapter to the best one according to the current platform the code is run on.
+ *
+ * @return Finder The current Finder instance
+ */
+ public function useBestAdapter()
+ {
+ $this->resetAdapterSelection();
+
+ return $this->sortAdapters();
+ }
+
+ /**
+ * Selects the adapter to use.
+ *
+ * @param string $name
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return Finder The current Finder instance
+ */
+ public function setAdapter($name)
+ {
+ if (!isset($this->adapters[$name])) {
+ throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
+ }
+
+ $this->resetAdapterSelection();
+ $this->adapters[$name]['selected'] = true;
+
+ return $this->sortAdapters();
+ }
+
+ /**
+ * Removes all adapters registered in the finder.
+ *
+ * @return Finder The current Finder instance
+ */
+ public function removeAdapters()
+ {
+ $this->adapters = array();
+
+ return $this;
+ }
+
+ /**
+ * Returns registered adapters ordered by priority without extra information.
+ *
+ * @return AdapterInterface[]
+ */
+ public function getAdapters()
+ {
+ return array_values(array_map(function (array $adapter) {
+ return $adapter['adapter'];
+ }, $this->adapters));
+ }
+
+ /**
+ * Restricts the matching to directories only.
+ *
+ * @return Finder The current Finder instance
+ *
+ * @api
+ */
+ public function directories()
+ {
+ $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
+
+ return $this;
+ }
+
+ /**
+ * Restricts the matching to files only.
+ *
+ * @return Finder The current Finder instance
+ *
+ * @api
+ */
+ public function files()
+ {
+ $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
+
+ return $this;
+ }
+
+ /**
+ * Adds tests for the directory depth.
+ *
+ * Usage:
+ *
+ * $finder->depth('> 1') // the Finder will start matching at level 1.
+ * $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point.
+ *
+ * @param int $level The depth level expression
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see DepthRangeFilterIterator
+ * @see NumberComparator
+ *
+ * @api
+ */
+ public function depth($level)
+ {
+ $this->depths[] = new Comparator\NumberComparator($level);
+
+ return $this;
+ }
+
+ /**
+ * Adds tests for file dates (last modified).
+ *
+ * The date must be something that strtotime() is able to parse:
+ *
+ * $finder->date('since yesterday');
+ * $finder->date('until 2 days ago');
+ * $finder->date('> now - 2 hours');
+ * $finder->date('>= 2005-10-15');
+ *
+ * @param string $date A date rage string
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see strtotime
+ * @see DateRangeFilterIterator
+ * @see DateComparator
+ *
+ * @api
+ */
+ public function date($date)
+ {
+ $this->dates[] = new Comparator\DateComparator($date);
+
+ return $this;
+ }
+
+ /**
+ * Adds rules that files must match.
+ *
+ * You can use patterns (delimited with / sign), globs or simple strings.
+ *
+ * $finder->name('*.php')
+ * $finder->name('/\.php$/') // same as above
+ * $finder->name('test.php')
+ *
+ * @param string $pattern A pattern (a regexp, a glob, or a string)
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see FilenameFilterIterator
+ *
+ * @api
+ */
+ public function name($pattern)
+ {
+ $this->names[] = $pattern;
+
+ return $this;
+ }
+
+ /**
+ * Adds rules that files must not match.
+ *
+ * @param string $pattern A pattern (a regexp, a glob, or a string)
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see FilenameFilterIterator
+ *
+ * @api
+ */
+ public function notName($pattern)
+ {
+ $this->notNames[] = $pattern;
+
+ return $this;
+ }
+
+ /**
+ * Adds tests that file contents must match.
+ *
+ * Strings or PCRE patterns can be used:
+ *
+ * $finder->contains('Lorem ipsum')
+ * $finder->contains('/Lorem ipsum/i')
+ *
+ * @param string $pattern A pattern (string or regexp)
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see FilecontentFilterIterator
+ */
+ public function contains($pattern)
+ {
+ $this->contains[] = $pattern;
+
+ return $this;
+ }
+
+ /**
+ * Adds tests that file contents must not match.
+ *
+ * Strings or PCRE patterns can be used:
+ *
+ * $finder->notContains('Lorem ipsum')
+ * $finder->notContains('/Lorem ipsum/i')
+ *
+ * @param string $pattern A pattern (string or regexp)
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see FilecontentFilterIterator
+ */
+ public function notContains($pattern)
+ {
+ $this->notContains[] = $pattern;
+
+ return $this;
+ }
+
+ /**
+ * Adds rules that filenames must match.
+ *
+ * You can use patterns (delimited with / sign) or simple strings.
+ *
+ * $finder->path('some/special/dir')
+ * $finder->path('/some\/special\/dir/') // same as above
+ *
+ * Use only / as dirname separator.
+ *
+ * @param string $pattern A pattern (a regexp or a string)
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see FilenameFilterIterator
+ */
+ public function path($pattern)
+ {
+ $this->paths[] = $pattern;
+
+ return $this;
+ }
+
+ /**
+ * Adds rules that filenames must not match.
+ *
+ * You can use patterns (delimited with / sign) or simple strings.
+ *
+ * $finder->notPath('some/special/dir')
+ * $finder->notPath('/some\/special\/dir/') // same as above
+ *
+ * Use only / as dirname separator.
+ *
+ * @param string $pattern A pattern (a regexp or a string)
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see FilenameFilterIterator
+ */
+ public function notPath($pattern)
+ {
+ $this->notPaths[] = $pattern;
+
+ return $this;
+ }
+
+ /**
+ * Adds tests for file sizes.
+ *
+ * $finder->size('> 10K');
+ * $finder->size('<= 1Ki');
+ * $finder->size(4);
+ *
+ * @param string $size A size range string
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see SizeRangeFilterIterator
+ * @see NumberComparator
+ *
+ * @api
+ */
+ public function size($size)
+ {
+ $this->sizes[] = new Comparator\NumberComparator($size);
+
+ return $this;
+ }
+
+ /**
+ * Excludes directories.
+ *
+ * @param string|array $dirs A directory path or an array of directories
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see ExcludeDirectoryFilterIterator
+ *
+ * @api
+ */
+ public function exclude($dirs)
+ {
+ $this->exclude = array_merge($this->exclude, (array) $dirs);
+
+ return $this;
+ }
+
+ /**
+ * Excludes "hidden" directories and files (starting with a dot).
+ *
+ * @param bool $ignoreDotFiles Whether to exclude "hidden" files or not
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see ExcludeDirectoryFilterIterator
+ *
+ * @api
+ */
+ public function ignoreDotFiles($ignoreDotFiles)
+ {
+ if ($ignoreDotFiles) {
+ $this->ignore = $this->ignore | static::IGNORE_DOT_FILES;
+ } else {
+ $this->ignore = $this->ignore & ~static::IGNORE_DOT_FILES;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Forces the finder to ignore version control directories.
+ *
+ * @param bool $ignoreVCS Whether to exclude VCS files or not
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see ExcludeDirectoryFilterIterator
+ *
+ * @api
+ */
+ public function ignoreVCS($ignoreVCS)
+ {
+ if ($ignoreVCS) {
+ $this->ignore = $this->ignore | static::IGNORE_VCS_FILES;
+ } else {
+ $this->ignore = $this->ignore & ~static::IGNORE_VCS_FILES;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Adds VCS patterns.
+ *
+ * @see ignoreVCS()
+ *
+ * @param string|string[] $pattern VCS patterns to ignore
+ */
+ public static function addVCSPattern($pattern)
+ {
+ foreach ((array) $pattern as $p) {
+ self::$vcsPatterns[] = $p;
+ }
+
+ self::$vcsPatterns = array_unique(self::$vcsPatterns);
+ }
+
+ /**
+ * Sorts files and directories by an anonymous function.
+ *
+ * The anonymous function receives two \SplFileInfo instances to compare.
+ *
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
+ *
+ * @param \Closure $closure An anonymous function
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see SortableIterator
+ *
+ * @api
+ */
+ public function sort(\Closure $closure)
+ {
+ $this->sort = $closure;
+
+ return $this;
+ }
+
+ /**
+ * Sorts files and directories by name.
+ *
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see SortableIterator
+ *
+ * @api
+ */
+ public function sortByName()
+ {
+ $this->sort = Iterator\SortableIterator::SORT_BY_NAME;
+
+ return $this;
+ }
+
+ /**
+ * Sorts files and directories by type (directories before files), then by name.
+ *
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see SortableIterator
+ *
+ * @api
+ */
+ public function sortByType()
+ {
+ $this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
+
+ return $this;
+ }
+
+ /**
+ * Sorts files and directories by the last accessed time.
+ *
+ * This is the time that the file was last accessed, read or written to.
+ *
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see SortableIterator
+ *
+ * @api
+ */
+ public function sortByAccessedTime()
+ {
+ $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
+
+ return $this;
+ }
+
+ /**
+ * Sorts files and directories by the last inode changed time.
+ *
+ * This is the time that the inode information was last modified (permissions, owner, group or other metadata).
+ *
+ * On Windows, since inode is not available, changed time is actually the file creation time.
+ *
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see SortableIterator
+ *
+ * @api
+ */
+ public function sortByChangedTime()
+ {
+ $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
+
+ return $this;
+ }
+
+ /**
+ * Sorts files and directories by the last modified time.
+ *
+ * This is the last time the actual contents of the file were last modified.
+ *
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see SortableIterator
+ *
+ * @api
+ */
+ public function sortByModifiedTime()
+ {
+ $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
+
+ return $this;
+ }
+
+ /**
+ * Filters the iterator with an anonymous function.
+ *
+ * The anonymous function receives a \SplFileInfo and must return false
+ * to remove files.
+ *
+ * @param \Closure $closure An anonymous function
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see CustomFilterIterator
+ *
+ * @api
+ */
+ public function filter(\Closure $closure)
+ {
+ $this->filters[] = $closure;
+
+ return $this;
+ }
+
+ /**
+ * Forces the following of symlinks.
+ *
+ * @return Finder The current Finder instance
+ *
+ * @api
+ */
+ public function followLinks()
+ {
+ $this->followLinks = true;
+
+ return $this;
+ }
+
+ /**
+ * Tells finder to ignore unreadable directories.
+ *
+ * By default, scanning unreadable directories content throws an AccessDeniedException.
+ *
+ * @param bool $ignore
+ *
+ * @return Finder The current Finder instance
+ */
+ public function ignoreUnreadableDirs($ignore = true)
+ {
+ $this->ignoreUnreadableDirs = (bool) $ignore;
+
+ return $this;
+ }
+
+ /**
+ * Searches files and directories which match defined rules.
+ *
+ * @param string|array $dirs A directory path or an array of directories
+ *
+ * @return Finder The current Finder instance
+ *
+ * @throws \InvalidArgumentException if one of the directories does not exist
+ *
+ * @api
+ */
+ public function in($dirs)
+ {
+ $resolvedDirs = array();
+
+ foreach ((array) $dirs as $dir) {
+ if (is_dir($dir)) {
+ $resolvedDirs[] = $dir;
+ } elseif ($glob = glob($dir, GLOB_BRACE | GLOB_ONLYDIR)) {
+ $resolvedDirs = array_merge($resolvedDirs, $glob);
+ } else {
+ throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
+ }
+ }
+
+ $this->dirs = array_merge($this->dirs, $resolvedDirs);
+
+ return $this;
+ }
+
+ /**
+ * Returns an Iterator for the current Finder configuration.
+ *
+ * This method implements the IteratorAggregate interface.
+ *
+ * @return \Iterator An iterator
+ *
+ * @throws \LogicException if the in() method has not been called
+ */
+ public function getIterator()
+ {
+ if (0 === count($this->dirs) && 0 === count($this->iterators)) {
+ throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
+ }
+
+ if (1 === count($this->dirs) && 0 === count($this->iterators)) {
+ return $this->searchInDirectory($this->dirs[0]);
+ }
+
+ $iterator = new \AppendIterator();
+ foreach ($this->dirs as $dir) {
+ $iterator->append($this->searchInDirectory($dir));
+ }
+
+ foreach ($this->iterators as $it) {
+ $iterator->append($it);
+ }
+
+ return $iterator;
+ }
+
+ /**
+ * Appends an existing set of files/directories to the finder.
+ *
+ * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array.
+ *
+ * @param mixed $iterator
+ *
+ * @return Finder The finder
+ *
+ * @throws \InvalidArgumentException When the given argument is not iterable.
+ */
+ public function append($iterator)
+ {
+ if ($iterator instanceof \IteratorAggregate) {
+ $this->iterators[] = $iterator->getIterator();
+ } elseif ($iterator instanceof \Iterator) {
+ $this->iterators[] = $iterator;
+ } elseif ($iterator instanceof \Traversable || is_array($iterator)) {
+ $it = new \ArrayIterator();
+ foreach ($iterator as $file) {
+ $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
+ }
+ $this->iterators[] = $it;
+ } else {
+ throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Counts all the results collected by the iterators.
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return iterator_count($this->getIterator());
+ }
+
+ /**
+ * @return Finder The current Finder instance
+ */
+ private function sortAdapters()
+ {
+ uasort($this->adapters, function (array $a, array $b) {
+ if ($a['selected'] || $b['selected']) {
+ return $a['selected'] ? -1 : 1;
+ }
+
+ return $a['priority'] > $b['priority'] ? -1 : 1;
+ });
+
+ return $this;
+ }
+
+ /**
+ * @param $dir
+ *
+ * @return \Iterator
+ *
+ * @throws \RuntimeException When none of the adapters are supported
+ */
+ private function searchInDirectory($dir)
+ {
+ if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
+ $this->exclude = array_merge($this->exclude, self::$vcsPatterns);
+ }
+
+ if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
+ $this->notPaths[] = '#(^|/)\..+(/|$)#';
+ }
+
+ foreach ($this->adapters as $adapter) {
+ if ($adapter['adapter']->isSupported()) {
+ try {
+ return $this
+ ->buildAdapter($adapter['adapter'])
+ ->searchInDirectory($dir);
+ } catch (ExceptionInterface $e) {
+ }
+ }
+ }
+
+ throw new \RuntimeException('No supported adapter found.');
+ }
+
+ /**
+ * @param AdapterInterface $adapter
+ *
+ * @return AdapterInterface
+ */
+ private function buildAdapter(AdapterInterface $adapter)
+ {
+ return $adapter
+ ->setFollowLinks($this->followLinks)
+ ->setDepths($this->depths)
+ ->setMode($this->mode)
+ ->setExclude($this->exclude)
+ ->setNames($this->names)
+ ->setNotNames($this->notNames)
+ ->setContains($this->contains)
+ ->setNotContains($this->notContains)
+ ->setSizes($this->sizes)
+ ->setDates($this->dates)
+ ->setFilters($this->filters)
+ ->setSort($this->sort)
+ ->setPath($this->paths)
+ ->setNotPath($this->notPaths)
+ ->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
+ }
+
+ /**
+ * Unselects all adapters.
+ */
+ private function resetAdapterSelection()
+ {
+ $this->adapters = array_map(function (array $properties) {
+ $properties['selected'] = false;
+
+ return $properties;
+ }, $this->adapters);
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Glob.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Glob.php
new file mode 100644
index 0000000..c2030c9
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Glob.php
@@ -0,0 +1,103 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder;
+
+/**
+ * Glob matches globbing patterns against text.
+ *
+ * if match_glob("foo.*", "foo.bar") echo "matched\n";
+ *
+ * // prints foo.bar and foo.baz
+ * $regex = glob_to_regex("foo.*");
+ * for (array('foo.bar', 'foo.baz', 'foo', 'bar') as $t)
+ * {
+ * if (/$regex/) echo "matched: $car\n";
+ * }
+ *
+ * Glob implements glob(3) style matching that can be used to match
+ * against text, rather than fetching names from a filesystem.
+ *
+ * Based on the Perl Text::Glob module.
+ *
+ * @author Fabien Potencier PHP port
+ * @author Richard Clamp Perl version
+ * @copyright 2004-2005 Fabien Potencier
+ * @copyright 2002 Richard Clamp
+ */
+class Glob
+{
+ /**
+ * Returns a regexp which is the equivalent of the glob pattern.
+ *
+ * @param string $glob The glob pattern
+ * @param bool $strictLeadingDot
+ * @param bool $strictWildcardSlash
+ *
+ * @return string regex The regexp
+ */
+ public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true)
+ {
+ $firstByte = true;
+ $escaping = false;
+ $inCurlies = 0;
+ $regex = '';
+ $sizeGlob = strlen($glob);
+ for ($i = 0; $i < $sizeGlob; $i++) {
+ $car = $glob[$i];
+ if ($firstByte) {
+ if ($strictLeadingDot && '.' !== $car) {
+ $regex .= '(?=[^\.])';
+ }
+
+ $firstByte = false;
+ }
+
+ if ('/' === $car) {
+ $firstByte = true;
+ }
+
+ if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
+ $regex .= "\\$car";
+ } elseif ('*' === $car) {
+ $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
+ } elseif ('?' === $car) {
+ $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
+ } elseif ('{' === $car) {
+ $regex .= $escaping ? '\\{' : '(';
+ if (!$escaping) {
+ ++$inCurlies;
+ }
+ } elseif ('}' === $car && $inCurlies) {
+ $regex .= $escaping ? '}' : ')';
+ if (!$escaping) {
+ --$inCurlies;
+ }
+ } elseif (',' === $car && $inCurlies) {
+ $regex .= $escaping ? ',' : '|';
+ } elseif ('\\' === $car) {
+ if ($escaping) {
+ $regex .= '\\\\';
+ $escaping = false;
+ } else {
+ $escaping = true;
+ }
+
+ continue;
+ } else {
+ $regex .= $car;
+ }
+ $escaping = false;
+ }
+
+ return '#^'.$regex.'$#';
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/CustomFilterIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/CustomFilterIterator.php
new file mode 100644
index 0000000..24b15d9
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/CustomFilterIterator.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * CustomFilterIterator filters files by applying anonymous functions.
+ *
+ * The anonymous function receives a \SplFileInfo and must return false
+ * to remove files.
+ *
+ * @author Fabien Potencier
+ */
+class CustomFilterIterator extends FilterIterator
+{
+ private $filters = array();
+
+ /**
+ * Constructor.
+ *
+ * @param \Iterator $iterator The Iterator to filter
+ * @param array $filters An array of PHP callbacks
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function __construct(\Iterator $iterator, array $filters)
+ {
+ foreach ($filters as $filter) {
+ if (!is_callable($filter)) {
+ throw new \InvalidArgumentException('Invalid PHP callback.');
+ }
+ }
+ $this->filters = $filters;
+
+ parent::__construct($iterator);
+ }
+
+ /**
+ * Filters the iterator values.
+ *
+ * @return bool true if the value should be kept, false otherwise
+ */
+ public function accept()
+ {
+ $fileinfo = $this->current();
+
+ foreach ($this->filters as $filter) {
+ if (false === call_user_func($filter, $fileinfo)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php
new file mode 100644
index 0000000..4d5ef9a
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php
@@ -0,0 +1,60 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+use Symfony\Component\Finder\Comparator\DateComparator;
+
+/**
+ * DateRangeFilterIterator filters out files that are not in the given date range (last modified dates).
+ *
+ * @author Fabien Potencier
+ */
+class DateRangeFilterIterator extends FilterIterator
+{
+ private $comparators = array();
+
+ /**
+ * Constructor.
+ *
+ * @param \Iterator $iterator The Iterator to filter
+ * @param DateComparator[] $comparators An array of DateComparator instances
+ */
+ public function __construct(\Iterator $iterator, array $comparators)
+ {
+ $this->comparators = $comparators;
+
+ parent::__construct($iterator);
+ }
+
+ /**
+ * Filters the iterator values.
+ *
+ * @return bool true if the value should be kept, false otherwise
+ */
+ public function accept()
+ {
+ $fileinfo = $this->current();
+
+ if (!file_exists($fileinfo->getRealPath())) {
+ return false;
+ }
+
+ $filedate = $fileinfo->getMTime();
+ foreach ($this->comparators as $compare) {
+ if (!$compare->test($filedate)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/DepthRangeFilterIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/DepthRangeFilterIterator.php
new file mode 100644
index 0000000..f78c71e
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/DepthRangeFilterIterator.php
@@ -0,0 +1,47 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * DepthRangeFilterIterator limits the directory depth.
+ *
+ * @author Fabien Potencier
+ */
+class DepthRangeFilterIterator extends FilterIterator
+{
+ private $minDepth = 0;
+
+ /**
+ * Constructor.
+ *
+ * @param \RecursiveIteratorIterator $iterator The Iterator to filter
+ * @param int $minDepth The min depth
+ * @param int $maxDepth The max depth
+ */
+ public function __construct(\RecursiveIteratorIterator $iterator, $minDepth = 0, $maxDepth = PHP_INT_MAX)
+ {
+ $this->minDepth = $minDepth;
+ $iterator->setMaxDepth(PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);
+
+ parent::__construct($iterator);
+ }
+
+ /**
+ * Filters the iterator values.
+ *
+ * @return bool true if the value should be kept, false otherwise
+ */
+ public function accept()
+ {
+ return $this->getInnerIterator()->getDepth() >= $this->minDepth;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php
new file mode 100644
index 0000000..1ddde85
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * ExcludeDirectoryFilterIterator filters out directories.
+ *
+ * @author Fabien Potencier
+ */
+class ExcludeDirectoryFilterIterator extends FilterIterator
+{
+ private $patterns = array();
+
+ /**
+ * Constructor.
+ *
+ * @param \Iterator $iterator The Iterator to filter
+ * @param array $directories An array of directories to exclude
+ */
+ public function __construct(\Iterator $iterator, array $directories)
+ {
+ foreach ($directories as $directory) {
+ $this->patterns[] = '#(^|/)'.preg_quote($directory, '#').'(/|$)#';
+ }
+
+ parent::__construct($iterator);
+ }
+
+ /**
+ * Filters the iterator values.
+ *
+ * @return bool true if the value should be kept, false otherwise
+ */
+ public function accept()
+ {
+ $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
+ $path = strtr($path, '\\', '/');
+ foreach ($this->patterns as $pattern) {
+ if (preg_match($pattern, $path)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilePathsIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilePathsIterator.php
new file mode 100644
index 0000000..4da2f5b
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilePathsIterator.php
@@ -0,0 +1,131 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+use Symfony\Component\Finder\SplFileInfo;
+
+/**
+ * Iterate over shell command result.
+ *
+ * @author Jean-François Simon
+ */
+class FilePathsIterator extends \ArrayIterator
+{
+ /**
+ * @var string
+ */
+ private $baseDir;
+
+ /**
+ * @var int
+ */
+ private $baseDirLength;
+
+ /**
+ * @var string
+ */
+ private $subPath;
+
+ /**
+ * @var string
+ */
+ private $subPathname;
+
+ /**
+ * @var SplFileInfo
+ */
+ private $current;
+
+ /**
+ * @param array $paths List of paths returned by shell command
+ * @param string $baseDir Base dir for relative path building
+ */
+ public function __construct(array $paths, $baseDir)
+ {
+ $this->baseDir = $baseDir;
+ $this->baseDirLength = strlen($baseDir);
+
+ parent::__construct($paths);
+ }
+
+ /**
+ * @param string $name
+ * @param array $arguments
+ *
+ * @return mixed
+ */
+ public function __call($name, array $arguments)
+ {
+ return call_user_func_array(array($this->current(), $name), $arguments);
+ }
+
+ /**
+ * Return an instance of SplFileInfo with support for relative paths.
+ *
+ * @return SplFileInfo File information
+ */
+ public function current()
+ {
+ return $this->current;
+ }
+
+ /**
+ * @return string
+ */
+ public function key()
+ {
+ return $this->current->getPathname();
+ }
+
+ public function next()
+ {
+ parent::next();
+ $this->buildProperties();
+ }
+
+ public function rewind()
+ {
+ parent::rewind();
+ $this->buildProperties();
+ }
+
+ /**
+ * @return string
+ */
+ public function getSubPath()
+ {
+ return $this->subPath;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSubPathname()
+ {
+ return $this->subPathname;
+ }
+
+ private function buildProperties()
+ {
+ $absolutePath = parent::current();
+
+ if ($this->baseDir === substr($absolutePath, 0, $this->baseDirLength)) {
+ $this->subPathname = ltrim(substr($absolutePath, $this->baseDirLength), '/\\');
+ $dir = dirname($this->subPathname);
+ $this->subPath = '.' === $dir ? '' : $dir;
+ } else {
+ $this->subPath = $this->subPathname = '';
+ }
+
+ $this->current = new SplFileInfo(parent::current(), $this->subPath, $this->subPathname);
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FileTypeFilterIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FileTypeFilterIterator.php
new file mode 100644
index 0000000..f50fd82
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FileTypeFilterIterator.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * FileTypeFilterIterator only keeps files, directories, or both.
+ *
+ * @author Fabien Potencier
+ */
+class FileTypeFilterIterator extends FilterIterator
+{
+ const ONLY_FILES = 1;
+ const ONLY_DIRECTORIES = 2;
+
+ private $mode;
+
+ /**
+ * Constructor.
+ *
+ * @param \Iterator $iterator The Iterator to filter
+ * @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES)
+ */
+ public function __construct(\Iterator $iterator, $mode)
+ {
+ $this->mode = $mode;
+
+ parent::__construct($iterator);
+ }
+
+ /**
+ * Filters the iterator values.
+ *
+ * @return bool true if the value should be kept, false otherwise
+ */
+ public function accept()
+ {
+ $fileinfo = $this->current();
+ if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
+ return false;
+ } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilecontentFilterIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilecontentFilterIterator.php
new file mode 100644
index 0000000..28cf770
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilecontentFilterIterator.php
@@ -0,0 +1,76 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * FilecontentFilterIterator filters files by their contents using patterns (regexps or strings).
+ *
+ * @author Fabien Potencier
+ * @author WÅ‚odzimierz Gajda
+ */
+class FilecontentFilterIterator extends MultiplePcreFilterIterator
+{
+ /**
+ * Filters the iterator values.
+ *
+ * @return bool true if the value should be kept, false otherwise
+ */
+ public function accept()
+ {
+ if (!$this->matchRegexps && !$this->noMatchRegexps) {
+ return true;
+ }
+
+ $fileinfo = $this->current();
+
+ if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
+ return false;
+ }
+
+ $content = $fileinfo->getContents();
+ if (!$content) {
+ return false;
+ }
+
+ // should at least not match one rule to exclude
+ foreach ($this->noMatchRegexps as $regex) {
+ if (preg_match($regex, $content)) {
+ return false;
+ }
+ }
+
+ // should at least match one rule
+ $match = true;
+ if ($this->matchRegexps) {
+ $match = false;
+ foreach ($this->matchRegexps as $regex) {
+ if (preg_match($regex, $content)) {
+ return true;
+ }
+ }
+ }
+
+ return $match;
+ }
+
+ /**
+ * Converts string to regexp if necessary.
+ *
+ * @param string $str Pattern: string or regexp
+ *
+ * @return string regexp corresponding to a given string or regexp
+ */
+ protected function toRegex($str)
+ {
+ return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilenameFilterIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilenameFilterIterator.php
new file mode 100644
index 0000000..f1cd391
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilenameFilterIterator.php
@@ -0,0 +1,67 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+use Symfony\Component\Finder\Expression\Expression;
+
+/**
+ * FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).
+ *
+ * @author Fabien Potencier
+ */
+class FilenameFilterIterator extends MultiplePcreFilterIterator
+{
+ /**
+ * Filters the iterator values.
+ *
+ * @return bool true if the value should be kept, false otherwise
+ */
+ public function accept()
+ {
+ $filename = $this->current()->getFilename();
+
+ // should at least not match one rule to exclude
+ foreach ($this->noMatchRegexps as $regex) {
+ if (preg_match($regex, $filename)) {
+ return false;
+ }
+ }
+
+ // should at least match one rule
+ $match = true;
+ if ($this->matchRegexps) {
+ $match = false;
+ foreach ($this->matchRegexps as $regex) {
+ if (preg_match($regex, $filename)) {
+ return true;
+ }
+ }
+ }
+
+ return $match;
+ }
+
+ /**
+ * Converts glob to regexp.
+ *
+ * PCRE patterns are left unchanged.
+ * Glob strings are transformed with Glob::toRegex().
+ *
+ * @param string $str Pattern: glob or regexp
+ *
+ * @return string regexp corresponding to a given glob or regexp
+ */
+ protected function toRegex($str)
+ {
+ return Expression::create($str)->getRegex()->render();
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilterIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilterIterator.php
new file mode 100644
index 0000000..f4da44c
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilterIterator.php
@@ -0,0 +1,49 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * This iterator just overrides the rewind method in order to correct a PHP bug.
+ *
+ * @see https://bugs.php.net/bug.php?id=49104
+ *
+ * @author Alex Bogomazov
+ */
+abstract class FilterIterator extends \FilterIterator
+{
+ /**
+ * This is a workaround for the problem with \FilterIterator leaving inner \FilesystemIterator in wrong state after
+ * rewind in some cases.
+ *
+ * @see FilterIterator::rewind()
+ */
+ public function rewind()
+ {
+ $iterator = $this;
+ while ($iterator instanceof \OuterIterator) {
+ $innerIterator = $iterator->getInnerIterator();
+
+ if ($innerIterator instanceof RecursiveDirectoryIterator) {
+ if ($innerIterator->isRewindable()) {
+ $innerIterator->next();
+ $innerIterator->rewind();
+ }
+ } elseif ($iterator->getInnerIterator() instanceof \FilesystemIterator) {
+ $iterator->getInnerIterator()->next();
+ $iterator->getInnerIterator()->rewind();
+ }
+ $iterator = $iterator->getInnerIterator();
+ }
+
+ parent::rewind();
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/MultiplePcreFilterIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/MultiplePcreFilterIterator.php
new file mode 100644
index 0000000..068a7ef
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/MultiplePcreFilterIterator.php
@@ -0,0 +1,66 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+use Symfony\Component\Finder\Expression\Expression;
+
+/**
+ * MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).
+ *
+ * @author Fabien Potencier
+ */
+abstract class MultiplePcreFilterIterator extends FilterIterator
+{
+ protected $matchRegexps = array();
+ protected $noMatchRegexps = array();
+
+ /**
+ * Constructor.
+ *
+ * @param \Iterator $iterator The Iterator to filter
+ * @param array $matchPatterns An array of patterns that need to match
+ * @param array $noMatchPatterns An array of patterns that need to not match
+ */
+ public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
+ {
+ foreach ($matchPatterns as $pattern) {
+ $this->matchRegexps[] = $this->toRegex($pattern);
+ }
+
+ foreach ($noMatchPatterns as $pattern) {
+ $this->noMatchRegexps[] = $this->toRegex($pattern);
+ }
+
+ parent::__construct($iterator);
+ }
+
+ /**
+ * Checks whether the string is a regex.
+ *
+ * @param string $str
+ *
+ * @return bool Whether the given string is a regex
+ */
+ protected function isRegex($str)
+ {
+ return Expression::create($str)->isRegex();
+ }
+
+ /**
+ * Converts string into regexp.
+ *
+ * @param string $str Pattern
+ *
+ * @return string regexp corresponding to a given string
+ */
+ abstract protected function toRegex($str);
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/PathFilterIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/PathFilterIterator.php
new file mode 100644
index 0000000..2bb8ebd
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/PathFilterIterator.php
@@ -0,0 +1,74 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * PathFilterIterator filters files by path patterns (e.g. some/special/dir).
+ *
+ * @author Fabien Potencier
+ * @author WÅ‚odzimierz Gajda
+ */
+class PathFilterIterator extends MultiplePcreFilterIterator
+{
+ /**
+ * Filters the iterator values.
+ *
+ * @return bool true if the value should be kept, false otherwise
+ */
+ public function accept()
+ {
+ $filename = $this->current()->getRelativePathname();
+
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $filename = strtr($filename, '\\', '/');
+ }
+
+ // should at least not match one rule to exclude
+ foreach ($this->noMatchRegexps as $regex) {
+ if (preg_match($regex, $filename)) {
+ return false;
+ }
+ }
+
+ // should at least match one rule
+ $match = true;
+ if ($this->matchRegexps) {
+ $match = false;
+ foreach ($this->matchRegexps as $regex) {
+ if (preg_match($regex, $filename)) {
+ return true;
+ }
+ }
+ }
+
+ return $match;
+ }
+
+ /**
+ * Converts strings to regexp.
+ *
+ * PCRE patterns are left unchanged.
+ *
+ * Default conversion:
+ * 'lorem/ipsum/dolor' ==> 'lorem\/ipsum\/dolor/'
+ *
+ * Use only / as directory separator (on Windows also).
+ *
+ * @param string $str Pattern: regexp or dirname.
+ *
+ * @return string regexp corresponding to a given string or regexp
+ */
+ protected function toRegex($str)
+ {
+ return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php
new file mode 100644
index 0000000..af824d0
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php
@@ -0,0 +1,126 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+use Symfony\Component\Finder\Exception\AccessDeniedException;
+use Symfony\Component\Finder\SplFileInfo;
+
+/**
+ * Extends the \RecursiveDirectoryIterator to support relative paths.
+ *
+ * @author Victor Berchet
+ */
+class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
+{
+ /**
+ * @var bool
+ */
+ private $ignoreUnreadableDirs;
+
+ /**
+ * @var bool
+ */
+ private $rewindable;
+
+ /**
+ * Constructor.
+ *
+ * @param string $path
+ * @param int $flags
+ * @param bool $ignoreUnreadableDirs
+ *
+ * @throws \RuntimeException
+ */
+ public function __construct($path, $flags, $ignoreUnreadableDirs = false)
+ {
+ if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
+ throw new \RuntimeException('This iterator only support returning current as fileinfo.');
+ }
+
+ parent::__construct($path, $flags);
+ $this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
+ }
+
+ /**
+ * Return an instance of SplFileInfo with support for relative paths.
+ *
+ * @return SplFileInfo File information
+ */
+ public function current()
+ {
+ return new SplFileInfo(parent::current()->getPathname(), $this->getSubPath(), $this->getSubPathname());
+ }
+
+ /**
+ * @return \RecursiveIterator
+ *
+ * @throws AccessDeniedException
+ */
+ public function getChildren()
+ {
+ try {
+ $children = parent::getChildren();
+
+ if ($children instanceof self) {
+ // parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
+ $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
+ }
+
+ return $children;
+ } catch (\UnexpectedValueException $e) {
+ if ($this->ignoreUnreadableDirs) {
+ // If directory is unreadable and finder is set to ignore it, a fake empty content is returned.
+ return new \RecursiveArrayIterator(array());
+ } else {
+ throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+ }
+
+ /**
+ * Do nothing for non rewindable stream.
+ */
+ public function rewind()
+ {
+ if (false === $this->isRewindable()) {
+ return;
+ }
+
+ // @see https://bugs.php.net/bug.php?id=49104
+ parent::next();
+
+ parent::rewind();
+ }
+
+ /**
+ * Checks if the stream is rewindable.
+ *
+ * @return bool true when the stream is rewindable, false otherwise
+ */
+ public function isRewindable()
+ {
+ if (null !== $this->rewindable) {
+ return $this->rewindable;
+ }
+
+ if (false !== $stream = @opendir($this->getPath())) {
+ $infos = stream_get_meta_data($stream);
+ closedir($stream);
+
+ if ($infos['seekable']) {
+ return $this->rewindable = true;
+ }
+ }
+
+ return $this->rewindable = false;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/SizeRangeFilterIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/SizeRangeFilterIterator.php
new file mode 100644
index 0000000..3d3140a
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/SizeRangeFilterIterator.php
@@ -0,0 +1,59 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+use Symfony\Component\Finder\Comparator\NumberComparator;
+
+/**
+ * SizeRangeFilterIterator filters out files that are not in the given size range.
+ *
+ * @author Fabien Potencier
+ */
+class SizeRangeFilterIterator extends FilterIterator
+{
+ private $comparators = array();
+
+ /**
+ * Constructor.
+ *
+ * @param \Iterator $iterator The Iterator to filter
+ * @param NumberComparator[] $comparators An array of NumberComparator instances
+ */
+ public function __construct(\Iterator $iterator, array $comparators)
+ {
+ $this->comparators = $comparators;
+
+ parent::__construct($iterator);
+ }
+
+ /**
+ * Filters the iterator values.
+ *
+ * @return bool true if the value should be kept, false otherwise
+ */
+ public function accept()
+ {
+ $fileinfo = $this->current();
+ if (!$fileinfo->isFile()) {
+ return true;
+ }
+
+ $filesize = $fileinfo->getSize();
+ foreach ($this->comparators as $compare) {
+ if (!$compare->test($filesize)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/SortableIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/SortableIterator.php
new file mode 100644
index 0000000..b32ac8d
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Iterator/SortableIterator.php
@@ -0,0 +1,82 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * SortableIterator applies a sort on a given Iterator.
+ *
+ * @author Fabien Potencier
+ */
+class SortableIterator implements \IteratorAggregate
+{
+ const SORT_BY_NAME = 1;
+ const SORT_BY_TYPE = 2;
+ const SORT_BY_ACCESSED_TIME = 3;
+ const SORT_BY_CHANGED_TIME = 4;
+ const SORT_BY_MODIFIED_TIME = 5;
+
+ private $iterator;
+ private $sort;
+
+ /**
+ * Constructor.
+ *
+ * @param \Traversable $iterator The Iterator to filter
+ * @param int|callable $sort The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback)
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function __construct(\Traversable $iterator, $sort)
+ {
+ $this->iterator = $iterator;
+
+ if (self::SORT_BY_NAME === $sort) {
+ $this->sort = function ($a, $b) {
+ return strcmp($a->getRealpath(), $b->getRealpath());
+ };
+ } elseif (self::SORT_BY_TYPE === $sort) {
+ $this->sort = function ($a, $b) {
+ if ($a->isDir() && $b->isFile()) {
+ return -1;
+ } elseif ($a->isFile() && $b->isDir()) {
+ return 1;
+ }
+
+ return strcmp($a->getRealpath(), $b->getRealpath());
+ };
+ } elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
+ $this->sort = function ($a, $b) {
+ return ($a->getATime() - $b->getATime());
+ };
+ } elseif (self::SORT_BY_CHANGED_TIME === $sort) {
+ $this->sort = function ($a, $b) {
+ return ($a->getCTime() - $b->getCTime());
+ };
+ } elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
+ $this->sort = function ($a, $b) {
+ return ($a->getMTime() - $b->getMTime());
+ };
+ } elseif (is_callable($sort)) {
+ $this->sort = $sort;
+ } else {
+ throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
+ }
+ }
+
+ public function getIterator()
+ {
+ $array = iterator_to_array($this->iterator, true);
+ uasort($array, $this->sort);
+
+ return new \ArrayIterator($array);
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/LICENSE b/core/vendor/symfony/finder/Symfony/Component/Finder/LICENSE
new file mode 100644
index 0000000..43028bc
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2015 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/README.md b/core/vendor/symfony/finder/Symfony/Component/Finder/README.md
new file mode 100644
index 0000000..7a96219
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/README.md
@@ -0,0 +1,53 @@
+Finder Component
+================
+
+Finder finds files and directories via an intuitive fluent interface.
+
+```php
+use Symfony\Component\Finder\Finder;
+
+$finder = new Finder();
+
+$iterator = $finder
+ ->files()
+ ->name('*.php')
+ ->depth(0)
+ ->size('>= 1K')
+ ->in(__DIR__);
+
+foreach ($iterator as $file) {
+ print $file->getRealpath()."\n";
+}
+```
+
+The iterator returns instances of [Symfony\Component\Finder\SplFileInfo\SplFileInfo][1].
+Besides the build-in methods inherited from [\SplFileInfo][2] (`getPerms()`, `getSize()`, ...),
+you can also use `getRelativePath()` and `getRelativePathname()`. Read the
+[official documentation][3] for more information.
+
+But you can also use it to find files stored remotely like in this example where
+we are looking for files on Amazon S3:
+
+```php
+$s3 = new \Zend_Service_Amazon_S3($key, $secret);
+$s3->registerStreamWrapper("s3");
+
+$finder = new Finder();
+$finder->name('photos*')->size('< 100K')->date('since 1 hour ago');
+foreach ($finder->in('s3://bucket-name') as $file) {
+ print $file->getFilename()."\n";
+}
+```
+
+Resources
+---------
+
+You can run the unit tests with the following command:
+
+ $ cd path/to/Symfony/Component/Finder/
+ $ composer.phar install
+ $ phpunit
+
+[1]: http://api.symfony.com/2.5/Symfony/Component/Finder/SplFileInfo.html
+[2]: http://php.net/splfileinfo
+[3]: http://symfony.com/doc/current/components/finder.html#usage
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Shell/Command.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Shell/Command.php
new file mode 100644
index 0000000..1f69afb
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Shell/Command.php
@@ -0,0 +1,294 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Shell;
+
+/**
+ * @author Jean-François Simon
+ */
+class Command
+{
+ /**
+ * @var Command|null
+ */
+ private $parent;
+
+ /**
+ * @var array
+ */
+ private $bits = array();
+
+ /**
+ * @var array
+ */
+ private $labels = array();
+
+ /**
+ * @var \Closure|null
+ */
+ private $errorHandler;
+
+ /**
+ * Constructor.
+ *
+ * @param Command|null $parent Parent command
+ */
+ public function __construct(Command $parent = null)
+ {
+ $this->parent = $parent;
+ }
+
+ /**
+ * Returns command as string.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->join();
+ }
+
+ /**
+ * Creates a new Command instance.
+ *
+ * @param Command|null $parent Parent command
+ *
+ * @return Command New Command instance
+ */
+ public static function create(Command $parent = null)
+ {
+ return new self($parent);
+ }
+
+ /**
+ * Escapes special chars from input.
+ *
+ * @param string $input A string to escape
+ *
+ * @return string The escaped string
+ */
+ public static function escape($input)
+ {
+ return escapeshellcmd($input);
+ }
+
+ /**
+ * Quotes input.
+ *
+ * @param string $input An argument string
+ *
+ * @return string The quoted string
+ */
+ public static function quote($input)
+ {
+ return escapeshellarg($input);
+ }
+
+ /**
+ * Appends a string or a Command instance.
+ *
+ * @param string|Command $bit
+ *
+ * @return Command The current Command instance
+ */
+ public function add($bit)
+ {
+ $this->bits[] = $bit;
+
+ return $this;
+ }
+
+ /**
+ * Prepends a string or a command instance.
+ *
+ * @param string|Command $bit
+ *
+ * @return Command The current Command instance
+ */
+ public function top($bit)
+ {
+ array_unshift($this->bits, $bit);
+
+ foreach ($this->labels as $label => $index) {
+ $this->labels[$label] += 1;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Appends an argument, will be quoted.
+ *
+ * @param string $arg
+ *
+ * @return Command The current Command instance
+ */
+ public function arg($arg)
+ {
+ $this->bits[] = self::quote($arg);
+
+ return $this;
+ }
+
+ /**
+ * Appends escaped special command chars.
+ *
+ * @param string $esc
+ *
+ * @return Command The current Command instance
+ */
+ public function cmd($esc)
+ {
+ $this->bits[] = self::escape($esc);
+
+ return $this;
+ }
+
+ /**
+ * Inserts a labeled command to feed later.
+ *
+ * @param string $label The unique label
+ *
+ * @return Command The current Command instance
+ *
+ * @throws \RuntimeException If label already exists
+ */
+ public function ins($label)
+ {
+ if (isset($this->labels[$label])) {
+ throw new \RuntimeException(sprintf('Label "%s" already exists.', $label));
+ }
+
+ $this->bits[] = self::create($this);
+ $this->labels[$label] = count($this->bits)-1;
+
+ return $this->bits[$this->labels[$label]];
+ }
+
+ /**
+ * Retrieves a previously labeled command.
+ *
+ * @param string $label
+ *
+ * @return Command The labeled command
+ *
+ * @throws \RuntimeException
+ */
+ public function get($label)
+ {
+ if (!isset($this->labels[$label])) {
+ throw new \RuntimeException(sprintf('Label "%s" does not exist.', $label));
+ }
+
+ return $this->bits[$this->labels[$label]];
+ }
+
+ /**
+ * Returns parent command (if any).
+ *
+ * @return Command Parent command
+ *
+ * @throws \RuntimeException If command has no parent
+ */
+ public function end()
+ {
+ if (null === $this->parent) {
+ throw new \RuntimeException('Calling end on root command doesn\'t make sense.');
+ }
+
+ return $this->parent;
+ }
+
+ /**
+ * Counts bits stored in command.
+ *
+ * @return int The bits count
+ */
+ public function length()
+ {
+ return count($this->bits);
+ }
+
+ /**
+ * @param \Closure $errorHandler
+ *
+ * @return Command
+ */
+ public function setErrorHandler(\Closure $errorHandler)
+ {
+ $this->errorHandler = $errorHandler;
+
+ return $this;
+ }
+
+ /**
+ * @return \Closure|null
+ */
+ public function getErrorHandler()
+ {
+ return $this->errorHandler;
+ }
+
+ /**
+ * Executes current command.
+ *
+ * @return array The command result
+ *
+ * @throws \RuntimeException
+ */
+ public function execute()
+ {
+ if (null === $errorHandler = $this->errorHandler) {
+ exec($this->join(), $output);
+ } else {
+ $process = proc_open($this->join(), array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes);
+ $output = preg_split('~(\r\n|\r|\n)~', stream_get_contents($pipes[1]), -1, PREG_SPLIT_NO_EMPTY);
+
+ if ($error = stream_get_contents($pipes[2])) {
+ $errorHandler($error);
+ }
+
+ proc_close($process);
+ }
+
+ return $output ?: array();
+ }
+
+ /**
+ * Joins bits.
+ *
+ * @return string
+ */
+ public function join()
+ {
+ return implode(' ', array_filter(
+ array_map(function ($bit) {
+ return $bit instanceof Command ? $bit->join() : ($bit ?: null);
+ }, $this->bits),
+ function ($bit) { return null !== $bit; }
+ ));
+ }
+
+ /**
+ * Insert a string or a Command instance before the bit at given position $index (index starts from 0).
+ *
+ * @param string|Command $bit
+ * @param int $index
+ *
+ * @return Command The current Command instance
+ */
+ public function addAtIndex($bit, $index)
+ {
+ array_splice($this->bits, $index, 0, $bit);
+
+ return $this;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Shell/Shell.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Shell/Shell.php
new file mode 100644
index 0000000..6d7bff3
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Shell/Shell.php
@@ -0,0 +1,97 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Shell;
+
+/**
+ * @author Jean-François Simon
+ */
+class Shell
+{
+ const TYPE_UNIX = 1;
+ const TYPE_DARWIN = 2;
+ const TYPE_CYGWIN = 3;
+ const TYPE_WINDOWS = 4;
+ const TYPE_BSD = 5;
+
+ /**
+ * @var string|null
+ */
+ private $type;
+
+ /**
+ * Returns guessed OS type.
+ *
+ * @return int
+ */
+ public function getType()
+ {
+ if (null === $this->type) {
+ $this->type = $this->guessType();
+ }
+
+ return $this->type;
+ }
+
+ /**
+ * Tests if a command is available.
+ *
+ * @param string $command
+ *
+ * @return bool
+ */
+ public function testCommand($command)
+ {
+ if (!function_exists('exec')) {
+ return false;
+ }
+
+ // todo: find a better way (command could not be available)
+ $testCommand = 'which ';
+ if (self::TYPE_WINDOWS === $this->type) {
+ $testCommand = 'where ';
+ }
+
+ $command = escapeshellcmd($command);
+
+ exec($testCommand.$command, $output, $code);
+
+ return 0 === $code && count($output) > 0;
+ }
+
+ /**
+ * Guesses OS type.
+ *
+ * @return int
+ */
+ private function guessType()
+ {
+ $os = strtolower(PHP_OS);
+
+ if (false !== strpos($os, 'cygwin')) {
+ return self::TYPE_CYGWIN;
+ }
+
+ if (false !== strpos($os, 'darwin')) {
+ return self::TYPE_DARWIN;
+ }
+
+ if (false !== strpos($os, 'bsd')) {
+ return self::TYPE_BSD;
+ }
+
+ if (0 === strpos($os, 'win')) {
+ return self::TYPE_WINDOWS;
+ }
+
+ return self::TYPE_UNIX;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/SplFileInfo.php b/core/vendor/symfony/finder/Symfony/Component/Finder/SplFileInfo.php
new file mode 100644
index 0000000..c7fbe02
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/SplFileInfo.php
@@ -0,0 +1,77 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder;
+
+/**
+ * Extends \SplFileInfo to support relative paths.
+ *
+ * @author Fabien Potencier
+ */
+class SplFileInfo extends \SplFileInfo
+{
+ private $relativePath;
+ private $relativePathname;
+
+ /**
+ * Constructor.
+ *
+ * @param string $file The file name
+ * @param string $relativePath The relative path
+ * @param string $relativePathname The relative path name
+ */
+ public function __construct($file, $relativePath, $relativePathname)
+ {
+ parent::__construct($file);
+ $this->relativePath = $relativePath;
+ $this->relativePathname = $relativePathname;
+ }
+
+ /**
+ * Returns the relative path.
+ *
+ * @return string the relative path
+ */
+ public function getRelativePath()
+ {
+ return $this->relativePath;
+ }
+
+ /**
+ * Returns the relative path name.
+ *
+ * @return string the relative path name
+ */
+ public function getRelativePathname()
+ {
+ return $this->relativePathname;
+ }
+
+ /**
+ * Returns the contents of the file.
+ *
+ * @return string the contents of the file
+ *
+ * @throws \RuntimeException
+ */
+ public function getContents()
+ {
+ $level = error_reporting(0);
+ $content = file_get_contents($this->getPathname());
+ error_reporting($level);
+ if (false === $content) {
+ $error = error_get_last();
+ throw new \RuntimeException($error['message']);
+ }
+
+ return $content;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Comparator/ComparatorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Comparator/ComparatorTest.php
new file mode 100644
index 0000000..bf59844
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Comparator/ComparatorTest.php
@@ -0,0 +1,64 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Comparator;
+
+use Symfony\Component\Finder\Comparator\Comparator;
+
+class ComparatorTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGetSetOperator()
+ {
+ $comparator = new Comparator();
+ try {
+ $comparator->setOperator('foo');
+ $this->fail('->setOperator() throws an \InvalidArgumentException if the operator is not valid.');
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('InvalidArgumentException', $e, '->setOperator() throws an \InvalidArgumentException if the operator is not valid.');
+ }
+
+ $comparator = new Comparator();
+ $comparator->setOperator('>');
+ $this->assertEquals('>', $comparator->getOperator(), '->getOperator() returns the current operator');
+ }
+
+ public function testGetSetTarget()
+ {
+ $comparator = new Comparator();
+ $comparator->setTarget(8);
+ $this->assertEquals(8, $comparator->getTarget(), '->getTarget() returns the target');
+ }
+
+ /**
+ * @dataProvider getTestData
+ */
+ public function testTest($operator, $target, $match, $noMatch)
+ {
+ $c = new Comparator();
+ $c->setOperator($operator);
+ $c->setTarget($target);
+
+ foreach ($match as $m) {
+ $this->assertTrue($c->test($m), '->test() tests a string against the expression');
+ }
+
+ foreach ($noMatch as $m) {
+ $this->assertFalse($c->test($m), '->test() tests a string against the expression');
+ }
+ }
+
+ public function getTestData()
+ {
+ return array(
+ array('<', '1000', array('500', '999'), array('1000', '1500')),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Comparator/DateComparatorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Comparator/DateComparatorTest.php
new file mode 100644
index 0000000..2739126
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Comparator/DateComparatorTest.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Comparator;
+
+use Symfony\Component\Finder\Comparator\DateComparator;
+
+class DateComparatorTest extends \PHPUnit_Framework_TestCase
+{
+ public function testConstructor()
+ {
+ try {
+ new DateComparator('foobar');
+ $this->fail('__construct() throws an \InvalidArgumentException if the test expression is not valid.');
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException if the test expression is not valid.');
+ }
+
+ try {
+ new DateComparator('');
+ $this->fail('__construct() throws an \InvalidArgumentException if the test expression is not valid.');
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException if the test expression is not valid.');
+ }
+ }
+
+ /**
+ * @dataProvider getTestData
+ */
+ public function testTest($test, $match, $noMatch)
+ {
+ $c = new DateComparator($test);
+
+ foreach ($match as $m) {
+ $this->assertTrue($c->test($m), '->test() tests a string against the expression');
+ }
+
+ foreach ($noMatch as $m) {
+ $this->assertFalse($c->test($m), '->test() tests a string against the expression');
+ }
+ }
+
+ public function getTestData()
+ {
+ return array(
+ array('< 2005-10-10', array(strtotime('2005-10-09')), array(strtotime('2005-10-15'))),
+ array('until 2005-10-10', array(strtotime('2005-10-09')), array(strtotime('2005-10-15'))),
+ array('before 2005-10-10', array(strtotime('2005-10-09')), array(strtotime('2005-10-15'))),
+ array('> 2005-10-10', array(strtotime('2005-10-15')), array(strtotime('2005-10-09'))),
+ array('after 2005-10-10', array(strtotime('2005-10-15')), array(strtotime('2005-10-09'))),
+ array('since 2005-10-10', array(strtotime('2005-10-15')), array(strtotime('2005-10-09'))),
+ array('!= 2005-10-10', array(strtotime('2005-10-11')), array(strtotime('2005-10-10'))),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Comparator/NumberComparatorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Comparator/NumberComparatorTest.php
new file mode 100644
index 0000000..d8cef1b
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Comparator/NumberComparatorTest.php
@@ -0,0 +1,107 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Comparator;
+
+use Symfony\Component\Finder\Comparator\NumberComparator;
+
+class NumberComparatorTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getConstructorTestData
+ */
+ public function testConstructor($successes, $failures)
+ {
+ foreach ($successes as $s) {
+ new NumberComparator($s);
+ }
+
+ foreach ($failures as $f) {
+ try {
+ new NumberComparator($f);
+ $this->fail('__construct() throws an \InvalidArgumentException if the test expression is not valid.');
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException if the test expression is not valid.');
+ }
+ }
+ }
+
+ /**
+ * @dataProvider getTestData
+ */
+ public function testTest($test, $match, $noMatch)
+ {
+ $c = new NumberComparator($test);
+
+ foreach ($match as $m) {
+ $this->assertTrue($c->test($m), '->test() tests a string against the expression');
+ }
+
+ foreach ($noMatch as $m) {
+ $this->assertFalse($c->test($m), '->test() tests a string against the expression');
+ }
+ }
+
+ public function getTestData()
+ {
+ return array(
+ array('< 1000', array('500', '999'), array('1000', '1500')),
+
+ array('< 1K', array('500', '999'), array('1000', '1500')),
+ array('<1k', array('500', '999'), array('1000', '1500')),
+ array(' < 1 K ', array('500', '999'), array('1000', '1500')),
+ array('<= 1K', array('1000'), array('1001')),
+ array('> 1K', array('1001'), array('1000')),
+ array('>= 1K', array('1000'), array('999')),
+
+ array('< 1KI', array('500', '1023'), array('1024', '1500')),
+ array('<= 1KI', array('1024'), array('1025')),
+ array('> 1KI', array('1025'), array('1024')),
+ array('>= 1KI', array('1024'), array('1023')),
+
+ array('1KI', array('1024'), array('1023', '1025')),
+ array('==1KI', array('1024'), array('1023', '1025')),
+
+ array('==1m', array('1000000'), array('999999', '1000001')),
+ array('==1mi', array(1024*1024), array(1024*1024-1, 1024*1024+1)),
+
+ array('==1g', array('1000000000'), array('999999999', '1000000001')),
+ array('==1gi', array(1024*1024*1024), array(1024*1024*1024-1, 1024*1024*1024+1)),
+
+ array('!= 1000', array('500', '999'), array('1000')),
+ );
+ }
+
+ public function getConstructorTestData()
+ {
+ return array(
+ array(
+ array(
+ '1', '0',
+ '3.5', '33.55', '123.456', '123456.78',
+ '.1', '.123',
+ '.0', '0.0',
+ '1.', '0.', '123.',
+ '==1', '!=1', '<1', '>1', '<=1', '>=1',
+ '==1k', '==1ki', '==1m', '==1mi', '==1g', '==1gi',
+ '1k', '1ki', '1m', '1mi', '1g', '1gi',
+ ),
+ array(
+ false, null, '',
+ ' ', 'foobar',
+ '=1', '===1',
+ '0 . 1', '123 .45', '234. 567',
+ '..', '.0.', '0.1.2',
+ ),
+ ),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Expression/ExpressionTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Expression/ExpressionTest.php
new file mode 100644
index 0000000..4254a45
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Expression/ExpressionTest.php
@@ -0,0 +1,68 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Expression;
+
+use Symfony\Component\Finder\Expression\Expression;
+
+class ExpressionTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getTypeGuesserData
+ */
+ public function testTypeGuesser($expr, $type)
+ {
+ $this->assertEquals($type, Expression::create($expr)->getType());
+ }
+
+ /**
+ * @dataProvider getCaseSensitiveData
+ */
+ public function testCaseSensitive($expr, $isCaseSensitive)
+ {
+ $this->assertEquals($isCaseSensitive, Expression::create($expr)->isCaseSensitive());
+ }
+
+ /**
+ * @dataProvider getRegexRenderingData
+ */
+ public function testRegexRendering($expr, $body)
+ {
+ $this->assertEquals($body, Expression::create($expr)->renderPattern());
+ }
+
+ public function getTypeGuesserData()
+ {
+ return array(
+ array('{foo}', Expression::TYPE_REGEX),
+ array('/foo/', Expression::TYPE_REGEX),
+ array('foo', Expression::TYPE_GLOB),
+ array('foo*', Expression::TYPE_GLOB),
+ );
+ }
+
+ public function getCaseSensitiveData()
+ {
+ return array(
+ array('{foo}m', true),
+ array('/foo/i', false),
+ array('foo*', true),
+ );
+ }
+
+ public function getRegexRenderingData()
+ {
+ return array(
+ array('{foo}m', 'foo'),
+ array('/foo/i', 'foo'),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Expression/GlobTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Expression/GlobTest.php
new file mode 100644
index 0000000..9d4c3e5
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Expression/GlobTest.php
@@ -0,0 +1,47 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Expression;
+
+use Symfony\Component\Finder\Expression\Expression;
+
+class GlobTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getToRegexData
+ */
+ public function testGlobToRegex($glob, $match, $noMatch)
+ {
+ foreach ($match as $m) {
+ $this->assertRegExp(Expression::create($glob)->getRegex()->render(), $m, '::toRegex() converts a glob to a regexp');
+ }
+
+ foreach ($noMatch as $m) {
+ $this->assertNotRegExp(Expression::create($glob)->getRegex()->render(), $m, '::toRegex() converts a glob to a regexp');
+ }
+ }
+
+ public function getToRegexData()
+ {
+ return array(
+ array('', array(''), array('f', '/')),
+ array('*', array('foo'), array('foo/', '/foo')),
+ array('foo.*', array('foo.php', 'foo.a', 'foo.'), array('fooo.php', 'foo.php/foo')),
+ array('fo?', array('foo', 'fot'), array('fooo', 'ffoo', 'fo/')),
+ array('fo{o,t}', array('foo', 'fot'), array('fob', 'fo/')),
+ array('foo(bar|foo)', array('foo(bar|foo)'), array('foobar', 'foofoo')),
+ array('foo,bar', array('foo,bar'), array('foo', 'bar')),
+ array('fo{o,\\,}', array('foo', 'fo,'), array()),
+ array('fo{o,\\\\}', array('foo', 'fo\\'), array()),
+ array('/foo', array('/foo'), array('foo')),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Expression/RegexTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Expression/RegexTest.php
new file mode 100644
index 0000000..620ba10
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Expression/RegexTest.php
@@ -0,0 +1,143 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Expression;
+
+use Symfony\Component\Finder\Expression\Expression;
+
+class RegexTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getHasFlagsData
+ */
+ public function testHasFlags($regex, $start, $end)
+ {
+ $expr = new Expression($regex);
+
+ $this->assertEquals($start, $expr->getRegex()->hasStartFlag());
+ $this->assertEquals($end, $expr->getRegex()->hasEndFlag());
+ }
+
+ /**
+ * @dataProvider getHasJokersData
+ */
+ public function testHasJokers($regex, $start, $end)
+ {
+ $expr = new Expression($regex);
+
+ $this->assertEquals($start, $expr->getRegex()->hasStartJoker());
+ $this->assertEquals($end, $expr->getRegex()->hasEndJoker());
+ }
+
+ /**
+ * @dataProvider getSetFlagsData
+ */
+ public function testSetFlags($regex, $start, $end, $expected)
+ {
+ $expr = new Expression($regex);
+ $expr->getRegex()->setStartFlag($start)->setEndFlag($end);
+
+ $this->assertEquals($expected, $expr->render());
+ }
+
+ /**
+ * @dataProvider getSetJokersData
+ */
+ public function testSetJokers($regex, $start, $end, $expected)
+ {
+ $expr = new Expression($regex);
+ $expr->getRegex()->setStartJoker($start)->setEndJoker($end);
+
+ $this->assertEquals($expected, $expr->render());
+ }
+
+ public function testOptions()
+ {
+ $expr = new Expression('~abc~is');
+ $expr->getRegex()->removeOption('i')->addOption('m');
+
+ $this->assertEquals('~abc~sm', $expr->render());
+ }
+
+ public function testMixFlagsAndJokers()
+ {
+ $expr = new Expression('~^.*abc.*$~is');
+
+ $expr->getRegex()->setStartFlag(false)->setEndFlag(false)->setStartJoker(false)->setEndJoker(false);
+ $this->assertEquals('~abc~is', $expr->render());
+
+ $expr->getRegex()->setStartFlag(true)->setEndFlag(true)->setStartJoker(true)->setEndJoker(true);
+ $this->assertEquals('~^.*abc.*$~is', $expr->render());
+ }
+
+ /**
+ * @dataProvider getReplaceJokersTestData
+ */
+ public function testReplaceJokers($regex, $expected)
+ {
+ $expr = new Expression($regex);
+ $expr = $expr->getRegex()->replaceJokers('@');
+
+ $this->assertEquals($expected, $expr->renderPattern());
+ }
+
+ public function getHasFlagsData()
+ {
+ return array(
+ array('~^abc~', true, false),
+ array('~abc$~', false, true),
+ array('~abc~', false, false),
+ array('~^abc$~', true, true),
+ array('~^abc\\$~', true, false),
+ );
+ }
+
+ public function getHasJokersData()
+ {
+ return array(
+ array('~.*abc~', true, false),
+ array('~abc.*~', false, true),
+ array('~abc~', false, false),
+ array('~.*abc.*~', true, true),
+ array('~.*abc\\.*~', true, false),
+ );
+ }
+
+ public function getSetFlagsData()
+ {
+ return array(
+ array('~abc~', true, false, '~^abc~'),
+ array('~abc~', false, true, '~abc$~'),
+ array('~abc~', false, false, '~abc~'),
+ array('~abc~', true, true, '~^abc$~'),
+ );
+ }
+
+ public function getSetJokersData()
+ {
+ return array(
+ array('~abc~', true, false, '~.*abc~'),
+ array('~abc~', false, true, '~abc.*~'),
+ array('~abc~', false, false, '~abc~'),
+ array('~abc~', true, true, '~.*abc.*~'),
+ );
+ }
+
+ public function getReplaceJokersTestData()
+ {
+ return array(
+ array('~.abc~', '@abc'),
+ array('~\\.abc~', '\\.abc'),
+ array('~\\\\.abc~', '\\\\@abc'),
+ array('~\\\\\\.abc~', '\\\\\\.abc'),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/DummyAdapter.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/DummyAdapter.php
new file mode 100644
index 0000000..0cbae14
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/DummyAdapter.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\FakeAdapter;
+
+use Symfony\Component\Finder\Adapter\AbstractAdapter;
+
+/**
+ * @author Jean-François Simon
+ */
+class DummyAdapter extends AbstractAdapter
+{
+ /**
+ * @var \Iterator
+ */
+ private $iterator;
+
+ /**
+ * @param \Iterator $iterator
+ */
+ public function __construct(\Iterator $iterator)
+ {
+ $this->iterator = $iterator;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function searchInDirectory($dir)
+ {
+ return $this->iterator;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'yes';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function canBeUsed()
+ {
+ return true;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/FailingAdapter.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/FailingAdapter.php
new file mode 100644
index 0000000..6e6ed24
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/FailingAdapter.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\FakeAdapter;
+
+use Symfony\Component\Finder\Adapter\AbstractAdapter;
+use Symfony\Component\Finder\Exception\AdapterFailureException;
+
+/**
+ * @author Jean-François Simon
+ */
+class FailingAdapter extends AbstractAdapter
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function searchInDirectory($dir)
+ {
+ throw new AdapterFailureException($this);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'failing';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function canBeUsed()
+ {
+ return true;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/NamedAdapter.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/NamedAdapter.php
new file mode 100644
index 0000000..5a260b0
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/NamedAdapter.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\FakeAdapter;
+
+use Symfony\Component\Finder\Adapter\AbstractAdapter;
+
+/**
+ * @author Jean-François Simon
+ */
+class NamedAdapter extends AbstractAdapter
+{
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @param string $name
+ */
+ public function __construct($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function searchInDirectory($dir)
+ {
+ return new \ArrayIterator(array());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function canBeUsed()
+ {
+ return true;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/UnsupportedAdapter.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/UnsupportedAdapter.php
new file mode 100644
index 0000000..1f91b98
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FakeAdapter/UnsupportedAdapter.php
@@ -0,0 +1,44 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\FakeAdapter;
+
+use Symfony\Component\Finder\Adapter\AbstractAdapter;
+
+/**
+ * @author Jean-François Simon
+ */
+class UnsupportedAdapter extends AbstractAdapter
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function searchInDirectory($dir)
+ {
+ return new \ArrayIterator(array());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'unsupported';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function canBeUsed()
+ {
+ return false;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FinderTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FinderTest.php
new file mode 100644
index 0000000..12f0678
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/FinderTest.php
@@ -0,0 +1,869 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests;
+
+use Symfony\Component\Finder\Finder;
+use Symfony\Component\Finder\Adapter;
+
+class FinderTest extends Iterator\RealIteratorTestCase
+{
+ public function testCreate()
+ {
+ $this->assertInstanceOf('Symfony\Component\Finder\Finder', Finder::create());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testDirectories($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->directories());
+ $this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->directories();
+ $finder->files();
+ $finder->directories();
+ $this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testFiles($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->files());
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->files();
+ $finder->directories();
+ $finder->files();
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testDepth($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->depth('< 1'));
+ $this->assertIterator($this->toAbsolute(array('foo', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->depth('<= 0'));
+ $this->assertIterator($this->toAbsolute(array('foo', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->depth('>= 1'));
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->depth('< 1')->depth('>= 1');
+ $this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testName($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->name('*.php'));
+ $this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->name('test.ph*');
+ $finder->name('test.py');
+ $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->name('~^test~i');
+ $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->name('~\\.php$~i');
+ $this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->name('test.p{hp,y}');
+ $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testNotName($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->notName('*.php'));
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->notName('*.php');
+ $finder->notName('*.py');
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->name('test.ph*');
+ $finder->name('test.py');
+ $finder->notName('*.php');
+ $finder->notName('*.py');
+ $this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->name('test.ph*');
+ $finder->name('test.py');
+ $finder->notName('*.p{hp,y}');
+ $this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getRegexNameTestData
+ *
+ * @group regexName
+ */
+ public function testRegexName($adapter, $regex)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->name($regex);
+ $this->assertIterator($this->toAbsolute(array('test.py', 'test.php')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testSize($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->files()->size('< 1K')->size('> 500'));
+ $this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testDate($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->files()->date('until last month'));
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testExclude($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->exclude('foo'));
+ $this->assertIterator($this->toAbsolute(array('test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testIgnoreVCS($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->ignoreVCS(false)->ignoreDotFiles(false));
+ $this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->ignoreVCS(false)->ignoreVCS(false)->ignoreDotFiles(false);
+ $this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->ignoreVCS(true)->ignoreDotFiles(false));
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testIgnoreDotFiles($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->ignoreDotFiles(false)->ignoreVCS(false));
+ $this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $finder->ignoreDotFiles(false)->ignoreDotFiles(false)->ignoreVCS(false);
+ $this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->ignoreDotFiles(true)->ignoreVCS(false));
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testSortByName($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->sortByName());
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testSortByType($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->sortByType());
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'toto', 'foo/bar.tmp', 'test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testSortByAccessedTime($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->sortByAccessedTime());
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'toto', 'test.py', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testSortByChangedTime($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->sortByChangedTime());
+ $this->assertIterator($this->toAbsolute(array('toto', 'test.py', 'test.php', 'foo/bar.tmp', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testSortByModifiedTime($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->sortByModifiedTime());
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'toto', 'test.py', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testSort($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->sort(function (\SplFileInfo $a, \SplFileInfo $b) { return strcmp($a->getRealpath(), $b->getRealpath()); }));
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testFilter($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->filter(function (\SplFileInfo $f) { return preg_match('/test/', $f) > 0; }));
+ $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testFollowLinks($adapter)
+ {
+ if ('\\' == DIRECTORY_SEPARATOR) {
+ return;
+ }
+
+ $finder = $this->buildFinder($adapter);
+ $this->assertSame($finder, $finder->followLinks());
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testIn($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ try {
+ $finder->in('foobar');
+ $this->fail('->in() throws a \InvalidArgumentException if the directory does not exist');
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('InvalidArgumentException', $e, '->in() throws a \InvalidArgumentException if the directory does not exist');
+ }
+
+ $finder = $this->buildFinder($adapter);
+ $iterator = $finder->files()->name('*.php')->depth('< 1')->in(array(self::$tmpDir, __DIR__))->getIterator();
+
+ $this->assertIterator(array(self::$tmpDir.DIRECTORY_SEPARATOR.'test.php', __DIR__.DIRECTORY_SEPARATOR.'FinderTest.php'), $iterator);
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testInWithGlob($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->in(array(__DIR__.'/Fixtures/*/B/C', __DIR__.'/Fixtures/*/*/B/C'))->getIterator();
+
+ $this->assertIterator($this->toAbsoluteFixtures(array('A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy')), $finder);
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ * @expectedException \InvalidArgumentException
+ */
+ public function testInWithNonDirectoryGlob($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->in(__DIR__.'/Fixtures/A/a*');
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testInWithGlobBrace($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->in(array(__DIR__.'/Fixtures/{A,copy/A}/B/C'))->getIterator();
+
+ $this->assertIterator($this->toAbsoluteFixtures(array('A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy')), $finder);
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testGetIterator($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ try {
+ $finder->getIterator();
+ $this->fail('->getIterator() throws a \LogicException if the in() method has not been called');
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('LogicException', $e, '->getIterator() throws a \LogicException if the in() method has not been called');
+ }
+
+ $finder = $this->buildFinder($adapter);
+ $dirs = array();
+ foreach ($finder->directories()->in(self::$tmpDir) as $dir) {
+ $dirs[] = (string) $dir;
+ }
+
+ $expected = $this->toAbsolute(array('foo', 'toto'));
+
+ sort($dirs);
+ sort($expected);
+
+ $this->assertEquals($expected, $dirs, 'implements the \IteratorAggregate interface');
+
+ $finder = $this->buildFinder($adapter);
+ $this->assertEquals(2, iterator_count($finder->directories()->in(self::$tmpDir)), 'implements the \IteratorAggregate interface');
+
+ $finder = $this->buildFinder($adapter);
+ $a = iterator_to_array($finder->directories()->in(self::$tmpDir));
+ $a = array_values(array_map(function ($a) { return (string) $a; }, $a));
+ sort($a);
+ $this->assertEquals($expected, $a, 'implements the \IteratorAggregate interface');
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testRelativePath($adapter)
+ {
+ $finder = $this->buildFinder($adapter)->in(self::$tmpDir);
+
+ $paths = array();
+
+ foreach ($finder as $file) {
+ $paths[] = $file->getRelativePath();
+ }
+
+ $ref = array("", "", "", "", "foo", "");
+
+ sort($ref);
+ sort($paths);
+
+ $this->assertEquals($ref, $paths);
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testRelativePathname($adapter)
+ {
+ $finder = $this->buildFinder($adapter)->in(self::$tmpDir)->sortByName();
+
+ $paths = array();
+
+ foreach ($finder as $file) {
+ $paths[] = $file->getRelativePathname();
+ }
+
+ $ref = array("test.php", "toto", "test.py", "foo", "foo".DIRECTORY_SEPARATOR."bar.tmp", "foo bar");
+
+ sort($paths);
+ sort($ref);
+
+ $this->assertEquals($ref, $paths);
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testAppendWithAFinder($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->files()->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
+
+ $finder1 = $this->buildFinder($adapter);
+ $finder1->directories()->in(self::$tmpDir);
+
+ $finder = $finder->append($finder1);
+
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto')), $finder->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testAppendWithAnArray($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->files()->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
+
+ $finder->append($this->toAbsolute(array('foo', 'toto')));
+
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto')), $finder->getIterator());
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testAppendReturnsAFinder($adapter)
+ {
+ $this->assertInstanceOf('Symfony\\Component\\Finder\\Finder', $this->buildFinder($adapter)->append(array()));
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testAppendDoesNotRequireIn($adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
+
+ $finder1 = Finder::create()->append($finder);
+
+ $this->assertIterator(iterator_to_array($finder->getIterator()), $finder1->getIterator());
+ }
+
+ public function testCountDirectories()
+ {
+ $directory = Finder::create()->directories()->in(self::$tmpDir);
+ $i = 0;
+
+ foreach ($directory as $dir) {
+ $i++;
+ }
+
+ $this->assertCount($i, $directory);
+ }
+
+ public function testCountFiles()
+ {
+ $files = Finder::create()->files()->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures');
+ $i = 0;
+
+ foreach ($files as $file) {
+ $i++;
+ }
+
+ $this->assertCount($i, $files);
+ }
+
+ /**
+ * @expectedException \LogicException
+ */
+ public function testCountWithoutIn()
+ {
+ $finder = Finder::create()->files();
+ count($finder);
+ }
+
+ /**
+ * @dataProvider getContainsTestData
+ * @group grep
+ */
+ public function testContains($adapter, $matchPatterns, $noMatchPatterns, $expected)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures')
+ ->name('*.txt')->sortByName()
+ ->contains($matchPatterns)
+ ->notContains($noMatchPatterns);
+
+ $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testContainsOnDirectory(Adapter\AdapterInterface $adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->in(__DIR__)
+ ->directories()
+ ->name('Fixtures')
+ ->contains('abc');
+ $this->assertIterator(array(), $finder);
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testNotContainsOnDirectory(Adapter\AdapterInterface $adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->in(__DIR__)
+ ->directories()
+ ->name('Fixtures')
+ ->notContains('abc');
+ $this->assertIterator(array(), $finder);
+ }
+
+ /**
+ * Searching in multiple locations involves AppendIterator which does an unnecessary rewind which leaves FilterIterator
+ * with inner FilesystemIterator in an invalid state.
+ *
+ * @see https://bugs.php.net/bug.php?id=49104
+ *
+ * @dataProvider getAdaptersTestData
+ */
+ public function testMultipleLocations(Adapter\AdapterInterface $adapter)
+ {
+ $locations = array(
+ self::$tmpDir.'/',
+ self::$tmpDir.'/toto/',
+ );
+
+ // it is expected that there are test.py test.php in the tmpDir
+ $finder = $this->buildFinder($adapter);
+ $finder->in($locations)->depth('< 1')->name('test.php');
+
+ $this->assertCount(1, $finder);
+ }
+
+ /**
+ * Iterator keys must be the file pathname.
+ *
+ * @dataProvider getAdaptersTestData
+ */
+ public function testIteratorKeys(Adapter\AdapterInterface $adapter)
+ {
+ $finder = $this->buildFinder($adapter)->in(self::$tmpDir);
+ foreach ($finder as $key => $file) {
+ $this->assertEquals($file->getPathname(), $key);
+ }
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testRegexSpecialCharsLocationWithPathRestrictionContainingStartFlag(Adapter\AdapterInterface $adapter)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'r+e.gex[c]a(r)s')
+ ->path('/^dir/');
+
+ $expected = array('r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir',
+ 'r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'bar.dat',);
+ $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
+ }
+
+ public function testAdaptersOrdering()
+ {
+ $finder = Finder::create()
+ ->removeAdapters()
+ ->addAdapter(new FakeAdapter\NamedAdapter('a'), 0)
+ ->addAdapter(new FakeAdapter\NamedAdapter('b'), -50)
+ ->addAdapter(new FakeAdapter\NamedAdapter('c'), 50)
+ ->addAdapter(new FakeAdapter\NamedAdapter('d'), -25)
+ ->addAdapter(new FakeAdapter\NamedAdapter('e'), 25);
+
+ $this->assertEquals(
+ array('c', 'e', 'a', 'd', 'b'),
+ array_map(function (Adapter\AdapterInterface $adapter) {
+ return $adapter->getName();
+ }, $finder->getAdapters())
+ );
+ }
+
+ public function testAdaptersChaining()
+ {
+ $iterator = new \ArrayIterator(array());
+ $filenames = $this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto'));
+ foreach ($filenames as $file) {
+ $iterator->append(new \Symfony\Component\Finder\SplFileInfo($file, null, null));
+ }
+
+ $finder = Finder::create()
+ ->removeAdapters()
+ ->addAdapter(new FakeAdapter\UnsupportedAdapter(), 3)
+ ->addAdapter(new FakeAdapter\FailingAdapter(), 2)
+ ->addAdapter(new FakeAdapter\DummyAdapter($iterator), 1);
+
+ $this->assertIterator($filenames, $finder->in(sys_get_temp_dir())->getIterator());
+ }
+
+ public function getAdaptersTestData()
+ {
+ return array_map(
+ function ($adapter) { return array($adapter); },
+ $this->getValidAdapters()
+ );
+ }
+
+ public function getContainsTestData()
+ {
+ $tests = array(
+ array('', '', array()),
+ array('foo', 'bar', array()),
+ array('', 'foobar', array('dolor.txt', 'ipsum.txt', 'lorem.txt')),
+ array('lorem ipsum dolor sit amet', 'foobar', array('lorem.txt')),
+ array('sit', 'bar', array('dolor.txt', 'ipsum.txt', 'lorem.txt')),
+ array('dolor sit amet', '@^L@m', array('dolor.txt', 'ipsum.txt')),
+ array('/^lorem ipsum dolor sit amet$/m', 'foobar', array('lorem.txt')),
+ array('lorem', 'foobar', array('lorem.txt')),
+ array('', 'lorem', array('dolor.txt', 'ipsum.txt')),
+ array('ipsum dolor sit amet', '/^IPSUM/m', array('lorem.txt')),
+ );
+
+ return $this->buildTestData($tests);
+ }
+
+ public function getRegexNameTestData()
+ {
+ $tests = array(
+ array('~.+\\.p.+~i'),
+ array('~t.*s~i'),
+ );
+
+ return $this->buildTestData($tests);
+ }
+
+ /**
+ * @dataProvider getTestPathData
+ */
+ public function testPath(Adapter\AdapterInterface $adapter, $matchPatterns, $noMatchPatterns, array $expected)
+ {
+ $finder = $this->buildFinder($adapter);
+ $finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures')
+ ->path($matchPatterns)
+ ->notPath($noMatchPatterns);
+
+ $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
+ }
+
+ public function testAdapterSelection()
+ {
+ // test that by default, PhpAdapter is selected
+ $adapters = Finder::create()->getAdapters();
+ $this->assertTrue($adapters[0] instanceof Adapter\PhpAdapter);
+
+ // test another adapter selection
+ $adapters = Finder::create()->setAdapter('gnu_find')->getAdapters();
+ $this->assertTrue($adapters[0] instanceof Adapter\GnuFindAdapter);
+
+ // test that useBestAdapter method removes selection
+ $adapters = Finder::create()->useBestAdapter()->getAdapters();
+ $this->assertFalse($adapters[0] instanceof Adapter\PhpAdapter);
+ }
+
+ public function getTestPathData()
+ {
+ $tests = array(
+ array('', '', array()),
+ array('/^A\/B\/C/', '/C$/',
+ array('A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat'),
+ ),
+ array('/^A\/B/', 'foobar',
+ array(
+ 'A'.DIRECTORY_SEPARATOR.'B',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
+ ),
+ ),
+ array('A/B/C', 'foobar',
+ array(
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat.copy',
+ ),
+ ),
+ array('A/B', 'foobar',
+ array(
+ //dirs
+ 'A'.DIRECTORY_SEPARATOR.'B',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
+ //files
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat.copy',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat.copy',
+ ),
+ ),
+ array('/^with space\//', 'foobar',
+ array(
+ 'with space'.DIRECTORY_SEPARATOR.'foo.txt',
+ ),
+ ),
+ );
+
+ return $this->buildTestData($tests);
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testAccessDeniedException(Adapter\AdapterInterface $adapter)
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('chmod is not supported on Windows');
+ }
+
+ $finder = $this->buildFinder($adapter);
+ $finder->files()->in(self::$tmpDir);
+
+ // make 'foo' directory non-readable
+ $testDir = self::$tmpDir.DIRECTORY_SEPARATOR.'foo';
+ chmod($testDir, 0333);
+
+ if (false === $couldRead = is_readable($testDir)) {
+ try {
+ $this->assertIterator($this->toAbsolute(array('foo bar', 'test.php', 'test.py')), $finder->getIterator());
+ $this->fail('Finder should throw an exception when opening a non-readable directory.');
+ } catch (\Exception $e) {
+ $expectedExceptionClass = 'Symfony\\Component\\Finder\\Exception\\AccessDeniedException';
+ if ($e instanceof \PHPUnit_Framework_ExpectationFailedException) {
+ $this->fail(sprintf("Expected exception:\n%s\nGot:\n%s\nWith comparison failure:\n%s", $expectedExceptionClass, 'PHPUnit_Framework_ExpectationFailedException', $e->getComparisonFailure()->getExpectedAsString()));
+ }
+
+ $this->assertInstanceOf($expectedExceptionClass, $e);
+ }
+ }
+
+ // restore original permissions
+ chmod($testDir, 0777);
+ clearstatcache($testDir);
+
+ if ($couldRead) {
+ $this->markTestSkipped('could read test files while test requires unreadable');
+ }
+ }
+
+ /**
+ * @dataProvider getAdaptersTestData
+ */
+ public function testIgnoredAccessDeniedException(Adapter\AdapterInterface $adapter)
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('chmod is not supported on Windows');
+ }
+
+ $finder = $this->buildFinder($adapter);
+ $finder->files()->ignoreUnreadableDirs()->in(self::$tmpDir);
+
+ // make 'foo' directory non-readable
+ $testDir = self::$tmpDir.DIRECTORY_SEPARATOR.'foo';
+ chmod($testDir, 0333);
+
+ if (false === ($couldRead = is_readable($testDir))) {
+ $this->assertIterator($this->toAbsolute(array('foo bar', 'test.php', 'test.py')), $finder->getIterator());
+ }
+
+ // restore original permissions
+ chmod($testDir, 0777);
+ clearstatcache($testDir);
+
+ if ($couldRead) {
+ $this->markTestSkipped('could read test files while test requires unreadable');
+ }
+ }
+
+ private function buildTestData(array $tests)
+ {
+ $data = array();
+ foreach ($this->getValidAdapters() as $adapter) {
+ foreach ($tests as $test) {
+ $data[] = array_merge(array($adapter), $test);
+ }
+ }
+
+ return $data;
+ }
+
+ private function buildFinder(Adapter\AdapterInterface $adapter)
+ {
+ return Finder::create()
+ ->removeAdapters()
+ ->addAdapter($adapter);
+ }
+
+ private function getValidAdapters()
+ {
+ return array_filter(
+ array(
+ new Adapter\BsdFindAdapter(),
+ new Adapter\GnuFindAdapter(),
+ new Adapter\PhpAdapter(),
+ ),
+ function (Adapter\AdapterInterface $adapter) {
+ return $adapter->isSupported();
+ }
+ );
+ }
+
+ /**
+ * Searching in multiple locations with sub directories involves
+ * AppendIterator which does an unnecessary rewind which leaves
+ * FilterIterator with inner FilesystemIterator in an invalid state.
+ *
+ * @see https://bugs.php.net/bug.php?id=49104
+ */
+ public function testMultipleLocationsWithSubDirectories()
+ {
+ $locations = array(
+ __DIR__.'/Fixtures/one',
+ self::$tmpDir.DIRECTORY_SEPARATOR.'toto',
+ );
+
+ $finder = new Finder();
+ $finder->in($locations)->depth('< 10')->name('*.neon');
+
+ $expected = array(
+ __DIR__.'/Fixtures/one'.DIRECTORY_SEPARATOR.'b'.DIRECTORY_SEPARATOR.'c.neon',
+ __DIR__.'/Fixtures/one'.DIRECTORY_SEPARATOR.'b'.DIRECTORY_SEPARATOR.'d.neon',
+ );
+
+ $this->assertIterator($expected, $finder);
+ $this->assertIteratorInForeach($expected, $finder);
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/A/B/C/abc.dat b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/A/B/C/abc.dat
new file mode 100644
index 0000000..e69de29
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/A/B/ab.dat b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/A/B/ab.dat
new file mode 100644
index 0000000..e69de29
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/A/a.dat b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/A/a.dat
new file mode 100644
index 0000000..e69de29
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/copy/A/B/C/abc.dat.copy b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/copy/A/B/C/abc.dat.copy
new file mode 100644
index 0000000..e69de29
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/copy/A/B/ab.dat.copy b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/copy/A/B/ab.dat.copy
new file mode 100644
index 0000000..e69de29
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/copy/A/a.dat.copy b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/copy/A/a.dat.copy
new file mode 100644
index 0000000..e69de29
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/dolor.txt b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/dolor.txt
new file mode 100644
index 0000000..658bec6
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/dolor.txt
@@ -0,0 +1,2 @@
+dolor sit amet
+DOLOR SIT AMET
\ No newline at end of file
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/ipsum.txt b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/ipsum.txt
new file mode 100644
index 0000000..c7f392d
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/ipsum.txt
@@ -0,0 +1,2 @@
+ipsum dolor sit amet
+IPSUM DOLOR SIT AMET
\ No newline at end of file
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/lorem.txt b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/lorem.txt
new file mode 100644
index 0000000..2991a2c
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/lorem.txt
@@ -0,0 +1,2 @@
+lorem ipsum dolor sit amet
+LOREM IPSUM DOLOR SIT AMET
\ No newline at end of file
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/one/a b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/one/a
new file mode 100644
index 0000000..e69de29
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/one/b/c.neon b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/one/b/c.neon
new file mode 100644
index 0000000..e69de29
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/one/b/d.neon b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/one/b/d.neon
new file mode 100644
index 0000000..e69de29
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/r+e.gex[c]a(r)s/dir/bar.dat b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/r+e.gex[c]a(r)s/dir/bar.dat
new file mode 100644
index 0000000..e69de29
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/with space/foo.txt b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Fixtures/with space/foo.txt
new file mode 100644
index 0000000..e69de29
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/CustomFilterIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/CustomFilterIteratorTest.php
new file mode 100644
index 0000000..62629b1
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/CustomFilterIteratorTest.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\CustomFilterIterator;
+
+class CustomFilterIteratorTest extends IteratorTestCase
+{
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testWithInvalidFilter()
+ {
+ new CustomFilterIterator(new Iterator(), array('foo'));
+ }
+
+ /**
+ * @dataProvider getAcceptData
+ */
+ public function testAccept($filters, $expected)
+ {
+ $inner = new Iterator(array('test.php', 'test.py', 'foo.php'));
+
+ $iterator = new CustomFilterIterator($inner, $filters);
+
+ $this->assertIterator($expected, $iterator);
+ }
+
+ public function getAcceptData()
+ {
+ return array(
+ array(array(function (\SplFileInfo $fileinfo) { return false; }), array()),
+ array(array(function (\SplFileInfo $fileinfo) { return preg_match('/^test/', $fileinfo) > 0; }), array('test.php', 'test.py')),
+ array(array('is_dir'), array()),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/DateRangeFilterIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/DateRangeFilterIteratorTest.php
new file mode 100644
index 0000000..709d5fe
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/DateRangeFilterIteratorTest.php
@@ -0,0 +1,72 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
+use Symfony\Component\Finder\Comparator\DateComparator;
+
+class DateRangeFilterIteratorTest extends RealIteratorTestCase
+{
+ /**
+ * @dataProvider getAcceptData
+ */
+ public function testAccept($size, $expected)
+ {
+ $files = self::$files;
+ $files[] = self::toAbsolute('doesnotexist');
+ $inner = new Iterator($files);
+
+ $iterator = new DateRangeFilterIterator($inner, $size);
+
+ $this->assertIterator($expected, $iterator);
+ }
+
+ public function getAcceptData()
+ {
+ $since20YearsAgo = array(
+ '.git',
+ 'test.py',
+ 'foo',
+ 'foo/bar.tmp',
+ 'test.php',
+ 'toto',
+ '.bar',
+ '.foo',
+ '.foo/.bar',
+ 'foo bar',
+ '.foo/bar',
+ );
+
+ $since2MonthsAgo = array(
+ '.git',
+ 'test.py',
+ 'foo',
+ 'toto',
+ '.bar',
+ '.foo',
+ '.foo/.bar',
+ 'foo bar',
+ '.foo/bar',
+ );
+
+ $untilLastMonth = array(
+ 'foo/bar.tmp',
+ 'test.php',
+ );
+
+ return array(
+ array(array(new DateComparator('since 20 years ago')), $this->toAbsolute($since20YearsAgo)),
+ array(array(new DateComparator('since 2 months ago')), $this->toAbsolute($since2MonthsAgo)),
+ array(array(new DateComparator('until last month')), $this->toAbsolute($untilLastMonth)),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/DepthRangeFilterIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/DepthRangeFilterIteratorTest.php
new file mode 100644
index 0000000..5ec9832
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/DepthRangeFilterIteratorTest.php
@@ -0,0 +1,80 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
+
+class DepthRangeFilterIteratorTest extends RealIteratorTestCase
+{
+ /**
+ * @dataProvider getAcceptData
+ */
+ public function testAccept($minDepth, $maxDepth, $expected)
+ {
+ $inner = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->toAbsolute(), \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
+
+ $iterator = new DepthRangeFilterIterator($inner, $minDepth, $maxDepth);
+
+ $actual = array_keys(iterator_to_array($iterator));
+ sort($expected);
+ sort($actual);
+ $this->assertEquals($expected, $actual);
+ }
+
+ public function getAcceptData()
+ {
+ $lessThan1 = array(
+ '.git',
+ 'test.py',
+ 'foo',
+ 'test.php',
+ 'toto',
+ '.foo',
+ '.bar',
+ 'foo bar',
+ );
+
+ $lessThanOrEqualTo1 = array(
+ '.git',
+ 'test.py',
+ 'foo',
+ 'foo/bar.tmp',
+ 'test.php',
+ 'toto',
+ '.foo',
+ '.foo/.bar',
+ '.bar',
+ 'foo bar',
+ '.foo/bar',
+ );
+
+ $graterThanOrEqualTo1 = array(
+ 'foo/bar.tmp',
+ '.foo/.bar',
+ '.foo/bar',
+ );
+
+ $equalTo1 = array(
+ 'foo/bar.tmp',
+ '.foo/.bar',
+ '.foo/bar',
+ );
+
+ return array(
+ array(0, 0, $this->toAbsolute($lessThan1)),
+ array(0, 1, $this->toAbsolute($lessThanOrEqualTo1)),
+ array(2, PHP_INT_MAX, array()),
+ array(1, PHP_INT_MAX, $this->toAbsolute($graterThanOrEqualTo1)),
+ array(1, 1, $this->toAbsolute($equalTo1)),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php
new file mode 100644
index 0000000..693b733
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php
@@ -0,0 +1,64 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
+use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
+
+class ExcludeDirectoryFilterIteratorTest extends RealIteratorTestCase
+{
+ /**
+ * @dataProvider getAcceptData
+ */
+ public function testAccept($directories, $expected)
+ {
+ $inner = new \RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->toAbsolute(), \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
+
+ $iterator = new ExcludeDirectoryFilterIterator($inner, $directories);
+
+ $this->assertIterator($expected, $iterator);
+ }
+
+ public function getAcceptData()
+ {
+ $foo = array(
+ '.bar',
+ '.foo',
+ '.foo/.bar',
+ '.foo/bar',
+ '.git',
+ 'test.py',
+ 'test.php',
+ 'toto',
+ 'foo bar',
+ );
+
+ $fo = array(
+ '.bar',
+ '.foo',
+ '.foo/.bar',
+ '.foo/bar',
+ '.git',
+ 'test.py',
+ 'foo',
+ 'foo/bar.tmp',
+ 'test.php',
+ 'toto',
+ 'foo bar',
+ );
+
+ return array(
+ array(array('foo'), $this->toAbsolute($foo)),
+ array(array('fo'), $this->toAbsolute($fo)),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilePathsIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilePathsIteratorTest.php
new file mode 100644
index 0000000..89853a8
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilePathsIteratorTest.php
@@ -0,0 +1,66 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\FilePathsIterator;
+
+class FilePathsIteratorTest extends RealIteratorTestCase
+{
+ /**
+ * @dataProvider getSubPathData
+ */
+ public function testSubPath($baseDir, array $paths, array $subPaths, array $subPathnames)
+ {
+ $iterator = new FilePathsIterator($paths, $baseDir);
+
+ foreach ($iterator as $index => $file) {
+ $this->assertEquals($paths[$index], $file->getPathname());
+ $this->assertEquals($subPaths[$index], $iterator->getSubPath());
+ $this->assertEquals($subPathnames[$index], $iterator->getSubPathname());
+ }
+ }
+
+ public function getSubPathData()
+ {
+ $tmpDir = sys_get_temp_dir().'/symfony_finder';
+
+ return array(
+ array(
+ $tmpDir,
+ array( // paths
+ $tmpDir.DIRECTORY_SEPARATOR.'.git' => $tmpDir.DIRECTORY_SEPARATOR.'.git',
+ $tmpDir.DIRECTORY_SEPARATOR.'test.py' => $tmpDir.DIRECTORY_SEPARATOR.'test.py',
+ $tmpDir.DIRECTORY_SEPARATOR.'foo' => $tmpDir.DIRECTORY_SEPARATOR.'foo',
+ $tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp' => $tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp',
+ $tmpDir.DIRECTORY_SEPARATOR.'test.php' => $tmpDir.DIRECTORY_SEPARATOR.'test.php',
+ $tmpDir.DIRECTORY_SEPARATOR.'toto' => $tmpDir.DIRECTORY_SEPARATOR.'toto',
+ ),
+ array( // subPaths
+ $tmpDir.DIRECTORY_SEPARATOR.'.git' => '',
+ $tmpDir.DIRECTORY_SEPARATOR.'test.py' => '',
+ $tmpDir.DIRECTORY_SEPARATOR.'foo' => '',
+ $tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp' => 'foo',
+ $tmpDir.DIRECTORY_SEPARATOR.'test.php' => '',
+ $tmpDir.DIRECTORY_SEPARATOR.'toto' => '',
+ ),
+ array( // subPathnames
+ $tmpDir.DIRECTORY_SEPARATOR.'.git' => '.git',
+ $tmpDir.DIRECTORY_SEPARATOR.'test.py' => 'test.py',
+ $tmpDir.DIRECTORY_SEPARATOR.'foo' => 'foo',
+ $tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp' => 'foo'.DIRECTORY_SEPARATOR.'bar.tmp',
+ $tmpDir.DIRECTORY_SEPARATOR.'test.php' => 'test.php',
+ $tmpDir.DIRECTORY_SEPARATOR.'toto' => 'toto',
+ ),
+ ),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FileTypeFilterIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FileTypeFilterIteratorTest.php
new file mode 100644
index 0000000..cfa8684
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FileTypeFilterIteratorTest.php
@@ -0,0 +1,72 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\FileTypeFilterIterator;
+
+class FileTypeFilterIteratorTest extends RealIteratorTestCase
+{
+ /**
+ * @dataProvider getAcceptData
+ */
+ public function testAccept($mode, $expected)
+ {
+ $inner = new InnerTypeIterator(self::$files);
+
+ $iterator = new FileTypeFilterIterator($inner, $mode);
+
+ $this->assertIterator($expected, $iterator);
+ }
+
+ public function getAcceptData()
+ {
+ $onlyFiles = array(
+ 'test.py',
+ 'foo/bar.tmp',
+ 'test.php',
+ '.bar',
+ '.foo/.bar',
+ '.foo/bar',
+ 'foo bar',
+ );
+
+ $onlyDirectories = array(
+ '.git',
+ 'foo',
+ 'toto',
+ '.foo',
+ );
+
+ return array(
+ array(FileTypeFilterIterator::ONLY_FILES, $this->toAbsolute($onlyFiles)),
+ array(FileTypeFilterIterator::ONLY_DIRECTORIES, $this->toAbsolute($onlyDirectories)),
+ );
+ }
+}
+
+class InnerTypeIterator extends \ArrayIterator
+{
+ public function current()
+ {
+ return new \SplFileInfo(parent::current());
+ }
+
+ public function isFile()
+ {
+ return $this->current()->isFile();
+ }
+
+ public function isDir()
+ {
+ return $this->current()->isDir();
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilecontentFilterIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilecontentFilterIteratorTest.php
new file mode 100644
index 0000000..744bdae
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilecontentFilterIteratorTest.php
@@ -0,0 +1,86 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
+
+class FilecontentFilterIteratorTest extends IteratorTestCase
+{
+ public function testAccept()
+ {
+ $inner = new MockFileListIterator(array('test.txt'));
+ $iterator = new FilecontentFilterIterator($inner, array(), array());
+ $this->assertIterator(array('test.txt'), $iterator);
+ }
+
+ public function testDirectory()
+ {
+ $inner = new MockFileListIterator(array('directory'));
+ $iterator = new FilecontentFilterIterator($inner, array('directory'), array());
+ $this->assertIterator(array(), $iterator);
+ }
+
+ public function testUnreadableFile()
+ {
+ $inner = new MockFileListIterator(array('file r-'));
+ $iterator = new FilecontentFilterIterator($inner, array('file r-'), array());
+ $this->assertIterator(array(), $iterator);
+ }
+
+ /**
+ * @dataProvider getTestFilterData
+ */
+ public function testFilter(\Iterator $inner, array $matchPatterns, array $noMatchPatterns, array $resultArray)
+ {
+ $iterator = new FilecontentFilterIterator($inner, $matchPatterns, $noMatchPatterns);
+ $this->assertIterator($resultArray, $iterator);
+ }
+
+ public function getTestFilterData()
+ {
+ $inner = new MockFileListIterator();
+
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'a.txt',
+ 'contents' => 'Lorem ipsum...',
+ 'type' => 'file',
+ 'mode' => 'r+', )
+ );
+
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'b.yml',
+ 'contents' => 'dolor sit...',
+ 'type' => 'file',
+ 'mode' => 'r+', )
+ );
+
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'some/other/dir/third.php',
+ 'contents' => 'amet...',
+ 'type' => 'file',
+ 'mode' => 'r+', )
+ );
+
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'unreadable-file.txt',
+ 'contents' => false,
+ 'type' => 'file',
+ 'mode' => 'r+', )
+ );
+
+ return array(
+ array($inner, array('.'), array(), array('a.txt', 'b.yml', 'some/other/dir/third.php')),
+ array($inner, array('ipsum'), array(), array('a.txt')),
+ array($inner, array('i', 'amet'), array('Lorem', 'amet'), array('b.yml')),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilenameFilterIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilenameFilterIteratorTest.php
new file mode 100644
index 0000000..c4b9795
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilenameFilterIteratorTest.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
+
+class FilenameFilterIteratorTest extends IteratorTestCase
+{
+ /**
+ * @dataProvider getAcceptData
+ */
+ public function testAccept($matchPatterns, $noMatchPatterns, $expected)
+ {
+ $inner = new InnerNameIterator(array('test.php', 'test.py', 'foo.php'));
+
+ $iterator = new FilenameFilterIterator($inner, $matchPatterns, $noMatchPatterns);
+
+ $this->assertIterator($expected, $iterator);
+ }
+
+ public function getAcceptData()
+ {
+ return array(
+ array(array('test.*'), array(), array('test.php', 'test.py')),
+ array(array(), array('test.*'), array('foo.php')),
+ array(array('*.php'), array('test.*'), array('foo.php')),
+ array(array('*.php', '*.py'), array('foo.*'), array('test.php', 'test.py')),
+ array(array('/\.php$/'), array(), array('test.php', 'foo.php')),
+ array(array(), array('/\.php$/'), array('test.py')),
+ );
+ }
+}
+
+class InnerNameIterator extends \ArrayIterator
+{
+ public function current()
+ {
+ return new \SplFileInfo(parent::current());
+ }
+
+ public function getFilename()
+ {
+ return parent::current();
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilterIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilterIteratorTest.php
new file mode 100644
index 0000000..029a266
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/FilterIteratorTest.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+/**
+ * @author Alex Bogomazov
+ */
+class FilterIteratorTest extends RealIteratorTestCase
+{
+ public function testFilterFilesystemIterators()
+ {
+ $i = new \FilesystemIterator($this->toAbsolute());
+
+ // it is expected that there are test.py test.php in the tmpDir
+ $i = $this->getMockForAbstractClass('Symfony\Component\Finder\Iterator\FilterIterator', array($i));
+ $i->expects($this->any())
+ ->method('accept')
+ ->will($this->returnCallback(function () use ($i) {
+ return (bool) preg_match('/\.php/', (string) $i->current());
+ })
+ );
+
+ $c = 0;
+ foreach ($i as $item) {
+ $c++;
+ }
+
+ $this->assertEquals(1, $c);
+
+ $i->rewind();
+
+ $c = 0;
+ foreach ($i as $item) {
+ $c++;
+ }
+
+ // This would fail with \FilterIterator but works with Symfony\Component\Finder\Iterator\FilterIterator
+ // see https://bugs.php.net/bug.php?id=49104
+ $this->assertEquals(1, $c);
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/Iterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/Iterator.php
new file mode 100644
index 0000000..849bf08
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/Iterator.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+class Iterator implements \Iterator
+{
+ protected $values = array();
+
+ public function __construct(array $values = array())
+ {
+ foreach ($values as $value) {
+ $this->attach(new \SplFileInfo($value));
+ }
+ $this->rewind();
+ }
+
+ public function attach(\SplFileInfo $fileinfo)
+ {
+ $this->values[] = $fileinfo;
+ }
+
+ public function rewind()
+ {
+ reset($this->values);
+ }
+
+ public function valid()
+ {
+ return false !== $this->current();
+ }
+
+ public function next()
+ {
+ next($this->values);
+ }
+
+ public function current()
+ {
+ return current($this->values);
+ }
+
+ public function key()
+ {
+ return key($this->values);
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/IteratorTestCase.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/IteratorTestCase.php
new file mode 100644
index 0000000..ae7388e
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/IteratorTestCase.php
@@ -0,0 +1,98 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+abstract class IteratorTestCase extends \PHPUnit_Framework_TestCase
+{
+ protected function assertIterator($expected, \Traversable $iterator)
+ {
+ // set iterator_to_array $use_key to false to avoid values merge
+ // this made FinderTest::testAppendWithAnArray() failed with GnuFinderAdapter
+ $values = array_map(function (\SplFileInfo $fileinfo) { return str_replace('/', DIRECTORY_SEPARATOR, $fileinfo->getPathname()); }, iterator_to_array($iterator, false));
+
+ $expected = array_map(function ($path) { return str_replace('/', DIRECTORY_SEPARATOR, $path); }, $expected);
+
+ sort($values);
+ sort($expected);
+
+ $this->assertEquals($expected, array_values($values));
+ }
+
+ protected function assertOrderedIterator($expected, \Traversable $iterator)
+ {
+ $values = array_map(function (\SplFileInfo $fileinfo) { return $fileinfo->getPathname(); }, iterator_to_array($iterator));
+
+ $this->assertEquals($expected, array_values($values));
+ }
+
+ /**
+ * Same as assertOrderedIterator, but checks the order of groups of
+ * array elements.
+ *
+ * @param array $expected - an array of arrays. For any two subarrays
+ * $a and $b such that $a goes before $b in $expected, the method
+ * asserts that any element of $a goes before any element of $b
+ * in the sequence generated by $iterator
+ * @param \Traversable $iterator
+ */
+ protected function assertOrderedIteratorForGroups($expected, \Traversable $iterator)
+ {
+ $values = array_values(array_map(function (\SplFileInfo $fileinfo) { return $fileinfo->getPathname(); }, iterator_to_array($iterator)));
+
+ foreach ($expected as $subarray) {
+ $temp = array();
+ while (count($values) && count($temp) < count($subarray)) {
+ array_push($temp, array_shift($values));
+ }
+ sort($temp);
+ sort($subarray);
+ $this->assertEquals($subarray, $temp);
+ }
+ }
+
+ /**
+ * Same as IteratorTestCase::assertIterator with foreach usage.
+ *
+ * @param array $expected
+ * @param \Traversable $iterator
+ */
+ protected function assertIteratorInForeach($expected, \Traversable $iterator)
+ {
+ $values = array();
+ foreach ($iterator as $file) {
+ $this->assertInstanceOf('Symfony\\Component\\Finder\\SplFileInfo', $file);
+ $values[] = $file->getPathname();
+ }
+
+ sort($values);
+ sort($expected);
+
+ $this->assertEquals($expected, array_values($values));
+ }
+
+ /**
+ * Same as IteratorTestCase::assertOrderedIterator with foreach usage.
+ *
+ * @param array $expected
+ * @param \Traversable $iterator
+ */
+ protected function assertOrderedIteratorInForeach($expected, \Traversable $iterator)
+ {
+ $values = array();
+ foreach ($iterator as $file) {
+ $this->assertInstanceOf('Symfony\\Component\\Finder\\SplFileInfo', $file);
+ $values[] = $file->getPathname();
+ }
+
+ $this->assertEquals($expected, array_values($values));
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/MockFileListIterator.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/MockFileListIterator.php
new file mode 100644
index 0000000..eb0adfa
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/MockFileListIterator.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+class MockFileListIterator extends \ArrayIterator
+{
+ public function __construct(array $filesArray = array())
+ {
+ $files = array_map(function ($file) { return new MockSplFileInfo($file); }, $filesArray);
+ parent::__construct($files);
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/MockSplFileInfo.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/MockSplFileInfo.php
new file mode 100644
index 0000000..f2e8f8e
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/MockSplFileInfo.php
@@ -0,0 +1,134 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+class MockSplFileInfo extends \SplFileInfo
+{
+ const TYPE_DIRECTORY = 1;
+ const TYPE_FILE = 2;
+ const TYPE_UNKNOWN = 3;
+
+ private $contents = null;
+ private $mode = null;
+ private $type = null;
+ private $relativePath = null;
+ private $relativePathname = null;
+
+ public function __construct($param)
+ {
+ if (is_string($param)) {
+ parent::__construct($param);
+ } elseif (is_array($param)) {
+ $defaults = array(
+ 'name' => 'file.txt',
+ 'contents' => null,
+ 'mode' => null,
+ 'type' => null,
+ 'relativePath' => null,
+ 'relativePathname' => null,
+ );
+ $defaults = array_merge($defaults, $param);
+ parent::__construct($defaults['name']);
+ $this->setContents($defaults['contents']);
+ $this->setMode($defaults['mode']);
+ $this->setType($defaults['type']);
+ $this->setRelativePath($defaults['relativePath']);
+ $this->setRelativePathname($defaults['relativePathname']);
+ } else {
+ throw new \RuntimeException(sprintf('Incorrect parameter "%s"', $param));
+ }
+ }
+
+ public function isFile()
+ {
+ if (null === $this->type) {
+ return preg_match('/file/', $this->getFilename());
+ };
+
+ return self::TYPE_FILE === $this->type;
+ }
+
+ public function isDir()
+ {
+ if (null === $this->type) {
+ return preg_match('/directory/', $this->getFilename());
+ }
+
+ return self::TYPE_DIRECTORY === $this->type;
+ }
+
+ public function isReadable()
+ {
+ if (null === $this->mode) {
+ return preg_match('/r\+/', $this->getFilename());
+ }
+
+ return preg_match('/r\+/', $this->mode);
+ }
+
+ public function getContents()
+ {
+ return $this->contents;
+ }
+
+ public function setContents($contents)
+ {
+ $this->contents = $contents;
+ }
+
+ public function setMode($mode)
+ {
+ $this->mode = $mode;
+ }
+
+ public function setType($type)
+ {
+ if (is_string($type)) {
+ switch ($type) {
+ case 'directory':
+ $this->type = self::TYPE_DIRECTORY;
+ case 'd':
+ $this->type = self::TYPE_DIRECTORY;
+ break;
+ case 'file':
+ $this->type = self::TYPE_FILE;
+ case 'f':
+ $this->type = self::TYPE_FILE;
+ break;
+ default:
+ $this->type = self::TYPE_UNKNOWN;
+ }
+ } else {
+ $this->type = $type;
+ }
+ }
+
+ public function setRelativePath($relativePath)
+ {
+ $this->relativePath = $relativePath;
+ }
+
+ public function setRelativePathname($relativePathname)
+ {
+ $this->relativePathname = $relativePathname;
+ }
+
+ public function getRelativePath()
+ {
+ return $this->relativePath;
+ }
+
+ public function getRelativePathname()
+ {
+ return $this->relativePathname;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/MultiplePcreFilterIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/MultiplePcreFilterIteratorTest.php
new file mode 100644
index 0000000..89d8edb
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/MultiplePcreFilterIteratorTest.php
@@ -0,0 +1,67 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator;
+
+class MultiplePcreFilterIteratorTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getIsRegexFixtures
+ */
+ public function testIsRegex($string, $isRegex, $message)
+ {
+ $testIterator = new TestMultiplePcreFilterIterator();
+ $this->assertEquals($isRegex, $testIterator->isRegex($string), $message);
+ }
+
+ public function getIsRegexFixtures()
+ {
+ return array(
+ array('foo', false, 'string'),
+ array(' foo ', false, '" " is not a valid delimiter'),
+ array('\\foo\\', false, '"\\" is not a valid delimiter'),
+ array('afooa', false, '"a" is not a valid delimiter'),
+ array('//', false, 'the pattern should contain at least 1 character'),
+ array('/a/', true, 'valid regex'),
+ array('/foo/', true, 'valid regex'),
+ array('/foo/i', true, 'valid regex with a single modifier'),
+ array('/foo/imsxu', true, 'valid regex with multiple modifiers'),
+ array('#foo#', true, '"#" is a valid delimiter'),
+ array('{foo}', true, '"{,}" is a valid delimiter pair'),
+ array('*foo.*', false, '"*" is not considered as a valid delimiter'),
+ array('?foo.?', false, '"?" is not considered as a valid delimiter'),
+ );
+ }
+}
+
+class TestMultiplePcreFilterIterator extends MultiplePcreFilterIterator
+{
+ public function __construct()
+ {
+ }
+
+ public function accept()
+ {
+ throw new \BadFunctionCallException('Not implemented');
+ }
+
+ public function isRegex($str)
+ {
+ return parent::isRegex($str);
+ }
+
+ public function toRegex($str)
+ {
+ throw new \BadFunctionCallException('Not implemented');
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/PathFilterIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/PathFilterIteratorTest.php
new file mode 100644
index 0000000..579beed
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/PathFilterIteratorTest.php
@@ -0,0 +1,83 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\PathFilterIterator;
+
+class PathFilterIteratorTest extends IteratorTestCase
+{
+ /**
+ * @dataProvider getTestFilterData
+ */
+ public function testFilter(\Iterator $inner, array $matchPatterns, array $noMatchPatterns, array $resultArray)
+ {
+ $iterator = new PathFilterIterator($inner, $matchPatterns, $noMatchPatterns);
+ $this->assertIterator($resultArray, $iterator);
+ }
+
+ public function getTestFilterData()
+ {
+ $inner = new MockFileListIterator();
+
+ //PATH: A/B/C/abc.dat
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'abc.dat',
+ 'relativePathname' => 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
+ ));
+
+ //PATH: A/B/ab.dat
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'ab.dat',
+ 'relativePathname' => 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
+ ));
+
+ //PATH: A/a.dat
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'a.dat',
+ 'relativePathname' => 'A'.DIRECTORY_SEPARATOR.'a.dat',
+ ));
+
+ //PATH: copy/A/B/C/abc.dat.copy
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'abc.dat.copy',
+ 'relativePathname' => 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
+ ));
+
+ //PATH: copy/A/B/ab.dat.copy
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'ab.dat.copy',
+ 'relativePathname' => 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
+ ));
+
+ //PATH: copy/A/a.dat.copy
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'a.dat.copy',
+ 'relativePathname' => 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'a.dat',
+ ));
+
+ return array(
+ array($inner, array('/^A/'), array(), array('abc.dat', 'ab.dat', 'a.dat')),
+ array($inner, array('/^A\/B/'), array(), array('abc.dat', 'ab.dat')),
+ array($inner, array('/^A\/B\/C/'), array(), array('abc.dat')),
+ array($inner, array('/A\/B\/C/'), array(), array('abc.dat', 'abc.dat.copy')),
+
+ array($inner, array('A'), array(), array('abc.dat', 'ab.dat', 'a.dat', 'abc.dat.copy', 'ab.dat.copy', 'a.dat.copy')),
+ array($inner, array('A/B'), array(), array('abc.dat', 'ab.dat', 'abc.dat.copy', 'ab.dat.copy')),
+ array($inner, array('A/B/C'), array(), array('abc.dat', 'abc.dat.copy')),
+
+ array($inner, array('copy/A'), array(), array('abc.dat.copy', 'ab.dat.copy', 'a.dat.copy')),
+ array($inner, array('copy/A/B'), array(), array('abc.dat.copy', 'ab.dat.copy')),
+ array($inner, array('copy/A/B/C'), array(), array('abc.dat.copy')),
+
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php
new file mode 100644
index 0000000..e22476d
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php
@@ -0,0 +1,109 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+abstract class RealIteratorTestCase extends IteratorTestCase
+{
+ protected static $tmpDir;
+ protected static $files;
+
+ public static function setUpBeforeClass()
+ {
+ self::$tmpDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'symfony_finder';
+
+ self::$files = array(
+ '.git/',
+ '.foo/',
+ '.foo/.bar',
+ '.foo/bar',
+ '.bar',
+ 'test.py',
+ 'foo/',
+ 'foo/bar.tmp',
+ 'test.php',
+ 'toto/',
+ 'foo bar',
+ );
+
+ self::$files = self::toAbsolute(self::$files);
+
+ if (is_dir(self::$tmpDir)) {
+ self::tearDownAfterClass();
+ } else {
+ mkdir(self::$tmpDir);
+ }
+
+ foreach (self::$files as $file) {
+ if (DIRECTORY_SEPARATOR === $file[strlen($file) - 1]) {
+ mkdir($file);
+ } else {
+ touch($file);
+ }
+ }
+
+ file_put_contents(self::toAbsolute('test.php'), str_repeat(' ', 800));
+ file_put_contents(self::toAbsolute('test.py'), str_repeat(' ', 2000));
+
+ touch(self::toAbsolute('foo/bar.tmp'), strtotime('2005-10-15'));
+ touch(self::toAbsolute('test.php'), strtotime('2005-10-15'));
+ }
+
+ public static function tearDownAfterClass()
+ {
+ foreach (array_reverse(self::$files) as $file) {
+ if (DIRECTORY_SEPARATOR === $file[strlen($file) - 1]) {
+ @rmdir($file);
+ } else {
+ @unlink($file);
+ }
+ }
+ }
+
+ protected static function toAbsolute($files = null)
+ {
+ /*
+ * Without the call to setUpBeforeClass() property can be null.
+ */
+ if (!self::$tmpDir) {
+ self::$tmpDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'symfony_finder';
+ }
+
+ if (is_array($files)) {
+ $f = array();
+ foreach ($files as $file) {
+ if (is_array($file)) {
+ $f[] = self::toAbsolute($file);
+ } else {
+ $f[] = self::$tmpDir.DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $file);
+ }
+ }
+
+ return $f;
+ }
+
+ if (is_string($files)) {
+ return self::$tmpDir.DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $files);
+ }
+
+ return self::$tmpDir;
+ }
+
+ protected static function toAbsoluteFixtures($files)
+ {
+ $f = array();
+ foreach ($files as $file) {
+ $f[] = realpath(__DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$file);
+ }
+
+ return $f;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php
new file mode 100644
index 0000000..412054b
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php
@@ -0,0 +1,83 @@
+
+*
+* For the full copyright and license information, please view the LICENSE
+* file that was distributed with this source code.
+*/
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
+
+class RecursiveDirectoryIteratorTest extends IteratorTestCase
+{
+ /**
+ * @dataProvider getPaths
+ *
+ * @param string $path
+ * @param bool $seekable
+ * @param array $contains
+ * @param string $message
+ */
+ public function testRewind($path, $seekable, $contains, $message = null)
+ {
+ try {
+ $i = new RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
+ } catch (\UnexpectedValueException $e) {
+ $this->markTestSkipped(sprintf('Unsupported stream "%s".', $path));
+ }
+
+ $i->rewind();
+
+ $this->assertTrue(true, $message);
+ }
+
+ /**
+ * @dataProvider getPaths
+ *
+ * @param string $path
+ * @param bool $seekable
+ * @param array $contains
+ * @param string $message
+ */
+ public function testSeek($path, $seekable, $contains, $message = null)
+ {
+ try {
+ $i = new RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
+ } catch (\UnexpectedValueException $e) {
+ $this->markTestSkipped(sprintf('Unsupported stream "%s".', $path));
+ }
+
+ $actual = array();
+
+ $i->seek(0);
+ $actual[] = $i->getPathname();
+
+ $i->seek(1);
+ $actual[] = $i->getPathname();
+
+ $i->seek(2);
+ $actual[] = $i->getPathname();
+
+ $this->assertEquals($contains, $actual);
+ }
+
+ public function getPaths()
+ {
+ $data = array();
+
+ // ftp
+ $contains = array(
+ 'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'README',
+ 'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'index.html',
+ 'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'pub',
+ );
+ $data[] = array('ftp://ftp.mozilla.org/', false, $contains);
+
+ return $data;
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/SizeRangeFilterIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/SizeRangeFilterIteratorTest.php
new file mode 100644
index 0000000..8780db4
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/SizeRangeFilterIteratorTest.php
@@ -0,0 +1,68 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
+use Symfony\Component\Finder\Comparator\NumberComparator;
+
+class SizeRangeFilterIteratorTest extends RealIteratorTestCase
+{
+ /**
+ * @dataProvider getAcceptData
+ */
+ public function testAccept($size, $expected)
+ {
+ $inner = new InnerSizeIterator(self::$files);
+
+ $iterator = new SizeRangeFilterIterator($inner, $size);
+
+ $this->assertIterator($expected, $iterator);
+ }
+
+ public function getAcceptData()
+ {
+ $lessThan1KGreaterThan05K = array(
+ '.foo',
+ '.git',
+ 'foo',
+ 'test.php',
+ 'toto',
+ );
+
+ return array(
+ array(array(new NumberComparator('< 1K'), new NumberComparator('> 0.5K')), $this->toAbsolute($lessThan1KGreaterThan05K)),
+ );
+ }
+}
+
+class InnerSizeIterator extends \ArrayIterator
+{
+ public function current()
+ {
+ return new \SplFileInfo(parent::current());
+ }
+
+ public function getFilename()
+ {
+ return parent::current();
+ }
+
+ public function isFile()
+ {
+ return $this->current()->isFile();
+ }
+
+ public function getSize()
+ {
+ return $this->current()->getSize();
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php
new file mode 100644
index 0000000..e2f433f
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php
@@ -0,0 +1,169 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\SortableIterator;
+
+class SortableIteratorTest extends RealIteratorTestCase
+{
+ public function testConstructor()
+ {
+ try {
+ new SortableIterator(new Iterator(array()), 'foobar');
+ $this->fail('__construct() throws an \InvalidArgumentException exception if the mode is not valid');
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException exception if the mode is not valid');
+ }
+ }
+
+ /**
+ * @dataProvider getAcceptData
+ */
+ public function testAccept($mode, $expected)
+ {
+ if (!is_callable($mode)) {
+ switch ($mode) {
+ case SortableIterator::SORT_BY_ACCESSED_TIME :
+ file_get_contents(self::toAbsolute('.git'));
+ sleep(1);
+ file_get_contents(self::toAbsolute('.bar'));
+ break;
+ case SortableIterator::SORT_BY_CHANGED_TIME :
+ file_put_contents(self::toAbsolute('test.php'), 'foo');
+ sleep(1);
+ file_put_contents(self::toAbsolute('test.py'), 'foo');
+ break;
+ case SortableIterator::SORT_BY_MODIFIED_TIME :
+ file_put_contents(self::toAbsolute('test.php'), 'foo');
+ sleep(1);
+ file_put_contents(self::toAbsolute('test.py'), 'foo');
+ break;
+ }
+ }
+
+ $inner = new Iterator(self::$files);
+
+ $iterator = new SortableIterator($inner, $mode);
+
+ if ($mode === SortableIterator::SORT_BY_ACCESSED_TIME
+ || $mode === SortableIterator::SORT_BY_CHANGED_TIME
+ || $mode === SortableIterator::SORT_BY_MODIFIED_TIME) {
+ $this->assertOrderedIteratorForGroups($expected, $iterator);
+ } else {
+ $this->assertOrderedIterator($expected, $iterator);
+ }
+ }
+
+ public function getAcceptData()
+ {
+ $sortByName = array(
+ '.bar',
+ '.foo',
+ '.foo/.bar',
+ '.foo/bar',
+ '.git',
+ 'foo',
+ 'foo bar',
+ 'foo/bar.tmp',
+ 'test.php',
+ 'test.py',
+ 'toto',
+ );
+
+ $sortByType = array(
+ '.foo',
+ '.git',
+ 'foo',
+ 'toto',
+ '.bar',
+ '.foo/.bar',
+ '.foo/bar',
+ 'foo bar',
+ 'foo/bar.tmp',
+ 'test.php',
+ 'test.py',
+ );
+
+ $customComparison = array(
+ '.bar',
+ '.foo',
+ '.foo/.bar',
+ '.foo/bar',
+ '.git',
+ 'foo',
+ 'foo bar',
+ 'foo/bar.tmp',
+ 'test.php',
+ 'test.py',
+ 'toto',
+ );
+
+ $sortByAccessedTime = array(
+ // For these two files the access time was set to 2005-10-15
+ array('foo/bar.tmp', 'test.php'),
+ // These files were created more or less at the same time
+ array(
+ '.git',
+ '.foo',
+ '.foo/.bar',
+ '.foo/bar',
+ 'test.py',
+ 'foo',
+ 'toto',
+ 'foo bar',
+ ),
+ // This file was accessed after sleeping for 1 sec
+ array('.bar'),
+ );
+
+ $sortByChangedTime = array(
+ array(
+ '.git',
+ '.foo',
+ '.foo/.bar',
+ '.foo/bar',
+ '.bar',
+ 'foo',
+ 'foo/bar.tmp',
+ 'toto',
+ 'foo bar',
+ ),
+ array('test.php'),
+ array('test.py'),
+ );
+
+ $sortByModifiedTime = array(
+ array(
+ '.git',
+ '.foo',
+ '.foo/.bar',
+ '.foo/bar',
+ '.bar',
+ 'foo',
+ 'foo/bar.tmp',
+ 'toto',
+ 'foo bar',
+ ),
+ array('test.php'),
+ array('test.py'),
+ );
+
+ return array(
+ array(SortableIterator::SORT_BY_NAME, $this->toAbsolute($sortByName)),
+ array(SortableIterator::SORT_BY_TYPE, $this->toAbsolute($sortByType)),
+ array(SortableIterator::SORT_BY_ACCESSED_TIME, $this->toAbsolute($sortByAccessedTime)),
+ array(SortableIterator::SORT_BY_CHANGED_TIME, $this->toAbsolute($sortByChangedTime)),
+ array(SortableIterator::SORT_BY_MODIFIED_TIME, $this->toAbsolute($sortByModifiedTime)),
+ array(function (\SplFileInfo $a, \SplFileInfo $b) { return strcmp($a->getRealpath(), $b->getRealpath()); }, $this->toAbsolute($customComparison)),
+ );
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/composer.json b/core/vendor/symfony/finder/Symfony/Component/Finder/composer.json
new file mode 100644
index 0000000..a91b470
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/composer.json
@@ -0,0 +1,31 @@
+{
+ "name": "symfony/finder",
+ "type": "library",
+ "description": "Symfony Finder Component",
+ "keywords": [],
+ "homepage": "http://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "autoload": {
+ "psr-0": { "Symfony\\Component\\Finder\\": "" }
+ },
+ "target-dir": "Symfony/Component/Finder",
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.6-dev"
+ }
+ }
+}
diff --git a/core/vendor/symfony/finder/Symfony/Component/Finder/phpunit.xml.dist b/core/vendor/symfony/finder/Symfony/Component/Finder/phpunit.xml.dist
new file mode 100644
index 0000000..0ed1223
--- /dev/null
+++ b/core/vendor/symfony/finder/Symfony/Component/Finder/phpunit.xml.dist
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+ ./Tests/
+
+
+
+
+
+ ./
+
+ ./Tests
+ ./vendor
+
+
+
+