aboutsummaryrefslogtreecommitdiff
path: root/engine/tests
diff options
context:
space:
mode:
Diffstat (limited to 'engine/tests')
-rw-r--r--engine/tests/api/access_collections.php290
-rw-r--r--engine/tests/api/annotations.php150
-rw-r--r--engine/tests/api/entity_getter_functions.php2884
-rw-r--r--engine/tests/api/helpers.php705
-rw-r--r--engine/tests/api/metadata.php230
-rw-r--r--engine/tests/api/metadata_cache.php176
-rw-r--r--engine/tests/api/metastrings.php217
-rw-r--r--engine/tests/api/output.php74
-rw-r--r--engine/tests/api/plugins.php299
-rw-r--r--engine/tests/api/river.php21
-rw-r--r--engine/tests/elgg_unit_test.php29
-rw-r--r--engine/tests/objects/entities.php423
-rw-r--r--engine/tests/objects/filestore.php100
-rw-r--r--engine/tests/objects/objects.php306
-rw-r--r--engine/tests/objects/sites.php77
-rw-r--r--engine/tests/objects/users.php250
-rw-r--r--engine/tests/regression/trac_bugs.php405
-rw-r--r--engine/tests/services/api.php324
-rw-r--r--engine/tests/suite.php53
-rw-r--r--engine/tests/test_files/output/autop/block-a.exp.norun.html6
-rw-r--r--engine/tests/test_files/output/autop/block-a.in.norun.html9
-rw-r--r--engine/tests/test_files/output/autop/domdoc_exp.html46
-rw-r--r--engine/tests/test_files/output/autop/domdoc_in.html80
-rw-r--r--engine/tests/test_files/output/autop/typical-post.exp.html84
-rw-r--r--engine/tests/test_files/output/autop/typical-post.in.html89
-rw-r--r--engine/tests/test_files/output/autop/wp-welcome.exp.html22
-rw-r--r--engine/tests/test_files/output/autop/wp-welcome.in.html25
-rw-r--r--engine/tests/test_files/output/autop/wpautop-fails.exp.html31
-rw-r--r--engine/tests/test_files/output/autop/wpautop-fails.in.html41
-rw-r--r--engine/tests/test_files/output/autop/wysiwyg-test.exp.html51
-rw-r--r--engine/tests/test_files/output/autop/wysiwyg-test.in.html79
-rw-r--r--engine/tests/test_files/plugin_17/manifest.xml10
-rw-r--r--engine/tests/test_files/plugin_17/start.php0
-rw-r--r--engine/tests/test_files/plugin_18/manifest.xml108
-rw-r--r--engine/tests/test_files/plugin_18/start.php0
-rw-r--r--engine/tests/test_files/xxe/external_entity.txt1
-rw-r--r--engine/tests/test_files/xxe/request.xml8
-rw-r--r--engine/tests/test_skeleton.php55
38 files changed, 7758 insertions, 0 deletions
diff --git a/engine/tests/api/access_collections.php b/engine/tests/api/access_collections.php
new file mode 100644
index 000000000..4acfae596
--- /dev/null
+++ b/engine/tests/api/access_collections.php
@@ -0,0 +1,290 @@
+<?php
+/**
+ * Access Collections tests
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreAccessCollectionsTest extends ElggCoreUnitTest {
+
+ /**
+ * Called before each test object.
+ */
+ public function __construct() {
+ parent::__construct();
+
+ $this->dbPrefix = get_config("dbprefix");
+
+ $user = new ElggUser();
+ $user->username = 'test_user_' . rand();
+ $user->email = 'fake_email@fake.com' . rand();
+ $user->name = 'fake user';
+ $user->access_id = ACCESS_PUBLIC;
+ $user->salt = generate_random_cleartext_password();
+ $user->password = generate_user_password($user, rand());
+ $user->owner_guid = 0;
+ $user->container_guid = 0;
+ $user->save();
+
+ $this->user = $user;
+ }
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ // do not allow SimpleTest to interpret Elgg notices as exceptions
+ $this->swallowErrors();
+ }
+
+ /**
+ * Called after each test object.
+ */
+ public function __destruct() {
+ // all __destruct() code should go above here
+ $this->user->delete();
+ parent::__destruct();
+ }
+
+ public function testCreateGetDeleteACL() {
+
+ $acl_name = 'test access collection';
+ $acl_id = create_access_collection($acl_name);
+
+ $this->assertTrue(is_int($acl_id));
+
+ $q = "SELECT * FROM {$this->dbPrefix}access_collections WHERE id = $acl_id";
+ $acl = get_data_row($q);
+
+ $this->assertEqual($acl->id, $acl_id);
+
+ if ($acl) {
+ $this->assertEqual($acl->name, $acl_name);
+
+ $result = delete_access_collection($acl_id);
+ $this->assertTrue($result);
+
+ $q = "SELECT * FROM {$this->dbPrefix}access_collections WHERE id = $acl_id";
+ $data = get_data($q);
+ $this->assertIdentical(array(), $data);
+ }
+ }
+
+ public function testAddRemoveUserToACL() {
+ $acl_id = create_access_collection('test acl');
+
+ $result = add_user_to_access_collection($this->user->guid, $acl_id);
+ $this->assertTrue($result);
+
+ if ($result) {
+ $result = remove_user_from_access_collection($this->user->guid, $acl_id);
+ $this->assertIdentical(true, $result);
+ }
+
+ delete_access_collection($acl_id);
+ }
+
+ public function testUpdateACL() {
+ // another fake user to test with
+ $user = new ElggUser();
+ $user->username = 'test_user_' . rand();
+ $user->email = 'fake_email@fake.com' . rand();
+ $user->name = 'fake user';
+ $user->access_id = ACCESS_PUBLIC;
+ $user->salt = generate_random_cleartext_password();
+ $user->password = generate_user_password($user, rand());
+ $user->owner_guid = 0;
+ $user->container_guid = 0;
+ $user->save();
+
+ $acl_id = create_access_collection('test acl');
+
+ $member_lists = array(
+ // adding
+ array(
+ $this->user->guid,
+ $user->guid
+ ),
+ // removing one, keeping one.
+ array(
+ $user->guid
+ ),
+ // removing one, adding one
+ array(
+ $this->user->guid,
+ ),
+ // removing all.
+ array()
+ );
+
+ foreach ($member_lists as $members) {
+ $result = update_access_collection($acl_id, $members);
+ $this->assertTrue($result);
+
+ if ($result) {
+ $q = "SELECT * FROM {$this->dbPrefix}access_collection_membership
+ WHERE access_collection_id = $acl_id";
+ $data = get_data($q);
+
+ if (count($members) == 0) {
+ $this->assertFalse($data);
+ } else {
+ $this->assertEqual(count($members), count($data));
+ }
+ foreach ($data as $row) {
+ $this->assertTrue(in_array($row->user_guid, $members));
+ }
+ }
+ }
+
+ delete_access_collection($acl_id);
+ $user->delete();
+ }
+
+ public function testCanEditACL() {
+ $acl_id = create_access_collection('test acl', $this->user->guid);
+
+ // should be true since it's the owner
+ $result = can_edit_access_collection($acl_id, $this->user->guid);
+ $this->assertTrue($result);
+
+ // should be true since IA is on.
+ $ia = elgg_set_ignore_access(true);
+ $result = can_edit_access_collection($acl_id);
+ $this->assertTrue($result);
+ elgg_set_ignore_access($ia);
+
+ // should be false since IA is off
+ $ia = elgg_set_ignore_access(false);
+ $result = can_edit_access_collection($acl_id);
+ $this->assertFalse($result);
+ elgg_set_ignore_access($ia);
+
+ delete_access_collection($acl_id);
+ }
+
+ public function testCanEditACLHook() {
+ // if only we supported closures!
+ global $acl_test_info;
+
+ $acl_id = create_access_collection('test acl');
+
+ $acl_test_info = array(
+ 'acl_id' => $acl_id,
+ 'user' => $this->user
+ );
+
+ function test_acl_access_hook($hook, $type, $value, $params) {
+ global $acl_test_info;
+ if ($params['user_id'] == $acl_test_info['user']->guid) {
+ $acl = get_access_collection($acl_test_info['acl_id']);
+ $value[$acl->id] = $acl->name;
+ }
+
+ return $value;
+ }
+
+ elgg_register_plugin_hook_handler('access:collections:write', 'all', 'test_acl_access_hook');
+
+ // enable security since we usually run as admin
+ $ia = elgg_set_ignore_access(false);
+ $result = can_edit_access_collection($acl_id, $this->user->guid);
+ $this->assertTrue($result);
+ $ia = elgg_set_ignore_access($ia);
+
+ elgg_unregister_plugin_hook_handler('access:collections:write', 'all', 'test_acl_access_hook');
+
+ delete_access_collection($acl_id);
+ }
+
+ // groups interface
+ // only runs if the groups plugin is enabled because implementation is split between
+ // core and the plugin.
+ public function testCreateDeleteGroupACL() {
+ if (!elgg_is_active_plugin('groups')) {
+ return;
+ }
+
+ $group = new ElggGroup();
+ $group->name = 'Test group';
+ $group->save();
+ $acl = get_access_collection($group->group_acl);
+
+ // ACLs are owned by groups
+ $this->assertEqual($acl->owner_guid, $group->guid);
+
+ // removing group and acl
+ $this->assertTrue($group->delete());
+
+ $acl = get_access_collection($group->group_acl);
+ $this->assertFalse($acl);
+
+ $group->delete();
+ }
+
+ public function testJoinLeaveGroupACL() {
+ if (!elgg_is_active_plugin('groups')) {
+ return;
+ }
+
+ $group = new ElggGroup();
+ $group->name = 'Test group';
+ $group->save();
+
+ $result = $group->join($this->user);
+ $this->assertTrue($result);
+
+ // disable security since we run as admin
+ $ia = elgg_set_ignore_access(false);
+
+ // need to set the page owner to emulate being in a group context.
+ // this is kinda hacky.
+ elgg_set_page_owner_guid($group->getGUID());
+
+ if ($result) {
+ $can_edit = can_edit_access_collection($group->group_acl, $this->user->guid);
+ $this->assertTrue($can_edit);
+ }
+
+ $result = $group->leave($this->user);
+ $this->assertTrue($result);
+
+ if ($result) {
+ $can_edit = can_edit_access_collection($group->group_acl, $this->user->guid);
+ $this->assertFalse($can_edit);
+ }
+
+ elgg_set_ignore_access($ia);
+
+ $group->delete();
+ }
+
+ public function testAccessCaching() {
+ // create a new user to check against
+ $user = new ElggUser();
+ $user->username = 'access_test_user';
+ $user->save();
+
+ foreach (array('get_access_list', 'get_access_array') as $func) {
+ $cache = _elgg_get_access_cache();
+ $cache->clear();
+
+ // admin users run tests, so disable access
+ elgg_set_ignore_access(true);
+ $access = $func($user->getGUID());
+
+ elgg_set_ignore_access(false);
+ $access2 = $func($user->getGUID());
+ $this->assertNotEqual($access, $access2, "Access test for $func");
+ }
+
+ $user->delete();
+ }
+}
diff --git a/engine/tests/api/annotations.php b/engine/tests/api/annotations.php
new file mode 100644
index 000000000..c0b0687cc
--- /dev/null
+++ b/engine/tests/api/annotations.php
@@ -0,0 +1,150 @@
+<?php
+/**
+ * Elgg Test annotation api
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreAnnotationAPITest extends ElggCoreUnitTest {
+ protected $metastrings;
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+ $this->object = new ElggObject();
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ // do not allow SimpleTest to interpret Elgg notices as exceptions
+ $this->swallowErrors();
+
+ unset($this->object);
+ }
+
+ public function testElggGetAnnotationsCount() {
+ $this->object->title = 'Annotation Unit Test';
+ $this->object->save();
+
+ $guid = $this->object->getGUID();
+ create_annotation($guid, 'tested', 'tested1', 'text', 0, ACCESS_PUBLIC);
+ create_annotation($guid, 'tested', 'tested2', 'text', 0, ACCESS_PUBLIC);
+
+ $count = (int)elgg_get_annotations(array(
+ 'annotation_names' => array('tested'),
+ 'guid' => $guid,
+ 'count' => true,
+ ));
+
+ $this->assertIdentical($count, 2);
+
+ $this->object->delete();
+ }
+
+ public function testElggDeleteAnnotations() {
+ $e = new ElggObject();
+ $e->save();
+
+ for ($i=0; $i<30; $i++) {
+ $e->annotate('test_annotation', rand(0,10000));
+ }
+
+ $options = array(
+ 'guid' => $e->getGUID(),
+ 'limit' => 0
+ );
+
+ $annotations = elgg_get_annotations($options);
+ $this->assertIdentical(30, count($annotations));
+
+ $this->assertTrue(elgg_delete_annotations($options));
+
+ $annotations = elgg_get_annotations($options);
+ $this->assertTrue(empty($annotations));
+
+ // nothing to delete so null returned
+ $this->assertNull(elgg_delete_annotations($options));
+
+ $this->assertTrue($e->delete());
+ }
+
+ public function testElggDisableAnnotations() {
+ $e = new ElggObject();
+ $e->save();
+
+ for ($i=0; $i<30; $i++) {
+ $e->annotate('test_annotation', rand(0,10000));
+ }
+
+ $options = array(
+ 'guid' => $e->getGUID(),
+ 'limit' => 0
+ );
+
+ $this->assertTrue(elgg_disable_annotations($options));
+
+ $annotations = elgg_get_annotations($options);
+ $this->assertTrue(empty($annotations));
+
+ access_show_hidden_entities(true);
+ $annotations = elgg_get_annotations($options);
+ $this->assertIdentical(30, count($annotations));
+ access_show_hidden_entities(false);
+
+ $this->assertTrue($e->delete());
+ }
+
+ public function testElggEnableAnnotations() {
+ $e = new ElggObject();
+ $e->save();
+
+ for ($i=0; $i<30; $i++) {
+ $e->annotate('test_annotation', rand(0,10000));
+ }
+
+ $options = array(
+ 'guid' => $e->getGUID(),
+ 'limit' => 0
+ );
+
+ $this->assertTrue(elgg_disable_annotations($options));
+
+ // cannot see any annotations so returns null
+ $this->assertNull(elgg_enable_annotations($options));
+
+ access_show_hidden_entities(true);
+ $this->assertTrue(elgg_enable_annotations($options));
+ access_show_hidden_entities(false);
+
+ $annotations = elgg_get_annotations($options);
+ $this->assertIdentical(30, count($annotations));
+
+ $this->assertTrue($e->delete());
+ }
+
+ public function testElggAnnotationExists() {
+ $e = new ElggObject();
+ $e->save();
+ $guid = $e->getGUID();
+
+ $this->assertFalse(elgg_annotation_exists($guid, 'test_annotation'));
+
+ $e->annotate('test_annotation', rand(0, 10000));
+ $this->assertTrue(elgg_annotation_exists($guid, 'test_annotation'));
+ // this metastring should always exist but an annotation of this name should not
+ $this->assertFalse(elgg_annotation_exists($guid, 'email'));
+
+ $options = array(
+ 'guid' => $guid,
+ 'limit' => 0
+ );
+ $this->assertTrue(elgg_disable_annotations($options));
+ $this->assertTrue(elgg_annotation_exists($guid, 'test_annotation'));
+
+ $this->assertTrue($e->delete());
+ $this->assertFalse(elgg_annotation_exists($guid, 'test_annotation'));
+ }
+}
diff --git a/engine/tests/api/entity_getter_functions.php b/engine/tests/api/entity_getter_functions.php
new file mode 100644
index 000000000..fef9dc0c5
--- /dev/null
+++ b/engine/tests/api/entity_getter_functions.php
@@ -0,0 +1,2884 @@
+<?php
+
+/**
+ * Elgg Test Entity Getter Functions
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest {
+ /**
+ * Called before each test object.
+ */
+ public function __construct() {
+ elgg_set_ignore_access(TRUE);
+ $this->entities = array();
+ $this->subtypes = array(
+ 'object' => array(),
+ 'user' => array(),
+ 'group' => array(),
+ //'site' => array()
+ );
+
+ // sites are a bit wonky. Don't use them just now.
+ $this->types = array('object', 'user', 'group');
+
+ // create some fun objects to play with.
+ // 5 with random subtypes
+ for ($i=0; $i<5; $i++) {
+ $subtype = 'test_object_subtype_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->save();
+
+ $this->entities[] = $e;
+ $this->subtypes['object'][] = $subtype;
+ }
+
+ // and users
+ for ($i=0; $i<5; $i++) {
+ $subtype = "test_user_subtype_" . rand();
+ $e = new ElggUser();
+ $e->username = "test_user_" . rand();
+ $e->subtype = $subtype;
+ $e->save();
+
+ $this->entities[] = $e;
+ $this->subtypes['user'][] = $subtype;
+ }
+
+ // and groups
+ for ($i=0; $i<5; $i++) {
+ $subtype = "test_group_subtype_" . rand();
+ $e = new ElggGroup();
+ $e->subtype = $subtype;
+ $e->save();
+
+ $this->entities[] = $e;
+ $this->subtypes['group'][] = $subtype;
+ }
+
+ parent::__construct();
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function setUp() {
+ return TRUE;
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ return TRUE;
+ }
+
+ /**
+ * Called after each test object.
+ */
+ public function __destruct() {
+ global $CONFIG;
+
+ $this->swallowErrors();
+ foreach ($this->entities as $e) {
+ $e->delete();
+ }
+
+ // manually remove subtype entries since there is no way
+ // to using the API.
+ $subtype_arr = array();
+ foreach ($this->subtypes as $type => $subtypes) {
+ foreach ($subtypes as $subtype) {
+ $subtype_arr[] = "'$subtype'";
+ }
+ }
+
+ $subtype_str = implode(',', $subtype_arr);
+ $q = "DELETE FROM {$CONFIG->dbprefix}entity_subtypes WHERE subtype IN ($subtype_str)";
+ delete_data($q);
+
+ parent::__destruct();
+ }
+
+
+ /*************************************************
+ * Helpers for getting random types and subtypes *
+ *************************************************/
+
+ /**
+ * Get a random valid subtype
+ *
+ * @param int $num
+ * @return array
+ */
+ public function getRandomValidTypes($num = 1) {
+ $r = array();
+
+ for ($i=1; $i<=$num; $i++) {
+ do {
+ $t = $this->types[array_rand($this->types)];
+ } while (in_array($t, $r) && count($r) < count($this->types));
+
+ $r[] = $t;
+ }
+
+ shuffle($r);
+ return $r;
+ }
+
+ /**
+ * Get a random valid subtype (that we just created)
+ *
+ * @param array $type Type of objects to return valid subtypes for.
+ * @param int $num of subtypes.
+ *
+ * @return array
+ */
+ public function getRandomValidSubtypes(array $types, $num = 1) {
+ $r = array();
+
+ for ($i=1; $i<=$num; $i++) {
+ do {
+ // make sure at least one subtype of each type is returned.
+ if ($i-1 < count($types)) {
+ $type = $types[$i-1];
+ } else {
+ $type = $types[array_rand($types)];
+ }
+
+ $k = array_rand($this->subtypes[$type]);
+ $t = $this->subtypes[$type][$k];
+ } while (in_array($t, $r));
+
+ $r[] = $t;
+ }
+
+ shuffle($r);
+ return $r;
+ }
+
+ /**
+ * Return an array of invalid strings for type or subtypes.
+ *
+ * @param int $num
+ * @return arr
+ */
+ public function getRandomInvalids($num = 1) {
+ $r = array();
+
+ for ($i=1; $i<=$num; $i++) {
+ $r[] = 'random_invalid_' . rand();
+ }
+
+ return $r;
+ }
+
+ /**
+ * Get a mix of valid and invalid types
+ *
+ * @param int $num
+ * @return array
+ */
+ public function getRandomMixedTypes($num = 2) {
+ $have_valid = $have_invalid = false;
+ $r = array();
+
+ // need at least one of each type.
+ $valid_n = rand(1, $num-1);
+ $r = array_merge($r, $this->getRandomValidTypes($valid_n));
+ $r = array_merge($r, $this->getRandomInvalids($num - $valid_n));
+
+ shuffle($r);
+ return $r;
+ }
+
+ /**
+ * Get random mix of valid and invalid subtypes for types given.
+ *
+ * @param array $types
+ * @param int $num
+ * @return array
+ */
+ public function getRandomMixedSubtypes(array $types, $num = 2) {
+ $types_c = count($types);
+ $r = array();
+
+ // this can be more efficient but I'm very sleepy...
+
+ // want at least one of valid and invalid of each type sent.
+ for ($i=0; $i < $types_c && $num > 0; $i++) {
+ // make sure we have a valid and invalid for each type
+ if (true) {
+ $type = $types[$i];
+ $r = array_merge($r, $this->getRandomValidSubtypes(array($type), 1));
+ $r = array_merge($r, $this->getRandomInvalids(1));
+
+ $num -= 2;
+ }
+ }
+
+ if ($num > 0) {
+ $valid_n = rand(1, $num);
+ $r = array_merge($r, $this->getRandomValidSubtypes($types, $valid_n));
+ $r = array_merge($r, $this->getRandomInvalids($num - $valid_n));
+ }
+
+ //shuffle($r);
+ return $r;
+ }
+
+ /**
+ * Creates random annotations on $entity
+ *
+ * @param ElggEntity $entity
+ * @param int $max
+ */
+ public function createRandomAnnotations($entity, $max = 1) {
+ $annotations = array();
+ for ($i=0; $i<$max; $i++) {
+ $name = 'test_annotation_name_' . rand();
+ $value = rand();
+ $id = create_annotation($entity->getGUID(), $name, $value, 'integer', $entity->getGUID());
+ $annotations[] = elgg_get_annotation_from_id($id);
+ }
+
+ return $annotations;
+ }
+
+
+ /***********************************
+ * TYPE TESTS
+ ***********************************
+ * check for getting a valid type in all ways we can.
+ * note that these aren't wonderful tests as there will be
+ * existing entities so we can't test against the ones we just created.
+ * So these just test that some are returned and match the type(s) requested.
+ * It could definitely be the case that the first 10 entities retrieved are all
+ * objects. Maybe best to limit to 4 and group by type.
+ */
+ public function testElggAPIGettersValidTypeUsingType() {
+ $type_arr = $this->getRandomValidTypes();
+ $type = $type_arr[0];
+ $options = array(
+ 'type' => $type,
+ 'group_by' => 'e.type'
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ // should only ever return one object because of group by
+ $this->assertIdentical(count($es), 1);
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $type_arr));
+ }
+ }
+
+ public function testElggAPIGettersValidTypeUsingTypesAsString() {
+ $type_arr = $this->getRandomValidTypes();
+ $type = $type_arr[0];
+ $options = array(
+ 'types' => $type,
+ 'group_by' => 'e.type'
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ // should only ever return one object because of group by
+ $this->assertIdentical(count($es), 1);
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $type_arr));
+ }
+ }
+
+ public function testElggAPIGettersValidTypeUsingTypesAsArray() {
+ $type_arr = $this->getRandomValidTypes();
+ $type = $type_arr[0];
+ $options = array(
+ 'types' => $type_arr,
+ 'group_by' => 'e.type'
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ // should only ever return one object because of group by
+ $this->assertIdentical(count($es), 1);
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $type_arr));
+ }
+ }
+
+ public function testElggAPIGettersValidTypeUsingTypesAsArrayPlural() {
+ $num = 2;
+ $types = $this->getRandomValidTypes($num);
+ $options = array(
+ 'types' => $types,
+ 'group_by' => 'e.type'
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ // one of object and one of group
+ $this->assertIdentical(count($es), $num);
+
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $types));
+ }
+ }
+
+
+
+ /*
+ * Test mixed valid and invalid types.
+ */
+
+
+ public function testElggAPIGettersValidAndInvalidTypes() {
+ //@todo replace this with $this->getRandomMixedTypes().
+ $t = $this->getRandomValidTypes();
+ $valid = $t[0];
+
+ $t = $this->getRandomInvalids();
+ $invalid = $t[0];
+ $options = array(
+ 'types' => array($invalid, $valid),
+ 'group_by' => 'e.type'
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ // should only ever return one object because of group by
+ $this->assertIdentical(count($es), 1);
+ $this->assertIdentical($es[0]->getType(), $valid);
+ }
+
+ public function testElggAPIGettersValidAndInvalidTypesPlural() {
+ $valid_num = 2;
+ $invalid_num = 3;
+ $valid = $this->getRandomValidTypes($valid_num);
+ $invalid = $this->getRandomInvalids($invalid_num);
+
+ $types = array();
+ foreach ($valid as $t) {
+ $types[] = $t;
+ }
+
+ foreach ($invalid as $t) {
+ $types[] = $t;
+ }
+
+ shuffle($types);
+ $options = array(
+ 'types' => $types,
+ 'group_by' => 'e.type'
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ // should only ever return one object because of group by
+ $this->assertIdentical(count($es), $valid_num);
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $valid));
+ }
+ }
+
+
+
+ /**************************************
+ * SUBTYPE TESTS
+ **************************************
+ *
+ * Here we can use the subtypes we created to test more finely.
+ * Subtypes are bound to types, so we must pass a type.
+ * This is where the fun logic starts.
+ */
+
+ public function testElggAPIGettersValidSubtypeUsingSubtypeSingularType() {
+ $types = $this->getRandomValidTypes();
+ $subtypes = $this->getRandomValidSubtypes($types);
+ $subtype = $subtypes[0];
+
+ $options = array(
+ 'types' => $types,
+ 'subtype' => $subtype
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ $this->assertIdentical(count($es), 1);
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $types));
+ $this->assertTrue(in_array($e->getSubtype(), $subtypes));
+ }
+ }
+
+ public function testElggAPIGettersValidSubtypeUsingSubtypesAsStringSingularType() {
+ $types = $this->getRandomValidTypes();
+ $subtypes = $this->getRandomValidSubtypes($types);
+ $subtype = $subtypes[0];
+
+ $options = array(
+ 'types' => $types,
+ 'subtypes' => $subtype
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ $this->assertIdentical(count($es), 1);
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $types));
+ $this->assertTrue(in_array($e->getSubtype(), $subtypes));
+ }
+ }
+
+ public function testElggAPIGettersValidSubtypeUsingSubtypesAsArraySingularType() {
+ $types = $this->getRandomValidTypes();
+ $subtypes = $this->getRandomValidSubtypes($types);
+
+ $options = array(
+ 'types' => $types,
+ 'subtypes' => $subtypes
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ $this->assertIdentical(count($es), 1);
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $types));
+ $this->assertTrue(in_array($e->getSubtype(), $subtypes));
+ }
+ }
+
+ public function testElggAPIGettersValidSubtypeUsingPluralSubtypesSingularType() {
+ $subtype_num = 2;
+ $types = $this->getRandomValidTypes();
+ $subtypes = $this->getRandomValidSubtypes($types, $subtype_num);
+
+ $options = array(
+ 'types' => $types,
+ 'subtypes' => $subtypes
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ $this->assertIdentical(count($es), $subtype_num);
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $types));
+ $this->assertTrue(in_array($e->getSubtype(), $subtypes));
+ }
+ }
+
+
+ /*
+ Because we're looking for type OR subtype (sorta)
+ it's possible that we've pulled in entities that aren't
+ of the subtype we've requested.
+ THIS COMBINATION MAKES LITTLE SENSE.
+ There is no mechanism in elgg to retrieve a subtype without a type, so
+ this combo gets trimmed down to only including subtypes that are valid to
+ each particular type.
+ FOR THE LOVE OF ALL GOOD PLEASE JUST USE TYPE_SUBTYPE_PAIRS!
+ */
+ public function testElggAPIGettersValidSubtypeUsingPluralSubtypesPluralTypes() {
+ $type_num = 2;
+ $subtype_num = 2;
+ $types = $this->getRandomValidTypes($type_num);
+ $subtypes = $this->getRandomValidSubtypes($types, $subtype_num);
+
+ $options = array(
+ 'types' => $types,
+ 'subtypes' => $subtypes
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ // this will unset all invalid subtypes for each type that that only
+ // one entity exists of each.
+ $this->assertIdentical(count($es), $subtype_num);
+ foreach ($es as $e) {
+ // entities must at least be in the type.
+ $this->assertTrue(in_array($e->getType(), $types));
+
+ // test that this is a valid subtype for the entity type.
+ $this->assertTrue(in_array($e->getSubtype(), $this->subtypes[$e->getType()]));
+ }
+ }
+
+ /*
+ * This combination will remove all invalid subtypes for this type.
+ */
+ public function testElggAPIGettersValidSubtypeUsingPluralMixedSubtypesSingleType() {
+ $type_num = 1;
+ $subtype_num = 2;
+ $types = $this->getRandomValidTypes($type_num);
+
+
+ //@todo replace this with $this->getRandomMixedSubtypes()
+ // we want this to return an invalid subtype for the returned type.
+ $subtype_types = $types;
+ $i = 1;
+ while ($i <= $subtype_num) {
+ $type = $this->types[$i-1];
+
+ if (!in_array($type, $subtype_types)) {
+ $subtype_types[] = $type;
+ }
+ $i++;
+ }
+
+ $subtypes = $this->getRandomValidSubtypes($subtype_types, $type_num);
+
+ $options = array(
+ 'types' => $types,
+ 'subtypes' => $subtypes
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ // this will unset all invalid subtypes for each type that that only
+ // one entity exists of each.
+ $this->assertIdentical(count($es), $type_num);
+ foreach ($es as $e) {
+ // entities must at least be in the type.
+ $this->assertTrue(in_array($e->getType(), $types));
+
+ // test that this is a valid subtype for the entity type.
+ $this->assertTrue(in_array($e->getSubtype(), $this->subtypes[$e->getType()]));
+ }
+ }
+
+
+ /***************************
+ * TYPE_SUBTYPE_PAIRS
+ ***************************/
+
+ /**
+ * Valid type, valid subtype pairs
+ */
+ public function testElggAPIGettersTSPValidTypeValidSubtype() {
+ $type_num = 1;
+ $subtype_num = 1;
+ $types = $this->getRandomValidTypes($type_num);
+ $subtypes = $this->getRandomValidSubtypes($types, $subtype_num);
+
+ $pair = array($types[0] => $subtypes[0]);
+
+ $options = array(
+ 'type_subtype_pairs' => $pair
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ $this->assertIdentical(count($es), $type_num);
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $types));
+ $this->assertTrue(in_array($e->getSubtype(), $subtypes));
+ }
+ }
+
+ /**
+ * Valid type, multiple valid subtypes
+ */
+ public function testElggAPIGettersTSPValidTypeValidPluralSubtype() {
+ $type_num = 1;
+ $subtype_num = 3;
+ $types = $this->getRandomValidTypes($type_num);
+ $subtypes = $this->getRandomValidSubtypes($types, $subtype_num);
+
+ $pair = array($types[0] => $subtypes);
+
+ $options = array(
+ 'type_subtype_pairs' => $pair
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ $this->assertIdentical(count($es), $subtype_num);
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $types));
+ $this->assertTrue(in_array($e->getSubtype(), $subtypes));
+ }
+ }
+
+ /**
+ * Valid type, both valid and invalid subtypes
+ */
+ public function testElggAPIGettersTSPValidTypeMixedPluralSubtype() {
+ $type_num = 1;
+ $valid_subtype_num = 2;
+ $types = $this->getRandomValidTypes($type_num);
+ $valid = $this->getRandomValidSubtypes($types, $valid_subtype_num);
+ $invalid = $this->getRandomInvalids();
+
+ $subtypes = array_merge($valid, $invalid);
+ shuffle($subtypes);
+
+ $pair = array($types[0] => $subtypes);
+
+ $options = array(
+ 'type_subtype_pairs' => $pair
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertIsA($es, 'array');
+
+ $this->assertIdentical(count($es), $valid_subtype_num);
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->getType(), $types));
+ $this->assertTrue(in_array($e->getSubtype(), $valid));
+ }
+ }
+
+
+ /****************************
+ * FALSE-RETURNING TESTS
+ ****************************
+ * The original bug corrected returned
+ * all entities when invalid subtypes were passed.
+ * Because there's a huge numer of combinations that
+ * return entities, I'm only writing tests for
+ * things that should return false.
+ *
+ * I'm leaving the above in case anyone is inspired to
+ * write out the rest of the possible combinations
+ */
+
+
+ /**
+ * Test invalid types with singular 'type'.
+ */
+ public function testElggApiGettersInvalidTypeUsingType() {
+ $type_arr = $this->getRandomInvalids();
+ $type = $type_arr[0];
+
+ $options = array(
+ 'type' => $type
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ /**
+ * Test invalid types with plural 'types'.
+ */
+ public function testElggApiGettersInvalidTypeUsingTypesAsString() {
+ $type_arr = $this->getRandomInvalids();
+ $type = $type_arr[0];
+
+ $options = array(
+ 'types' => $type
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ /**
+ * Test invalid types with plural 'types' and an array of a single type
+ */
+ public function testElggApiGettersInvalidTypeUsingTypesAsArray() {
+ $type_arr = $this->getRandomInvalids(1);
+
+ $options = array(
+ 'types' => $type_arr
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ /**
+ * Test invalid types with plural 'types' and an array of a two types
+ */
+ public function testElggApiGettersInvalidTypes() {
+ $type_arr = $this->getRandomInvalids(2);
+
+ $options = array(
+ 'types' => $type_arr
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ public function testElggApiGettersInvalidSubtypeValidType() {
+ $type_num = 1;
+ $subtype_num = 1;
+ $types = $this->getRandomValidTypes($type_num);
+ $subtypes = $this->getRandomInvalids($subtype_num);
+
+ $options = array(
+ 'types' => $types,
+ 'subtypes' => $subtypes
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ public function testElggApiGettersInvalidSubtypeValidTypes() {
+ $type_num = 2;
+ $subtype_num = 1;
+ $types = $this->getRandomValidTypes($type_num);
+ $subtypes = $this->getRandomInvalids($subtype_num);
+
+ $options = array(
+ 'types' => $types,
+ 'subtypes' => $subtypes
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ public function testElggApiGettersInvalidSubtypesValidType() {
+ $type_num = 1;
+ $subtype_num = 2;
+ $types = $this->getRandomValidTypes($type_num);
+ $subtypes = $this->getRandomInvalids($subtype_num);
+
+ $options = array(
+ 'types' => $types,
+ 'subtypes' => $subtypes
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ public function testElggApiGettersInvalidSubtypesValidTypes() {
+ $type_num = 2;
+ $subtype_num = 2;
+ $types = $this->getRandomValidTypes($type_num);
+ $subtypes = $this->getRandomInvalids($subtype_num);
+
+ $options = array(
+ 'types' => $types,
+ 'subtypes' => $subtypes
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ public function testElggApiGettersTSPInvalidType() {
+ $type_num = 1;
+ $types = $this->getRandomInvalids($type_num);
+
+ $pair = array();
+
+ foreach ($types as $type) {
+ $pair[$type] = NULL;
+ }
+
+ $options = array(
+ 'type_subtype_pairs' => $pair
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ public function testElggApiGettersTSPInvalidTypes() {
+ $type_num = 2;
+ $types = $this->getRandomInvalids($type_num);
+
+ $pair = array();
+ foreach ($types as $type) {
+ $pair[$type] = NULL;
+ }
+
+ $options = array(
+ 'type_subtype_pairs' => $pair
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ public function testElggApiGettersTSPValidTypeInvalidSubtype() {
+ $type_num = 1;
+ $subtype_num = 1;
+ $types = $this->getRandomValidTypes($type_num);
+ $subtypes = $this->getRandomInvalids($subtype_num);
+
+ $pair = array($types[0] => $subtypes[0]);
+
+ $options = array(
+ 'type_subtype_pairs' => $pair
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ public function testElggApiGettersTSPValidTypeInvalidSubtypes() {
+ $type_num = 1;
+ $subtype_num = 2;
+ $types = $this->getRandomValidTypes($type_num);
+ $subtypes = $this->getRandomInvalids($subtype_num);
+
+ $pair = array($types[0] => array($subtypes[0], $subtypes[0]));
+
+ $options = array(
+ 'type_subtype_pairs' => $pair
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+ public function testElggApiGettersTSPValidTypesInvalidSubtypes() {
+ $type_num = 2;
+ $subtype_num = 2;
+ $types = $this->getRandomValidTypes($type_num);
+ $subtypes = $this->getRandomInvalids($subtype_num);
+
+ $pair = array();
+ foreach ($types as $type) {
+ $pair[$type] = $subtypes;
+ }
+
+ $options = array(
+ 'type_subtype_pairs' => $pair
+ );
+
+ $es = elgg_get_entities($options);
+ $this->assertFalse($es);
+ }
+
+
+
+
+
+
+ public function testElggApiGettersEntityNoSubtype() {
+ // create an entity we can later delete.
+ // order by guid and limit by 1 should == this entity.
+
+ $e = new ElggObject();
+ $e->save();
+
+ $options = array(
+ 'type' => 'object',
+ 'limit' => 1,
+ 'order_by' => 'guid desc'
+ );
+
+ // grab ourself again to fill out attributes.
+ $e = get_entity($e->getGUID());
+
+ $entities = elgg_get_entities($options);
+
+ $this->assertEqual(count($entities), 1);
+
+ foreach ($entities as $entity) {
+ $this->assertIdentical($e->getGUID(), $entity->getGUID());
+ }
+
+ $e->delete();
+ }
+
+ public function testElggApiGettersEntityNoValueSubtypeNotSet() {
+ // create an entity we can later delete.
+ // order by time created and limit by 1 should == this entity.
+
+ $e = new ElggObject();
+ $e->save();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => ELGG_ENTITIES_NO_VALUE,
+ 'limit' => 1,
+ 'order_by' => 'guid desc'
+ );
+
+ // grab ourself again to fill out attributes.
+ $e = get_entity($e->getGUID());
+
+ $entities = elgg_get_entities($options);
+
+ $this->assertEqual(count($entities), 1);
+
+ foreach ($entities as $entity) {
+ $this->assertIdentical($e->getGUID(), $entity->getGUID());
+ }
+
+ $e->delete();
+ }
+
+ public function testElggApiGettersEntityNoValueSubtypeSet() {
+ global $CONFIG;
+ // create an entity we can later delete.
+ // order by time created and limit by 1 should == this entity.
+
+ $subtype = 'subtype_' . rand();
+
+ $e_subtype = new ElggObject();
+ $e_subtype->subtype = $subtype;
+ $e_subtype->save();
+
+ $e = new ElggObject();
+ $e->save();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => ELGG_ENTITIES_NO_VALUE,
+ 'limit' => 1,
+ 'order_by' => 'guid desc'
+ );
+
+ // grab ourself again to fill out attributes.
+ $e = get_entity($e->getGUID());
+
+ $entities = elgg_get_entities($options);
+
+ $this->assertEqual(count($entities), 1);
+
+ // this entity should NOT be the entity we just created
+ // and should have no subtype
+ foreach ($entities as $entity) {
+ $this->assertEqual($entity->subtype_id, 0);
+ }
+
+ $e_subtype->delete();
+ $e->delete();
+
+ $q = "DELETE FROM {$CONFIG->dbprefix}entity_subtypes WHERE subtype = '$subtype'";
+ delete_data($q);
+ }
+
+
+
+ /************
+ * METADATA
+ ************/
+
+ //names
+
+ function testElggApiGettersEntityMetadataNameValidSingle() {
+ // create a new entity with a subtype we know
+ // use an existing type so it will clean up automatically
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_name' => $md_name
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 1);
+
+ foreach ($entities as $entity) {
+ $this->assertEqual($entity->getGUID(), $e->getGUID());
+ $this->assertEqual($entity->$md_name, $md_value);
+ }
+
+ $e->delete();
+ }
+
+ function testElggApiGettersEntityMetadataNameValidMultiple() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_names = array();
+
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+ $md_names[] = $md_name;
+ $e_guids = array();
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+ $e_guids[] = $e->getGUID();
+
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+ $md_names[] = $md_name;
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+ $e_guids[] = $e->getGUID();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_names' => $md_names
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 2);
+
+ foreach ($entities as $entity) {
+ $this->assertTrue(in_array($entity->getGUID(), $e_guids));
+ $entity->delete();
+ }
+ }
+
+ function testElggApiGettersEntityMetadataNameInvalidSingle() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+
+ $md_invalid_name = 'test_metadata_name_' . rand();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_name' => $md_invalid_name
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIdentical(array(), $entities);
+
+ $e->delete();
+ }
+
+ function testElggApiGettersEntityMetadataNameInvalidMultiple() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+
+ $md_invalid_names = array();
+ $md_invalid_names[] = 'test_metadata_name_' . rand();
+ $md_invalid_names[] = 'test_metadata_name_' . rand();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_names' => $md_invalid_names
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIdentical(array(), $entities);
+
+ $e->delete();
+ }
+
+
+ function testElggApiGettersEntityMetadataNameMixedMultiple() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_names = array();
+
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+ $md_names[] = $md_name;
+ $e_guids = array();
+
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->$md_name = $md_value;
+ $valid->save();
+ $e_guids[] = $valid->getGUID();
+
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+
+ // add a random invalid name.
+ $md_names[] = 'test_metadata_name_' . rand();
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+ $e_guids[] = $e->getGUID();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_names' => $md_names
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 1);
+
+ foreach ($entities as $entity) {
+ $this->assertEqual($entity->getGUID(), $valid->getGUID());
+ }
+
+ foreach ($e_guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+
+ // values
+ function testElggApiGettersEntityMetadataValueValidSingle() {
+ // create a new entity with a subtype we know
+ // use an existing type so it will clean up automatically
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_value' => $md_value
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 1);
+
+ foreach ($entities as $entity) {
+ $this->assertEqual($entity->getGUID(), $e->getGUID());
+ $this->assertEqual($entity->$md_name, $md_value);
+ }
+
+ $e->delete();
+ }
+
+ function testElggApiGettersEntityMetadataValueValidMultiple() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_values = array();
+
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+ $md_values[] = $md_value;
+ $e_guids = array();
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+ $e_guids[] = $e->getGUID();
+
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+ $md_values[] = $md_value;
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+ $e_guids[] = $e->getGUID();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_values' => $md_values
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 2);
+
+ foreach ($entities as $entity) {
+ $this->assertTrue(in_array($entity->getGUID(), $e_guids));
+ $entity->delete();
+ }
+ }
+
+ function testElggApiGettersEntityMetadataValueInvalidSingle() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+
+ $md_invalid_value = 'test_metadata_value_' . rand();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_value' => $md_invalid_value
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIdentical(array(), $entities);
+
+ $e->delete();
+ }
+
+ function testElggApiGettersEntityMetadataValueInvalidMultiple() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+
+ $md_invalid_values = array();
+ $md_invalid_values[] = 'test_metadata_value_' . rand();
+ $md_invalid_values[] = 'test_metadata_value_' . rand();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_values' => $md_invalid_values
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIdentical(array(), $entities);
+
+ $e->delete();
+ }
+
+
+ function testElggApiGettersEntityMetadataValueMixedMultiple() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_values = array();
+
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+ $md_values[] = $md_value;
+ $e_guids = array();
+
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->$md_name = $md_value;
+ $valid->save();
+ $e_guids[] = $valid->getGUID();
+
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+
+ // add a random invalid value.
+ $md_values[] = 'test_metadata_value_' . rand();
+
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $md_value;
+ $e->save();
+ $e_guids[] = $e->getGUID();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_values' => $md_values
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 1);
+
+ foreach ($entities as $entity) {
+ $this->assertEqual($entity->getGUID(), $valid->getGUID());
+ }
+
+ foreach ($e_guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+
+ // name_value_pairs
+
+
+ function testElggApiGettersEntityMetadataNVPValidNValidVEquals() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+ $guids = array();
+
+ // our target
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->$md_name = $md_value;
+ $valid->save();
+ $guids[] = $valid->getGUID();
+
+ // make some bad ones
+ $invalid_md_name = 'test_metadata_name_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$invalid_md_name = $md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $invalid_md_value = 'test_metadata_value_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $invalid_md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $md_invalid_names = array();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_name_value_pairs' => array(array(
+ 'name' => $md_name,
+ 'value' => $md_value
+ ))
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 1);
+
+ foreach ($entities as $entity) {
+ $this->assertEqual($entity->getGUID(), $valid->getGUID());
+ $this->assertEqual($entity->$md_name, $md_value);
+ $entity->delete();
+ }
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+ function testElggApiGettersEntityMetadataNVPValidNValidVEqualsTriple() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+
+ $md_name2 = 'test_metadata_name_' . rand();
+ $md_value2 = 'test_metadata_value_' . rand();
+
+ $md_name3 = 'test_metadata_name_' . rand();
+ $md_value3 = 'test_metadata_value_' . rand();
+
+ $guids = array();
+
+ // our target
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->$md_name = $md_value;
+ $valid->$md_name2 = $md_value2;
+ $valid->$md_name3 = $md_value3;
+ $valid->save();
+ $guids[] = $valid->getGUID();
+
+ // make some bad ones
+ $invalid_md_name = 'test_metadata_name_' . rand();
+ $invalid_md_name2 = 'test_metadata_name_' . rand();
+ $invalid_md_name3 = 'test_metadata_name_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$invalid_md_name = $md_value;
+ $e->$invalid_md_name2 = $md_value2;
+ $e->$invalid_md_name3 = $md_value3;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $invalid_md_value = 'test_metadata_value_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $invalid_md_value;
+ $e->$md_name2 = $invalid_md_value;
+ $e->$md_name3 = $invalid_md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $md_invalid_names = array();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_name_value_pairs' => array(
+ array(
+ 'name' => $md_name,
+ 'value' => $md_value
+ ),
+ array(
+ 'name' => $md_name2,
+ 'value' => $md_value2
+ ),
+ array(
+ 'name' => $md_name3,
+ 'value' => $md_value3
+ )
+ )
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 1);
+
+ foreach ($entities as $entity) {
+ $this->assertEqual($entity->getGUID(), $valid->getGUID());
+ $this->assertEqual($entity->$md_name, $md_value);
+ $entity->delete();
+ }
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+ function testElggApiGettersEntityMetadataNVPValidNValidVEqualsDouble() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+
+ $md_name2 = 'test_metadata_name_' . rand();
+ $md_value2 = 'test_metadata_value_' . rand();
+
+ $guids = array();
+
+ // our target
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->$md_name = $md_value;
+ $valid->$md_name2 = $md_value2;
+ $valid->save();
+ $guids[] = $valid->getGUID();
+
+ // make some bad ones
+ $invalid_md_name = 'test_metadata_name_' . rand();
+ $invalid_md_name2 = 'test_metadata_name_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$invalid_md_name = $md_value;
+ $e->$invalid_md_name2 = $md_value2;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $invalid_md_value = 'test_metadata_value_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $invalid_md_value;
+ $e->$md_name2 = $invalid_md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $md_invalid_names = array();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_name_value_pairs' => array(
+ array(
+ 'name' => $md_name,
+ 'value' => $md_value
+ ),
+ array(
+ 'name' => $md_name2,
+ 'value' => $md_value2
+ )
+ )
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 1);
+
+ foreach ($entities as $entity) {
+ $this->assertEqual($entity->getGUID(), $valid->getGUID());
+ $this->assertEqual($entity->$md_name, $md_value);
+ $entity->delete();
+ }
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+ // this keeps locking up my database...
+ function xtestElggApiGettersEntityMetadataNVPValidNValidVEqualsStupid() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+
+ $md_name2 = 'test_metadata_name_' . rand();
+ $md_value2 = 'test_metadata_value_' . rand();
+
+ $md_name3 = 'test_metadata_name_' . rand();
+ $md_value3 = 'test_metadata_value_' . rand();
+
+ $md_name3 = 'test_metadata_name_' . rand();
+ $md_value3 = 'test_metadata_value_' . rand();
+
+ $md_name4 = 'test_metadata_name_' . rand();
+ $md_value4 = 'test_metadata_value_' . rand();
+
+ $md_name5 = 'test_metadata_name_' . rand();
+ $md_value5 = 'test_metadata_value_' . rand();
+
+ $guids = array();
+
+ // our target
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->$md_name = $md_value;
+ $valid->$md_name2 = $md_value2;
+ $valid->$md_name3 = $md_value3;
+ $valid->$md_name4 = $md_value4;
+ $valid->$md_name5 = $md_value5;
+ $valid->save();
+ $guids[] = $valid->getGUID();
+
+ // make some bad ones
+ $invalid_md_name = 'test_metadata_name_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$invalid_md_name = $md_value;
+ $e->$md_name2 = $md_value2;
+ $e->$md_name3 = $md_value3;
+ $e->$md_name4 = $md_value4;
+ $e->$md_name5 = $md_value5;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $invalid_md_value = 'test_metadata_value_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $invalid_md_value;
+ $e->$md_name2 = $invalid_md_value;
+ $e->$md_name3 = $invalid_md_value;
+ $e->$md_name4 = $invalid_md_value;
+ $e->$md_name5 = $invalid_md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $md_invalid_names = array();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_name_value_pairs' => array(
+ array(
+ 'name' => $md_name,
+ 'value' => $md_value
+ ),
+ array(
+ 'name' => $md_name2,
+ 'value' => $md_value2
+ ),
+ array(
+ 'name' => $md_name3,
+ 'value' => $md_value3
+ ),
+ array(
+ 'name' => $md_name4,
+ 'value' => $md_value4
+ ),
+ array(
+ 'name' => $md_name5,
+ 'value' => $md_value5
+ ),
+ )
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 1);
+
+ foreach ($entities as $entity) {
+ $this->assertEqual($entity->getGUID(), $valid->getGUID());
+ $this->assertEqual($entity->$md_name, $md_value);
+ $entity->delete();
+ }
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+ /**
+ * Name value pair with valid name and invalid value
+ */
+ function testElggApiGettersEntityMetadataNVPValidNInvalidV() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+ $guids = array();
+
+ // make some bad ones
+ $invalid_md_name = 'test_metadata_name_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$invalid_md_name = $md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $invalid_md_value = 'test_metadata_value_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $invalid_md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $md_invalid_names = array();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_name_value_pairs' => array(array(
+ 'name' => $md_name,
+ 'value' => 'test_metadata_value_' . rand()
+ ))
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIdentical(array(), $entities);
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+ /**
+ * Name value pair with invalid name and valid value
+ */
+ function testElggApiGettersEntityMetadataNVPInvalidNValidV() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+ $guids = array();
+
+ // make some bad ones
+ $invalid_md_name = 'test_metadata_name_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$invalid_md_name = $md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $invalid_md_value = 'test_metadata_value_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $invalid_md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $md_invalid_names = array();
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_name_value_pairs' => array(array(
+ 'name' => 'test_metadata_name_' . rand(),
+ 'value' => $md_value
+ ))
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIdentical(array(), $entities);
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+
+ function testElggApiGettersEntityMetadataNVPValidNValidVOperandIn() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+ $guids = array();
+ $valid_guids = array();
+
+ // our targets
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->$md_name = $md_value;
+ $valid->save();
+ $guids[] = $valid->getGUID();
+ $valid_guids[] = $valid->getGUID();
+
+ $md_name2 = 'test_metadata_name_' . rand();
+ $md_value2 = 'test_metadata_value_' . rand();
+
+ $valid2 = new ElggObject();
+ $valid2->subtype = $subtype;
+ $valid2->$md_name2 = $md_value2;
+ $valid2->save();
+ $guids[] = $valid->getGUID();
+ $valid_guids[] = $valid2->getGUID();
+
+ // make some bad ones
+ $invalid_md_name = 'test_metadata_name_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$invalid_md_name = $md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $invalid_md_value = 'test_metadata_value_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $invalid_md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $md_valid_values = "'$md_value', '$md_value2'";
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_name_value_pairs' => array(
+ array(
+ 'name' => $md_name,
+ 'value' => $md_valid_values,
+ 'operand' => 'IN'
+ ),
+ array(
+ 'name' => $md_name2,
+ 'value' => $md_valid_values,
+ 'operand' => 'IN'
+ ),
+ ),
+ 'metadata_name_value_pairs_operator' => 'OR'
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 2);
+
+ foreach ($entities as $entity) {
+ $this->assertTrue(in_array($entity->getGUID(), $valid_guids));
+ $entity->delete();
+ }
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+ function testElggApiGettersEntityMetadataNVPValidNValidVPlural() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $md_value = 'test_metadata_value_' . rand();
+ $guids = array();
+ $valid_guids = array();
+
+ // our targets
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->$md_name = $md_value;
+ $valid->save();
+ $guids[] = $valid->getGUID();
+ $valid_guids[] = $valid->getGUID();
+
+ $md_name2 = 'test_metadata_name_' . rand();
+ $md_value2 = 'test_metadata_value_' . rand();
+
+ $valid2 = new ElggObject();
+ $valid2->subtype = $subtype;
+ $valid2->$md_name2 = $md_value2;
+ $valid2->save();
+ $guids[] = $valid->getGUID();
+ $valid_guids[] = $valid2->getGUID();
+
+ // make some bad ones
+ $invalid_md_name = 'test_metadata_name_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$invalid_md_name = $md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $invalid_md_value = 'test_metadata_value_' . rand();
+ $e = new ElggObject();
+ $e->subtype = $subtype;
+ $e->$md_name = $invalid_md_value;
+ $e->save();
+ $guids[] = $e->getGUID();
+
+ $md_valid_values = array($md_value, $md_value2);
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_name_value_pairs' => array(
+ array(
+ 'name' => $md_name,
+ 'value' => $md_valid_values,
+ 'operand' => 'IN'
+ ),
+ array(
+ 'name' => $md_name2,
+ 'value' => $md_valid_values,
+ 'operand' => 'IN'
+ ),
+ ),
+ 'metadata_name_value_pairs_operator' => 'OR'
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 2);
+
+ foreach ($entities as $entity) {
+ $this->assertTrue(in_array($entity->getGUID(), $valid_guids));
+ $entity->delete();
+ }
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+ function testElggApiGettersEntityMetadataNVPOrderByMDText() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $guids = array();
+ $valid_guids = array();
+
+ // our targets
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->$md_name = 1;
+ $valid->save();
+ $guids[] = $valid->getGUID();
+ $valid_guids[] = $valid->getGUID();
+
+ $valid2 = new ElggObject();
+ $valid2->subtype = $subtype;
+ $valid2->$md_name = 2;
+ $valid2->save();
+ $guids[] = $valid->getGUID();
+ $valid_guids[] = $valid2->getGUID();
+
+ $valid3 = new ElggObject();
+ $valid3->subtype = $subtype;
+ $valid3->$md_name = 3;
+ $valid3->save();
+ $guids[] = $valid->getGUID();
+ $valid_guids[] = $valid3->getGUID();
+
+ $md_valid_values = array(1, 2, 3);
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ //'metadata_name' => $md_name,
+ 'order_by_metadata' => array('name' => $md_name, 'as' => 'integer')
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 3);
+
+ $i = 1;
+ foreach ($entities as $entity) {
+ $this->assertTrue(in_array($entity->getGUID(), $valid_guids));
+ $this->assertEqual($entity->$md_name, $i);
+ $i++;
+ $entity->delete();
+ }
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+ function testElggApiGettersEntityMetadataNVPOrderByMDString() {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $md_name = 'test_metadata_name_' . rand();
+ $guids = array();
+ $valid_guids = array();
+
+ // our targets
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->$md_name = 'a';
+ $valid->save();
+ $guids[] = $valid->getGUID();
+ $valid_guids[] = $valid->getGUID();
+
+ $valid2 = new ElggObject();
+ $valid2->subtype = $subtype;
+ $valid2->$md_name = 'b';
+ $valid2->save();
+ $guids[] = $valid->getGUID();
+ $valid_guids[] = $valid2->getGUID();
+
+ $valid3 = new ElggObject();
+ $valid3->subtype = $subtype;
+ $valid3->$md_name = 'c';
+ $valid3->save();
+ $guids[] = $valid->getGUID();
+ $valid_guids[] = $valid3->getGUID();
+
+ $md_valid_values = array('a', 'b', 'c');
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'metadata_name' => $md_name,
+ 'order_by_metadata' => array('name' => $md_name, 'as' => 'text')
+ );
+
+ $entities = elgg_get_entities_from_metadata($options);
+
+ $this->assertIsa($entities, 'array');
+ $this->assertEqual(count($entities), 3);
+
+ $alpha = array('a', 'b', 'c');
+
+ $i = 0;
+ foreach ($entities as $entity) {
+ $this->assertTrue(in_array($entity->getGUID(), $valid_guids));
+ $this->assertEqual($entity->$md_name, $alpha[$i]);
+ $i++;
+ $entity->delete();
+ }
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+ /**
+ * Annotations
+ */
+ public function testElggApiGettersEntitiesFromAnnotation() {
+
+ // grab a few different users to annotation
+ // there will always be at least 2 here because of the construct.
+ $users = elgg_get_entities(array('type' => 'user', 'limit' => 2));
+
+ // create some test annotations
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $annotation_name = 'test_annotation_name_' . rand();
+ $annotation_value = rand(1000, 9999);
+ $annotation_name2 = 'test_annotation_name_' . rand();
+ $annotation_value2 = rand(1000, 9999);
+ $guids = array();
+
+ // our targets
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->save();
+ $guids[] = $valid->getGUID();
+ create_annotation($valid->getGUID(), $annotation_name, $annotation_value, 'integer', $users[0]->getGUID());
+
+ $valid2 = new ElggObject();
+ $valid2->subtype = $subtype;
+ $valid2->save();
+ $guids[] = $valid2->getGUID();
+ create_annotation($valid2->getGUID(), $annotation_name2, $annotation_value2, 'integer', $users[1]->getGUID());
+
+ $options = array(
+ 'annotation_owner_guid' => $users[0]->getGUID(),
+ 'annotation_name' => $annotation_name
+ );
+
+ $entities = elgg_get_entities_from_annotations($options);
+
+ foreach ($entities as $entity) {
+ $this->assertTrue(in_array($entity->getGUID(), $guids));
+ $annotations = $entity->getAnnotations($annotation_name);
+ $this->assertEqual(count($annotations), 1);
+
+ $this->assertEqual($annotations[0]->name, $annotation_name);
+ $this->assertEqual($annotations[0]->value, $annotation_value);
+ $this->assertEqual($annotations[0]->owner_guid, $users[0]->getGUID());
+ }
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+ // Make sure metadata doesn't affect getting entities by relationship. See #2274
+ public function testElggApiGettersEntityRelationshipWithMetadata() {
+ $guids = array();
+
+ $obj1 = new ElggObject();
+ $obj1->test_md = 'test';
+ $obj1->save();
+ $guids[] = $obj1->guid;
+
+ $obj2 = new ElggObject();
+ $obj2->test_md = 'test';
+ $obj2->save();
+ $guids[] = $obj2->guid;
+
+ add_entity_relationship($guids[0], 'test', $guids[1]);
+
+ $options = array(
+ 'relationship' => 'test',
+ 'relationship_guid' => $guids[0]
+ );
+
+ $es = elgg_get_entities_from_relationship($options);
+ $this->assertTrue(is_array($es));
+ $this->assertIdentical(count($es), 1);
+
+ foreach ($es as $e) {
+ $this->assertEqual($guids[1], $e->guid);
+ }
+
+ foreach ($guids as $guid) {
+ $e = get_entity($guid);
+ $e->delete();
+ }
+ }
+
+ public function testElggApiGettersEntityRelationshipWithOutMetadata() {
+ $guids = array();
+
+ $obj1 = new ElggObject();
+ $obj1->save();
+ $guids[] = $obj1->guid;
+
+ $obj2 = new ElggObject();
+ $obj2->save();
+ $guids[] = $obj2->guid;
+
+ add_entity_relationship($guids[0], 'test', $guids[1]);
+
+ $options = array(
+ 'relationship' => 'test',
+ 'relationship_guid' => $guids[0]
+ );
+
+ $es = elgg_get_entities_from_relationship($options);
+ $this->assertTrue(is_array($es));
+ $this->assertIdentical(count($es), 1);
+
+ foreach ($es as $e) {
+ $this->assertEqual($guids[1], $e->guid);
+ }
+
+ foreach ($guids as $guid) {
+ $e = get_entity($guid);
+ $e->delete();
+ }
+ }
+
+ public function testElggApiGettersEntityRelationshipWithMetadataIncludingRealMetadata() {
+ $guids = array();
+
+ $obj1 = new ElggObject();
+ $obj1->test_md = 'test';
+ $obj1->save();
+ $guids[] = $obj1->guid;
+
+ $obj2 = new ElggObject();
+ $obj2->test_md = 'test';
+ $obj2->save();
+ $guids[] = $obj2->guid;
+
+ add_entity_relationship($guids[0], 'test', $guids[1]);
+
+ $options = array(
+ 'relationship' => 'test',
+ 'relationship_guid' => $guids[0],
+ 'metadata_name' => 'test_md',
+ 'metadata_value' => 'test',
+ );
+
+ $es = elgg_get_entities_from_relationship($options);
+ $this->assertTrue(is_array($es));
+ $this->assertIdentical(count($es), 1);
+
+ foreach ($es as $e) {
+ $this->assertEqual($guids[1], $e->guid);
+ }
+
+ foreach ($guids as $guid) {
+ $e = get_entity($guid);
+ $e->delete();
+ }
+ }
+
+ public function testElggApiGettersEntityRelationshipWithMetadataIncludingFakeMetadata() {
+ $guids = array();
+
+ $obj1 = new ElggObject();
+ $obj1->test_md = 'test';
+ $obj1->save();
+ $guids[] = $obj1->guid;
+
+ $obj2 = new ElggObject();
+ $obj2->test_md = 'test';
+ $obj2->save();
+ $guids[] = $obj2->guid;
+
+ add_entity_relationship($guids[0], 'test', $guids[1]);
+
+ $options = array(
+ 'relationship' => 'test',
+ 'relationship_guid' => $guids[0],
+ 'metadata_name' => 'test_md',
+ 'metadata_value' => 'invalid',
+ );
+
+ $es = elgg_get_entities_from_relationship($options);
+
+ $this->assertTrue(empty($es));
+
+ foreach ($guids as $guid) {
+ $e = get_entity($guid);
+ $e->delete();
+ }
+ }
+
+ public function testElggApiGettersEntitySiteSingular() {
+ global $CONFIG;
+
+ $guids = array();
+
+ $obj1 = new ElggObject();
+ $obj1->test_md = 'test';
+ // luckily this is never checked.
+ $obj1->site_guid = 2;
+ $obj1->save();
+ $guids[] = $obj1->guid;
+ $right_guid = $obj1->guid;
+
+ $obj2 = new ElggObject();
+ $obj2->test_md = 'test';
+ $obj2->site_guid = $CONFIG->site->guid;
+ $obj2->save();
+ $guids[] = $obj2->guid;
+
+ $options = array(
+ 'metadata_name' => 'test_md',
+ 'metadata_value' => 'test',
+ 'site_guid' => 2
+ );
+
+ $es = elgg_get_entities_from_metadata($options);
+ $this->assertTrue(is_array($es));
+ $this->assertEqual(1, count($es));
+ $this->assertEqual($right_guid, $es[0]->guid);
+
+ foreach ($guids as $guid) {
+ get_entity($guid)->delete();
+ }
+ }
+
+ public function testElggApiGettersEntitySiteSingularAny() {
+ global $CONFIG;
+
+ $guids = array();
+
+ $obj1 = new ElggObject();
+ $obj1->test_md = 'test';
+ // luckily this is never checked.
+ $obj1->site_guid = 2;
+ $obj1->save();
+ $guids[] = $obj1->guid;
+
+ $obj2 = new ElggObject();
+ $obj2->test_md = 'test';
+ $obj2->site_guid = $CONFIG->site->guid;
+ $obj2->save();
+ $guids[] = $obj2->guid;
+
+ $options = array(
+ 'metadata_name' => 'test_md',
+ 'metadata_value' => 'test',
+ 'site_guid' => ELGG_ENTITIES_ANY_VALUE,
+ 'limit' => 2,
+ 'order_by' => 'e.guid DESC'
+ );
+
+ $es = elgg_get_entities_from_metadata($options);
+ $this->assertTrue(is_array($es));
+ $this->assertEqual(2, count($es));
+
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->guid, $guids));
+ }
+
+ foreach ($guids as $guid) {
+ get_entity($guid)->delete();
+ }
+ }
+
+ public function testElggApiGettersEntitySitePlural() {
+ global $CONFIG;
+
+ $guids = array();
+
+ $obj1 = new ElggObject();
+ $obj1->test_md = 'test';
+ // luckily this is never checked.
+ $obj1->site_guid = 2;
+ $obj1->save();
+ $guids[] = $obj1->guid;
+
+ $obj2 = new ElggObject();
+ $obj2->test_md = 'test';
+ $obj2->site_guid = $CONFIG->site->guid;
+ $obj2->save();
+ $guids[] = $obj2->guid;
+
+ $options = array(
+ 'metadata_name' => 'test_md',
+ 'metadata_value' => 'test',
+ 'site_guids' => array($CONFIG->site->guid, 2),
+ 'limit' => 2,
+ 'order_by' => 'e.guid DESC'
+ );
+
+ $es = elgg_get_entities_from_metadata($options);
+ $this->assertTrue(is_array($es));
+ $this->assertEqual(2, count($es));
+
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->guid, $guids));
+ }
+
+ foreach ($guids as $guid) {
+ get_entity($guid)->delete();
+ }
+ }
+
+ public function testElggApiGettersEntitySitePluralSomeInvalid() {
+ global $CONFIG;
+
+ $guids = array();
+
+ $obj1 = new ElggObject();
+ $obj1->test_md = 'test';
+ // luckily this is never checked.
+ $obj1->site_guid = 2;
+ $obj1->save();
+ $guids[] = $obj1->guid;
+
+ $obj2 = new ElggObject();
+ $obj2->test_md = 'test';
+ $obj2->save();
+ $guids[] = $obj2->guid;
+ $right_guid = $obj2->guid;
+
+ $options = array(
+ 'metadata_name' => 'test_md',
+ 'metadata_value' => 'test',
+ // just created the first entity so nothing will be "sited" by it.
+ 'site_guids' => array($CONFIG->site->guid, $guids[0]),
+ 'limit' => 2,
+ 'order_by' => 'e.guid DESC'
+ );
+
+ $es = elgg_get_entities_from_metadata($options);
+
+ $this->assertTrue(is_array($es));
+ $this->assertEqual(1, count($es));
+ $this->assertEqual($es[0]->guid, $right_guid);
+
+ foreach ($guids as $guid) {
+ get_entity($guid)->delete();
+ }
+ }
+
+ public function testElggApiGettersEntitySitePluralAllInvalid() {
+ global $CONFIG;
+
+ $guids = array();
+
+ $obj1 = new ElggObject();
+ $obj1->test_md = 'test';
+ // luckily this is never checked.
+ $obj1->site_guid = 2;
+ $obj1->save();
+ $guids[] = $obj1->guid;
+
+ $obj2 = new ElggObject();
+ $obj2->test_md = 'test';
+ $obj2->save();
+ $guids[] = $obj2->guid;
+ $right_guid = $obj2->guid;
+
+ $options = array(
+ 'metadata_name' => 'test_md',
+ 'metadata_value' => 'test',
+ // just created the first entity so nothing will be "sited" by it.
+ 'site_guids' => array($guids[0], $guids[1]),
+ 'limit' => 2,
+ 'order_by' => 'e.guid DESC'
+ );
+
+ $es = elgg_get_entities_from_metadata($options);
+
+ $this->assertTrue(empty($es));
+
+ foreach ($guids as $guid) {
+ get_entity($guid)->delete();
+ }
+ }
+
+ /**
+ * Private settings
+ */
+ public function testElggApiGettersEntitiesFromPrivateSettings() {
+
+ // create some test private settings
+ $setting_name = 'test_setting_name_' . rand();
+ $setting_value = rand(1000, 9999);
+ $setting_name2 = 'test_setting_name_' . rand();
+ $setting_value2 = rand(1000, 9999);
+
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $guids = array();
+
+ // our targets
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->save();
+ $guids[] = $valid->getGUID();
+ set_private_setting($valid->getGUID(), $setting_name, $setting_value);
+ set_private_setting($valid->getGUID(), $setting_name2, $setting_value2);
+
+ $valid2 = new ElggObject();
+ $valid2->subtype = $subtype;
+ $valid2->save();
+ $guids[] = $valid2->getGUID();
+ set_private_setting($valid2->getGUID(), $setting_name, $setting_value);
+ set_private_setting($valid2->getGUID(), $setting_name2, $setting_value2);
+
+ // simple test with name
+ $options = array(
+ 'private_setting_name' => $setting_name
+ );
+
+ $entities = elgg_get_entities_from_private_settings($options);
+
+ foreach ($entities as $entity) {
+ $this->assertTrue(in_array($entity->getGUID(), $guids));
+ $value = get_private_setting($entity->getGUID(), $setting_name);
+ $this->assertEqual($value, $setting_value);
+ }
+
+ // simple test with value
+ $options = array(
+ 'private_setting_value' => $setting_value
+ );
+
+ $entities = elgg_get_entities_from_private_settings($options);
+
+ foreach ($entities as $entity) {
+ $this->assertTrue(in_array($entity->getGUID(), $guids));
+ $value = get_private_setting($entity->getGUID(), $setting_name);
+ $this->assertEqual($value, $setting_value);
+ }
+
+ // test pairs
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'private_setting_name_value_pairs' => array(
+ array(
+ 'name' => $setting_name,
+ 'value' => $setting_value
+ ),
+ array(
+ 'name' => $setting_name2,
+ 'value' => $setting_value2
+ )
+ )
+ );
+
+ $entities = elgg_get_entities_from_private_settings($options);
+ $this->assertEqual(2, count($entities));
+ foreach ($entities as $entity) {
+ $this->assertTrue(in_array($entity->getGUID(), $guids));
+ }
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+ /**
+ * Location
+ */
+ public function testElggApiGettersEntitiesFromLocation() {
+
+ // a test location that is out of this world
+ $lat = 500;
+ $long = 500;
+ $delta = 5;
+
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $subtype = $subtypes[0];
+ $guids = array();
+
+ // our objects
+ $valid = new ElggObject();
+ $valid->subtype = $subtype;
+ $valid->save();
+ $guids[] = $valid->getGUID();
+ $valid->setLatLong($lat, $long);
+
+ $valid2 = new ElggObject();
+ $valid2->subtype = $subtype;
+ $valid2->save();
+ $guids[] = $valid2->getGUID();
+ $valid2->setLatLong($lat + 2 * $delta, $long + 2 * $delta);
+
+ // limit to first object
+ $options = array(
+ 'latitude' => $lat,
+ 'longitude' => $long,
+ 'distance' => $delta
+ );
+
+ //global $CONFIG;
+ //$CONFIG->debug = 'NOTICE';
+ $entities = elgg_get_entities_from_location($options);
+ //unset($CONFIG->debug);
+
+ $this->assertEqual(1, count($entities));
+ $this->assertEqual($entities[0]->getGUID(), $valid->getGUID());
+
+ // get both objects
+ $options = array(
+ 'latitude' => $lat,
+ 'longitude' => $long,
+ 'distance' => array('latitude' => 2 * $delta, 'longitude' => 2 * $delta)
+ );
+
+ $entities = elgg_get_entities_from_location($options);
+
+ $this->assertEqual(2, count($entities));
+ foreach ($entities as $entity) {
+ $this->assertTrue(in_array($entity->getGUID(), $guids));
+ }
+
+ foreach ($guids as $guid) {
+ if ($e = get_entity($guid)) {
+ $e->delete();
+ }
+ }
+ }
+
+
+ public function testElggGetEntitiesFromRelationshipCount() {
+ $entities = $this->entities;
+ $relationships = array();
+ $count = count($entities);
+ $max = $count - 1;
+ $relationship_name = 'test_relationship_' . rand(0, 1000);
+
+ for ($i = 0; $i < $count; $i++) {
+ do {
+ $popular_entity = $entities[array_rand($entities)];
+ } while (array_key_exists($popular_entity->guid, $relationships));
+
+ $relationships[$popular_entity->guid] = array();
+
+ for ($c = 0; $c < $max; $c++) {
+ do {
+ $fan_entity = $entities[array_rand($entities)];
+ } while ($fan_entity->guid == $popular_entity->guid || in_array($fan_entity->guid, $relationships[$popular_entity->guid]));
+
+ $relationships[$popular_entity->guid][] = $fan_entity->guid;
+ add_entity_relationship($fan_entity->guid, $relationship_name, $popular_entity->guid);
+ }
+
+ $max--;
+ }
+
+ $options = array(
+ 'relationship' => $relationship_name,
+ 'limit' => $count
+ );
+
+ $entities = elgg_get_entities_from_relationship_count($options);
+
+ foreach ($entities as $e) {
+ $options = array(
+ 'relationship' => $relationship_name,
+ 'limit' => 100,
+ 'relationship_guid' => $e->guid,
+ 'inverse_relationship' => true
+ );
+
+ $fan_entities = elgg_get_entities_from_relationship($options);
+
+ $this->assertEqual(count($fan_entities), count($relationships[$e->guid]));
+
+ foreach ($fan_entities as $fan_entity) {
+ $this->assertTrue(in_array($fan_entity->guid, $relationships[$e->guid]));
+ $this->assertNotIdentical(false, check_entity_relationship($fan_entity->guid, $relationship_name, $e->guid));
+ }
+ }
+ }
+
+ public function testElggGetEntitiesByGuidSingular() {
+ foreach ($this->entities as $e) {
+ $options = array(
+ 'guid' => $e->guid
+ );
+ $es = elgg_get_entities($options);
+
+ $this->assertEqual(count($es), 1);
+ $this->assertEqual($es[0]->guid, $e->guid);
+ }
+ }
+
+ public function testElggGetEntitiesByGuidPlural() {
+ $guids = array();
+
+ foreach ($this->entities as $e) {
+ $guids[] = $e->guid;
+ }
+
+ $options = array(
+ 'guids' => $guids,
+ 'limit' => 100
+ );
+
+ $es = elgg_get_entities($options);
+
+ $this->assertEqual(count($es), count($this->entities));
+
+ foreach ($es as $e) {
+ $this->assertTrue(in_array($e->guid, $guids));
+ }
+ }
+
+ public function testElggGetEntitiesFromAnnotationsCalculateX() {
+ $types = array(
+ 'sum',
+ 'avg',
+ 'min',
+ 'max'
+ );
+
+ foreach ($types as $type) {
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 5);
+ $name = 'test_annotation_' . rand(0, 9999);
+ $values = array();
+ $options = array(
+ 'type' => 'object',
+ 'subtypes' => $subtypes,
+ 'limit' => 5
+ );
+
+ $es = elgg_get_entities($options);
+
+ foreach ($es as $e) {
+ $value = rand(0,9999);
+ $e->annotate($name, $value);
+
+ $value2 = rand(0,9999);
+ $e->annotate($name, $value2);
+
+ switch ($type) {
+ case 'sum':
+ $calc_value = $value + $value2;
+ break;
+
+ case 'avg':
+ $calc_value = ($value + $value2) / 2;
+ break;
+
+ case 'min':
+ $calc_value = min(array($value, $value2));
+ break;
+
+ case 'max':
+ $calc_value = max(array($value, $value2));
+ break;
+ }
+
+ $values[$e->guid] = $calc_value;
+ }
+
+ arsort($values);
+ $order = array_keys($values);
+
+ $options = array(
+ 'type' => 'object',
+ 'subtypes' => $subtypes,
+ 'limit' => 5,
+ 'annotation_name' => $name,
+ 'calculation' => $type
+ );
+
+ $es = elgg_get_entities_from_annotation_calculation($options);
+
+ foreach ($es as $i => $e) {
+ $value = 0;
+ $as = $e->getAnnotations($name);
+ // should only ever be 2
+ $this->assertEqual(2, count($as));
+
+ $value = $as[0]->value;
+ $value2 = $as[1]->value;
+
+ switch ($type) {
+ case 'sum':
+ $calc_value = $value + $value2;
+ break;
+
+ case 'avg':
+ $calc_value = ($value + $value2) / 2;
+ break;
+
+ case 'min':
+ $calc_value = min(array($value, $value2));
+ break;
+
+ case 'max':
+ $calc_value = max(array($value, $value2));
+ break;
+ }
+
+ $this->assertEqual($e->guid, $order[$i]);
+ $this->assertEqual($values[$e->guid], $calc_value);
+ }
+ }
+ }
+
+ public function testElggGetEntitiesFromAnnotationCalculationCount() {
+ // add two annotations with a unique name to an entity
+ // then count the number of entities with that annotation name
+
+ $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
+ $name = 'test_annotation_' . rand(0, 9999);
+ $values = array();
+ $options = array(
+ 'type' => 'object',
+ 'subtypes' => $subtypes,
+ 'limit' => 1
+ );
+ $es = elgg_get_entities($options);
+ $entity = $es[0];
+ $value = rand(0, 9999);
+ $entity->annotate($name, $value);
+ $value = rand(0, 9999);
+ $entity->annotate($name, $value);
+
+ $options = array(
+ 'type' => 'object',
+ 'subtypes' => $subtypes,
+ 'annotation_name' => $name,
+ 'calculation' => 'count',
+ 'count' => true,
+ );
+ $count = elgg_get_entities_from_annotation_calculation($options);
+ $this->assertEqual(1, $count);
+ }
+
+ public function testElggGetAnnotationsAnnotationNames() {
+ $options = array('annotation_names' => array());
+ $a_e_map = array();
+
+ // create test annotations on a few entities.
+ for ($i=0; $i<3; $i++) {
+ do {
+ $e = $this->entities[array_rand($this->entities)];
+ } while(in_array($e->guid, $a_e_map));
+ $annotations = $this->createRandomAnnotations($e);
+
+ foreach($annotations as $a) {
+ $options['annotation_names'][] = $a->name;
+ $a_e_map[$a->id] = $e->guid;
+ }
+ }
+
+ $as = elgg_get_annotations($options);
+
+ $this->assertEqual(count($a_e_map), count($as));
+
+ foreach ($as as $a) {
+ $this->assertEqual($a_e_map[$a->id], $a->entity_guid);
+ }
+ }
+
+ public function testElggGetAnnotationsAnnotationValues() {
+ $options = array('annotation_values' => array());
+ $a_e_map = array();
+
+ // create test annotations on a few entities.
+ for ($i=0; $i<3; $i++) {
+ do {
+ $e = $this->entities[array_rand($this->entities)];
+ } while(in_array($e->guid, $a_e_map));
+ $annotations = $this->createRandomAnnotations($e);
+
+ foreach($annotations as $a) {
+ $options['annotation_values'][] = $a->value;
+ $a_e_map[$a->id] = $e->guid;
+ }
+ }
+
+ $as = elgg_get_annotations($options);
+
+ $this->assertEqual(count($a_e_map), count($as));
+
+ foreach ($as as $a) {
+ $this->assertEqual($a_e_map[$a->id], $a->entity_guid);
+ }
+ }
+
+ public function testElggGetAnnotationsAnnotationOwnerGuids() {
+ $options = array('annotation_owner_guids' => array());
+ $a_e_map = array();
+
+ // create test annotations on a single entity
+ for ($i=0; $i<3; $i++) {
+ do {
+ $e = $this->entities[array_rand($this->entities)];
+ } while(in_array($e->guid, $a_e_map));
+
+ // remove annotations left over from previous tests.
+ elgg_delete_annotations(array('annotation_owner_guid' => $e->guid));
+ $annotations = $this->createRandomAnnotations($e);
+
+ foreach($annotations as $a) {
+ $options['annotation_owner_guids'][] = $e->guid;
+ $a_e_map[$a->id] = $e->guid;
+ }
+ }
+
+ $as = elgg_get_annotations($options);
+ $this->assertEqual(count($a_e_map), count($as));
+
+ foreach ($as as $a) {
+ $this->assertEqual($a_e_map[$a->id], $a->owner_guid);
+ }
+ }
+
+ public function testElggGetEntitiesBadWheres() {
+ $options = array(
+ 'container_guid' => 'abc'
+ );
+
+ $entities = elgg_get_entities($options);
+ $this->assertFalse($entities);
+ }
+
+ public function testEGEEmptySubtypePlurality() {
+ $options = array(
+ 'type' => 'user',
+ 'subtypes' => ''
+ );
+
+ $entities = elgg_get_entities($options);
+ $this->assertTrue(is_array($entities));
+
+ $options = array(
+ 'type' => 'user',
+ 'subtype' => ''
+ );
+
+ $entities = elgg_get_entities($options);
+ $this->assertTrue(is_array($entities));
+
+ $options = array(
+ 'type' => 'user',
+ 'subtype' => array('')
+ );
+
+ $entities = elgg_get_entities($options);
+ $this->assertTrue(is_array($entities));
+
+ $options = array(
+ 'type' => 'user',
+ 'subtypes' => array('')
+ );
+
+ $entities = elgg_get_entities($options);
+ $this->assertTrue(is_array($entities));
+ }
+}
diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php
new file mode 100644
index 000000000..414fb4145
--- /dev/null
+++ b/engine/tests/api/helpers.php
@@ -0,0 +1,705 @@
+<?php
+/**
+ * Elgg Test helper functions
+ *
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreHelpersTest extends ElggCoreUnitTest {
+
+ /**
+ * Called before each test object.
+ */
+ public function __construct() {
+ parent::__construct();
+ }
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ // do not allow SimpleTest to interpret Elgg notices as exceptions
+ $this->swallowErrors();
+
+ global $CONFIG;
+ unset($CONFIG->externals);
+ unset($CONFIG->externals_map);
+ }
+
+ /**
+ * Called after each test object.
+ */
+ public function __destruct() {
+ // all __destruct() code should go above here
+ parent::__destruct();
+ }
+
+ /**
+ * Test elgg_instanceof()
+ */
+ public function testElggInstanceOf() {
+ $entity = new ElggObject();
+ $entity->subtype = 'test_subtype';
+ $entity->save();
+
+ $this->assertTrue(elgg_instanceof($entity));
+ $this->assertTrue(elgg_instanceof($entity, 'object'));
+ $this->assertTrue(elgg_instanceof($entity, 'object', 'test_subtype'));
+
+ $this->assertFalse(elgg_instanceof($entity, 'object', 'invalid_subtype'));
+ $this->assertFalse(elgg_instanceof($entity, 'user', 'test_subtype'));
+
+ $entity->delete();
+
+ $bad_entity = FALSE;
+ $this->assertFalse(elgg_instanceof($bad_entity));
+ $this->assertFalse(elgg_instanceof($bad_entity, 'object'));
+ $this->assertFalse(elgg_instanceof($bad_entity, 'object', 'test_subtype'));
+
+ remove_subtype('object', 'test_subtype');
+ }
+
+ /**
+ * Test elgg_normalize_url()
+ */
+ public function testElggNormalizeURL() {
+ $conversions = array(
+ 'http://example.com' => 'http://example.com',
+ 'https://example.com' => 'https://example.com',
+ 'http://example-time.com' => 'http://example-time.com',
+
+ '//example.com' => '//example.com',
+ 'ftp://example.com/file' => 'ftp://example.com/file',
+ 'mailto:brett@elgg.org' => 'mailto:brett@elgg.org',
+ 'javascript:alert("test")' => 'javascript:alert("test")',
+ 'app://endpoint' => 'app://endpoint',
+
+ 'example.com' => 'http://example.com',
+ 'example.com/subpage' => 'http://example.com/subpage',
+
+ 'page/handler' => elgg_get_site_url() . 'page/handler',
+ 'page/handler?p=v&p2=v2' => elgg_get_site_url() . 'page/handler?p=v&p2=v2',
+ 'mod/plugin/file.php' => elgg_get_site_url() . 'mod/plugin/file.php',
+ 'mod/plugin/file.php?p=v&p2=v2' => elgg_get_site_url() . 'mod/plugin/file.php?p=v&p2=v2',
+ 'rootfile.php' => elgg_get_site_url() . 'rootfile.php',
+ 'rootfile.php?p=v&p2=v2' => elgg_get_site_url() . 'rootfile.php?p=v&p2=v2',
+
+ '/page/handler' => elgg_get_site_url() . 'page/handler',
+ '/page/handler?p=v&p2=v2' => elgg_get_site_url() . 'page/handler?p=v&p2=v2',
+ '/mod/plugin/file.php' => elgg_get_site_url() . 'mod/plugin/file.php',
+ '/mod/plugin/file.php?p=v&p2=v2' => elgg_get_site_url() . 'mod/plugin/file.php?p=v&p2=v2',
+ '/rootfile.php' => elgg_get_site_url() . 'rootfile.php',
+ '/rootfile.php?p=v&p2=v2' => elgg_get_site_url() . 'rootfile.php?p=v&p2=v2',
+ );
+
+ foreach ($conversions as $input => $output) {
+ $this->assertIdentical($output, elgg_normalize_url($input));
+ }
+ }
+
+
+ /**
+ * Test elgg_register_js()
+ */
+ public function testElggRegisterJS() {
+ global $CONFIG;
+
+ // specify name
+ $result = elgg_register_js('key', 'http://test1.com', 'footer');
+ $this->assertTrue($result);
+ $this->assertTrue(isset($CONFIG->externals_map['js']['key']));
+
+ $item = $CONFIG->externals_map['js']['key'];
+ $this->assertTrue($CONFIG->externals['js']->contains($item));
+
+ $priority = $CONFIG->externals['js']->getPriority($item);
+ $this->assertTrue($priority !== false);
+
+ $item = $CONFIG->externals['js']->getElement($priority);
+ $this->assertIdentical('http://test1.com', $item->url);
+
+ // send a bad url
+ $result = elgg_register_js('bad', null);
+ $this->assertFalse($result);
+ }
+
+ /**
+ * Test elgg_register_css()
+ */
+ public function testElggRegisterCSS() {
+ global $CONFIG;
+
+ // specify name
+ $result = elgg_register_css('key', 'http://test1.com');
+ $this->assertTrue($result);
+ $this->assertTrue(isset($CONFIG->externals_map['css']['key']));
+
+ $item = $CONFIG->externals_map['css']['key'];
+ $this->assertTrue($CONFIG->externals['css']->contains($item));
+
+ $priority = $CONFIG->externals['css']->getPriority($item);
+ $this->assertTrue($priority !== false);
+
+ $item = $CONFIG->externals['css']->getElement($priority);
+ $this->assertIdentical('http://test1.com', $item->url);
+ }
+
+ /**
+ * Test elgg_unregister_js()
+ */
+ public function testElggUnregisterJS() {
+ global $CONFIG;
+
+ $base = trim(elgg_get_site_url(), "/");
+
+ $urls = array('id1' => "$base/urla", 'id2' => "$base/urlb", 'id3' => "$base/urlc");
+
+ foreach ($urls as $id => $url) {
+ elgg_register_js($id, $url);
+ }
+
+ $result = elgg_unregister_js('id1');
+ $this->assertTrue($result);
+
+ $js = $CONFIG->externals['js'];
+ $elements = $js->getElements();
+ $this->assertFalse(isset($CONFIG->externals_map['js']['id1']));
+
+ foreach ($elements as $element) {
+ if (isset($element->name)) {
+ $this->assertFalse($element->name == 'id1');
+ }
+ }
+
+ $result = elgg_unregister_js('id1');
+ $this->assertFalse($result);
+
+ $result = elgg_unregister_js('', 'does_not_exist');
+ $this->assertFalse($result);
+
+ $result = elgg_unregister_js('id2');
+ $elements = $js->getElements();
+
+ $this->assertFalse(isset($CONFIG->externals_map['js']['id2']));
+ foreach ($elements as $element) {
+ if (isset($element->name)) {
+ $this->assertFalse($element->name == 'id2');
+ }
+ }
+
+ $this->assertTrue(isset($CONFIG->externals_map['js']['id3']));
+
+ $priority = $CONFIG->externals['js']->getPriority($CONFIG->externals_map['js']['id3']);
+ $this->assertTrue($priority !== false);
+
+ $item = $CONFIG->externals['js']->getElement($priority);
+ $this->assertIdentical($urls['id3'], $item->url);
+ }
+
+ /**
+ * Test elgg_load_js()
+ */
+ public function testElggLoadJS() {
+ global $CONFIG;
+
+ // load before register
+ elgg_load_js('key');
+ $result = elgg_register_js('key', 'http://test1.com', 'footer');
+ $this->assertTrue($result);
+
+ $js_urls = elgg_get_loaded_js('footer');
+ $this->assertIdentical(array(500 => 'http://test1.com'), $js_urls);
+ }
+
+ /**
+ * Test elgg_get_loaded_js()
+ */
+ public function testElggGetJS() {
+ global $CONFIG;
+
+ $base = trim(elgg_get_site_url(), "/");
+
+ $urls = array(
+ 'id1' => "$base/urla",
+ 'id2' => "$base/urlb",
+ 'id3' => "$base/urlc"
+ );
+
+ foreach ($urls as $id => $url) {
+ elgg_register_js($id, $url);
+ elgg_load_js($id);
+ }
+
+ $js_urls = elgg_get_loaded_js('head');
+
+ $this->assertIdentical($js_urls[500], $urls['id1']);
+ $this->assertIdentical($js_urls[501], $urls['id2']);
+ $this->assertIdentical($js_urls[502], $urls['id3']);
+
+ $js_urls = elgg_get_loaded_js('footer');
+ $this->assertIdentical(array(), $js_urls);
+ }
+
+ // test ElggPriorityList
+ public function testElggPriorityListAdd() {
+ $pl = new ElggPriorityList();
+ $elements = array(
+ 'Test value',
+ 'Test value 2',
+ 'Test value 3'
+ );
+
+ shuffle($elements);
+
+ foreach ($elements as $element) {
+ $this->assertTrue($pl->add($element) !== false);
+ }
+
+ $test_elements = $pl->getElements();
+
+ $this->assertTrue(is_array($test_elements));
+
+ foreach ($test_elements as $i => $element) {
+ // should be in the array
+ $this->assertTrue(in_array($element, $elements));
+
+ // should be the only element, so priority 0
+ $this->assertEqual($i, array_search($element, $elements));
+ }
+ }
+
+ public function testElggPriorityListAddWithPriority() {
+ $pl = new ElggPriorityList();
+
+ $elements = array(
+ 10 => 'Test Element 10',
+ 5 => 'Test Element 5',
+ 0 => 'Test Element 0',
+ 100 => 'Test Element 100',
+ -1 => 'Test Element -1',
+ -5 => 'Test Element -5'
+ );
+
+ foreach ($elements as $priority => $element) {
+ $pl->add($element, $priority);
+ }
+
+ $test_elements = $pl->getElements();
+
+ // should be sorted by priority
+ $elements_sorted = array(
+ -5 => 'Test Element -5',
+ -1 => 'Test Element -1',
+ 0 => 'Test Element 0',
+ 5 => 'Test Element 5',
+ 10 => 'Test Element 10',
+ 100 => 'Test Element 100',
+ );
+
+ $this->assertIdentical($elements_sorted, $test_elements);
+
+ foreach ($test_elements as $priority => $element) {
+ $this->assertIdentical($elements[$priority], $element);
+ }
+ }
+
+ public function testElggPriorityListGetNextPriority() {
+ $pl = new ElggPriorityList();
+
+ $elements = array(
+ 2 => 'Test Element',
+ 0 => 'Test Element 2',
+ -2 => 'Test Element 3',
+ );
+
+ foreach ($elements as $priority => $element) {
+ $pl->add($element, $priority);
+ }
+
+ // we're not specifying a priority so it should be the next consecutive to 0.
+ $this->assertEqual(1, $pl->getNextPriority());
+
+ // add another one at priority 1
+ $pl->add('Test Element 1');
+
+ // next consecutive to 0 is now 3.
+ $this->assertEqual(3, $pl->getNextPriority());
+ }
+
+ public function testElggPriorityListRemove() {
+ $pl = new ElggPriorityList();
+
+ $elements = array();
+ for ($i=0; $i<3; $i++) {
+ $element = new stdClass();
+ $element->name = "Test Element $i";
+ $element->someAttribute = rand(0, 9999);
+ $elements[] = $element;
+ $pl->add($element);
+ }
+
+ $pl->remove($elements[1]);
+
+ $test_elements = $pl->getElements();
+
+ // make sure it's gone.
+ $this->assertEqual(2, count($test_elements));
+ $this->assertIdentical($elements[0], $test_elements[0]);
+ $this->assertIdentical($elements[2], $test_elements[2]);
+ }
+
+ public function testElggPriorityListMove() {
+ $pl = new ElggPriorityList();
+
+ $elements = array(
+ -5 => 'Test Element -5',
+ 0 => 'Test Element 0',
+ 5 => 'Test Element 5',
+ );
+
+ foreach ($elements as $priority => $element) {
+ $pl->add($element, $priority);
+ }
+
+ $this->assertEqual($pl->move($elements[-5], 10), 10);
+
+ // check it's at the new place
+ $this->assertIdentical($elements[-5], $pl->getElement(10));
+
+ // check it's not at the old
+ $this->assertFalse($pl->getElement(-5));
+ }
+
+ public function testElggPriorityListConstructor() {
+ $elements = array(
+ 10 => 'Test Element 10',
+ 5 => 'Test Element 5',
+ 0 => 'Test Element 0',
+ 100 => 'Test Element 100',
+ -1 => 'Test Element -1',
+ -5 => 'Test Element -5'
+ );
+
+ $pl = new ElggPriorityList($elements);
+ $test_elements = $pl->getElements();
+
+ $elements_sorted = array(
+ -5 => 'Test Element -5',
+ -1 => 'Test Element -1',
+ 0 => 'Test Element 0',
+ 5 => 'Test Element 5',
+ 10 => 'Test Element 10',
+ 100 => 'Test Element 100',
+ );
+
+ $this->assertIdentical($elements_sorted, $test_elements);
+ }
+
+ public function testElggPriorityListGetPriority() {
+ $pl = new ElggPriorityList();
+
+ $elements = array(
+ 'Test element 0',
+ 'Test element 1',
+ 'Test element 2',
+ );
+
+ foreach ($elements as $element) {
+ $pl->add($element);
+ }
+
+ $this->assertIdentical(0, $pl->getPriority($elements[0]));
+ $this->assertIdentical(1, $pl->getPriority($elements[1]));
+ $this->assertIdentical(2, $pl->getPriority($elements[2]));
+ }
+
+ public function testElggPriorityListGetElement() {
+ $pl = new ElggPriorityList();
+ $priorities = array();
+
+ $elements = array(
+ 'Test element 0',
+ 'Test element 1',
+ 'Test element 2',
+ );
+
+ foreach ($elements as $element) {
+ $priorities[] = $pl->add($element);
+ }
+
+ $this->assertIdentical($elements[0], $pl->getElement($priorities[0]));
+ $this->assertIdentical($elements[1], $pl->getElement($priorities[1]));
+ $this->assertIdentical($elements[2], $pl->getElement($priorities[2]));
+ }
+
+ public function testElggPriorityListPriorityCollision() {
+ $pl = new ElggPriorityList();
+
+ $elements = array(
+ 5 => 'Test element 5',
+ 6 => 'Test element 6',
+ 0 => 'Test element 0',
+ );
+
+ foreach ($elements as $priority => $element) {
+ $pl->add($element, $priority);
+ }
+
+ // add at a colliding priority
+ $pl->add('Colliding element', 5);
+
+ // should float to the top closest to 5, so 7
+ $this->assertEqual(7, $pl->getPriority('Colliding element'));
+ }
+
+ public function testElggPriorityListIterator() {
+ $elements = array(
+ -5 => 'Test element -5',
+ 0 => 'Test element 0',
+ 5 => 'Test element 5'
+ );
+
+ $pl = new ElggPriorityList($elements);
+
+ foreach ($pl as $priority => $element) {
+ $this->assertIdentical($elements[$priority], $element);
+ }
+ }
+
+ public function testElggPriorityListCountable() {
+ $pl = new ElggPriorityList();
+
+ $this->assertEqual(0, count($pl));
+
+ $pl->add('Test element 0');
+ $this->assertEqual(1, count($pl));
+
+ $pl->add('Test element 1');
+ $this->assertEqual(2, count($pl));
+
+ $pl->add('Test element 2');
+ $this->assertEqual(3, count($pl));
+ }
+
+ public function testElggPriorityListUserSort() {
+ $elements = array(
+ 'A',
+ 'B',
+ 'C',
+ 'D',
+ 'E',
+ );
+
+ $elements_sorted_string = $elements;
+
+ shuffle($elements);
+ $pl = new ElggPriorityList($elements);
+
+ // will sort by priority
+ $test_elements = $pl->getElements();
+ $this->assertIdentical($elements, $test_elements);
+
+ function test_sort($elements) {
+ sort($elements, SORT_LOCALE_STRING);
+ return $elements;
+ }
+
+ // force a new sort using our function
+ $pl->sort('test_sort');
+ $test_elements = $pl->getElements();
+
+ $this->assertIdentical($elements_sorted_string, $test_elements);
+ }
+
+ // see https://github.com/elgg/elgg/issues/4288
+ public function testElggBatchIncOffset() {
+ // normal increment
+ $options = array(
+ 'offset' => 0,
+ 'limit' => 11
+ );
+ $batch = new ElggBatch(array('ElggCoreHelpersTest', 'elgg_batch_callback_test'), $options,
+ null, 5);
+ $j = 0;
+ foreach ($batch as $e) {
+ $offset = floor($j / 5) * 5;
+ $this->assertEqual($offset, $e['offset']);
+ $this->assertEqual($j + 1, $e['index']);
+ $j++;
+ }
+
+ $this->assertEqual(11, $j);
+
+ // no increment, 0 start
+ ElggCoreHelpersTest::elgg_batch_callback_test(array(), true);
+ $options = array(
+ 'offset' => 0,
+ 'limit' => 11
+ );
+ $batch = new ElggBatch(array('ElggCoreHelpersTest', 'elgg_batch_callback_test'), $options,
+ null, 5);
+ $batch->setIncrementOffset(false);
+
+ $j = 0;
+ foreach ($batch as $e) {
+ $this->assertEqual(0, $e['offset']);
+ // should always be the same 5
+ $this->assertEqual($e['index'], $j + 1 - (floor($j / 5) * 5));
+ $j++;
+ }
+ $this->assertEqual(11, $j);
+
+ // no increment, 3 start
+ ElggCoreHelpersTest::elgg_batch_callback_test(array(), true);
+ $options = array(
+ 'offset' => 3,
+ 'limit' => 11
+ );
+ $batch = new ElggBatch(array('ElggCoreHelpersTest', 'elgg_batch_callback_test'), $options,
+ null, 5);
+ $batch->setIncrementOffset(false);
+
+ $j = 0;
+ foreach ($batch as $e) {
+ $this->assertEqual(3, $e['offset']);
+ // same 5 results
+ $this->assertEqual($e['index'], $j + 4 - (floor($j / 5) * 5));
+ $j++;
+ }
+
+ $this->assertEqual(11, $j);
+ }
+
+ public function testElggBatchReadHandlesBrokenEntities() {
+ $num_test_entities = 8;
+ $guids = array();
+ for ($i = $num_test_entities; $i > 0; $i--) {
+ $entity = new ElggObject();
+ $entity->type = 'object';
+ $entity->subtype = 'test_5357_subtype';
+ $entity->access_id = ACCESS_PUBLIC;
+ $entity->save();
+ $guids[] = $entity->guid;
+ _elgg_invalidate_cache_for_entity($entity->guid);
+ }
+
+ // break entities such that the first fetch has one incomplete
+ // and the second and third fetches have only incompletes!
+ $db_prefix = elgg_get_config('dbprefix');
+ delete_data("
+ DELETE FROM {$db_prefix}objects_entity
+ WHERE guid IN ({$guids[1]}, {$guids[2]}, {$guids[3]}, {$guids[4]}, {$guids[5]})
+ ");
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => 'test_5357_subtype',
+ 'order_by' => 'e.guid',
+ );
+
+ $entities_visited = array();
+ $batch = new ElggBatch('elgg_get_entities', $options, null, 2);
+ /* @var ElggEntity[] $batch */
+ foreach ($batch as $entity) {
+ $entities_visited[] = $entity->guid;
+ }
+
+ // The broken entities should not have been visited
+ $this->assertEqual($entities_visited, array($guids[0], $guids[6], $guids[7]));
+
+ // cleanup (including leftovers from previous tests)
+ $entity_rows = elgg_get_entities(array_merge($options, array(
+ 'callback' => '',
+ 'limit' => false,
+ )));
+ $guids = array();
+ foreach ($entity_rows as $row) {
+ $guids[] = $row->guid;
+ }
+ delete_data("DELETE FROM {$db_prefix}entities WHERE guid IN (" . implode(',', $guids) . ")");
+ delete_data("DELETE FROM {$db_prefix}objects_entity WHERE guid IN (" . implode(',', $guids) . ")");
+ }
+
+ public function testElggBatchDeleteHandlesBrokenEntities() {
+ $num_test_entities = 8;
+ $guids = array();
+ for ($i = $num_test_entities; $i > 0; $i--) {
+ $entity = new ElggObject();
+ $entity->type = 'object';
+ $entity->subtype = 'test_5357_subtype';
+ $entity->access_id = ACCESS_PUBLIC;
+ $entity->save();
+ $guids[] = $entity->guid;
+ _elgg_invalidate_cache_for_entity($entity->guid);
+ }
+
+ // break entities such that the first fetch has one incomplete
+ // and the second and third fetches have only incompletes!
+ $db_prefix = elgg_get_config('dbprefix');
+ delete_data("
+ DELETE FROM {$db_prefix}objects_entity
+ WHERE guid IN ({$guids[1]}, {$guids[2]}, {$guids[3]}, {$guids[4]}, {$guids[5]})
+ ");
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => 'test_5357_subtype',
+ 'order_by' => 'e.guid',
+ );
+
+ $entities_visited = array();
+ $batch = new ElggBatch('elgg_get_entities', $options, null, 2, false);
+ /* @var ElggEntity[] $batch */
+ foreach ($batch as $entity) {
+ $entities_visited[] = $entity->guid;
+ $entity->delete();
+ }
+
+ // The broken entities should not have been visited
+ $this->assertEqual($entities_visited, array($guids[0], $guids[6], $guids[7]));
+
+ // cleanup (including leftovers from previous tests)
+ $entity_rows = elgg_get_entities(array_merge($options, array(
+ 'callback' => '',
+ 'limit' => false,
+ )));
+ $guids = array();
+ foreach ($entity_rows as $row) {
+ $guids[] = $row->guid;
+ }
+ delete_data("DELETE FROM {$db_prefix}entities WHERE guid IN (" . implode(',', $guids) . ")");
+ delete_data("DELETE FROM {$db_prefix}objects_entity WHERE guid IN (" . implode(',', $guids) . ")");
+ }
+
+ static function elgg_batch_callback_test($options, $reset = false) {
+ static $count = 1;
+
+ if ($reset) {
+ $count = 1;
+ return true;
+ }
+
+ if ($count > 20) {
+ return false;
+ }
+
+ for ($j = 0; ($options['limit'] < 5) ? $j < $options['limit'] : $j < 5; $j++) {
+ $return[] = array(
+ 'offset' => $options['offset'],
+ 'limit' => $options['limit'],
+ 'count' => $count++,
+ 'index' => 1 + $options['offset'] + $j
+ );
+ }
+
+ return $return;
+ }
+} \ No newline at end of file
diff --git a/engine/tests/api/metadata.php b/engine/tests/api/metadata.php
new file mode 100644
index 000000000..d23510c6a
--- /dev/null
+++ b/engine/tests/api/metadata.php
@@ -0,0 +1,230 @@
+<?php
+/**
+ * Elgg Test metadata API
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreMetadataAPITest extends ElggCoreUnitTest {
+ protected $metastrings;
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+ $this->metastrings = array();
+ $this->object = new ElggObject();
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ // do not allow SimpleTest to interpret Elgg notices as exceptions
+ $this->swallowErrors();
+
+ unset($this->object);
+ }
+
+ public function testGetMetastringById() {
+ foreach (array('metaUnitTest', 'metaunittest', 'METAUNITTEST') as $string) {
+ // since there is no guarantee that metastrings are garbage collected
+ // between unit test runs, we delete before testing
+ $this->delete_metastrings($string);
+ $this->create_metastring($string);
+ }
+
+ // lookup metastring id
+ $cs_ids = get_metastring_id('metaUnitTest', TRUE);
+ $this->assertEqual($cs_ids, $this->metastrings['metaUnitTest']);
+
+ // lookup all metastrings, ignoring case
+ $cs_ids = get_metastring_id('metaUnitTest', FALSE);
+ $this->assertEqual(count($cs_ids), 3);
+ $this->assertEqual(count($cs_ids), count($this->metastrings));
+ foreach ($cs_ids as $string )
+ {
+ $this->assertTrue(in_array($string, $this->metastrings));
+ }
+ }
+
+ public function testElggGetEntitiesFromMetadata() {
+ global $CONFIG, $METASTRINGS_CACHE, $METASTRINGS_DEADNAME_CACHE;
+ $METASTRINGS_CACHE = $METASTRINGS_DEADNAME_CACHE = array();
+
+ $this->object->title = 'Meta Unit Test';
+ $this->object->save();
+ $this->create_metastring('metaUnitTest');
+ $this->create_metastring('tested');
+
+ // create_metadata returns id of metadata on success
+ $this->assertNotEqual(false, create_metadata($this->object->guid, 'metaUnitTest', 'tested'));
+
+ // check value with improper case
+ $options = array('metadata_names' => 'metaUnitTest', 'metadata_values' => 'Tested', 'limit' => 10, 'metadata_case_sensitive' => TRUE);
+ $this->assertIdentical(array(), elgg_get_entities_from_metadata($options));
+
+ // compare forced case with ignored case
+ $options = array('metadata_names' => 'metaUnitTest', 'metadata_values' => 'tested', 'limit' => 10, 'metadata_case_sensitive' => TRUE);
+ $case_true = elgg_get_entities_from_metadata($options);
+ $this->assertIsA($case_true, 'array');
+
+ $options = array('metadata_names' => 'metaUnitTest', 'metadata_values' => 'Tested', 'limit' => 10, 'metadata_case_sensitive' => FALSE);
+ $case_false = elgg_get_entities_from_metadata($options);
+ $this->assertIsA($case_false, 'array');
+
+ $this->assertIdentical($case_true, $case_false);
+
+ // clean up
+ $this->object->delete();
+ }
+
+ public function testElggGetMetadataCount() {
+ $this->object->title = 'Meta Unit Test';
+ $this->object->save();
+
+ $guid = $this->object->getGUID();
+ create_metadata($guid, 'tested', 'tested1', 'text', 0, ACCESS_PUBLIC, true);
+ create_metadata($guid, 'tested', 'tested2', 'text', 0, ACCESS_PUBLIC, true);
+
+ $count = (int)elgg_get_metadata(array(
+ 'metadata_names' => array('tested'),
+ 'guid' => $guid,
+ 'count' => true,
+ ));
+
+ $this->assertIdentical($count, 2);
+
+ $this->object->delete();
+ }
+
+ public function testElggDeleteMetadata() {
+ $e = new ElggObject();
+ $e->save();
+
+ for ($i = 0; $i < 30; $i++) {
+ $name = "test_metadata$i";
+ $e->$name = rand(0, 10000);
+ }
+
+ $options = array(
+ 'guid' => $e->getGUID(),
+ 'limit' => 0,
+ );
+
+ $md = elgg_get_metadata($options);
+ $this->assertIdentical(30, count($md));
+
+ $this->assertTrue(elgg_delete_metadata($options));
+
+ $md = elgg_get_metadata($options);
+ $this->assertTrue(empty($md));
+
+ $e->delete();
+ }
+
+ /**
+ * https://github.com/Elgg/Elgg/issues/4867
+ */
+ public function testElggGetEntityMetadataWhereSqlWithFalseValue() {
+ $pair = array('name' => 'test' , 'value' => false);
+ $result = elgg_get_entity_metadata_where_sql('e', 'metadata', null, null, $pair);
+ $where = preg_replace( '/\s+/', ' ', $result['wheres'][0]);
+ $this->assertTrue(strpos($where, "msn1.string = 'test' AND BINARY msv1.string = 0") > 0);
+
+ $result = elgg_get_entity_metadata_where_sql('e', 'metadata', array('test'), array(false));
+ $where = preg_replace( '/\s+/', ' ', $result['wheres'][0]);
+ $this->assertTrue(strpos($where, "msn.string IN ('test')) AND ( BINARY msv.string IN ('0')"));
+ }
+
+ // Make sure metadata with multiple values is correctly deleted when re-written
+ // by another user
+ // https://github.com/elgg/elgg/issues/2776
+ public function test_elgg_metadata_multiple_values() {
+ $u1 = new ElggUser();
+ $u1->username = rand();
+ $u1->save();
+
+ $u2 = new ElggUser();
+ $u2->username = rand();
+ $u2->save();
+
+ $obj = new ElggObject();
+ $obj->owner_guid = $u1->guid;
+ $obj->container_guid = $u1->guid;
+ $obj->access_id = ACCESS_PUBLIC;
+ $obj->save();
+
+ $md_values = array(
+ 'one',
+ 'two',
+ 'three'
+ );
+
+ // need to fake different logins.
+ // good times without mocking.
+ $original_user = elgg_get_logged_in_user_entity();
+ $_SESSION['user'] = $u1;
+
+ elgg_set_ignore_access(false);
+
+ // add metadata as one user
+ $obj->test = $md_values;
+
+ // check only these md exists
+ $db_prefix = elgg_get_config('dbprefix');
+ $q = "SELECT * FROM {$db_prefix}metadata WHERE entity_guid = $obj->guid";
+ $data = get_data($q);
+
+ $this->assertEqual(count($md_values), count($data));
+ foreach ($data as $md_row) {
+ $md = elgg_get_metadata_from_id($md_row->id);
+ $this->assertTrue(in_array($md->value, $md_values));
+ $this->assertEqual('test', $md->name);
+ }
+
+ // add md w/ same name as a different user
+ $_SESSION['user'] = $u2;
+ $md_values2 = array(
+ 'four',
+ 'five',
+ 'six',
+ 'seven'
+ );
+
+ $obj->test = $md_values2;
+
+ $q = "SELECT * FROM {$db_prefix}metadata WHERE entity_guid = $obj->guid";
+ $data = get_data($q);
+
+ $this->assertEqual(count($md_values2), count($data));
+ foreach ($data as $md_row) {
+ $md = elgg_get_metadata_from_id($md_row->id);
+ $this->assertTrue(in_array($md->value, $md_values2));
+ $this->assertEqual('test', $md->name);
+ }
+
+ $_SESSION['user'] = $original_user;
+
+ $obj->delete();
+ $u1->delete();
+ $u2->delete();
+ }
+
+ protected function delete_metastrings($string) {
+ global $CONFIG, $METASTRINGS_CACHE, $METASTRINGS_DEADNAME_CACHE;
+ $METASTRINGS_CACHE = $METASTRINGS_DEADNAME_CACHE = array();
+
+ $string = sanitise_string($string);
+ mysql_query("DELETE FROM {$CONFIG->dbprefix}metastrings WHERE string = BINARY '$string'");
+ }
+
+ protected function create_metastring($string) {
+ global $CONFIG, $METASTRINGS_CACHE, $METASTRINGS_DEADNAME_CACHE;
+ $METASTRINGS_CACHE = $METASTRINGS_DEADNAME_CACHE = array();
+
+ $string = sanitise_string($string);
+ mysql_query("INSERT INTO {$CONFIG->dbprefix}metastrings (string) VALUES ('$string')");
+ $this->metastrings[$string] = mysql_insert_id();
+ }
+}
diff --git a/engine/tests/api/metadata_cache.php b/engine/tests/api/metadata_cache.php
new file mode 100644
index 000000000..7fb328169
--- /dev/null
+++ b/engine/tests/api/metadata_cache.php
@@ -0,0 +1,176 @@
+<?php
+/**
+ * Elgg Test metadata cache
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreMetadataCacheTest extends ElggCoreUnitTest {
+
+ /**
+ * @var ElggVolatileMetadataCache
+ */
+ protected $cache;
+
+ /**
+ * @var ElggObject
+ */
+ protected $obj1;
+
+ /**
+ * @var int
+ */
+ protected $guid1;
+
+ /**
+ * @var ElggObject
+ */
+ protected $obj2;
+
+ /**
+ * @var int
+ */
+ protected $guid2;
+
+ protected $name = 'test';
+ protected $value = 'test';
+ protected $ignoreAccess;
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+ $this->ignoreAccess = elgg_set_ignore_access(false);
+
+ $this->cache = elgg_get_metadata_cache();
+
+ $this->obj1 = new ElggObject();
+ $this->obj1->save();
+ $this->guid1 = $this->obj1->guid;
+
+ $this->obj2 = new ElggObject();
+ $this->obj2->save();
+ $this->guid2 = $this->obj2->guid;
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ $this->obj1->delete();
+ $this->obj2->delete();
+
+ elgg_set_ignore_access($this->ignoreAccess);
+ }
+
+ public function testBasicApi() {
+ // test de-coupled instance
+ $cache = new ElggVolatileMetadataCache();
+ $cache->setIgnoreAccess(false);
+ $guid = 1;
+
+ $this->assertFalse($cache->isKnown($guid, $this->name));
+
+ $cache->markEmpty($guid, $this->name);
+ $this->assertTrue($cache->isKnown($guid, $this->name));
+ $this->assertNull($cache->load($guid, $this->name));
+
+ $cache->markUnknown($guid, $this->name);
+ $this->assertFalse($cache->isKnown($guid, $this->name));
+
+ $cache->save($guid, $this->name, $this->value);
+ $this->assertIdentical($cache->load($guid, $this->name), $this->value);
+
+ $cache->save($guid, $this->name, 1, true);
+ $this->assertIdentical($cache->load($guid, $this->name), array($this->value, 1));
+
+ $cache->clear($guid);
+ $this->assertFalse($cache->isKnown($guid, $this->name));
+ }
+
+ public function testReadsAreCached() {
+ // test that reads fill cache
+ $this->obj1->setMetaData($this->name, $this->value);
+ $this->cache->flush();
+
+ $this->obj1->getMetaData($this->name);
+ $this->assertIdentical($this->cache->load($this->guid1, $this->name), $this->value);
+ }
+
+ public function testWritesAreCached() {
+ // delete should mark cache as known to be empty
+ $this->obj1->deleteMetadata($this->name);
+ $this->assertTrue($this->cache->isKnown($this->guid1, $this->name));
+ $this->assertNull($this->cache->load($this->guid1, $this->name));
+
+ // without name, delete should invalidate the entire entity
+ $this->cache->save($this->guid1, $this->name, $this->value);
+ elgg_delete_metadata(array(
+ 'guid' => $this->guid1,
+ ));
+ $this->assertFalse($this->cache->isKnown($this->guid1, $this->name));
+
+ // test set
+ $this->obj1->setMetaData($this->name, $this->value);
+ $this->assertIdentical($this->cache->load($this->guid1, $this->name), $this->value);
+
+ // test set multiple
+ $this->obj1->setMetaData($this->name, 1, 'integer', true);
+ $this->assertIdentical($this->cache->load($this->guid1, $this->name), array($this->value, 1));
+
+ // writes when access is ignore should invalidate
+ $tmp_ignore = elgg_set_ignore_access(true);
+ $this->obj1->setMetaData($this->name, $this->value);
+ $this->assertFalse($this->cache->isKnown($this->guid1, $this->name));
+ elgg_set_ignore_access($tmp_ignore);
+ }
+
+ public function testDisableAndEnable() {
+ // both should mark cache unknown
+ $this->obj1->setMetaData($this->name, $this->value);
+ $this->obj1->disableMetadata($this->name);
+ $this->assertFalse($this->cache->isKnown($this->guid1, $this->name));
+
+ $this->cache->save($this->guid1, $this->name, $this->value);
+ $this->obj1->enableMetadata($this->name);
+ $this->assertFalse($this->cache->isKnown($this->guid1, $this->name));
+ }
+
+ public function testPopulateFromEntities() {
+ // test populating cache from set of entities
+ $this->obj1->setMetaData($this->name, $this->value);
+ $this->obj1->setMetaData($this->name, 4, 'integer', true);
+ $this->obj1->setMetaData("{$this->name}-2", "{$this->value}-2");
+ $this->obj2->setMetaData($this->name, $this->value);
+
+ $this->cache->flush();
+ $this->cache->populateFromEntities(array($this->guid1, $this->guid2));
+
+ $expected = array();
+ $expected[$this->name][] = $this->value;
+ $expected[$this->name][] = 4;
+ $expected["{$this->name}-2"] = "{$this->value}-2";
+ $this->assertIdentical($this->cache->loadAll($this->guid1), $expected);
+
+ $expected = array();
+ $expected[$this->name] = $this->value;
+ $this->assertIdentical($this->cache->loadAll($this->guid2), $expected);
+ }
+
+ public function testFilterHeavyEntities() {
+ $big_str = str_repeat('-', 5000);
+ $this->obj2->setMetaData($this->name, array($big_str, $big_str));
+
+ $guids = array($this->guid1, $this->guid2);
+ $expected = array($this->guid1);
+ $actual = $this->cache->filterMetadataHeavyEntities($guids, 6000);
+ $this->assertIdentical($actual, $expected);
+ }
+
+ public function testCreateMetadataInvalidates() {
+ $this->obj1->foo = 1;
+ create_metadata($this->guid1, 'foo', 2, '', elgg_get_logged_in_user_guid(), ACCESS_FRIENDS);
+
+ $this->assertEqual($this->obj1->foo, 2);
+ }
+}
diff --git a/engine/tests/api/metastrings.php b/engine/tests/api/metastrings.php
new file mode 100644
index 000000000..5efdab972
--- /dev/null
+++ b/engine/tests/api/metastrings.php
@@ -0,0 +1,217 @@
+<?php
+/**
+ * Elgg Metastrings test
+ *
+ * @package Elgg.Core
+ * @subpackage Metastrings.Test
+ */
+class ElggCoreMetastringsTest extends ElggCoreUnitTest {
+
+ public $metastringTypes = array('metadata', 'annotations');
+
+ /**
+ * Called before each test object.
+ */
+ public function __construct() {
+ parent::__construct();
+
+ $this->metastrings = array();
+ $this->object = new ElggObject();
+ $this->object->save();
+ }
+
+ public function createAnnotations($max = 1) {
+ $annotations = array();
+ for ($i=0; $i<$max; $i++) {
+ $name = 'test_annotation_name' . rand();
+ $value = 'test_annotation_value' . rand();
+ $id = create_annotation($this->object->guid, $name, $value);
+ $annotations[] = $id;
+ }
+
+ return $annotations;
+ }
+
+ public function createMetadata($max = 1) {
+ $metadata = array();
+ for ($i=0; $i<$max; $i++) {
+ $name = 'test_metadata_name' . rand();
+ $value = 'test_metadata_value' . rand();
+ $id = create_metadata($this->object->guid, $name, $value);
+ $metadata[] = $id;
+ }
+
+ return $metadata;
+ }
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ access_show_hidden_entities(true);
+ elgg_delete_annotations(array(
+ 'guid' => $this->object->guid,
+ ));
+ access_show_hidden_entities(false);
+ }
+
+ /**
+ * Called after each test object.
+ */
+ public function __destruct() {
+ $this->object->delete();
+
+ parent::__destruct();
+ }
+
+ public function testDeleteByID() {
+ $db_prefix = elgg_get_config('dbprefix');
+ $annotations = $this->createAnnotations(1);
+ $metadata = $this->createMetadata(1);
+
+ foreach ($this->metastringTypes as $type) {
+ $id = ${$type}[0];
+ $table = $db_prefix . $type;
+ $q = "SELECT * FROM $table WHERE id = $id";
+ $test = get_data($q);
+
+ $this->assertEqual($test[0]->id, $id);
+ $this->assertIdentical(true, elgg_delete_metastring_based_object_by_id($id, $type));
+ $this->assertIdentical(array(), get_data($q));
+ }
+ }
+
+ public function testGetMetastringObjectFromID() {
+ $db_prefix = elgg_get_config('dbprefix');
+ $annotations = $this->createAnnotations(1);
+ $metadata = $this->createMetadata(1);
+
+ foreach ($this->metastringTypes as $type) {
+ $id = ${$type}[0];
+ $test = elgg_get_metastring_based_object_from_id($id, $type);
+
+ $this->assertEqual($id, $test->id);
+ }
+ }
+
+ public function testGetMetastringObjectFromIDWithDisabledAnnotation() {
+ $name = 'test_annotation_name' . rand();
+ $value = 'test_annotation_value' . rand();
+ $id = create_annotation($this->object->guid, $name, $value);
+ $annotation = elgg_get_annotation_from_id($id);
+ $this->assertTrue($annotation->disable());
+
+ $test = elgg_get_metastring_based_object_from_id($id, 'annotation');
+ $this->assertEqual(false, $test);
+ }
+
+ public function testGetMetastringBasedObjectWithDisabledAnnotation() {
+ $name = 'test_annotation_name' . rand();
+ $value = 'test_annotation_value' . rand();
+ $id = create_annotation($this->object->guid, $name, $value);
+ $annotation = elgg_get_annotation_from_id($id);
+ $this->assertTrue($annotation->disable());
+
+ $test = elgg_get_metastring_based_objects(array(
+ 'metastring_type' => 'annotations',
+ 'guid' => $this->object->guid,
+ ));
+ $this->assertEqual(array(), $test);
+ }
+
+ public function testEnableDisableByID() {
+ $db_prefix = elgg_get_config('dbprefix');
+ $annotations = $this->createAnnotations(1);
+ $metadata = $this->createMetadata(1);
+
+ foreach ($this->metastringTypes as $type) {
+ $id = ${$type}[0];
+ $table = $db_prefix . $type;
+ $q = "SELECT * FROM $table WHERE id = $id";
+ $test = get_data($q);
+
+ // disable
+ $this->assertEqual($test[0]->enabled, 'yes');
+ $this->assertTrue(elgg_set_metastring_based_object_enabled_by_id($id, 'no', $type));
+
+ $test = get_data($q);
+ $this->assertEqual($test[0]->enabled, 'no');
+
+ // enable
+ $ashe = access_get_show_hidden_status();
+ access_show_hidden_entities(true);
+ $this->assertTrue(elgg_set_metastring_based_object_enabled_by_id($id, 'yes', $type));
+
+ $test = get_data($q);
+ $this->assertEqual($test[0]->enabled, 'yes');
+
+ access_show_hidden_entities($ashe);
+ }
+ }
+
+ public function testKeepMeFromDeletingEverything() {
+ foreach ($this->metastringTypes as $type) {
+ $required = array(
+ 'guid', 'guids'
+ );
+
+ switch ($type) {
+ case 'metadata':
+ $metadata_required = array(
+ 'metadata_owner_guid', 'metadata_owner_guids',
+ 'metadata_name', 'metadata_names',
+ 'metadata_value', 'metadata_values'
+ );
+
+ $required = array_merge($required, $metadata_required);
+ break;
+
+ case 'annotations':
+ $annotations_required = array(
+ 'annotation_owner_guid', 'annotation_owner_guids',
+ 'annotation_name', 'annotation_names',
+ 'annotation_value', 'annotation_values'
+ );
+
+ $required = array_merge($required, $annotations_required);
+ break;
+ }
+
+ $options = array();
+ $this->assertFalse(elgg_is_valid_options_for_batch_operation($options, $type));
+
+ // limit alone isn't valid:
+ $options = array('limit' => 10);
+ $this->assertFalse(elgg_is_valid_options_for_batch_operation($options, $type));
+
+ foreach ($required as $key) {
+ $options = array();
+
+ $options[$key] = ELGG_ENTITIES_ANY_VALUE;
+ $this->assertFalse(elgg_is_valid_options_for_batch_operation($options, $type), "Sent $key = ELGG_ENTITIES_ANY_VALUE");
+
+ $options[$key] = ELGG_ENTITIES_NO_VALUE;
+ $this->assertFalse(elgg_is_valid_options_for_batch_operation($options, $type), "Sent $key = ELGG_ENTITIES_NO_VALUE");
+
+ $options[$key] = false;
+ $this->assertFalse(elgg_is_valid_options_for_batch_operation($options, $type), "Sent $key = bool false");
+
+ $options[$key] = true;
+ $this->assertTrue(elgg_is_valid_options_for_batch_operation($options, $type), "Sent $key = bool true");
+
+ $options[$key] = 'test';
+ $this->assertTrue(elgg_is_valid_options_for_batch_operation($options, $type), "Sent $key = 'test'");
+
+ $options[$key] = array('test');
+ $this->assertTrue(elgg_is_valid_options_for_batch_operation($options, $type), "Sent $key = array('test')");
+ }
+ }
+ }
+}
diff --git a/engine/tests/api/output.php b/engine/tests/api/output.php
new file mode 100644
index 000000000..c3d5aa8c6
--- /dev/null
+++ b/engine/tests/api/output.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Test case for ElggAutoP functionality.
+ */
+class ElggCoreOutputAutoPTest extends ElggCoreUnitTest {
+
+ /**
+ * @var ElggAutoP
+ */
+ protected $_autop;
+
+ public function setUp() {
+ $this->_autop = new ElggAutoP();
+ }
+
+ public function testDomRoundtrip() {
+ $d = dir(dirname(dirname(__FILE__)) . '/test_files/output/autop');
+ $in = file_get_contents($d->path . "/domdoc_in.html");
+ $exp = file_get_contents($d->path . "/domdoc_exp.html");
+ $exp = $this->flattenString($exp);
+
+ $doc = new DOMDocument();
+ libxml_use_internal_errors(true);
+ $doc->loadHTML("<html><meta http-equiv='content-type' content='text/html; charset=utf-8'><body>"
+ . $in . '</body></html>');
+ $serialized = $doc->saveHTML();
+ list(,$out) = explode('<body>', $serialized, 2);
+ list($out) = explode('</body>', $out, 2);
+ $out = $this->flattenString($out);
+
+ $this->assertEqual($exp, $out, "DOMDocument's parsing/serialization roundtrip");
+ }
+
+ public function testProcess() {
+ $data = $this->provider();
+ foreach ($data as $row) {
+ list($test, $in, $exp) = $row;
+ $exp = $this->flattenString($exp);
+ $out = $this->_autop->process($in);
+ $out = $this->flattenString($out);
+
+ $this->assertEqual($exp, $out, "Equality case {$test}");
+ }
+ }
+
+ public function provider() {
+ $d = dir(dirname(dirname(__FILE__)) . '/test_files/output/autop');
+ $tests = array();
+ while (false !== ($entry = $d->read())) {
+ if (preg_match('/^([a-z\\-]+)\.in\.html$/i', $entry, $m)) {
+ $tests[] = $m[1];
+ }
+ }
+
+ $data = array();
+ foreach ($tests as $test) {
+ $data[] = array(
+ $test,
+ file_get_contents($d->path . '/' . "{$test}.in.html"),
+ file_get_contents($d->path . '/' . "{$test}.exp.html"),
+ );
+ }
+ return $data;
+ }
+
+ /**
+ * Different versions of PHP return different whitespace between tags.
+ * Removing all line breaks normalizes that.
+ */
+ public function flattenString($string) {
+ $r = preg_replace('/[\n\r]+/', '', $string);
+ return $r;
+ }
+} \ No newline at end of file
diff --git a/engine/tests/api/plugins.php b/engine/tests/api/plugins.php
new file mode 100644
index 000000000..d0f111c48
--- /dev/null
+++ b/engine/tests/api/plugins.php
@@ -0,0 +1,299 @@
+<?php
+/**
+ * Elgg Plugins Test
+ *
+ * @package Elgg.Core
+ * @subpackage Plugins.Test
+ */
+class ElggCorePluginsAPITest extends ElggCoreUnitTest {
+ // 1.8 manifest object
+ var $manifest18;
+
+ // 1.8 package at test_files/plugin_18/
+ var $package18;
+
+ // 1.7 manifest object
+ var $manifest17;
+
+ // 1.7 package at test_files/plugin_17/
+ var $package17;
+
+ public function __construct() {
+ parent::__construct();
+
+ $this->manifest18 = new ElggPluginManifest(get_config('path') . 'engine/tests/test_files/plugin_18/manifest.xml', 'plugin_test_18');
+ $this->manifest17 = new ElggPluginManifest(get_config('path') . 'engine/tests/test_files/plugin_17/manifest.xml', 'plugin_test_17');
+
+ $this->package18 = new ElggPluginPackage(get_config('path') . 'engine/tests/test_files/plugin_18');
+ $this->package17 = new ElggPluginPackage(get_config('path') . 'engine/tests/test_files/plugin_17');
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ // do not allow SimpleTest to interpret Elgg notices as exceptions
+ $this->swallowErrors();
+ }
+
+ // generic tests
+ public function testElggPluginManifestFromString() {
+ $manifest_file = file_get_contents(get_config('path') . 'engine/tests/test_files/plugin_17/manifest.xml');
+ $manifest = new ElggPluginManifest($manifest_file);
+
+ $this->assertIsA($manifest, 'ElggPluginManifest');
+ }
+
+ public function testElggPluginManifestFromFile() {
+ $file = get_config('path') . 'engine/tests/test_files/plugin_17/manifest.xml';
+ $manifest = new ElggPluginManifest($file);
+
+ $this->assertIsA($manifest, 'ElggPluginManifest');
+ }
+
+ public function testElggPluginManifestFromXMLEntity() {
+ $xml = xml_to_object($manifest_file = file_get_contents(get_config('path') . 'engine/tests/test_files/plugin_17/manifest.xml'));
+ $manifest = new ElggPluginManifest($xml);
+
+ $this->assertIsA($manifest, 'ElggPluginManifest');
+ }
+
+ // exact manifest values
+ // 1.8 interface
+ public function testElggPluginManifest18() {
+ $manifest_array = array(
+ 'name' => 'Test Manifest',
+ 'author' => 'Anyone',
+ 'version' => '1.0',
+ 'blurb' => 'A concise description.',
+ 'description' => 'A longer, more interesting description.',
+ 'website' => 'http://www.elgg.org/',
+ 'repository' => 'https://github.com/Elgg/Elgg',
+ 'bugtracker' => 'https://github.com/elgg/elgg/issues',
+ 'donations' => 'http://elgg.org/supporter.php',
+ 'copyright' => '(C) Elgg Foundation 2011',
+ 'license' => 'GNU General Public License version 2',
+
+ 'requires' => array(
+ array('type' => 'elgg_version', 'version' => '3009030802', 'comparison' => 'lt'),
+ array('type' => 'elgg_release', 'version' => '1.8-svn'),
+ array('type' => 'php_extension', 'name' => 'gd'),
+ array('type' => 'php_ini', 'name' => 'short_open_tag', 'value' => 'off'),
+ array('type' => 'php_extension', 'name' => 'made_up', 'version' => '1.0'),
+ array('type' => 'plugin', 'name' => 'fake_plugin', 'version' => '1.0'),
+ array('type' => 'plugin', 'name' => 'profile', 'version' => '1.0'),
+ array('type' => 'plugin', 'name' => 'profile_api', 'version' => '1.3', 'comparison' => 'lt'),
+ array('type' => 'priority', 'priority' => 'after', 'plugin' => 'profile'),
+ ),
+
+ 'screenshot' => array(
+ array('description' => 'Fun things to do 1', 'path' => 'graphics/plugin_ss1.png'),
+ array('description' => 'Fun things to do 2', 'path' => 'graphics/plugin_ss2.png'),
+ ),
+
+ 'category' => array(
+ 'Admin', 'ServiceAPI'
+ ),
+
+ 'conflicts' => array(
+ array('type' => 'plugin', 'name' => 'profile_api', 'version' => '1.0')
+ ),
+
+ 'provides' => array(
+ array('type' => 'plugin', 'name' => 'profile_api', 'version' => '1.3'),
+ array('type' => 'php_extension', 'name' => 'big_math', 'version' => '1.0')
+ ),
+
+ 'suggests' => array(
+ array('type' => 'plugin', 'name' => 'facebook_connect', 'version' => '1.0'),
+ ),
+
+ // string because we are reading from a file
+ 'activate_on_install' => 'true',
+ );
+
+ $this->assertIdentical($this->manifest18->getManifest(), $manifest_array);
+ }
+
+ public function testElggPluginManifest17() {
+ $manifest_array = array(
+ 'author' => 'Anyone',
+ 'version' => '1.0',
+ 'description' => 'A 1.7-style manifest.',
+ 'website' => 'http://www.elgg.org/',
+ 'copyright' => '(C) Elgg Foundation 2011',
+ 'license' => 'GNU General Public License version 2',
+ 'elgg_version' => '2009030702',
+ 'name' => 'Plugin Test 17',
+ );
+
+ $this->assertIdentical($this->manifest17->getManifest(), $manifest_array);
+ }
+
+
+ public function testElggPluginManifestGetApiVersion() {
+ $this->assertEqual($this->manifest18->getApiVersion(), 1.8);
+ $this->assertEqual($this->manifest17->getApiVersion(), 1.7);
+ }
+
+ public function testElggPluginManifestGetPluginID() {
+ $this->assertEqual($this->manifest18->getPluginID(), 'plugin_test_18');
+ $this->assertEqual($this->manifest17->getPluginID(), 'plugin_test_17');
+ }
+
+
+ // normalized attributes
+ public function testElggPluginManifestGetName() {
+ $this->assertEqual($this->manifest18->getName(), 'Test Manifest');
+ $this->assertEqual($this->manifest17->getName(), 'Plugin Test 17');
+ }
+
+ public function testElggPluginManifestGetAuthor() {
+ $this->assertEqual($this->manifest18->getAuthor(), 'Anyone');
+ $this->assertEqual($this->manifest17->getAuthor(), 'Anyone');
+ }
+
+ public function testElggPluginManifestGetVersion() {
+ $this->assertEqual($this->manifest18->getVersion(), 1.0);
+ $this->assertEqual($this->manifest17->getVersion(), 1.0);
+ }
+
+ public function testElggPluginManifestGetBlurb() {
+ $this->assertEqual($this->manifest18->getBlurb(), 'A concise description.');
+ $this->assertEqual($this->manifest17->getBlurb(), 'A 1.7-style manifest.');
+ }
+
+ public function testElggPluginManifestGetWebsite() {
+ $this->assertEqual($this->manifest18->getWebsite(), 'http://www.elgg.org/');
+ $this->assertEqual($this->manifest17->getWebsite(), 'http://www.elgg.org/');
+ }
+
+ public function testElggPluginManifestGetRepository() {
+ $this->assertEqual($this->manifest18->getRepositoryURL(), 'https://github.com/Elgg/Elgg');
+ $this->assertEqual($this->manifest17->getRepositoryURL(), '');
+ }
+
+ public function testElggPluginManifestGetBugtracker() {
+ $this->assertEqual($this->manifest18->getBugTrackerURL(), 'https://github.com/elgg/elgg/issues');
+ $this->assertEqual($this->manifest17->getBugTrackerURL(), '');
+ }
+
+ public function testElggPluginManifestGetDonationsPage() {
+ $this->assertEqual($this->manifest18->getDonationsPageURL(), 'http://elgg.org/supporter.php');
+ $this->assertEqual($this->manifest17->getDonationsPageURL(), '');
+ }
+
+ public function testElggPluginManifestGetCopyright() {
+ $this->assertEqual($this->manifest18->getCopyright(), '(C) Elgg Foundation 2011');
+ $this->assertEqual($this->manifest18->getCopyright(), '(C) Elgg Foundation 2011');
+ }
+
+ public function testElggPluginManifestGetLicense() {
+ $this->assertEqual($this->manifest18->getLicense(), 'GNU General Public License version 2');
+ $this->assertEqual($this->manifest17->getLicense(), 'GNU General Public License version 2');
+ }
+
+
+ public function testElggPluginManifestGetRequires() {
+ $requires = array(
+ array('type' => 'elgg_version', 'version' => '3009030802', 'comparison' => 'lt'),
+ array('type' => 'elgg_release', 'version' => '1.8-svn', 'comparison' => 'ge'),
+ array('type' => 'php_extension', 'name' => 'gd', 'version' => '', 'comparison' => '='),
+ array('type' => 'php_ini', 'name' => 'short_open_tag', 'value' => 0, 'comparison' => '='),
+ array('type' => 'php_extension', 'name' => 'made_up', 'version' => '1.0', 'comparison' => '='),
+ array('type' => 'plugin', 'name' => 'fake_plugin', 'version' => '1.0', 'comparison' => 'ge'),
+ array('type' => 'plugin', 'name' => 'profile', 'version' => '1.0', 'comparison' => 'ge'),
+ array('type' => 'plugin', 'name' => 'profile_api', 'version' => '1.3', 'comparison' => 'lt'),
+ array('type' => 'priority', 'priority' => 'after', 'plugin' => 'profile'),
+ );
+
+ $this->assertIdentical($this->package18->getManifest()->getRequires(), $requires);
+
+ $requires = array(
+ array('type' => 'elgg_version', 'version' => '2009030702', 'comparison' => 'ge')
+ );
+
+ $this->assertIdentical($this->package17->getManifest()->getRequires(), $requires);
+ }
+
+ public function testElggPluginManifestGetSuggests() {
+ $suggests = array(
+ array('type' => 'plugin', 'name' => 'facebook_connect', 'version' => '1.0', 'comparison' => 'ge'),
+ );
+
+ $this->assertIdentical($this->package18->getManifest()->getSuggests(), $suggests);
+
+ $suggests = array();
+
+ $this->assertIdentical($this->package17->getManifest()->getSuggests(), $suggests);
+ }
+
+ public function testElggPluginManifestGetDescription() {
+ $this->assertEqual($this->package18->getManifest()->getDescription(), 'A longer, more interesting description.');
+ $this->assertEqual($this->package17->getManifest()->getDescription(), 'A 1.7-style manifest.');
+ }
+
+ public function testElggPluginManifestGetCategories() {
+ $categories = array(
+ 'Admin', 'ServiceAPI'
+ );
+
+ $this->assertIdentical($this->package18->getManifest()->getCategories(), $categories);
+ $this->assertIdentical($this->package17->getManifest()->getCategories(), array());
+ }
+
+ public function testElggPluginManifestGetScreenshots() {
+ $screenshots = array(
+ array('description' => 'Fun things to do 1', 'path' => 'graphics/plugin_ss1.png'),
+ array('description' => 'Fun things to do 2', 'path' => 'graphics/plugin_ss2.png'),
+ );
+
+ $this->assertIdentical($this->package18->getManifest()->getScreenshots(), $screenshots);
+ $this->assertIdentical($this->package17->getManifest()->getScreenshots(), array());
+ }
+
+ public function testElggPluginManifestGetProvides() {
+ $provides = array(
+ array('type' => 'plugin', 'name' => 'profile_api', 'version' => '1.3'),
+ array('type' => 'php_extension', 'name' => 'big_math', 'version' => '1.0'),
+ array('type' => 'plugin', 'name' => 'plugin_18', 'version' => '1.0')
+ );
+
+ $this->assertIdentical($this->package18->getManifest()->getProvides(), $provides);
+
+
+ $provides = array(
+ array('type' => 'plugin', 'name' => 'plugin_17', 'version' => '1.0')
+ );
+
+ $this->assertIdentical($this->package17->getManifest()->getProvides(), $provides);
+ }
+
+ public function testElggPluginManifestGetConflicts() {
+ $conflicts = array(
+ array(
+ 'type' => 'plugin',
+ 'name' => 'profile_api',
+ 'version' => '1.0',
+ 'comparison' => '='
+ )
+ );
+
+ $this->assertIdentical($this->manifest18->getConflicts(), $conflicts);
+ $this->assertIdentical($this->manifest17->getConflicts(), array());
+ }
+
+ public function testElggPluginManifestGetActivateOnInstall() {
+ $this->assertIdentical($this->manifest18->getActivateOnInstall(), true);
+ }
+
+ // ElggPluginPackage
+ public function testElggPluginPackageDetectIDFromPath() {
+ $this->assertEqual($this->package18->getID(), 'plugin_18');
+ }
+
+ public function testElggPluginPackageDetectIDFromPluginID() {
+ $package = new ElggPluginPackage('profile');
+ $this->assertEqual($package->getID(), 'profile');
+ }
+}
diff --git a/engine/tests/api/river.php b/engine/tests/api/river.php
new file mode 100644
index 000000000..6931b9f41
--- /dev/null
+++ b/engine/tests/api/river.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Elgg Test river api
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreRiverAPITest extends ElggCoreUnitTest {
+
+ public function testElggTypeSubtypeWhereSQL() {
+ $types = array('object');
+ $subtypes = array('blog');
+ $result = elgg_get_river_type_subtype_where_sql('rv', $types, $subtypes, null);
+ $this->assertIdentical($result, "((rv.type = 'object') AND ((rv.subtype = 'blog')))");
+
+ $types = array('object');
+ $subtypes = array('blog', 'file');
+ $result = elgg_get_river_type_subtype_where_sql('rv', $types, $subtypes, null);
+ $this->assertIdentical($result, "((rv.type = 'object') AND ((rv.subtype = 'blog') OR (rv.subtype = 'file')))");
+ }
+}
diff --git a/engine/tests/elgg_unit_test.php b/engine/tests/elgg_unit_test.php
new file mode 100644
index 000000000..70f8788a0
--- /dev/null
+++ b/engine/tests/elgg_unit_test.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * Elgg Core Unit Tester
+ *
+ * This class is to be extended by all Elgg unit tests. As such, any method here
+ * will be available to the tests.
+ */
+abstract class ElggCoreUnitTest extends UnitTestCase
+{
+ /**
+ * Class constructor.
+ *
+ * A simple wrapper to call the parent constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+ /**
+ * Class destructor.
+ *
+ * The parent does not provide a destructor, so including an explicit one here.
+ */
+ public function __destruct()
+ {
+ }
+}
diff --git a/engine/tests/objects/entities.php b/engine/tests/objects/entities.php
new file mode 100644
index 000000000..bac72079e
--- /dev/null
+++ b/engine/tests/objects/entities.php
@@ -0,0 +1,423 @@
+<?php
+/**
+ * Elgg Test ElggEntities
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreEntityTest extends ElggCoreUnitTest {
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+ $this->entity = new ElggEntityTest();
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ $this->swallowErrors();
+ unset($this->entity);
+ }
+
+ /**
+ * Tests the protected attributes
+ */
+ public function testElggEntityAttributes() {
+ $test_attributes = array();
+ $test_attributes['guid'] = NULL;
+ $test_attributes['type'] = NULL;
+ $test_attributes['subtype'] = NULL;
+ $test_attributes['owner_guid'] = elgg_get_logged_in_user_guid();
+ $test_attributes['container_guid'] = elgg_get_logged_in_user_guid();
+ $test_attributes['site_guid'] = NULL;
+ $test_attributes['access_id'] = ACCESS_PRIVATE;
+ $test_attributes['time_created'] = NULL;
+ $test_attributes['time_updated'] = NULL;
+ $test_attributes['last_action'] = NULL;
+ $test_attributes['enabled'] = 'yes';
+ $test_attributes['tables_split'] = 1;
+ $test_attributes['tables_loaded'] = 0;
+ ksort($test_attributes);
+
+ $entity_attributes = $this->entity->expose_attributes();
+ ksort($entity_attributes);
+
+ $this->assertIdentical($entity_attributes, $test_attributes);
+ }
+
+ public function testElggEntityGetAndSetBaseAttributes() {
+ // explicitly set and get access_id
+ $this->assertIdentical($this->entity->get('access_id'), ACCESS_PRIVATE);
+ $this->assertTrue($this->entity->set('access_id', ACCESS_PUBLIC));
+ $this->assertIdentical($this->entity->get('access_id'), ACCESS_PUBLIC);
+
+ // check internal attributes array
+ $attributes = $this->entity->expose_attributes();
+ $this->assertIdentical($attributes['access_id'], ACCESS_PUBLIC);
+
+ // implicitly set and get access_id
+ $this->entity->access_id = ACCESS_PRIVATE;
+ $this->assertIdentical($this->entity->access_id, ACCESS_PRIVATE);
+
+ // unset access_id
+ unset($this->entity->access_id);
+ $this->assertIdentical($this->entity->access_id, '');
+
+ // unable to directly set guid
+ $this->assertFalse($this->entity->set('guid', 'error'));
+ $this->entity->guid = 'error';
+ $this->assertNotEqual($this->entity->guid, 'error');
+
+ // fail on non-attribute
+ $this->assertNull($this->entity->get('non_existent'));
+
+ // consider helper methods
+ $this->assertIdentical($this->entity->getGUID(), $this->entity->guid );
+ $this->assertIdentical($this->entity->getType(), $this->entity->type );
+ $this->assertIdentical($this->entity->getSubtype(), $this->entity->subtype );
+ $this->assertIdentical($this->entity->getOwnerGUID(), $this->entity->owner_guid );
+ $this->assertIdentical($this->entity->getAccessID(), $this->entity->access_id );
+ $this->assertIdentical($this->entity->getTimeCreated(), $this->entity->time_created );
+ $this->assertIdentical($this->entity->getTimeUpdated(), $this->entity->time_updated );
+ }
+
+ public function testElggEntityGetAndSetMetaData() {
+ // ensure metadata not set
+ $this->assertNull($this->entity->get('non_existent'));
+ $this->assertFalse(isset($this->entity->non_existent));
+
+ // create metadata
+ $this->entity->existent = 'testing';
+ $this->assertIdentical($this->entity->existent, 'testing');
+
+ // check metadata set
+ $this->assertTrue(isset($this->entity->existent));
+ $this->assertIdentical($this->entity->getMetaData('existent'), 'testing');
+
+ // check internal metadata array
+ $metadata = $this->entity->expose_metadata();
+ $this->assertIdentical($metadata['existent'], array('testing'));
+ }
+
+ public function testElggEnityGetAndSetAnnotations() {
+ $this->assertFalse(array_key_exists('non_existent', $this->entity->expose_annotations()));
+ $this->assertIdentical($this->entity->getAnnotations('non_existent'), array());
+
+ // set and check temp annotation
+ $this->assertTrue($this->entity->annotate('non_existent', 'testing'));
+ $this->assertIdentical($this->entity->getAnnotations('non_existent'), array('testing'));
+ $this->assertTrue(array_key_exists('non_existent', $this->entity->expose_annotations()));
+
+ // save entity and check for annotation
+ $this->entity->subtype = 'testing';
+ $this->save_entity();
+ $this->assertFalse(array_key_exists('non_existent', $this->entity->expose_annotations()));
+ $annotations = $this->entity->getAnnotations('non_existent');
+ $this->assertIsA($annotations[0], 'ElggAnnotation');
+ $this->assertIdentical($annotations[0]->name, 'non_existent');
+ $this->assertEqual($this->entity->countAnnotations('non_existent'), 1);
+
+ $this->assertIdentical($annotations, elgg_get_annotations(array('guid' => $this->entity->getGUID())));
+ $this->assertIdentical($annotations, elgg_get_annotations(array('guid' => $this->entity->getGUID(), 'type' => 'site')));
+ $this->assertIdentical($annotations, elgg_get_annotations(array('guid' => $this->entity->getGUID(), 'type' => 'site', 'subtype' => 'testing')));
+ $this->assertIdentical(FALSE, elgg_get_annotations(array('guid' => $this->entity->getGUID(), 'type' => 'site', 'subtype' => 'fail')));
+
+ // clear annotation
+ $this->assertTrue($this->entity->deleteAnnotations());
+ $this->assertEqual($this->entity->countAnnotations('non_existent'), 0);
+
+ $this->assertIdentical(array(), elgg_get_annotations(array('guid' => $this->entity->getGUID())));
+ $this->assertIdentical(array(), elgg_get_annotations(array('guid' => $this->entity->getGUID(), 'type' => 'site')));
+ $this->assertIdentical(array(), elgg_get_annotations(array('guid' => $this->entity->getGUID(), 'type' => 'site', 'subtype' => 'testing')));
+
+ // clean up
+ $this->assertTrue($this->entity->delete());
+ remove_subtype('site', 'testing');
+ }
+
+ public function testElggEntityCache() {
+ global $ENTITY_CACHE;
+ $this->assertIsA($ENTITY_CACHE, 'array');
+ }
+
+ public function testElggEntitySaveAndDelete() {
+ global $ENTITY_CACHE;
+
+ // unable to delete with no guid
+ $this->assertFalse($this->entity->delete());
+
+ // error on save
+ try {
+ $this->entity->save();
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'InvalidParameterException');
+ $this->assertIdentical($e->getMessage(), elgg_echo('InvalidParameterException:EntityTypeNotSet'));
+ }
+
+ // set elements
+ $this->entity->type = 'site';
+ $this->entity->non_existent = 'testing';
+
+ // save
+ $this->AssertEqual($this->entity->getGUID(), 0);
+ $guid = $this->entity->save();
+ $this->AssertNotEqual($guid, 0);
+
+ // check guid
+ $this->AssertEqual($this->entity->getGUID(), $guid);
+ $attributes = $this->entity->expose_attributes();
+ $this->AssertEqual($attributes['guid'], $guid);
+ $this->AssertIdentical($ENTITY_CACHE[$guid], $this->entity);
+
+ // check metadata
+ $metadata = $this->entity->expose_metadata();
+ $this->AssertFalse(in_array('non_existent', $metadata));
+ $this->AssertEqual($this->entity->get('non_existent'), 'testing');
+
+ // clean up with delete
+ $this->assertIdentical(true, $this->entity->delete());
+ }
+
+ public function testElggEntityDisableAndEnable() {
+ global $CONFIG;
+
+ // ensure enabled
+ $this->assertTrue($this->entity->isEnabled());
+
+ // false on disable because it's not saved yet.
+ $this->assertFalse($this->entity->disable());
+
+ // save and disable
+ $this->save_entity();
+
+ // add annotations and metadata to check if they're disabled.
+ $annotation_id = create_annotation($this->entity->guid, 'test_annotation_' . rand(), 'test_value_' . rand());
+ $metadata_id = create_metadata($this->entity->guid, 'test_metadata_' . rand(), 'test_value_' . rand());
+
+ $this->assertTrue($this->entity->disable());
+
+ // ensure disabled by comparing directly with database
+ $entity = get_data_row("SELECT * FROM {$CONFIG->dbprefix}entities WHERE guid = '{$this->entity->guid}'");
+ $this->assertIdentical($entity->enabled, 'no');
+
+ $annotation = get_data_row("SELECT * FROM {$CONFIG->dbprefix}annotations WHERE id = '$annotation_id'");
+ $this->assertIdentical($annotation->enabled, 'no');
+
+ $metadata = get_data_row("SELECT * FROM {$CONFIG->dbprefix}metadata WHERE id = '$metadata_id'");
+ $this->assertIdentical($metadata->enabled, 'no');
+
+ // re-enable for deletion to work
+ $this->assertTrue($this->entity->enable());
+
+ // check enabled
+ // check annotations and metadata enabled.
+ $entity = get_data_row("SELECT * FROM {$CONFIG->dbprefix}entities WHERE guid = '{$this->entity->guid}'");
+ $this->assertIdentical($entity->enabled, 'yes');
+
+ $annotation = get_data_row("SELECT * FROM {$CONFIG->dbprefix}annotations WHERE id = '$annotation_id'");
+ $this->assertIdentical($annotation->enabled, 'yes');
+
+ $metadata = get_data_row("SELECT * FROM {$CONFIG->dbprefix}metadata WHERE id = '$metadata_id'");
+ $this->assertIdentical($metadata->enabled, 'yes');
+
+ $this->assertTrue($this->entity->delete());
+ }
+
+ public function testElggEntityRecursiveDisableAndEnable() {
+ global $CONFIG;
+
+ $this->save_entity();
+ $obj1 = new ElggObject();
+ $obj1->container_guid = $this->entity->getGUID();
+ $obj1->save();
+ $obj2 = new ElggObject();
+ $obj2->container_guid = $this->entity->getGUID();
+ $obj2->save();
+
+ // disable $obj2 before disabling the container
+ $this->assertTrue($obj2->disable());
+
+ // disable entities container by $this->entity
+ $this->assertTrue($this->entity->disable());
+ $entity = get_data_row("SELECT * FROM {$CONFIG->dbprefix}entities WHERE guid = '{$obj1->guid}'");
+ $this->assertIdentical($entity->enabled, 'no');
+
+ // enable entities that were disabled with the container (but not $obj2)
+ $this->assertTrue($this->entity->enable());
+ $entity = get_data_row("SELECT * FROM {$CONFIG->dbprefix}entities WHERE guid = '{$obj1->guid}'");
+ $this->assertIdentical($entity->enabled, 'yes');
+ $entity = get_data_row("SELECT * FROM {$CONFIG->dbprefix}entities WHERE guid = '{$obj2->guid}'");
+ $this->assertIdentical($entity->enabled, 'no');
+
+ // cleanup
+ $this->assertTrue($obj2->enable());
+ $this->assertTrue($obj2->delete());
+ $this->assertTrue($obj1->delete());
+ $this->assertTrue($this->entity->delete());
+ }
+
+ public function testElggEntityMetadata() {
+ // let's delete a non-existent metadata
+ $this->assertFalse($this->entity->deleteMetadata('important'));
+
+ // let's add the metadata
+ $this->entity->important = 'indeed!';
+ $this->assertIdentical('indeed!', $this->entity->important);
+ $this->entity->less_important = 'true, too!';
+ $this->assertIdentical('true, too!', $this->entity->less_important);
+ $this->save_entity();
+
+ // test deleting incorrectly
+ // @link https://github.com/elgg/elgg/issues/2273
+ $this->assertNull($this->entity->deleteMetadata('impotent'));
+ $this->assertEqual($this->entity->important, 'indeed!');
+
+ // get rid of one metadata
+ $this->assertEqual($this->entity->important, 'indeed!');
+ $this->assertTrue($this->entity->deleteMetadata('important'));
+ $this->assertNull($this->entity->important);
+
+ // get rid of all metadata
+ $this->assertTrue($this->entity->deleteMetadata());
+ $this->assertNull($this->entity->less_important);
+
+ // clean up database
+ $this->assertTrue($this->entity->delete());
+ }
+
+ public function testElggEntityExportables() {
+ $exportables = array(
+ 'guid',
+ 'type',
+ 'subtype',
+ 'time_created',
+ 'time_updated',
+ 'container_guid',
+ 'owner_guid',
+ 'site_guid'
+ );
+
+ $this->assertIdentical($exportables, $this->entity->getExportableValues());
+ }
+
+ public function testElggEntityMultipleMetadata() {
+ foreach (array(false, true) as $save) {
+ if ($save) {
+ $this->save_entity();
+ }
+ $md = array('brett', 'bryan', 'brad');
+ $name = 'test_md_' . rand();
+
+ $this->entity->$name = $md;
+
+ $this->assertEqual($md, $this->entity->$name);
+
+ if ($save) {
+ $this->assertTrue($this->entity->delete());
+ }
+ }
+ }
+
+ public function testElggEntitySingleElementArrayMetadata() {
+ foreach (array(false, true) as $save) {
+ if ($save) {
+ $this->save_entity();
+ }
+ $md = array('test');
+ $name = 'test_md_' . rand();
+
+ $this->entity->$name = $md;
+
+ $this->assertEqual($md[0], $this->entity->$name);
+
+ if ($save) {
+ $this->assertTrue($this->entity->delete());
+ }
+ }
+ }
+
+ public function testElggEntityAppendMetadata() {
+ foreach (array(false, true) as $save) {
+ if ($save) {
+ $this->save_entity();
+ }
+ $md = 'test';
+ $name = 'test_md_' . rand();
+
+ $this->entity->$name = $md;
+ $this->entity->setMetaData($name, 'test2', '', true);
+
+ $this->assertEqual(array('test', 'test2'), $this->entity->$name);
+
+ if ($save) {
+ $this->assertTrue($this->entity->delete());
+ }
+ }
+ }
+
+ public function testElggEntitySingleElementArrayAppendMetadata() {
+ foreach (array(false, true) as $save) {
+ if ($save) {
+ $this->save_entity();
+ }
+ $md = 'test';
+ $name = 'test_md_' . rand();
+
+ $this->entity->$name = $md;
+ $this->entity->setMetaData($name, array('test2'), '', true);
+
+ $this->assertEqual(array('test', 'test2'), $this->entity->$name);
+
+ if ($save) {
+ $this->assertTrue($this->entity->delete());
+ }
+ }
+ }
+
+ public function testElggEntityArrayAppendMetadata() {
+ foreach (array(false, true) as $save) {
+ if ($save) {
+ $this->save_entity();
+ }
+ $md = array('brett', 'bryan', 'brad');
+ $md2 = array('test1', 'test2', 'test3');
+ $name = 'test_md_' . rand();
+
+ $this->entity->$name = $md;
+ $this->entity->setMetaData($name, $md2, '', true);
+
+ $this->assertEqual(array_merge($md, $md2), $this->entity->$name);
+
+ if ($save) {
+ $this->assertTrue($this->entity->delete());
+ }
+ }
+ }
+
+ protected function save_entity($type='site') {
+ $this->entity->type = $type;
+ $this->assertNotEqual($this->entity->save(), 0);
+ }
+}
+
+// ElggEntity is an abstract class with no abstact methods.
+class ElggEntityTest extends ElggEntity {
+ public function __construct() {
+ $this->initializeAttributes();
+ }
+
+ public function expose_attributes() {
+ return $this->attributes;
+ }
+
+ public function expose_metadata() {
+ return $this->temp_metadata;
+ }
+
+ public function expose_annotations() {
+ return $this->temp_annotations;
+ }
+}
diff --git a/engine/tests/objects/filestore.php b/engine/tests/objects/filestore.php
new file mode 100644
index 000000000..9732f0af4
--- /dev/null
+++ b/engine/tests/objects/filestore.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Elgg Test Skeleton
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreFilestoreTest extends ElggCoreUnitTest {
+
+ /**
+ * Called before each test object.
+ */
+ public function __construct() {
+ parent::__construct();
+
+ // all code should come after here
+ }
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+ $this->filestore = new ElggDiskFilestoreTest();
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ // do not allow SimpleTest to interpret Elgg notices as exceptions
+ $this->swallowErrors();
+
+ unset($this->filestore);
+ }
+
+ /**
+ * Called after each test object.
+ */
+ public function __destruct() {
+ // all code should go above here
+ parent::__destruct();
+ }
+
+ public function testFileMatrix() {
+ global $CONFIG;
+
+ // create a test user
+ $user = $this->createTestUser();
+ $created = date('Y/m/d', $user->time_created);
+
+ // check matrix with guid
+ $guid_dir = $this->filestore->makeFileMatrix($user->guid);
+ $this->assertIdentical($guid_dir, "$created/$user->guid/");
+
+ // clean up user
+ $user->delete();
+ }
+
+ public function testFilenameOnFilestore() {
+ global $CONFIG;
+
+ // create a user to own the file
+ $user = $this->createTestUser();
+ $created = date('Y/m/d', $user->time_created);
+
+ // setup a test file
+ $file = new ElggFile();
+ $file->owner_guid = $user->guid;
+ $file->setFilename('testing/filestore.txt');
+ $file->open('write');
+ $file->write('Testing!');
+ $this->assertTrue($file->close());
+
+ // ensure filename and path is expected
+ $filename = $file->getFilenameOnFilestore($file);
+ $filepath = "$CONFIG->dataroot$created/$user->guid/testing/filestore.txt";
+ $this->assertIdentical($filename, $filepath);
+ $this->assertTrue(file_exists($filepath));
+
+ // ensure file removed on user delete
+ $user->delete();
+ $this->assertFalse(file_exists($filepath));
+ }
+
+
+ protected function createTestUser($username = 'fileTest') {
+ $user = new ElggUser();
+ $user->username = $username;
+ $guid = $user->save();
+
+ // load user to have access to creation time
+ return get_entity($guid);
+ }
+}
+
+class ElggDiskFilestoreTest extends ElggDiskFilestore {
+ public function makeFileMatrix($guid) {
+ return parent::makeFileMatrix($guid);
+ }
+}
diff --git a/engine/tests/objects/objects.php b/engine/tests/objects/objects.php
new file mode 100644
index 000000000..263ab2414
--- /dev/null
+++ b/engine/tests/objects/objects.php
@@ -0,0 +1,306 @@
+<?php
+/**
+ * Elgg Test ElggObject
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreObjectTest extends ElggCoreUnitTest {
+
+ /**
+ * Called before each test object.
+ */
+ public function __construct() {
+ parent::__construct();
+ }
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+ $this->entity = new ElggObjectTest();
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ $this->swallowErrors();
+ unset($this->entity);
+ }
+
+ /**
+ * Called after each test object.
+ */
+ public function __destruct() {
+ parent::__destruct();
+ }
+
+ public function testElggObjectConstructor() {
+ $attributes = array();
+ $attributes['guid'] = NULL;
+ $attributes['type'] = 'object';
+ $attributes['subtype'] = NULL;
+ $attributes['owner_guid'] = elgg_get_logged_in_user_guid();
+ $attributes['container_guid'] = elgg_get_logged_in_user_guid();
+ $attributes['site_guid'] = NULL;
+ $attributes['access_id'] = ACCESS_PRIVATE;
+ $attributes['time_created'] = NULL;
+ $attributes['time_updated'] = NULL;
+ $attributes['last_action'] = NULL;
+ $attributes['enabled'] = 'yes';
+ $attributes['tables_split'] = 2;
+ $attributes['tables_loaded'] = 0;
+ $attributes['title'] = NULL;
+ $attributes['description'] = NULL;
+ ksort($attributes);
+
+ $entity_attributes = $this->entity->expose_attributes();
+ ksort($entity_attributes);
+
+ $this->assertIdentical($entity_attributes, $attributes);
+ }
+
+ public function testElggObjectSave() {
+ // new object
+ $this->AssertEqual($this->entity->getGUID(), 0);
+ $guid = $this->entity->save();
+ $this->AssertNotEqual($guid, 0);
+
+ $entity_row = $this->get_entity_row($guid);
+ $this->assertIsA($entity_row, 'stdClass');
+
+ // update existing object
+ $this->entity->title = 'testing';
+ $this->entity->description = 'ElggObject';
+ $this->assertEqual($this->entity->save(), $guid);
+
+ $object_row = $this->get_object_row($guid);
+ $this->assertIsA($object_row, 'stdClass');
+ $this->assertIdentical($object_row->title, 'testing');
+ $this->assertIdentical($object_row->description, 'ElggObject');
+
+ // clean up
+ $this->entity->delete();
+ }
+
+ public function testElggObjectLoad() {
+ // fail on wrong type
+ try {
+ $error = new ElggObjectTest(elgg_get_logged_in_user_guid());
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'InvalidClassException');
+ $message = sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), elgg_get_logged_in_user_guid(), 'ElggObject');
+ $this->assertIdentical($e->getMessage(), $message);
+ }
+ }
+
+ public function testElggObjectConstructorByGUID() {
+ $guid = $this->entity->save();
+
+ // load a new object using guid
+ $entity = new ElggObjectTest($guid);
+ $this->assertIdentical($this->entity, $entity);
+
+ // clean up
+ $this->entity->delete();
+ }
+
+ public function testElggObjectClone() {
+ $this->entity->title = 'testing';
+ $this->entity->description = 'ElggObject';
+ $this->entity->var1 = "test";
+ $this->entity->var2 = 1;
+ $this->entity->var3 = true;
+ $this->entity->save();
+
+ // add tag array
+ $tag_string = 'tag1, tag2, tag3';
+ $tagarray = string_to_tag_array($tag_string);
+ $this->entity->tags = $tagarray;
+
+ // a cloned ElggEntity has the guid reset
+ $object = clone $this->entity;
+ $this->assertIdentical(0, (int)$object->guid);
+
+ // make sure attributes were copied over
+ $this->assertIdentical($object->title, 'testing');
+ $this->assertIdentical($object->description, 'ElggObject');
+
+ $guid = $object->save();
+ $this->assertTrue($guid !== 0);
+ $this->assertTrue($guid !== $this->entity->guid);
+
+ // test that metadata was transfered
+ $this->assertIdentical($this->entity->var1, $object->var1);
+ $this->assertIdentical($this->entity->var2, $object->var2);
+ $this->assertIdentical($this->entity->var3, $object->var3);
+ $this->assertIdentical($this->entity->tags, $object->tags);
+
+ // clean up
+ $object->delete();
+ $this->entity->delete();
+ }
+
+ public function testElggObjectContainer() {
+ $this->assertEqual($this->entity->getContainerGUID(), elgg_get_logged_in_user_guid());
+
+ // create and save to group
+ $group = new ElggGroup();
+ $guid = $group->save();
+ $this->assertTrue($this->entity->setContainerGUID($guid));
+
+ // check container
+ $this->assertEqual($this->entity->getContainerGUID(), $guid);
+ $this->assertIdentical($group, $this->entity->getContainerEntity());
+
+ // clean up
+ $group->delete();
+ }
+
+ public function testElggObjectExportables() {
+ $exportables = array(
+ 'guid',
+ 'type',
+ 'subtype',
+ 'time_created',
+ 'time_updated',
+ 'container_guid',
+ 'owner_guid',
+ 'site_guid',
+ 'title',
+ 'description'
+ );
+
+ $this->assertIdentical($exportables, $this->entity->getExportableValues());
+ }
+
+ public function xtestElggObjectAccessOverrides() {
+ // set entity to private access with no owner.
+ $entity = $this->entity;
+ $entity->access_id = ACCESS_PRIVATE;
+ $entity->owner_guid = 0;
+ $this->assertTrue($entity->save());
+ $guid = $entity->getGUID();
+
+ var_dump($guid);
+ // try to grab entity
+ $entity = false;
+ $entity = get_entity($guid);
+ var_dump($entity);
+ $this->assertFalse($entity);
+
+ $old = elgg_set_ignore_access(true);
+ }
+
+ // see https://github.com/elgg/elgg/issues/1196
+ public function testElggEntityRecursiveDisableWhenLoggedOut() {
+ $e1 = new ElggObject();
+ $e1->access_id = ACCESS_PUBLIC;
+ $e1->owner_guid = 0;
+ $e1->container_guid = 0;
+ $e1->save();
+ $guid1 = $e1->getGUID();
+
+ $e2 = new ElggObject();
+ $e2->container_guid = $guid1;
+ $e2->access_id = ACCESS_PUBLIC;
+ $e2->owner_guid = 0;
+ $e2->save();
+ $guid2 = $e2->getGUID();
+
+ // fake being logged out
+ $user = $_SESSION['user'];
+ unset($_SESSION['user']);
+ $ia = elgg_set_ignore_access(true);
+
+ $this->assertTrue(disable_entity($guid1, null, true));
+
+ // "log in" original user
+ $_SESSION['user'] = $user;
+ elgg_set_ignore_access($ia);
+
+ $this->assertFalse(get_entity($guid1));
+ $this->assertFalse(get_entity($guid2));
+
+ $db_prefix = get_config('dbprefix');
+ $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $guid1";
+ $r = get_data_row($q);
+ $this->assertEqual('no', $r->enabled);
+
+ $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $guid2";
+ $r = get_data_row($q);
+ $this->assertEqual('no', $r->enabled);
+
+ access_show_hidden_entities(true);
+ delete_entity($guid1);
+ delete_entity($guid2);
+ access_show_hidden_entities(false);
+ }
+
+ public function testElggRecursiveDelete() {
+ $types = array('ElggGroup', 'ElggObject', 'ElggUser', 'ElggSite');
+ $db_prefix = elgg_get_config('dbprefix');
+
+ foreach ($types as $type) {
+ $parent = new $type();
+ $this->assertTrue($parent->save());
+
+ $child = new ElggObject();
+ $child->container_guid = $parent->guid;
+ $this->assertTrue($child->save());
+
+ $grandchild = new ElggObject();
+ $grandchild->container_guid = $child->guid;
+ $this->assertTrue($grandchild->save());
+
+ $this->assertTrue($parent->delete(true));
+
+ $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $parent->guid";
+ $r = get_data($q);
+ $this->assertFalse($r);
+
+ $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $child->guid";
+ $r = get_data($q);
+ $this->assertFalse($r);
+
+ $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $grandchild->guid";
+ $r = get_data($q);
+ $this->assertFalse($r);
+ }
+
+ // object that owns itself
+ // can't check container_guid because of infinite loops in can_edit_entity()
+ $obj = new ElggObject();
+ $obj->save();
+ $obj->owner_guid = $obj->guid;
+ $obj->save();
+
+ $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $obj->guid";
+ $r = get_data_row($q);
+ $this->assertEqual($obj->guid, $r->owner_guid);
+
+ $this->assertTrue($obj->delete(true));
+
+ $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $obj->guid";
+ $r = get_data_row($q);
+ $this->assertFalse($r);
+ }
+
+ protected function get_object_row($guid) {
+ global $CONFIG;
+ return get_data_row("SELECT * FROM {$CONFIG->dbprefix}objects_entity WHERE guid='$guid'");
+ }
+
+ protected function get_entity_row($guid) {
+ global $CONFIG;
+ return get_data_row("SELECT * FROM {$CONFIG->dbprefix}entities WHERE guid='$guid'");
+ }
+}
+
+class ElggObjectTest extends ElggObject {
+ public function expose_attributes() {
+ return $this->attributes;
+ }
+}
diff --git a/engine/tests/objects/sites.php b/engine/tests/objects/sites.php
new file mode 100644
index 000000000..a01a661e3
--- /dev/null
+++ b/engine/tests/objects/sites.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Elgg Test ElggSite
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreSiteTest extends ElggCoreUnitTest {
+
+ /**
+ * Called before each test object.
+ */
+ public function __construct() {
+ parent::__construct();
+ }
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+ $this->site = new ElggSiteTest();
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ $this->swallowErrors();
+ unset($this->site);
+ }
+
+ /**
+ * Called after each test object.
+ */
+ public function __destruct() {
+ parent::__destruct();
+ }
+
+ public function testElggSiteConstructor() {
+ $attributes = array();
+ $attributes['guid'] = NULL;
+ $attributes['type'] = 'site';
+ $attributes['subtype'] = NULL;
+ $attributes['owner_guid'] = elgg_get_logged_in_user_guid();
+ $attributes['container_guid'] = elgg_get_logged_in_user_guid();
+ $attributes['site_guid'] = NULL;
+ $attributes['access_id'] = ACCESS_PRIVATE;
+ $attributes['time_created'] = NULL;
+ $attributes['time_updated'] = NULL;
+ $attributes['last_action'] = NULL;
+ $attributes['enabled'] = 'yes';
+ $attributes['tables_split'] = 2;
+ $attributes['tables_loaded'] = 0;
+ $attributes['name'] = NULL;
+ $attributes['description'] = NULL;
+ $attributes['url'] = NULL;
+ ksort($attributes);
+
+ $entity_attributes = $this->site->expose_attributes();
+ ksort($entity_attributes);
+
+ $this->assertIdentical($entity_attributes, $attributes);
+ }
+
+ public function testElggSiteSaveAndDelete() {
+ $guid = $this->site->save();
+ $this->assertIsA($guid, 'int');
+ $this->assertTrue($guid > 0);
+ $this->assertIdentical(true, $this->site->delete());
+ }
+}
+
+class ElggSiteTest extends ElggSite {
+ public function expose_attributes() {
+ return $this->attributes;
+ }
+}
diff --git a/engine/tests/objects/users.php b/engine/tests/objects/users.php
new file mode 100644
index 000000000..8a1033ac4
--- /dev/null
+++ b/engine/tests/objects/users.php
@@ -0,0 +1,250 @@
+<?php
+/**
+ * Elgg Test ElggUser
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreUserTest extends ElggCoreUnitTest {
+
+ /**
+ * Called before each test object.
+ */
+ public function __construct() {
+ parent::__construct();
+
+ // all code should come after here
+ }
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+ $this->user = new ElggUserTest();
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ // do not allow SimpleTest to interpret Elgg notices as exceptions
+ $this->swallowErrors();
+
+ unset($this->user);
+ }
+
+ /**
+ * Called after each test object.
+ */
+ public function __destruct() {
+ // all code should go above here
+ parent::__destruct();
+ }
+
+ public function testElggUserConstructor() {
+ $attributes = array();
+ $attributes['guid'] = NULL;
+ $attributes['type'] = 'user';
+ $attributes['subtype'] = NULL;
+ $attributes['owner_guid'] = elgg_get_logged_in_user_guid();
+ $attributes['container_guid'] = elgg_get_logged_in_user_guid();
+ $attributes['site_guid'] = NULL;
+ $attributes['access_id'] = ACCESS_PRIVATE;
+ $attributes['time_created'] = NULL;
+ $attributes['time_updated'] = NULL;
+ $attributes['last_action'] = NULL;
+ $attributes['enabled'] = 'yes';
+ $attributes['tables_split'] = 2;
+ $attributes['tables_loaded'] = 0;
+ $attributes['name'] = NULL;
+ $attributes['username'] = NULL;
+ $attributes['password'] = NULL;
+ $attributes['salt'] = NULL;
+ $attributes['email'] = NULL;
+ $attributes['language'] = NULL;
+ $attributes['code'] = NULL;
+ $attributes['banned'] = 'no';
+ $attributes['admin'] = 'no';
+ $attributes['prev_last_action'] = NULL;
+ $attributes['last_login'] = NULL;
+ $attributes['prev_last_login'] = NULL;
+ ksort($attributes);
+
+ $entity_attributes = $this->user->expose_attributes();
+ ksort($entity_attributes);
+
+ $this->assertIdentical($entity_attributes, $attributes);
+ }
+
+ public function testElggUserLoad() {
+ // new object
+ $object = new ElggObject();
+ $this->AssertEqual($object->getGUID(), 0);
+ $guid = $object->save();
+ $this->AssertNotEqual($guid, 0);
+
+ // fail on wrong type
+ try {
+ $error = new ElggUserTest($guid);
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'InvalidClassException');
+ $message = sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, 'ElggUser');
+ $this->assertIdentical($e->getMessage(), $message);
+ }
+
+ // clean up
+ $object->delete();
+ }
+
+ public function testElggUserConstructorByGuid() {
+ $user = new ElggUser(elgg_get_logged_in_user_guid());
+ $this->assertIdentical($user, $_SESSION['user']);
+
+ // fail with garbage
+ try {
+ $error = new ElggUserTest(array('invalid'));
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'InvalidParameterException');
+ $message = sprintf(elgg_echo('InvalidParameterException:UnrecognisedValue'));
+ $this->assertIdentical($e->getMessage(), $message);
+ }
+ }
+
+ public function testElggUserConstructorByDbRow() {
+ $row = $this->fetchUser(elgg_get_logged_in_user_guid());
+ $user = new ElggUser($row);
+ $this->assertIdentical($user, $_SESSION['user']);
+ }
+
+ public function testElggUserConstructorByUsername() {
+ $row = $this->fetchUser(elgg_get_logged_in_user_guid());
+ $user = new ElggUser($row->username);
+ $this->assertIdentical($user, $_SESSION['user']);
+ }
+
+ public function testElggUserSave() {
+ // new object
+ $this->AssertEqual($this->user->getGUID(), 0);
+ $guid = $this->user->save();
+ $this->AssertNotEqual($guid, 0);
+
+ // clean up
+ $this->user->delete();
+ }
+
+ public function testElggUserDelete() {
+ $guid = $this->user->save();
+
+ // delete object
+ $this->assertIdentical(true, $this->user->delete());
+
+ // check GUID not in database
+ $this->assertFalse($this->fetchUser($guid));
+ }
+
+ public function testElggUserNameCache() {
+ // issue https://github.com/elgg/elgg/issues/1305
+
+ // very unlikely a user would have this username
+ $name = (string)time();
+ $this->user->username = $name;
+
+ $guid = $this->user->save();
+
+ $user = get_user_by_username($name);
+ $user->delete();
+ $user = get_user_by_username($name);
+ $this->assertFalse($user);
+ }
+
+ public function testGetUserByUsernameAcceptsUrlEncoded() {
+ $username = (string)time();
+ $this->user->username = $username;
+ $guid = $this->user->save();
+
+ // percent encode first letter
+ $first_letter = $username[0];
+ $first_letter = str_pad('%' . dechex(ord($first_letter)), 2, '0', STR_PAD_LEFT);
+ $username = $first_letter . substr($username, 1);
+
+ $user = get_user_by_username($username);
+ $this->assertTrue((bool) $user);
+ $this->assertEqual($guid, $user->guid);
+
+ $this->user->delete();
+ }
+
+ public function testElggUserMakeAdmin() {
+ global $CONFIG;
+
+ // need to save user to have a guid
+ $guid = $this->user->save();
+
+ $this->assertTrue($this->user->makeAdmin());
+
+ $q = "SELECT admin FROM {$CONFIG->dbprefix}users_entity WHERE guid = $guid";
+ $r = mysql_query($q);
+
+ $admin = mysql_fetch_assoc($r);
+ $this->assertEqual($admin['admin'], 'yes');
+
+ $this->user->delete();
+ }
+
+ public function testElggUserRemoveAdmin() {
+ global $CONFIG;
+
+ // need to save user to have a guid
+ $guid = $this->user->save();
+
+ $this->assertTrue($this->user->removeAdmin());
+
+ $q = "SELECT admin FROM {$CONFIG->dbprefix}users_entity WHERE guid = $guid";
+ $r = mysql_query($q);
+
+ $admin = mysql_fetch_assoc($r);
+ $this->assertEqual($admin['admin'], 'no');
+
+ $this->user->delete();
+ }
+
+ public function testElggUserIsAdmin() {
+ // need to grab a real user with a guid and everything.
+ $guid = $this->user->save();
+
+ $this->assertTrue($this->user->makeAdmin());
+
+ // this is testing the function, not the SQL.
+ // that's been tested above.
+ $this->assertTrue($this->user->isAdmin());
+
+ $this->user->delete();
+ }
+
+ public function testElggUserIsNotAdmin() {
+ // need to grab a real user with a guid and everything.
+ $guid = $this->user->save();
+
+ $this->assertTrue($this->user->removeAdmin());
+
+ // this is testing the function, not the SQL.
+ // that's been tested above.
+ $this->assertFalse($this->user->isAdmin());
+
+ $this->user->delete();
+ }
+
+ protected function fetchUser($guid) {
+ global $CONFIG;
+
+ return get_data_row("SELECT * FROM {$CONFIG->dbprefix}users_entity WHERE guid = '$guid'");
+ }
+}
+
+class ElggUserTest extends ElggUser {
+ public function expose_attributes() {
+ return $this->attributes;
+ }
+}
diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
new file mode 100644
index 000000000..689275661
--- /dev/null
+++ b/engine/tests/regression/trac_bugs.php
@@ -0,0 +1,405 @@
+<?php
+/**
+ * Elgg Regression Tests -- GitHub Bugfixes
+ * Any bugfixes from GitHub that require testing belong here.
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
+
+ /**
+ * Called before each test object.
+ */
+ public function __construct() {
+ $this->ia = elgg_set_ignore_access(TRUE);
+ parent::__construct();
+
+ // all __construct() code should come after here
+ }
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ // do not allow SimpleTest to interpret Elgg notices as exceptions
+ $this->swallowErrors();
+ }
+
+ /**
+ * Called after each test object.
+ */
+ public function __destruct() {
+ elgg_set_ignore_access($this->ia);
+ // all __destruct() code should go above here
+ parent::__destruct();
+ }
+
+ /**
+ * #1558
+ */
+ public function testElggObjectDeleteAnnotations() {
+ $this->entity = new ElggObject();
+ $guid = $this->entity->save();
+
+ $this->entity->annotate('test', 'hello', ACCESS_PUBLIC);
+
+ $this->entity->deleteAnnotations('does not exist');
+
+ $num = $this->entity->countAnnotations('test');
+
+ //$this->assertIdentical($num, 1);
+ $this->assertEqual($num, 1);
+
+ // clean up
+ $this->entity->delete();
+ }
+
+ /**
+ * #2063 - get_resized_image_from_existing_file() fails asked for image larger than selection and not scaling an image up
+ * Test get_image_resize_parameters().
+ */
+ public function testElggResizeImage() {
+ $orig_width = 100;
+ $orig_height = 150;
+
+ // test against selection > max
+ $options = array(
+ 'maxwidth' => 50,
+ 'maxheight' => 50,
+ 'square' => TRUE,
+ 'upscale' => FALSE,
+
+ 'x1' => 25,
+ 'y1' => 75,
+ 'x2' => 100,
+ 'y2' => 150
+ );
+
+ // should get back the same x/y offset == x1, y1 and an image of 50x50
+ $params = get_image_resize_parameters($orig_width, $orig_height, $options);
+
+ $this->assertEqual($params['newwidth'], $options['maxwidth']);
+ $this->assertEqual($params['newheight'], $options['maxheight']);
+ $this->assertEqual($params['xoffset'], $options['x1']);
+ $this->assertEqual($params['yoffset'], $options['y1']);
+
+ // test against selection < max
+ $options = array(
+ 'maxwidth' => 50,
+ 'maxheight' => 50,
+ 'square' => TRUE,
+ 'upscale' => FALSE,
+
+ 'x1' => 75,
+ 'y1' => 125,
+ 'x2' => 100,
+ 'y2' => 150
+ );
+
+ // should get back the same x/y offset == x1, y1 and an image of 25x25 because no upscale
+ $params = get_image_resize_parameters($orig_width, $orig_height, $options);
+
+ $this->assertEqual($params['newwidth'], 25);
+ $this->assertEqual($params['newheight'], 25);
+ $this->assertEqual($params['xoffset'], $options['x1']);
+ $this->assertEqual($params['yoffset'], $options['y1']);
+ }
+
+ // #3722 Check canEdit() works for contains regardless of groups
+ function test_can_write_to_container() {
+ $user = new ElggUser();
+ $user->username = 'test_user_' . rand();
+ $user->name = 'test_user_name_' . rand();
+ $user->email = 'test@user.net';
+ $user->container_guid = 0;
+ $user->owner_guid = 0;
+ $user->save();
+
+ $object = new ElggObject();
+ $object->save();
+
+ $group = new ElggGroup();
+ $group->save();
+
+ // disable access overrides because we're admin.
+ $ia = elgg_set_ignore_access(false);
+
+ $this->assertFalse(can_write_to_container($user->guid, $object->guid));
+
+ global $elgg_test_user;
+ $elgg_test_user = $user;
+
+ // register hook to allow access
+ function can_write_to_container_test_hook($hook, $type, $value, $params) {
+ global $elgg_test_user;
+
+ if ($params['user']->getGUID() == $elgg_test_user->getGUID()) {
+ return true;
+ }
+ }
+
+ elgg_register_plugin_hook_handler('container_permissions_check', 'all', 'can_write_to_container_test_hook');
+ $this->assertTrue(can_write_to_container($user->guid, $object->guid));
+ elgg_unregister_plugin_hook_handler('container_permissions_check', 'all', 'can_write_to_container_test_hook');
+
+ $this->assertFalse(can_write_to_container($user->guid, $group->guid));
+ $group->join($user);
+ $this->assertTrue(can_write_to_container($user->guid, $group->guid));
+
+ elgg_set_ignore_access($ia);
+
+ $user->delete();
+ $object->delete();
+ $group->delete();
+ }
+
+ function test_db_shutdown_links() {
+ global $DB_DELAYED_QUERIES, $test_results;
+ $DB_DELAYED_QUERIES = array();
+
+ function test_delayed_results($results) {
+ global $test_results;
+ $test_results = $results;
+ }
+
+ $q = 'SELECT 1 as test';
+
+ $links = array('read', 'write', get_db_link('read'), get_db_link('write'));
+
+ foreach ($links as $link) {
+ $DB_DELAYED_QUERIES = array();
+
+ $result = execute_delayed_query($q, $link, 'test_delayed_results');
+
+ $this->assertTrue($result, "Failed with link = $link");
+ $this->assertEqual(count($DB_DELAYED_QUERIES), 1);
+ $this->assertEqual($DB_DELAYED_QUERIES[0]['q'], $q);
+ $this->assertEqual($DB_DELAYED_QUERIES[0]['l'], $link);
+ $this->assertEqual($DB_DELAYED_QUERIES[0]['h'], 'test_delayed_results');
+
+ db_delayedexecution_shutdown_hook();
+
+ $num_rows = mysql_num_rows($test_results);
+ $this->assertEqual($num_rows, 1);
+ $row = mysql_fetch_assoc($test_results);
+ $this->assertEqual($row['test'], 1);
+ }
+
+ // test bad case
+ $DB_DELAYED_QUERIES = array();
+ $result = execute_delayed_query($q, 'not_a_link', 'test_delayed_results');
+ $this->assertFalse($result);
+ $this->assertEqual(array(), $DB_DELAYED_QUERIES);
+ }
+
+ /**
+ * https://github.com/elgg/elgg/issues/3210 - Don't remove -s in friendly titles
+ * https://github.com/elgg/elgg/issues/2276 - improve char encoding
+ */
+ public function test_friendly_title() {
+ $cases = array(
+ // acid test
+ "B&N > Amazon, OK? <bold> 'hey!' $34"
+ => "bn-amazon-ok-bold-hey-34",
+
+ // hyphen, underscore and ASCII whitespace replaced by separator,
+ // other non-alphanumeric ASCII removed
+ "a-a_a a\na\ra\ta\va!a\"a#a\$a%aa'a(a)a*a+a,a.a/a:a;a=a?a@a[a\\a]a^a`a{a|a}a~a"
+ => "a-a-a-a-a-a-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+
+ // separators trimmed
+ "-_ hello _-"
+ => "hello",
+
+ // accents removed, lower case, other multibyte chars are URL encoded
+ "I\xC3\xB1t\xC3\xABrn\xC3\xA2ti\xC3\xB4n\xC3\xA0liz\xC3\xA6ti\xC3\xB8n, AND \xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"
+ // Iñtërnâtiônàlizætiøn, AND 日本語
+ => 'internationalizaetion-and-%E6%97%A5%E6%9C%AC%E8%AA%9E',
+ );
+
+ // where available, string is converted to NFC before transliteration
+ if (ElggTranslit::hasNormalizerSupport()) {
+ $form_d = "A\xCC\x8A"; // A followed by 'COMBINING RING ABOVE' (U+030A)
+ $cases[$form_d] = "a";
+ }
+
+ foreach ($cases as $case => $expected) {
+ $friendly_title = elgg_get_friendly_title($case);
+ $this->assertIdentical($expected, $friendly_title);
+ }
+ }
+
+ /**
+ * Test #5369 -- parse_urls()
+ * https://github.com/Elgg/Elgg/issues/5369
+ */
+ public function test_parse_urls() {
+
+ $cases = array(
+ 'no.link.here' =>
+ 'no.link.here',
+ 'simple link http://example.org test' =>
+ 'simple link <a href="http://example.org" rel="nofollow">http:/<wbr />/<wbr />example.org</a> test',
+ 'non-ascii http://ñew.org/ test' =>
+ 'non-ascii <a href="http://ñew.org/" rel="nofollow">http:/<wbr />/<wbr />ñew.org/<wbr /></a> test',
+
+ // section 2.1
+ 'percent encoded http://example.org/a%20b test' =>
+ 'percent encoded <a href="http://example.org/a%20b" rel="nofollow">http:/<wbr />/<wbr />example.org/<wbr />a%20b</a> test',
+ // section 2.2: skipping single quote and parenthese
+ 'reserved characters http://example.org/:/?#[]@!$&*+,;= test' =>
+ 'reserved characters <a href="http://example.org/:/?#[]@!$&*+,;=" rel="nofollow">http:/<wbr />/<wbr />example.org/<wbr />:/<wbr />?#[]@!$&*+,;=</a> test',
+ // section 2.3
+ 'unreserved characters http://example.org/a1-._~ test' =>
+ 'unreserved characters <a href="http://example.org/a1-._~" rel="nofollow">http:/<wbr />/<wbr />example.org/<wbr />a1-._~</a> test',
+
+ 'parameters http://example.org/?val[]=1&val[]=2 test' =>
+ 'parameters <a href="http://example.org/?val[]=1&val[]=2" rel="nofollow">http:/<wbr />/<wbr />example.org/<wbr />?val[]=1&val[]=2</a> test',
+ 'port http://example.org:80/ test' =>
+ 'port <a href="http://example.org:80/" rel="nofollow">http:/<wbr />/<wbr />example.org:80/<wbr /></a> test',
+
+ 'parentheses (http://www.google.com) test' =>
+ 'parentheses (<a href="http://www.google.com" rel="nofollow">http:/<wbr />/<wbr />www.google.com</a>) test',
+ 'comma http://elgg.org, test' =>
+ 'comma <a href="http://elgg.org" rel="nofollow">http:/<wbr />/<wbr />elgg.org</a>, test',
+ 'period http://elgg.org. test' =>
+ 'period <a href="http://elgg.org" rel="nofollow">http:/<wbr />/<wbr />elgg.org</a>. test',
+ 'exclamation http://elgg.org! test' =>
+ 'exclamation <a href="http://elgg.org" rel="nofollow">http:/<wbr />/<wbr />elgg.org</a>! test',
+
+ 'already anchor <a href="http://twitter.com/">twitter</a> test' =>
+ 'already anchor <a href="http://twitter.com/">twitter</a> test',
+
+ 'ssl https://example.org/ test' =>
+ 'ssl <a href="https://example.org/" rel="nofollow">https:/<wbr />/<wbr />example.org/<wbr /></a> test',
+ 'ftp ftp://example.org/ test' =>
+ 'ftp <a href="ftp://example.org/" rel="nofollow">ftp:/<wbr />/<wbr />example.org/<wbr /></a> test',
+
+ 'web archive anchor <a href="http://web.archive.org/web/20000229040250/http://www.google.com/">google</a>' =>
+ 'web archive anchor <a href="http://web.archive.org/web/20000229040250/http://www.google.com/">google</a>',
+
+ 'single quotes already anchor <a href=\'http://www.yahoo.com\'>yahoo</a>' =>
+ 'single quotes already anchor <a href=\'http://www.yahoo.com\'>yahoo</a>',
+
+ 'unquoted already anchor <a href=http://www.yahoo.com>yahoo</a>' =>
+ 'unquoted already anchor <a href=http://www.yahoo.com>yahoo</a>',
+
+ 'parens in uri http://thedailywtf.com/Articles/A-(Long-Overdue)-BuildMaster-Introduction.aspx' =>
+ 'parens in uri <a href="http://thedailywtf.com/Articles/A-(Long-Overdue)-BuildMaster-Introduction.aspx" rel="nofollow">http:/<wbr />/<wbr />thedailywtf.com/<wbr />Articles/<wbr />A-(Long-Overdue)-BuildMaster-Introduction.aspx</a>'
+ );
+ foreach ($cases as $input => $output) {
+ $this->assertEqual($output, parse_urls($input));
+ }
+ }
+
+ /**
+ * Ensure additional select columns do not end up in entity attributes.
+ *
+ * https://github.com/Elgg/Elgg/issues/5538
+ */
+ public function test_extra_columns_dont_appear_in_attributes() {
+ global $ENTITY_CACHE;
+
+ // may not have groups in DB - let's create one
+ $group = new ElggGroup();
+ $group->name = 'test_group';
+ $group->access_id = ACCESS_PUBLIC;
+ $this->assertTrue($group->save() !== false);
+
+ // entity cache interferes with our test
+ $ENTITY_CACHE = array();
+
+ foreach (array('site', 'user', 'group', 'object') as $type) {
+ $entities = elgg_get_entities(array(
+ 'type' => $type,
+ 'selects' => array('1 as _nonexistent_test_column'),
+ 'limit' => 1,
+ ));
+ if (!$this->assertTrue($entities, "Query for '$type' did not return an entity.")) {
+ continue;
+ }
+ $entity = $entities[0];
+ $this->assertNull($entity->_nonexistent_test_column, "Additional select columns are leaking to attributes for '$type'");
+ }
+
+ $group->delete();
+ }
+
+ /**
+ * Ensure that ElggBatch doesn't go into infinite loop when disabling annotations recursively when show hidden is enabled.
+ *
+ * https://github.com/Elgg/Elgg/issues/5952
+ */
+ public function test_disabling_annotations_infinite_loop() {
+
+ //let's have some entity
+ $group = new ElggGroup();
+ $group->name = 'test_group';
+ $group->access_id = ACCESS_PUBLIC;
+ $this->assertTrue($group->save() !== false);
+
+ $total = 51;
+ //add some annotations
+ for ($cnt = 0; $cnt < $total; $cnt++) {
+ $group->annotate('test_annotation', 'value_' . $total);
+ }
+
+ //disable them
+ $show_hidden = access_get_show_hidden_status();
+ access_show_hidden_entities(true);
+ $options = array(
+ 'guid' => $group->guid,
+ 'limit' => $total, //using strict limit to avoid real infinite loop and just see ElggBatch limiting on it before finishing the work
+ );
+ elgg_disable_annotations($options);
+ access_show_hidden_entities($show_hidden);
+
+ //confirm all being disabled
+ $annotations = $group->getAnnotations(array(
+ 'limit' => $total,
+ ));
+ foreach ($annotations as $annotation) {
+ $this->assertTrue($annotation->enabled == 'no');
+ }
+
+ //delete group and annotations
+ $group->delete();
+ }
+
+ public function test_ElggXMLElement_does_not_load_external_entities() {
+ $elLast = libxml_disable_entity_loader(false);
+
+ // build payload that should trigger loading of external entity
+ $payload = file_get_contents(dirname(dirname(__FILE__)) . '/test_files/xxe/request.xml');
+ $path = realpath(dirname(dirname(__FILE__)) . '/test_files/xxe/external_entity.txt');
+ $path = str_replace('\\', '/', $path);
+ if ($path[0] != '/') {
+ $path = '/' . $path;
+ }
+ $path = 'file://' . $path;
+ $payload = sprintf($payload, $path);
+
+ // make sure we can actually this in this environment
+ $element = new SimpleXMLElement($payload);
+ $can_load_entity = preg_match('/secret/', (string)$element->methodName);
+
+ $this->skipUnless($can_load_entity, "XXE vulnerability cannot be tested on this system");
+
+ if ($can_load_entity) {
+ $el = new ElggXMLElement($payload);
+ $chidren = $el->getChildren();
+ $content = $chidren[0]->getContent();
+ $this->assertNoPattern('/secret/', $content);
+ }
+
+ libxml_disable_entity_loader($elLast);
+ }
+}
diff --git a/engine/tests/services/api.php b/engine/tests/services/api.php
new file mode 100644
index 000000000..3d07c0bbb
--- /dev/null
+++ b/engine/tests/services/api.php
@@ -0,0 +1,324 @@
+<?php
+/**
+ * Elgg Test Services - General API and REST
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreServicesApiTest extends ElggCoreUnitTest {
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ global $API_METHODS;
+ $this->swallowErrors();
+ $API_METHODS = array();
+ }
+
+// expose_function
+ public function testExposeFunctionNoMethod() {
+ try {
+ @expose_function();
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'InvalidParameterException');
+ $this->assertIdentical($e->getMessage(), elgg_echo('InvalidParameterException:APIMethodOrFunctionNotSet'));
+ }
+ }
+
+ public function testExposeFunctionNoFunction() {
+ try {
+ @expose_function('test');
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'InvalidParameterException');
+ $this->assertIdentical($e->getMessage(), elgg_echo('InvalidParameterException:APIMethodOrFunctionNotSet'));
+ }
+ }
+
+ public function testExposeFunctionBadParameters() {
+ try {
+ @expose_function('test', 'test', 'BAD');
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'InvalidParameterException');
+ $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('InvalidParameterException:APIParametersArrayStructure'), 'test'));
+ }
+ }
+
+ public function testExposeFunctionParametersBadArray() {
+ try {
+ expose_function('test', 'test', array('param1' => 'string'));
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'InvalidParameterException');
+ $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('InvalidParameterException:APIParametersArrayStructure'), 'test'));
+ }
+ }
+
+ public function testExposeFunctionBadHttpMethod() {
+ try {
+ @expose_function('test', 'test', null, '', 'BAD');
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'InvalidParameterException');
+ $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('InvalidParameterException:UnrecognisedHttpMethod'), 'BAD', 'test'));
+ }
+ }
+
+ public function testExposeFunctionSuccess() {
+ global $API_METHODS;
+ // this is a general test but also tests specifically for setting 'required' correctly
+ $parameters = array('param1' => array('type' => 'int', 'required' => true),
+ 'param2' => array('type' => 'bool'),
+ 'param3' => array('type' => 'string', 'required' => false), );
+
+ $this->assertTrue(expose_function('test', 'foo', $parameters));
+
+ $parameters = array('param1' => array('type' => 'int', 'required' => true),
+ 'param2' => array('type' => 'bool', 'required' => true),
+ 'param3' => array('type' => 'string', 'required' => false), );
+ $method['description'] = '';
+ $method['function'] = 'foo';
+ $method['parameters'] = $parameters;
+ $method['call_method'] = 'GET';
+ $method['require_api_auth'] = false;
+ $method['require_user_auth'] = false;
+
+ $this->assertIdentical($method, $API_METHODS['test']);
+ }
+
+// unexpose_function
+ public function testUnexposeFunction() {
+ global $API_METHODS;
+
+ $this->registerFunction();
+
+ unexpose_function('test');
+ $this->assertIdentical(array(), $API_METHODS);
+ }
+
+// authenticate_method
+ public function testAuthenticateMethodNotImplemented() {
+ try {
+ authenticate_method('BAD');
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'APIException');
+ $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('APIException:MethodCallNotImplemented'), 'BAD'));
+ }
+ }
+
+ public function testAuthenticateMethodApiAuth() {
+ $this->registerFunction(true);
+ try {
+ authenticate_method('test');
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'APIException');
+ $this->assertIdentical($e->getMessage(), elgg_echo('APIException:APIAuthenticationFailed'));
+ }
+ }
+
+ public function testAuthenticateMethodUserAuth() {
+ $this->registerFunction(false, true);
+ try {
+ authenticate_method('test');
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'APIException');
+ }
+ }
+
+ public function testAuthenticateMethod() {
+ $this->registerFunction(false, false);
+ // anonymous with no user authentication
+ $this->assertTrue(authenticate_method('test'));
+ }
+
+// execute_method
+ public function testExecuteMethodNotImplemented() {
+ try {
+ execute_method('BAD');
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'APIException');
+ $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('APIException:MethodCallNotImplemented'), 'BAD'));
+ }
+ }
+
+ public function testExecuteMethodNonCallable() {
+ expose_function('test', 'foo');
+
+ try {
+ execute_method('test');
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'APIException');
+ $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('APIException:FunctionDoesNotExist'), 'test'));
+ }
+ }
+
+ public function testExecuteMethodWrongMethod() {
+ $this->registerFunction();
+
+ try {
+ // GET when it should be a POST
+ execute_method('test');
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'CallException');
+ $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('CallException:InvalidCallMethod'), 'test', 'POST'));
+ }
+ }
+
+// verify parameters
+ public function testVerifyParametersTypeNotSet() {
+ $params = array('param1' => array('required' => true));
+ expose_function('test', 'elgg_echo', $params);
+
+ try {
+ verify_parameters('test', array());
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'APIException');
+ $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('APIException:InvalidParameter'), 'param1', 'test'));
+ }
+ }
+
+ public function testVerifyParametersMissing() {
+ $params = array('param1' => array('type' => 'int', 'required' => true));
+ expose_function('test', 'elgg_echo', $params);
+
+ try {
+ verify_parameters('test', array());
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'APIException');
+ $this->assertIdentical($e->getMessage(), sprintf(elgg_echo('APIException:MissingParameterInMethod'), 'param1', 'test'));
+ }
+ }
+
+ public function testVerifyParameters() {
+ $this->registerFunction();
+
+ $parameters = array('param1' => 0);
+ $this->assertTrue(verify_parameters('test', $parameters));
+ }
+
+ public function testSerialiseParameters() {
+
+ // int and bool
+ $this->registerFunction();
+ $parameters = array('param1' => 1, 'param2' => 0);
+ $s = serialise_parameters('test', $parameters);
+ $this->assertIdentical($s, ',1,false');
+
+ // string
+ $this->registerFunction(false, false, array('param1' => array('type' => 'string')));
+ $parameters = array('param1' => 'testing');
+ $s = serialise_parameters('test', $parameters);
+ $this->assertIdentical($s, ",'testing'");
+
+ // test string with " in it
+ $this->registerFunction(false, false, array('param1' => array('type' => 'string')));
+ $parameters = array('param1' => 'test"ing');
+ $s = serialise_parameters('test', $parameters);
+ $this->assertIdentical($s, ',\'test"ing\'');
+
+ // test string with ' in it
+ $this->registerFunction(false, false, array('param1' => array('type' => 'string')));
+ $parameters = array('param1' => 'test\'ing');
+ $s = serialise_parameters('test', $parameters);
+ $this->assertIdentical($s, ",'test\'ing'");
+
+ // test string with \ in it
+ $this->registerFunction(false, false, array('param1' => array('type' => 'string')));
+ $parameters = array('param1' => 'test\ing');
+ $s = serialise_parameters('test', $parameters);
+ $this->assertIdentical($s, ",'test\\ing'");
+
+ // test string with \' in it
+ $this->registerFunction(false, false, array('param1' => array('type' => 'string')));
+ $parameters = array('param1' => "test\'ing");
+ $s = serialise_parameters('test', $parameters);
+ $this->assertIdentical($s, ",'test\\\\'ing'"); // test\\'ing
+
+ // test string reported by twall in #1364
+ $this->registerFunction(false, false, array('param1' => array('type' => 'string')));
+ $parameters = array('param1' => '{"html":"<div><img src=\\"http://foo.com\\"/>Blah Blah</div>"}');
+ $s = serialise_parameters('test', $parameters);
+ $this->assertIdentical($s, ",'{\"html\":\"<div><img src=\\\"http://foo.com\\\"/>Blah Blah</div>\"}'");
+
+ // float
+ $this->registerFunction(false, false, array('param1' => array('type' => 'float')));
+ $parameters = array('param1' => 2.5);
+ $s = serialise_parameters('test', $parameters);
+ $this->assertIdentical($s, ',2.5');
+
+ // indexed array of strings
+ $this->registerFunction(false, false, array('param1' => array('type' => 'array')));
+ $parameters = array('param1' => array('one', 'two'));
+ $s = serialise_parameters('test', $parameters);
+ $this->assertIdentical($s, ",array('0'=>'one','1'=>'two')");
+
+ // associative array of strings
+ $this->registerFunction(false, false, array('param1' => array('type' => 'array')));
+ $parameters = array('param1' => array('first' => 'one', 'second' => 'two'));
+ $s = serialise_parameters('test', $parameters);
+ $this->assertIdentical($s, ",array('first'=>'one','second'=>'two')");
+
+ // indexed array of strings
+ $this->registerFunction(false, false, array('param1' => array('type' => 'array')));
+ $parameters = array('param1' => array(1, 2));
+ $s = serialise_parameters('test', $parameters);
+ $this->assertIdentical($s, ",array('0'=>'1','1'=>'2')");
+
+ // test unknown type
+ $this->registerFunction(false, false, array('param1' => array('type' => 'bad')));
+ $parameters = array('param1' => 'test');
+ $this->expectException('APIException');
+ $s = serialise_parameters('test', $parameters);
+ }
+
+// api key methods
+ //public function testApiAuthenticate() {
+ // $this->assertFalse(pam_authenticate(null, "api"));
+ //}
+
+ public function testApiAuthKeyNoKey() {
+ try {
+ api_auth_key();
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'APIException');
+ $this->assertIdentical($e->getMessage(), elgg_echo('APIException:MissingAPIKey'));
+ }
+ }
+
+ public function testApiAuthKeyBadKey() {
+ global $CONFIG;
+
+ $CONFIG->input['api_key'] = 'BAD';
+ try {
+ api_auth_key();
+ $this->assertTrue(FALSE);
+ } catch (Exception $e) {
+ $this->assertIsA($e, 'APIException');
+ $this->assertIdentical($e->getMessage(), elgg_echo('APIException:BadAPIKey'));
+ }
+ }
+
+ protected function registerFunction($api_auth = false, $user_auth = false, $params = null) {
+ $parameters = array('param1' => array('type' => 'int', 'required' => true),
+ 'param2' => array('type' => 'bool', 'required' => false), );
+
+ if ($params == null) {
+ $params = $parameters;
+ }
+
+ expose_function('test', 'elgg_echo', $params, '', 'POST', $api_auth, $user_auth);
+ }
+
+}
diff --git a/engine/tests/suite.php b/engine/tests/suite.php
new file mode 100644
index 000000000..4203bc5d6
--- /dev/null
+++ b/engine/tests/suite.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Runs unit tests.
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+
+
+require_once(dirname( __FILE__ ) . '/../start.php');
+
+admin_gatekeeper();
+
+$vendor_path = "$CONFIG->path/vendors/simpletest";
+$test_path = "$CONFIG->path/engine/tests";
+
+require_once("$vendor_path/unit_tester.php");
+require_once("$vendor_path/mock_objects.php");
+require_once("$vendor_path/reporter.php");
+require_once("$test_path/elgg_unit_test.php");
+
+// turn off system log
+elgg_unregister_event_handler('all', 'all', 'system_log_listener');
+elgg_unregister_event_handler('log', 'systemlog', 'system_log_default_logger');
+
+// Disable maximum execution time.
+// Tests take a while...
+set_time_limit(0);
+
+$suite = new TestSuite('Elgg Core Unit Tests');
+
+// emit a hook to pull in all tests
+$test_files = elgg_trigger_plugin_hook('unit_test', 'system', null, array());
+foreach ($test_files as $file) {
+ $suite->addTestFile($file);
+}
+
+// Only run tests in debug mode.
+if (!isset($CONFIG->debug)) {
+ exit ('The site must be in debug mode to run unit tests.');
+}
+
+if (TextReporter::inCli()) {
+ // In CLI error codes are returned: 0 is success
+ elgg_set_ignore_access(TRUE);
+ exit ($suite->Run(new TextReporter()) ? 0 : 1 );
+}
+
+// Ensure that only logged-in users can see this page
+//admin_gatekeeper();
+$old = elgg_set_ignore_access(TRUE);
+$suite->Run(new HtmlReporter('utf-8'));
+elgg_set_ignore_access($old);
diff --git a/engine/tests/test_files/output/autop/block-a.exp.norun.html b/engine/tests/test_files/output/autop/block-a.exp.norun.html
new file mode 100644
index 000000000..addf29dec
--- /dev/null
+++ b/engine/tests/test_files/output/autop/block-a.exp.norun.html
@@ -0,0 +1,6 @@
+
+<p>HTML5 allows A to contain block-level content</p>
+<a href="foo"><h3>A treated as block</h3>
+<p>Read more</p>
+</a>
+<p><a href="foo">A treated as<br /> inline</a></p>
diff --git a/engine/tests/test_files/output/autop/block-a.in.norun.html b/engine/tests/test_files/output/autop/block-a.in.norun.html
new file mode 100644
index 000000000..fc2dac43a
--- /dev/null
+++ b/engine/tests/test_files/output/autop/block-a.in.norun.html
@@ -0,0 +1,9 @@
+HTML5 allows A to contain block-level content
+<a href="foo">
+
+ <h3>A treated as block</h3>
+
+ Read more
+</a>
+<a href="foo">A treated as
+ inline</a>
diff --git a/engine/tests/test_files/output/autop/domdoc_exp.html b/engine/tests/test_files/output/autop/domdoc_exp.html
new file mode 100644
index 000000000..8480c1083
--- /dev/null
+++ b/engine/tests/test_files/output/autop/domdoc_exp.html
@@ -0,0 +1,46 @@
+›
+Vietnamese - Tiếng Việt
+
+<h1>h1</h1>
+<p>Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em> <span style="background-color: #ffff00; "></span></p>
+<h2>h2</h2>
+<p>Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span></p>
+<h3>h3</h3>
+<p>Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span></p>
+<blockquote>
+ <p>Blockquoted paragraph</p>
+</blockquote>
+<p>Paragraph following blockquote</p>
+<ul><li>Unordered</li>
+ <li>List</li>
+</ul><p>Paragraph between lists</p>
+<ol><li>Ordered</li>
+ <li>List</li>
+</ol><p>Paragraph between lists</p>
+<ul><li>OL list</li>
+ <li>nested<ol><li>inside a</li>
+ <li>UL list</li>
+ </ol></li>
+</ul><p>Paragraph between lists</p>
+<table border="0"><tbody><tr><td>Table with</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>border=0</td>
+ </tr></tbody></table><p>Paragraph</p>
+<ol><li>UL list</li>
+ <li>nested
+ <ul><li>inside a</li>
+ <li>OL list</li>
+ </ul></li>
+</ol><p>Paragraph between tables</p>
+<table border="1" cellpadding="5"><tbody><tr><td>Table with border=1</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>cellpadding = 5</td>
+ </tr></tbody></table><p>Paragraph between tables</p>
+<table border="2"><tbody><tr><td>Table with</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>border=2</td>
+ </tr></tbody></table> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/domdoc_in.html b/engine/tests/test_files/output/autop/domdoc_in.html
new file mode 100644
index 000000000..4c465b435
--- /dev/null
+++ b/engine/tests/test_files/output/autop/domdoc_in.html
@@ -0,0 +1,80 @@
+&#8250;
+&nbsp;
+Vietnamese - Tiếng Việt
+
+<h1>h1</h1>
+<p>Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em>&nbsp;<span style="background-color: #ffff00; "></span></p>
+<h2>h2</h2>
+<p>Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span></p>
+<h3>h3</h3>
+<p>Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span></p>
+<blockquote>
+ <p>Blockquoted paragraph</p>
+</blockquote>
+<p>Paragraph following blockquote</p>
+<ul>
+ <li>Unordered</li>
+ <li>List</li>
+</ul>
+<p>Paragraph between lists</p>
+<ol>
+ <li>Ordered</li>
+ <li>List</li>
+</ol>
+<p>Paragraph between lists</p>
+<ul>
+ <li>OL list</li>
+ <li>nested<ol>
+ <li>inside a</li>
+ <li>UL list</li>
+ </ol></li>
+</ul>
+<p>Paragraph between lists</p>
+<table border="0">
+ <tbody>
+ <tr>
+ <td>Table with</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>border=0</td>
+ </tr>
+ </tbody>
+</table>
+<p>Paragraph</p>
+<ol>
+ <li>UL list</li>
+ <li>nested
+ <ul>
+ <li>inside a</li>
+ <li>OL list</li>
+ </ul>
+ </li>
+</ol>
+<p>Paragraph between tables</p>
+<table border="1" cellpadding="5">
+ <tbody>
+ <tr>
+ <td>Table with border=1</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>cellpadding = 5</td>
+ </tr>
+ </tbody>
+</table>
+<p>Paragraph between tables</p>
+<table border="2">
+ <tbody>
+ <tr>
+ <td>Table with</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>border=2</td>
+ </tr>
+ </tbody>
+</table> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/typical-post.exp.html b/engine/tests/test_files/output/autop/typical-post.exp.html
new file mode 100644
index 000000000..f9d75a114
--- /dev/null
+++ b/engine/tests/test_files/output/autop/typical-post.exp.html
@@ -0,0 +1,84 @@
+<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
+<p><img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150">Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum.</p>
+
+<p>Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor.</p>
+<h3>Donec at massa ante, sagittis fermentum urna.</h3><blockquote>
+<p>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare.</p>
+
+<p>[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150">[/caption]</p>
+
+<p>Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis.</p>
+
+<p>Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</p>
+</blockquote>
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus.</p>
+<pre><code>&lt;?php
+class DataTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provider
+ */
+ public function testAdd($a, $b, $c)
+ {
+ $this-&gt;assertEquals($c, $a + $b);
+ }
+
+ public function provider()
+ {
+ return array(
+ array(0, 0, 0),
+ array(0, 1, 1),
+ array(1, 0, 1),
+ array(1, 1, 3)
+ );
+ }
+}</code></pre><ul><li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li>
+ <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li>
+ <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li>
+ <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li>
+</ul>
+<p>Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna.</p>
+
+<p><object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object></p>
+<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
+<p><img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150">Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum.</p>
+
+<p>Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor.</p>
+<h3>Donec at massa ante, sagittis fermentum urna.</h3><blockquote>
+<p>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare.</p>
+
+<p>[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150">[/caption]</p>
+
+<p>Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis.</p>
+
+<p>Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</p>
+</blockquote>
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus.</p>
+<pre><code>&lt;?php
+class DataTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provider
+ */
+ public function testAdd($a, $b, $c)
+ {
+ $this-&gt;assertEquals($c, $a + $b);
+ }
+
+ public function provider()
+ {
+ return array(
+ array(0, 0, 0),
+ array(0, 1, 1),
+ array(1, 0, 1),
+ array(1, 1, 3)
+ );
+ }
+}</code></pre><ul><li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li>
+ <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li>
+ <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li>
+ <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li>
+</ul>
+<p>Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna.</p>
+
+<p><object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object></p>
diff --git a/engine/tests/test_files/output/autop/typical-post.in.html b/engine/tests/test_files/output/autop/typical-post.in.html
new file mode 100644
index 000000000..6e4984cc4
--- /dev/null
+++ b/engine/tests/test_files/output/autop/typical-post.in.html
@@ -0,0 +1,89 @@
+<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
+<img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150" />Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum.
+
+Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor.
+<h3>Donec at massa ante, sagittis fermentum urna.</h3>
+<blockquote>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare.
+
+[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150" />[/caption]
+
+Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis.
+
+Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</blockquote>
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus.
+
+<pre><code>&lt;?php
+class DataTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provider
+ */
+ public function testAdd($a, $b, $c)
+ {
+ $this-&gt;assertEquals($c, $a + $b);
+ }
+
+ public function provider()
+ {
+ return array(
+ array(0, 0, 0),
+ array(0, 1, 1),
+ array(1, 0, 1),
+ array(1, 1, 3)
+ );
+ }
+}</code></pre>
+<ul>
+ <li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li>
+ <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li>
+ <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li>
+ <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li>
+</ul>
+Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna.
+
+<object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object>
+
+<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
+<img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150" />Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum.
+
+Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor.
+<h3>Donec at massa ante, sagittis fermentum urna.</h3>
+<blockquote>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare.
+
+[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150" />[/caption]
+
+Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis.
+
+Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</blockquote>
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus.
+
+<pre><code>&lt;?php
+class DataTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provider
+ */
+ public function testAdd($a, $b, $c)
+ {
+ $this-&gt;assertEquals($c, $a + $b);
+ }
+
+ public function provider()
+ {
+ return array(
+ array(0, 0, 0),
+ array(0, 1, 1),
+ array(1, 0, 1),
+ array(1, 1, 3)
+ );
+ }
+}</code></pre>
+<ul>
+ <li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li>
+ <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li>
+ <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li>
+ <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li>
+</ul>
+Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna.
+
+<object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&amp;hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/wp-welcome.exp.html b/engine/tests/test_files/output/autop/wp-welcome.exp.html
new file mode 100644
index 000000000..2f612e3dd
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wp-welcome.exp.html
@@ -0,0 +1,22 @@
+
+<p>Welcome to WordPress! This post contains important information. After you read it, you can make it private to hide it from visitors but still have the information handy for future reference.</p>
+
+<p>First things first:</p>
+<ul><li><a href="%1%24s" title="Subscribe to the WordPress mailing list for Release Notifications">Subscribe to the WordPress mailing list for release notifications</a></li>
+</ul>
+<p>As a subscriber, you will receive an email every time an update is available (and only then). This will make it easier to keep your site up to date, and secure from evildoers.<br />When a new version is released, <a href="%2%24s" title="If you are already logged in, this will take you directly to the Dashboard">log in to the Dashboard</a> and follow the instructions.<br />Upgrading is a couple of clicks!</p>
+
+<p>Then you can start enjoying the WordPress experience:</p>
+<ul><li>Edit your personal information at <a href="%3%24s" title="Edit settings like your password, your display name and your contact information">Users &#8250; Your Profile</a></li>
+ <li>Start publishing at <a href="%4%24s" title="Create a new post">Posts &#8250; Add New</a> and at <a href="%5%24s" title="Create a new page">Pages &#8250; Add New</a></li>
+ <li>Browse and install plugins at <a href="%6%24s" title="Browse and install plugins at the official WordPress repository directly from your Dashboard">Plugins &#8250; Add New</a></li>
+ <li>Browse and install themes at <a href="%7%24s" title="Browse and install themes at the official WordPress repository directly from your Dashboard">Appearance &#8250; Add New Themes</a></li>
+ <li>Modify and prettify your website&#8217;s links at <a href="%8%24s" title="For example, select a link structure like: http://example.com/1999/12/post-name">Settings &#8250; Permalinks</a></li>
+ <li>Import content from another system or WordPress site at <a href="%9%24s" title="WordPress comes with importers for the most common publishing systems">Tools &#8250; Import</a></li>
+ <li>Find answers to your questions at the <a href="%10%24s" title="The official WordPress documentation, maintained by the WordPress community">WordPress Codex</a></li>
+</ul>
+<p>To keep this post for reference, <a href="%11%24s" title="Click to edit the content and settings of this post">click to edit it</a>, go to the Publish box and change its Visibility from Public to Private.</p>
+
+<p>Thank you for selecting WordPress. We wish you happy publishing!</p>
+
+<p>PS. Not yet subscribed for update notifications? <a href="%1%24s" title="Subscribe to the WordPress mailing list for Release Notifications">Do it now!</a></p>
diff --git a/engine/tests/test_files/output/autop/wp-welcome.in.html b/engine/tests/test_files/output/autop/wp-welcome.in.html
new file mode 100644
index 000000000..338ede73f
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wp-welcome.in.html
@@ -0,0 +1,25 @@
+Welcome to WordPress! This post contains important information. After you read it, you can make it private to hide it from visitors but still have the information handy for future reference.
+
+First things first:
+<ul>
+ <li><a href="%1$s" title="Subscribe to the WordPress mailing list for Release Notifications">Subscribe to the WordPress mailing list for release notifications</a></li>
+</ul>
+As a subscriber, you will receive an email every time an update is available (and only then). This will make it easier to keep your site up to date, and secure from evildoers.
+When a new version is released, <a href="%2$s" title="If you are already logged in, this will take you directly to the Dashboard">log in to the Dashboard</a> and follow the instructions.
+Upgrading is a couple of clicks!
+
+Then you can start enjoying the WordPress experience:
+<ul>
+ <li>Edit your personal information at <a href="%3$s" title="Edit settings like your password, your display name and your contact information">Users &#8250; Your Profile</a></li>
+ <li>Start publishing at <a href="%4$s" title="Create a new post">Posts &#8250; Add New</a> and at <a href="%5$s" title="Create a new page">Pages &#8250; Add New</a></li>
+ <li>Browse and install plugins at <a href="%6$s" title="Browse and install plugins at the official WordPress repository directly from your Dashboard">Plugins &#8250; Add New</a></li>
+ <li>Browse and install themes at <a href="%7$s" title="Browse and install themes at the official WordPress repository directly from your Dashboard">Appearance &#8250; Add New Themes</a></li>
+ <li>Modify and prettify your website&#8217;s links at <a href="%8$s" title="For example, select a link structure like: http://example.com/1999/12/post-name">Settings &#8250; Permalinks</a></li>
+ <li>Import content from another system or WordPress site at <a href="%9$s" title="WordPress comes with importers for the most common publishing systems">Tools &#8250; Import</a></li>
+ <li>Find answers to your questions at the <a href="%10$s" title="The official WordPress documentation, maintained by the WordPress community">WordPress Codex</a></li>
+</ul>
+To keep this post for reference, <a href="%11$s" title="Click to edit the content and settings of this post">click to edit it</a>, go to the Publish box and change its Visibility from Public to Private.
+
+Thank you for selecting WordPress. We wish you happy publishing!
+
+PS. Not yet subscribed for update notifications? <a href="%1$s" title="Subscribe to the WordPress mailing list for Release Notifications">Do it now!</a>
diff --git a/engine/tests/test_files/output/autop/wpautop-fails.exp.html b/engine/tests/test_files/output/autop/wpautop-fails.exp.html
new file mode 100644
index 000000000..d018db4ff
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wpautop-fails.exp.html
@@ -0,0 +1,31 @@
+
+<p>paragraph</p>
+
+<p>paragraph</p>
+<div class="whatever"><blockquote>
+<p>paragraph</p>
+</blockquote>
+<p>line</p>
+</div>
+<p>paragraph</p>
+<ul><li>line</li>
+<li>paragraph
+
+paragraph</li>
+</ul>
+<p>paragraph<br />line<br />line</p>
+<pre>Honor
+this whitespace
+</pre>
+<p>paragraph</p>
+<style><!--
+Do not alter!
+--></style>
+<p>paragraph <!-- do not alter --></p>
+<dl><dt>term</dt> <dd>paragraph
+
+<a href="xx"> <img src="yy"></a>
+
+paragraph</dd> </dl><div><a href="xx"> <img src="yy"></a></div>
+<p>Hello <a href="link"><br /><br />World</a></p>
+<p id="abc">Paragraph</p><div>Line</div> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/wpautop-fails.in.html b/engine/tests/test_files/output/autop/wpautop-fails.in.html
new file mode 100644
index 000000000..9aa24be59
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wpautop-fails.in.html
@@ -0,0 +1,41 @@
+
+paragraph
+
+paragraph <div class="whatever"><blockquote>
+ paragraph
+ </blockquote>
+ line
+</div>
+
+paragraph
+<ul>
+<li>line</li>
+<li>paragraph
+
+paragraph</li>
+</ul>
+paragraph
+line<br>
+ line
+<pre>Honor
+this whitespace
+</pre>
+paragraph
+<style><!--
+Do not alter!
+--></style>
+paragraph <!-- do not alter -->
+<dl> <dt>term</dt> <dd>paragraph
+
+<a href="xx"> <img src="yy" /> </a>
+
+paragraph</dd> </dl>
+<div><a href="xx"> <img src="yy" /> </a></div>
+
+Hello <a href="link">
+
+World</a>
+
+<p id="abc">Paragraph</p>
+
+<div>Line</div> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/wysiwyg-test.exp.html b/engine/tests/test_files/output/autop/wysiwyg-test.exp.html
new file mode 100644
index 000000000..1f23d6154
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wysiwyg-test.exp.html
@@ -0,0 +1,51 @@
+
+<p>&nbps;<br />&#8820;</p>
+<h1>h1</h1>
+<p>Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em>&nbsp;<span style="background-color: #ffff00; "></span></p>
+<h2>h2</h2>
+<p>Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span></p>
+<h3>h3</h3>
+<p>Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span></p>
+<blockquote>
+<p>Blockquoted paragraph</p>
+</blockquote>
+<p>Paragraph following blockquote</p>
+<ul><li>Unordered</li>
+ <li>List</li>
+</ul>
+<p>Paragraph between lists</p>
+<ol><li>Ordered</li>
+ <li>List</li>
+</ol>
+<p>Paragraph between lists</p>
+<ul><li>OL list</li>
+ <li>nested
+ <ol><li>inside a</li>
+ <li>UL list</li>
+ </ol></li>
+</ul>
+<p>Paragraph between lists</p>
+<table border="0"><tbody><tr></tr><tr><td>Table with</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>border=0</td>
+ </tr></tbody></table>
+<p>Paragraph</p>
+<ol><li>UL list</li>
+ <li>nested
+ <ul><li>inside a</li>
+ <li>OL list</li>
+ </ul></li>
+</ol>
+<p>Paragraph between tables</p>
+<table border="1" cellpadding="5"><tbody><tr><td>Table with border=1</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>cellpadding = 5</td>
+ </tr></tbody></table>
+<p>Paragraph between tables</p>
+<table border="2"><tbody><tr><td>Table with</td>
+ <td></td>
+ </tr><tr><td></td>
+ <td>border=2</td>
+ </tr></tbody></table> \ No newline at end of file
diff --git a/engine/tests/test_files/output/autop/wysiwyg-test.in.html b/engine/tests/test_files/output/autop/wysiwyg-test.in.html
new file mode 100644
index 000000000..733b0e2ec
--- /dev/null
+++ b/engine/tests/test_files/output/autop/wysiwyg-test.in.html
@@ -0,0 +1,79 @@
+&nbps;
+&#8820;
+<h1>h1</h1>
+Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em>&nbsp;<span style="background-color: #ffff00; "></span>
+<h2>h2</h2>
+Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span>
+<h3>h3</h3>
+Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span>
+<blockquote>Blockquoted paragraph</blockquote>
+Paragraph following blockquote
+<ul>
+ <li>Unordered</li>
+ <li>List</li>
+</ul>
+Paragraph between lists
+<ol>
+ <li>Ordered</li>
+ <li>List</li>
+</ol>
+Paragraph between lists
+<ul>
+ <li>OL list</li>
+ <li>nested
+ <ol>
+ <li>inside a</li>
+ <li>UL list</li>
+ </ol></li>
+</ul>
+Paragraph between lists
+<table border="0">
+ <tbody>
+ <tr>
+ </tr>
+ <tr>
+ <td>Table with</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>border=0</td>
+ </tr>
+ </tbody>
+</table>
+Paragraph
+<ol>
+ <li>UL list</li>
+ <li>nested
+ <ul>
+ <li>inside a</li>
+ <li>OL list</li>
+ </ul>
+ </li>
+</ol>
+Paragraph between tables
+<table border="1" cellpadding="5">
+ <tbody>
+ <tr>
+ <td>Table with border=1</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>cellpadding = 5</td>
+ </tr>
+ </tbody>
+</table>
+Paragraph between tables
+<table border="2">
+ <tbody>
+ <tr>
+ <td>Table with</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>border=2</td>
+ </tr>
+ </tbody>
+</table> \ No newline at end of file
diff --git a/engine/tests/test_files/plugin_17/manifest.xml b/engine/tests/test_files/plugin_17/manifest.xml
new file mode 100644
index 000000000..706734265
--- /dev/null
+++ b/engine/tests/test_files/plugin_17/manifest.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin_manifest>
+ <field key="author" value="Anyone" />
+ <field key="version" value="1.0" />
+ <field key="description" value="A 1.7-style manifest." />
+ <field key="website" value="http://www.elgg.org/" />
+ <field key="copyright" value="(C) Elgg Foundation 2011" />
+ <field key="license" value="GNU General Public License version 2" />
+ <field key="elgg_version" value="2009030702" />
+</plugin_manifest> \ No newline at end of file
diff --git a/engine/tests/test_files/plugin_17/start.php b/engine/tests/test_files/plugin_17/start.php
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/engine/tests/test_files/plugin_17/start.php
diff --git a/engine/tests/test_files/plugin_18/manifest.xml b/engine/tests/test_files/plugin_18/manifest.xml
new file mode 100644
index 000000000..c8b407511
--- /dev/null
+++ b/engine/tests/test_files/plugin_18/manifest.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin_manifest xmlns="http://www.elgg.org/plugin_manifest/1.8">
+ <name>Test Manifest</name>
+ <author>Anyone</author>
+ <version>1.0</version>
+ <blurb>A concise description.</blurb>
+ <description>A longer, more interesting description.</description>
+ <website>http://www.elgg.org/</website>
+ <repository>https://github.com/Elgg/Elgg</repository>
+ <bugtracker>https://github.com/elgg/elgg/issues</bugtracker>
+ <donations>http://elgg.org/supporter.php</donations>
+ <copyright>(C) Elgg Foundation 2011</copyright>
+ <license>GNU General Public License version 2</license>
+
+ <requires>
+ <type>elgg_version</type>
+ <version>3009030802</version>
+ <comparison>lt</comparison>
+ </requires>
+
+ <requires>
+ <type>elgg_release</type>
+ <version>1.8-svn</version>
+ </requires>
+
+ <screenshot>
+ <description>Fun things to do 1</description>
+ <path>graphics/plugin_ss1.png</path>
+ </screenshot>
+
+ <screenshot>
+ <description>Fun things to do 2</description>
+ <path>graphics/plugin_ss2.png</path>
+ </screenshot>
+
+ <category>Admin</category>
+
+ <category>ServiceAPI</category>
+
+ <requires>
+ <type>php_extension</type>
+ <name>gd</name>
+ </requires>
+
+ <requires>
+ <type>php_ini</type>
+ <name>short_open_tag</name>
+ <value>off</value>
+ </requires>
+
+ <requires>
+ <type>php_extension</type>
+ <name>made_up</name>
+ <version>1.0</version>
+ </requires>
+
+ <requires>
+ <type>plugin</type>
+ <name>fake_plugin</name>
+ <version>1.0</version>
+ </requires>
+
+ <requires>
+ <type>plugin</type>
+ <name>profile</name>
+ <version>1.0</version>
+ </requires>
+
+ <requires>
+ <type>plugin</type>
+ <name>profile_api</name>
+ <version>1.3</version>
+ <comparison>lt</comparison>
+ </requires>
+
+ <requires>
+ <type>priority</type>
+ <priority>after</priority>
+ <plugin>profile</plugin>
+ </requires>
+
+ <conflicts>
+ <type>plugin</type>
+ <name>profile_api</name>
+ <version>1.0</version>
+ </conflicts>
+
+ <provides>
+ <type>plugin</type>
+ <name>profile_api</name>
+ <version>1.3</version>
+ </provides>
+
+ <provides>
+ <type>php_extension</type>
+ <name>big_math</name>
+ <version>1.0</version>
+ </provides>
+
+ <suggests>
+ <type>plugin</type>
+ <name>facebook_connect</name>
+ <version>1.0</version>
+ </suggests>
+
+ <activate_on_install>true</activate_on_install>
+
+</plugin_manifest>
diff --git a/engine/tests/test_files/plugin_18/start.php b/engine/tests/test_files/plugin_18/start.php
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/engine/tests/test_files/plugin_18/start.php
diff --git a/engine/tests/test_files/xxe/external_entity.txt b/engine/tests/test_files/xxe/external_entity.txt
new file mode 100644
index 000000000..536aca34d
--- /dev/null
+++ b/engine/tests/test_files/xxe/external_entity.txt
@@ -0,0 +1 @@
+secret \ No newline at end of file
diff --git a/engine/tests/test_files/xxe/request.xml b/engine/tests/test_files/xxe/request.xml
new file mode 100644
index 000000000..4390f9db2
--- /dev/null
+++ b/engine/tests/test_files/xxe/request.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE foo [
+<!ELEMENT methodName ANY >
+<!ENTITY xxe SYSTEM "%s" >
+]>
+<methodCall>
+ <methodName>test&xxe;test</methodName>
+</methodCall>
diff --git a/engine/tests/test_skeleton.php b/engine/tests/test_skeleton.php
new file mode 100644
index 000000000..5a5de89bb
--- /dev/null
+++ b/engine/tests/test_skeleton.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Elgg Test Skeleton
+ *
+ * Plugin authors: copy this file to your plugin's test directory. Register an Elgg
+ * plugin hook and function similar to:
+ *
+ * elgg_register_plugin_hook_handler('unit_test', 'system', 'my_new_unit_test');
+ *
+ * function my_new_unit_test($hook, $type, $value, $params) {
+ * $value[] = "path/to/my/unit_test.php";
+ * return $value;
+ * }
+ *
+ * @package Elgg
+ * @subpackage Test
+ */
+class ElggCoreSkeletonTest extends ElggCoreUnitTest {
+
+ /**
+ * Called before each test object.
+ */
+ public function __construct() {
+ parent::__construct();
+
+ // all __construct() code should come after here
+ }
+
+ /**
+ * Called before each test method.
+ */
+ public function setUp() {
+
+ }
+
+ /**
+ * Called after each test method.
+ */
+ public function tearDown() {
+ // do not allow SimpleTest to interpret Elgg notices as exceptions
+ $this->swallowErrors();
+ }
+
+ /**
+ * Called after each test object.
+ */
+ public function __destruct() {
+ // all __destruct() code should go above here
+ parent::__destruct();
+ }
+
+ public function testFailure() {
+ $this->assertTrue(FALSE);
+ }
+}