_readme: This file locks the dependencies of your project to a known state

_readme: Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file

cilex/cilex

type: git

type: zip

Cilex: src/

description: The PHP micro-framework for Command line tools based on the Symfony2 Components

keywords: cli microframework

cilex/console-service-provider

Cilex\Provider\Console: src

description: Console Service Provider

keywords: cilex console pimple service-provider silex

doctrine/annotations

Doctrine\Common\Annotations\: lib/

description: Docblock Annotations Parser

keywords: annotations docblock parser

doctrine/instantiator

Doctrine\Instantiator\: src/Doctrine/Instantiator/

description: A small, lightweight utility to instantiate objects in PHP without invoking their constructors

keywords: constructor instantiate

doctrine/lexer

Doctrine\Common\Lexer\: lib/

description: Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.

keywords: lexer parser

erusev/parsedown

description: Parser for Markdown.

keywords: markdown parser

herrera-io/json

Herrera\Json: src/lib

description: A library for simplifying JSON linting and validation.

keywords: json lint schema validate

abandoned: kherge/json

herrera-io/phar-update

Herrera\Phar\Update: src/lib

description: A library for self-updating Phars.

keywords: phar update

jms/metadata

Metadata\: src/

description: Class/method/property metadata management in PHP

keywords: annotations metadata xml yaml

jms/parser-lib

JMS\: src/

description: A library for easily creating recursive-descent parsers.

jms/serializer

symfony/yaml: Required if you'd like to serialize data to YAML format.

JMS\Serializer: src/

Johannes Schmitt

role: Developer of wrapped JMSSerializerBundle

description: Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.

keywords: deserialization jaxb json serialization xml

justinrainbow/json-schema

JsonSchema\: src/JsonSchema/

description: A library to validate a json schema.

keywords: json schema

kherge/version

KevinGH\Version: src/lib/

description: A parsing and comparison library for semantic versioning.

version: dev-master

description: Microformats test suite

monolog/monolog

aws/aws-sdk-php: Allow sending log messages to AWS services like DynamoDB

doctrine/couchdb: Allow sending log messages to a CouchDB server

ext-amqp: Allow sending log messages to an AMQP server (1.0+ required)

graylog2/gelf-php: Allow sending log messages to a GrayLog2 server

mongodb/mongodb: Allow sending log messages to a MongoDB server via PHP Driver

php-amqplib/php-amqplib: Allow sending log messages to an AMQP server using php-amqplib

php-console/php-console: Allow sending log messages to Google Chrome

rollbar/rollbar: Allow sending log messages to Rollbar

ruflin/elastica: Allow sending log messages to an Elastic Search server

sentry/sentry: Allow sending log messages to a Sentry server

Monolog\: src/Monolog

description: Sends your logs to files, sockets, inboxes, databases and various web services

keywords: log logging psr-3

nikic/php-parser

PHPParser: lib/

description: A PHP parser written in PHP

keywords: parser php

phpcollection/phpcollection

PhpCollection: src/

description: General-Purpose Collection Library for PHP

keywords: collection list map sequence set

phpdocumentor/fileset

phpDocumentor: src/ tests/unit/

description: Fileset component for collecting a set of files given directories and file paths

keywords: files fileset phpdoc

phpdocumentor/graphviz

phpDocumentor: src/ tests/unit

phpdocumentor/phpdocumentor

ext-twig: Enabling the twig extension improves the generation of twig based templates.

ext-xslcache: Enabling the XSLCache extension improves the generation of xml based templates.

description: Documentation Generator for PHP

keywords: api application dga documentation phpdoc

phpdocumentor/reflection

phpDocumentor: src/ tests/unit/ tests/mocks/

description: Reflection library to do Static Analysis for PHP Projects

keywords:
phpDocumentor
phpdoc
reflection
static analysis

phpoption/phpoption

description: Option Type for PHP

phpspec/prophecy

description: Highly opinionated mocking framework for PHP 5.3+

phpunit/php-code-coverage

description: Library that provides collection, processing, and rendering functionality for PHP code coverage information.

phpunit/php-file-iterator

description: FilterIterator implementation that filters files based on a list of suffixes.

phpunit/php-text-template

description: Simple template engine.

phpunit/php-timer

description: Utility class for timing

phpunit/php-token-stream

description: Wrapper around PHP's tokenizer extension.

phpunit/phpunit

description: The PHP Unit Testing framework.

phpunit/phpunit-mock-objects

description: Mock Object library for PHPUnit

pimple/pimple

description: Pimple is a simple Dependency Injection Container for PHP 5.3

psr/log

description: Common interface for logging libraries

sebastian/comparator

description: Provides the functionality to compare PHP values for equality

sebastian/diff

description: Diff implementation

sebastian/environment

description: Provides functionality to handle HHVM/PHP environments

sebastian/exporter

description: Provides the functionality to export PHP variables for visualization

sebastian/global-state

description: Snapshotting of global state

sebastian/recursion-context

description: Provides functionality to recursively process PHP variables

sebastian/version

description: Library that helps with managing the version number of Git-hosted PHP projects

seld/jsonlint

description: JSON Linter

symfony/config

description: Symfony Config Component

symfony/console

description: Symfony Console Component

symfony/debug

description: Symfony Debug Component

symfony/event-dispatcher

description: Symfony EventDispatcher Component

symfony/filesystem

description: Symfony Filesystem Component

symfony/finder

description: Symfony Finder Component

symfony/polyfill-mbstring

description: Symfony polyfill for the Mbstring extension

keywords: compatibility mbstring polyfill portable shim

symfony/process

description: Symfony Process Component

symfony/stopwatch

description: Symfony Stopwatch Component

symfony/translation

description: Symfony Translation Component

symfony/validator

doctrine/annotations: For using the annotation mapping. You will also need doctrine/cache.

doctrine/cache: For using the default cached annotation reader and metadata cache.

description: Symfony Validator Component

symfony/yaml

description: Symfony Yaml Component

twig/twig

description: Twig, the flexible, fast, and secure template language for PHP

zendframework/zend-cache

ext-apc: APC >= 3.1.6 to use the APC storage adapter

ext-memcached: Memcached >= 1.0.0 to use the Memcached storage adapter

ext-wincache: WinCache, to use the WinCache storage adapter

mongofill/mongofill: Alternative to ext-mongo - a pure PHP implementation designed as a drop in replacement

description: provides a generic way to cache any data

zendframework/zend-config

zendframework/zend-json: Zend\Json to use the Json reader or writer classes

zendframework/zend-servicemanager: Zend\ServiceManager for use with the Config Factory to retrieve reader and writer instances

description: provides a nested object property based user interface for accessing this configuration data within application code

zendframework/zend-filter

zendframework/zend-uri: Zend\Uri component for UriNormalize filter

description: provides a set of commonly needed data filters

ext-intl: Required for most features of Zend\I18n; included in default builds of PHP

zendframework/zend-eventmanager: You should install this package to use the events in the translator

zendframework/zend-filter: You should install this package to use the provided filters

zendframework/zend-validator: You should install this package to use the provided validators

zendframework/zend-view: You should install this package to use the provided view helpers

zendframework/zend-json

zendframework/zendxml: To support Zend\Json\Json::fromXml() usage

description: provides convenience methods for serializing native PHP to JSON and decoding JSON to native PHP

zendframework/zend-math

ircmaxell/random-lib: Fallback random byte generator for Zend\Math\Rand if OpenSSL/Mcrypt extensions are unavailable

zendframework/zend-servicemanager: >= current version, if using the BigInteger::factory functionality

zendframework/zend-serializer

description: provides an adapter based interface to simply generate storable representation of PHP types by different facilities, and recover

zendframework/zend-servicemanager

ocramius/proxy-manager: ProxyManager 0.5.* to handle lazy initialization of services

zendframework/zend-stdlib

zendframework/zend-filter: To support naming strategy hydrator usage

zendframework/zend-servicemanager: To support hydrator plugin manager usage

zetacomponents/base

description: The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package.

zetacomponents/document

description: The Document components provides a general conversion framework for different semantic document markup languages like XHTML, Docbook, RST and similar.


code:
<?xml version="1.0"?>
<phpunit bootstrap="tests/Mf2/bootstrap.php">
	<testsuites>
		<testsuite name="php-mf2">
			<directory suffix="Test.php">tests/Mf2</directory>
		</testsuite>
	</testsuites>
</phpunit>

license: mit


code:
<?php

namespace Mf2\Parser\Test;

use Mf2\Parser;
use Mf2;
use PHPUnit_Framework_TestCase;

/**
 * Combined Microformats Test
 *
 * Tests the ability of Parser::parse() to handle nested microformats correctly.
 * More info at http://microformats.org/wiki/microformats-2#combining_microformats
 *
 * @todo implement
 */
