]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
[CORE] Make tests great gain
authorDiogo Cordeiro <diogo@fc.up.pt>
Fri, 12 Jul 2019 15:31:14 +0000 (16:31 +0100)
committerDiogo Cordeiro <diogo@fc.up.pt>
Sat, 3 Aug 2019 16:47:27 +0000 (17:47 +0100)
80 files changed:
composer.lock
lib/callable_left_curry.php [deleted file]
lib/callableleftcurry.php [new file with mode: 0644]
lib/common.php
lib/event.php
lib/gnusocial.php
lib/language.php
lib/plugin.php
lib/util.php
phpunit.xml [new file with mode: 0644]
tests/ActivityGenerationTests.php [deleted file]
tests/ActivityParseTests.php [deleted file]
tests/CommandInterperterTest.php [deleted file]
tests/Core/ActivityGenerationTests.php [new file with mode: 0644]
tests/Core/ActivityParseTests.php [new file with mode: 0644]
tests/Core/CallableLeftCurryTest.php [new file with mode: 0644]
tests/Core/CommandInterperterTest.php [new file with mode: 0644]
tests/Core/HashTagDetectionTests.php [new file with mode: 0644]
tests/Core/LocationTest.php [new file with mode: 0644]
tests/Core/NicknameTest.php [new file with mode: 0644]
tests/Core/TagURITest.php [new file with mode: 0644]
tests/Core/URLDetectionTest.php [new file with mode: 0644]
tests/Core/UUIDTest.php [new file with mode: 0644]
tests/Core/UserFeedParseTest.php [new file with mode: 0644]
tests/Core/UserRightsTest.php [new file with mode: 0644]
tests/Core/XmppValidateTest.php [new file with mode: 0644]
tests/CurryTest.php [deleted file]
tests/HashTagDetectionTests.php [deleted file]
tests/LocationTest.php [deleted file]
tests/Media/MediaFileTest.php [new file with mode: 0644]
tests/Media/sample-uploads/image.gif [new file with mode: 0644]
tests/Media/sample-uploads/image.jpeg [new file with mode: 0644]
tests/Media/sample-uploads/image.jpg [new file with mode: 0644]
tests/Media/sample-uploads/image.png [new file with mode: 0644]
tests/Media/sample-uploads/office.pdf [new file with mode: 0644]
tests/Media/sample-uploads/presentation.odp [new file with mode: 0644]
tests/Media/sample-uploads/presentation.otp [new file with mode: 0644]
tests/Media/sample-uploads/presentation.pot [new file with mode: 0644]
tests/Media/sample-uploads/presentation.potm [new file with mode: 0644]
tests/Media/sample-uploads/presentation.ppt [new file with mode: 0644]
tests/Media/sample-uploads/presentation.pptx [new file with mode: 0644]
tests/Media/sample-uploads/spreadsheet.ods [new file with mode: 0644]
tests/Media/sample-uploads/spreadsheet.ots [new file with mode: 0644]
tests/Media/sample-uploads/spreadsheet.xls [new file with mode: 0644]
tests/Media/sample-uploads/spreadsheet.xlsx [new file with mode: 0644]
tests/Media/sample-uploads/spreadsheet.xlt [new file with mode: 0644]
tests/Media/sample-uploads/wordproc.doc [new file with mode: 0644]
tests/Media/sample-uploads/wordproc.docx [new file with mode: 0644]
tests/Media/sample-uploads/wordproc.odt [new file with mode: 0644]
tests/Media/sample-uploads/wordproc.ott [new file with mode: 0644]
tests/Media/sample-uploads/wordproc.rtf [new file with mode: 0644]
tests/MediaFileTest.php [deleted file]
tests/NicknameTest.php [deleted file]
tests/TagURITest.php [deleted file]
tests/URLDetectionTest.php [deleted file]
tests/UUIDTest.php [deleted file]
tests/UserFeedParseTest.php [deleted file]
tests/UserRightsTest.php [deleted file]
tests/XmppValidateTest.php [deleted file]
tests/sample-uploads/image.gif [deleted file]
tests/sample-uploads/image.jpeg [deleted file]
tests/sample-uploads/image.jpg [deleted file]
tests/sample-uploads/image.png [deleted file]
tests/sample-uploads/office.pdf [deleted file]
tests/sample-uploads/presentation.odp [deleted file]
tests/sample-uploads/presentation.otp [deleted file]
tests/sample-uploads/presentation.pot [deleted file]
tests/sample-uploads/presentation.potm [deleted file]
tests/sample-uploads/presentation.ppt [deleted file]
tests/sample-uploads/presentation.pptx [deleted file]
tests/sample-uploads/spreadsheet.ods [deleted file]
tests/sample-uploads/spreadsheet.ots [deleted file]
tests/sample-uploads/spreadsheet.xls [deleted file]
tests/sample-uploads/spreadsheet.xlsx [deleted file]
tests/sample-uploads/spreadsheet.xlt [deleted file]
tests/sample-uploads/wordproc.doc [deleted file]
tests/sample-uploads/wordproc.docx [deleted file]
tests/sample-uploads/wordproc.odt [deleted file]
tests/sample-uploads/wordproc.ott [deleted file]
tests/sample-uploads/wordproc.rtf [deleted file]

index 5d4ab05e8f6778d8be89524dec737db2c214a57e..d624005f05399a3bfc88f5990ca28266b5182547 100644 (file)
         },
         {
             "name": "jms/serializer",
-            "version": "3.0.1",
+            "version": "3.1.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/schmittjoh/serializer.git",
-                "reference": "bf2bae374e565f443fc01fe60695061366bd3261"
+                "reference": "7f8dc86e9168d0112b3cc38ba8cca41b17f409a0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/bf2bae374e565f443fc01fe60695061366bd3261",
-                "reference": "bf2bae374e565f443fc01fe60695061366bd3261",
+                "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/7f8dc86e9168d0112b3cc38ba8cca41b17f409a0",
+                "reference": "7f8dc86e9168d0112b3cc38ba8cca41b17f409a0",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
                 "serialization",
                 "xml"
             ],
-            "time": "2019-04-23T17:53:59+00:00"
+            "time": "2019-06-28T09:09:40+00:00"
         },
         {
             "name": "justinrainbow/json-schema",
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "7.0.5",
+            "version": "7.0.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "aed67b57d459dcab93e84a5c9703d3deb5025dff"
+                "reference": "d471d0d2b529a67c6a722dd446c4ec90881ac315"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aed67b57d459dcab93e84a5c9703d3deb5025dff",
-                "reference": "aed67b57d459dcab93e84a5c9703d3deb5025dff",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d471d0d2b529a67c6a722dd446c4ec90881ac315",
+                "reference": "d471d0d2b529a67c6a722dd446c4ec90881ac315",
                 "shasum": ""
             },
             "require": {
                 "php": "^7.2",
                 "phpunit/php-file-iterator": "^2.0.2",
                 "phpunit/php-text-template": "^1.2.1",
-                "phpunit/php-token-stream": "^3.0.1",
+                "phpunit/php-token-stream": "^3.0.2",
                 "sebastian/code-unit-reverse-lookup": "^1.0.1",
-                "sebastian/environment": "^4.1",
+                "sebastian/environment": "^4.2.2",
                 "sebastian/version": "^2.0.1",
-                "theseer/tokenizer": "^1.1"
+                "theseer/tokenizer": "^1.1.3"
             },
             "require-dev": {
-                "phpunit/phpunit": "^8.0"
+                "phpunit/phpunit": "^8.2.2"
             },
             "suggest": {
-                "ext-xdebug": "^2.6.1"
+                "ext-xdebug": "^2.7.2"
             },
             "type": "library",
             "extra": {
                 "testing",
                 "xunit"
             ],
-            "time": "2019-06-06T12:28:18+00:00"
+            "time": "2019-07-08T05:29:42+00:00"
         },
         {
             "name": "phpunit/php-file-iterator",
         },
         {
             "name": "phpunit/php-token-stream",
-            "version": "3.0.1",
+            "version": "3.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-token-stream.git",
-                "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18"
+                "reference": "c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18",
-                "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c",
+                "reference": "c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c",
                 "shasum": ""
             },
             "require": {
             "keywords": [
                 "tokenizer"
             ],
-            "time": "2018-10-30T05:52:18+00:00"
+            "time": "2019-07-08T05:24:54+00:00"
         },
         {
             "name": "phpunit/phpunit",
-            "version": "8.2.3",
+            "version": "8.2.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "f67ca36860ebca7224d4573f107f79bd8ed0ba03"
+                "reference": "25fe0b5031b24722f66a75ad479a074cccc1bb37"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f67ca36860ebca7224d4573f107f79bd8ed0ba03",
-                "reference": "f67ca36860ebca7224d4573f107f79bd8ed0ba03",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/25fe0b5031b24722f66a75ad479a074cccc1bb37",
+                "reference": "25fe0b5031b24722f66a75ad479a074cccc1bb37",
                 "shasum": ""
             },
             "require": {
                 "sebastian/global-state": "^3.0.0",
                 "sebastian/object-enumerator": "^3.0.3",
                 "sebastian/resource-operations": "^2.0.1",
-                "sebastian/type": "^1.1.0",
+                "sebastian/type": "^1.1.3",
                 "sebastian/version": "^2.0.1"
             },
             "require-dev": {
                 "testing",
                 "xunit"
             ],
-            "time": "2019-06-19T12:03:56+00:00"
+            "time": "2019-07-03T08:30:33+00:00"
         },
         {
             "name": "pimple/pimple",
         },
         {
             "name": "sebastian/type",
-            "version": "1.1.2",
+            "version": "1.1.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/type.git",
-                "reference": "251ca774d58181fe1d3eda68843264eaae7e07ef"
+                "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/251ca774d58181fe1d3eda68843264eaae7e07ef",
-                "reference": "251ca774d58181fe1d3eda68843264eaae7e07ef",
+                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3",
+                "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3",
                 "shasum": ""
             },
             "require": {
             ],
             "description": "Collection of value objects that represent the types of the PHP type system",
             "homepage": "https://github.com/sebastianbergmann/type",
-            "time": "2019-06-19T06:39:12+00:00"
+            "time": "2019-07-02T08:10:15+00:00"
         },
         {
             "name": "sebastian/version",
diff --git a/lib/callable_left_curry.php b/lib/callable_left_curry.php
deleted file mode 100644 (file)
index 37c9c1c..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * PHP 5.3 implementation of function currying, using native closures.
- * On 5.2 and lower we use the fallback implementation in util.php
- *
- * @param callback $fn
- * @param ... any remaining arguments will be appended to call-time params
- * @return callback
- */
-function callable_left_curry($fn) {
-    $extra_args = func_get_args();
-    array_shift($extra_args);
-    return function() use ($fn, $extra_args) {
-        $args = func_get_args();
-        return call_user_func_array($fn,
-            array_merge($args, $extra_args));
-    };
-}
diff --git a/lib/callableleftcurry.php b/lib/callableleftcurry.php
new file mode 100644 (file)
index 0000000..8ad2e61
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * PHP 5.3 implementation of function currying, using native closures.
+ * On 5.2 and lower we use the fallback implementation in util.php
+ *
+ * @param callback $fn
+ * @param ... any remaining arguments will be appended to call-time params
+ * @return callback
+ */
+function callableLeftCurry($fn) {
+    $extra_args = func_get_args();
+    array_shift($extra_args);
+    return function() use ($fn, $extra_args) {
+        $args = func_get_args();
+        return call_user_func_array($fn,
+            array_merge($args, $extra_args));
+    };
+}
index c31c45f62612f8d218f6ef8cfe33a72ad3b94c17..4a74fb5e7fc1a302da515a3f2b06e4777adc87b4 100644 (file)
@@ -1,25 +1,28 @@
 <?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008-2010, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
 
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+defined('GNUSOCIAL') || die();
 
-// All the fun stuff to actually initialize StatusNet's framework code,
+/* Work internally in UTC */
+date_default_timezone_set('UTC');
+
+/* Work internally with UTF-8 */
+mb_internal_encoding('UTF-8');
+
+// All the fun stuff to actually initialize GNU social's framework code,
 // without loading up a site configuration.
 require_once INSTALLDIR . '/lib/framework.php';
 
index e6bb41091e1d6f9f104c0b5f50adfb94b1c0092c..5ece77edf3e2c9134d287772c152f17029216ebb 100644 (file)
@@ -1,35 +1,20 @@
 <?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * utilities for defining and running event handlers
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Event
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2008 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
 
-if (!defined('STATUSNET') && !defined('LACONICA')) {
-    exit(1);
-}
+defined('GNUSOCIAL') || die();
 
 /**
  * Class for events
@@ -37,14 +22,13 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
  * This "class" two static functions for managing events in the StatusNet code.
  *
  * @category Event
- * @package  StatusNet
+ * @package  GNU social
  * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
+ * @copyright 2010-2019 Free Software Foundation, Inc http://www.fsf.org
+ * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  *
  * @todo     Define a system for using Event instances
  */
-
 class Event {
 
     /* Global array of hooks, mapping eventname => array of callables */
index 789cece2bea924d2c04e35a60e3e926df000e762..43c7c60ad2da12bb726fc5e11d961b62bb3d0549 100644 (file)
@@ -1,24 +1,20 @@
 <?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009-2010 StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-if (!defined('GNUSOCIAL')) { exit(1); }
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+defined('GNUSOCIAL') || die();
 
 global $config, $_server, $_path;
 
@@ -343,11 +339,6 @@ class GNUsocial
         $config['db'] = &$_PEAR->getStaticProperty('DB_DataObject','options');
 
         $config['db'] = $default['db'];
-
-        if (function_exists('date_default_timezone_set')) {
-            /* Work internally in UTC */
-            date_default_timezone_set('UTC');
-        }
     }
 
     public static function loadSiteProfile($name)
index f0144b4106db42479395c118d19fb27d6da969de..c70adb8ea52525fd7bd8540755e0e4a8379eefa6 100644 (file)
@@ -1,34 +1,33 @@
 <?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
 /**
- * GNU social - a federating social network
- *
- * utility functions for i18n
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * Utility functions for i18n
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category I18n
- * @package  GNU social
- * @author   Matthew Gregg <matthew.gregg@gmail.com>
- * @author   Ciaran Gultnieks <ciaran@ciarang.com>
- * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
+ * @category  I18n
+ * @package   GNU social
+ * @author    Matthew Gregg <matthew.gregg@gmail.com>
+ * @author    Ciaran Gultnieks <ciaran@ciarang.com>
+ * @author    Evan Prodromou <evan@status.net>
+ * @author    Diogo Cordeiro <diogo@fc.up.pt>
+ * @copyright 2010-2019 Free Software Foundation, Inc http://www.fsf.org
+ * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  */
 
-if (!defined('STATUSNET') && !defined('LACONICA')) {
-    exit(1);
-}
+defined('GNUSOCIAL') || die();
 
 // Locale category constants are usually predefined, but may not be
 // on some systems such as Win32.
index 2625bf35205d7be045d3af4982ee114fcd0d6d65..cd0c9c6badbc8b49fac9832516a8a12e7351bded 100644 (file)
@@ -1,35 +1,20 @@
 <?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Utility class for plugins
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @category  Plugin
- * @package   StatusNet
- * @author    Evan Prodromou <evan@status.net>
- * @copyright 2008 StatusNet, Inc.
- * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link      http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
-    exit(1);
-}
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+defined('GNUSOCIAL') || die();
 
 /**
  * Base class for plugins
@@ -45,14 +30,13 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
  * initialize() and cleanup() methods, respectively.
  *
  * @category Plugin
- * @package  StatusNet
+ * @package  GNU social
  * @author   Evan Prodromou <evan@status.net>
- * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link     http://status.net/
+ * @copyright 2010-2019 Free Software Foundation, Inc http://www.fsf.org
+ * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  *
  * @see      Event
  */