class CombinedMicroformatsTest extends PHPUnit_Framework_TestCase {

	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	/**
	 * From http://microformats.org/wiki/microformats2#combining_microformats
	 */
	public function testHEventLocationHCard() {
		$input = '

	IndieWebCamp 2012

	from <time class="dt-start">2012-06-30</time>
	to <time class="dt-end">2012-07-01</time> at

	Geoloqi, 920 SW 3rd Ave. Suite 400, Portland, OR

';
		$expected = '{
	"rels": {},
	"rel-urls": {},
	"items": [{
		"type": ["h-event"],
		"properties": {
			"name": ["IndieWebCamp 2012"],
			"url": ["http://indiewebcamp.com/2012"],
			"start": ["2012-06-30"],
			"end": ["2012-07-01"],
			"location": [{
				"value": "Geoloqi",
				"type": ["h-card"],
				"properties": {
					"name": ["Geoloqi"],
					"org": ["Geoloqi"],
					"url": ["http://geoloqi.com/"],
					"street-address": ["920 SW 3rd Ave. Suite 400"],
					"locality": ["Portland"],
					"region": ["Oregon"]
				}
			}]
		}
	}]
}';

		$parser = new Parser($input, '', true);
		$parser->stringDateTimes = true;
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	/**
	 * From http://microformats.org/wiki/microformats2#combining_microformats
	 */
	public function testHCardOrgPOrg() {
		$input = '

  Mitchell Baker
  (Mozilla Foundation)

';
		$expected = '{
	"rels": {},
	"rel-urls": {},
  "items": [{
	"type": ["h-card"],
	"properties": {
	  "name": ["Mitchell Baker"],
	  "url": ["http://blog.lizardwrangler.com/"],
	  "org": ["Mozilla Foundation"]
	}
  }]
}';

		$parser = new Parser($input, '', true);
		$parser->stringDateTimes = true;
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	/**
	 * From http://microformats.org/wiki/microformats2#combining_microformats
	 */
	public function testHCardOrgHCard() {
		$input = '

  Mitchell Baker
  (Mozilla Foundation)

';
		$expected = '{
	"rels": {},
	"rel-urls": {},
  "items": [{
	"type": ["h-card"],
	"properties": {
	  "name": ["Mitchell Baker"],
	  "url": ["http://blog.lizardwrangler.com/"],
	  "org": [{
		"value": "Mozilla Foundation",
		"type": ["h-card"],
		"properties": {
		  "name": ["Mozilla Foundation"],
		  "url": ["http://mozilla.org/"]
		 }
	  }]
	}
  }]
}';

		$parser = new Parser($input, '', true);
		$parser->stringDateTimes = true;
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	/**
	 * From http://microformats.org/wiki/microformats2#combining_microformats
	 */
	public function testHCardPOrgHCardHOrg() {
		$input = '

  Mitchell Baker
  (Mozilla Foundation)

';
		$expected = '{
	"rels": {},
	"rel-urls": {},
  "items": [{
	"type": ["h-card"],
	"properties": {
	  "name": ["Mitchell Baker"],
	  "url": ["http://blog.lizardwrangler.com/"],
	  "org": [{
		"value": "Mozilla Foundation",
		"type": ["h-card", "h-org"],
		"properties": {
		  "name": ["Mozilla Foundation"],
		  "url": ["http://mozilla.org/"]
		}
	  }]
	}
  }]
}';

		$parser = new Parser($input, '', true);
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	/**
	 * From http://microformats.org/wiki/microformats2#combining_microformats
	 */
	public function testHCardChildHCard() {
		$input = '

	Mitchell Baker
	(
	Mozilla Foundation)

';
		$expected = '{
	"rels": {},
	"rel-urls": {},
  "items": [{
		"type": ["h-card"],
		"properties": {
			"name": ["Mitchell Baker"],
			"url": ["http://blog.lizardwrangler.com/"]
		},
		"children": [{
			"type": ["h-card","h-org"],
			"properties": {
				"name": ["Mozilla Foundation"],
				"url": ["http://mozilla.org/"]
			}
		}]
	}]
}';

		$parser = new Parser($input, '', true);
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	/**
	 * Regression test for https://github.com/indieweb/php-mf2/issues/42
	 *
	 * This was occurring because mfPropertyNamesFromClass was only ever returning the first property name
	 * rather than all of them.
	 */
	public function testNestedMicroformatUnderMultipleProperties() {
		$input = '

';
		$mf = Mf2\parse($input);

		$this->assertCount(1, $mf['items'][0]['properties']['like-of']);
		$this->assertCount(1, $mf['items'][0]['properties']['in-reply-to']);
	}

	/**
	 * Test microformats nested under e-* property classnames retain html: key in structure
	 *
	 * @see https://github.com/indieweb/php-mf2/issues/64
	 */
	public function testMicroformatsNestedUnderEPropertyClassnamesRetainHtmlKey() {
		$input = '

Hello

';
		$mf = Mf2\parse($input);

		$this->assertArrayHasKey('value', $mf['items'][0]['properties']['content'][0]);
		$this->assertEquals($mf['items'][0]['properties']['content'][0]['value'], 'Hello');
		$this->assertArrayHasKey('html', $mf['items'][0]['properties']['content'][0]);
		$this->assertEquals($mf['items'][0]['properties']['content'][0]['html'], '
Hello
');
	}

	/**
	 * Test microformats nested under u-* property classnames derive value: key from parsing as u-*
	 */
	public function testMicroformatsNestedUnderUPropertyClassnamesDeriveValueCorrectly() {
		$input = '

';
		$mf = Mf2\parse($input);

		$this->assertEquals($mf['items'][0]['properties']['url'][0]['value'], 'This should be the value');
	}

	public function testMicroformatsNestedUnderUPropertyClassnamesDeriveValueFromURL() {
		$input = '

Name

Hello World

		    	Jane Bloggs

lol

		    	<time class="dt-published">2015-07-12 12:03</time>

';
		$expected = '{
		  "items": [{
    	  "type": ["h-entry"],
	      "properties": {
	        "name": ["Name"],
	        "content": [{
	          "html": "Hello World",
	          "value": "Hello World"
	        }],
	        "comment": [{
            "type": ["h-cite"],
            "properties": {
              "author": [{
                "type": ["h-card"],
                "properties": {
                  "name": ["Jane Bloggs"],
                  "url": ["http:\/\/jane.example.com\/"]
                },
                "value": "http:\/\/jane.example.com\/"
              }],
              "content": ["lol"],
              "name": ["lol"],
              "url": ["http:\/\/example.org\/post1234"],
              "published": ["2015-07-12 12:03"]
            },
            "value": "http:\/\/example.org\/post1234"
          }]
	      }
	    }],
	    "rels":[],
	    "rel-urls": []
	  }';
	  	$mf = Mf2\parse($input);

		$this->assertJsonStringEqualsJsonString(json_encode($mf), $expected);
		$this->assertEquals($mf['items'][0]['properties']['comment'][0]['value'], 'http://example.org/post1234');
		$this->assertEquals($mf['items'][0]['properties']['comment'][0]['properties']['author'][0]['value'], 'http://jane.example.com/');
	}

	public function testMicroformatsNestedUnderPPropertyClassnamesDeriveValueFromFirstPName() {
		$input = '

This post was written by Zoe.

';
		$mf = Mf2\parse($input);

		$this->assertEquals($mf['items'][0]['properties']['author'][0]['value'], 'Zoe');
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/98
	 * @see https://github.com/microformats/tests/issues/58
	 */
	public function testNoValueForNestedMicroformatWithoutProperty() {
		$input = '
Jane Doe

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('children', $output['items'][0]);
		$this->assertArrayNotHasKey('value', $output['items'][0]['children'][0]);
	}

	/**
	 * With the backcompat changes I worked on in this PR, I ran into a case where
	 * nested mf1 without properties were not added to the 'children' property properly.
	 * I fixed that but then wanted to ensure it worked beyond 1-level deep. This example
	 * is contrived, but lets me test to confirm 'children' is set correctly. - Gregor Morrill
	 */
	public function testNestedMf1() {
		$input = '

Jane Doe and
John Doe

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEmpty($output['items'][0]['properties']);
		$this->assertArrayHasKey('children', $output['items'][0]);
		$this->assertEquals('h-card', $output['items'][0]['children'][0]['type'][0]);
		$this->assertEquals('Jane Doe', $output['items'][0]['children'][0]['properties']['name'][0]);
		$child_mf = $output['items'][0]['children'][0];
		$this->assertArrayHasKey('children', $child_mf);
		$this->assertEquals('h-card', $child_mf['children'][0]['type'][0]);
		$this->assertEquals('John Doe', $child_mf['children'][0]['properties']['name'][0]);
	}

  public function testNoUrlFromRelOnMf2() {
    $input = <<< END

 Title of Post

 This is the post

END;
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('name', $output['items'][0]['properties']);
    $this->assertArrayHasKey('content', $output['items'][0]['properties']);
    $this->assertArrayNotHasKey('url', $output['items'][0]['properties']);
  }

	/**
	 * Simplified h-entry with `p-location h-adr` from https://aaronparecki.com/2018/03/14/3/
	 * Whitespace cleaned up for easier test assertion
	 * @see https://github.com/indieweb/php-mf2/issues/151
	 */
	public function testNestedValuePProperty() {
		$input = <<< END

Portland, Oregon • 44°F
<data class="p-latitude" value="45.535623"></data>
<data class="p-longitude" value="-122.621209"></data>

END;
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('value', $output['items'][0]['properties']['location'][0]);
		$this->assertEquals("Portland, Oregon • 44°F", $output['items'][0]['properties']['location'][0]['value']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/151
	 */
	public function testNestedValueDTProperty() {
		$input = <<< END

1997-12-12

END;
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('value', $output['items'][0]['properties']['acme'][0]);
		$this->assertEquals('1997-12-12', $output['items'][0]['properties']['acme'][0]['value']);
	}

	/**
	 * rel=tag should not be upgraded within microformats2
	 * @see https://github.com/indieweb/php-mf2/issues/157
	 */
	public function testMf2DoesNotParseRelTag() {
		$input = '

Tests

Reviews

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayNotHasKey('category', $output['items'][0]['properties']);
		$this->assertArrayNotHasKey('category', $output['items'][1]['properties']);
	}

	/**
	 * JSON-mode should return an empty stdClass when a microformat has no properties.
	 * @see https://github.com/indieweb/php-mf2/issues/171
	 */
	public function testEmptyPropertiesObjectInJSONMode() {
		$input = '

';
		// Try in JSON-mode: expect the raw PHP to be an stdClass instance that serializes to an empty object.
		$parser = new Parser($input, null, true);
		$output = $parser->parse();
		$this->assertInstanceOf('\stdClass', $output['items'][0]['properties']);
		$this->assertSame('{}', json_encode($output['items'][0]['properties']));
		// Repeat in non-JSON-mode: expect the raw PHP to be an array. Check that its serialization is not what we need for mf2 JSON.
		$parser = new Parser($input, null, false);
		$output = $parser->parse();
		$this->assertInternalType('array', $output['items'][0]['properties']);
		$this->assertSame('[]', json_encode($output['items'][0]['properties']));
	}

}


code:
<?php

/**
 * Tests of the parsing methods within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2\Parser;
use PHPUnit_Framework_TestCase;

/**
 * Microformats Wiki Examples
 *
 * Contains tests built directly from examples given on the microformats wiki pages about µf2.
 *
 * These tend to compare the JSON-encoded output of Parser::parse() with the JSON strings given on the wiki.
 * If the given JSON is not within an `items` key of the root object, I add it and mark as so.
 *
 * @author Barnaby Walters waterpigs.co.uk <barnaby@waterpigs.co.uk>
 */
class MicroformatsWikiExamplesTest extends PHPUnit_Framework_TestCase {

	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	public function testHandlesEmptyStringsCorrectly() {
		$input = '';
		$expected = '{
	"rels": {},
	"rel-urls": {},
	"items": []
}';

		$parser = new Parser($input, '', true);
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	public function testHandlesNullCorrectly() {
		$input = Null;
		$expected = '{
	"rels": {},
	"rel-urls": {},
	"items": []
}';

		$parser = new Parser($input, '', true);
		$parser->jsonMode = true;
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	/**
	 * From http://microformats.org/wiki/microformats-2
	 */
	public function testSimplePersonReference() {
		$input = 'Frances Berriman';
		$expected = '{
	"rels": {},
	"rel-urls": {},
  "items": [{
	"type": ["h-card"],
	"properties": {
	  "name": ["Frances Berriman"]
	}
  }]
}';
		$parser = new Parser($input, '', true);
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	/**
	 * From http://microformats.org/wiki/microformats-2
	 */
	public function testSimpleHyperlinkedPersonReference() {
		$input = 'Ben Ward';
		$expected = '{
	"rels": {},
	"rel-urls": {},
  "items": [{
	"type": ["h-card"],
	"properties": {
	  "name": ["Ben Ward"],
	  "url": ["http://benward.me"]
	}
  }]
}';
		$parser = new Parser($input, '', true);
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	/**
	 * From http://microformats.org/wiki/microformats-2-implied-properties
	 */
	public function testSimplePersonImage() {
		$input = '';
		// Added root items key
		$expected = '{
	"rels": {},
	"rel-urls": {},
	"items": [{
  "type": ["h-card"],
  "properties": {
	"name": ["Chris Messina"],
	"photo": ["http://example.org/pic.jpg"]
  }
}]}';
		$parser = new Parser($input, '', true);
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	/**
	 * From http://microformats.org/wiki/microformats-2-implied-properties
	 */
	public function testHyperlinkedImageNameAndPhotoProperties() {
		$input = '

';
		// Added root items key
		$expected = '{
	"rels": {},
	"rel-urls": {},
	"items": [{
  "type": ["h-card"],
  "properties": {
	"name": ["Rohit Khare"],
	"url": ["http://rohit.khare.org/"],
	"photo": ["https://s3.amazonaws.com/twitter_production/profile_images/53307499/180px-Rohit-sq_bigger.jpg"]
  }
}]}';
		$parser = new Parser($input, '', true);
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	/**
	 * From http://microformats.org/wiki/microformats-2
	 */
	public function testMoreDetailedPerson() {
		$input = '

  Mitchell Baker
 (@MitchellBaker)
  Mozilla Foundation

	Mitchell is responsible for setting the direction and scope of the Mozilla Foundation and its activities.

  Strategy
  Leadership

';

		$expected = '{
  "rels": {},
  "rel-urls": {},
	"items": [{
	"type": ["h-card"],
	"properties": {
	  "photo": ["https://webfwd.org/content/about-experts/300.mitchellbaker/mentor_mbaker.jpg"],
	  "name": ["Mitchell Baker"],
	  "url": [
		"http://blog.lizardwrangler.com/",
		"https://twitter.com/MitchellBaker"
	  ],
	  "org": ["Mozilla Foundation"],
	  "note": ["Mitchell is responsible for setting the direction and scope of the Mozilla Foundation and its activities."],
	  "category": [
		"Strategy",
		"Leadership"
	  ]
	}
  }]
}';
		$parser = new Parser($input, '', true);
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}
}


code:
<?php

/**
 * Tests of the parsing methods within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2\Parser;
use PHPUnit_Framework_TestCase;

class ParseDTTest extends PHPUnit_Framework_TestCase {

	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	// Note that value-class tests for dt-* attributes are stored elsewhere, as there are so many of the bloody things

	/**
	 * @group parseDT
	 */
	public function testParseDTHandlesImg() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-08-05T14:50', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @group parseDT
	 */
	public function testParseDTHandlesDataValueAttr() {
		$input = '
<data class="dt-start" value="2012-08-05T14:50">
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-08-05T14:50', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @group parseDT
	 */
	public function testParseDTHandlesDataInnerHTML() {
		$input = '
<data class="dt-start">2012-08-05T14:50</data>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-08-05T14:50', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @group parseDT
	 */
	public function testParseDTHandlesAbbrValueAttr() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-08-05T14:50', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @group parseDT
	 */
	public function testParseDTHandlesAbbrInnerHTML() {
		$input = '
2012-08-05T14:50
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-08-05T14:50', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @group parseDT
	 */
	public function testParseDTHandlesTimeDatetimeAttr() {
		$input = '
<time class="dt-start" datetime="2012-08-05T14:50">
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-08-05T14:50', $output['items'][0]['properties']['start'][0]);
	}

  /**
   * @group parseDT
   */
  public function testParseDTHandlesTimeDatetimeAttrWithZ() {
    $input = '
<time class="dt-start" datetime="2012-08-05T14:50:00Z">
';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('start', $output['items'][0]['properties']);
    $this->assertEquals('2012-08-05T14:50:00Z', $output['items'][0]['properties']['start'][0]);
  }

  /**
   * @group parseDT
   */
  public function testParseDTHandlesTimeDatetimeAttrWithTZOffset() {
    $input = '
<time class="dt-start" datetime="2012-08-05T14:50:00-0700">
';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('start', $output['items'][0]['properties']);
    $this->assertEquals('2012-08-05T14:50:00-0700', $output['items'][0]['properties']['start'][0]);
  }

  /**
   * @group parseDT
   */
  public function testParseDTHandlesTimeDatetimeAttrWithTZOffset2() {
    $input = '
<time class="dt-start" datetime="2012-08-05T14:50:00-07:00">
';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('start', $output['items'][0]['properties']);
    $this->assertEquals('2012-08-05T14:50:00-07:00', $output['items'][0]['properties']['start'][0]);
  }

	/**
	 * @group parseDT
	 */
	public function testParseDTHandlesTimeInnerHTML() {
		$input = '
<time class="dt-start">2012-08-05T14:50</time>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-08-05T14:50', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @group parseDT
	 */
	public function testParseDTHandlesInsDelDatetime() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertArrayHasKey('end', $output['items'][0]['properties']);
		$this->assertEquals('2012-08-05T14:50', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2012-08-05T18:00', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 * @group parseDT
	 * @group valueClass
	 */
	public function testYYYY_MM_DD__HH_MM() {
		$input = '
2012-10-07 at 21:18
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-10-07 21:18', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @group parseDT
	 * @group valueClass
	 */
	public function testAbbrYYYY_MM_DD__HH_MM() {
		$input = '
some day at 21:18
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-10-07 21:18', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @group parseDT
	 * @group valueClass
	 */
	public function testYYYY_MM_DD__HHpm() {
		$input = '
2012-10-07 at 9pm
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-10-07 21:00', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @group parseDT
	 * @group valueClass
	 */
	public function testYYYY_MM_DD__HH_MMpm() {
		$input = '
2012-10-07 at 9:00pm
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-10-07 21:00', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @group parseDT
	 * @group valueClass
	 */
	public function testYYYY_MM_DD__HH_MM_SSpm() {
		$input = '
2012-10-07 at 9:00:00pm
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2012-10-07 21:00:00', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * This test name refers to the value-class used within the dt-end.
	 * @group parseDT
	 * @group valueClass
	 */
	public function testImpliedDTEndWithValueClass() {
		$input = '
 2014-06-04 at 18:30 19:30
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertArrayHasKey('end', $output['items'][0]['properties']);
		$this->assertEquals('2014-06-04 18:30', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2014-06-04 19:30', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 * This test name refers to the lack of value-class within the dt-end.
	 * @group parseDT
	 * @group valueClass
	 */
	public function testImpliedDTEndWithoutValueClass() {
		$input = '
 2014-06-05 at 18:31 19:31
';

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertArrayHasKey('end', $output['items'][0]['properties']);
		$this->assertEquals('2014-06-05 18:31', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2014-06-05 19:31', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/pull/46
	 * @group parseDT
	 * @group valueClass
	 */
	public function testImpliedDTEndUsingNonValueClassDTStart() {
		$input = '
 <time class="dt-start">2014-06-05T18:31</time> until 19:31
';

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertArrayHasKey('end', $output['items'][0]['properties']);
		$this->assertEquals('2014-06-05T18:31', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2014-06-05 19:31', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 * @group parseDT
	 * @group valueClass
	 */
	public function testDTStartOnly() {
		$input = '
 2014-06-06 at 18:32
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2014-06-06 18:32', $output['items'][0]['properties']['start'][0]);
		$this->assertArrayNotHasKey('end', $output['items'][0]['properties']);
	}

	/**
	 * @group parseDT
	 * @group valueClass
	 */
	public function testDTStartDateOnly() {
		$input = '
 2014-06-07
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('start', $output['items'][0]['properties']);
		$this->assertEquals('2014-06-07', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * TZ offsets normalized only for VCP.
	 * This behavior is implied from "However the colons ":" separating the hours and minutes of any timezone offset are optional and discouraged in order to make it less likely that a timezone offset will be confused for a time."
	 * @see http://microformats.org/wiki/index.php?title=value-class-pattern&oldid=66473##However+the+colons
	 */
	public function testNormalizeTZOffsetVCP() {
		$input = '

             <time class="value" datetime="2017-05-27">May 27</time>, from
            <time class="value">20:57-07:00</time>

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2017-05-27 20:57-0700', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * TZ offsets *not* normalized for non-VCP dates
	 */
	public function testNoNormalizeTZOffset() {
		$input = '
 <time class="dt-start" datetime="2018-03-13 15:30-07:00">March 13, 2018 3:30PM</time>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2018-03-13 15:30-07:00', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/115
	 */
	public function testDoNotAddT() {
		$input = '

    <time class="value" datetime="2009-06-26">26 July</time>, from
    <time class="value">19:00:00-08:00</time>

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2009-06-26 19:00:00-0800', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/115
	 */
	public function testPreserrveTIfAuthored() {
		$input = '
 <time class="dt-start" datetime="2009-06-26T19:01-08:00">26 July, 7:01pm</time>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2009-06-26T19:01-08:00', $output['items'][0]['properties']['start'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/126
	 */
	public function testDtVCPTimezone() {
		$input = '

 HomebrewWebsiteClub Berlin will be next on

  2017-05-31, from
  19:00 (UTC+02:00)
 to  21:00.
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2017-05-31 19:00+0200', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2017-05-31 21:00+0200', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/126
	 */
	public function testDtVCPTimezoneShort() {
		$input = '

 HomebrewWebsiteClub Berlin will be next on

  2017-05-31, from
  19:00 (UTC+2)
 to  21:00.
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2017-05-31 19:00+0200', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2017-05-31 21:00+0200', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/126
	 */
	public function testDtVCPTimezoneNoLeadingZero() {
		$input = '

		2017-06-17
		22:00-700

		2017-06-17
		23:00-700

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2017-06-17 22:00-0700', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2017-06-17 23:00-0700', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 * @see https://github.com/microformats/microformats2-parsing/issues/4
	 */
	public function testImplyTimezoneFromStart() {
		$input = '
 <time class="dt-start" datetime="2014-09-11 13:30-0700">13:30</time> to <time class="dt-end">15:30</time>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2014-09-11 13:30-0700', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2014-09-11 15:30-0700', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 * @see https://github.com/microformats/microformats2-parsing/issues/4
	 */
	public function testImplyTimezoneFromEnd() {
		$input = '
 <time class="dt-start" datetime="2014-09-11 13:30">13:30</time> to <time class="dt-end">15:30-0700</time>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2014-09-11 13:30-0700', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2014-09-11 15:30-0700', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 *
	 */
	public function testAMPMWithPeriods() {
		$input = '

		2017-06-11
		10:00P.M.

		2017-06-12
		02:00a.m.

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2017-06-11 22:00', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2017-06-12 02:00', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 *
	 */
	public function testAMPMWithoutPeriods() {
		$input = '

		2017-06-17
		10:30pm

		2017-06-18
		02:30AM

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2017-06-17 22:30', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2017-06-18 02:30', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 *
	 */
	public function testDtVCPTimeAndTimezone() {
		$input = '

		2017-06-17
		13:30-07:00

		2017-06-17
		15:30-0700

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2017-06-17 13:30-0700', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2017-06-17 15:30-0700', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/147
	 */
	public function testDtVCPMultipleDatesAndTimezones() {
		$input = '

Multiple date and time values

 When:

    2014-06-01
    3014-06-01
    12:30
    (UTC-06:00)
    23:00
    (UTC+01:00)
    –
    19:30

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2014-06-01 12:30-0600', $output['items'][0]['properties']['start'][0]);
		$this->assertEquals('2014-06-01 19:30-0600', $output['items'][0]['properties']['end'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/149
	 */
	public function testDtWithoutYear() {
		$input = '
 <time class="dt-bday" datetime="--12-28"></time>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('--12-28', $output['items'][0]['properties']['bday'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/167
	 * @see https://github.com/microformats/mf2py/blob/master/test/examples/datetimes.html
	 */
	public function testNormalizeOrdinalDate() {
		$input = '

Ordinal date

 When:

			2016-062
			12:30AM
			(UTC-06:00)

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2016-03-02 12:30-0600', $output['items'][0]['properties']['start'][0]);
	}
}


code:
<?php
/**
 * Tests of the parsing methods within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2;
use Mf2\Parser;
use PHPUnit_Framework_TestCase;

/**
 * @todo some of these can be made into single tests with dataProviders
 */
class ParseImpliedTest extends PHPUnit_Framework_TestCase {
	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	public function testParsesImpliedPNameFromNodeValue() {
		$input = 'The Name';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('The Name', $output['items'][0]['properties']['name'][0]);
	}

	public function testParsesImpliedPNameFromImgAlt() {
		$input = '';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('The Name', $output['items'][0]['properties']['name'][0]);
	}

	public function testParsesImpliedPNameFromNestedImgAlt() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('The Name', $output['items'][0]['properties']['name'][0]);
	}

	public function testParsesImpliedPNameFromDoublyNestedImgAlt() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('The Name', $output['items'][0]['properties']['name'][0]);
	}

	public function testParsesImpliedUPhotoFromImgSrc() {
		$input = '';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/img.png', $output['items'][0]['properties']['photo'][0]);
	}

	public function testParsesImpliedUPhotoFromNestedImgSrc() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/img.png', $output['items'][0]['properties']['photo'][0]);
	}

	public function testParsesImpliedUPhotoFromDoublyNestedImgSrc() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/img.png', $output['items'][0]['properties']['photo'][0]);
	}

	/*
	 * see testImpliedPhotoFromNestedObject() and testImpliedPhotoFromNestedObject()
	public function testIgnoresImgIfNotOnlyChild() {
		$input = '

Moar text

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayNotHasKey('photo', $output['items'][0]['properties']);
	}

	public function testIgnoresDoublyNestedImgIfNotOnlyDoublyNestedChild() {
		$input = '

Moar text

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayNotHasKey('photo', $output['items'][0]['properties']);
	}
	*/

	public function testParsesImpliedUUrlFromAHref() {
		$input = 'Some Name';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][0]['properties']['url'][0]);
	}

	public function testParsesImpliedUUrlFromNestedAHref() {
		$input = 'Some Name';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][0]['properties']['url'][0]);
	}

  public function testParsesImpliedUUrlWithExplicitName() {
    $input = 'Some Name';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('url', $output['items'][0]['properties']);
    $this->assertEquals('http://example.com/', $output['items'][0]['properties']['url'][0]);
  }

  public function testParsesImpliedNameWithExplicitURL() {
    $input = 'Some Name';
    $parser = new Parser($input);
    $output = $parser->parse();

    $this->assertArrayHasKey('url', $output['items'][0]['properties']);
    $this->assertEquals('http://example.com/', $output['items'][0]['properties']['url'][0]);
    $this->assertEquals('Some Name', $output['items'][0]['properties']['name'][0]);
  }

	public function testMultipleImpliedHCards() {
		$input = 'Frances Berriman

Ben Ward

';
		$expected = '{
	"rels": {},
	"rel-urls": {},
	"items": [{
		"type": ["h-card"],
		"properties": {
			"name": ["Frances Berriman"]
		}
	},
	{
		"type": ["h-card"],
		"properties": {
			"name": ["Ben Ward"],
			"url": ["http://benward.me"]
		}
	},
	{
		"type": ["h-card"],
		"properties": {
			"name": ["Sally Ride"],
			"photo": ["http://upload.wikimedia.org/wikipedia/commons/a/a4/Ride-s.jpg"]
		}
	},
	{
		"type": ["h-card"],
		"properties": {
			"name": ["Tantek Çelik"],
			"url": ["http://tantek.com"],
			"photo": ["http://ttk.me/logo.jpg"]
		}
	}]
}';

		$parser = new Parser($input, '', true);
		$output = $parser->parse();

		$this->assertJsonStringEqualsJsonString(json_encode($output), $expected);
	}

	/** as per https://github.com/indieweb/php-mf2/issues/37 */
	public function testParsesImpliedNameConsistentWithPName() {
		$inner = "Name	\nand more";
		$test = ' ' . $inner .'  ' . $inner . ' ';
		$result = Mf2\parse($test);
		$this->assertEquals('Name and more', $result['items'][0]['properties']['name'][0]);
		$this->assertEquals('Name and more', $result['items'][1]['properties']['name'][0]);
	}

	/** @see https://github.com/indieweb/php-mf2/issues/6 */
	public function testParsesImpliedNameFromAbbrTitle() {
		$input = 'BJW';
		$result = Mf2\parse($input);
		$this->assertEquals('Barnaby Walters', $result['items'][0]['properties']['name'][0]);
	}

	public function testImpliedPhotoFromObject() {
		$input = '<object class="h-card" data="http://example/photo1.jpg">John Doe</object>';
		$result = Mf2\parse($input);

		$this->assertArrayHasKey('photo', $result['items'][0]['properties']);
		$this->assertEquals('http://example/photo1.jpg', $result['items'][0]['properties']['photo'][0]);
	}

	/**
	 * Correcting previous test testIgnoresImgIfNotOnlyChild()
	 * This *should* return the photo since h-x>img[src]:only-of-type:not[.h-*]
	 * @see https://indiewebcamp.com/User:Tantek.com
	 */
	public function testImpliedPhotoFromNestedImg() {
		$input = 'Tantek Çelik';
		$result = Mf2\parse($input);

		$this->assertArrayHasKey('photo', $result['items'][0]['properties']);
		$this->assertEquals('https://pbs.twimg.com/profile_images/423350922408767488/nlA_m2WH.jpeg', $result['items'][0]['properties']['photo'][0]);
	}

	public function testIgnoredPhotoIfMultipleImg() {
		$input = '

';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('photo', $result['items'][0]['properties']);
	}

	/**
	 * Correcting previous test testIgnoresDoublyNestedImgIfNotOnlyDoublyNestedChild()
	 * This *should* return the photo since .h-x>object[data]:only-of-type:not[.h-*]
	 */
	public function testImpliedPhotoFromNestedObject() {
		$input = '
<object data="http://example/photo3.jpg">John Doe</object>
Moar text

';
		$result = Mf2\parse($input);

		$this->assertArrayHasKey('photo', $result['items'][0]['properties']);
		$this->assertEquals('http://example/photo3.jpg', $result['items'][0]['properties']['photo'][0]);
	}

	public function testIgnoredPhotoIfMultipleObject() {
		$input = '
<object data="http://example/photo3.jpg">John Doe</object> <object data="http://example/photo4.jpg"></object>
';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('photo', $result['items'][0]['properties']);
	}

	public function testIgnoredPhotoIfNestedImgH() {
		$input = '

';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('photo', $result['items'][0]['properties']);
	}

	public function testIgnoredPhotoIfNestedImgHasHClass() {
		$input = '

';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('photo', $result['items'][0]['properties']);
	}

	public function testIgnoredPhotoIfNestedObjectHasHClass() {
		$input = '
 <object data="http://example/photo3.jpg" class="h-card">John Doe</object>
';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('photo', $result['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/176
	 */
	public function testIgnoredPhotoImgInNestedH() {
		$input = '

';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('photo', $result['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/176
	 */
	public function testIgnoredPhotoObjectInNestedH() {
		$input = '

 <object data="/image2.jpg">John Doe</object>

';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('photo', $result['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/190
	 */
	public function testIgnoredMultiChildrenWithNestedPhotoImg() {
		$input = '
  Max Mustermann
';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('photo', $result['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/190
	 */
	public function testIgnoredMultiChildrenWithNestedPhotoObject() {
		$input = '
 <object data="https://example.com/photo.jpg"></object> Max Mustermann
';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('photo', $result['items'][0]['properties']);
	}

	/**
	 * Imply properties only on explicit h-x class name root microformat element (no backcompat roots)
	 * @see http://microformats.org/wiki/microformats2-parsing#parsing_for_implied_properties
	 */
	public function testBackcompatNoImpliedName() {
		$input = '

 blah blah blah

';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('name', $result['items'][0]['properties']);
		$this->assertArrayHasKey('content', $result['items'][0]['properties']);
	}

	/**
	 * Imply properties only on explicit h-x class name root microformat element (no backcompat roots)
	 * @see http://microformats.org/wiki/microformats2-parsing#parsing_for_implied_properties
	 */
	public function testBackcompatNoImpliedPhoto() {
		$input = '

';
		$result = Mf2\parse($input);

		$this->assertEmpty($result['items'][0]['properties']);
	}

	/**
	 * Imply properties only on explicit h-x class name root microformat element (no backcompat roots)
	 * @see http://microformats.org/wiki/microformats2-parsing#parsing_for_implied_properties
	 */
	public function testBackcompatNoImpliedUrl() {
		$input = '
 Title

 blah blah blah

';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('url', $result['items'][0]['properties']);
		$this->assertArrayHasKey('name', $result['items'][0]['properties']);
		$this->assertArrayHasKey('content', $result['items'][0]['properties']);
	}

	/**
	 * Don't imply u-url if there are other u-*
	 * @see http://microformats.org/wiki/microformats2-parsing#parsing_for_implied_properties
	 * @see https://github.com/microformats/php-mf2/issues/183
	 */
	public function testNoImpliedUrl() {
		$input = '

Title

 blah blah blah

';
		$result = Mf2\parse($input);

		$this->assertArrayNotHasKey('url', $result['items'][0]['properties']);
	}

	/**
	 * Do not use img src in implied p-name
	 * @see https://github.com/microformats/php-mf2/issues/180
	 */
	public function testNoImgSrcImpliedName() {
		$input = '
My Name
';
		$result = Mf2\parse($input);

		$this->assertArrayHasKey('name', $result['items'][0]['properties']);
		$this->assertEquals('My Name', $result['items'][0]['properties']['name'][0]);
	}
}


code:
<?php

/**
 * Tests of the language parsing methods within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2\Parser;
use Mf2;
use PHPUnit_Framework_TestCase;

class ParseLanguageTest extends PHPUnit_Framework_TestCase {

	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	/**
	 * Test with only
	 */
	public function testHtmlLangOnly()
	{
		$input = '
This test is in English.
 ';
		$parser = new Parser($input);
		$parser->lang = true;
		$result = $parser->parse();

		$this->assertArrayHasKey('lang', $result['items'][0]);
		$this->assertEquals('en', $result['items'][0]['lang']);
	} # end method testHtmlLangOnly()

	/**
	 * Test with only h-entry lang
	 */
	public function testHEntryLangOnly()
	{
		$input = '
This test is in English.
 ';
		$parser = new Parser($input);
		$parser->lang = true;
		$result = $parser->parse();

		$this->assertArrayHasKey('lang', $result['items'][0]);
		$this->assertEquals('en', $result['items'][0]['lang']);
	} # end method testHEntryLangOnly()

	/**
	 * Test with different  and h-entry lang
	 */
	public function testHtmlAndHEntryLang()
	{
		$input = '
Esta prueba está en español.
 ';
		$parser = new Parser($input);
		$parser->lang = true;
		$result = $parser->parse();

		$this->assertArrayHasKey('lang', $result['items'][0]);
		$this->assertEquals('es', $result['items'][0]['lang']);
	} # end method testHtmlAndHEntryLang()

    /**
     * Test HTML fragment with only h-entry lang
     */
    public function testFragmentHEntryLangOnly()
    {
        $input = '
This test is in English.
';
        $parser = new Parser($input);
        $parser->lang = true;
        $result = $parser->parse();

        $this->assertArrayHasKey('lang', $result['items'][0]);
        $this->assertEquals('en', $result['items'][0]['lang']);
    } # end method testFragmentHEntryLangOnly()

    /**
     * Test HTML fragment with no lang
     */
    public function testFragmentHEntryNoLang()
    {
        $input = '
This test is in English.
';
        $parser = new Parser($input);
        $parser->lang = true;
        $result = $parser->parse();

        $this->assertArrayNotHasKey('lang', $result['items'][0]);
    } # end method testFragmentHEntryNoLang()

    /**
     * Test HTML fragment with no lang, loaded with loadXML()
     */
    public function testFragmentHEntryNoLangXML()
    {
        $input = new \DOMDocument();
        $input->loadXML('
This test is in English.
');
        $parser = new Parser($input);
        $result = $parser->parse();

        $this->assertArrayNotHasKey('lang', $result['items'][0]);
    } # end method testFragmentHEntryNoLangXML()

	/**
	 * Test with different , h-entry lang, and h-entry without lang,
	 * which should inherit from the
	 */
	public function testMultiLanguageInheritance()
	{
		$input = '
This test is in English.

Esta prueba está en español.
 ';
		$parser = new Parser($input);
		$parser->lang = true;
		$result = $parser->parse();

		$this->assertArrayHasKey('lang', $result['items'][0]);
		$this->assertArrayHasKey('lang', $result['items'][1]);
		$this->assertEquals('en', $result['items'][0]['lang']);
		$this->assertEquals('es', $result['items'][1]['lang']);
	} # end method testMultiLanguageInheritance()

	/**
	 * Test feed with .h-feed lang which contains multiple h-entries of different languages
	 * (or none specified), which should inherit from the .h-feed lang.
	 */
	public function testMultiLanguageFeed()
	{
		$input = '

Test Feed

This test is in English.

Esta prueba está en español.

Ce test est en français.
 ';
		$parser = new Parser($input);
		$parser->lang = true;
		$result = $parser->parse();

		$this->assertArrayHasKey('lang', $result['items'][0]);
		$this->assertEquals('en', $result['items'][0]['lang']);

		$this->assertArrayHasKey('lang', $result['items'][0]['children'][0]);
		$this->assertEquals('en', $result['items'][0]['children'][0]['lang']);

		$this->assertArrayHasKey('lang', $result['items'][0]['children'][1]);
		$this->assertEquals('es', $result['items'][0]['children'][1]['lang']);

		$this->assertArrayHasKey('lang', $result['items'][0]['children'][2]);
		$this->assertEquals('fr', $result['items'][0]['children'][2]['lang']);
	} # end method testMultiLanguageFeed()

	/**
	 * Test with language specified in <meta> http-equiv Content-Language
	 */
	public function testMetaContentLanguage()
	{
		$input = ' <meta http-equiv="Content-Language" content="es"/>
Esta prueba está en español.
 ';
		$parser = new Parser($input);
		$parser->lang = true;
		$result = $parser->parse();

		$this->assertArrayHasKey('lang', $result['items'][0]);
		$this->assertEquals('es', $result['items'][0]['lang']);
	} # end method testMetaContentLanguage()

	/**
	 * Test with real-world post on voxpelli.com
	 * @see http://voxpelli.com/2015/09/oberoende-sociala-webben-2015/
	 */
	public function testVoxpelliCom()
	{
		$input = <<< END
<!DOCTYPE html>

<meta charset="utf-8">
<title>Den oberoende sociala webben 2015 – Pelle Wessman</title>

<meta content="width=device-width, initial-scale=1" name="viewport">
<link href="/css/style.css" media="all" rel="stylesheet" type="text/css">
<link href="/all.xml" rel="home alternate" title="All posts" type="application/atom+xml">
<link href="/english.xml" rel="home alternate" title="English posts" type="application/atom+xml">
<link href="http://voxpelli.com/2015/09/oberoende-sociala-webben-2015/" rel="canonical">
<meta content="@voxpelli" name="twitter:site">
<link href="/" rel="author" title="Pelle Wessman" type="text/html">
<link href="https://flattr.com/submit/auto?url=http%3A%2F%2Fvoxpelli.com%2F2015%2F09%2Foberoende-sociala-webben-2015%2F&user_id=voxpelli&title=Den+oberoende+sociala+webben+2015&category=text&tags=blog&language=sv" rel="payment" title="Flattr this post" type="text/html">
<link href="https://webmention.herokuapp.com/api/webmention" rel="webmention">

Pelle Wessman

Things about me and the world around us

Den oberoende sociala webben 2015

Sociala medier. Synonymt med Facebook, Twitter, Instagram. Vad händer när en av dem försvinner? Är det game over då? Jaiku i repris, fast denna gång utan livlina?

Framtiden för sociala medier kan låta dyster. Om de inte läggs ner helt så kan de ju i alla fall ha moraliska frågetecken kring konst, aktivism eller annat. Men i det fördolda har många länge ställt frågan: Om webben är öppen, varför måste det sociala vara stängt? Och nu börjar det röra sig där.

Att ställa en fråga har alltid varit bra. Att fixa en lösning har ofta varit bättre. Att fixa lösningar har dock inte lyckats lika bra som alla frågor som ställts. Många fina lösningar har tänkts ut, men de flesta har ignorerat den verklighet och det sammanhang vi lever i och framförallt den nätverkseffekt som ger de sociala medierna sitt största värde idag. Men – turligt nog rättar sig inte alla i det ledet och nu börjar det bli spännande.

IndieWebCamp startade 2010 av Aaron Parecki och Tantek Çelik för att de ville se ett annat fokus än det tanke-centrerade, små-akademiska som varit innan. Ett fokus på att skapa snarare än att prata. Ett fokus på att lösa ens egna problem. Och ett fokus på att äga sin egna data i praktiken, inte bara i teorin. Sedan dess har många anslutit sig och flertalet verktyg och tjänster växt fram – IndieWebben har blivit en rörelse.

Idag är i princip alla komponenter redo för att kunna återföra det som en gång i tiden kallades för mikrobloggar tillbaka till sina bloggrötter. Och det utan att bryta med de stora sociala medierna så som många tidigare lösningar krävt. Det finns de som redan gör så idag, bl.a. grundarna av IndieWebCamp, och även min blogg är väl nästan redo att sälla sig dit.

Så – idag kan man alltså i princip både vara sin egen och vara en del i de stora sociala plattformarna – och de skarpa hörnen som ännu finns blir mer och mer rundade för var dag som går.

För att vara mer konkret så har det ur IndieWeb-rörelsen kommit möjligheter att:

Ta emot replies, likes m.m. på sina inlägg direkt från andra bloggar via en teknik som kallas WebMentions. Bl.a. jag själv tillhandahåller en Disqus-liknande tjänst som gör det lätt att ta emot sådana reaktioner i realtid på vilken sida som helst – något flera har valt att nyttja.

Posta poster från ens egna sajt till existerande sociala medier via vad som kallas POSSE (Publish (on your) Own Site, Syndicate Elsewhere) och få tillbaka reaktioner därifrån som WebMentions genom tjänster såsom Brid.gy – så att de som ännu hänger kvar i klassiska sociala medier kan fortsatt vara lika delaktiga som de är idag.

Svara på inlägg direkt från någon annans sajt genom Webactions och Indie-Config (se mitt tidigare inlägg). Sådana knappar finns t.ex. på denna posten, men i nuläget har jag inte själv kopplat in reaktioner från Twitter så de kommentarer som postas via Twitter syns tyvärr inte här ännu.

Posta nytt innehåll via ett standardiserat API, Micropub. Det möjliggör t.ex. för mobila klienter (har spelat in en screencast som visar en prototyp på ett flöde som man kan få till redan idag) liksom för automatisk import från existerande medier såsom från Instagram via OwnYourGram. Mitt nuvarande IndieWeb-projekt som i princip är klart exponerar till och med ett sådant API för statiska Jekyll-sajter på GitHub Pages eftersom jag själv kör en sådan. Kommer blogga mer om det längre fram.

En inloggningsmekanism, IndieAuth, som gör att man kan logga in på alla olika tjänster med sin egna sajt och ge tillgång till olika saker där – likt ”Sign in with Twitter” och liknande – fast som allt annat inom IndieWebben helt distribuerat.

Olika läsare för oberoende innehåll om man vill följa dem och interagera med dem oberoende av existerande medier. Vissa av dessa kan också användas för att interagera med poster och publicera nya vilket i princip gör dem till fullgoda sociala medie-alternativ, med enda skillnaden att alla poster och aktiviteter postas på individuella och helt separata bloggar. Hittills efterliknar tyvärr de flesta sådana läsarna RSS-läsare snarare än sociala medier, men det är mer av en designutmaning än en teknisk utmaning – grunden är densamma oavsett.

Så I stort sett täcker IndieWebben idag åtminstone allt det en plattform som Twitter behöver kunna – och i stort så kan det göras lika smidigt där som det kan på Twitter.

IndieWeb-rörelsen tog dessutom för någon månad sedan och demonstrerade att de kunde genomföra det så kallade SWAT0-testet som är tänkt att vara ett implementationsoberoende test för att visa att ens tjänster distribuerat klarar av att hantera ett måttligt vanligt sociala medier scenario. Tre aktörer med tre olika implementationer deltog i testet och många fler är på gång att kunna demonstrera detsamma, däribland min egna WebMentions-tjänst som nästan har alla bitar på plats.

Så – vad är slutsatsen med allt detta Indie-hit och Indie-dit? Är det inte ändå till syvende och sist bara massa tekniknördar som flippar loss med sina älskade tekniska termer och som saknar varje liten verklighetsförankring man skulle kunna önska? Nej. Denna gången är det annorlunda. Denna gången är fokus på verkstad. Denna gången bevisas att något funkar innan det dokumenteras som en standard. Denna gången löser något ett verkligt behov före att det lyfts fram som frälsaren för alla de andra. Ingen IndieWeb-standard har kommit till utan att också ha haft en fungerade använd implementation i verkligheten från dag ett.

Eftersom fokuset varit på verkstad så har indiewebben byggts för att kunna samexistera med dagens sociala webb och i takt med att de stora sociala mediernas roll därmed så sakteliga kan minska i takt med att oberoende lösningar börjar användas så kan ett gradvis överflyttande ske i takt med att allt fler upptäcker fördelarna – ett hyfsat realistiskt scenario alltså till skillnad mot många tidigare drömmar.

Allt är såklart inte guld och gröna skogar ännu. Det finns fortfarande svårigheter kvar och alla varken kan, bör eller kommer att byta över idag eller imorgon. Men det viktiga är: Det finns en lovande start som det är lätt att börja nosa på och i takt med att allt fler nosar så fås allt mer erfarenhet och med mer erfarenhet byggs än bättre upplevelser och plötsligt finns där en klar väg framåt (en väg som dessutom öppnar för många nya spännande innovationer inom området).

Så när Twitter kanske så småningom försvinner så kanske den inte blir ett nytt Jaiku. För då kanske vi flyttat tillbaka hem. Vi kanske då har vår bas på den egna bloggen igen. Och då kan ingen någonsin stänga ner oss igen. Då är vi våra egna och ingen annans. Oberoende på riktigt. Så som webben är ment att vara.

Inskickad till:

news.indiewebcamp

<time class="dt-published" datetime="2015-09-18T19:00:00+00:00" pubdate="">18 September 2015</time> by  Pelle Wessman

Like Share Reply

See mentions of this post

Have you written a response to this? Let me know the URL:
<form action="https://webmention.herokuapp.com/api/webmention" method="post"><input name="source" placeholder="http://example.com/my-cool-post" type="url"> <input name="target" type="hidden" value="http://voxpelli.com/2015/09/oberoende-sociala-webben-2015/"> <input type="submit" value="Send Webmention"></form>

END;
		$parser = new Parser($input);
		$parser->lang = true;
		$result = $parser->parse();

		$this->assertArrayHasKey('lang', $result['items'][0]);
		$this->assertEquals('sv', $result['items'][0]['lang']);
	} # end method testVoxpelliCom()

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/96#issuecomment-304457341
	 */
	public function testNoLangInParsedProperties() {
		$input = '

En svensk titel

With an english summary

Och svensk huvudtext

';
		$parser = new Parser($input);
		$parser->lang = true;
		$result = $parser->parse();

		$this->assertArrayNotHasKey('lang', $result['items'][0]['properties']);
		$this->assertArrayHasKey('lang', $result['items'][0]);
	}

}


code:
<?php

/**
 * Tests of the parsing methods within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2;
use Mf2\Parser;
use PHPUnit_Framework_TestCase;

class ParsePTest extends PHPUnit_Framework_TestCase {

	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	/**
	 * @group parseP
	 */
	public function testParsePHandlesInnerText() {
		$input = '

Example User

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Example User', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @group parseP
	 */
	public function testParsePHandlesImg() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Example User', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @group parseP
	 */
	public function testParsePHandlesAbbr() {
		$input = '
@example
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Example User', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @group parseP
	 */
	public function testParsePHandlesData() {
		$input = '
<data class="p-name" value="Example User"></data>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Example User', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @group parseP
	 */
	public function testParsePHandlesDataWithBlankValueAttribute() {
		$input = '
<data class="p-name" value="">Example User</data>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @group parseP
	 */
	public function testParsePReturnsEmptyStringForBrHr() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('', $output['items'][0]['properties']['name'][0]);
		$this->assertEquals('', $output['items'][0]['properties']['name'][0]);
	}

	public function testParsesInputValue() {
		$input = '<input class="u-url" value="http://example.com" />';
		$result = Mf2\parse($input);
		$this->assertEquals('http://example.com', $result['items'][0]['properties']['url'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/53
	 * @see http://microformats.org/wiki/microformats2-parsing#parsing_an_e-_property
	 */
	public function testConvertsNestedImgElementToAltOrSrc() {
		$input = <<<EOT

The day I saw a

Blah blah

EOT;
		$result = Mf2\parse($input, 'http://waterpigs.co.uk/articles/five-legged-elephant');
		$this->assertEquals('The day I saw a five legged elephant', $result['items'][0]['properties']['name'][0]);
		$this->assertEquals('Blah blah http://waterpigs.co.uk/photos/five-legged-elephant.jpg', $result['items'][0]['properties']['summary'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/69
	 */
	public function testBrWhitespaceIssue69() {
		$input = '

Street Name 9
12345 NY, USA

';
		$result = Mf2\parse($input);

		$this->assertEquals('Street Name 9' . "\n" . '12345 NY, USA', $result['items'][0]['properties']['adr'][0]);
		$this->assertEquals('Street Name 9', $result['items'][0]['properties']['street-address'][0]);
		$this->assertEquals('12345 NY, USA', $result['items'][0]['properties']['locality'][0]);
		// p-name is no longer implied for this test due to other p-*
		// see https://github.com/microformats/microformats2-parsing/issues/6
		$this->assertArrayNotHasKey('name', $result['items'][0]['properties']);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/89
	 */
	public function testEmptyAlt() {
		$input = '
mention.tech
';
		$result = Mf2\parse($input);

		$this->assertEquals('mention.tech', $result['items'][0]['properties']['org'][0]);
		$this->assertEquals('mention.tech', $result['items'][0]['properties']['name'][0]);
	}

}


code:
<?php
/**
 * Tests of the parsing methods within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2;
use Mf2\Parser;
use PHPUnit_Framework_TestCase;

class ParseUTest extends PHPUnit_Framework_TestCase {
	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesA() {
		$input = '
Awesome example website
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com', $output['items'][0]['properties']['url'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesEmptyHrefAttribute() {
		$input = '
Awesome example website
';
		$parser = new Parser($input, "http://example.com/");
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][0]['properties']['url'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesMissingHrefAttribute() {
		$input = '
Awesome example website
';
		$parser = new Parser($input, "http://example.com/");
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/Awesome example website', $output['items'][0]['properties']['url'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesImg() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/someimage.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesArea() {
		$input = '
<area class="u-photo" href="http://example.com/someimage.png"></area>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/someimage.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesObject() {
		$input = '
<object class="u-photo" data="http://example.com/someimage.png"></object>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/someimage.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesAbbr() {
		$input = '

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/someimage.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesAbbrNoTitle() {
		$input = '
no title attribute
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('no title attribute', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesData() {
		$input = '
<data class="u-photo" value="http://example.com/someimage.png"></data>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('photo', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/someimage.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group baseUrl
	 */
	public function testResolvesRelativeUrlsFromDocumentUrl() {
		$input = '

';
		$parser = new Parser($input, 'http://example.com/things/more/more.html');
		$output = $parser->parse();

		$this->assertEquals('http://example.com/things/image.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group baseUrl
	 */
	public function testResolvesRelativeUrlsFromBaseUrl() {
		$input = '<base href="http://example.com/things/more/andmore/" />

';
		$parser = new Parser($input, 'http://example.com/things/more.html');
		$output = $parser->parse();

		$this->assertEquals('http://example.com/things/more/image.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group baseUrl
	 */
	public function testResolvesRelativeUrlsInImpliedMicroformats() {
		$input = '';
		$parser = new Parser($input, 'http://example.com/things/more.html');
		$output = $parser->parse();

		$this->assertEquals('http://example.com/things/image.png', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group baseUrl
	 */
	public function testResolvesRelativeBaseRelativeUrlsInImpliedMicroformats() {
		$input = '<base href="things/"/>';
		$parser = new Parser($input, 'http://example.com/');
		$output = $parser->parse();

		$this->assertEquals('http://example.com/things/image.png', $output['items'][0]['properties']['photo'][0]);
	}

	/** @see https://github.com/indieweb/php-mf2/issues/33 */
	public function testParsesHrefBeforeValueClass() {
		$input = 'WRONG';
		$result = Mf2\parse($input);
		$this->assertEquals('http://example.com/right', $result['items'][0]['properties']['url'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesAudio() {
		$input = '
<audio class="u-audio" src="http://example.com/audio.mp3">
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('audio', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/audio.mp3', $output['items'][0]['properties']['audio'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesVideo() {
		$input = '
<video class="u-video" src="http://example.com/video.mp4"></video>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('video', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/video.mp4', $output['items'][0]['properties']['video'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesVideoNoSrc() {
		$input = '
<video class="u-video">no video support</video>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('video', $output['items'][0]['properties']);
		$this->assertEquals('no video support', $output['items'][0]['properties']['video'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesSource() {
		$input = '
<video><source class="u-video" src="http://example.com/video.mp4" type="video/mp4"><source class="u-video" src="http://example.com/video.ogg" type="video/ogg"></video>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('video', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/video.mp4', $output['items'][0]['properties']['video'][0]);
		$this->assertEquals('http://example.com/video.ogg', $output['items'][0]['properties']['video'][1]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUHandlesVideoPoster() {
		$input = '
<video class="u-photo" poster="http://example.com/posterimage.jpg"><source class="u-video" src="http://example.com/video.mp4" type="video/mp4"></video>
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('video', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/video.mp4', $output['items'][0]['properties']['video'][0]);
		$this->assertEquals('http://example.com/posterimage.jpg', $output['items'][0]['properties']['photo'][0]);
	}

	/**
	 * @group parseU
	 */
	public function testParseUWithSpaces() {
		$input = '
Awesome example website
';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com', $output['items'][0]['properties']['url'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/130
	 */
	public function testImpliedUWithEmptyHref() {
		$input = 'Jane Doe
<area class="h-card" href="" alt="Jane Doe"/ >

Jane Doe

<area href="">Jane Doe</area>

Jane Doe

';
		$parser = new Parser($input, 'http://example.com');
		$output = $parser->parse();

		$this->assertArrayHasKey('url', $output['items'][0]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][0]['properties']['url'][0]);

		$this->assertArrayHasKey('url', $output['items'][1]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][1]['properties']['url'][0]);

		$this->assertArrayHasKey('url', $output['items'][2]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][2]['properties']['url'][0]);

		$this->assertArrayHasKey('url', $output['items'][3]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][3]['properties']['url'][0]);

		$this->assertArrayHasKey('url', $output['items'][4]['children'][0]['properties']);
		$this->assertEquals('http://example.com/', $output['items'][4]['children'][0]['properties']['url'][0]);
	}

  public function testValueFromLinkTag() {
    $input = <<< END
<!doctype html>

    <link rel="canonical" class="u-url p-name" href="https://example.com/" title="Example.com homepage">

END;

    $parser = new Parser($input, 'https://example.com');
    $output = $parser->parse();

    $this->assertArrayHasKey('url', $output['items'][0]['properties']);
    $this->assertEquals('https://example.com/', $output['items'][0]['properties']['url'][0]);

    $this->assertArrayHasKey('name', $output['items'][0]['properties']);
    $this->assertEquals('Example.com homepage', $output['items'][0]['properties']['name'][0]);
  }

  public function testResolveFromDataElement() {
    $parser = new Parser('
<data class="u-url" value="relative.html"></data>
', 'https://example.com/index.html');
    $output = $parser->parse();

    $this->assertArrayHasKey('url', $output['items'][0]['properties']);
    $this->assertEquals('https://example.com/relative.html', $output['items'][0]['properties']['url'][0]);
  }

}


code:
<?php

/**
 * Tests of the parsing methods within mf2\Parser
 */

namespace Mf2\Parser\Test;

use Mf2;
use Mf2\Parser;
use PHPUnit_Framework_TestCase;

class ParseValueClassTitleTest extends PHPUnit_Framework_TestCase {

	public function setUp() {
		date_default_timezone_set('Europe/London');
	}

	public function testValueClassTitleHandlesSingleValueClass() {
		$input = '

Name (this should not be included)

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Name', $output['items'][0]['properties']['name'][0]);
	}

	public function testValueClassTitleHandlesMultipleValueClass() {
		$input = '

Name (this should not be included) Endname

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('NameEndname', $output['items'][0]['properties']['name'][0]);
	}

	public function testValueClassTitleHandlesSingleValueTitle() {
		$input = '

Wrong Name (this should not be included)

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Real Name', $output['items'][0]['properties']['name'][0]);
	}

	public function testValueClassTitleHandlesMultipleValueTitle() {
		$input = '

Wrong Name (this should not be included)

';
		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('name', $output['items'][0]['properties']);
		$this->assertEquals('Real Name', $output['items'][0]['properties']['name'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/25
	 */
	public function testValueClassDatetimeWorksWithUrlProperties() {
		$input = <<<EOT

			<time class="value">10:17</time>
			on <time class="value">2013-06-27</time>

EOT;

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertArrayHasKey('published', $output['items'][0]['properties']);
		$this->assertEquals('2013-06-27 10:17', $output['items'][0]['properties']['published'][0]);
	}

	/**
	 * @see https://github.com/indieweb/php-mf2/issues/27
	 */
	public function testParsesValueTitleDatetimes() {
		$input = <<<EOT

test

  16.02.2012

EOT;

		$parser = new Parser($input);
		$output = $parser->parse();

		$this->assertEquals('2012-02-16T16:14:47+00:00', $output['items'][0]['properties']['published'][0]);
	}

	/** @see https://github.com/indieweb/php-mf2/issues/34 */
	public function testIgnoresValueClassNestedFurtherThanChild() {
		$test = '
12345678';
		$result = Mf2\parse($test);
		$this->assertEquals('1234', $result['items'][0]['properties']['tel'][0]);
		$this->assertEquals('5678', $result['items'][0]['children'][0]['properties']['tel'][0]);
	}

	/** @see https://github.com/indieweb/php-mf2/issues/38 */
	public function testValueClassDtMatchesSingleDigitTimeComponent() {
		$test = '
<time class="value">6:01</time>, <time class="value">2013-02-01</time>
';
		$result = Mf2\parse($test);
		$this->assertEquals('2013-02-01 6:01', $result['items'][0]['properties']['published'][0]);
	}
}