-
 class Plugin
 {
     function __construct()
index 0866b32d55b10469d16eda102c44eefbd6c0cae2..966c415024a8f05ac0e51cf29b45ff96e593176b 100644 (file)
@@ -1040,7 +1040,7 @@ function common_replace_urls_callback($text, $callback, $arg = null)
     '#ixu';
     //preg_match_all($regex,$text,$matches);
     //print_r($matches);
-    return preg_replace_callback($regex, callable_left_curry('callback_helper', $callback, $arg), $text);
+    return preg_replace_callback($regex, callableLeftCurry('callback_helper', $callback, $arg), $text);
 }
 
 /**
@@ -1102,7 +1102,7 @@ function callback_helper($matches, $callback, $arg = null)
     return substr($matches[0], 0, $left) . $result . substr($matches[0], $right);
 }
 
-require_once INSTALLDIR . "/lib/callable_left_curry.php";
+require_once INSTALLDIR . "/lib/callableleftcurry.php";
 
 function common_linkify($url)
 {
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644 (file)
index 0000000..b57ab9c
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit backupGlobals="false"
+         backupStaticAttributes="false"
+         bootstrap="vendor/autoload.php"
+         colors="true"
+         convertErrorsToExceptions="true"
+         convertNoticesToExceptions="true"
+         convertWarningsToExceptions="true"
+         processIsolation="false"
+         stopOnFailure="false">
+    <testsuites>
+        <testsuite name="Core">
+            <directory suffix="Test.php">./tests/Core</directory>
+        </testsuite>
+        <testsuite name="Media">
+            <directory suffix="Test.php">./tests/Media</directory>
+        </testsuite>
+    </testsuites>
+    <php>
+        <env name="APP_ENV" value="testing"/>
+        <env name="CACHE_DRIVER" value="array"/>
+        <env name="SESSION_DRIVER" value="array"/>
+        <env name="QUEUE_DRIVER" value="sync"/>
+        <env name="MAIL_DRIVER" value="array"/>
+    </php>
+</phpunit>
diff --git a/tests/ActivityGenerationTests.php b/tests/ActivityGenerationTests.php
deleted file mode 100644 (file)
index 21fe32a..0000000
+++ /dev/null
@@ -1,567 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-// XXX: we should probably have some common source for this stuff
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-class ActivityGenerationTests extends PHPUnit_Framework_TestCase
-{
-    static $author1 = null;
-    static $author2 = null;
-
-    static $targetUser1 = null;
-    static $targetUser2 = null;
-
-    static $targetGroup1 = null;
-    static $targetGroup2 = null;
-
-    public static function setUpBeforeClass()
-    {
-        $authorNick1 = 'activitygenerationtestsuser' . common_random_hexstr(4);
-        $authorNick2 = 'activitygenerationtestsuser' . common_random_hexstr(4);
-
-        $targetNick1 = 'activitygenerationteststarget' . common_random_hexstr(4);
-        $targetNick2 = 'activitygenerationteststarget' . common_random_hexstr(4);
-
-        $groupNick1 = 'activitygenerationtestsgroup' . common_random_hexstr(4);
-        $groupNick2 = 'activitygenerationtestsgroup' . common_random_hexstr(4);
-
-        try{
-               self::$author1 = User::register(array('nickname' => $authorNick1,
-                                              'email' => $authorNick1 . '@example.net',
-                                              'email_confirmed' => true));
-
-               self::$author2 = User::register(array('nickname' => $authorNick2,
-                                              'email' => $authorNick2 . '@example.net',
-                                              'email_confirmed' => true));
-
-               self::$targetUser1 = User::register(array('nickname' => $targetNick1,
-                                                  'email' => $targetNick1 . '@example.net',
-                                                  'email_confirmed' => true));
-
-               self::$targetUser2 = User::register(array('nickname' => $targetNick2,
-                                                  'email' => $targetNick2 . '@example.net',
-                                                  'email_confirmed' => true));
-
-               self::$targetGroup1 = User_group::register(array('nickname' => $groupNick1,
-                                                         'userid' => self::$author1->id,
-                                                         'aliases' => array(),
-                                                         'local' => true,
-                                                         'location' => null,
-                                                         'description' => null,
-                                                         'fullname' => null,
-                                                         'homepage' => null,
-                                                         'mainpage' => null));
-               self::$targetGroup2 = User_group::register(array('nickname' => $groupNick2,
-                                                         'userid' => self::$author1->id,
-                                                         'aliases' => array(),
-                                                         'local' => true,
-                                                         'location' => null,
-                                                         'description' => null,
-                                                         'fullname' => null,
-                                                         'homepage' => null,
-                                                         'mainpage' => null));
-        } catch (Exception $e) {
-               self::tearDownAfterClass();
-               throw $e;
-        }
-    }
-
-    public function testBasicNoticeActivity()
-    {
-        $notice = $this->_fakeNotice();
-
-        $entry = $notice->asAtomEntry(true);
-
-        $element = $this->_entryToElement($entry, false);
-
-        $this->assertEquals($notice->getUri(), ActivityUtils::childContent($element, 'id'));
-        $this->assertEquals('New note by '. self::$author1->nickname, ActivityUtils::childContent($element, 'title'));
-        $this->assertEquals($notice->rendered, ActivityUtils::childContent($element, 'content'));
-        $this->assertEquals(strtotime($notice->created), strtotime(ActivityUtils::childContent($element, 'published')));
-        $this->assertEquals(strtotime($notice->created), strtotime(ActivityUtils::childContent($element, 'updated')));
-        $this->assertEquals(ActivityVerb::POST, ActivityUtils::childContent($element, 'verb', Activity::SPEC));
-        $this->assertEquals(ActivityObject::NOTE, ActivityUtils::childContent($element, 'object-type', Activity::SPEC));
-    }
-
-    public function testNamespaceFlag()
-    {
-        $notice = $this->_fakeNotice();
-
-        $entry = $notice->asAtomEntry(true);
-
-        $element = $this->_entryToElement($entry, false);
-
-        $this->assertTrue($element->hasAttribute('xmlns'));
-        $this->assertTrue($element->hasAttribute('xmlns:thr'));
-        $this->assertTrue($element->hasAttribute('xmlns:georss'));
-        $this->assertTrue($element->hasAttribute('xmlns:activity'));
-        $this->assertTrue($element->hasAttribute('xmlns:media'));
-        $this->assertTrue($element->hasAttribute('xmlns:poco'));
-        $this->assertTrue($element->hasAttribute('xmlns:ostatus'));
-        $this->assertTrue($element->hasAttribute('xmlns:statusnet'));
-
-        $entry = $notice->asAtomEntry(false);
-
-        $element = $this->_entryToElement($entry, true);
-
-        $this->assertFalse($element->hasAttribute('xmlns'));
-        $this->assertFalse($element->hasAttribute('xmlns:thr'));
-        $this->assertFalse($element->hasAttribute('xmlns:georss'));
-        $this->assertFalse($element->hasAttribute('xmlns:activity'));
-        $this->assertFalse($element->hasAttribute('xmlns:media'));
-        $this->assertFalse($element->hasAttribute('xmlns:poco'));
-        $this->assertFalse($element->hasAttribute('xmlns:ostatus'));
-        $this->assertFalse($element->hasAttribute('xmlns:statusnet'));
-    }
-
-    public function testSourceFlag()
-    {
-        $notice = $this->_fakeNotice();
-
-        // Test with no source
-
-        $entry = $notice->asAtomEntry(false, false);
-
-        $element = $this->_entryToElement($entry, true);
-
-        $source = ActivityUtils::child($element, 'source');
-
-        $this->assertNull($source);
-
-        // Test with source
-
-        $entry = $notice->asAtomEntry(false, true);
-
-        $element = $this->_entryToElement($entry, true);
-
-        $source = ActivityUtils::child($element, 'source');
-
-        $this->assertNotNull($source);
-    }
-
-    public function testSourceContent()
-    {
-        $notice = $this->_fakeNotice();
-        // make a time difference!
-        sleep(2);
-        $notice2 = $this->_fakeNotice();
-
-        $entry = $notice->asAtomEntry(false, true);
-
-        $element = $this->_entryToElement($entry, true);
-
-        $source = ActivityUtils::child($element, 'source');
-
-        $atomUrl = common_local_url('ApiTimelineUser', array('id' => self::$author1->id, 'format' => 'atom'));
-
-        $profile = self::$author1->getProfile();
-
-        $this->assertEquals($atomUrl, ActivityUtils::childContent($source, 'id'));
-        $this->assertEquals($atomUrl, ActivityUtils::getLink($source, 'self', 'application/atom+xml'));
-        $this->assertEquals($profile->profileurl, ActivityUtils::getPermalink($source));
-        $this->assertEquals(strtotime($notice2->created), strtotime(ActivityUtils::childContent($source, 'updated')));
-        // XXX: do we care here?
-        $this->assertFalse(is_null(ActivityUtils::childContent($source, 'title')));
-        $this->assertEquals(common_config('license', 'url'), ActivityUtils::getLink($source, 'license'));
-    }
-
-    public function testAuthorFlag()
-    {
-        $notice = $this->_fakeNotice();
-
-        // Test with no author
-
-        $entry = $notice->asAtomEntry(false, false, false);
-
-        $element = $this->_entryToElement($entry, true);
-
-        $this->assertNull(ActivityUtils::child($element, 'author'));
-        $this->assertNull(ActivityUtils::child($element, 'actor', Activity::SPEC));
-
-        // Test with source
-
-        $entry = $notice->asAtomEntry(false, false, true);
-
-        $element = $this->_entryToElement($entry, true);
-
-        $author = ActivityUtils::child($element, 'author');
-        $actor  = ActivityUtils::child($element, 'actor', Activity::SPEC);
-
-        $this->assertFalse(is_null($author));
-        $this->assertTrue(is_null($actor)); // <activity:actor> is obsolete, no longer added
-    }
-
-    public function testAuthorContent()
-    {
-        $notice = $this->_fakeNotice();
-
-        // Test with author
-
-        $entry = $notice->asAtomEntry(false, false, true);
-
-        $element = $this->_entryToElement($entry, true);
-
-        $author = ActivityUtils::child($element, 'author');
-
-        $this->assertEquals(self::$author1->getNickname(), ActivityUtils::childContent($author, 'name'));
-        $this->assertEquals(self::$author1->getUri(), ActivityUtils::childContent($author, 'uri'));
-    }
-
-    /**
-     * We no longer create <activity:actor> entries, they have merged to <atom:author>
-     */
-    public function testActorContent()
-    {
-        $notice = $this->_fakeNotice();
-
-        // Test with author
-
-        $entry = $notice->asAtomEntry(false, false, true);
-
-        $element = $this->_entryToElement($entry, true);
-
-        $actor = ActivityUtils::child($element, 'actor', Activity::SPEC);
-
-        $this->assertEquals($actor, null);
-    }
-
-    public function testReplyLink()
-    {
-        $orig = $this->_fakeNotice(self::$targetUser1);
-
-        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);
-
-        $reply = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));
-
-        $entry = $reply->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $irt = ActivityUtils::child($element, 'in-reply-to', 'http://purl.org/syndication/thread/1.0');
-
-        $this->assertNotNull($irt);
-        $this->assertEquals($orig->getUri(), $irt->getAttribute('ref'));
-        $this->assertEquals($orig->getUrl(), $irt->getAttribute('href'));
-    }
-
-    public function testReplyAttention()
-    {
-        $orig = $this->_fakeNotice(self::$targetUser1);
-
-        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);
-
-        $reply = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));
-
-        $entry = $reply->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $this->assertEquals(self::$targetUser1->getUri(), ActivityUtils::getLink($element, 'mentioned'));
-    }
-
-    public function testMultipleReplyAttention()
-    {
-        $orig = $this->_fakeNotice(self::$targetUser1);
-
-        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);
-
-        $reply = Notice::saveNew(self::$targetUser2->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));
-
-        $text = "@" . self::$targetUser1->nickname . " @" . self::$targetUser2->nickname . " reply text " . common_random_hexstr(4);
-
-        $reply2 = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $reply->id));
-
-        $entry = $reply2->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $links = ActivityUtils::getLinks($element, 'mentioned');
-
-        $hrefs = array();
-
-        foreach ($links as $link) {
-            $hrefs[] = $link->getAttribute('href');
-        }
-
-        $this->assertTrue(in_array(self::$targetUser1->getUri(), $hrefs));
-        $this->assertTrue(in_array(self::$targetUser2->getUri(), $hrefs));
-    }
-
-    public function testGroupPostAttention()
-    {
-        $text = "!" . self::$targetGroup1->nickname . " reply text " . common_random_hexstr(4);
-
-        $notice = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null));
-
-        $entry = $notice->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $this->assertEquals(self::$targetGroup1->getUri(), ActivityUtils::getLink($element, 'mentioned'));
-    }
-
-    public function testMultipleGroupPostAttention()
-    {
-        $text = "!" . self::$targetGroup1->nickname . " !" . self::$targetGroup2->nickname . " reply text " . common_random_hexstr(4);
-
-        $notice = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null));
-
-        $entry = $notice->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $links = ActivityUtils::getLinks($element, 'mentioned');
-
-        $hrefs = array();
-
-        foreach ($links as $link) {
-            $hrefs[] = $link->getAttribute('href');
-        }
-
-        $this->assertTrue(in_array(self::$targetGroup1->getUri(), $hrefs));
-        $this->assertTrue(in_array(self::$targetGroup2->getUri(), $hrefs));
-
-    }
-
-    public function testRepeatLink()
-    {
-        $notice = $this->_fakeNotice(self::$author1);
-        $repeat = $notice->repeat(self::$author2->getProfile(), 'test');
-
-        $entry = $repeat->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $noticeInfo = ActivityUtils::child($element, 'notice_info', 'http://status.net/schema/api/1/');
-
-        $this->assertNotNull($noticeInfo);
-        $this->assertEquals($notice->id, $noticeInfo->getAttribute('repeat_of'));
-        $this->assertEquals($repeat->id, $noticeInfo->getAttribute('local_id'));
-    }
-
-    public function testTag()
-    {
-        $tag1 = common_random_hexstr(4);
-
-        $notice = $this->_fakeNotice(self::$author1, '#' . $tag1);
-
-        $entry = $notice->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $category = ActivityUtils::child($element, 'category');
-
-        $this->assertNotNull($category);
-        $this->assertEquals($tag1, $category->getAttribute('term'));
-    }
-
-    public function testMultiTag()
-    {
-        $tag1 = common_random_hexstr(4);
-        $tag2 = common_random_hexstr(4);
-
-        $notice = $this->_fakeNotice(self::$author1, '#' . $tag1 . ' #' . $tag2);
-
-        $entry = $notice->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $categories = $element->getElementsByTagName('category');
-
-        $this->assertNotNull($categories);
-        $this->assertEquals(2, $categories->length);
-
-        $terms = array();
-
-        for ($i = 0; $i < $categories->length; $i++) {
-            $cat = $categories->item($i);
-            $terms[] = $cat->getAttribute('term');
-        }
-
-        $this->assertTrue(in_array($tag1, $terms));
-        $this->assertTrue(in_array($tag2, $terms));
-    }
-
-    public function testGeotaggedActivity()
-    {
-        $notice = Notice::saveNew(self::$author1->id, common_random_hexstr(4), 'test', array('uri' => null, 'lat' => 45.5, 'lon' => -73.6));
-
-        $entry = $notice->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $this->assertEquals('45.5000000 -73.6000000', ActivityUtils::childContent($element, 'point', "http://www.georss.org/georss"));
-    }
-
-    public function testNoticeInfo()
-    {
-        $notice = $this->_fakeNotice();
-
-        $entry = $notice->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
-
-        $this->assertEquals($notice->id, $noticeInfo->getAttribute('local_id'));
-        $this->assertEquals($notice->source, $noticeInfo->getAttribute('source'));
-        $this->assertEquals('', $noticeInfo->getAttribute('repeat_of'));
-        $this->assertEquals('', $noticeInfo->getAttribute('repeated'));
-//        $this->assertEquals('', $noticeInfo->getAttribute('favorite'));
-        $this->assertEquals('', $noticeInfo->getAttribute('source_link'));
-    }
-
-    public function testNoticeInfoRepeatOf()
-    {
-        $notice = $this->_fakeNotice();
-
-        $repeat = $notice->repeat(self::$author2->getProfile(), 'test');
-
-        $entry = $repeat->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
-
-        $this->assertEquals($notice->id, $noticeInfo->getAttribute('repeat_of'));
-    }
-
-    public function testNoticeInfoRepeated()
-    {
-        $notice = $this->_fakeNotice();
-
-        $repeat = $notice->repeat(self::$author2->getProfile(), 'test');
-
-        $entry = $notice->asAtomEntry(false, false, false, self::$author2->getProfile());
-
-        $element = $this->_entryToElement($entry, true);
-
-        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
-
-        $this->assertEquals('true', $noticeInfo->getAttribute('repeated'));
-
-        $entry = $notice->asAtomEntry(false, false, false, self::$targetUser1->getProfile());
-
-        $element = $this->_entryToElement($entry, true);
-
-        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
-
-        $this->assertEquals('false', $noticeInfo->getAttribute('repeated'));
-    }
-
-/*    public function testNoticeInfoFave()
-    {
-        $notice = $this->_fakeNotice();
-
-        $fave = Fave::addNew(self::$author2->getProfile(), $notice);
-
-        // Should be set if user has faved
-
-        $entry = $notice->asAtomEntry(false, false, false, self::$author2);
-
-        $element = $this->_entryToElement($entry, true);
-
-        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
-
-        $this->assertEquals('true', $noticeInfo->getAttribute('favorite'));
-
-        // Shouldn't be set if user has not faved
-
-        $entry = $notice->asAtomEntry(false, false, false, self::$targetUser1);
-
-        $element = $this->_entryToElement($entry, true);
-
-        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
-
-        $this->assertEquals('false', $noticeInfo->getAttribute('favorite'));
-    }*/
-
-    public function testConversationLink()
-    {
-        $orig = $this->_fakeNotice(self::$targetUser1);
-
-        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);
-
-        $reply = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));
-
-        $conv = Conversation::getKV('id', $reply->conversation);
-
-        $entry = $reply->asAtomEntry();
-
-        $element = $this->_entryToElement($entry, true);
-
-        $this->assertEquals($conv->getUrl(), ActivityUtils::getLink($element, 'ostatus:conversation'));
-    }
-
-    public static function tearDownAfterClass()
-    {
-        if (!is_null(self::$author1)) {
-            self::$author1->getProfile()->delete();
-        }
-
-        if (!is_null(self::$author2)) {
-            self::$author2->getProfile()->delete();
-        }
-
-        if (!is_null(self::$targetUser1)) {
-            self::$targetUser1->getProfile()->delete();
-        }
-
-        if (!is_null(self::$targetUser2)) {
-            self::$targetUser2->getProfile()->delete();
-        }
-
-        if (!is_null(self::$targetGroup1)) {
-            self::$targetGroup1->delete();
-        }
-
-        if (!is_null(self::$targetGroup2)) {
-            self::$targetGroup2->delete();
-        }
-    }
-
-    private function _fakeNotice($user = null, $text = null)
-    {
-        if (empty($user)) {
-            $user = self::$author1;
-        }
-
-        if (empty($text)) {
-            $text = "fake-o text-o " . common_random_hexstr(32);
-        }
-
-        return Notice::saveNew($user->id, $text, 'test', array('uri' => null));
-    }
-
-    private function _entryToElement($entry, $namespace = false)
-    {
-        $xml = '<?xml version="1.0" encoding="utf-8"?>'."\n\n";
-        $xml .= '<feed';
-        if ($namespace) {
-            $xml .= ' xmlns="http://www.w3.org/2005/Atom"';
-            $xml .= ' xmlns:thr="http://purl.org/syndication/thread/1.0"';
-            $xml .= ' xmlns:georss="http://www.georss.org/georss"';
-            $xml .= ' xmlns:activity="http://activitystrea.ms/spec/1.0/"';
-            $xml .= ' xmlns:media="http://purl.org/syndication/atommedia"';
-            $xml .= ' xmlns:poco="http://portablecontacts.net/spec/1.0"';
-            $xml .= ' xmlns:ostatus="http://ostatus.org/schema/1.0"';
-            $xml .= ' xmlns:statusnet="http://status.net/schema/api/1/"';
-        }
-        $xml .= '>' . "\n" . $entry . "\n" . '</feed>' . "\n";
-        $doc = DOMDocument::loadXML($xml);
-        $feed = $doc->documentElement;
-        $entries = $feed->getElementsByTagName('entry');
-
-        return $entries->item(0);
-    }
-}
diff --git a/tests/ActivityParseTests.php b/tests/ActivityParseTests.php
deleted file mode 100644 (file)
index 566318e..0000000
+++ /dev/null
@@ -1,1044 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-// XXX: we should probably have some common source for this stuff
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-class ActivityParseTests extends PHPUnit_Framework_TestCase
-{
-
-    public function testMastodonRetweet() {
-        global $_mastodon_retweet;
-        $dom = DOMDocument::loadXML($_mastodon_retweet);
-        $feed = $dom->documentElement;
-        $entries = $feed->getElementsByTagName('entry');
-        $entry = $entries->item(0);
-        $act = new Activity($entry, $feed);
-        $this->assertFalse(empty($act));
-        $this->assertFalse(empty($act->objects[0]));
-
-        $object = $act->objects[0];
-        $this->assertEquals($object->verb, ActivityVerb::POST);
-    }
-
-    public function testGSReweet() {
-        global $_gs_retweet;
-        $dom = DOMDocument::loadXML($_gs_retweet);
-        $feed = $dom->documentElement;
-        $entries = $feed->getElementsByTagName('entry');
-        $entry = $entries->item(0);
-        $act = new Activity($entry, $feed);
-        $this->assertFalse(empty($act));
-        $this->assertFalse(empty($act->objects[0]));
-
-        $object = $act->objects[0];
-        $this->assertEquals($object->verb, ActivityVerb::POST);
-    }
-
-    public function testExample1()
-    {
-        global $_example1;
-        $dom = DOMDocument::loadXML($_example1);
-        $act = new Activity($dom->documentElement);
-
-        $this->assertFalse(empty($act));
-
-        $this->assertEquals(1243860840, $act->time);
-        $this->assertEquals(ActivityVerb::POST, $act->verb);
-
-        $this->assertFalse(empty($act->objects[0]));
-        $this->assertEquals('Punctuation Changeset', $act->objects[0]->title);
-        $this->assertEquals('http://versioncentral.example.org/activity/changeset', $act->objects[0]->type);
-        $this->assertEquals('Fixing punctuation because it makes it more readable.', $act->objects[0]->summary);
-        $this->assertEquals('tag:versioncentral.example.org,2009:/change/1643245', $act->objects[0]->id);
-    }
-
-    public function testExample2()
-    {
-        global $_example2;
-        $dom = DOMDocument::loadXML($_example2);
-        $act = new Activity($dom->documentElement);
-
-        $this->assertFalse(empty($act));
-        // Did we handle <content type="html"> correctly with a typical payload?
-        $this->assertEquals("<p>Geraldine posted a Photo on PhotoPanic</p>\n     " .
-                            "<img src=\"/geraldine/photo1.jpg\">", trim($act->content));
-    }
-
-    public function testExample3()
-    {
-        global $_example3;
-        $dom = DOMDocument::loadXML($_example3);
-
-        $feed = $dom->documentElement;
-
-        $entries = $feed->getElementsByTagName('entry');
-
-        $entry = $entries->item(0);
-
-        $act = new Activity($entry, $feed);
-
-        $this->assertFalse(empty($act));
-        $this->assertEquals(1071340202, $act->time);
-        $this->assertEquals('http://example.org/2003/12/13/atom03.html', $act->link);
-
-        $this->assertEquals($act->verb, ActivityVerb::POST);
-
-        $this->assertFalse(empty($act->actor));
-        $this->assertEquals(ActivityObject::PERSON, $act->actor->type);
-        $this->assertEquals('John Doe', $act->actor->title);
-        $this->assertEquals('mailto:johndoe@example.com', $act->actor->id);
-
-        $this->assertFalse(empty($act->objects[0]));
-        $this->assertEquals(ActivityObject::NOTE, $act->objects[0]->type);
-        $this->assertEquals('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', $act->objects[0]->id);
-        $this->assertEquals('Atom-Powered Robots Run Amok', $act->objects[0]->title);
-        $this->assertEquals('Some text.', $act->objects[0]->summary);
-        $this->assertEquals('http://example.org/2003/12/13/atom03.html', $act->objects[0]->link);
-
-        $this->assertFalse(empty($act->context));
-
-        $this->assertTrue(empty($act->target));
-
-        $this->assertEquals($act->entry, $entry);
-        $this->assertEquals($act->feed, $feed);
-    }
-
-    public function testExample4()
-    {
-        global $_example4;
-        $dom = DOMDocument::loadXML($_example4);
-
-        $entry = $dom->documentElement;
-
-        $act = new Activity($entry);
-
-        $this->assertFalse(empty($act));
-        $this->assertEquals(1266547958, $act->time);
-        $this->assertEquals('http://example.net/notice/14', $act->link);
-
-        $this->assertFalse(empty($act->context));
-        $this->assertEquals('http://example.net/notice/12', $act->context->replyToID);
-        $this->assertEquals('http://example.net/notice/12', $act->context->replyToUrl);
-        $this->assertEquals('http://example.net/conversation/11', $act->context->conversation);
-        $this->assertEquals(array('http://example.net/user/1'), array_keys($act->context->attention));
-
-        $this->assertFalse(empty($act->objects[0]));
-        $this->assertEquals($act->objects[0]->content,
-                            '@<span class="vcard"><a href="http://example.net/user/1" class="url"><span class="fn nickname">evan</span></a></span> now is the time for all good men to come to the aid of their country. #<span class="tag"><a href="http://example.net/tag/thetime" rel="tag">thetime</a></span>');
-
-        $this->assertFalse(empty($act->actor));
-    }
-
-    public function testExample5()
-    {
-        global $_example5;
-        $dom = DOMDocument::loadXML($_example5);
-
-        $feed = $dom->documentElement;
-
-        // @todo Test feed elements
-
-        $entries = $feed->getElementsByTagName('entry');
-        $entry = $entries->item(0);
-
-        $act = new Activity($entry, $feed);
-
-        // Post
-        $this->assertEquals($act->verb, ActivityVerb::POST);
-        $this->assertFalse(empty($act->context));
-
-        // Actor w/Portable Contacts stuff
-        $this->assertFalse(empty($act->actor));
-        $this->assertEquals($act->actor->type, ActivityObject::PERSON);
-        $this->assertEquals($act->actor->title, 'Test User');
-        $this->assertEquals($act->actor->id, 'http://example.net/mysite/user/3');
-        $this->assertEquals($act->actor->link, 'http://example.net/mysite/testuser');
-
-        $avatars = $act->actor->avatarLinks;
-
-        $this->assertEquals(
-                $avatars[0]->url,
-                'http://example.net/mysite/avatar/3-96-20100224004207.jpeg'
-        );
-
-        $this->assertEquals($act->actor->displayName, 'Test User');
-
-        $poco = $act->actor->poco;
-        $this->assertEquals($poco->preferredUsername, 'testuser');
-        $this->assertEquals($poco->address->formatted, 'San Francisco, CA');
-        $this->assertEquals($poco->urls[0]->type, 'homepage');
-        $this->assertEquals($poco->urls[0]->value, 'http://example.com/blog.html');
-        $this->assertEquals($poco->urls[0]->primary, 'true');
-        $this->assertEquals($act->actor->geopoint, '37.7749295 -122.4194155');
-    }
-
-    public function testExample6()
-    {
-        global $_example6;
-
-        $dom = DOMDocument::loadXML($_example6);
-
-        $rss = $dom->documentElement;
-
-        $channels = $dom->getElementsByTagName('channel');
-
-        $channel = $channels->item(0);
-
-        $items = $channel->getElementsByTagName('item');
-
-        $item = $items->item(0);
-
-        $act = new Activity($item, $channel);
-
-        $this->assertEquals($act->verb, ActivityVerb::POST);
-
-        $this->assertEquals($act->id, 'http://en.blog.wordpress.com/?p=3857');
-        $this->assertEquals($act->link, 'http://en.blog.wordpress.com/2010/03/03/rub-a-dub-dub-in-the-pubsubhubbub/');
-        $this->assertEquals($act->title, 'Rub-a-Dub-Dub in the PubSubHubbub');
-        $this->assertEquals($act->time, 1267634892);
-
-        $actor = $act->actor;
-
-        $this->assertFalse(empty($actor));
-        $this->assertEquals($actor->title, "Joseph Scott");
-    }
-
-    public function testExample7()
-    {
-        global $_example7;
-
-        $dom = DOMDocument::loadXML($_example7);
-
-        $rss = $dom->documentElement;
-
-        $channels = $dom->getElementsByTagName('channel');
-
-        $channel = $channels->item(0);
-
-        $items = $channel->getElementsByTagName('item');
-
-        $item = $items->item(0);
-
-        $act = new Activity($item, $channel);
-
-        $this->assertEquals(ActivityVerb::POST, $act->verb);
-        $this->assertEquals('http://evanpro.posterous.com/checking-out-captain-bones', $act->link);
-        $this->assertEquals('http://evanpro.posterous.com/checking-out-captain-bones', $act->id);
-        $this->assertEquals('Checking out captain bones', $act->title);
-        $this->assertEquals(1269095551, $act->time);
-
-        $actor = $act->actor;
-
-        $this->assertEquals(ActivityObject::PERSON, $actor->type);
-        $this->assertEquals('http://posterous.com/people/3sDslhaepotz', $actor->id);
-        $this->assertEquals('Evan Prodromou', $actor->title);
-        $this->assertNull($actor->summary);
-        $this->assertNull($actor->content);
-        $this->assertEquals('http://posterous.com/people/3sDslhaepotz', $actor->link);
-        $this->assertNull($actor->source);
-        $this->assertTrue(is_array($actor->avatarLinks));
-        $this->assertEquals(1, count($actor->avatarLinks));
-        $this->assertEquals('http://files.posterous.com/user_profile_pics/480326/2009-08-05-142447.jpg',
-                            $actor->avatarLinks[0]->url);
-        $this->assertNotNull($actor->poco);
-        $this->assertEquals('evanpro', $actor->poco->preferredUsername);
-        $this->assertEquals('Evan Prodromou', $actor->poco->displayName);
-        $this->assertNull($actor->poco->note);
-        $this->assertNull($actor->poco->address);
-        $this->assertEquals(0, count($actor->poco->urls));
-    }
-
-    // Media test - cliqset
-    public function testExample8()
-    {
-        global $_example8;
-        $dom = DOMDocument::loadXML($_example8);
-
-        $feed = $dom->documentElement;
-
-        $entries = $feed->getElementsByTagName('entry');
-
-        $entry = $entries->item(0);
-
-        $act = new Activity($entry, $feed);
-
-        $this->assertFalse(empty($act));
-        $this->assertEquals($act->time, 1269221753);
-        $this->assertEquals($act->verb, ActivityVerb::POST);
-        $this->assertEquals($act->summary, 'zcopley posted 5 photos on Flickr');
-
-        $this->assertFalse(empty($act->objects));
-        $this->assertEquals(sizeof($act->objects), 5);
-
-        $this->assertEquals($act->objects[0]->type, ActivityObject::PHOTO);
-        $this->assertEquals($act->objects[0]->title, 'IMG_1368');
-        $this->assertNull($act->objects[0]->description);
-        $this->assertEquals(
-            $act->objects[0]->thumbnail,
-            'http://media.cliqset.com/6f6fbee9d7dfbffc73b6ef626275eb5f_thumb.jpg'
-        );
-        $this->assertEquals(
-            $act->objects[0]->link,
-            'http://www.flickr.com/photos/zcopley/4452933806/'
-        );
-
-        $this->assertEquals($act->objects[1]->type, ActivityObject::PHOTO);
-        $this->assertEquals($act->objects[1]->title, 'IMG_1365');
-        $this->assertNull($act->objects[1]->description);
-        $this->assertEquals(
-            $act->objects[1]->thumbnail,
-            'http://media.cliqset.com/b8f3932cd0bba1b27f7c8b3ef986915e_thumb.jpg'
-        );
-        $this->assertEquals(
-            $act->objects[1]->link,
-            'http://www.flickr.com/photos/zcopley/4442630390/'
-        );
-
-        $this->assertEquals($act->objects[2]->type, ActivityObject::PHOTO);
-        $this->assertEquals($act->objects[2]->title, 'Classic');
-        $this->assertEquals(
-            $act->objects[2]->description,
-            '-Powered by pikchur.com/n0u'
-        );
-        $this->assertEquals(
-            $act->objects[2]->thumbnail,
-            'http://media.cliqset.com/fc54c15f850b7a9a8efa644087a48c91_thumb.jpg'
-        );
-        $this->assertEquals(
-            $act->objects[2]->link,
-            'http://www.flickr.com/photos/zcopley/4430754103/'
-        );
-
-        $this->assertEquals($act->objects[3]->type, ActivityObject::PHOTO);
-        $this->assertEquals($act->objects[3]->title, 'IMG_1363');
-        $this->assertNull($act->objects[3]->description);
-
-        $this->assertEquals(
-            $act->objects[3]->thumbnail,
-            'http://media.cliqset.com/4b1d307c9217e2114391a8b229d612cb_thumb.jpg'
-        );
-        $this->assertEquals(
-            $act->objects[3]->link,
-            'http://www.flickr.com/photos/zcopley/4416969717/'
-        );
-
-        $this->assertEquals($act->objects[4]->type, ActivityObject::PHOTO);
-        $this->assertEquals($act->objects[4]->title, 'IMG_1361');
-        $this->assertNull($act->objects[4]->description);
-
-        $this->assertEquals(
-            $act->objects[4]->thumbnail,
-            'http://media.cliqset.com/23d9b4b96b286e0347d36052f22f6e60_thumb.jpg'
-        );
-        $this->assertEquals(
-            $act->objects[4]->link,
-            'http://www.flickr.com/photos/zcopley/4417734232/'
-        );
-
-    }
-
-    public function testAtomContent()
-    {
-        $tests = array(array("<content>Some regular plain text.</content>",
-                             "Some regular plain text."),
-                       array("<content>&lt;b&gt;this is not HTML&lt;/b&gt;</content>",
-                             "&lt;b&gt;this is not HTML&lt;/b&gt;"),
-                       array("<content type='html'>Some regular plain HTML.</content>",
-                             "Some regular plain HTML."),
-                       array("<content type='html'>&lt;b&gt;this is too HTML&lt;/b&gt;</content>",
-                             "<b>this is too HTML</b>"),
-                       array("<content type='html'>&amp;lt;b&amp;gt;but this is not HTML!&amp;lt;/b&amp;gt;</content>",
-                             "&lt;b&gt;but this is not HTML!&lt;/b&gt;"),
-                       array("<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>Some regular plain XHTML.</div></content>",
-                             "Some regular plain XHTML."),
-                       array("<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'><b>This is some XHTML!</b></div></content>",
-                             "<b>This is some XHTML!</b>"),
-                       array("<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>&lt;b&gt;This is not some XHTML!&lt;/b&gt;</div></content>",
-                             "&lt;b&gt;This is not some XHTML!&lt;/b&gt;"),
-                       array("<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>&amp;lt;b&amp;gt;This is not some XHTML either!&amp;lt;/b&amp;gt;</div></content>",
-                             "&amp;lt;b&amp;gt;This is not some XHTML either!&amp;lt;/b&amp;gt;"));
-        foreach ($tests as $data) {
-            list($source, $output) = $data;
-            $xml = "<entry xmlns='http://www.w3.org/2005/Atom'>" .
-                   "<id>http://example.com/fakeid</id>" .
-                   "<author><name>Test</name></author>" .
-                   "<title>Atom content tests</title>" .
-                   $source .
-                   "</entry>";
-            $dom = DOMDocument::loadXML($xml);
-            $act = new Activity($dom->documentElement);
-
-            $this->assertFalse(empty($act));
-            $this->assertEquals($output, trim($act->content));
-        }
-    }
-
-    public function testRssContent()
-    {
-        $tests = array(array("<content:encoded>Some regular plain HTML.</content:encoded>",
-                             "Some regular plain HTML."),
-                       array("<content:encoded>Some &lt;b&gt;exciting bold HTML&lt;/b&gt;</content:encoded>",
-                             "Some <b>exciting bold HTML</b>"),
-                       array("<content:encoded>Some &amp;lt;b&amp;gt;escaped non-HTML.&amp;lt;/b&amp;gt;</content:encoded>",
-                             "Some &lt;b&gt;escaped non-HTML.&lt;/b&gt;"),
-                       array("<description>Some plain text.</description>",
-                             "Some plain text."),
-                       array("<description>Some &lt;b&gt;non-HTML text&lt;/b&gt;</description>",
-                             "Some &lt;b&gt;non-HTML text&lt;/b&gt;"),
-                       array("<description>Some &amp;lt;b&amp;gt;double-escaped text&amp;lt;/b&amp;gt;</description>",
-                             "Some &amp;lt;b&amp;gt;double-escaped text&amp;lt;/b&amp;gt;"));
-        foreach ($tests as $data) {
-            list($source, $output) = $data;
-            $xml = "<item xmlns:content='http://purl.org/rss/1.0/modules/content/'>" .
-                   "<guid>http://example.com/fakeid</guid>" .
-                   "<title>RSS content tests</title>" .
-                   $source .
-                   "</item>";
-            $dom = DOMDocument::loadXML($xml);
-            $act = new Activity($dom->documentElement);
-
-            $this->assertFalse(empty($act));
-            $this->assertEquals($output, trim($act->content));
-        }
-    }
-
-    public function testExample10()
-    {
-        global $_example10;
-        $dom = new DOMDocument();
-        $dom->loadXML($_example10);
-
-        // example 10 is a PuSH item of a post on a group feed, as generated
-        // by 0.9.7 code after migration away from <activity:actor> to <author>
-        $feed = $dom->documentElement;
-        $entry = $dom->getElementsByTagName('entry')->item(0);
-        $expected = 'http://lazarus.local/mublog/user/557';
-
-        // Reading just the entry alone should pick up its own <author>
-        // as the actor.
-        $act = new Activity($entry);
-        $this->assertEquals($act->actor->id, $expected);
-
-        // Reading the entry in feed context used to be buggy, picking up
-        // the feed's <activity:subject> which referred to the group.
-        // It should now be returning the expected author entry...
-        $act = new Activity($entry, $feed);
-        $this->assertEquals($act->actor->id, $expected);
-    }
-
-    public function testBookmarkRelated()
-    {
-        global $_example11;
-        $dom = new DOMDocument();
-        $dom->loadXML($_example11);
-
-        $feed = $dom->documentElement;
-        $entry = $dom->getElementsByTagName('entry')->item(0);
-
-        $expected = 'http://blog.teambox.com/open-source-companies';
-
-        $links = ActivityUtils::getLinks($entry, 'related');
-
-        $this->assertFalse(empty($links));
-        $this->assertTrue(is_array($links));
-        $this->assertEquals(count($links), 1);
-
-        $url = $links[0]->getAttribute('href');
-
-        $this->assertEquals($url, $expected);
-    }
-}
-
-$_example1 = <<<EXAMPLE1
-<?xml version='1.0' encoding='UTF-8'?>
-<entry xmlns='http://www.w3.org/2005/Atom' xmlns:activity='http://activitystrea.ms/spec/1.0/'>
-  <id>tag:versioncentral.example.org,2009:/commit/1643245</id>
-  <published>2009-06-01T12:54:00Z</published>
-  <title>Geraldine committed a change to yate</title>
-  <content type="xhtml">Geraldine just committed a change to yate on VersionCentral</content>
-  <link rel="alternate" type="text/html"
-        href="http://versioncentral.example.org/geraldine/yate/commit/1643245" />
-  <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-  <activity:verb>http://versioncentral.example.org/activity/commit</activity:verb>
-  <activity:object>
-    <activity:object-type>http://versioncentral.example.org/activity/changeset</activity:object-type>
-    <id>tag:versioncentral.example.org,2009:/change/1643245</id>
-    <title>Punctuation Changeset</title>
-    <summary>Fixing punctuation because it makes it more readable.</summary>
-    <link rel="alternate" type="text/html" href="..." />
-  </activity:object>
-</entry>
-EXAMPLE1;
-
-$_example2 = <<<EXAMPLE2
-<?xml version='1.0' encoding='UTF-8'?>
-<entry xmlns='http://www.w3.org/2005/Atom' xmlns:activity='http://activitystrea.ms/spec/1.0/'>
-  <id>tag:photopanic.example.com,2008:activity01</id>
-  <title>Geraldine posted a Photo on PhotoPanic</title>
-  <published>2008-11-02T15:29:00Z</published>
-  <link rel="alternate" type="text/html" href="/geraldine/activities/1" />
-  <activity:verb>
-  http://activitystrea.ms/schema/1.0/post
-  </activity:verb>
-  <activity:object>
-    <id>tag:photopanic.example.com,2008:photo01</id>
-    <title>My Cat</title>
-    <published>2008-11-02T15:29:00Z</published>
-    <link rel="alternate" type="text/html" href="/geraldine/photos/1" />
-    <activity:object-type>
-      tag:atomactivity.example.com,2008:photo
-    </activity:object-type>
-    <source>
-      <title>Geraldine's Photos</title>
-      <link rel="self" type="application/atom+xml" href="/geraldine/photofeed.xml" />
-      <link rel="alternate" type="text/html" href="/geraldine/" />
-    </source>
-  </activity:object>
-  <content type="html">
-     &lt;p&gt;Geraldine posted a Photo on PhotoPanic&lt;/p&gt;
-     &lt;img src="/geraldine/photo1.jpg"&gt;
-  </content>
-</entry>
-EXAMPLE2;
-
-$_example3 = <<<EXAMPLE3
-<?xml version="1.0" encoding="utf-8"?>
-
-<feed xmlns="http://www.w3.org/2005/Atom">
-
-    <title>Example Feed</title>
-    <subtitle>A subtitle.</subtitle>
-    <link href="http://example.org/feed/" rel="self" />
-    <link href="http://example.org/" />
-    <id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
-    <updated>2003-12-13T18:30:02Z</updated>
-    <author>
-        <name>John Doe</name>
-        <email>johndoe@example.com</email>
-    </author>
-
-    <entry>
-        <title>Atom-Powered Robots Run Amok</title>
-        <link href="http://example.org/2003/12/13/atom03" />
-        <link rel="alternate" type="text/html" href="http://example.org/2003/12/13/atom03.html"/>
-        <link rel="edit" href="http://example.org/2003/12/13/atom03/edit"/>
-        <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
-        <updated>2003-12-13T18:30:02Z</updated>
-        <summary>Some text.</summary>
-    </entry>
-
-</feed>
-EXAMPLE3;
-
-$_example4 = <<<EXAMPLE4
-<?xml version='1.0' encoding='UTF-8'?>
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:ostatus="http://ostatus.org/schema/1.0">
- <title>@evan now is the time for all good men to come to the aid of their country. #thetime</title>
- <summary>@evan now is the time for all good men to come to the aid of their country. #thetime</summary>
-<author>
- <name>spock</name>
- <uri>http://example.net/user/2</uri>
-</author>
-<activity:actor>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>http://example.net/user/2</id>
- <title>spock</title>
- <link type="image/png" rel="avatar" href="http://example.net/theme/identica/default-avatar-profile.png"></link>
-</activity:actor>
- <link rel="alternate" type="text/html" href="http://example.net/notice/14"/>
- <id>http://example.net/notice/14</id>
- <published>2010-02-19T02:52:38+00:00</published>
- <updated>2010-02-19T02:52:38+00:00</updated>
- <link rel="related" href="http://example.net/notice/12"/>
- <thr:in-reply-to ref="http://example.net/notice/12" href="http://example.net/notice/12"></thr:in-reply-to>
- <link rel="ostatus:conversation" href="http://example.net/conversation/11"/>
- <link rel="mentioned" href="http://example.net/user/1"/>
- <content type="html">@&lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;http://example.net/user/1&quot; class=&quot;url&quot;&gt;&lt;span class=&quot;fn nickname&quot;&gt;evan&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; now is the time for all good men to come to the aid of their country. #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;http://example.net/tag/thetime&quot; rel=&quot;tag&quot;&gt;thetime&lt;/a&gt;&lt;/span&gt;</content>
- <category term="thetime"></category>
-</entry>
-EXAMPLE4;
-
-$_example5 = <<<EXAMPLE5
-<?xml version="1.0" encoding="UTF-8"?>
-<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0">
- <id>3</id>
- <title>testuser timeline</title>
- <subtitle>Updates from testuser on Zach Dev!</subtitle>
- <logo>http://example.net/mysite/avatar/3-96-20100224004207.jpeg</logo>
- <updated>2010-02-24T06:38:49+00:00</updated>
-<author>
- <name>testuser</name>
- <uri>http://example.net/mysite/user/3</uri>
-
-</author>
- <link href="http://example.net/mysite/testuser" rel="alternate" type="text/html"/>
- <link href="http://example.net/mysite/api/statuses/user_timeline/3.atom" rel="self" type="application/atom+xml"/>
- <link href="http://example.net/mysite/main/sup#3" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
- <link href="http://example.net/mysite/main/push/hub" rel="hub"/>
- <link href="http://example.net/mysite/main/salmon/user/3" rel="salmon"/>
-<activity:subject>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>http://example.net/mysite/user/3</id>
- <title>Test User</title>
- <link rel="alternate" type="text/html" href="http://example.net/mysite/testuser"/>
- <link type="image/jpeg" rel="avatar" href="http://example.net/mysite/avatar/3-96-20100224004207.jpeg"/>
- <georss:point>37.7749295 -122.4194155</georss:point>
-
-<poco:preferredUsername>testuser</poco:preferredUsername>
-<poco:displayName>Test User</poco:displayName>
-<poco:note>Just another test user.</poco:note>
-<poco:address>
- <poco:formatted>San Francisco, CA</poco:formatted>
-</poco:address>
-<poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>http://example.com/blog.html</poco:value>
- <poco:primary>true</poco:primary>
-
-</poco:urls>
-</activity:subject>
-<entry>
- <title>Hey man, is that Freedom Code?! #freedom #hippy</title>
- <summary>Hey man, is that Freedom Code?! #freedom #hippy</summary>
-<author>
- <name>testuser</name>
- <uri>http://example.net/mysite/user/3</uri>
-</author>
-<activity:actor>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>http://example.net/mysite/user/3</id>
- <title>Test User</title>
- <link rel="alternate" type="text/html" href="http://example.net/mysite/testuser"/>
- <link type="image/jpeg" rel="avatar" href="http://example.net/mysite/avatar/3-96-20100224004207.jpeg"/>
- <georss:point>37.7749295 -122.4194155</georss:point>
-
-<poco:preferredUsername>testuser</poco:preferredUsername>
-<poco:displayName>Test User</poco:displayName>
-<poco:note>Just another test user.</poco:note>
-<poco:address>
- <poco:formatted>San Francisco, CA</poco:formatted>
-</poco:address>
-<poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>http://example.com/blog.html</poco:value>
- <poco:primary>true</poco:primary>
-
-</poco:urls>
-</activity:actor>
- <link rel="alternate" type="text/html" href="http://example.net/mysite/notice/7"/>
- <id>http://example.net/mysite/notice/7</id>
- <published>2010-02-24T00:53:06+00:00</published>
- <updated>2010-02-24T00:53:06+00:00</updated>
- <link rel="ostatus:conversation" href="http://example.net/mysite/conversation/7"/>
- <content type="html">Hey man, is that Freedom Code?! #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;http://example.net/mysite/tag/freedom&quot; rel=&quot;tag&quot;&gt;freedom&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;http://example.net/mysite/tag/hippy&quot; rel=&quot;tag&quot;&gt;hippy&lt;/a&gt;&lt;/span&gt;</content>
- <georss:point>37.8313160 -122.2852473</georss:point>
-
-</entry>
-</feed>
-EXAMPLE5;
-
-$_example6 = <<<EXAMPLE6
-<?xml version="1.0" encoding="UTF-8"?>
-<rss version="2.0"
-       xmlns:content="http://purl.org/rss/1.0/modules/content/"
-       xmlns:wfw="http://wellformedweb.org/CommentAPI/"
-       xmlns:dc="http://purl.org/dc/elements/1.1/"
-       xmlns:atom="http://www.w3.org/2005/Atom"
-       xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
-       xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
-       xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
-       >
-
-       <channel>
-               <title>WordPress.com News</title>
-               <atom:link href="http://en.blog.wordpress.com/feed/" rel="self" type="application/rss+xml" />
-               <link>http://en.blog.wordpress.com</link>
-               <description>The latest news on WordPress.com and the WordPress community.</description>
-               <lastBuildDate>Thu, 18 Mar 2010 23:25:35 +0000</lastBuildDate>
-
-               <generator>http://wordpress.com/</generator>
-               <language>en</language>
-               <sy:updatePeriod>hourly</sy:updatePeriod>
-               <sy:updateFrequency>1</sy:updateFrequency>
-               <cloud domain='en.blog.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
-               <image>
-                       <url>http://www.gravatar.com/blavatar/e6392390e3bcfadff3671c5a5653d95b?s=96&#038;d=http://s2.wp.com/i/buttonw-com.png</url>
-                       <title>WordPress.com News</title>
-                       <link>http://en.blog.wordpress.com</link>
-               </image>
-               <atom:link rel="search" type="application/opensearchdescription+xml" href="http://en.blog.wordpress.com/osd.xml" title="WordPress.com News" />
-               <atom:link rel='hub' href='http://en.blog.wordpress.com/?pushpress=hub'/>
-
-               <item>
-                       <title>Rub-a-Dub-Dub in the PubSubHubbub</title>
-                       <link>http://en.blog.wordpress.com/2010/03/03/rub-a-dub-dub-in-the-pubsubhubbub/</link>
-                       <comments>http://en.blog.wordpress.com/2010/03/03/rub-a-dub-dub-in-the-pubsubhubbub/#comments</comments>
-                       <pubDate>Wed, 03 Mar 2010 16:48:12 +0000</pubDate>
-                       <dc:creator>Joseph Scott</dc:creator>
-
-                       <category><![CDATA[Feeds]]></category>
-                       <category><![CDATA[atom]]></category>
-                       <category><![CDATA[pubsubhubbub]]></category>
-                       <category><![CDATA[rss]]></category>
-
-                       <guid isPermaLink="false">http://en.blog.wordpress.com/?p=3857</guid>
-                       <description><![CDATA[From the tongue twisting name department we welcome PubSubHubbub, or as some people have shortened it to: PuSH.  Like rssCloud, PuSH is a way for services that subscribe to updates from your blog to get updates even faster.  In a nutshell, instead of having to periodically ask [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=en.blog.wordpress.com&blog=3584907&post=3857&subd=en.blog&ref=&feed=1" />]]></description>
-                               <content:encoded><![CDATA[<p>From the tongue twisting name department we welcome PubSubHubbub, or as some people have shortened it to: PuSH.  Like <a href="http://en.blog.wordpress.com/2009/09/07/rss-in-the-clouds/">rssCloud</a>, PuSH is a way for services that subscribe to updates from your blog to get updates even faster.  In a nutshell, instead of having to periodically ask your blog if there are any updates they can now register to automatically receive updates each time you publish new content.  In most cases these updates are sent out within a second or two of when you hit the publish button.</p>
-       <p>Today we&#8217;ve turned on PuSH support for the more than 10.5 million blogs on WordPress.com.  There&#8217;s nothing to configure, it&#8217;s working right now behind the scenes to help others keep up to date with your posts.</p>
-       <p>For those using the WordPress.org software we are releasing a new PuSH plugin: <a href="http://wordpress.org/extend/plugins/pushpress/">PuSHPress</a>.  This plugin differs from the current PuSH related plugins by including a built-in hub.</p>
-       <br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/en.blog.wordpress.com/3857/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/en.blog.wordpress.com/3857/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/en.blog.wordpress.com/3857/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/en.blog.wordpress.com/3857/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/en.blog.wordpress.com/3857/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/en.blog.wordpress.com/3857/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/en.blog.wordpress.com/3857/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/en.blog.wordpress.com/3857/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/en.blog.wordpress.com/3857/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/en.blog.wordpress.com/3857/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=en.blog.wordpress.com&blog=3584907&post=3857&subd=en.blog&ref=&feed=1" />]]></content:encoded>
-                               <wfw:commentRss>http://en.blog.wordpress.com/2010/03/03/rub-a-dub-dub-in-the-pubsubhubbub/feed/</wfw:commentRss>
-
-                       <slash:comments>96</slash:comments>
-
-                       <media:content url="http://1.gravatar.com/avatar/582b66ad5ae1b69c7601a990cb9a661a?s=96&#38;d=identicon" medium="image">
-                               <media:title type="html">josephscott</media:title>
-                       </media:content>
-               </item>
-       </channel>
-</rss>
-EXAMPLE6;
-
-$_example7 = <<<EXAMPLE7
-<?xml version="1.0" encoding="UTF-8"?>
-       <rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:posterous="http://posterous.com/help/rss/1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
-         <channel>
-           <title>evanpro's posterous</title>
-           <link>http://evanpro.posterous.com</link>
-           <description>Most recent posts at evanpro's posterous</description>
-           <generator>posterous.com</generator>
-           <link type="application/json" xmlns="http://www.w3.org/2005/Atom" rel="http://api.friendfeed.com/2008/03#sup" href="http://posterous.com/api/sup_update#56bcc5eb7"/>
-           <atom:link rel="self" href="http://evanpro.posterous.com/rss.xml"/>
-           <atom:link rel="hub" href="http://posterous.superfeedr.com"/>
-           <item>
-             <pubDate>Sat, 20 Mar 2010 07:32:31 -0700</pubDate>
-             <title>Checking out captain bones</title>
-             <link>http://evanpro.posterous.com/checking-out-captain-bones</link>
-             <guid>http://evanpro.posterous.com/checking-out-captain-bones</guid>
-             <description>
-               <![CDATA[<p>
-               <p>Bones!</p>
-
-       </p>
-
-       <p><a href="http://evanpro.posterous.com/checking-out-captain-bones">Permalink</a>
-
-               | <a href="http://evanpro.posterous.com/checking-out-captain-bones#comment">Leave a comment&nbsp;&nbsp;&raquo;</a>
-
-       </p>]]>
-             </description>
-             <posterous:author>
-               <posterous:userImage>http://files.posterous.com/user_profile_pics/480326/2009-08-05-142447.jpg</posterous:userImage>
-               <posterous:profileUrl>http://posterous.com/people/3sDslhaepotz</posterous:profileUrl>
-               <posterous:firstName>Evan</posterous:firstName>
-               <posterous:lastnNme>Prodromou</posterous:lastnNme>
-               <posterous:nickName>evanpro</posterous:nickName>
-               <posterous:displayName>Evan Prodromou</posterous:displayName>
-             </posterous:author>
-           </item>
-       </channel>
-</rss>
-EXAMPLE7;
-
-$_example8 = <<<EXAMPLE8
-<?xml version="1.0"?>
-<feed xmlns="http://www.w3.org/2005/Atom">
-    <link href="http://pubsubhubbub.appspot.com/" rel="hub"/>
-    <title type="text">Activity Stream for: zcopley</title>
-    <id>http://cliqset.com/feed/atom?uid=zcopley</id>
-    <entry xmlns:service="http://activitystrea.ms/service-provider" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-        <thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total>
-        <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-        <published>2010-03-22T01:35:53.000Z</published>
-        <service:provider>
-            <name>flickr</name>
-            <uri>http://flickr.com</uri>
-            <icon>http://cliqset-services.s3.amazonaws.com/flickr.png</icon>
-        </service:provider>
-        <activity:object>
-            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
-            <title type="text">IMG_1368</title>
-            <link type="image/jpeg" rel="preview" href="http://media.cliqset.com/6f6fbee9d7dfbffc73b6ef626275eb5f_thumb.jpg"/>
-            <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/zcopley/4452933806/"/>
-        </activity:object>
-        <activity:object>
-            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
-            <title type="text">IMG_1365</title>
-            <link type="image/jpeg" rel="preview" href="http://media.cliqset.com/b8f3932cd0bba1b27f7c8b3ef986915e_thumb.jpg"/>
-            <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/zcopley/4442630390/"/>
-        </activity:object>
-        <activity:object xmlns:media="http://purl.org/syndication/atommedia">
-            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
-            <title type="text">Classic</title>
-            <link type="image/jpeg" rel="preview" href="http://media.cliqset.com/fc54c15f850b7a9a8efa644087a48c91_thumb.jpg"/>
-            <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/zcopley/4430754103/"/>
-            <media:description type="text">-Powered by pikchur.com/n0u</media:description>
-        </activity:object>
-        <activity:object>
-            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
-            <title type="text">IMG_1363</title>
-            <link type="image/jpeg" rel="preview" href="http://media.cliqset.com/4b1d307c9217e2114391a8b229d612cb_thumb.jpg"/>
-            <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/zcopley/4416969717/"/>
-        </activity:object>
-        <activity:object>
-            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
-            <title type="text">IMG_1361</title>
-            <link type="image/jpeg" rel="preview" href="http://media.cliqset.com/23d9b4b96b286e0347d36052f22f6e60_thumb.jpg"/>
-            <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/zcopley/4417734232/"/>
-        </activity:object>
-        <title type="text">zcopley posted some photos on Flickr</title>
-        <summary type="text">zcopley posted 5 photos on Flickr</summary>
-        <category scheme="http://schemas.cliqset.com/activity/categories/1.0" term="PhotoPosted" label="Photo Posted"/>
-        <updated>2010-03-22T20:46:42.778Z</updated>
-        <id>tag:cliqset.com,2010-03-22:/user/zcopley/SVgAZubGhtAnSAee</id>
-        <link href="http://cliqset.com/user/zcopley/SVgAZubGhtAnSAee" type="text/xhtml" rel="alternate" title="zcopley posted some photos on Flickr"/>
-        <author>
-            <name>zcopley</name>
-            <uri>http://cliqset.com/user/zcopley</uri>
-        </author>
-        <activity:actor xmlns:poco="http://portablecontacts.net/spec/1.0">
-            <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-            <id>zcopley</id>
-            <poco:name>
-                <poco:givenName>Zach</poco:givenName>
-                <poco:familyName>Copley</poco:familyName>
-            </poco:name>
-            <link xmlns:media="http://purl.org/syndication/atommedia" type="image/png" rel="avatar" href="http://dynamic.cliqset.com/avatar/zcopley?s=80" media:height="80" media:width="80"/>
-            <link xmlns:media="http://purl.org/syndication/atommedia" type="image/png" rel="avatar" href="http://dynamic.cliqset.com/avatar/zcopley?s=120" media:height="120" media:width="120"/>
-            <link xmlns:media="http://purl.org/syndication/atommedia" type="image/png" rel="avatar" href="http://dynamic.cliqset.com/avatar/zcopley?s=200" media:height="200" media:width="200"/>
-        </activity:actor>
-    </entry>
-</feed>
-EXAMPLE8;
-
-$_example9 = <<<EXAMPLE9
-<?xml version="1.0" encoding="utf-8"?>
-<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:media="http://search.yahoo.com/mrss" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-    <link rel="self" type="application/atom+xml" href="http://"/>
-    <link rel="hub" href="http://pubsubhubbub.appspot.com/"/>
-    <title type="text">Test</title>
-    <updated>2010-03-22T01:55:53.596Z</updated>
-    <id>test53725745374</id>
-    <generator>test</generator>
-    <entry>
-        <title type="html">Buzz by Zach Copley from Flickr</title>
-        <summary type="text">IMG_1366</summary>
-        <published>2010-03-18T04:29:23.000Z</published>
-        <updated>2010-03-18T05:14:03.325Z</updated>
-        <id>test53725745374entry</id>
-        <link rel="alternate" type="text/html" href="http://buzz.example/117848251937215158042/ZU7b6mHJEmC/IMG-1366"/>
-        <author>
-            <name>Zach Copley</name>
-            <uri>https://mywebsite.net/profiles/zcopley</uri>
-        </author>
-        <content type="html">&lt;div&gt;IMG_1366&lt;/div&gt;</content>
-        <link rel="enclosure" href="http://www.flickr.com/photos/22823034@N00/4442630700" type="image/jpeg" title="IMG_1366"/>
-        <media:content url="http://www.flickr.com/photos/22823034@N00/4442630700" type="image/jpeg" medium="image">
-            <media:title>IMG_1366</media:title>
-            <media:player url="http://farm5.static.flickr.com/4053/4442630700_980b19a1a6_o.jpg" height="1600" width="1200"/>
-        </media:content>
-        <link rel="enclosure" href="http://www.flickr.com/photos/22823034@N00/4442630390" type="image/jpeg" title="IMG_1365"/>
-        <media:content url="http://www.flickr.com/photos/22823034@N00/4442630390" type="image/jpeg" medium="image">
-            <media:title>IMG_1365</media:title>
-            <media:player url="http://farm5.static.flickr.com/4043/4442630390_62da5560ae_o.jpg" height="1200" width="1600"/>
-        </media:content>
-        <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-        <activity:object>
-            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
-            <id>test53725745374entry</id>
-            <title>Buzz by Zach Copley from Flickr</title>
-            <content type="html">&lt;div&gt;IMG_1366&lt;/div&gt;</content>
-            <link rel="enclosure" href="http://www.flickr.com/photos/22823034@N00/4442630700" type="image/jpeg" title="IMG_1366"/>
-            <link rel="enclosure" href="http://www.flickr.com/photos/22823034@N00/4442630390" type="image/jpeg" title="IMG_1365"/>
-        </activity:object>
-        <link rel="replies" type="application/atom+xml" href="http://buzz.example/test53725745374/comments" thr:count="0"/>
-        <thr:total>0</thr:total>
-    </entry>
-</feed>
-EXAMPLE9;
-
-// Sample PuSH entry from a group feed in 0.9.7
-// Old <activity:actor> has been removed from entries in this version.
-// A bug in the order of input processing meant that we were incorrectly
-// reading the feed's <activity:subject> instead of the entry's <author>,
-// causing the entry to get rejected as malformed (groups can't post on
-// their own; we want to see the actual author's info here).
-$_example10 = <<<EXAMPLE10
-<?xml version="1.0" encoding="UTF-8"?>
-<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
- <generator uri="http://status.net" version="0.9.7alpha1">StatusNet</generator>
- <id>http://lazarus.local/mublog/api/statusnet/groups/timeline/22.atom</id>
- <title>grouptest316173 timeline</title>
- <subtitle>Updates from grouptest316173 on Blaguette!</subtitle>
- <logo>http://lazarus.local/mublog/theme/default/default-avatar-profile.png</logo>
- <updated>2011-01-06T22:44:18+00:00</updated>
-<author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/group</activity:object-type>
- <uri>http://lazarus.local/mublog/group/22/id</uri>
- <name>grouptest316173</name>
- <link rel="alternate" type="text/html" href="http://lazarus.local/mublog/group/22/id"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://lazarus.local/mublog/theme/default/default-avatar-profile.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://lazarus.local/mublog/theme/default/default-avatar-stream.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://lazarus.local/mublog/theme/default/default-avatar-mini.png"/>
- <poco:preferredUsername>grouptest316173</poco:preferredUsername>
- <poco:displayName>grouptest316173</poco:displayName>
-</author>
-<activity:subject>
- <activity:object-type>http://activitystrea.ms/schema/1.0/group</activity:object-type>
- <id>http://lazarus.local/mublog/group/22/id</id>
- <title>grouptest316173</title>
- <link rel="alternate" type="text/html" href="http://lazarus.local/mublog/group/22/id"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://lazarus.local/mublog/theme/default/default-avatar-profile.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://lazarus.local/mublog/theme/default/default-avatar-stream.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://lazarus.local/mublog/theme/default/default-avatar-mini.png"/>
- <poco:preferredUsername>grouptest316173</poco:preferredUsername>
- <poco:displayName>grouptest316173</poco:displayName>
-</activity:subject>
- <link href="http://lazarus.local/mublog/group/grouptest316173" rel="alternate" type="text/html"/>
- <link href="http://lazarus.local/mublog/main/push/hub" rel="hub"/>
- <link href="http://lazarus.local/mublog/main/salmon/group/22" rel="salmon"/>
- <link href="http://lazarus.local/mublog/main/salmon/group/22" rel="http://salmon-protocol.org/ns/salmon-replies"/>
- <link href="http://lazarus.local/mublog/main/salmon/group/22" rel="http://salmon-protocol.org/ns/salmon-mention"/>
- <link href="http://lazarus.local/mublog/api/statusnet/groups/timeline/22.atom" rel="self" type="application/atom+xml"/>
- <statusnet:group_info member_count="2"></statusnet:group_info>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>http://lazarus.local/mublog/notice/1243</id>
- <title>Group post from local to !grouptest316173, should go out over push.</title>
- <content type="html">Group post from local to !&lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;http://lazarus.local/mublog/group/22/id&quot; class=&quot;url&quot;&gt;&lt;span class=&quot;fn nickname&quot;&gt;grouptest316173&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;, should go out over push.</content>
- <link rel="alternate" type="text/html" href="http://lazarus.local/mublog/notice/1243"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2011-01-06T22:44:18+00:00</published>
- <updated>2011-01-06T22:44:18+00:00</updated>
- <author>
-  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-  <uri>http://lazarus.local/mublog/user/557</uri>
-  <name>Pubtest316173 Smith</name>
-  <link rel="alternate" type="text/html" href="http://lazarus.local/mublog/pubtest316173"/>
-  <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://lazarus.local/mublog/theme/default/default-avatar-profile.png"/>
-  <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://lazarus.local/mublog/theme/default/default-avatar-stream.png"/>
-  <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://lazarus.local/mublog/theme/default/default-avatar-mini.png"/>
-  <poco:preferredUsername>pubtest316173</poco:preferredUsername>
-  <poco:displayName>Pubtest316173 Smith</poco:displayName>
-  <poco:note>Stub account for OStatus tests.</poco:note>
-  <poco:urls>
-   <poco:type>homepage</poco:type>
-   <poco:value>http://example.org/pubtest316173</poco:value>
-   <poco:primary>true</poco:primary>
-  </poco:urls>
- </author>
- <link rel="ostatus:conversation" href="http://lazarus.local/mublog/conversation/1131"/>
- <link rel="mentioned" href="http://lazarus.local/mublog/group/22/id"/>
- <category term="grouptest316173"></category>
- <source>
-  <id>http://lazarus.local/mublog/api/statuses/user_timeline/557.atom</id>
-  <title>Pubtest316173 Smith</title>
-  <link rel="alternate" type="text/html" href="http://lazarus.local/mublog/pubtest316173"/>
-  <link rel="self" type="application/atom+xml" href="http://lazarus.local/mublog/api/statuses/user_timeline/557.atom"/>
-  <link rel="license" href="http://creativecommons.org/licenses/by/3.0/"/>
-  <icon>http://lazarus.local/mublog/theme/default/default-avatar-profile.png</icon>
-  <updated>2011-01-06T22:44:18+00:00</updated>
- </source>
- <link rel="self" type="application/atom+xml" href="http://lazarus.local/mublog/api/statuses/show/1243.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://lazarus.local/mublog/api/statuses/show/1243.atom"/>
- <statusnet:notice_info local_id="1243" source="api"></statusnet:notice_info>
-</entry>
-</feed>
-EXAMPLE10;
-
-$_example11 = <<<EXAMPLE11
-<?xml version="1.0" encoding="UTF-8"?>
-<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
- <generator uri="http://status.net" version="0.9.7">StatusNet</generator>
- <id>http://freelish.us/api/statuses/user_timeline/1.atom</id>
- <title>demon timeline</title>
- <subtitle>Updates from demon on freelish.us!</subtitle>
- <logo>http://avatar.status.net/f/freelishus/1-96-20110331163048.jpeg</logo>
- <updated>2011-05-30T09:36:03-04:00</updated>
-<author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>http://freelishus.status.net/user/1</uri>
- <name>demon</name>
- <link rel="alternate" type="text/html" href="http://freelish.us/demon"/>
- <link rel="avatar" type="image/jpeg" media:width="192" media:height="192" href="http://avatar.status.net/f/freelishus/1-192-20110331163048.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="http://avatar.status.net/f/freelishus/1-96-20110331163048.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="http://avatar.status.net/f/freelishus/1-48-20110331163048.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="http://avatar.status.net/f/freelishus/1-24-20110331163049.jpeg"/>
- <georss:point>45.50884 -73.58781</georss:point>
- <poco:preferredUsername>demon</poco:preferredUsername>
- <poco:displayName>Evan Prodromou</poco:displayName>
- <poco:note>Montreal hacker and entrepreneur.</poco:note>
- <poco:address>
-  <poco:formatted>Montreal, Quebec</poco:formatted>
-
-</poco:address>
- <poco:urls>
-  <poco:type>homepage</poco:type>
-  <poco:value>http://evan.status.net/</poco:value>
-  <poco:primary>true</poco:primary>
-</poco:urls>
- <statusnet:profile_info local_id="1"></statusnet:profile_info>
-</author>
-<!--Deprecation warning: activity:subject is present only for backward compatibility. It will be removed in the next version of StatusNet.-->
-<activity:subject>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>http://freelishus.status.net/user/1</id>
- <title>Evan Prodromou</title>
- <link rel="alternate" type="text/html" href="http://freelish.us/demon"/>
- <link rel="avatar" type="image/jpeg" media:width="192" media:height="192" href="http://avatar.status.net/f/freelishus/1-192-20110331163048.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="http://avatar.status.net/f/freelishus/1-96-20110331163048.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="http://avatar.status.net/f/freelishus/1-48-20110331163048.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="http://avatar.status.net/f/freelishus/1-24-20110331163049.jpeg"/>
- <georss:point>45.50884 -73.58781</georss:point>
- <poco:preferredUsername>demon</poco:preferredUsername>
- <poco:displayName>Evan Prodromou</poco:displayName>
- <poco:note>Montreal hacker and entrepreneur.</poco:note>
- <poco:address>
-  <poco:formatted>Montreal, Quebec</poco:formatted>
-
-</poco:address>
- <poco:urls>
-  <poco:type>homepage</poco:type>
-  <poco:value>http://evan.status.net/</poco:value>
-  <poco:primary>true</poco:primary>
-</poco:urls>
- <statusnet:profile_info local_id="1"></statusnet:profile_info>
-</activity:subject>
- <link href="http://freelish.us/demon" rel="alternate" type="text/html"/>
- <link href="http://freelish.us/main/sup#1" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
- <link href="http://freelish.us/api/statuses/user_timeline/1.atom?max_id=13210408" rel="next" type="application/atom+xml"/>
- <link href="http://freelish.us/main/push/hub" rel="hub"/>
- <link href="http://freelish.us/main/salmon/user/1" rel="salmon"/>
- <link href="http://freelish.us/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-replies"/>
- <link href="http://freelish.us/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-mention"/>
- <link href="http://freelish.us/api/statuses/user_timeline/1.atom" rel="self" type="application/atom+xml"/>
-
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/bookmark</activity:object-type>
- <id>http://freelish.us/bookmark/9e930c3e-7ed9-47de-aba5-df6c60cec542</id>
- <title>Why you should build an open-source startup | Teambox Blog</title>
- <link rel="alternate" type="text/html" href="http://freelish.us/bookmark/9e930c3e-7ed9-47de-aba5-df6c60cec542"/>
- <link rel="related" href="http://blog.teambox.com/open-source-companies"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2011-05-26T20:36:25+00:00</published>
- <updated>2011-05-26T20:36:25+00:00</updated>
- <link rel="ostatus:conversation" href="http://freelish.us/conversation/13835232"/>
- <category term="opensource"></category>
- <category term="startup"></category>
- <link rel="self" type="application/atom+xml" href="http://freelish.us/api/statuses/show/13836862.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://freelish.us/api/statuses/show/13836862.atom"/>
- <statusnet:notice_info local_id="13836862" source="web" favorite="false" repeated="false"></statusnet:notice_info>
-
-</entry>
-</feed>
-EXAMPLE11;
diff --git a/tests/CommandInterperterTest.php b/tests/CommandInterperterTest.php
deleted file mode 100644 (file)
index 5f681ae..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-class CommandInterpreterTest extends PHPUnit_Framework_TestCase
-{
-
-    /**
-     * @dataProvider commandInterpreterCases
-     */
-    public function testCommandInterpreter($input, $expectedType, $comment='')
-    {
-        $inter = new CommandInterpreter();
-
-        $cmd = $inter->handle_command(null, $input);
-
-        $type = $cmd ? get_class($cmd) : null;
-        $this->assertEquals(strtolower($expectedType), strtolower($type), $comment);
-    }
-
-    static public function commandInterpreterCases()
-    {
-        $sets = array(
-            array('help', 'HelpCommand'),
-            array('help me bro', null, 'help does not accept multiple params'),
-            array('HeLP', 'HelpCommand', 'case check'),
-            array('HeLP Me BRO!', null, 'case & non-params check'),
-
-            array('login', 'LoginCommand'),
-            array('login to savings!', null, 'login does not accept params'),
-
-            array('lose', null, 'lose must have at least 1 parameter'),
-            array('lose foobar', 'LoseCommand', 'lose requires 1 parameter'),
-            array('lose        foobar', 'LoseCommand', 'check for space norm'),
-            array('lose more weight', null, 'lose does not accept multiple params'),
-
-            array('subscribers', 'SubscribersCommand'),
-            array('subscribers foo', null, 'subscribers does not take params'),
-
-            array('subscriptions', 'SubscriptionsCommand'),
-            array('subscriptions foo', null, 'subscriptions does not take params'),
-
-            array('groups', 'GroupsCommand'),
-            array('groups foo', null, 'groups does not take params'),
-
-            array('off', 'OffCommand', 'off accepts 0 or 1 params'),
-            array('off foo', 'OffCommand', 'off accepts 0 or 1 params'),
-            array('off foo bar', null, 'off accepts 0 or 1 params'),
-
-            array('stop', 'OffCommand', 'stop accepts 0 params'),
-            array('stop foo', null, 'stop accepts 0 params'),
-
-            array('quit', 'OffCommand', 'quit accepts 0 params'),
-            array('quit foo', null, 'quit accepts 0 params'),
-
-            array('on', 'OnCommand', 'on accepts 0 or 1 params'),
-            array('on foo', 'OnCommand', 'on accepts 0 or 1 params'),
-            array('on foo bar', null, 'on accepts 0 or 1 params'),
-
-            array('join', null),
-            array('join foo', 'JoinCommand'),
-            array('join foo bar', null),
-
-            array('drop', null),
-            array('drop foo', 'DropCommand'),
-            array('drop foo bar', null),
-
-            array('follow', null),
-            array('follow foo', 'SubCommand'),
-            array('follow foo bar', null),
-
-            array('sub', null),
-            array('sub foo', 'SubCommand'),
-            array('sub foo bar', null),
-
-            array('leave', null),
-            array('leave foo', 'UnsubCommand'),
-            array('leave foo bar', null),
-
-            array('unsub', null),
-            array('unsub foo', 'UnsubCommand'),
-            array('unsub foo bar', null),
-
-            array('leave', null),
-            array('leave foo', 'UnsubCommand'),
-            array('leave foo bar', null),
-
-            array('d', null),
-            array('d foo', null),
-            array('d foo bar', 'MessageCommand'),
-
-            array('dm', null),
-            array('dm foo', null),
-            array('dm foo bar', 'MessageCommand'),
-
-            array('r', null),
-            array('r foo', null),
-            array('r foo bar', 'ReplyCommand'),
-
-            array('reply', null),
-            array('reply foo', null),
-            array('reply foo bar', 'ReplyCommand'),
-
-            array('repeat', null),
-            array('repeat foo', 'RepeatCommand'),
-            array('repeat foo bar', null),
-
-            array('rp', null),
-            array('rp foo', 'RepeatCommand'),
-            array('rp foo bar', null),
-
-            array('rt', null),
-            array('rt foo', 'RepeatCommand'),
-            array('rt foo bar', null),
-
-            array('rd', null),
-            array('rd foo', 'RepeatCommand'),
-            array('rd foo bar', null),
-
-            array('whois', null),
-            array('whois foo', 'WhoisCommand'),
-            array('whois foo bar', null),
-
-/*            array('fav', null),
-            array('fav foo', 'FavCommand'),
-            array('fav foo bar', null),*/
-
-            array('nudge', null),
-            array('nudge foo', 'NudgeCommand'),
-            array('nudge foo bar', null),
-
-            array('stats', 'StatsCommand'),
-            array('stats foo', null),
-
-            array('invite', null),
-            array('invite foo', 'InviteCommand'),
-            array('invite foo bar', null),
-
-            array('track', null),
-            array('track foo', 'SearchSubTrackCommand'),
-            array('track off', 'SearchSubTrackOffCommand'),
-            array('track foo bar', null),
-            array('track off foo', null),
-
-            array('untrack', null),
-            array('untrack foo', 'SearchSubUntrackCommand'),
-            array('untrack all', 'SearchSubTrackOffCommand'),
-            array('untrack foo bar', null),
-            array('untrack all foo', null),
-
-            array('tracking', 'SearchSubTrackingCommand'),
-            array('tracking foo', null),
-
-            array('tracks', 'SearchSubTrackingCommand'),
-            array('tracks foo', null),
-
-        );
-        return $sets;
-    }
-
-}
-
diff --git a/tests/Core/ActivityGenerationTests.php b/tests/Core/ActivityGenerationTests.php
new file mode 100644 (file)
index 0000000..f8bb025
--- /dev/null
@@ -0,0 +1,598 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('PUBLICDIR')) {
+    define('PUBLICDIR', INSTALLDIR . DIRECTORY_SEPARATOR . 'public');
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use Activity;
+use ActivityObject;
+use ActivityUtils;
+use ActivityVerb;
+use Conversation;
+use DOMDocument;
+use Exception;
+use Notice;
+use PHPUnit\Framework\TestCase;
+use User;
+use User_group;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+final class ActivityGenerationTests extends TestCase
+{
+    static $author1 = null;
+    static $author2 = null;
+
+    static $targetUser1 = null;
+    static $targetUser2 = null;
+
+    static $targetGroup1 = null;
+    static $targetGroup2 = null;
+
+    public static function setUpBeforeClass()
+    {
+        $authorNick1 = 'activitygenerationtestsuser' . common_random_hexstr(4);
+        $authorNick2 = 'activitygenerationtestsuser' . common_random_hexstr(4);
+
+        $targetNick1 = 'activitygenerationteststarget' . common_random_hexstr(4);
+        $targetNick2 = 'activitygenerationteststarget' . common_random_hexstr(4);
+
+        $groupNick1 = 'activitygenerationtestsgroup' . common_random_hexstr(4);
+        $groupNick2 = 'activitygenerationtestsgroup' . common_random_hexstr(4);
+
+        try {
+            self::$author1 = User::register(array('nickname' => $authorNick1,
+                'email' => $authorNick1 . '@example.net',
+                'email_confirmed' => true));
+
+            self::$author2 = User::register(array('nickname' => $authorNick2,
+                'email' => $authorNick2 . '@example.net',
+                'email_confirmed' => true));
+
+            self::$targetUser1 = User::register(array('nickname' => $targetNick1,
+                'email' => $targetNick1 . '@example.net',
+                'email_confirmed' => true));
+
+            self::$targetUser2 = User::register(array('nickname' => $targetNick2,
+                'email' => $targetNick2 . '@example.net',
+                'email_confirmed' => true));
+
+            self::$targetGroup1 = User_group::register(array('nickname' => $groupNick1,
+                'userid' => self::$author1->id,
+                'aliases' => array(),
+                'local' => true,
+                'location' => null,
+                'description' => null,
+                'fullname' => null,
+                'homepage' => null,
+                'mainpage' => null));
+            self::$targetGroup2 = User_group::register(array('nickname' => $groupNick2,
+                'userid' => self::$author1->id,
+                'aliases' => array(),
+                'local' => true,
+                'location' => null,
+                'description' => null,
+                'fullname' => null,
+                'homepage' => null,
+                'mainpage' => null));
+        } catch (Exception $e) {
+            self::tearDownAfterClass();
+            throw $e;
+        }
+    }
+
+    public function testBasicNoticeActivity()
+    {
+        $notice = $this->_fakeNotice();
+
+        $entry = $notice->asAtomEntry(true);
+
+        $element = $this->_entryToElement($entry, false);
+
+        $this->assertEquals($notice->getUri(), ActivityUtils::childContent($element, 'id'));
+        $this->assertEquals('New note by ' . self::$author1->nickname, ActivityUtils::childContent($element, 'title'));
+        $this->assertEquals($notice->rendered, ActivityUtils::childContent($element, 'content'));
+        $this->assertEquals(strtotime($notice->created), strtotime(ActivityUtils::childContent($element, 'published')));
+        $this->assertEquals(strtotime($notice->created), strtotime(ActivityUtils::childContent($element, 'updated')));
+        $this->assertEquals(ActivityVerb::POST, ActivityUtils::childContent($element, 'verb', Activity::SPEC));
+        $this->assertEquals(ActivityObject::NOTE, ActivityUtils::childContent($element, 'object-type', Activity::SPEC));
+    }
+
+    public function testNamespaceFlag()
+    {
+        $notice = $this->_fakeNotice();
+
+        $entry = $notice->asAtomEntry(true);
+
+        $element = $this->_entryToElement($entry, false);
+
+        $this->assertTrue($element->hasAttribute('xmlns'));
+        $this->assertTrue($element->hasAttribute('xmlns:thr'));
+        $this->assertTrue($element->hasAttribute('xmlns:georss'));
+        $this->assertTrue($element->hasAttribute('xmlns:activity'));
+        $this->assertTrue($element->hasAttribute('xmlns:media'));
+        $this->assertTrue($element->hasAttribute('xmlns:poco'));
+        $this->assertTrue($element->hasAttribute('xmlns:ostatus'));
+        $this->assertTrue($element->hasAttribute('xmlns:statusnet'));
+
+        $entry = $notice->asAtomEntry(false);
+
+        $element = $this->_entryToElement($entry, true);
+
+        $this->assertFalse($element->hasAttribute('xmlns'));
+        $this->assertFalse($element->hasAttribute('xmlns:thr'));
+        $this->assertFalse($element->hasAttribute('xmlns:georss'));
+        $this->assertFalse($element->hasAttribute('xmlns:activity'));
+        $this->assertFalse($element->hasAttribute('xmlns:media'));
+        $this->assertFalse($element->hasAttribute('xmlns:poco'));
+        $this->assertFalse($element->hasAttribute('xmlns:ostatus'));
+        $this->assertFalse($element->hasAttribute('xmlns:statusnet'));
+    }
+
+    public function testSourceFlag()
+    {
+        $notice = $this->_fakeNotice();
+
+        // Test with no source
+
+        $entry = $notice->asAtomEntry(false, false);
+
+        $element = $this->_entryToElement($entry, true);
+
+        $source = ActivityUtils::child($element, 'source');
+
+        $this->assertNull($source);
+
+        // Test with source
+
+        $entry = $notice->asAtomEntry(false, true);
+
+        $element = $this->_entryToElement($entry, true);
+
+        $source = ActivityUtils::child($element, 'source');
+
+        $this->assertNotNull($source);
+    }
+
+    public function testSourceContent()
+    {
+        $notice = $this->_fakeNotice();
+        // make a time difference!
+        sleep(2);
+        $notice2 = $this->_fakeNotice();
+
+        $entry = $notice->asAtomEntry(false, true);
+
+        $element = $this->_entryToElement($entry, true);
+
+        $source = ActivityUtils::child($element, 'source');
+
+        $atomUrl = common_local_url('ApiTimelineUser', array('id' => self::$author1->id, 'format' => 'atom'));
+
+        $profile = self::$author1->getProfile();
+
+        $this->assertEquals($atomUrl, ActivityUtils::childContent($source, 'id'));
+        $this->assertEquals($atomUrl, ActivityUtils::getLink($source, 'self', 'application/atom+xml'));
+        $this->assertEquals($profile->profileurl, ActivityUtils::getPermalink($source));
+        $this->assertEquals(strtotime($notice2->created), strtotime(ActivityUtils::childContent($source, 'updated')));
+        // XXX: do we care here?
+        $this->assertFalse(is_null(ActivityUtils::childContent($source, 'title')));
+        $this->assertEquals(common_config('license', 'url'), ActivityUtils::getLink($source, 'license'));
+    }
+
+    public function testAuthorFlag()
+    {
+        $notice = $this->_fakeNotice();
+
+        // Test with no author
+
+        $entry = $notice->asAtomEntry(false, false, false);
+
+        $element = $this->_entryToElement($entry, true);
+
+        $this->assertNull(ActivityUtils::child($element, 'author'));
+        $this->assertNull(ActivityUtils::child($element, 'actor', Activity::SPEC));
+
+        // Test with source
+
+        $entry = $notice->asAtomEntry(false, false, true);
+
+        $element = $this->_entryToElement($entry, true);
+
+        $author = ActivityUtils::child($element, 'author');
+        $actor = ActivityUtils::child($element, 'actor', Activity::SPEC);
+
+        $this->assertFalse(is_null($author));
+        $this->assertTrue(is_null($actor)); // <activity:actor> is obsolete, no longer added
+    }
+
+    public function testAuthorContent()
+    {
+        $notice = $this->_fakeNotice();
+
+        // Test with author
+
+        $entry = $notice->asAtomEntry(false, false, true);
+
+        $element = $this->_entryToElement($entry, true);
+
+        $author = ActivityUtils::child($element, 'author');
+
+        $this->assertEquals(self::$author1->getNickname(), ActivityUtils::childContent($author, 'name'));
+        $this->assertEquals(self::$author1->getUri(), ActivityUtils::childContent($author, 'uri'));
+    }
+
+    /**
+     * We no longer create <activity:actor> entries, they have merged to <atom:author>
+     */
+    public function testActorContent()
+    {
+        $notice = $this->_fakeNotice();
+
+        // Test with author
+
+        $entry = $notice->asAtomEntry(false, false, true);
+
+        $element = $this->_entryToElement($entry, true);
+
+        $actor = ActivityUtils::child($element, 'actor', Activity::SPEC);
+
+        $this->assertEquals($actor, null);
+    }
+
+    public function testReplyLink()
+    {
+        $orig = $this->_fakeNotice(self::$targetUser1);
+
+        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);
+
+        $reply = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));
+
+        $entry = $reply->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $irt = ActivityUtils::child($element, 'in-reply-to', 'http://purl.org/syndication/thread/1.0');
+
+        $this->assertNotNull($irt);
+        $this->assertEquals($orig->getUri(), $irt->getAttribute('ref'));
+        $this->assertEquals($orig->getUrl(), $irt->getAttribute('href'));
+    }
+
+    public function testReplyAttention()
+    {
+        $orig = $this->_fakeNotice(self::$targetUser1);
+
+        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);
+
+        $reply = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));
+
+        $entry = $reply->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $this->assertEquals(self::$targetUser1->getUri(), ActivityUtils::getLink($element, 'mentioned'));
+    }
+
+    public function testMultipleReplyAttention()
+    {
+        $orig = $this->_fakeNotice(self::$targetUser1);
+
+        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);
+
+        $reply = Notice::saveNew(self::$targetUser2->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));
+
+        $text = "@" . self::$targetUser1->nickname . " @" . self::$targetUser2->nickname . " reply text " . common_random_hexstr(4);
+
+        $reply2 = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $reply->id));
+
+        $entry = $reply2->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $links = ActivityUtils::getLinks($element, 'mentioned');
+
+        $hrefs = array();
+
+        foreach ($links as $link) {
+            $hrefs[] = $link->getAttribute('href');
+        }
+
+        $this->assertTrue(in_array(self::$targetUser1->getUri(), $hrefs));
+        $this->assertTrue(in_array(self::$targetUser2->getUri(), $hrefs));
+    }
+
+    public function testGroupPostAttention()
+    {
+        $text = "!" . self::$targetGroup1->nickname . " reply text " . common_random_hexstr(4);
+
+        $notice = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null));
+
+        $entry = $notice->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $this->assertEquals(self::$targetGroup1->getUri(), ActivityUtils::getLink($element, 'mentioned'));
+    }
+
+    public function testMultipleGroupPostAttention()
+    {
+        $text = "!" . self::$targetGroup1->nickname . " !" . self::$targetGroup2->nickname . " reply text " . common_random_hexstr(4);
+
+        $notice = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null));
+
+        $entry = $notice->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $links = ActivityUtils::getLinks($element, 'mentioned');
+
+        $hrefs = array();
+
+        foreach ($links as $link) {
+            $hrefs[] = $link->getAttribute('href');
+        }
+
+        $this->assertTrue(in_array(self::$targetGroup1->getUri(), $hrefs));
+        $this->assertTrue(in_array(self::$targetGroup2->getUri(), $hrefs));
+
+    }
+
+    public function testRepeatLink()
+    {
+        $notice = $this->_fakeNotice(self::$author1);
+        $repeat = $notice->repeat(self::$author2->getProfile(), 'test');
+
+        $entry = $repeat->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $noticeInfo = ActivityUtils::child($element, 'notice_info', 'http://status.net/schema/api/1/');
+
+        $this->assertNotNull($noticeInfo);
+        $this->assertEquals($notice->id, $noticeInfo->getAttribute('repeat_of'));
+        $this->assertEquals($repeat->id, $noticeInfo->getAttribute('local_id'));
+    }
+
+    public function testTag()
+    {
+        $tag1 = common_random_hexstr(4);
+
+        $notice = $this->_fakeNotice(self::$author1, '#' . $tag1);
+
+        $entry = $notice->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $category = ActivityUtils::child($element, 'category');
+
+        $this->assertNotNull($category);
+        $this->assertEquals($tag1, $category->getAttribute('term'));
+    }
+
+    public function testMultiTag()
+    {
+        $tag1 = common_random_hexstr(4);
+        $tag2 = common_random_hexstr(4);
+
+        $notice = $this->_fakeNotice(self::$author1, '#' . $tag1 . ' #' . $tag2);
+
+        $entry = $notice->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $categories = $element->getElementsByTagName('category');
+
+        $this->assertNotNull($categories);
+        $this->assertEquals(2, $categories->length);
+
+        $terms = array();
+
+        for ($i = 0; $i < $categories->length; $i++) {
+            $cat = $categories->item($i);
+            $terms[] = $cat->getAttribute('term');
+        }
+
+        $this->assertTrue(in_array($tag1, $terms));
+        $this->assertTrue(in_array($tag2, $terms));
+    }
+
+    public function testGeotaggedActivity()
+    {
+        $notice = Notice::saveNew(self::$author1->id, common_random_hexstr(4), 'test', array('uri' => null, 'lat' => 45.5, 'lon' => -73.6));
+
+        $entry = $notice->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $this->assertEquals('45.5000000 -73.6000000', ActivityUtils::childContent($element, 'point', "http://www.georss.org/georss"));
+    }
+
+    public function testNoticeInfo()
+    {
+        $notice = $this->_fakeNotice();
+
+        $entry = $notice->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
+
+        $this->assertEquals($notice->id, $noticeInfo->getAttribute('local_id'));
+        $this->assertEquals($notice->source, $noticeInfo->getAttribute('source'));
+        $this->assertEquals('', $noticeInfo->getAttribute('repeat_of'));
+        $this->assertEquals('', $noticeInfo->getAttribute('repeated'));
+//        $this->assertEquals('', $noticeInfo->getAttribute('favorite'));
+        $this->assertEquals('', $noticeInfo->getAttribute('source_link'));
+    }
+
+    public function testNoticeInfoRepeatOf()
+    {
+        $notice = $this->_fakeNotice();
+
+        $repeat = $notice->repeat(self::$author2->getProfile(), 'test');
+
+        $entry = $repeat->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
+
+        $this->assertEquals($notice->id, $noticeInfo->getAttribute('repeat_of'));
+    }
+
+    public function testNoticeInfoRepeated()
+    {
+        $notice = $this->_fakeNotice();
+
+        $repeat = $notice->repeat(self::$author2->getProfile(), 'test');
+
+        $entry = $notice->asAtomEntry(false, false, false, self::$author2->getProfile());
+
+        $element = $this->_entryToElement($entry, true);
+
+        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
+
+        $this->assertEquals('true', $noticeInfo->getAttribute('repeated'));
+
+        $entry = $notice->asAtomEntry(false, false, false, self::$targetUser1->getProfile());
+
+        $element = $this->_entryToElement($entry, true);
+
+        $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
+
+        $this->assertEquals('false', $noticeInfo->getAttribute('repeated'));
+    }
+
+    /*    public function testNoticeInfoFave()
+        {
+            $notice = $this->_fakeNotice();
+
+            $fave = Fave::addNew(self::$author2->getProfile(), $notice);
+
+            // Should be set if user has faved
+
+            $entry = $notice->asAtomEntry(false, false, false, self::$author2);
+
+            $element = $this->_entryToElement($entry, true);
+
+            $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
+
+            $this->assertEquals('true', $noticeInfo->getAttribute('favorite'));
+
+            // Shouldn't be set if user has not faved
+
+            $entry = $notice->asAtomEntry(false, false, false, self::$targetUser1);
+
+            $element = $this->_entryToElement($entry, true);
+
+            $noticeInfo = ActivityUtils::child($element, 'notice_info', "http://status.net/schema/api/1/");
+
+            $this->assertEquals('false', $noticeInfo->getAttribute('favorite'));
+        }*/
+
+    public function testConversationLink()
+    {
+        $orig = $this->_fakeNotice(self::$targetUser1);
+
+        $text = "@" . self::$targetUser1->nickname . " reply text " . common_random_hexstr(4);
+
+        $reply = Notice::saveNew(self::$author1->id, $text, 'test', array('uri' => null, 'reply_to' => $orig->id));
+
+        $conv = Conversation::getKV('id', $reply->conversation);
+
+        $entry = $reply->asAtomEntry();
+
+        $element = $this->_entryToElement($entry, true);
+
+        $this->assertEquals($conv->getUrl(), ActivityUtils::getLink($element, 'ostatus:conversation'));
+    }
+
+    public static function tearDownAfterClass()
+    {
+        if (!is_null(self::$author1)) {
+            self::$author1->getProfile()->delete();
+        }
+
+        if (!is_null(self::$author2)) {
+            self::$author2->getProfile()->delete();
+        }
+
+        if (!is_null(self::$targetUser1)) {
+            self::$targetUser1->getProfile()->delete();
+        }
+
+        if (!is_null(self::$targetUser2)) {
+            self::$targetUser2->getProfile()->delete();
+        }
+
+        if (!is_null(self::$targetGroup1)) {
+            self::$targetGroup1->delete();
+        }
+
+        if (!is_null(self::$targetGroup2)) {
+            self::$targetGroup2->delete();
+        }
+    }
+
+    private function _fakeNotice($user = null, $text = null)
+    {
+        if (empty($user)) {
+            $user = self::$author1;
+        }
+
+        if (empty($text)) {
+            $text = "fake-o text-o " . common_random_hexstr(32);
+        }
+
+        return Notice::saveNew($user->id, $text, 'test', array('uri' => null));
+    }
+
+    private function _entryToElement($entry, $namespace = false)
+    {
+        $xml = '<?xml version="1.0" encoding="utf-8"?>' . "\n\n";
+        $xml .= '<feed';
+        if ($namespace) {
+            $xml .= ' xmlns="http://www.w3.org/2005/Atom"';
+            $xml .= ' xmlns:thr="http://purl.org/syndication/thread/1.0"';
+            $xml .= ' xmlns:georss="http://www.georss.org/georss"';
+            $xml .= ' xmlns:activity="http://activitystrea.ms/spec/1.0/"';
+            $xml .= ' xmlns:media="http://purl.org/syndication/atommedia"';
+            $xml .= ' xmlns:poco="http://portablecontacts.net/spec/1.0"';
+            $xml .= ' xmlns:ostatus="http://ostatus.org/schema/1.0"';
+            $xml .= ' xmlns:statusnet="http://status.net/schema/api/1/"';
+        }
+        $xml .= '>' . "\n" . $entry . "\n" . '</feed>' . "\n";
+        $doc = new DOMDocument();
+        $doc->loadXML($xml);
+        $feed = $doc->documentElement;
+        $entries = $feed->getElementsByTagName('entry');
+
+        return $entries->item(0);
+    }
+}
diff --git a/tests/Core/ActivityParseTests.php b/tests/Core/ActivityParseTests.php
new file mode 100644 (file)
index 0000000..12e2f03
--- /dev/null
@@ -0,0 +1,1080 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use Activity;
+use ActivityObject;
+use ActivityUtils;
+use ActivityVerb;
+use DOMDocument;
+use PHPUnit\Framework\TestCase;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+final class ActivityParseTests extends TestCase
+{
+
+    public function testMastodonRetweet()
+    {
+        global $_mastodon_retweet;
+        $dom = new DOMDocument();
+        $dom->loadXML($_mastodon_retweet);
+        $feed = $dom->documentElement;
+        $entries = $feed->getElementsByTagName('entry');
+        $entry = $entries->item(0);
+        $act = new Activity($entry, $feed);
+        $this->assertFalse(empty($act));
+        $this->assertFalse(empty($act->objects[0]));
+
+        $object = $act->objects[0];
+        $this->assertEquals($object->verb, ActivityVerb::POST);
+    }
+
+    public function testGSReweet()
+    {
+        global $_gs_retweet;
+        $dom = new DOMDocument();
+        $dom->loadXML($_gs_retweet);
+        $feed = $dom->documentElement;
+        $entries = $feed->getElementsByTagName('entry');
+        $entry = $entries->item(0);
+        $act = new Activity($entry, $feed);
+        $this->assertFalse(empty($act));
+        $this->assertFalse(empty($act->objects[0]));
+
+        $object = $act->objects[0];
+        $this->assertEquals($object->verb, ActivityVerb::POST);
+    }
+
+    public function testExample1()
+    {
+        global $_example1;
+        $dom = new DOMDocument();
+        $dom->loadXML($_example1);
+        $act = new Activity($dom->documentElement);
+
+        $this->assertFalse(empty($act));
+
+        $this->assertEquals(1243860840, $act->time);
+        $this->assertEquals(ActivityVerb::POST, $act->verb);
+
+        $this->assertFalse(empty($act->objects[0]));
+        $this->assertEquals('Punctuation Changeset', $act->objects[0]->title);
+        $this->assertEquals('http://versioncentral.example.org/activity/changeset', $act->objects[0]->type);
+        $this->assertEquals('Fixing punctuation because it makes it more readable.', $act->objects[0]->summary);
+        $this->assertEquals('tag:versioncentral.example.org,2009:/change/1643245', $act->objects[0]->id);
+    }
+
+    public function testExample2()
+    {
+        global $_example2;
+        $dom = new DOMDocument();
+        $dom->loadXML($_example2);
+        $act = new Activity($dom->documentElement);
+
+        $this->assertFalse(empty($act));
+        // Did we handle <content type="html"> correctly with a typical payload?
+        $this->assertEquals("<p>Geraldine posted a Photo on PhotoPanic</p>\n     " .
+            "<img src=\"/geraldine/photo1.jpg\">", trim($act->content));
+    }
+
+    public function testExample3()
+    {
+        global $_example3;
+        $dom = new DOMDocument();
+        $dom->loadXML($_example3);
+
+        $feed = $dom->documentElement;
+
+        $entries = $feed->getElementsByTagName('entry');
+
+        $entry = $entries->item(0);
+
+        $act = new Activity($entry, $feed);
+
+        $this->assertFalse(empty($act));
+        $this->assertEquals(1071340202, $act->time);
+        $this->assertEquals('http://example.org/2003/12/13/atom03.html', $act->link);
+
+        $this->assertEquals($act->verb, ActivityVerb::POST);
+
+        $this->assertFalse(empty($act->actor));
+        $this->assertEquals(ActivityObject::PERSON, $act->actor->type);
+        $this->assertEquals('John Doe', $act->actor->title);
+        $this->assertEquals('mailto:johndoe@example.com', $act->actor->id);
+
+        $this->assertFalse(empty($act->objects[0]));
+        $this->assertEquals(ActivityObject::NOTE, $act->objects[0]->type);
+        $this->assertEquals('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', $act->objects[0]->id);
+        $this->assertEquals('Atom-Powered Robots Run Amok', $act->objects[0]->title);
+        $this->assertEquals('Some text.', $act->objects[0]->summary);
+        $this->assertEquals('http://example.org/2003/12/13/atom03.html', $act->objects[0]->link);
+
+        $this->assertFalse(empty($act->context));
+
+        $this->assertTrue(empty($act->target));
+
+        $this->assertEquals($act->entry, $entry);
+        $this->assertEquals($act->feed, $feed);
+    }
+
+    public function testExample4()
+    {
+        global $_example4;
+        $dom = new DOMDocument();
+        $dom->loadXML($_example4);
+
+        $entry = $dom->documentElement;
+
+        $act = new Activity($entry);
+
+        $this->assertFalse(empty($act));
+        $this->assertEquals(1266547958, $act->time);
+        $this->assertEquals('http://example.net/notice/14', $act->link);
+
+        $this->assertFalse(empty($act->context));
+        $this->assertEquals('http://example.net/notice/12', $act->context->replyToID);
+        $this->assertEquals('http://example.net/notice/12', $act->context->replyToUrl);
+        $this->assertEquals('http://example.net/conversation/11', $act->context->conversation);
+        $this->assertEquals(array('http://example.net/user/1'), array_keys($act->context->attention));
+
+        $this->assertFalse(empty($act->objects[0]));
+        $this->assertEquals($act->objects[0]->content,
+            '@<span class="vcard"><a href="http://example.net/user/1" class="url"><span class="fn nickname">evan</span></a></span> now is the time for all good men to come to the aid of their country. #<span class="tag"><a href="http://example.net/tag/thetime" rel="tag">thetime</a></span>');
+
+        $this->assertFalse(empty($act->actor));
+    }
+
+    public function testExample5()
+    {
+        global $_example5;
+        $dom = new DOMDocument();
+        $dom->loadXML($_example5);
+
+        $feed = $dom->documentElement;
+
+        // @todo Test feed elements
+
+        $entries = $feed->getElementsByTagName('entry');
+        $entry = $entries->item(0);
+
+        $act = new Activity($entry, $feed);
+
+        // Post
+        $this->assertEquals($act->verb, ActivityVerb::POST);
+        $this->assertFalse(empty($act->context));
+
+        // Actor w/Portable Contacts stuff
+        $this->assertFalse(empty($act->actor));
+        $this->assertEquals($act->actor->type, ActivityObject::PERSON);
+        $this->assertEquals($act->actor->title, 'Test User');
+        $this->assertEquals($act->actor->id, 'http://example.net/mysite/user/3');
+        $this->assertEquals($act->actor->link, 'http://example.net/mysite/testuser');
+
+        $avatars = $act->actor->avatarLinks;
+
+        $this->assertEquals(
+            $avatars[0]->url,
+            'http://example.net/mysite/avatar/3-96-20100224004207.jpeg'
+        );
+
+        $this->assertEquals($act->actor->displayName, 'Test User');
+
+        $poco = $act->actor->poco;
+        $this->assertEquals($poco->preferredUsername, 'testuser');
+        $this->assertEquals($poco->address->formatted, 'San Francisco, CA');
+        $this->assertEquals($poco->urls[0]->type, 'homepage');
+        $this->assertEquals($poco->urls[0]->value, 'http://example.com/blog.html');
+        $this->assertEquals($poco->urls[0]->primary, 'true');
+        $this->assertEquals($act->actor->geopoint, '37.7749295 -122.4194155');
+    }
+
+    public function testExample6()
+    {
+        global $_example6;
+
+        $dom = new DOMDocument();
+        $dom->loadXML($_example6);
+
+        $rss = $dom->documentElement;
+
+        $channels = $dom->getElementsByTagName('channel');
+
+        $channel = $channels->item(0);
+
+        $items = $channel->getElementsByTagName('item');
+
+        $item = $items->item(0);
+
+        $act = new Activity($item, $channel);
+
+        $this->assertEquals($act->verb, ActivityVerb::POST);
+
+        $this->assertEquals($act->id, 'http://en.blog.wordpress.com/?p=3857');
+        $this->assertEquals($act->link, 'http://en.blog.wordpress.com/2010/03/03/rub-a-dub-dub-in-the-pubsubhubbub/');
+        $this->assertEquals($act->title, 'Rub-a-Dub-Dub in the PubSubHubbub');
+        $this->assertEquals($act->time, 1267634892);
+
+        $actor = $act->actor;
+
+        $this->assertFalse(empty($actor));
+        $this->assertEquals($actor->title, "Joseph Scott");
+    }
+
+    public function testExample7()
+    {
+        global $_example7;
+
+        $dom = new DOMDocument();
+        $dom->loadXML($_example7);
+
+        $rss = $dom->documentElement;
+
+        $channels = $dom->getElementsByTagName('channel');
+
+        $channel = $channels->item(0);
+
+        $items = $channel->getElementsByTagName('item');
+
+        $item = $items->item(0);
+
+        $act = new Activity($item, $channel);
+
+        $this->assertEquals(ActivityVerb::POST, $act->verb);
+        $this->assertEquals('http://evanpro.posterous.com/checking-out-captain-bones', $act->link);
+        $this->assertEquals('http://evanpro.posterous.com/checking-out-captain-bones', $act->id);
+        $this->assertEquals('Checking out captain bones', $act->title);
+        $this->assertEquals(1269095551, $act->time);
+
+        $actor = $act->actor;
+
+        $this->assertEquals(ActivityObject::PERSON, $actor->type);
+        $this->assertEquals('http://posterous.com/people/3sDslhaepotz', $actor->id);
+        $this->assertEquals('Evan Prodromou', $actor->title);
+        $this->assertNull($actor->summary);
+        $this->assertNull($actor->content);
+        $this->assertEquals('http://posterous.com/people/3sDslhaepotz', $actor->link);
+        $this->assertNull($actor->source);
+        $this->assertTrue(is_array($actor->avatarLinks));
+        $this->assertEquals(1, count($actor->avatarLinks));
+        $this->assertEquals('http://files.posterous.com/user_profile_pics/480326/2009-08-05-142447.jpg',
+            $actor->avatarLinks[0]->url);
+        $this->assertNotNull($actor->poco);
+        $this->assertEquals('evanpro', $actor->poco->preferredUsername);
+        $this->assertEquals('Evan Prodromou', $actor->poco->displayName);
+        $this->assertNull($actor->poco->note);
+        $this->assertNull($actor->poco->address);
+        $this->assertEquals(0, count($actor->poco->urls));
+    }
+
+    // Media test - cliqset
+    public function testExample8()
+    {
+        global $_example8;
+        $dom = new DOMDocument();
+        $dom->loadXML($_example8);
+
+        $feed = $dom->documentElement;
+
+        $entries = $feed->getElementsByTagName('entry');
+
+        $entry = $entries->item(0);
+
+        $act = new Activity($entry, $feed);
+
+        $this->assertFalse(empty($act));
+        $this->assertEquals($act->time, 1269221753);
+        $this->assertEquals($act->verb, ActivityVerb::POST);
+        $this->assertEquals($act->summary, 'zcopley posted 5 photos on Flickr');
+
+        $this->assertFalse(empty($act->objects));
+        $this->assertEquals(sizeof($act->objects), 5);
+
+        $this->assertEquals($act->objects[0]->type, ActivityObject::PHOTO);
+        $this->assertEquals($act->objects[0]->title, 'IMG_1368');
+        $this->assertNull($act->objects[0]->description);
+        $this->assertEquals(
+            $act->objects[0]->thumbnail,
+            'http://media.cliqset.com/6f6fbee9d7dfbffc73b6ef626275eb5f_thumb.jpg'
+        );
+        $this->assertEquals(
+            $act->objects[0]->link,
+            'http://www.flickr.com/photos/zcopley/4452933806/'
+        );
+
+        $this->assertEquals($act->objects[1]->type, ActivityObject::PHOTO);
+        $this->assertEquals($act->objects[1]->title, 'IMG_1365');
+        $this->assertNull($act->objects[1]->description);
+        $this->assertEquals(
+            $act->objects[1]->thumbnail,
+            'http://media.cliqset.com/b8f3932cd0bba1b27f7c8b3ef986915e_thumb.jpg'
+        );
+        $this->assertEquals(
+            $act->objects[1]->link,
+            'http://www.flickr.com/photos/zcopley/4442630390/'
+        );
+
+        $this->assertEquals($act->objects[2]->type, ActivityObject::PHOTO);
+        $this->assertEquals($act->objects[2]->title, 'Classic');
+        $this->assertEquals(
+            $act->objects[2]->description,
+            '-Powered by pikchur.com/n0u'
+        );
+        $this->assertEquals(
+            $act->objects[2]->thumbnail,
+            'http://media.cliqset.com/fc54c15f850b7a9a8efa644087a48c91_thumb.jpg'
+        );
+        $this->assertEquals(
+            $act->objects[2]->link,
+            'http://www.flickr.com/photos/zcopley/4430754103/'
+        );
+
+        $this->assertEquals($act->objects[3]->type, ActivityObject::PHOTO);
+        $this->assertEquals($act->objects[3]->title, 'IMG_1363');
+        $this->assertNull($act->objects[3]->description);
+
+        $this->assertEquals(
+            $act->objects[3]->thumbnail,
+            'http://media.cliqset.com/4b1d307c9217e2114391a8b229d612cb_thumb.jpg'
+        );
+        $this->assertEquals(
+            $act->objects[3]->link,
+            'http://www.flickr.com/photos/zcopley/4416969717/'
+        );
+
+        $this->assertEquals($act->objects[4]->type, ActivityObject::PHOTO);
+        $this->assertEquals($act->objects[4]->title, 'IMG_1361');
+        $this->assertNull($act->objects[4]->description);
+
+        $this->assertEquals(
+            $act->objects[4]->thumbnail,
+            'http://media.cliqset.com/23d9b4b96b286e0347d36052f22f6e60_thumb.jpg'
+        );
+        $this->assertEquals(
+            $act->objects[4]->link,
+            'http://www.flickr.com/photos/zcopley/4417734232/'
+        );
+
+    }
+
+    public function testAtomContent()
+    {
+        $tests = array(array("<content>Some regular plain text.</content>",
+            "Some regular plain text."),
+            array("<content>&lt;b&gt;this is not HTML&lt;/b&gt;</content>",
+                "&lt;b&gt;this is not HTML&lt;/b&gt;"),
+            array("<content type='html'>Some regular plain HTML.</content>",
+                "Some regular plain HTML."),
+            array("<content type='html'>&lt;b&gt;this is too HTML&lt;/b&gt;</content>",
+                "<b>this is too HTML</b>"),
+            array("<content type='html'>&amp;lt;b&amp;gt;but this is not HTML!&amp;lt;/b&amp;gt;</content>",
+                "&lt;b&gt;but this is not HTML!&lt;/b&gt;"),
+            array("<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>Some regular plain XHTML.</div></content>",
+                "Some regular plain XHTML."),
+            array("<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'><b>This is some XHTML!</b></div></content>",
+                "<b>This is some XHTML!</b>"),
+            array("<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>&lt;b&gt;This is not some XHTML!&lt;/b&gt;</div></content>",
+                "&lt;b&gt;This is not some XHTML!&lt;/b&gt;"),
+            array("<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>&amp;lt;b&amp;gt;This is not some XHTML either!&amp;lt;/b&amp;gt;</div></content>",
+                "&amp;lt;b&amp;gt;This is not some XHTML either!&amp;lt;/b&amp;gt;"));
+        foreach ($tests as $data) {
+            list($source, $output) = $data;
+            $xml = "<entry xmlns='http://www.w3.org/2005/Atom'>" .
+                "<id>http://example.com/fakeid</id>" .
+                "<author><name>Test</name></author>" .
+                "<title>Atom content tests</title>" .
+                $source .
+                "</entry>";
+            $dom = new DOMDocument();
+            $dom->loadXML($xml);
+            $act = new Activity($dom->documentElement);
+
+            $this->assertFalse(empty($act));
+            $this->assertEquals($output, trim($act->content));
+        }
+    }
+
+    public function testRssContent()
+    {
+        $tests = array(array("<content:encoded>Some regular plain HTML.</content:encoded>",
+            "Some regular plain HTML."),
+            array("<content:encoded>Some &lt;b&gt;exciting bold HTML&lt;/b&gt;</content:encoded>",
+                "Some <b>exciting bold HTML</b>"),
+            array("<content:encoded>Some &amp;lt;b&amp;gt;escaped non-HTML.&amp;lt;/b&amp;gt;</content:encoded>",
+                "Some &lt;b&gt;escaped non-HTML.&lt;/b&gt;"),
+            array("<description>Some plain text.</description>",
+                "Some plain text."),
+            array("<description>Some &lt;b&gt;non-HTML text&lt;/b&gt;</description>",
+                "Some &lt;b&gt;non-HTML text&lt;/b&gt;"),
+            array("<description>Some &amp;lt;b&amp;gt;double-escaped text&amp;lt;/b&amp;gt;</description>",
+                "Some &amp;lt;b&amp;gt;double-escaped text&amp;lt;/b&amp;gt;"));
+        foreach ($tests as $data) {
+            list($source, $output) = $data;
+            $xml = "<item xmlns:content='http://purl.org/rss/1.0/modules/content/'>" .
+                "<guid>http://example.com/fakeid</guid>" .
+                "<title>RSS content tests</title>" .
+                $source .
+                "</item>";
+            $dom = new DOMDocument();
+            $dom->loadXML($xml);
+            $act = new Activity($dom->documentElement);
+
+            $this->assertFalse(empty($act));
+            $this->assertEquals($output, trim($act->content));
+        }
+    }
+
+    public function testExample10()
+    {
+        global $_example10;
+        $dom = new DOMDocument();
+        $dom->loadXML($_example10);
+
+        // example 10 is a PuSH item of a post on a group feed, as generated
+        // by 0.9.7 code after migration away from <activity:actor> to <author>
+        $feed = $dom->documentElement;
+        $entry = $dom->getElementsByTagName('entry')->item(0);
+        $expected = 'http://lazarus.local/mublog/user/557';
+
+        // Reading just the entry alone should pick up its own <author>
+        // as the actor.
+        $act = new Activity($entry);
+        $this->assertEquals($act->actor->id, $expected);
+
+        // Reading the entry in feed context used to be buggy, picking up
+        // the feed's <activity:subject> which referred to the group.
+        // It should now be returning the expected author entry...
+        $act = new Activity($entry, $feed);
+        $this->assertEquals($act->actor->id, $expected);
+    }
+
+    public function testBookmarkRelated()
+    {
+        global $_example11;
+        $dom = new DOMDocument();
+        $dom->loadXML($_example11);
+
+        $feed = $dom->documentElement;
+        $entry = $dom->getElementsByTagName('entry')->item(0);
+
+        $expected = 'http://blog.teambox.com/open-source-companies';
+
+        $links = ActivityUtils::getLinks($entry, 'related');
+
+        $this->assertFalse(empty($links));
+        $this->assertTrue(is_array($links));
+        $this->assertEquals(count($links), 1);
+
+        $url = $links[0]->getAttribute('href');
+
+        $this->assertEquals($url, $expected);
+    }
+}
+
+$_example1 = <<<EXAMPLE1
+<?xml version='1.0' encoding='UTF-8'?>
+<entry xmlns='http://www.w3.org/2005/Atom' xmlns:activity='http://activitystrea.ms/spec/1.0/'>
+  <id>tag:versioncentral.example.org,2009:/commit/1643245</id>
+  <published>2009-06-01T12:54:00Z</published>
+  <title>Geraldine committed a change to yate</title>
+  <content type="xhtml">Geraldine just committed a change to yate on VersionCentral</content>
+  <link rel="alternate" type="text/html"
+        href="http://versioncentral.example.org/geraldine/yate/commit/1643245" />
+  <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
+  <activity:verb>http://versioncentral.example.org/activity/commit</activity:verb>
+  <activity:object>
+    <activity:object-type>http://versioncentral.example.org/activity/changeset</activity:object-type>
+    <id>tag:versioncentral.example.org,2009:/change/1643245</id>
+    <title>Punctuation Changeset</title>
+    <summary>Fixing punctuation because it makes it more readable.</summary>
+    <link rel="alternate" type="text/html" href="..." />
+  </activity:object>
+</entry>
+EXAMPLE1;
+
+$_example2 = <<<EXAMPLE2
+<?xml version='1.0' encoding='UTF-8'?>
+<entry xmlns='http://www.w3.org/2005/Atom' xmlns:activity='http://activitystrea.ms/spec/1.0/'>
+  <id>tag:photopanic.example.com,2008:activity01</id>
+  <title>Geraldine posted a Photo on PhotoPanic</title>
+  <published>2008-11-02T15:29:00Z</published>
+  <link rel="alternate" type="text/html" href="/geraldine/activities/1" />
+  <activity:verb>
+  http://activitystrea.ms/schema/1.0/post
+  </activity:verb>
+  <activity:object>
+    <id>tag:photopanic.example.com,2008:photo01</id>
+    <title>My Cat</title>
+    <published>2008-11-02T15:29:00Z</published>
+    <link rel="alternate" type="text/html" href="/geraldine/photos/1" />
+    <activity:object-type>
+      tag:atomactivity.example.com,2008:photo
+    </activity:object-type>
+    <source>
+      <title>Geraldine's Photos</title>
+      <link rel="self" type="application/atom+xml" href="/geraldine/photofeed.xml" />
+      <link rel="alternate" type="text/html" href="/geraldine/" />
+    </source>
+  </activity:object>
+  <content type="html">
+     &lt;p&gt;Geraldine posted a Photo on PhotoPanic&lt;/p&gt;
+     &lt;img src="/geraldine/photo1.jpg"&gt;
+  </content>
+</entry>
+EXAMPLE2;
+
+$_example3 = <<<EXAMPLE3
+<?xml version="1.0" encoding="utf-8"?>
+
+<feed xmlns="http://www.w3.org/2005/Atom">
+
+    <title>Example Feed</title>
+    <subtitle>A subtitle.</subtitle>
+    <link href="http://example.org/feed/" rel="self" />
+    <link href="http://example.org/" />
+    <id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
+    <updated>2003-12-13T18:30:02Z</updated>
+    <author>
+        <name>John Doe</name>
+        <email>johndoe@example.com</email>
+    </author>
+
+    <entry>
+        <title>Atom-Powered Robots Run Amok</title>
+        <link href="http://example.org/2003/12/13/atom03" />
+        <link rel="alternate" type="text/html" href="http://example.org/2003/12/13/atom03.html"/>
+        <link rel="edit" href="http://example.org/2003/12/13/atom03/edit"/>
+        <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+        <updated>2003-12-13T18:30:02Z</updated>
+        <summary>Some text.</summary>
+    </entry>
+
+</feed>
+EXAMPLE3;
+
+$_example4 = <<<EXAMPLE4
+<?xml version='1.0' encoding='UTF-8'?>
+<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:ostatus="http://ostatus.org/schema/1.0">
+ <title>@evan now is the time for all good men to come to the aid of their country. #thetime</title>
+ <summary>@evan now is the time for all good men to come to the aid of their country. #thetime</summary>
+<author>
+ <name>spock</name>
+ <uri>http://example.net/user/2</uri>
+</author>
+<activity:actor>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
+ <id>http://example.net/user/2</id>
+ <title>spock</title>
+ <link type="image/png" rel="avatar" href="http://example.net/theme/identica/default-avatar-profile.png"></link>
+</activity:actor>
+ <link rel="alternate" type="text/html" href="http://example.net/notice/14"/>
+ <id>http://example.net/notice/14</id>
+ <published>2010-02-19T02:52:38+00:00</published>
+ <updated>2010-02-19T02:52:38+00:00</updated>
+ <link rel="related" href="http://example.net/notice/12"/>
+ <thr:in-reply-to ref="http://example.net/notice/12" href="http://example.net/notice/12"></thr:in-reply-to>
+ <link rel="ostatus:conversation" href="http://example.net/conversation/11"/>
+ <link rel="mentioned" href="http://example.net/user/1"/>
+ <content type="html">@&lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;http://example.net/user/1&quot; class=&quot;url&quot;&gt;&lt;span class=&quot;fn nickname&quot;&gt;evan&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; now is the time for all good men to come to the aid of their country. #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;http://example.net/tag/thetime&quot; rel=&quot;tag&quot;&gt;thetime&lt;/a&gt;&lt;/span&gt;</content>
+ <category term="thetime"></category>
+</entry>
+EXAMPLE4;
+
+$_example5 = <<<EXAMPLE5
+<?xml version="1.0" encoding="UTF-8"?>
+<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0">
+ <id>3</id>
+ <title>testuser timeline</title>
+ <subtitle>Updates from testuser on Zach Dev!</subtitle>
+ <logo>http://example.net/mysite/avatar/3-96-20100224004207.jpeg</logo>
+ <updated>2010-02-24T06:38:49+00:00</updated>
+<author>
+ <name>testuser</name>
+ <uri>http://example.net/mysite/user/3</uri>
+
+</author>
+ <link href="http://example.net/mysite/testuser" rel="alternate" type="text/html"/>
+ <link href="http://example.net/mysite/api/statuses/user_timeline/3.atom" rel="self" type="application/atom+xml"/>
+ <link href="http://example.net/mysite/main/sup#3" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
+ <link href="http://example.net/mysite/main/push/hub" rel="hub"/>
+ <link href="http://example.net/mysite/main/salmon/user/3" rel="salmon"/>
+<activity:subject>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
+ <id>http://example.net/mysite/user/3</id>
+ <title>Test User</title>
+ <link rel="alternate" type="text/html" href="http://example.net/mysite/testuser"/>
+ <link type="image/jpeg" rel="avatar" href="http://example.net/mysite/avatar/3-96-20100224004207.jpeg"/>
+ <georss:point>37.7749295 -122.4194155</georss:point>
+
+<poco:preferredUsername>testuser</poco:preferredUsername>
+<poco:displayName>Test User</poco:displayName>
+<poco:note>Just another test user.</poco:note>
+<poco:address>
+ <poco:formatted>San Francisco, CA</poco:formatted>
+</poco:address>
+<poco:urls>
+ <poco:type>homepage</poco:type>
+ <poco:value>http://example.com/blog.html</poco:value>
+ <poco:primary>true</poco:primary>
+
+</poco:urls>
+</activity:subject>
+<entry>
+ <title>Hey man, is that Freedom Code?! #freedom #hippy</title>
+ <summary>Hey man, is that Freedom Code?! #freedom #hippy</summary>
+<author>
+ <name>testuser</name>
+ <uri>http://example.net/mysite/user/3</uri>
+</author>
+<activity:actor>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
+ <id>http://example.net/mysite/user/3</id>
+ <title>Test User</title>
+ <link rel="alternate" type="text/html" href="http://example.net/mysite/testuser"/>
+ <link type="image/jpeg" rel="avatar" href="http://example.net/mysite/avatar/3-96-20100224004207.jpeg"/>
+ <georss:point>37.7749295 -122.4194155</georss:point>
+
+<poco:preferredUsername>testuser</poco:preferredUsername>
+<poco:displayName>Test User</poco:displayName>
+<poco:note>Just another test user.</poco:note>
+<poco:address>
+ <poco:formatted>San Francisco, CA</poco:formatted>
+</poco:address>
+<poco:urls>
+ <poco:type>homepage</poco:type>
+ <poco:value>http://example.com/blog.html</poco:value>
+ <poco:primary>true</poco:primary>
+
+</poco:urls>
+</activity:actor>
+ <link rel="alternate" type="text/html" href="http://example.net/mysite/notice/7"/>
+ <id>http://example.net/mysite/notice/7</id>
+ <published>2010-02-24T00:53:06+00:00</published>
+ <updated>2010-02-24T00:53:06+00:00</updated>
+ <link rel="ostatus:conversation" href="http://example.net/mysite/conversation/7"/>
+ <content type="html">Hey man, is that Freedom Code?! #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;http://example.net/mysite/tag/freedom&quot; rel=&quot;tag&quot;&gt;freedom&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;http://example.net/mysite/tag/hippy&quot; rel=&quot;tag&quot;&gt;hippy&lt;/a&gt;&lt;/span&gt;</content>
+ <georss:point>37.8313160 -122.2852473</georss:point>
+
+</entry>
+</feed>
+EXAMPLE5;
+
+$_example6 = <<<EXAMPLE6
+<?xml version="1.0" encoding="UTF-8"?>
+<rss version="2.0"
+       xmlns:content="http://purl.org/rss/1.0/modules/content/"
+       xmlns:wfw="http://wellformedweb.org/CommentAPI/"
+       xmlns:dc="http://purl.org/dc/elements/1.1/"
+       xmlns:atom="http://www.w3.org/2005/Atom"
+       xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
+       xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
+       xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
+       >
+
+       <channel>
+               <title>WordPress.com News</title>
+               <atom:link href="http://en.blog.wordpress.com/feed/" rel="self" type="application/rss+xml" />
+               <link>http://en.blog.wordpress.com</link>
+               <description>The latest news on WordPress.com and the WordPress community.</description>
+               <lastBuildDate>Thu, 18 Mar 2010 23:25:35 +0000</lastBuildDate>
+
+               <generator>http://wordpress.com/</generator>
+               <language>en</language>
+               <sy:updatePeriod>hourly</sy:updatePeriod>
+               <sy:updateFrequency>1</sy:updateFrequency>
+               <cloud domain='en.blog.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
+               <image>
+                       <url>http://www.gravatar.com/blavatar/e6392390e3bcfadff3671c5a5653d95b?s=96&#038;d=http://s2.wp.com/i/buttonw-com.png</url>
+                       <title>WordPress.com News</title>
+                       <link>http://en.blog.wordpress.com</link>
+               </image>
+               <atom:link rel="search" type="application/opensearchdescription+xml" href="http://en.blog.wordpress.com/osd.xml" title="WordPress.com News" />
+               <atom:link rel='hub' href='http://en.blog.wordpress.com/?pushpress=hub'/>
+
+               <item>
+                       <title>Rub-a-Dub-Dub in the PubSubHubbub</title>
+                       <link>http://en.blog.wordpress.com/2010/03/03/rub-a-dub-dub-in-the-pubsubhubbub/</link>
+                       <comments>http://en.blog.wordpress.com/2010/03/03/rub-a-dub-dub-in-the-pubsubhubbub/#comments</comments>
+                       <pubDate>Wed, 03 Mar 2010 16:48:12 +0000</pubDate>
+                       <dc:creator>Joseph Scott</dc:creator>
+
+                       <category><![CDATA[Feeds]]></category>
+                       <category><![CDATA[atom]]></category>
+                       <category><![CDATA[pubsubhubbub]]></category>
+                       <category><![CDATA[rss]]></category>
+
+                       <guid isPermaLink="false">http://en.blog.wordpress.com/?p=3857</guid>
+                       <description><![CDATA[From the tongue twisting name department we welcome PubSubHubbub, or as some people have shortened it to: PuSH.  Like rssCloud, PuSH is a way for services that subscribe to updates from your blog to get updates even faster.  In a nutshell, instead of having to periodically ask [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=en.blog.wordpress.com&blog=3584907&post=3857&subd=en.blog&ref=&feed=1" />]]></description>
+                               <content:encoded><![CDATA[<p>From the tongue twisting name department we welcome PubSubHubbub, or as some people have shortened it to: PuSH.  Like <a href="http://en.blog.wordpress.com/2009/09/07/rss-in-the-clouds/">rssCloud</a>, PuSH is a way for services that subscribe to updates from your blog to get updates even faster.  In a nutshell, instead of having to periodically ask your blog if there are any updates they can now register to automatically receive updates each time you publish new content.  In most cases these updates are sent out within a second or two of when you hit the publish button.</p>
+       <p>Today we&#8217;ve turned on PuSH support for the more than 10.5 million blogs on WordPress.com.  There&#8217;s nothing to configure, it&#8217;s working right now behind the scenes to help others keep up to date with your posts.</p>
+       <p>For those using the WordPress.org software we are releasing a new PuSH plugin: <a href="http://wordpress.org/extend/plugins/pushpress/">PuSHPress</a>.  This plugin differs from the current PuSH related plugins by including a built-in hub.</p>
+       <br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/en.blog.wordpress.com/3857/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/en.blog.wordpress.com/3857/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/en.blog.wordpress.com/3857/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/en.blog.wordpress.com/3857/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/en.blog.wordpress.com/3857/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/en.blog.wordpress.com/3857/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/en.blog.wordpress.com/3857/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/en.blog.wordpress.com/3857/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/en.blog.wordpress.com/3857/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/en.blog.wordpress.com/3857/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=en.blog.wordpress.com&blog=3584907&post=3857&subd=en.blog&ref=&feed=1" />]]></content:encoded>
+                               <wfw:commentRss>http://en.blog.wordpress.com/2010/03/03/rub-a-dub-dub-in-the-pubsubhubbub/feed/</wfw:commentRss>
+
+                       <slash:comments>96</slash:comments>
+
+                       <media:content url="http://1.gravatar.com/avatar/582b66ad5ae1b69c7601a990cb9a661a?s=96&#38;d=identicon" medium="image">
+                               <media:title type="html">josephscott</media:title>
+                       </media:content>
+               </item>
+       </channel>
+</rss>
+EXAMPLE6;
+
+$_example7 = <<<EXAMPLE7
+<?xml version="1.0" encoding="UTF-8"?>
+       <rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:posterous="http://posterous.com/help/rss/1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
+         <channel>
+           <title>evanpro's posterous</title>
+           <link>http://evanpro.posterous.com</link>
+           <description>Most recent posts at evanpro's posterous</description>
+           <generator>posterous.com</generator>
+           <link type="application/json" xmlns="http://www.w3.org/2005/Atom" rel="http://api.friendfeed.com/2008/03#sup" href="http://posterous.com/api/sup_update#56bcc5eb7"/>
+           <atom:link rel="self" href="http://evanpro.posterous.com/rss.xml"/>
+           <atom:link rel="hub" href="http://posterous.superfeedr.com"/>
+           <item>
+             <pubDate>Sat, 20 Mar 2010 07:32:31 -0700</pubDate>
+             <title>Checking out captain bones</title>
+             <link>http://evanpro.posterous.com/checking-out-captain-bones</link>
+             <guid>http://evanpro.posterous.com/checking-out-captain-bones</guid>
+             <description>
+               <![CDATA[<p>
+               <p>Bones!</p>
+
+       </p>
+
+       <p><a href="http://evanpro.posterous.com/checking-out-captain-bones">Permalink</a>
+
+               | <a href="http://evanpro.posterous.com/checking-out-captain-bones#comment">Leave a comment&nbsp;&nbsp;&raquo;</a>
+
+       </p>]]>
+             </description>
+             <posterous:author>
+               <posterous:userImage>http://files.posterous.com/user_profile_pics/480326/2009-08-05-142447.jpg</posterous:userImage>
+               <posterous:profileUrl>http://posterous.com/people/3sDslhaepotz</posterous:profileUrl>
+               <posterous:firstName>Evan</posterous:firstName>
+               <posterous:lastnNme>Prodromou</posterous:lastnNme>
+               <posterous:nickName>evanpro</posterous:nickName>
+               <posterous:displayName>Evan Prodromou</posterous:displayName>
+             </posterous:author>
+           </item>
+       </channel>
+</rss>
+EXAMPLE7;
+
+$_example8 = <<<EXAMPLE8
+<?xml version="1.0"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+    <link href="http://pubsubhubbub.appspot.com/" rel="hub"/>
+    <title type="text">Activity Stream for: zcopley</title>
+    <id>http://cliqset.com/feed/atom?uid=zcopley</id>
+    <entry xmlns:service="http://activitystrea.ms/service-provider" xmlns:activity="http://activitystrea.ms/spec/1.0/">
+        <thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total>
+        <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
+        <published>2010-03-22T01:35:53.000Z</published>
+        <service:provider>
+            <name>flickr</name>
+            <uri>http://flickr.com</uri>
+            <icon>http://cliqset-services.s3.amazonaws.com/flickr.png</icon>
+        </service:provider>
+        <activity:object>
+            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
+            <title type="text">IMG_1368</title>
+            <link type="image/jpeg" rel="preview" href="http://media.cliqset.com/6f6fbee9d7dfbffc73b6ef626275eb5f_thumb.jpg"/>
+            <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/zcopley/4452933806/"/>
+        </activity:object>
+        <activity:object>
+            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
+            <title type="text">IMG_1365</title>
+            <link type="image/jpeg" rel="preview" href="http://media.cliqset.com/b8f3932cd0bba1b27f7c8b3ef986915e_thumb.jpg"/>
+            <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/zcopley/4442630390/"/>
+        </activity:object>
+        <activity:object xmlns:media="http://purl.org/syndication/atommedia">
+            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
+            <title type="text">Classic</title>
+            <link type="image/jpeg" rel="preview" href="http://media.cliqset.com/fc54c15f850b7a9a8efa644087a48c91_thumb.jpg"/>
+            <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/zcopley/4430754103/"/>
+            <media:description type="text">-Powered by pikchur.com/n0u</media:description>
+        </activity:object>
+        <activity:object>
+            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
+            <title type="text">IMG_1363</title>
+            <link type="image/jpeg" rel="preview" href="http://media.cliqset.com/4b1d307c9217e2114391a8b229d612cb_thumb.jpg"/>
+            <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/zcopley/4416969717/"/>
+        </activity:object>
+        <activity:object>
+            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
+            <title type="text">IMG_1361</title>
+            <link type="image/jpeg" rel="preview" href="http://media.cliqset.com/23d9b4b96b286e0347d36052f22f6e60_thumb.jpg"/>
+            <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/zcopley/4417734232/"/>
+        </activity:object>
+        <title type="text">zcopley posted some photos on Flickr</title>
+        <summary type="text">zcopley posted 5 photos on Flickr</summary>
+        <category scheme="http://schemas.cliqset.com/activity/categories/1.0" term="PhotoPosted" label="Photo Posted"/>
+        <updated>2010-03-22T20:46:42.778Z</updated>
+        <id>tag:cliqset.com,2010-03-22:/user/zcopley/SVgAZubGhtAnSAee</id>
+        <link href="http://cliqset.com/user/zcopley/SVgAZubGhtAnSAee" type="text/xhtml" rel="alternate" title="zcopley posted some photos on Flickr"/>
+        <author>
+            <name>zcopley</name>
+            <uri>http://cliqset.com/user/zcopley</uri>
+        </author>
+        <activity:actor xmlns:poco="http://portablecontacts.net/spec/1.0">
+            <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
+            <id>zcopley</id>
+            <poco:name>
+                <poco:givenName>Zach</poco:givenName>
+                <poco:familyName>Copley</poco:familyName>
+            </poco:name>
+            <link xmlns:media="http://purl.org/syndication/atommedia" type="image/png" rel="avatar" href="http://dynamic.cliqset.com/avatar/zcopley?s=80" media:height="80" media:width="80"/>
+            <link xmlns:media="http://purl.org/syndication/atommedia" type="image/png" rel="avatar" href="http://dynamic.cliqset.com/avatar/zcopley?s=120" media:height="120" media:width="120"/>
+            <link xmlns:media="http://purl.org/syndication/atommedia" type="image/png" rel="avatar" href="http://dynamic.cliqset.com/avatar/zcopley?s=200" media:height="200" media:width="200"/>
+        </activity:actor>
+    </entry>
+</feed>
+EXAMPLE8;
+
+$_example9 = <<<EXAMPLE9
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:media="http://search.yahoo.com/mrss" xmlns:activity="http://activitystrea.ms/spec/1.0/">
+    <link rel="self" type="application/atom+xml" href="http://"/>
+    <link rel="hub" href="http://pubsubhubbub.appspot.com/"/>
+    <title type="text">Test</title>
+    <updated>2010-03-22T01:55:53.596Z</updated>
+    <id>test53725745374</id>
+    <generator>test</generator>
+    <entry>
+        <title type="html">Buzz by Zach Copley from Flickr</title>
+        <summary type="text">IMG_1366</summary>
+        <published>2010-03-18T04:29:23.000Z</published>
+        <updated>2010-03-18T05:14:03.325Z</updated>
+        <id>test53725745374entry</id>
+        <link rel="alternate" type="text/html" href="http://buzz.example/117848251937215158042/ZU7b6mHJEmC/IMG-1366"/>
+        <author>
+            <name>Zach Copley</name>
+            <uri>https://mywebsite.net/profiles/zcopley</uri>
+        </author>
+        <content type="html">&lt;div&gt;IMG_1366&lt;/div&gt;</content>
+        <link rel="enclosure" href="http://www.flickr.com/photos/22823034@N00/4442630700" type="image/jpeg" title="IMG_1366"/>
+        <media:content url="http://www.flickr.com/photos/22823034@N00/4442630700" type="image/jpeg" medium="image">
+            <media:title>IMG_1366</media:title>
+            <media:player url="http://farm5.static.flickr.com/4053/4442630700_980b19a1a6_o.jpg" height="1600" width="1200"/>
+        </media:content>
+        <link rel="enclosure" href="http://www.flickr.com/photos/22823034@N00/4442630390" type="image/jpeg" title="IMG_1365"/>
+        <media:content url="http://www.flickr.com/photos/22823034@N00/4442630390" type="image/jpeg" medium="image">
+            <media:title>IMG_1365</media:title>
+            <media:player url="http://farm5.static.flickr.com/4043/4442630390_62da5560ae_o.jpg" height="1200" width="1600"/>
+        </media:content>
+        <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
+        <activity:object>
+            <activity:object-type>http://activitystrea.ms/schema/1.0/photo</activity:object-type>
+            <id>test53725745374entry</id>
+            <title>Buzz by Zach Copley from Flickr</title>
+            <content type="html">&lt;div&gt;IMG_1366&lt;/div&gt;</content>
+            <link rel="enclosure" href="http://www.flickr.com/photos/22823034@N00/4442630700" type="image/jpeg" title="IMG_1366"/>
+            <link rel="enclosure" href="http://www.flickr.com/photos/22823034@N00/4442630390" type="image/jpeg" title="IMG_1365"/>
+        </activity:object>
+        <link rel="replies" type="application/atom+xml" href="http://buzz.example/test53725745374/comments" thr:count="0"/>
+        <thr:total>0</thr:total>
+    </entry>
+</feed>
+EXAMPLE9;
+
+// Sample PuSH entry from a group feed in 0.9.7
+// Old <activity:actor> has been removed from entries in this version.
+// A bug in the order of input processing meant that we were incorrectly
+// reading the feed's <activity:subject> instead of the entry's <author>,
+// causing the entry to get rejected as malformed (groups can't post on
+// their own; we want to see the actual author's info here).
+$_example10 = <<<EXAMPLE10
+<?xml version="1.0" encoding="UTF-8"?>
+<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
+ <generator uri="http://status.net" version="0.9.7alpha1">StatusNet</generator>
+ <id>http://lazarus.local/mublog/api/statusnet/groups/timeline/22.atom</id>
+ <title>grouptest316173 timeline</title>
+ <subtitle>Updates from grouptest316173 on Blaguette!</subtitle>
+ <logo>http://lazarus.local/mublog/theme/default/default-avatar-profile.png</logo>
+ <updated>2011-01-06T22:44:18+00:00</updated>
+<author>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/group</activity:object-type>
+ <uri>http://lazarus.local/mublog/group/22/id</uri>
+ <name>grouptest316173</name>
+ <link rel="alternate" type="text/html" href="http://lazarus.local/mublog/group/22/id"/>
+ <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://lazarus.local/mublog/theme/default/default-avatar-profile.png"/>
+ <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://lazarus.local/mublog/theme/default/default-avatar-stream.png"/>
+ <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://lazarus.local/mublog/theme/default/default-avatar-mini.png"/>
+ <poco:preferredUsername>grouptest316173</poco:preferredUsername>
+ <poco:displayName>grouptest316173</poco:displayName>
+</author>
+<activity:subject>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/group</activity:object-type>
+ <id>http://lazarus.local/mublog/group/22/id</id>
+ <title>grouptest316173</title>
+ <link rel="alternate" type="text/html" href="http://lazarus.local/mublog/group/22/id"/>
+ <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://lazarus.local/mublog/theme/default/default-avatar-profile.png"/>
+ <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://lazarus.local/mublog/theme/default/default-avatar-stream.png"/>
+ <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://lazarus.local/mublog/theme/default/default-avatar-mini.png"/>
+ <poco:preferredUsername>grouptest316173</poco:preferredUsername>
+ <poco:displayName>grouptest316173</poco:displayName>
+</activity:subject>
+ <link href="http://lazarus.local/mublog/group/grouptest316173" rel="alternate" type="text/html"/>
+ <link href="http://lazarus.local/mublog/main/push/hub" rel="hub"/>
+ <link href="http://lazarus.local/mublog/main/salmon/group/22" rel="salmon"/>
+ <link href="http://lazarus.local/mublog/main/salmon/group/22" rel="http://salmon-protocol.org/ns/salmon-replies"/>
+ <link href="http://lazarus.local/mublog/main/salmon/group/22" rel="http://salmon-protocol.org/ns/salmon-mention"/>
+ <link href="http://lazarus.local/mublog/api/statusnet/groups/timeline/22.atom" rel="self" type="application/atom+xml"/>
+ <statusnet:group_info member_count="2"></statusnet:group_info>
+<entry>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
+ <id>http://lazarus.local/mublog/notice/1243</id>
+ <title>Group post from local to !grouptest316173, should go out over push.</title>
+ <content type="html">Group post from local to !&lt;span class=&quot;vcard&quot;&gt;&lt;a href=&quot;http://lazarus.local/mublog/group/22/id&quot; class=&quot;url&quot;&gt;&lt;span class=&quot;fn nickname&quot;&gt;grouptest316173&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;, should go out over push.</content>
+ <link rel="alternate" type="text/html" href="http://lazarus.local/mublog/notice/1243"/>
+ <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
+ <published>2011-01-06T22:44:18+00:00</published>
+ <updated>2011-01-06T22:44:18+00:00</updated>
+ <author>
+  <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
+  <uri>http://lazarus.local/mublog/user/557</uri>
+  <name>Pubtest316173 Smith</name>
+  <link rel="alternate" type="text/html" href="http://lazarus.local/mublog/pubtest316173"/>
+  <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://lazarus.local/mublog/theme/default/default-avatar-profile.png"/>
+  <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://lazarus.local/mublog/theme/default/default-avatar-stream.png"/>
+  <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://lazarus.local/mublog/theme/default/default-avatar-mini.png"/>
+  <poco:preferredUsername>pubtest316173</poco:preferredUsername>
+  <poco:displayName>Pubtest316173 Smith</poco:displayName>
+  <poco:note>Stub account for OStatus tests.</poco:note>
+  <poco:urls>
+   <poco:type>homepage</poco:type>
+   <poco:value>http://example.org/pubtest316173</poco:value>
+   <poco:primary>true</poco:primary>
+  </poco:urls>
+ </author>
+ <link rel="ostatus:conversation" href="http://lazarus.local/mublog/conversation/1131"/>
+ <link rel="mentioned" href="http://lazarus.local/mublog/group/22/id"/>
+ <category term="grouptest316173"></category>
+ <source>
+  <id>http://lazarus.local/mublog/api/statuses/user_timeline/557.atom</id>
+  <title>Pubtest316173 Smith</title>
+  <link rel="alternate" type="text/html" href="http://lazarus.local/mublog/pubtest316173"/>
+  <link rel="self" type="application/atom+xml" href="http://lazarus.local/mublog/api/statuses/user_timeline/557.atom"/>
+  <link rel="license" href="http://creativecommons.org/licenses/by/3.0/"/>
+  <icon>http://lazarus.local/mublog/theme/default/default-avatar-profile.png</icon>
+  <updated>2011-01-06T22:44:18+00:00</updated>
+ </source>
+ <link rel="self" type="application/atom+xml" href="http://lazarus.local/mublog/api/statuses/show/1243.atom"/>
+ <link rel="edit" type="application/atom+xml" href="http://lazarus.local/mublog/api/statuses/show/1243.atom"/>
+ <statusnet:notice_info local_id="1243" source="api"></statusnet:notice_info>
+</entry>
+</feed>
+EXAMPLE10;
+
+$_example11 = <<<EXAMPLE11
+<?xml version="1.0" encoding="UTF-8"?>
+<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
+ <generator uri="http://status.net" version="0.9.7">StatusNet</generator>
+ <id>http://freelish.us/api/statuses/user_timeline/1.atom</id>
+ <title>demon timeline</title>
+ <subtitle>Updates from demon on freelish.us!</subtitle>
+ <logo>http://avatar.status.net/f/freelishus/1-96-20110331163048.jpeg</logo>
+ <updated>2011-05-30T09:36:03-04:00</updated>
+<author>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
+ <uri>http://freelishus.status.net/user/1</uri>
+ <name>demon</name>
+ <link rel="alternate" type="text/html" href="http://freelish.us/demon"/>
+ <link rel="avatar" type="image/jpeg" media:width="192" media:height="192" href="http://avatar.status.net/f/freelishus/1-192-20110331163048.jpeg"/>
+ <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="http://avatar.status.net/f/freelishus/1-96-20110331163048.jpeg"/>
+ <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="http://avatar.status.net/f/freelishus/1-48-20110331163048.jpeg"/>
+ <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="http://avatar.status.net/f/freelishus/1-24-20110331163049.jpeg"/>
+ <georss:point>45.50884 -73.58781</georss:point>
+ <poco:preferredUsername>demon</poco:preferredUsername>
+ <poco:displayName>Evan Prodromou</poco:displayName>
+ <poco:note>Montreal hacker and entrepreneur.</poco:note>
+ <poco:address>
+  <poco:formatted>Montreal, Quebec</poco:formatted>
+
+</poco:address>
+ <poco:urls>
+  <poco:type>homepage</poco:type>
+  <poco:value>http://evan.status.net/</poco:value>
+  <poco:primary>true</poco:primary>
+</poco:urls>
+ <statusnet:profile_info local_id="1"></statusnet:profile_info>
+</author>
+<!--Deprecation warning: activity:subject is present only for backward compatibility. It will be removed in the next version of StatusNet.-->
+<activity:subject>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
+ <id>http://freelishus.status.net/user/1</id>
+ <title>Evan Prodromou</title>
+ <link rel="alternate" type="text/html" href="http://freelish.us/demon"/>
+ <link rel="avatar" type="image/jpeg" media:width="192" media:height="192" href="http://avatar.status.net/f/freelishus/1-192-20110331163048.jpeg"/>
+ <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="http://avatar.status.net/f/freelishus/1-96-20110331163048.jpeg"/>
+ <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="http://avatar.status.net/f/freelishus/1-48-20110331163048.jpeg"/>
+ <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="http://avatar.status.net/f/freelishus/1-24-20110331163049.jpeg"/>
+ <georss:point>45.50884 -73.58781</georss:point>
+ <poco:preferredUsername>demon</poco:preferredUsername>
+ <poco:displayName>Evan Prodromou</poco:displayName>
+ <poco:note>Montreal hacker and entrepreneur.</poco:note>
+ <poco:address>
+  <poco:formatted>Montreal, Quebec</poco:formatted>
+
+</poco:address>
+ <poco:urls>
+  <poco:type>homepage</poco:type>
+  <poco:value>http://evan.status.net/</poco:value>
+  <poco:primary>true</poco:primary>
+</poco:urls>
+ <statusnet:profile_info local_id="1"></statusnet:profile_info>
+</activity:subject>
+ <link href="http://freelish.us/demon" rel="alternate" type="text/html"/>
+ <link href="http://freelish.us/main/sup#1" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
+ <link href="http://freelish.us/api/statuses/user_timeline/1.atom?max_id=13210408" rel="next" type="application/atom+xml"/>
+ <link href="http://freelish.us/main/push/hub" rel="hub"/>
+ <link href="http://freelish.us/main/salmon/user/1" rel="salmon"/>
+ <link href="http://freelish.us/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-replies"/>
+ <link href="http://freelish.us/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-mention"/>
+ <link href="http://freelish.us/api/statuses/user_timeline/1.atom" rel="self" type="application/atom+xml"/>
+
+<entry>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/bookmark</activity:object-type>
+ <id>http://freelish.us/bookmark/9e930c3e-7ed9-47de-aba5-df6c60cec542</id>
+ <title>Why you should build an open-source startup | Teambox Blog</title>
+ <link rel="alternate" type="text/html" href="http://freelish.us/bookmark/9e930c3e-7ed9-47de-aba5-df6c60cec542"/>
+ <link rel="related" href="http://blog.teambox.com/open-source-companies"/>
+ <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
+ <published>2011-05-26T20:36:25+00:00</published>
+ <updated>2011-05-26T20:36:25+00:00</updated>
+ <link rel="ostatus:conversation" href="http://freelish.us/conversation/13835232"/>
+ <category term="opensource"></category>
+ <category term="startup"></category>
+ <link rel="self" type="application/atom+xml" href="http://freelish.us/api/statuses/show/13836862.atom"/>
+ <link rel="edit" type="application/atom+xml" href="http://freelish.us/api/statuses/show/13836862.atom"/>
+ <statusnet:notice_info local_id="13836862" source="web" favorite="false" repeated="false"></statusnet:notice_info>
+
+</entry>
+</feed>
+EXAMPLE11;
diff --git a/tests/Core/CallableLeftCurryTest.php b/tests/Core/CallableLeftCurryTest.php
new file mode 100644 (file)
index 0000000..b3eeea3
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+
+use PHPUnit\Framework\TestCase;
+
+require_once INSTALLDIR . "/lib/callableleftcurry.php";
+
+final class CallableLeftCurryTest extends TestCase
+{
+    /**
+     * @dataProvider provider
+     * @param $callback_test
+     * @param $curry_params
+     * @param $call_params
+     * @param $expected
+     */
+    public function testCallableLeftCurry($callback_test, $curry_params, $call_params, $expected)
+    {
+        $params = array_merge([$callback_test], $curry_params);
+        $curried = call_user_func_array('callableLeftCurry', $params);
+        $result = call_user_func_array($curried, $call_params);
+        $this->assertEquals($expected, $result);
+    }
+
+    static public function provider()
+    {
+        $obj = new CurryTestHelperObj('oldval');
+        return [[['Tests\Unit\CallableLeftCurryTest', 'callback_test'],
+            ['curried'],
+            ['called'],
+            'called|curried'],
+            [['Tests\Unit\CallableLeftCurryTest', 'callback_test'],
+                ['curried1', 'curried2'],
+                ['called1', 'called2'],
+                'called1|called2|curried1|curried2'],
+            [['Tests\Unit\CallableLeftCurryTest', 'callback_testObj'],
+                [$obj],
+                ['newval1'],
+                'oldval|newval1'],
+            // Confirm object identity is retained...
+            [['Tests\Unit\CallableLeftCurryTest', 'callback_testObj'],
+                [$obj],
+                ['newval2'],
+                'newval1|newval2']];
+    }
+
+    static function callback_test()
+    {
+        $args = func_get_args();
+        return implode("|", $args);
+    }
+
+    static function callback_testObj($val, $obj)
+    {
+        $old = $obj->val;
+        $obj->val = $val;
+        return "$old|$val";
+    }
+}
+
+class CurryTestHelperObj
+{
+    public $val = '';
+
+    function __construct($val)
+    {
+        $this->val = $val;
+    }
+}
diff --git a/tests/Core/CommandInterperterTest.php b/tests/Core/CommandInterperterTest.php
new file mode 100644 (file)
index 0000000..d8f6149
--- /dev/null
@@ -0,0 +1,194 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use CommandInterpreter;
+use PHPUnit\Framework\TestCase;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+final class CommandInterpreterTest extends TestCase
+{
+
+    /**
+     * @dataProvider commandInterpreterCases
+     * @param $input
+     * @param $expectedType
+     * @param string $comment
+     */
+    public function testCommandInterpreter($input, $expectedType, $comment = '')
+    {
+        $inter = new CommandInterpreter();
+
+        $cmd = $inter->handle_command(null, $input);
+
+        $type = $cmd ? get_class($cmd) : null;
+        $this->assertEquals(strtolower($expectedType), strtolower($type), $comment);
+    }
+
+    static public function commandInterpreterCases()
+    {
+        $sets = array(
+            array('help', 'HelpCommand'),
+            array('help me bro', null, 'help does not accept multiple params'),
+            array('HeLP', 'HelpCommand', 'case check'),
+            array('HeLP Me BRO!', null, 'case & non-params check'),
+
+            array('login', 'LoginCommand'),
+            array('login to savings!', null, 'login does not accept params'),
+
+            array('lose', null, 'lose must have at least 1 parameter'),
+            array('lose foobar', 'LoseCommand', 'lose requires 1 parameter'),
+            array('lose        foobar', 'LoseCommand', 'check for space norm'),
+            array('lose more weight', null, 'lose does not accept multiple params'),
+
+            array('subscribers', 'SubscribersCommand'),
+            array('subscribers foo', null, 'subscribers does not take params'),
+
+            array('subscriptions', 'SubscriptionsCommand'),
+            array('subscriptions foo', null, 'subscriptions does not take params'),
+
+            array('groups', 'GroupsCommand'),
+            array('groups foo', null, 'groups does not take params'),
+
+            array('off', 'OffCommand', 'off accepts 0 or 1 params'),
+            array('off foo', 'OffCommand', 'off accepts 0 or 1 params'),
+            array('off foo bar', null, 'off accepts 0 or 1 params'),
+
+            array('stop', 'OffCommand', 'stop accepts 0 params'),
+            array('stop foo', null, 'stop accepts 0 params'),
+
+            array('quit', 'OffCommand', 'quit accepts 0 params'),
+            array('quit foo', null, 'quit accepts 0 params'),
+
+            array('on', 'OnCommand', 'on accepts 0 or 1 params'),
+            array('on foo', 'OnCommand', 'on accepts 0 or 1 params'),
+            array('on foo bar', null, 'on accepts 0 or 1 params'),
+
+            array('join', null),
+            array('join foo', 'JoinCommand'),
+            array('join foo bar', null),
+
+            array('drop', null),
+            array('drop foo', 'DropCommand'),
+            array('drop foo bar', null),
+
+            array('follow', null),
+            array('follow foo', 'SubCommand'),
+            array('follow foo bar', null),
+
+            array('sub', null),
+            array('sub foo', 'SubCommand'),
+            array('sub foo bar', null),
+
+            array('leave', null),
+            array('leave foo', 'UnsubCommand'),
+            array('leave foo bar', null),
+
+            array('unsub', null),
+            array('unsub foo', 'UnsubCommand'),
+            array('unsub foo bar', null),
+
+            array('leave', null),
+            array('leave foo', 'UnsubCommand'),
+            array('leave foo bar', null),
+
+            array('d', null),
+            array('d foo', null),
+            array('d foo bar', 'MessageCommand'),
+
+            array('dm', null),
+            array('dm foo', null),
+            array('dm foo bar', 'MessageCommand'),
+
+            array('r', null),
+            array('r foo', null),
+            array('r foo bar', 'ReplyCommand'),
+
+            array('reply', null),
+            array('reply foo', null),
+            array('reply foo bar', 'ReplyCommand'),
+
+            array('repeat', null),
+            array('repeat foo', 'RepeatCommand'),
+            array('repeat foo bar', null),
+
+            array('rp', null),
+            array('rp foo', 'RepeatCommand'),
+            array('rp foo bar', null),
+
+            array('rt', null),
+            array('rt foo', 'RepeatCommand'),
+            array('rt foo bar', null),
+
+            array('rd', null),
+            array('rd foo', 'RepeatCommand'),
+            array('rd foo bar', null),
+
+            array('whois', null),
+            array('whois foo', 'WhoisCommand'),
+            array('whois foo bar', null),
+
+            /*            array('fav', null),
+                        array('fav foo', 'FavCommand'),
+                        array('fav foo bar', null),*/
+
+            array('nudge', null),
+            array('nudge foo', 'NudgeCommand'),
+            array('nudge foo bar', null),
+
+            array('stats', 'StatsCommand'),
+            array('stats foo', null),
+
+            array('invite', null),
+            array('invite foo', 'InviteCommand'),
+            array('invite foo bar', null),
+
+            array('track', null),
+            array('track foo', 'SearchSubTrackCommand'),
+            array('track off', 'SearchSubTrackOffCommand'),
+            array('track foo bar', null),
+            array('track off foo', null),
+
+            array('untrack', null),
+            array('untrack foo', 'SearchSubUntrackCommand'),
+            array('untrack all', 'SearchSubTrackOffCommand'),
+            array('untrack foo bar', null),
+            array('untrack all foo', null),
+
+            array('tracking', 'SearchSubTrackingCommand'),
+            array('tracking foo', null),
+
+            array('tracks', 'SearchSubTrackingCommand'),
+            array('tracks foo', null),
+
+        );
+        return $sets;
+    }
+
+}
+
diff --git a/tests/Core/HashTagDetectionTests.php b/tests/Core/HashTagDetectionTests.php
new file mode 100644 (file)
index 0000000..00b3125
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use PHPUnit\Framework\TestCase;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+final class HashTagDetectionTests extends TestCase
+{
+    /**
+     * @dataProvider provider
+     * @param $content
+     * @param $expected
+     */
+    public function testProduction($content, $expected)
+    {
+        $rendered = common_render_text($content);
+        $this->assertEquals($expected, $rendered);
+    }
+
+    static public function provider()
+    {
+        return array(
+            array('hello',
+                'hello'),
+            array('#hello people',
+                '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span> people'),
+            array('"#hello" people',
+                '&quot;#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>&quot; people'),
+            array('say "#hello" people',
+                'say &quot;#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>&quot; people'),
+            array('say (#hello) people',
+                'say (#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>) people'),
+            array('say [#hello] people',
+                'say [#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>] people'),
+            array('say {#hello} people',
+                'say {#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>} people'),
+            array('say \'#hello\' people',
+                'say \'#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>\' people'),
+
+            // Unicode legit letters
+            array('#éclair yummy',
+                '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('éclair'))) . '" rel="tag">éclair</a></span> yummy'),
+            array('#维基百科 zh.wikipedia!',
+                '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('维基百科'))) . '" rel="tag">维基百科</a></span> zh.wikipedia!'),
+            array('#Россия russia',
+                '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('Россия'))) . '" rel="tag">Россия</a></span> russia'),
+
+            // Unicode punctuators -- the ideographic "," separates the tag, just as "," does
+            array('#维基百科,zh.wikipedia!',
+                '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('维基百科'))) . '" rel="tag">维基百科</a></span>,zh.wikipedia!'),
+            array('#维基百科,zh.wikipedia!',
+                '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('维基百科'))) . '" rel="tag">维基百科</a></span>,zh.wikipedia!'),
+
+        );
+    }
+}
+
diff --git a/tests/Core/LocationTest.php b/tests/Core/LocationTest.php
new file mode 100644 (file)
index 0000000..747a470
--- /dev/null
@@ -0,0 +1,124 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use GeonamesPlugin;
+use Location;
+use PHPUnit\Framework\TestCase;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+// Make sure this is loaded
+// XXX: how to test other plugins...?
+
+addPlugin('Geonames');
+
+final class LocationTest extends TestCase
+{
+
+    /**
+     * @dataProvider locationNames
+     * @param $name
+     * @param $language
+     * @param $location
+     */
+
+    public function testLocationFromName($name, $language, $location)
+    {
+        $result = Location::fromName($name, $language);
+        $this->assertEquals($result, $location);
+    }
+
+    static public function locationNames()
+    {
+        return array(array('Montreal', 'en', null),
+            array('San Francisco, CA', 'en', null),
+            array('Paris, France', 'en', null),
+            array('Paris, Texas', 'en', null));
+    }
+
+    /**
+     * @dataProvider locationIds
+     * @param $id
+     * @param $ns
+     * @param $language
+     * @param $location
+     */
+
+    public function testLocationFromId($id, $ns, $language, $location)
+    {
+        $result = Location::fromId($id, $ns, $language);
+        $this->assertEquals($result, $location);
+    }
+
+    static public function locationIds()
+    {
+        return array(array(6077243, GeonamesPlugin::LOCATION_NS, 'en', null),
+            array(5391959, GeonamesPlugin::LOCATION_NS, 'en', null));
+    }
+
+    /**
+     * @dataProvider locationLatLons
+     * @param $lat
+     * @param $lon
+     * @param $language
+     * @param $location
+     */
+
+    public function testLocationFromLatLon($lat, $lon, $language, $location)
+    {
+        $result = Location::fromLatLon($lat, $lon, $language);
+        $this->assertEquals($location, $result->location_id);
+    }
+
+    static public function locationLatLons()
+    {
+        return array(array(37.77493, -122.41942, 'en', null),
+            array(45.509, -73.588, 'en', null));
+    }
+
+    /**
+     * @dataProvider nameOfLocation
+     * @param $location
+     * @param $language
+     * @param $name
+     */
+
+    public function testLocationGetName($location, $language, $name)
+    {
+        $result = empty($location) ? null : $location->getName($language);
+        $this->assertEquals($name, $result);
+    }
+
+    static public function nameOfLocation()
+    {
+        $loc = Location::fromName('Montreal', 'en');
+        return array(array($loc, 'en', null), //'Montreal'),
+            array($loc, 'fr', null));//'Montréal'));
+    }
+}
+
diff --git a/tests/Core/NicknameTest.php b/tests/Core/NicknameTest.php
new file mode 100644 (file)
index 0000000..e315033
--- /dev/null
@@ -0,0 +1,156 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use Nickname;
+use NicknameBlacklistedException;
+use NicknameEmptyException;
+use NicknameException;
+use NicknameInvalidException;
+use NicknamePathCollisionException;
+use NicknameTakenException;
+use NicknameTooLongException;
+use PHPUnit\Framework\TestCase;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+/**
+ * Test cases for nickname validity and normalization.
+ */
+final class NicknameTest extends TestCase
+{
+    /**
+     * Basic test using Nickname::normalize()
+     *
+     * @dataProvider provider
+     * @param $input
+     * @param $expected
+     * @param null $expectedException
+     */
+    public function testBasic($input, $expected, $expectedException = null)
+    {
+        $exception = null;
+        $normalized = false;
+        try {
+            $normalized = Nickname::normalize($input);
+        } catch (NicknameException $e) {
+            $exception = $e;
+        }
+
+        if ($expected === false) {
+            if ($expectedException) {
+                if ($exception) {
+                    $stuff = get_class($exception) . ': ' . $exception->getMessage();
+                } else {
+                    $stuff = var_export($exception, true);
+                }
+                $this->assertTrue($exception && $exception instanceof $expectedException,
+                    "invalid input '$input' expected to fail with $expectedException, " .
+                    "got $stuff");
+            } else {
+                $this->assertTrue($normalized == false,
+                    "invalid input '$input' expected to fail");
+            }
+        } else {
+            $msg = "normalized input nickname '$input' expected to normalize to '$expected', got ";
+            if ($exception) {
+                $msg .= get_class($exception) . ': ' . $exception->getMessage();
+            } else {
+                $msg .= "'$normalized'";
+            }
+            $this->assertEquals($expected, $normalized, $msg);
+        }
+    }
+
+    /**
+     * Test on the regex matching used in common_find_mentions
+     * (testing on the full notice rendering is difficult as it needs
+     * to be able to pull from global state)
+     *
+     * @dataProvider provider
+     * @param $input
+     * @param $expected
+     * @param null $expectedException
+     * @throws NicknameBlacklistedException
+     * @throws NicknameEmptyException
+     * @throws NicknameException
+     * @throws NicknameInvalidException
+     * @throws NicknamePathCollisionException
+     * @throws NicknameTakenException
+     * @throws NicknameTooLongException
+     */
+    public function testAtReply($input, $expected, $expectedException = null)
+    {
+        if ($expected == false) {
+            // nothing to do
+        } else {
+            $text = "@{$input} awesome! :)";
+            $matches = common_find_mentions_raw($text);
+            $this->assertEquals(1, count($matches));
+            $this->assertEquals($expected, Nickname::normalize($matches[0][0]));
+        }
+    }
+
+    static public function provider()
+    {
+        return array(
+            array('evan', 'evan'),
+
+            // Case and underscore variants
+            array('Evan', 'evan'),
+            array('EVAN', 'evan'),
+            array('ev_an', 'evan'),
+            array('E__V_an', 'evan'),
+            array('evan1', 'evan1'),
+            array('evan_1', 'evan1'),
+            array('0x20', '0x20'),
+            array('1234', '1234'), // should this be allowed though? :)
+            array('12__34', '1234'),
+
+            // Some (currently) invalid chars...
+            array('^#@&^#@', false, 'NicknameInvalidException'), // all invalid :D
+            array('ev.an', false, 'NicknameInvalidException'),
+            array('ev/an', false, 'NicknameInvalidException'),
+            array('ev an', false, 'NicknameInvalidException'),
+            array('ev-an', false, 'NicknameInvalidException'),
+
+            // Non-ASCII letters; currently not allowed, in future
+            // we'll add them at least with conversion to ASCII.
+            // Not much use until we have storage of display names,
+            // though.
+            array('évan', false, 'NicknameInvalidException'), // so far...
+            array('Évan', false, 'NicknameInvalidException'), // so far...
+
+            // Length checks
+            array('', false, 'NicknameEmptyException'),
+            array('___', false, 'NicknameEmptyException'),
+            array('eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'), // 64 chars
+            array('eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_', false, 'NicknameTooLongException'), // the _ is too long...
+            array('eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', false, 'NicknameTooLongException'), // 65 chars -- too long
+        );
+    }
+}
diff --git a/tests/Core/TagURITest.php b/tests/Core/TagURITest.php
new file mode 100644 (file)
index 0000000..07343a3
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use PHPUnit\Framework\TestCase;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+$config['site']['server'] = 'example.net';
+$config['site']['path'] = '/apps/statusnet';
+
+final class TagURITest extends TestCase
+{
+    /**
+     * @dataProvider provider
+     * @param $format
+     * @param $args
+     * @param $uri
+     */
+    public function testProduction($format, $args, $uri)
+    {
+        $minted = call_user_func_array(array('TagURI', 'mint'),
+            array_merge(array($format), $args));
+
+        $this->assertEquals($uri, $minted);
+    }
+
+    static public function provider()
+    {
+        return array(array('favorite:%d:%d',
+            array(1, 3),
+            'tag:example.net,' . date('Y-m-d') . ':apps:statusnet:favorite:1:3'));
+    }
+}
+
diff --git a/tests/Core/URLDetectionTest.php b/tests/Core/URLDetectionTest.php
new file mode 100644 (file)
index 0000000..e4adce5
--- /dev/null
@@ -0,0 +1,377 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use PHPUnit\Framework\TestCase;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+final class URLDetectionTest extends TestCase
+{
+    /**
+     * @dataProvider provider
+     * @param $content
+     * @param $expected
+     */
+    public function testProduction($content, $expected)
+    {
+        $rendered = common_render_text($content);
+        // hack!
+        $rendered = preg_replace('/id="attachment-\d+"/', 'id="attachment-XXX"', $rendered);
+        $this->assertEquals($expected, $rendered);
+    }
+
+    /**
+     * @dataProvider linkifyProvider
+     * @param $content
+     * @param $expected
+     * @param $config
+     */
+    public function testLinkifyProduction($content, $expected, $config)
+    {
+        $rendered = common_render_text($content);
+        // hack!
+        $rendered = preg_replace('/id="attachment-\d+"/', 'id="attachment-XXX"', $rendered);
+        if (common_config('linkify', $config)) {
+            $this->assertEquals($expected, $rendered);
+        } else {
+            $content = common_remove_unicode_formatting(nl2br(htmlspecialchars($content)));
+            $this->assertEquals($content, $rendered);
+        }
+    }
+
+    static public function provider()
+    {
+        return array(
+            array('not a link :: no way',
+                'not a link :: no way'),
+            array('link http://www.somesite.com/xyz/35637563@N00/52803365/ link',
+                'link <a href="http://www.somesite.com/xyz/35637563@N00/52803365/" title="http://www.somesite.com/xyz/35637563@N00/52803365/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://www.somesite.com/xyz/35637563@N00/52803365/</a> link'),
+            array('http://127.0.0.1',
+                '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://127.0.0.1</a>'),
+            array('http://[::1]:99/test.php',
+                '<a href="http://[::1]:99/test.php" title="http://[::1]:99/test.php" rel="nofollow external">http://[::1]:99/test.php</a>'),
+            array('http://::1/test.php',
+                '<a href="http://::1/test.php" title="http://::1/test.php" rel="nofollow external">http://::1/test.php</a>'),
+            array('http://::1',
+                '<a href="http://::1/" title="http://::1/" rel="nofollow external">http://::1</a>'),
+            array('http://127.0.0.1',
+                '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://127.0.0.1</a>'),
+            array('http://example.com',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>'),
+            array('http://example.com.',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>.'),
+            array('/var/lib/example.so',
+                '/var/lib/example.so'),
+            array('example',
+                'example'),
+            array('mailto:user@example.com',
+                '<a href="mailto:user@example.com" title="mailto:user@example.com" rel="nofollow external">mailto:user@example.com</a>'),
+            array('mailto:user@example.com?subject=test',
+                '<a href="mailto:user@example.com?subject=test" title="mailto:user@example.com?subject=test" rel="nofollow external">mailto:user@example.com?subject=test</a>'),
+            array('xmpp:user@example.com',
+                '<a href="xmpp:user@example.com" title="xmpp:user@example.com" rel="nofollow external">xmpp:user@example.com</a>'),
+            array('#example',
+                '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('example'))) . '" rel="tag">example</a></span>'),
+            array('#example.com',
+                '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('example.com'))) . '" rel="tag">example.com</a></span>'),
+            array('#.net',
+                '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('.net'))) . '" rel="tag">.net</a></span>'),
+            array('http://example',
+                '<a href="http://example/" title="http://example/" rel="nofollow external">http://example</a>'),
+            array('http://3xampl3',
+                '<a href="http://3xampl3/" title="http://3xampl3/" rel="nofollow external">http://3xampl3</a>'),
+            array('http://example/',
+                '<a href="http://example/" title="http://example/" rel="nofollow external">http://example/</a>'),
+            array('http://example/path',
+                '<a href="http://example/path" title="http://example/path" rel="nofollow external">http://example/path</a>'),
+            array('http://example.com',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>'),
+            array('https://example.com',
+                '<a href="https://example.com/" title="https://example.com/" rel="nofollow external">https://example.com</a>'),
+            array('ftp://example.com',
+                '<a href="ftp://example.com/" title="ftp://example.com/" rel="nofollow external">ftp://example.com</a>'),
+            array('ftps://example.com',
+                '<a href="ftps://example.com/" title="ftps://example.com/" rel="nofollow external">ftps://example.com</a>'),
+            array('http://user@example.com',
+                '<a href="http://@example.com/" title="http://@example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://user@example.com</a>'),
+            array('http://user:pass@example.com',
+                '<a href="http://@example.com/" title="http://@example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://user:pass@example.com</a>'),
+            array('http://example.com:8080',
+                '<a href="http://example.com:8080/" title="http://example.com:8080/" rel="nofollow external">http://example.com:8080</a>'),
+            array('http://example.com:8080/test.php',
+                '<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="nofollow external">http://example.com:8080/test.php</a>'),
+            array('http://www.example.com',
+                '<a href="http://www.example.com/" title="http://www.example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://www.example.com</a>'),
+            array('http://example.com/',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/</a>'),
+            array('http://example.com/path',
+                '<a href="http://example.com/path" title="http://example.com/path" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path</a>'),
+            array('http://example.com/path.html',
+                '<a href="http://example.com/path.html" title="http://example.com/path.html" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path.html</a>'),
+            array('http://example.com/path.html#fragment',
+                '<a href="http://example.com/path.html#fragment" title="http://example.com/path.html#fragment" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path.html#fragment</a>'),
+            array('http://example.com/path.php?foo=bar&bar=foo',
+                '<a href="http://example.com/path.php?foo=bar&amp;bar=foo" title="http://example.com/path.php?foo=bar&amp;bar=foo" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path.php?foo=bar&amp;bar=foo</a>'),
+            array('http://example.com.',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>.'),
+            array('http://müllärör.de',
+                '<a href="http://m&#xFC;ll&#xE4;r&#xF6;r.de/" title="http://m&#xFC;ll&#xE4;r&#xF6;r.de/" rel="nofollow external">http://müllärör.de</a>'),
+            array('http://ﺱﺲﺷ.com',
+                '<a href="http://&#xFEB1;&#xFEB2;&#xFEB7;.com/" title="http://&#xFEB1;&#xFEB2;&#xFEB7;.com/" rel="nofollow external">http://ﺱﺲﺷ.com</a>'),
+            array('http://сделаткартинки.com',
+                '<a href="http://&#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x438;.com/" title="http://&#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x438;.com/" rel="nofollow external">http://сделаткартинки.com</a>'),
+            array('http://tūdaliņ.lv',
+                '<a href="http://t&#x16B;dali&#x146;.lv/" title="http://t&#x16B;dali&#x146;.lv/" rel="nofollow external">http://tūdaliņ.lv</a>'),
+            array('http://brændendekærlighed.com',
+                '<a href="http://br&#xE6;ndendek&#xE6;rlighed.com/" title="http://br&#xE6;ndendek&#xE6;rlighed.com/" rel="nofollow external">http://brændendekærlighed.com</a>'),
+            array('http://あーるいん.com',
+                '<a href="http://&#x3042;&#x30FC;&#x308B;&#x3044;&#x3093;.com/" title="http://&#x3042;&#x30FC;&#x308B;&#x3044;&#x3093;.com/" rel="nofollow external">http://あーるいん.com</a>'),
+            array('http://예비교사.com',
+                '<a href="http://&#xC608;&#xBE44;&#xAD50;&#xC0AC;.com/" title="http://&#xC608;&#xBE44;&#xAD50;&#xC0AC;.com/" rel="nofollow external">http://예비교사.com</a>'),
+            array('http://example.com.',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>.'),
+            array('http://example.com?',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>?'),
+            array('http://example.com!',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>!'),
+            array('http://example.com,',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>,'),
+            array('http://example.com;',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>;'),
+            array('http://example.com:',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>:'),
+            array('\'http://example.com\'',
+                '\'<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>\''),
+            array('"http://example.com"',
+                '&quot;<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>&quot;'),
+            array('"http://example.com/"',
+                '&quot;<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/</a>&quot;'),
+            array('http://example.com',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>'),
+            array('(http://example.com)',
+                '(<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>)'),
+            array('[http://example.com]',
+                '[<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>]'),
+            array('<http://example.com>',
+                '&lt;<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>&gt;'),
+            array('http://example.com/path/(foo)/bar',
+                '<a href="http://example.com/path/" title="http://example.com/path/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/</a>(foo)/bar'),
+            array('http://example.com/path/[foo]/bar',
+                '<a href="http://example.com/path/" title="http://example.com/path/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/</a>[foo]/bar'),
+            array('http://example.com/path/foo/(bar)',
+                '<a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>(bar)'),
+            //Not a valid url - urls cannot contain unencoded square brackets
+            array('http://example.com/path/foo/[bar]',
+                '<a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>[bar]'),
+            array('Hey, check out my cool site http://example.com okay?',
+                'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a> okay?'),
+            array('What about parens (e.g. http://example.com/path/foo/(bar))?',
+                'What about parens (e.g. <a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>(bar))?'),
+            array('What about parens (e.g. http://example.com/path/foo/(bar)?',
+                'What about parens (e.g. <a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>(bar)?'),
+            array('What about parens (e.g. http://example.com/path/foo/(bar).)?',
+                'What about parens (e.g. <a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>(bar).)?'),
+            //Not a valid url - urls cannot contain unencoded commas
+            array('What about parens (e.g. http://example.com/path/(foo,bar)?',
+                'What about parens (e.g. <a href="http://example.com/path/" title="http://example.com/path/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/</a>(foo,bar)?'),
+            array('Unbalanced too (e.g. http://example.com/path/((((foo)/bar)?',
+                'Unbalanced too (e.g. <a href="http://example.com/path/" title="http://example.com/path/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/</a>((((foo)/bar)?'),
+            array('Unbalanced too (e.g. http://example.com/path/(foo))))/bar)?',
+                'Unbalanced too (e.g. <a href="http://example.com/path/" title="http://example.com/path/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/</a>(foo))))/bar)?'),
+            array('Unbalanced too (e.g. http://example.com/path/foo/((((bar)?',
+                'Unbalanced too (e.g. <a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>((((bar)?'),
+            array('Unbalanced too (e.g. http://example.com/path/foo/(bar))))?',
+                'Unbalanced too (e.g. <a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>(bar))))?'),
+            array('file.ext',
+                'file.ext'),
+            array('file.html',
+                'file.html'),
+            array('file.php',
+                'file.php'),
+
+            // scheme-less HTTP URLs with @ in the path: http://status.net/open-source/issues/2248
+            array('http://flickr.com/photos/34807140@N05/3838905434',
+                '<a href="http://www.flickr.com/photos/34807140@N05/3838905434" title="http://www.flickr.com/photos/34807140@N05/3838905434" rel="nofollow external noreferrer" class="attachment thumbnail" id="attachment-XXX">http://flickr.com/photos/34807140@N05/3838905434</a>'),
+        );
+    }
+
+    static public function linkifyProvider()
+    {
+        return array(
+            //bare ip addresses are no longer supported
+            array('127.0.0.1',
+                '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external">127.0.0.1</a>',
+                'bare_ipv4'),
+            array('127.0.0.1:99',
+                '<a href="http://127.0.0.1:99/" title="http://127.0.0.1:99/" rel="nofollow external">127.0.0.1:99</a>',
+                'bare_ipv4'),
+            array('127.0.0.1/Name:test.php',
+                '<a href="http://127.0.0.1/Name:test.php" title="http://127.0.0.1/Name:test.php" rel="nofollow external">127.0.0.1/Name:test.php</a>',
+                'bare_ipv4'),
+            array('127.0.0.1/~test',
+                '<a href="http://127.0.0.1/~test" title="http://127.0.0.1/~test" rel="nofollow external">127.0.0.1/~test</a>',
+                'bare_ipv4'),
+            array('127.0.0.1/+test',
+                '<a href="http://127.0.0.1/+test" title="http://127.0.0.1/+test" rel="nofollow external">127.0.0.1/+test</a>',
+                'bare_ipv4'),
+            array('127.0.0.1/$test',
+                '<a href="http://127.0.0.1/$test" title="http://127.0.0.1/$test" rel="nofollow external">127.0.0.1/$test</a>',
+                'bare_ipv4'),
+            array('127.0.0.1/\'test',
+                '<a href="http://127.0.0.1/\'test" title="http://127.0.0.1/\'test" rel="nofollow external">127.0.0.1/\'test</a>',
+                'bare_ipv4'),
+            array('127.0.0.1/"test',
+                '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external">127.0.0.1/</a>&quot;test',
+                'bare_ipv4'),
+            array('127.0.0.1/test"test',
+                '<a href="http://127.0.0.1/test" title="http://127.0.0.1/test" rel="nofollow external">127.0.0.1/test</a>&quot;test',
+                'bare_ipv4'),
+            array('127.0.0.1/-test',
+                '<a href="http://127.0.0.1/-test" title="http://127.0.0.1/-test" rel="nofollow external">127.0.0.1/-test</a>',
+                'bare_ipv4'),
+            array('127.0.0.1/_test',
+                '<a href="http://127.0.0.1/_test" title="http://127.0.0.1/_test" rel="nofollow external">127.0.0.1/_test</a>',
+                'bare_ipv4'),
+            array('127.0.0.1/!test',
+                '<a href="http://127.0.0.1/!test" title="http://127.0.0.1/!test" rel="nofollow external">127.0.0.1/!test</a>',
+                'bare_ipv4'),
+            array('127.0.0.1/*test',
+                '<a href="http://127.0.0.1/*test" title="http://127.0.0.1/*test" rel="nofollow external">127.0.0.1/*test</a>',
+                'bare_ipv4'),
+            array('127.0.0.1/test%20stuff',
+                '<a href="http://127.0.0.1/test%20stuff" title="http://127.0.0.1/test%20stuff" rel="nofollow external">127.0.0.1/test%20stuff</a>',
+                'bare_ipv4'),
+            array('2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php',
+                '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" rel="nofollow external">2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php</a>',
+                'bare_ipv6'),
+            array('[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php',
+                '<a href="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" title="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" rel="nofollow external">[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php</a>',
+                'bare_ipv6'),
+            array('2001:4978:1b5:0:21d:e0ff:fe66:59ab',
+                '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" rel="nofollow external">2001:4978:1b5:0:21d:e0ff:fe66:59ab</a>',
+                'bare_ipv6'),
+            array('example.com',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>',
+                'bare_domains'),
+            array('flickr.com/photos/34807140@N05/3838905434',
+                '<a href="http://flickr.com/photos/34807140@N05/3838905434" title="http://flickr.com/photos/34807140@N05/3838905434" class="attachment thumbnail" id="attachment-XXX" rel="nofollow external">flickr.com/photos/34807140@N05/3838905434</a>',
+                'bare_domains'),
+            array('What about parens (e.g. example.com/path/foo/(bar))?',
+                'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">example.com/path/foo/(bar)</a>)?',
+                'bare_domains'),
+            array('What about parens (e.g. example.com/path/foo/(bar)?',
+                'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">example.com/path/foo/(bar)</a>?',
+                'bare_domains'),
+            array('What about parens (e.g. example.com/path/foo/(bar).)?',
+                'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">example.com/path/foo/(bar)</a>.?',
+                'bare_domains'),
+            array('What about parens (e.g. example.com/path/(foo,bar)?',
+                'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" title="http://example.com/path/(foo,bar)" rel="nofollow external">example.com/path/(foo,bar)</a>?',
+                'bare_domains'),
+            array('example.com',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>',
+                'bare_domains'),
+            array('example.org',
+                '<a href="http://example.org/" title="http://example.org/" rel="nofollow external">example.org</a>',
+                'bare_domains'),
+            array('example.co.uk',
+                '<a href="http://example.co.uk/" title="http://example.co.uk/" rel="nofollow external">example.co.uk</a>',
+                'bare_domains'),
+            array('www.example.co.uk',
+                '<a href="http://www.example.co.uk/" title="http://www.example.co.uk/" rel="nofollow external">www.example.co.uk</a>',
+                'bare_domains'),
+            array('farm1.images.example.co.uk',
+                '<a href="http://farm1.images.example.co.uk/" title="http://farm1.images.example.co.uk/" rel="nofollow external">farm1.images.example.co.uk</a>',
+                'bare_domains'),
+            array('example.museum',
+                '<a href="http://example.museum/" title="http://example.museum/" rel="nofollow external">example.museum</a>',
+                'bare_domains'),
+            array('example.travel',
+                '<a href="http://example.travel/" title="http://example.travel/" rel="nofollow external">example.travel</a>',
+                'bare_domains'),
+            array('example.com.',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.',
+                'bare_domains'),
+            array('example.com?',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>?',
+                'bare_domains'),
+            array('example.com!',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>!',
+                'bare_domains'),
+            array('example.com,',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>,',
+                'bare_domains'),
+            array('example.com;',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>;',
+                'bare_domains'),
+            array('example.com:',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>:',
+                'bare_domains'),
+            array('\'example.com\'',
+                '\'<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>\'',
+                'bare_domains'),
+            array('"example.com"',
+                '&quot;<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>&quot;',
+                'bare_domains'),
+            array('example.com',
+                '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>',
+                'bare_domains'),
+            array('(example.com)',
+                '(<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>)',
+                'bare_domains'),
+            array('[example.com]',
+                '[<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>]',
+                'bare_domains'),
+            array('<example.com>',
+                '&lt;<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>&gt;',
+                'bare_domains'),
+            array('Hey, check out my cool site example.com okay?',
+                'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a> okay?',
+                'bare_domains'),
+            array('Hey, check out my cool site example.com.I made it.',
+                'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.I made it.',
+                'bare_domains'),
+            array('Hey, check out my cool site example.com.Funny thing...',
+                'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.Funny thing...',
+                'bare_domains'),
+            array('Hey, check out my cool site example.com.You will love it.',
+                'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.You will love it.',
+                'bare_domains'),
+            array('example.com:8080/test.php',
+                '<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="nofollow external">example.com:8080/test.php</a>',
+                'bare_domains'),
+            array('user_name+other@example.com',
+                '<a href="mailto:user_name+other@example.com" title="mailto:user_name+other@example.com" rel="nofollow external">user_name+other@example.com</a>',
+                'bare_domains'),
+            array('user@example.com',
+                '<a href="mailto:user@example.com" title="mailto:user@example.com" rel="nofollow external">user@example.com</a>',
+                'bare_domains'),
+        );
+    }
+}
+
diff --git a/tests/Core/UUIDTest.php b/tests/Core/UUIDTest.php
new file mode 100644 (file)
index 0000000..50e9257
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use PHPUnit\Framework\TestCase;
+use UUID;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+final class UUIDTest extends TestCase
+{
+    public function testGenerate()
+    {
+        $result = UUID::gen();
+        $this->assertRegExp('/^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$/',
+            $result);
+        // Check version number
+        $this->assertEquals(0x4000, hexdec(substr($result, 14, 4)) & 0xF000);
+        $this->assertEquals(0x8000, hexdec(substr($result, 19, 4)) & 0xC000);
+    }
+
+    public function testUnique()
+    {
+        $reps = 100;
+        $ids = array();
+
+        for ($i = 0; $i < $reps; $i++) {
+            $ids[] = UUID::gen();
+        }
+
+        $this->assertEquals(count($ids), count(array_unique($ids)), "UUIDs must be unique");
+    }
+}
+
diff --git a/tests/Core/UserFeedParseTest.php b/tests/Core/UserFeedParseTest.php
new file mode 100644 (file)
index 0000000..f268546
--- /dev/null
@@ -0,0 +1,155 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use Activity;
+use ActivityObject;
+use DOMDocument;
+use PHPUnit\Framework\TestCase;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+final class UserFeedParseTests extends TestCase
+{
+    public function testFeed1()
+    {
+        global $_testfeed1;
+        $dom = new DOMDocument();
+        $dom->loadXML($_testfeed1);
+        $this->assertFalse(empty($dom));
+
+        $entries = $dom->getElementsByTagName('entry');
+
+        $entry1 = $entries->item(0);
+        $this->assertFalse(empty($entry1));
+
+        $feedEl = $dom->getElementsByTagName('feed')->item(0);
+        $this->assertFalse(empty($feedEl));
+
+        // Test actor (from activity:subject)
+
+        $act1 = new Activity($entry1, $feedEl);
+        $this->assertFalse(empty($act1));
+        $this->assertFalse(empty($act1->actor));
+        $this->assertEquals($act1->actor->type, ActivityObject::PERSON);
+        $this->assertEquals($act1->actor->title, 'Zach Copley');
+        $this->assertEquals($act1->actor->id, 'http://localhost/statusnet/user/1');
+        $this->assertEquals($act1->actor->link, 'http://localhost/statusnet/zach');
+
+        $avatars = $act1->actor->avatarLinks;
+
+        $this->assertEquals(
+            $avatars[0]->url,
+            'http://localhost/statusnet/theme/default/default-avatar-profile.png'
+        );
+
+        $this->assertEquals(
+            $avatars[1]->url,
+            'http://localhost/statusnet/theme/default/default-avatar-stream.png'
+        );
+
+        $this->assertEquals(
+            $avatars[2]->url,
+            'http://localhost/statusnet/theme/default/default-avatar-mini.png'
+        );
+
+        $this->assertEquals($act1->actor->displayName, 'Zach Copley');
+
+        $poco = $act1->actor->poco;
+        $this->assertEquals($poco->preferredUsername, 'zach');
+        $this->assertEquals($poco->address->formatted, 'El Cerrito, CA');
+        $this->assertEquals($poco->urls[0]->type, 'homepage');
+        $this->assertEquals($poco->urls[0]->value, 'http://zach.copley.name');
+        $this->assertEquals($poco->urls[0]->primary, true);
+        $this->assertEquals($poco->note, 'Zach Hack Attack');
+
+        // test the post
+
+        //var_export($act1);
+        $this->assertEquals($act1->objects[0]->type, 'http://activitystrea.ms/schema/1.0/note');
+        $this->assertEquals($act1->objects[0]->title, 'And now for something completely insane...');
+
+        $this->assertEquals($act1->objects[0]->content, 'And now for something completely insane...');
+        $this->assertEquals($act1->objects[0]->id, 'http://localhost/statusnet/notice/3');
+
+    }
+
+}
+
+$_testfeed1 = <<<TESTFEED1
+<?xml version="1.0" encoding="UTF-8"?>
+<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0">
+ <id>http://localhost/statusnet/api/statuses/user_timeline/1.atom</id>
+ <title>zach timeline</title>
+ <subtitle>Updates from zach on Zach Dev!</subtitle>
+ <logo>http://localhost/statusnet/theme/default/default-avatar-profile.png</logo>
+ <updated>2010-03-04T01:41:14+00:00</updated>
+<author>
+ <name>zach</name>
+ <uri>http://localhost/statusnet/user/1</uri>
+
+</author>
+ <link href="http://localhost/statusnet/zach" rel="alternate" type="text/html"/>
+ <link href="http://localhost/statusnet/main/sup#1" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
+ <link href="http://localhost/statusnet/main/push/hub" rel="hub"/>
+ <link href="http://localhost/statusnet/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-replies"/>
+ <link href="http://localhost/statusnet/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-mention"/>
+ <link href="http://localhost/statusnet/api/statuses/user_timeline/1.atom" rel="self" type="application/atom+xml"/>
+<activity:subject>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
+ <id>http://localhost/statusnet/user/1</id>
+ <title>Zach Copley</title>
+ <link rel="alternate" type="text/html" href="http://localhost/statusnet/zach"/>
+ <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://localhost/statusnet/theme/default/default-avatar-profile.png"/>
+ <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://localhost/statusnet/theme/default/default-avatar-stream.png"/>
+ <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://localhost/statusnet/theme/default/default-avatar-mini.png"/>
+
+<poco:preferredUsername>zach</poco:preferredUsername>
+<poco:displayName>Zach Copley</poco:displayName>
+<poco:note>Zach Hack Attack</poco:note>
+<poco:address>
+ <poco:formatted>El Cerrito, CA</poco:formatted>
+</poco:address>
+<poco:urls>
+ <poco:type>homepage</poco:type>
+ <poco:value>http://zach.copley.name</poco:value>
+ <poco:primary>true</poco:primary>
+
+</poco:urls>
+</activity:subject>
+<entry>
+ <title>And now for something completely insane...</title>
+ <link rel="alternate" type="text/html" href="http://localhost/statusnet/notice/3"/>
+ <id>http://localhost/statusnet/notice/3</id>
+ <published>2010-03-04T01:41:07+00:00</published>
+ <updated>2010-03-04T01:41:07+00:00</updated>
+ <link rel="ostatus:conversation" href="http://localhost/statusnet/conversation/3"/>
+ <content type="html">And now for something completely insane...</content>
+</entry>
+
+</feed>
+TESTFEED1;
diff --git a/tests/Core/UserRightsTest.php b/tests/Core/UserRightsTest.php
new file mode 100644 (file)
index 0000000..42af9ba
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use Exception;
+use PHPUnit\Framework\TestCase;
+use User;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+final class UserRightsTest extends TestCase
+{
+    protected $user = null;
+
+    function setUp()
+    {
+        $user = User::getKV('nickname', 'userrightstestuser');
+        if ($user) {
+            // Leftover from a broken test run?
+            $profile = $user->getProfile();
+            $user->delete();
+            $profile->delete();
+        }
+        $this->user = User::register(array('nickname' => 'userrightstestuser'));
+        if (!$this->user) {
+            throw new Exception("Couldn't register userrightstestuser");
+        }
+    }
+
+    function tearDown()
+    {
+        if ($this->user) {
+            $profile = $this->user->getProfile();
+            $this->user->delete();
+            $profile->delete();
+        }
+    }
+
+    function testInvalidRole()
+    {
+        $this->assertFalse($this->user->hasRole('invalidrole'));
+    }
+
+    function standardRoles()
+    {
+        return array(array('admin'),
+            array('moderator'));
+    }
+
+    /**
+     * @dataProvider standardRoles
+     * @param $role
+     */
+
+    function testUngrantedRole($role)
+    {
+        $this->assertFalse($this->user->hasRole($role));
+    }
+
+    /**
+     * @dataProvider standardRoles
+     * @param $role
+     */
+
+    function testGrantedRole($role)
+    {
+        $this->user->grantRole($role);
+        $this->assertTrue($this->user->hasRole($role));
+    }
+}
diff --git a/tests/Core/XmppValidateTest.php b/tests/Core/XmppValidateTest.php
new file mode 100644 (file)
index 0000000..f751eb0
--- /dev/null
@@ -0,0 +1,199 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use GNUsocial;
+use PHPUnit\Framework\TestCase;
+use XmppPlugin;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+require_once INSTALLDIR . '/plugins/Xmpp/XmppPlugin.php';
+
+final class XmppValidateTest extends TestCase
+{
+    public function setUp()
+    {
+        if (!array_key_exists('Xmpp', GNUsocial::getActivePlugins())) {
+            $this->markTestSkipped('XmppPlugin is not enabled.');
+        }
+    }
+
+    /**
+     * @dataProvider validationCases
+     * @param $jid
+     * @param $validFull
+     * @param $validBase
+     */
+    public function testValidate($jid, $validFull, $validBase)
+    {
+        $xmpp = new TestXmppPlugin();
+        $this->assertEquals($validFull || $validBase, $xmpp->validate($jid));
+        $this->assertEquals($validFull, $xmpp->validateFullJid($jid), "validating as full or base JID");
+        $this->assertEquals($validBase, $xmpp->validateBaseJid($jid), "validating as base JID only");
+    }
+
+    /**
+     * @dataProvider normalizationCases
+     * @param $jid
+     * @param $expected
+     */
+    public function testNormalize($jid, $expected)
+    {
+        $xmpp = new XmppPlugin();
+        $this->assertEquals($expected, $xmpp->normalize($jid));
+    }
+
+    /**
+     * @dataProvider domainCheckCases()
+     * @param $domain
+     * @param $expected
+     * @param $note
+     */
+    public function testDomainCheck($domain, $expected, $note)
+    {
+        $xmpp = new TestXmppPlugin();
+        $this->assertEquals($expected, $xmpp->checkDomain($domain), $note);
+    }
+
+    static public function validationCases()
+    {
+        $long1023 = "long1023" . str_repeat('x', 1023 - 8);
+        $long1024 = "long1024" . str_repeat('x', 1024 - 8);
+        return array(
+            // Our own test cases for standard things & those mentioned in bug reports
+            // (jid, valid_full, valid_base)
+            array('user@example.com', true, true),
+            array('user@example.com/resource', true, false),
+            array('user with spaces@example.com', false, false), // not kosher
+
+            array('user.@example.com', true, true), // "common in intranets"
+            array('example.com', true, true),
+            array('example.com/resource', true, false),
+            array('jabchat', true, true),
+
+            array("$long1023@$long1023/$long1023", true, false), // max 1023 "bytes" per portion per spec. Do they really mean bytes though?
+            array("$long1024@$long1023/$long1023", false, false),
+            array("$long1023@$long1024/$long1023", false, false),
+            array("$long1023@$long1023/$long1024", false, false),
+
+            // Borrowed from test_jabber_jutil.c in libpurple
+            array("gmail.com", true, true),
+            array("gmail.com/Test", true, false),
+            array("gmail.com/Test@", true, false),
+            array("gmail.com/@", true, false),
+            array("gmail.com/Test@alkjaweflkj", true, false),
+            array("mark.doliner@gmail.com", true, true),
+            array("mark.doliner@gmail.com/Test12345", true, false),
+            array("mark.doliner@gmail.com/Test@12345", true, false),
+            array("mark.doliner@gmail.com/Te/st@12@//345", true, false),
+            array("わいど@conference.jabber.org", true, true),
+            array("まりるーむ@conference.jabber.org", true, true),
+            array("mark.doliner@gmail.com/まりるーむ", true, false),
+            array("mark.doliner@gmail/stuff.org", true, false),
+            array("stuart@nödåtXäYZ.se", true, true),
+            array("stuart@nödåtXäYZ.se/まりるーむ", true, false),
+            array("mark.doliner@わいど.org", true, true),
+            array("nick@まつ.おおかみ.net", true, true),
+            array("paul@10.0.42.230/s", true, false),
+            array("paul@[::1]", true, true), /* IPv6 */
+            array("paul@[2001:470:1f05:d58::2]", true, true),
+            array("paul@[2001:470:1f05:d58::2]/foo", true, false),
+            array("pa=ul@10.0.42.230", true, true),
+            array("pa,ul@10.0.42.230", true, true),
+
+            array("@gmail.com", false, false),
+            array("@@gmail.com", false, false),
+            array("mark.doliner@@gmail.com/Test12345", false, false),
+            array("mark@doliner@gmail.com/Test12345", false, false),
+            array("@gmail.com/Test@12345", false, false),
+            array("/Test@12345", false, false),
+            array("mark.doliner@", false, false),
+            array("mark.doliner/", false, false),
+            array("mark.doliner@gmail_stuff.org", false, false),
+            array("mark.doliner@gmail[stuff.org", false, false),
+            array("mark.doliner@gmail\\stuff.org", false, false),
+            array("paul@[::1]124", false, false),
+            array("paul@2[::1]124/as", false, false),
+            array("paul@まつ.おおかみ/\x01", false, false),
+
+            /*
+             * RFC 3454 Section 6 reads, in part,
+             * "If a string contains any RandALCat character, the
+             *  string MUST NOT contain any LCat character."
+             * The character is U+066D (ARABIC FIVE POINTED STAR).
+             */
+            // Leaving this one commented out for the moment
+            // as it shouldn't hurt anything for our purposes.
+            //array("foo@example.com/٭simplexe٭", false, false)
+        );
+    }
+
+    static public function normalizationCases()
+    {
+        return array(
+            // Borrowed from test_jabber_jutil.c in libpurple
+            array('PaUL@DaRkRain42.org', 'paul@darkrain42.org'),
+            array('PaUL@DaRkRain42.org/', 'paul@darkrain42.org'),
+            array('PaUL@DaRkRain42.org/resource', 'paul@darkrain42.org'),
+
+            // Also adapted from libpurple tests...
+            array('Ф@darkrain42.org', 'ф@darkrain42.org'),
+            array('paul@Өarkrain.org', 'paul@өarkrain.org'),
+        );
+    }
+
+    static public function domainCheckCases()
+    {
+        return array(
+            array('gmail.com', true, 'known SRV record'),
+            array('jabber.org', true, 'known SRV record'),
+            array('status.net', true, 'known SRV record'),
+            array('status.leuksman.com', true, 'known no SRV record but valid domain'),
+        );
+    }
+
+
+}
+
+class TestXmppPlugin extends XmppPlugin
+{
+    public function checkDomain($domain)
+    {
+        return parent::checkDomain($domain);
+    }
+
+    public function validateBaseJid($jid, $check_domain = false)
+    {
+        return parent::validateBaseJid($jid, $check_domain);
+    }
+
+    public function validateFullJid($jid, $check_domain = false)
+    {
+        return parent::validateFullJid($jid, $check_domain);
+    }
+}
diff --git a/tests/CurryTest.php b/tests/CurryTest.php
deleted file mode 100644 (file)
index 2722a54..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-class CurryTest extends PHPUnit_Framework_TestCase
-{
-    /**
-     * @dataProvider provider
-     *
-     */
-    public function testProduction($callback, $curry_params, $call_params, $expected)
-    {
-        $params = array_merge(array($callback), $curry_params);
-        $curried = call_user_func_array('callable_left_curry', $params);
-        $result = call_user_func_array($curried, $call_params);
-        $this->assertEquals($expected, $result);
-    }
-
-    static public function provider()
-    {
-        $obj = new CurryTestHelperObj('oldval');
-        return array(array(array('CurryTest', 'callback'),
-                           array('curried'),
-                           array('called'),
-                           'called|curried'),
-                     array(array('CurryTest', 'callback'),
-                           array('curried1', 'curried2'),
-                           array('called1', 'called2'),
-                           'called1|called2|curried1|curried2'),
-                     array(array('CurryTest', 'callbackObj'),
-                           array($obj),
-                           array('newval1'),
-                           'oldval|newval1'),
-                     // Confirm object identity is retained...
-                     array(array('CurryTest', 'callbackObj'),
-                           array($obj),
-                           array('newval2'),
-                           'newval1|newval2'));
-    }
-
-    static function callback()
-    {
-        $args = func_get_args();
-        return implode("|", $args);
-    }
-
-    static function callbackObj($val, $obj)
-    {
-        $old = $obj->val;
-        $obj->val = $val;
-        return "$old|$val";
-    }
-}
-
-class CurryTestHelperObj
-{
-    public $val='';
-
-    function __construct($val)
-    {
-        $this->val = $val;
-    }
-}
diff --git a/tests/HashTagDetectionTests.php b/tests/HashTagDetectionTests.php
deleted file mode 100644 (file)
index 1fbc989..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-class HashTagDetectionTests extends PHPUnit_Framework_TestCase
-{
-    /**
-     * @dataProvider provider
-     *
-     */
-    public function testProduction($content, $expected)
-    {
-        $rendered = common_render_text($content);
-        $this->assertEquals($expected, $rendered);
-    }
-
-    static public function provider()
-    {
-        return array(
-                     array('hello',
-                           'hello'),
-                     array('#hello people',
-                           '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span> people'),
-                     array('"#hello" people',
-                           '&quot;#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>&quot; people'),
-                     array('say "#hello" people',
-                           'say &quot;#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>&quot; people'),
-                     array('say (#hello) people',
-                           'say (#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>) people'),
-                     array('say [#hello] people',
-                           'say [#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>] people'),
-                     array('say {#hello} people',
-                           'say {#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>} people'),
-                     array('say \'#hello\' people',
-                           'say \'#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>\' people'),
-
-                     // Unicode legit letters
-                     array('#éclair yummy',
-                           '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('éclair'))) . '" rel="tag">éclair</a></span> yummy'),
-                     array('#维基百科 zh.wikipedia!',
-                           '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('维基百科'))) . '" rel="tag">维基百科</a></span> zh.wikipedia!'),
-                     array('#Россия russia',
-                           '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('Россия'))) . '" rel="tag">Россия</a></span> russia'),
-
-                     // Unicode punctuators -- the ideographic "," separates the tag, just as "," does
-                     array('#维基百科,zh.wikipedia!',
-                           '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('维基百科'))) . '" rel="tag">维基百科</a></span>,zh.wikipedia!'),
-                     array('#维基百科,zh.wikipedia!',
-                           '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('维基百科'))) . '" rel="tag">维基百科</a></span>,zh.wikipedia!'),
-
-                     );
-    }
-}
-
diff --git a/tests/LocationTest.php b/tests/LocationTest.php
deleted file mode 100644 (file)
index f7df271..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-// Make sure this is loaded
-// XXX: how to test other plugins...?
-
-addPlugin('Geonames');
-
-class LocationTest extends PHPUnit_Framework_TestCase
-{
-
-    /**
-     * @dataProvider locationNames
-     */
-
-    public function testLocationFromName($name, $language, $location)
-    {
-        $result = Location::fromName($name, $language);
-        $this->assertEquals($result, $location);
-    }
-
-    static public function locationNames()
-    {
-        return array(array('Montreal', 'en', null),
-                     array('San Francisco, CA', 'en', null),
-                     array('Paris, France', 'en', null),
-                     array('Paris, Texas', 'en', null));
-    }
-
-    /**
-     * @dataProvider locationIds
-     */
-
-    public function testLocationFromId($id, $ns, $language, $location)
-    {
-        $result = Location::fromId($id, $ns, $language);
-        $this->assertEquals($result, $location);
-    }
-
-    static public function locationIds()
-    {
-        return array(array(6077243, GeonamesPlugin::LOCATION_NS, 'en', null),
-                     array(5391959, GeonamesPlugin::LOCATION_NS, 'en', null));
-    }
-
-    /**
-     * @dataProvider locationLatLons
-     */
-
-    public function testLocationFromLatLon($lat, $lon, $language, $location)
-    {
-        $result = Location::fromLatLon($lat, $lon, $language);
-        $this->assertEquals($location, $result->location_id);
-    }
-
-    static public function locationLatLons()
-    {
-        return array(array(37.77493, -122.41942, 'en', null),
-                     array(45.509, -73.588, 'en', null));
-    }
-
-    /**
-     * @dataProvider nameOfLocation
-     */
-
-    public function testLocationGetName($location, $language, $name)
-    {
-        $result = empty($location)?null:$location->getName($language);
-        $this->assertEquals($name, $result);
-    }
-
-    static public function nameOfLocation()
-    {
-        $loc = Location::fromName('Montreal', 'en');
-        return array(array($loc, 'en', null), //'Montreal'),
-                     array($loc, 'fr', null));//'Montréal'));
-    }
-}
-
diff --git a/tests/Media/MediaFileTest.php b/tests/Media/MediaFileTest.php
new file mode 100644 (file)
index 0000000..cd28941
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace Tests\Unit;
+
+if (!defined('INSTALLDIR')) {
+    define('INSTALLDIR', dirname(dirname(__DIR__)));
+}
+if (!defined('GNUSOCIAL')) {
+    define('GNUSOCIAL', true);
+}
+if (!defined('STATUSNET')) { // Compatibility
+    define('STATUSNET', true);
+}
+
+use ClientException;
+use Exception;
+use MediaFile;
+use PHPUnit\Framework\TestCase;
+use ServerException;
+
+require_once INSTALLDIR . '/lib/common.php';
+
+final class MediaFileTest extends TestCase
+{
+
+    public function setup()
+    {
+        $this->old_attachments_supported = common_config('attachments', 'supported');
+        $GLOBALS['config']['attachments']['supported'] = true;
+    }
+
+    public function tearDown()
+    {
+        $GLOBALS['config']['attachments']['supported'] = $this->old_attachments_supported;
+    }
+
+    /**
+     * @dataProvider fileTypeCases
+     * @param $filename
+     * @param $expectedType
+     * @throws ClientException
+     * @throws ServerException
+     */
+    public function testMimeType($filename, $expectedType)
+    {
+        if (!file_exists($filename)) {
+            throw new Exception("Test file $filename missing");
+        }
+
+        $type = MediaFile::getUploadedMimeType($filename, basename($filename));
+        $this->assertEquals($expectedType, $type);
+    }
+
+    /**
+     * @dataProvider fileTypeCases
+     * @param $filename
+     * @param $expectedType
+     * @throws ClientException
+     * @throws ServerException
+     */
+    public function testUploadedMimeType($filename, $expectedType)
+    {
+        if (!file_exists($filename)) {
+            throw new Exception("WTF? $filename test file missing");
+        }
+        $tmp = tmpfile();
+        fwrite($tmp, file_get_contents($filename));
+
+        $tmp_metadata = stream_get_meta_data($tmp);
+        $type = MediaFile::getUploadedMimeType($tmp_metadata['uri'], basename($filename));
+        $this->assertEquals($expectedType, $type);
+    }
+
+    static public function fileTypeCases()
+    {
+        $base = dirname(__FILE__);
+        $dir = "$base/sample-uploads";
+        $files = array(
+            "image.png" => "image/png",
+            "image.gif" => "image/gif",
+            "image.jpg" => "image/jpeg",
+            "image.jpeg" => "image/jpeg",
+            "office.pdf" => "application/pdf",
+            "wordproc.odt" => "application/vnd.oasis.opendocument.text",
+            "wordproc.ott" => "application/vnd.oasis.opendocument.text-template",
+            "wordproc.doc" => "application/msword",
+            "wordproc.docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+            "wordproc.rtf" => "text/rtf",
+            "spreadsheet.ods" => "application/vnd.oasis.opendocument.spreadsheet",
+            "spreadsheet.ots" => "application/vnd.oasis.opendocument.spreadsheet-template",
+            "spreadsheet.xls" => "application/vnd.ms-excel",
+            "spreadsheet.xlt" => "application/vnd.ms-excel",
+            "spreadsheet.xlsx" =>"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+            "presentation.odp" => "application/vnd.oasis.opendocument.presentation",
+            "presentation.otp" => "application/vnd.oasis.opendocument.presentation-template",
+            "presentation.ppt" => "application/vnd.ms-powerpoint",
+            "presentation.pptx" => 'application/zip', //"application/vnd.openxmlformats-officedocument.presentationml.presentation",
+        );
+
+        $dataset = array();
+        foreach ($files as $file => $type) {
+            $dataset[] = array("$dir/$file", $type);
+        }
+        return $dataset;
+    }
+
+}
+
diff --git a/tests/Media/sample-uploads/image.gif b/tests/Media/sample-uploads/image.gif
new file mode 100644 (file)
index 0000000..b636f4b
Binary files /dev/null and b/tests/Media/sample-uploads/image.gif differ
diff --git a/tests/Media/sample-uploads/image.jpeg b/tests/Media/sample-uploads/image.jpeg
new file mode 100644 (file)
index 0000000..21fcb5a
Binary files /dev/null and b/tests/Media/sample-uploads/image.jpeg differ
diff --git a/tests/Media/sample-uploads/image.jpg b/tests/Media/sample-uploads/image.jpg
new file mode 100644 (file)
index 0000000..21fcb5a
Binary files /dev/null and b/tests/Media/sample-uploads/image.jpg differ
diff --git a/tests/Media/sample-uploads/image.png b/tests/Media/sample-uploads/image.png
new file mode 100644 (file)
index 0000000..60cbcfd
Binary files /dev/null and b/tests/Media/sample-uploads/image.png differ
diff --git a/tests/Media/sample-uploads/office.pdf b/tests/Media/sample-uploads/office.pdf
new file mode 100644 (file)
index 0000000..670bc23
Binary files /dev/null and b/tests/Media/sample-uploads/office.pdf differ
diff --git a/tests/Media/sample-uploads/presentation.odp b/tests/Media/sample-uploads/presentation.odp
new file mode 100644 (file)
index 0000000..8dd3a42
Binary files /dev/null and b/tests/Media/sample-uploads/presentation.odp differ
diff --git a/tests/Media/sample-uploads/presentation.otp b/tests/Media/sample-uploads/presentation.otp
new file mode 100644 (file)
index 0000000..1927ee7
Binary files /dev/null and b/tests/Media/sample-uploads/presentation.otp differ
diff --git a/tests/Media/sample-uploads/presentation.pot b/tests/Media/sample-uploads/presentation.pot
new file mode 100644 (file)
index 0000000..f5124ff
Binary files /dev/null and b/tests/Media/sample-uploads/presentation.pot differ
diff --git a/tests/Media/sample-uploads/presentation.potm b/tests/Media/sample-uploads/presentation.potm
new file mode 100644 (file)
index 0000000..ade1bcb
Binary files /dev/null and b/tests/Media/sample-uploads/presentation.potm differ
diff --git a/tests/Media/sample-uploads/presentation.ppt b/tests/Media/sample-uploads/presentation.ppt
new file mode 100644 (file)
index 0000000..f5124ff
Binary files /dev/null and b/tests/Media/sample-uploads/presentation.ppt differ
diff --git a/tests/Media/sample-uploads/presentation.pptx b/tests/Media/sample-uploads/presentation.pptx
new file mode 100644 (file)
index 0000000..21ea61a
Binary files /dev/null and b/tests/Media/sample-uploads/presentation.pptx differ
diff --git a/tests/Media/sample-uploads/spreadsheet.ods b/tests/Media/sample-uploads/spreadsheet.ods
new file mode 100644 (file)
index 0000000..7b43e75
Binary files /dev/null and b/tests/Media/sample-uploads/spreadsheet.ods differ
diff --git a/tests/Media/sample-uploads/spreadsheet.ots b/tests/Media/sample-uploads/spreadsheet.ots
new file mode 100644 (file)
index 0000000..5f830e6
Binary files /dev/null and b/tests/Media/sample-uploads/spreadsheet.ots differ
diff --git a/tests/Media/sample-uploads/spreadsheet.xls b/tests/Media/sample-uploads/spreadsheet.xls
new file mode 100644 (file)
index 0000000..2d470e6
Binary files /dev/null and b/tests/Media/sample-uploads/spreadsheet.xls differ
diff --git a/tests/Media/sample-uploads/spreadsheet.xlsx b/tests/Media/sample-uploads/spreadsheet.xlsx
new file mode 100644 (file)
index 0000000..b97a551
Binary files /dev/null and b/tests/Media/sample-uploads/spreadsheet.xlsx differ
diff --git a/tests/Media/sample-uploads/spreadsheet.xlt b/tests/Media/sample-uploads/spreadsheet.xlt
new file mode 100644 (file)
index 0000000..980423b
Binary files /dev/null and b/tests/Media/sample-uploads/spreadsheet.xlt differ
diff --git a/tests/Media/sample-uploads/wordproc.doc b/tests/Media/sample-uploads/wordproc.doc
new file mode 100644 (file)
index 0000000..81c5e34
Binary files /dev/null and b/tests/Media/sample-uploads/wordproc.doc differ
diff --git a/tests/Media/sample-uploads/wordproc.docx b/tests/Media/sample-uploads/wordproc.docx
new file mode 100644 (file)
index 0000000..04ea3c3
Binary files /dev/null and b/tests/Media/sample-uploads/wordproc.docx differ
diff --git a/tests/Media/sample-uploads/wordproc.odt b/tests/Media/sample-uploads/wordproc.odt
new file mode 100644 (file)
index 0000000..fa6fe5e
Binary files /dev/null and b/tests/Media/sample-uploads/wordproc.odt differ
diff --git a/tests/Media/sample-uploads/wordproc.ott b/tests/Media/sample-uploads/wordproc.ott
new file mode 100644 (file)
index 0000000..99ca8c0
Binary files /dev/null and b/tests/Media/sample-uploads/wordproc.ott differ
diff --git a/tests/Media/sample-uploads/wordproc.rtf b/tests/Media/sample-uploads/wordproc.rtf
new file mode 100644 (file)
index 0000000..aad2c46
--- /dev/null
@@ -0,0 +1,16 @@
+{\rtf1\ansi\deff0\adeflang1025
+{\fonttbl{\f0\froman\fprq2\fcharset128 Times New Roman;}{\f1\froman\fprq2\fcharset128 Times New Roman;}{\f2\fswiss\fprq2\fcharset128 Arial;}{\f3\fnil\fprq2\fcharset128 DejaVu Sans;}}
+{\colortbl;\red0\green0\blue0;\red128\green128\blue128;}
+{\stylesheet{\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\snext1 Normal;}
+{\s2\sb240\sa120\keepn\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\afs28\lang1081\ltrch\dbch\langfe2052\hich\f2\fs28\lang1033\loch\f2\fs28\lang1033\sbasedon1\snext3 Heading;}
+{\s3\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext3 Body Text;}
+{\s4\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon3\snext4 List;}
+{\s5\sb120\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ai\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\i\loch\f0\fs24\lang1033\i\sbasedon1\snext5 caption;}
+{\s6\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext6 Index;}
+}
+{\info{\author Brion }{\creatim\yr2010\mo5\dy10\hr15\min2}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment StarWriter}{\vern3200}}\deftab709
+{\*\pgdsctbl
+{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\pgdscnxt0 Standard;}}
+\paperh15840\paperw12240\margl1134\margr1134\margt1134\margb1134\sectd\sbknone\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
+\pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 
+\par }
\ No newline at end of file
diff --git a/tests/MediaFileTest.php b/tests/MediaFileTest.php
deleted file mode 100644 (file)
index 1e4a3c9..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-class MediaFileTest extends PHPUnit_Framework_TestCase
-{
-
-    public function setup()
-    {
-        $this->old_attachments_supported = common_config('attachments', 'supported');
-        $GLOBALS['config']['attachments']['supported'] = true;
-    }
-
-    public function tearDown()
-    {
-        $GLOBALS['config']['attachments']['supported'] = $this->old_attachments_supported;
-    }
-
-    /**
-     * @dataProvider fileTypeCases
-     *
-     */
-    public function testMimeType($filename, $expectedType)
-    {
-        if (!file_exists($filename)) {
-            throw new Exception("Test file $filename missing");
-        }
-
-        $type = MediaFile::getUploadedMimeType($filename, basename($filename));
-        $this->assertEquals($expectedType, $type);
-    }
-
-    /**
-     * @dataProvider fileTypeCases
-     *
-     */
-    public function testUploadedMimeType($filename, $expectedType)
-    {
-        if (!file_exists($filename)) {
-            throw new Exception("WTF? $filename test file missing");
-        }
-        $tmp = tmpfile();
-        fwrite($tmp, file_get_contents($filename));
-
-        $tmp_metadata = stream_get_meta_data($tmp);
-        $type = MediaFile::getUploadedMimeType($tmp_metadata['uri'], basename($filename));
-        $this->assertEquals($expectedType, $type);
-    }
-
-    static public function fileTypeCases()
-    {
-        $base = dirname(__FILE__);
-        $dir = "$base/sample-uploads";
-        $files = array(
-            "image.png" => "image/png",
-            "image.gif" => "image/gif",
-            "image.jpg" => "image/jpeg",
-            "image.jpeg" => "image/jpeg",
-            "office.pdf" => "application/pdf",
-            "wordproc.odt" => "application/vnd.oasis.opendocument.text",
-            "wordproc.ott" => "application/vnd.oasis.opendocument.text-template",
-            "wordproc.doc" => "application/msword",
-            "wordproc.docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
-            "wordproc.rtf" => "text/rtf",
-            "spreadsheet.ods" => "application/vnd.oasis.opendocument.spreadsheet",
-            "spreadsheet.ots" => "application/vnd.oasis.opendocument.spreadsheet-template",
-            "spreadsheet.xls" => "application/vnd.ms-excel",
-            "spreadsheet.xlt" => "application/vnd.ms-excel",
-            "spreadsheet.xlsx" =>"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
-            "presentation.odp" => "application/vnd.oasis.opendocument.presentation",
-            "presentation.otp" => "application/vnd.oasis.opendocument.presentation-template",
-            "presentation.ppt" => "application/vnd.ms-powerpoint",
-            "presentation.pptx" => 'application/zip', //"application/vnd.openxmlformats-officedocument.presentationml.presentation",
-        );
-
-        $dataset = array();
-        foreach ($files as $file => $type) {
-            $dataset[] = array("$dir/$file", $type);
-        }
-        return $dataset;
-    }
-
-}
-
diff --git a/tests/NicknameTest.php b/tests/NicknameTest.php
deleted file mode 100644 (file)
index 2841398..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-/**
- * Test cases for nickname validity and normalization.
- */
-class NicknameTest extends PHPUnit_Framework_TestCase
-{
-    /**
-     * Basic test using Nickname::normalize()
-     *
-     * @dataProvider provider
-     */
-    public function testBasic($input, $expected, $expectedException=null)
-    {
-        $exception = null;
-        $normalized = false;
-        try {
-            $normalized = Nickname::normalize($input);
-        } catch (NicknameException $e) {
-            $exception = $e;
-        }
-
-        if ($expected === false) {
-            if ($expectedException) {
-                if ($exception) {
-                    $stuff = get_class($exception) . ': ' . $exception->getMessage();
-                } else {
-                    $stuff = var_export($exception, true);
-                }
-                $this->assertTrue($exception && $exception instanceof $expectedException,
-                        "invalid input '$input' expected to fail with $expectedException, " .
-                        "got $stuff");
-            } else {
-                $this->assertTrue($normalized == false,
-                        "invalid input '$input' expected to fail");
-            }
-        } else {
-            $msg = "normalized input nickname '$input' expected to normalize to '$expected', got ";
-            if ($exception) {
-                $msg .= get_class($exception) . ': ' . $exception->getMessage();
-            } else {
-                $msg .= "'$normalized'";
-            }
-            $this->assertEquals($expected, $normalized, $msg);
-        }
-    }
-
-    /**
-     * Test on the regex matching used in common_find_mentions
-     * (testing on the full notice rendering is difficult as it needs
-     * to be able to pull from global state)
-     *
-     * @dataProvider provider
-     */
-    public function testAtReply($input, $expected, $expectedException=null)
-    {
-        if ($expected == false) {
-            // nothing to do
-        } else {
-            $text = "@{$input} awesome! :)";
-            $matches = common_find_mentions_raw($text);
-            $this->assertEquals(1, count($matches));
-            $this->assertEquals($expected, Nickname::normalize($matches[0][0]));
-        }
-    }
-
-    static public function provider()
-    {
-        return array(
-                     array('evan', 'evan'),
-
-                     // Case and underscore variants
-                     array('Evan', 'evan'),
-                     array('EVAN', 'evan'),
-                     array('ev_an', 'evan'),
-                     array('E__V_an', 'evan'),
-                     array('evan1', 'evan1'),
-                     array('evan_1', 'evan1'),
-                     array('0x20', '0x20'),
-                     array('1234', '1234'), // should this be allowed though? :)
-                     array('12__34', '1234'),
-
-                     // Some (currently) invalid chars...
-                     array('^#@&^#@', false, 'NicknameInvalidException'), // all invalid :D
-                     array('ev.an', false, 'NicknameInvalidException'),
-                     array('ev/an', false, 'NicknameInvalidException'),
-                     array('ev an', false, 'NicknameInvalidException'),
-                     array('ev-an', false, 'NicknameInvalidException'),
-
-                     // Non-ASCII letters; currently not allowed, in future
-                     // we'll add them at least with conversion to ASCII.
-                     // Not much use until we have storage of display names,
-                     // though.
-                     array('évan', false, 'NicknameInvalidException'), // so far...
-                     array('Évan', false, 'NicknameInvalidException'), // so far...
-
-                     // Length checks
-                     array('', false, 'NicknameEmptyException'),
-                     array('___', false, 'NicknameEmptyException'),
-                     array('eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'), // 64 chars
-                     array('eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_', false, 'NicknameTooLongException'), // the _ is too long...
-                     array('eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', false, 'NicknameTooLongException'), // 65 chars -- too long
-                     );
-    }
-}
diff --git a/tests/TagURITest.php b/tests/TagURITest.php
deleted file mode 100644 (file)
index ccc80b8..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-$config['site']['server'] = 'example.net';
-$config['site']['path']   = '/apps/statusnet';
-
-class TagURITest extends PHPUnit_Framework_TestCase
-{
-    /**
-     * @dataProvider provider
-     */
-    public function testProduction($format, $args, $uri)
-    {
-        $minted = call_user_func_array(array('TagURI', 'mint'),
-                                       array_merge(array($format), $args));
-
-        $this->assertEquals($uri, $minted);
-    }
-
-    static public function provider()
-    {
-        return array(array('favorite:%d:%d',
-                           array(1, 3),
-                           'tag:example.net,'.date('Y-m-d').':apps:statusnet:favorite:1:3'));
-    }
-}
-
diff --git a/tests/URLDetectionTest.php b/tests/URLDetectionTest.php
deleted file mode 100644 (file)
index 6d0771d..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-class URLDetectionTest extends PHPUnit_Framework_TestCase
-{
-    /**
-     * @dataProvider provider
-     *
-     */
-    public function testProduction($content, $expected)
-    {
-        $rendered = common_render_text($content);
-        // hack!
-        $rendered = preg_replace('/id="attachment-\d+"/', 'id="attachment-XXX"', $rendered);
-        $this->assertEquals($expected, $rendered);
-    }
-
-    /**
-     * @dataProvider linkifyProvider
-     *
-     */
-    public function testLinkifyProduction($content, $expected, $config)
-    {
-        $rendered = common_render_text($content);
-        // hack!
-        $rendered = preg_replace('/id="attachment-\d+"/', 'id="attachment-XXX"', $rendered);
-        if(common_config('linkify', $config)){
-            $this->assertEquals($expected, $rendered);
-        } else {
-            $content = common_remove_unicode_formatting(nl2br(htmlspecialchars($content)));
-            $this->assertEquals($content, $rendered);
-        }
-    }
-
-    static public function provider()
-    {
-        return array(
-                     array('not a link :: no way',
-                           'not a link :: no way'),
-                     array('link http://www.somesite.com/xyz/35637563@N00/52803365/ link',
-                           'link <a href="http://www.somesite.com/xyz/35637563@N00/52803365/" title="http://www.somesite.com/xyz/35637563@N00/52803365/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://www.somesite.com/xyz/35637563@N00/52803365/</a> link'),
-                     array('http://127.0.0.1',
-                           '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://127.0.0.1</a>'),
-                     array('http://[::1]:99/test.php',
-                           '<a href="http://[::1]:99/test.php" title="http://[::1]:99/test.php" rel="nofollow external">http://[::1]:99/test.php</a>'),
-                     array('http://::1/test.php',
-                           '<a href="http://::1/test.php" title="http://::1/test.php" rel="nofollow external">http://::1/test.php</a>'),
-                     array('http://::1',
-                           '<a href="http://::1/" title="http://::1/" rel="nofollow external">http://::1</a>'),
-                     array('http://127.0.0.1',
-                           '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://127.0.0.1</a>'),
-                     array('http://example.com',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>'),
-                     array('http://example.com.',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>.'),
-                     array('/var/lib/example.so',
-                           '/var/lib/example.so'),
-                     array('example',
-                           'example'),
-                     array('mailto:user@example.com',
-                           '<a href="mailto:user@example.com" title="mailto:user@example.com" rel="nofollow external">mailto:user@example.com</a>'),
-                     array('mailto:user@example.com?subject=test',
-                           '<a href="mailto:user@example.com?subject=test" title="mailto:user@example.com?subject=test" rel="nofollow external">mailto:user@example.com?subject=test</a>'),
-                     array('xmpp:user@example.com',
-                           '<a href="xmpp:user@example.com" title="xmpp:user@example.com" rel="nofollow external">xmpp:user@example.com</a>'),
-                     array('#example',
-                           '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('example'))) . '" rel="tag">example</a></span>'),
-                     array('#example.com',
-                           '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('example.com'))) . '" rel="tag">example.com</a></span>'),
-                     array('#.net',
-                           '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('.net'))) . '" rel="tag">.net</a></span>'),
-                     array('http://example',
-                           '<a href="http://example/" title="http://example/" rel="nofollow external">http://example</a>'),
-                     array('http://3xampl3',
-                           '<a href="http://3xampl3/" title="http://3xampl3/" rel="nofollow external">http://3xampl3</a>'),
-                     array('http://example/',
-                           '<a href="http://example/" title="http://example/" rel="nofollow external">http://example/</a>'),
-                     array('http://example/path',
-                           '<a href="http://example/path" title="http://example/path" rel="nofollow external">http://example/path</a>'),
-                     array('http://example.com',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>'),
-                     array('https://example.com',
-                           '<a href="https://example.com/" title="https://example.com/" rel="nofollow external">https://example.com</a>'),
-                     array('ftp://example.com',
-                           '<a href="ftp://example.com/" title="ftp://example.com/" rel="nofollow external">ftp://example.com</a>'),
-                     array('ftps://example.com',
-                           '<a href="ftps://example.com/" title="ftps://example.com/" rel="nofollow external">ftps://example.com</a>'),
-                     array('http://user@example.com',
-                           '<a href="http://@example.com/" title="http://@example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://user@example.com</a>'),
-                     array('http://user:pass@example.com',
-                           '<a href="http://@example.com/" title="http://@example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://user:pass@example.com</a>'),
-                     array('http://example.com:8080',
-                           '<a href="http://example.com:8080/" title="http://example.com:8080/" rel="nofollow external">http://example.com:8080</a>'),
-                     array('http://example.com:8080/test.php',
-                           '<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="nofollow external">http://example.com:8080/test.php</a>'),
-                     array('http://www.example.com',
-                           '<a href="http://www.example.com/" title="http://www.example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://www.example.com</a>'),
-                     array('http://example.com/',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/</a>'),
-                     array('http://example.com/path',
-                           '<a href="http://example.com/path" title="http://example.com/path" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path</a>'),
-                     array('http://example.com/path.html',
-                           '<a href="http://example.com/path.html" title="http://example.com/path.html" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path.html</a>'),
-                     array('http://example.com/path.html#fragment',
-                           '<a href="http://example.com/path.html#fragment" title="http://example.com/path.html#fragment" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path.html#fragment</a>'),
-                     array('http://example.com/path.php?foo=bar&bar=foo',
-                           '<a href="http://example.com/path.php?foo=bar&amp;bar=foo" title="http://example.com/path.php?foo=bar&amp;bar=foo" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path.php?foo=bar&amp;bar=foo</a>'),
-                     array('http://example.com.',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>.'),
-                     array('http://müllärör.de',
-                           '<a href="http://m&#xFC;ll&#xE4;r&#xF6;r.de/" title="http://m&#xFC;ll&#xE4;r&#xF6;r.de/" rel="nofollow external">http://müllärör.de</a>'),
-                     array('http://ﺱﺲﺷ.com',
-                           '<a href="http://&#xFEB1;&#xFEB2;&#xFEB7;.com/" title="http://&#xFEB1;&#xFEB2;&#xFEB7;.com/" rel="nofollow external">http://ﺱﺲﺷ.com</a>'),
-                     array('http://сделаткартинки.com',
-                           '<a href="http://&#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x438;.com/" title="http://&#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x438;.com/" rel="nofollow external">http://сделаткартинки.com</a>'),
-                     array('http://tūdaliņ.lv',
-                           '<a href="http://t&#x16B;dali&#x146;.lv/" title="http://t&#x16B;dali&#x146;.lv/" rel="nofollow external">http://tūdaliņ.lv</a>'),
-                     array('http://brændendekærlighed.com',
-                           '<a href="http://br&#xE6;ndendek&#xE6;rlighed.com/" title="http://br&#xE6;ndendek&#xE6;rlighed.com/" rel="nofollow external">http://brændendekærlighed.com</a>'),
-                     array('http://あーるいん.com',
-                           '<a href="http://&#x3042;&#x30FC;&#x308B;&#x3044;&#x3093;.com/" title="http://&#x3042;&#x30FC;&#x308B;&#x3044;&#x3093;.com/" rel="nofollow external">http://あーるいん.com</a>'),
-                     array('http://예비교사.com',
-                           '<a href="http://&#xC608;&#xBE44;&#xAD50;&#xC0AC;.com/" title="http://&#xC608;&#xBE44;&#xAD50;&#xC0AC;.com/" rel="nofollow external">http://예비교사.com</a>'),
-                     array('http://example.com.',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>.'),
-                     array('http://example.com?',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>?'),
-                     array('http://example.com!',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>!'),
-                     array('http://example.com,',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>,'),
-                     array('http://example.com;',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>;'),
-                     array('http://example.com:',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>:'),
-                     array('\'http://example.com\'',
-                           '\'<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>\''),
-                     array('"http://example.com"',
-                           '&quot;<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>&quot;'),
-                     array('"http://example.com/"',
-                           '&quot;<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/</a>&quot;'),
-                     array('http://example.com',
-                           '<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>'),
-                     array('(http://example.com)',
-                           '(<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>)'),
-                     array('[http://example.com]',
-                           '[<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>]'),
-                     array('<http://example.com>',
-                           '&lt;<a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a>&gt;'),
-                     array('http://example.com/path/(foo)/bar',
-                           '<a href="http://example.com/path/" title="http://example.com/path/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/</a>(foo)/bar'),
-                     array('http://example.com/path/[foo]/bar',
-                           '<a href="http://example.com/path/" title="http://example.com/path/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/</a>[foo]/bar'),
-                     array('http://example.com/path/foo/(bar)',
-                           '<a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>(bar)'),
-                     //Not a valid url - urls cannot contain unencoded square brackets
-                     array('http://example.com/path/foo/[bar]',
-                           '<a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>[bar]'),
-                     array('Hey, check out my cool site http://example.com okay?',
-                           'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com</a> okay?'),
-                     array('What about parens (e.g. http://example.com/path/foo/(bar))?',
-                           'What about parens (e.g. <a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>(bar))?'),
-                     array('What about parens (e.g. http://example.com/path/foo/(bar)?',
-                           'What about parens (e.g. <a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>(bar)?'),
-                     array('What about parens (e.g. http://example.com/path/foo/(bar).)?',
-                           'What about parens (e.g. <a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>(bar).)?'),
-                     //Not a valid url - urls cannot contain unencoded commas
-                     array('What about parens (e.g. http://example.com/path/(foo,bar)?',
-                           'What about parens (e.g. <a href="http://example.com/path/" title="http://example.com/path/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/</a>(foo,bar)?'),
-                     array('Unbalanced too (e.g. http://example.com/path/((((foo)/bar)?',
-                           'Unbalanced too (e.g. <a href="http://example.com/path/" title="http://example.com/path/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/</a>((((foo)/bar)?'),
-                     array('Unbalanced too (e.g. http://example.com/path/(foo))))/bar)?',
-                           'Unbalanced too (e.g. <a href="http://example.com/path/" title="http://example.com/path/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/</a>(foo))))/bar)?'),
-                     array('Unbalanced too (e.g. http://example.com/path/foo/((((bar)?',
-                           'Unbalanced too (e.g. <a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>((((bar)?'),
-                     array('Unbalanced too (e.g. http://example.com/path/foo/(bar))))?',
-                           'Unbalanced too (e.g. <a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external noreferrer" class="attachment" id="attachment-XXX">http://example.com/path/foo/</a>(bar))))?'),
-                     array('file.ext',
-                           'file.ext'),
-                     array('file.html',
-                           'file.html'),
-                     array('file.php',
-                           'file.php'),
-
-                     // scheme-less HTTP URLs with @ in the path: http://status.net/open-source/issues/2248
-                     array('http://flickr.com/photos/34807140@N05/3838905434',
-                           '<a href="http://www.flickr.com/photos/34807140@N05/3838905434" title="http://www.flickr.com/photos/34807140@N05/3838905434" rel="nofollow external noreferrer" class="attachment thumbnail" id="attachment-XXX">http://flickr.com/photos/34807140@N05/3838905434</a>'),
-                     );
-    }
-
-    static public function linkifyProvider()
-    {
-        return array(
-            //bare ip addresses are no longer supported
-            array('127.0.0.1',
-                  '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external">127.0.0.1</a>',
-                  'bare_ipv4'),
-            array('127.0.0.1:99',
-                  '<a href="http://127.0.0.1:99/" title="http://127.0.0.1:99/" rel="nofollow external">127.0.0.1:99</a>',
-                  'bare_ipv4'),
-            array('127.0.0.1/Name:test.php',
-                  '<a href="http://127.0.0.1/Name:test.php" title="http://127.0.0.1/Name:test.php" rel="nofollow external">127.0.0.1/Name:test.php</a>',
-                  'bare_ipv4'),
-            array('127.0.0.1/~test',
-                  '<a href="http://127.0.0.1/~test" title="http://127.0.0.1/~test" rel="nofollow external">127.0.0.1/~test</a>',
-                  'bare_ipv4'),
-            array('127.0.0.1/+test',
-                  '<a href="http://127.0.0.1/+test" title="http://127.0.0.1/+test" rel="nofollow external">127.0.0.1/+test</a>',
-                  'bare_ipv4'),
-            array('127.0.0.1/$test',
-                  '<a href="http://127.0.0.1/$test" title="http://127.0.0.1/$test" rel="nofollow external">127.0.0.1/$test</a>',
-                  'bare_ipv4'),
-            array('127.0.0.1/\'test',
-                  '<a href="http://127.0.0.1/\'test" title="http://127.0.0.1/\'test" rel="nofollow external">127.0.0.1/\'test</a>',
-                  'bare_ipv4'),
-            array('127.0.0.1/"test',
-                  '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external">127.0.0.1/</a>&quot;test',
-                  'bare_ipv4'),
-            array('127.0.0.1/test"test',
-                  '<a href="http://127.0.0.1/test" title="http://127.0.0.1/test" rel="nofollow external">127.0.0.1/test</a>&quot;test',
-                  'bare_ipv4'),
-            array('127.0.0.1/-test',
-                  '<a href="http://127.0.0.1/-test" title="http://127.0.0.1/-test" rel="nofollow external">127.0.0.1/-test</a>',
-                  'bare_ipv4'),
-            array('127.0.0.1/_test',
-                  '<a href="http://127.0.0.1/_test" title="http://127.0.0.1/_test" rel="nofollow external">127.0.0.1/_test</a>',
-                  'bare_ipv4'),
-            array('127.0.0.1/!test',
-                  '<a href="http://127.0.0.1/!test" title="http://127.0.0.1/!test" rel="nofollow external">127.0.0.1/!test</a>',
-                  'bare_ipv4'),
-            array('127.0.0.1/*test',
-                  '<a href="http://127.0.0.1/*test" title="http://127.0.0.1/*test" rel="nofollow external">127.0.0.1/*test</a>',
-                  'bare_ipv4'),
-            array('127.0.0.1/test%20stuff',
-                  '<a href="http://127.0.0.1/test%20stuff" title="http://127.0.0.1/test%20stuff" rel="nofollow external">127.0.0.1/test%20stuff</a>',
-                  'bare_ipv4'),
-            array('2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php',
-                  '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" rel="nofollow external">2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php</a>',
-                  'bare_ipv6'),
-            array('[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php',
-                  '<a href="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" title="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" rel="nofollow external">[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php</a>',
-                  'bare_ipv6'),
-            array('2001:4978:1b5:0:21d:e0ff:fe66:59ab',
-                  '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" rel="nofollow external">2001:4978:1b5:0:21d:e0ff:fe66:59ab</a>',
-                  'bare_ipv6'),
-            array('example.com',
-                  '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>',
-                  'bare_domains'),
-            array('flickr.com/photos/34807140@N05/3838905434',
-                  '<a href="http://flickr.com/photos/34807140@N05/3838905434" title="http://flickr.com/photos/34807140@N05/3838905434" class="attachment thumbnail" id="attachment-XXX" rel="nofollow external">flickr.com/photos/34807140@N05/3838905434</a>',
-                  'bare_domains'),
-            array('What about parens (e.g. example.com/path/foo/(bar))?',
-                  'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">example.com/path/foo/(bar)</a>)?',
-                  'bare_domains'),
-            array('What about parens (e.g. example.com/path/foo/(bar)?',
-                  'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">example.com/path/foo/(bar)</a>?',
-                  'bare_domains'),
-            array('What about parens (e.g. example.com/path/foo/(bar).)?',
-                  'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">example.com/path/foo/(bar)</a>.?',
-                  'bare_domains'),
-            array('What about parens (e.g. example.com/path/(foo,bar)?',
-                  'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" title="http://example.com/path/(foo,bar)" rel="nofollow external">example.com/path/(foo,bar)</a>?',
-                  'bare_domains'),
-            array('example.com',
-                  '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>',
-                  'bare_domains'),
-            array('example.org',
-                  '<a href="http://example.org/" title="http://example.org/" rel="nofollow external">example.org</a>',
-                  'bare_domains'),
-            array('example.co.uk',
-                  '<a href="http://example.co.uk/" title="http://example.co.uk/" rel="nofollow external">example.co.uk</a>',
-                  'bare_domains'),
-            array('www.example.co.uk',
-                  '<a href="http://www.example.co.uk/" title="http://www.example.co.uk/" rel="nofollow external">www.example.co.uk</a>',
-                  'bare_domains'),
-            array('farm1.images.example.co.uk',
-                  '<a href="http://farm1.images.example.co.uk/" title="http://farm1.images.example.co.uk/" rel="nofollow external">farm1.images.example.co.uk</a>',
-                  'bare_domains'),
-            array('example.museum',
-                  '<a href="http://example.museum/" title="http://example.museum/" rel="nofollow external">example.museum</a>',
-                  'bare_domains'),
-            array('example.travel',
-                  '<a href="http://example.travel/" title="http://example.travel/" rel="nofollow external">example.travel</a>',
-                  'bare_domains'),
-            array('example.com.',
-                  '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.',
-                  'bare_domains'),
-            array('example.com?',
-                  '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>?',
-                  'bare_domains'),
-            array('example.com!',
-                  '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>!',
-                  'bare_domains'),
-            array('example.com,',
-                  '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>,',
-                  'bare_domains'),
-            array('example.com;',
-                  '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>;',
-                  'bare_domains'),
-            array('example.com:',
-                  '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>:',
-                  'bare_domains'),
-            array('\'example.com\'',
-                  '\'<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>\'',
-                  'bare_domains'),
-            array('"example.com"',
-                  '&quot;<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>&quot;',
-                  'bare_domains'),
-            array('example.com',
-                  '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>',
-                  'bare_domains'),
-            array('(example.com)',
-                  '(<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>)',
-                  'bare_domains'),
-            array('[example.com]',
-                  '[<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>]',
-                  'bare_domains'),
-            array('<example.com>',
-                  '&lt;<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>&gt;',
-                  'bare_domains'),
-            array('Hey, check out my cool site example.com okay?',
-                  'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a> okay?',
-                  'bare_domains'),
-            array('Hey, check out my cool site example.com.I made it.',
-                  'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.I made it.',
-                  'bare_domains'),
-            array('Hey, check out my cool site example.com.Funny thing...',
-                  'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.Funny thing...',
-                  'bare_domains'),
-            array('Hey, check out my cool site example.com.You will love it.',
-                  'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.You will love it.',
-                  'bare_domains'),
-            array('example.com:8080/test.php',
-                  '<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="nofollow external">example.com:8080/test.php</a>',
-                  'bare_domains'),
-            array('user_name+other@example.com',
-                  '<a href="mailto:user_name+other@example.com" title="mailto:user_name+other@example.com" rel="nofollow external">user_name+other@example.com</a>',
-                  'bare_domains'),
-            array('user@example.com',
-                  '<a href="mailto:user@example.com" title="mailto:user@example.com" rel="nofollow external">user@example.com</a>',
-                  'bare_domains'),
-        );
-    }
-}
-
diff --git a/tests/UUIDTest.php b/tests/UUIDTest.php
deleted file mode 100644 (file)
index ce330d7..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-class UUIDTest extends PHPUnit_Framework_TestCase
-{
-    public function testGenerate()
-    {
-        $result = UUID::gen();
-        $this->assertRegExp('/^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$/',
-                            $result);
-        // Check version number
-        $this->assertEquals(0x4000, hexdec(substr($result, 14, 4)) & 0xF000);
-        $this->assertEquals(0x8000, hexdec(substr($result, 19, 4)) & 0xC000);
-    }
-
-    public function testUnique()
-    {
-        $reps = 100;
-        $ids = array();
-
-        for ($i = 0; $i < $reps; $i++) {
-            $ids[] = UUID::gen();
-        }
-
-        $this->assertEquals(count($ids), count(array_unique($ids)), "UUIDs must be unique");
-    }
-}
-
diff --git a/tests/UserFeedParseTest.php b/tests/UserFeedParseTest.php
deleted file mode 100644 (file)
index b68783b..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-class UserFeedParseTests extends PHPUnit_Framework_TestCase
-{
-    public function testFeed1()
-    {
-        global $_testfeed1;
-        $dom = DOMDocument::loadXML($_testfeed1);
-        $this->assertFalse(empty($dom));
-
-        $entries = $dom->getElementsByTagName('entry');
-
-        $entry1 = $entries->item(0);
-        $this->assertFalse(empty($entry1));
-
-        $feedEl = $dom->getElementsByTagName('feed')->item(0);
-        $this->assertFalse(empty($feedEl));
-
-        // Test actor (from activity:subject)
-
-        $act1 = new Activity($entry1, $feedEl);
-        $this->assertFalse(empty($act1));
-        $this->assertFalse(empty($act1->actor));
-        $this->assertEquals($act1->actor->type, ActivityObject::PERSON);
-        $this->assertEquals($act1->actor->title, 'Zach Copley');
-        $this->assertEquals($act1->actor->id, 'http://localhost/statusnet/user/1');
-        $this->assertEquals($act1->actor->link, 'http://localhost/statusnet/zach');
-
-        $avatars = $act1->actor->avatarLinks;
-
-        $this->assertEquals(
-                $avatars[0]->url,
-                'http://localhost/statusnet/theme/default/default-avatar-profile.png'
-        );
-
-        $this->assertEquals(
-                $avatars[1]->url,
-                'http://localhost/statusnet/theme/default/default-avatar-stream.png'
-        );
-
-        $this->assertEquals(
-                $avatars[2]->url,
-                'http://localhost/statusnet/theme/default/default-avatar-mini.png'
-        );
-
-        $this->assertEquals($act1->actor->displayName, 'Zach Copley');
-
-        $poco = $act1->actor->poco;
-        $this->assertEquals($poco->preferredUsername, 'zach');
-        $this->assertEquals($poco->address->formatted, 'El Cerrito, CA');
-        $this->assertEquals($poco->urls[0]->type, 'homepage');
-        $this->assertEquals($poco->urls[0]->value, 'http://zach.copley.name');
-        $this->assertEquals($poco->urls[0]->primary, true);
-        $this->assertEquals($poco->note, 'Zach Hack Attack');
-
-        // test the post
-
-        //var_export($act1);
-        $this->assertEquals($act1->objects[0]->type, 'http://activitystrea.ms/schema/1.0/note');
-        $this->assertEquals($act1->objects[0]->title, 'And now for something completely insane...');
-
-        $this->assertEquals($act1->objects[0]->content, 'And now for something completely insane...');
-        $this->assertEquals($act1->objects[0]->id, 'http://localhost/statusnet/notice/3');
-
-    }
-
-}
-
-$_testfeed1 = <<<TESTFEED1
-<?xml version="1.0" encoding="UTF-8"?>
-<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0">
- <id>http://localhost/statusnet/api/statuses/user_timeline/1.atom</id>
- <title>zach timeline</title>
- <subtitle>Updates from zach on Zach Dev!</subtitle>
- <logo>http://localhost/statusnet/theme/default/default-avatar-profile.png</logo>
- <updated>2010-03-04T01:41:14+00:00</updated>
-<author>
- <name>zach</name>
- <uri>http://localhost/statusnet/user/1</uri>
-
-</author>
- <link href="http://localhost/statusnet/zach" rel="alternate" type="text/html"/>
- <link href="http://localhost/statusnet/main/sup#1" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
- <link href="http://localhost/statusnet/main/push/hub" rel="hub"/>
- <link href="http://localhost/statusnet/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-replies"/>
- <link href="http://localhost/statusnet/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-mention"/>
- <link href="http://localhost/statusnet/api/statuses/user_timeline/1.atom" rel="self" type="application/atom+xml"/>
-<activity:subject>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>http://localhost/statusnet/user/1</id>
- <title>Zach Copley</title>
- <link rel="alternate" type="text/html" href="http://localhost/statusnet/zach"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://localhost/statusnet/theme/default/default-avatar-profile.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://localhost/statusnet/theme/default/default-avatar-stream.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://localhost/statusnet/theme/default/default-avatar-mini.png"/>
-
-<poco:preferredUsername>zach</poco:preferredUsername>
-<poco:displayName>Zach Copley</poco:displayName>
-<poco:note>Zach Hack Attack</poco:note>
-<poco:address>
- <poco:formatted>El Cerrito, CA</poco:formatted>
-</poco:address>
-<poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>http://zach.copley.name</poco:value>
- <poco:primary>true</poco:primary>
-
-</poco:urls>
-</activity:subject>
-<entry>
- <title>And now for something completely insane...</title>
- <link rel="alternate" type="text/html" href="http://localhost/statusnet/notice/3"/>
- <id>http://localhost/statusnet/notice/3</id>
- <published>2010-03-04T01:41:07+00:00</published>
- <updated>2010-03-04T01:41:07+00:00</updated>
- <link rel="ostatus:conversation" href="http://localhost/statusnet/conversation/3"/>
- <content type="html">And now for something completely insane...</content>
-</entry>
-
-</feed>
-TESTFEED1;
diff --git a/tests/UserRightsTest.php b/tests/UserRightsTest.php
deleted file mode 100644 (file)
index bd9124a..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-class UserRightsTest extends PHPUnit_Framework_TestCase
-{
-    protected $user = null;
-
-    function setUp()
-    {
-        $user = User::getKV('nickname', 'userrightstestuser');
-        if ($user) {
-            // Leftover from a broken test run?
-            $profile = $user->getProfile();
-            $user->delete();
-            $profile->delete();
-        }
-        $this->user = User::register(array('nickname' => 'userrightstestuser'));
-        if (!$this->user) {
-            throw new Exception("Couldn't register userrightstestuser");
-        }
-    }
-
-    function tearDown()
-    {
-        if ($this->user) {
-            $profile = $this->user->getProfile();
-            $this->user->delete();
-            $profile->delete();
-        }
-    }
-
-    function testInvalidRole()
-    {
-        $this->assertFalse($this->user->hasRole('invalidrole'));
-    }
-
-    function standardRoles()
-    {
-        return array(array('admin'),
-                     array('moderator'));
-    }
-
-    /**
-     * @dataProvider standardRoles
-     *
-     */
-
-    function testUngrantedRole($role)
-    {
-        $this->assertFalse($this->user->hasRole($role));
-    }
-
-    /**
-     * @dataProvider standardRoles
-     *
-     */
-
-    function testGrantedRole($role)
-    {
-        $this->user->grantRole($role);
-        $this->assertTrue($this->user->hasRole($role));
-    }
-}
diff --git a/tests/XmppValidateTest.php b/tests/XmppValidateTest.php
deleted file mode 100644 (file)
index f337739..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true);  // compatibility
-
-mb_internal_encoding('UTF-8'); // @fixme this probably belongs in common.php?
-
-require_once INSTALLDIR . '/lib/common.php';
-require_once INSTALLDIR . '/plugins/Xmpp/XmppPlugin.php';
-
-class XmppValidateTest extends PHPUnit_Framework_TestCase
-{
-       public function setUp()
-       {
-               if(!array_key_exists('Xmpp', GNUsocial::getActivePlugins())){
-                       $this->markTestSkipped('XmppPlugin is not enabled.');
-               }
-       }
-    /**
-     * @dataProvider validationCases
-     *
-     */
-    public function testValidate($jid, $validFull, $validBase)
-    {
-       $xmpp = new TestXmppPlugin();
-       $this->assertEquals($validFull || $validBase, $xmpp->validate($jid));
-        $this->assertEquals($validFull, $xmpp->validateFullJid($jid), "validating as full or base JID");
-        $this->assertEquals($validBase, $xmpp->validateBaseJid($jid), "validating as base JID only");
-    }
-
-    /**
-     * @dataProvider normalizationCases
-     *
-     */
-    public function testNormalize($jid, $expected)
-    {
-       $xmpp = new XmppPlugin();
-        $this->assertEquals($expected, $xmpp->normalize($jid));
-    }
-
-    /**
-     * @dataProvider domainCheckCases()
-     */
-    public function testDomainCheck($domain, $expected, $note)
-    {
-       $xmpp = new TestXmppPlugin();
-        $this->assertEquals($expected, $xmpp->checkDomain($domain), $note);
-    }
-
-    static public function validationCases()
-    {
-        $long1023 = "long1023" . str_repeat('x', 1023 - 8);
-        $long1024 = "long1024" . str_repeat('x', 1024 - 8);
-        return array(
-            // Our own test cases for standard things & those mentioned in bug reports
-            // (jid, valid_full, valid_base)
-            array('user@example.com', true, true),
-            array('user@example.com/resource', true, false),
-            array('user with spaces@example.com', false, false), // not kosher
-
-            array('user.@example.com', true, true), // "common in intranets"
-            array('example.com', true, true),
-            array('example.com/resource', true, false),
-            array('jabchat', true, true),
-            
-            array("$long1023@$long1023/$long1023", true, false), // max 1023 "bytes" per portion per spec. Do they really mean bytes though?
-            array("$long1024@$long1023/$long1023", false, false),
-            array("$long1023@$long1024/$long1023", false, false),
-            array("$long1023@$long1023/$long1024", false, false),
-
-            // Borrowed from test_jabber_jutil.c in libpurple
-            array("gmail.com", true, true),
-            array("gmail.com/Test", true, false),
-            array("gmail.com/Test@", true, false),
-            array("gmail.com/@", true, false),
-            array("gmail.com/Test@alkjaweflkj", true, false),
-            array("mark.doliner@gmail.com", true, true),
-            array("mark.doliner@gmail.com/Test12345", true, false),
-            array("mark.doliner@gmail.com/Test@12345", true, false),
-            array("mark.doliner@gmail.com/Te/st@12@//345", true, false),
-            array("わいど@conference.jabber.org", true, true),
-            array("まりるーむ@conference.jabber.org", true, true),
-            array("mark.doliner@gmail.com/まりるーむ", true, false),
-            array("mark.doliner@gmail/stuff.org", true, false),
-            array("stuart@nödåtXäYZ.se", true, true),
-            array("stuart@nödåtXäYZ.se/まりるーむ", true, false),
-            array("mark.doliner@わいど.org", true, true),
-            array("nick@まつ.おおかみ.net", true, true),
-            array("paul@10.0.42.230/s", true, false),
-            array("paul@[::1]", true, true), /* IPv6 */
-            array("paul@[2001:470:1f05:d58::2]", true, true),
-            array("paul@[2001:470:1f05:d58::2]/foo", true, false),
-            array("pa=ul@10.0.42.230", true, true),
-            array("pa,ul@10.0.42.230", true, true),
-
-            array("@gmail.com", false, false),
-            array("@@gmail.com", false, false),
-            array("mark.doliner@@gmail.com/Test12345", false, false),
-            array("mark@doliner@gmail.com/Test12345", false, false),
-            array("@gmail.com/Test@12345", false, false),
-            array("/Test@12345", false, false),
-            array("mark.doliner@", false, false),
-            array("mark.doliner/", false, false),
-            array("mark.doliner@gmail_stuff.org", false, false),
-            array("mark.doliner@gmail[stuff.org", false, false),
-            array("mark.doliner@gmail\\stuff.org", false, false),
-            array("paul@[::1]124", false, false),
-            array("paul@2[::1]124/as", false, false),
-            array("paul@まつ.おおかみ/\x01", false, false),
-
-            /*
-             * RFC 3454 Section 6 reads, in part,
-             * "If a string contains any RandALCat character, the
-             *  string MUST NOT contain any LCat character."
-             * The character is U+066D (ARABIC FIVE POINTED STAR).
-             */
-            // Leaving this one commented out for the moment
-            // as it shouldn't hurt anything for our purposes.
-            //array("foo@example.com/٭simplexe٭", false, false)
-        );
-    }
-    
-    static public function normalizationCases()
-    {
-        return array(
-            // Borrowed from test_jabber_jutil.c in libpurple
-            array('PaUL@DaRkRain42.org', 'paul@darkrain42.org'),
-            array('PaUL@DaRkRain42.org/', 'paul@darkrain42.org'),
-            array('PaUL@DaRkRain42.org/resource', 'paul@darkrain42.org'),
-
-            // Also adapted from libpurple tests...
-            array('Ф@darkrain42.org', 'ф@darkrain42.org'),
-            array('paul@Өarkrain.org', 'paul@өarkrain.org'),
-        );
-    }
-
-    static public function domainCheckCases()
-    {
-        return array(
-            array('gmail.com', true, 'known SRV record'),
-            array('jabber.org', true, 'known SRV record'),
-            array('status.net', true, 'known SRV record'),
-            array('status.leuksman.com', true, 'known no SRV record but valid domain'),
-        );
-    }
-
-
-}
-
-class TestXmppPlugin extends XmppPlugin {
-       public function checkDomain($domain)
-       {
-               return parent::checkDomain($domain);
-       }
-       
-       public function validateBaseJid($jid, $check_domain=false)
-       {
-               return parent::validateBaseJid($jid, $check_domain);
-       }
-       
-       public function validateFullJid($jid, $check_domain=false)
-       {
-               return parent::validateFullJid($jid, $check_domain);
-       }
-}
\ No newline at end of file
diff --git a/tests/sample-uploads/image.gif b/tests/sample-uploads/image.gif
deleted file mode 100644 (file)
index b636f4b..0000000
Binary files a/tests/sample-uploads/image.gif and /dev/null differ
diff --git a/tests/sample-uploads/image.jpeg b/tests/sample-uploads/image.jpeg
deleted file mode 100644 (file)
index 21fcb5a..0000000
Binary files a/tests/sample-uploads/image.jpeg and /dev/null differ
diff --git a/tests/sample-uploads/image.jpg b/tests/sample-uploads/image.jpg
deleted file mode 100644 (file)
index 21fcb5a..0000000
Binary files a/tests/sample-uploads/image.jpg and /dev/null differ
diff --git a/tests/sample-uploads/image.png b/tests/sample-uploads/image.png
deleted file mode 100644 (file)
index 60cbcfd..0000000
Binary files a/tests/sample-uploads/image.png and /dev/null differ
diff --git a/tests/sample-uploads/office.pdf b/tests/sample-uploads/office.pdf
deleted file mode 100644 (file)
index 670bc23..0000000
Binary files a/tests/sample-uploads/office.pdf and /dev/null differ
diff --git a/tests/sample-uploads/presentation.odp b/tests/sample-uploads/presentation.odp
deleted file mode 100644 (file)
index 8dd3a42..0000000
Binary files a/tests/sample-uploads/presentation.odp and /dev/null differ
diff --git a/tests/sample-uploads/presentation.otp b/tests/sample-uploads/presentation.otp
deleted file mode 100644 (file)
index 1927ee7..0000000
Binary files a/tests/sample-uploads/presentation.otp and /dev/null differ
diff --git a/tests/sample-uploads/presentation.pot b/tests/sample-uploads/presentation.pot
deleted file mode 100644 (file)
index f5124ff..0000000
Binary files a/tests/sample-uploads/presentation.pot and /dev/null differ
diff --git a/tests/sample-uploads/presentation.potm b/tests/sample-uploads/presentation.potm
deleted file mode 100644 (file)
index ade1bcb..0000000
Binary files a/tests/sample-uploads/presentation.potm and /dev/null differ
diff --git a/tests/sample-uploads/presentation.ppt b/tests/sample-uploads/presentation.ppt
deleted file mode 100644 (file)
index f5124ff..0000000
Binary files a/tests/sample-uploads/presentation.ppt and /dev/null differ
diff --git a/tests/sample-uploads/presentation.pptx b/tests/sample-uploads/presentation.pptx
deleted file mode 100644 (file)
index 21ea61a..0000000
Binary files a/tests/sample-uploads/presentation.pptx and /dev/null differ
diff --git a/tests/sample-uploads/spreadsheet.ods b/tests/sample-uploads/spreadsheet.ods
deleted file mode 100644 (file)
index 7b43e75..0000000
Binary files a/tests/sample-uploads/spreadsheet.ods and /dev/null differ
diff --git a/tests/sample-uploads/spreadsheet.ots b/tests/sample-uploads/spreadsheet.ots
deleted file mode 100644 (file)
index 5f830e6..0000000
Binary files a/tests/sample-uploads/spreadsheet.ots and /dev/null differ
diff --git a/tests/sample-uploads/spreadsheet.xls b/tests/sample-uploads/spreadsheet.xls
deleted file mode 100644 (file)
index 2d470e6..0000000
Binary files a/tests/sample-uploads/spreadsheet.xls and /dev/null differ
diff --git a/tests/sample-uploads/spreadsheet.xlsx b/tests/sample-uploads/spreadsheet.xlsx
deleted file mode 100644 (file)
index b97a551..0000000
Binary files a/tests/sample-uploads/spreadsheet.xlsx and /dev/null differ
diff --git a/tests/sample-uploads/spreadsheet.xlt b/tests/sample-uploads/spreadsheet.xlt
deleted file mode 100644 (file)
index 980423b..0000000
Binary files a/tests/sample-uploads/spreadsheet.xlt and /dev/null differ
diff --git a/tests/sample-uploads/wordproc.doc b/tests/sample-uploads/wordproc.doc
deleted file mode 100644 (file)
index 81c5e34..0000000
Binary files a/tests/sample-uploads/wordproc.doc and /dev/null differ
diff --git a/tests/sample-uploads/wordproc.docx b/tests/sample-uploads/wordproc.docx
deleted file mode 100644 (file)
index 04ea3c3..0000000
Binary files a/tests/sample-uploads/wordproc.docx and /dev/null differ
diff --git a/tests/sample-uploads/wordproc.odt b/tests/sample-uploads/wordproc.odt
deleted file mode 100644 (file)
index fa6fe5e..0000000
Binary files a/tests/sample-uploads/wordproc.odt and /dev/null differ
diff --git a/tests/sample-uploads/wordproc.ott b/tests/sample-uploads/wordproc.ott
deleted file mode 100644 (file)
index 99ca8c0..0000000
Binary files a/tests/sample-uploads/wordproc.ott and /dev/null differ
diff --git a/tests/sample-uploads/wordproc.rtf b/tests/sample-uploads/wordproc.rtf
deleted file mode 100644 (file)
index aad2c46..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-{\rtf1\ansi\deff0\adeflang1025
-{\fonttbl{\f0\froman\fprq2\fcharset128 Times New Roman;}{\f1\froman\fprq2\fcharset128 Times New Roman;}{\f2\fswiss\fprq2\fcharset128 Arial;}{\f3\fnil\fprq2\fcharset128 DejaVu Sans;}}
-{\colortbl;\red0\green0\blue0;\red128\green128\blue128;}
-{\stylesheet{\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\snext1 Normal;}
-{\s2\sb240\sa120\keepn\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\afs28\lang1081\ltrch\dbch\langfe2052\hich\f2\fs28\lang1033\loch\f2\fs28\lang1033\sbasedon1\snext3 Heading;}
-{\s3\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext3 Body Text;}
-{\s4\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon3\snext4 List;}
-{\s5\sb120\sa120\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ai\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\i\loch\f0\fs24\lang1033\i\sbasedon1\snext5 caption;}
-{\s6\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033\sbasedon1\snext6 Index;}
-}
-{\info{\author Brion }{\creatim\yr2010\mo5\dy10\hr15\min2}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment StarWriter}{\vern3200}}\deftab709
-{\*\pgdsctbl
-{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\pgdscnxt0 Standard;}}
-\paperh15840\paperw12240\margl1134\margr1134\margt1134\margb1134\sectd\sbknone\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
-\pard\plain \ltrpar\s1\cf0{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\rtlch\af3\afs24\lang1081\ltrch\dbch\af3\langfe2052\hich\f0\fs24\lang1033\loch\f0\fs24\lang1033 
-\par }
\ No newline at end of file