aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/acceptance/behat.yml27
-rw-r--r--tests/acceptance/features/bootstrap/AdminContext.php23
-rw-r--r--tests/acceptance/features/bootstrap/ApiContext.php23
-rw-r--r--tests/acceptance/features/bootstrap/FeatureContext.php23
-rw-r--r--tests/acceptance/features/login_local.feature18
-rwxr-xr-xtests/create_test_db.sh113
-rw-r--r--tests/fakes/fake_dba.php18
-rw-r--r--tests/phpunit.xml48
-rw-r--r--tests/unit/GetTagsTest.php5
-rw-r--r--tests/unit/Lib/ActivityTest.php39
-rw-r--r--tests/unit/Lib/ConfigTest.php12
-rw-r--r--tests/unit/Lib/JcsEddsa2022Test.php174
-rw-r--r--tests/unit/Lib/PermissionDescriptionTest.php47
-rw-r--r--tests/unit/UnitTestCase.php94
-rw-r--r--tests/unit/Web/HttpSigTest.php7
-rw-r--r--tests/unit/includes/AccountTest.php34
-rw-r--r--tests/unit/includes/BBCodeTest.php220
-rw-r--r--tests/unit/includes/MarkdownTest.php129
-rw-r--r--tests/unit/includes/NetworkTest.php89
-rw-r--r--tests/unit/includes/PhotodriverTest.php28
-rw-r--r--tests/unit/includes/TextTest.php2
-rw-r--r--tests/unit/includes/dba/TransactionTest.php207
-rw-r--r--tests/unit/includes/dba/_files/config.yml23
23 files changed, 1166 insertions, 237 deletions
diff --git a/tests/acceptance/behat.yml b/tests/acceptance/behat.yml
deleted file mode 100644
index 933571e5e..000000000
--- a/tests/acceptance/behat.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-default:
- suites:
- default:
- paths:
- - %paths.base%/features
- contexts:
- - Behat\MinkExtension\Context\MinkContext
- admin_features:
- filters: { role: admin }
- contexts:
- - AdminContext
- api_features:
- paths:
- - %paths.base%/features/api
- filters:
- tags: "@api"
- contexts:
- - ApiContext
- gherkin:
- filters:
- tags: ~@wip
- extensions:
- Behat\MinkExtension:
- base_url: 'http://localhost'
- sessions:
- default:
- goutte: ~
diff --git a/tests/acceptance/features/bootstrap/AdminContext.php b/tests/acceptance/features/bootstrap/AdminContext.php
deleted file mode 100644
index aa4dced67..000000000
--- a/tests/acceptance/features/bootstrap/AdminContext.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-
-use Behat\Behat\Context\Context;
-use Behat\Behat\Context\SnippetAcceptingContext;
-use Behat\Gherkin\Node\PyStringNode;
-use Behat\Gherkin\Node\TableNode;
-
-/**
- * Defines application features from the specific context.
- */
-class AdminContext implements Context, SnippetAcceptingContext
-{
- /**
- * Initializes context.
- *
- * Every scenario gets its own context instance.
- * You can also pass arbitrary arguments to the
- * context constructor through behat.yml.
- */
- public function __construct()
- {
- }
-}
diff --git a/tests/acceptance/features/bootstrap/ApiContext.php b/tests/acceptance/features/bootstrap/ApiContext.php
deleted file mode 100644
index 9b772b209..000000000
--- a/tests/acceptance/features/bootstrap/ApiContext.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-
-use Behat\Behat\Context\Context;
-use Behat\Behat\Context\SnippetAcceptingContext;
-use Behat\Gherkin\Node\PyStringNode;
-use Behat\Gherkin\Node\TableNode;
-
-/**
- * Defines application features from the specific context.
- */
-class ApiContext implements Context, SnippetAcceptingContext
-{
- /**
- * Initializes context.
- *
- * Every scenario gets its own context instance.
- * You can also pass arbitrary arguments to the
- * context constructor through behat.yml.
- */
- public function __construct()
- {
- }
-}
diff --git a/tests/acceptance/features/bootstrap/FeatureContext.php b/tests/acceptance/features/bootstrap/FeatureContext.php
deleted file mode 100644
index 2ec02da85..000000000
--- a/tests/acceptance/features/bootstrap/FeatureContext.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-
-use Behat\Behat\Context\Context;
-use Behat\Behat\Context\SnippetAcceptingContext;
-use Behat\Gherkin\Node\PyStringNode;
-use Behat\Gherkin\Node\TableNode;
-
-/**
- * Defines application features from the specific context.
- */
-class FeatureContext implements Context, SnippetAcceptingContext
-{
- /**
- * Initializes context.
- *
- * Every scenario gets its own context instance.
- * You can also pass arbitrary arguments to the
- * context constructor through behat.yml.
- */
- public function __construct()
- {
- }
-}
diff --git a/tests/acceptance/features/login_local.feature b/tests/acceptance/features/login_local.feature
deleted file mode 100644
index a7814b8f6..000000000
--- a/tests/acceptance/features/login_local.feature
+++ /dev/null
@@ -1,18 +0,0 @@
-Feature: Local login
- In order to login locally
- As a member
- I need to successfully authenticate
-
- Scenario: Provide wrong credentials
- Given I am on "/login"
- When I fill in "id_username" with "foo"
- And I fill in "id_password" with "bar"
- And I press "submit"
- Then I should be on "/login"
-
- Scenario: Provide correct credentials
- Given I am on "/login"
- When I fill in "id_username" with "behat"
- And I fill in "id_password" with "behat"
- And I press "submit"
- Then I should be on "/apps"
diff --git a/tests/create_test_db.sh b/tests/create_test_db.sh
new file mode 100755
index 000000000..b98f5e2a5
--- /dev/null
+++ b/tests/create_test_db.sh
@@ -0,0 +1,113 @@
+#!/usr/bin/env bash
+
+#
+# Copyright (c) 2016 Hubzilla
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+
+# Exit if anything fails
+set -e
+
+#
+# Initialize some defaults if they're not set by the environment
+#
+: ${HZ_TEST_DB_TYPE:=postgres}
+
+case $HZ_TEST_DB_TYPE in
+ postgres | pg | pgsql )
+ db_type="postgres"
+ default_charset="UTF8"
+ root_user="postgres"
+ root_passwd=""
+ ;;
+
+ mariadb | mysql )
+ db_type="mysql"
+ default_charset="utf8mb4"
+ root_user="root"
+ root_passwd="root"
+ ;;
+
+ * )
+ echo "Unknown database type: '${HZ_TEST_DB_TYPE}'"
+ exit
+ ;;
+esac
+
+: ${HZ_TEST_DB_ROOT_USER:=$root_user}
+: ${HZ_TEST_DB_ROOT_PASS:=$root_passwd}
+: ${HZ_TEST_DB_USER:=test_user}
+: ${HZ_TEST_DB_PASS:=hubzilla}
+: ${HZ_TEST_DB_NAME:=hubzilla_test_db}
+: ${HZ_TEST_DB_CHARSET:=$default_charset}
+
+echo "Creating Hubzilla test db..."
+
+if [[ $db_type == "postgres" ]]
+then
+ psql --version
+ psql -U $HZ_TEST_DB_ROOT_USER -c "SELECT VERSION();"
+
+ psql -U $HZ_TEST_DB_ROOT_USER -v ON_ERROR_STOP=1 <<-EOSQL
+ DROP DATABASE IF EXISTS $HZ_TEST_DB_NAME;
+ DROP USER IF EXISTS $HZ_TEST_DB_USER;
+
+ CREATE USER $HZ_TEST_DB_USER WITH PASSWORD '$HZ_TEST_DB_PASS';
+ CREATE DATABASE $HZ_TEST_DB_NAME
+ WITH
+ OWNER $HZ_TEST_DB_USER
+ ENCODING $HZ_TEST_DB_CHARSET;
+
+ EOSQL
+
+ export PGPASSWORD=$HZ_TEST_DB_PASS
+
+ # Import table structure
+ echo "Importing schema..."
+ psql -U $HZ_TEST_DB_USER -v ON_ERROR_STOP=1 $HZ_TEST_DB_NAME < ./install/schema_postgres.sql
+
+ # Show databases and tables
+ psql -U $HZ_TEST_DB_USER -l
+ psql -U $HZ_TEST_DB_USER -d $HZ_TEST_DB_NAME -c "\dt;"
+else
+ echo -e "\n--------------"
+ echo "Client version:"
+ echo -e "--------------\n"
+ mysql --version
+
+ mysql -v -u $HZ_TEST_DB_ROOT_USER -p$HZ_TEST_DB_ROOT_PASS -Ns -e "SELECT VERSION();"
+
+ mysql -u $HZ_TEST_DB_ROOT_USER -p$HZ_TEST_DB_ROOT_PASS <<-EOSQL
+ DROP DATABASE IF EXISTS $HZ_TEST_DB_NAME;
+ CREATE DATABASE $HZ_TEST_DB_NAME CHARACTER SET $HZ_TEST_DB_CHARSET;
+
+ DROP USER IF EXISTS $HZ_TEST_DB_USER;
+ CREATE USER $HZ_TEST_DB_USER IDENTIFIED BY '$HZ_TEST_DB_PASS';
+
+ GRANT ALL ON ${HZ_TEST_DB_NAME}.* TO $HZ_TEST_DB_USER;
+ EOSQL
+
+ echo -e "\n--------------"
+ echo "Importing schema..."
+ echo -e "--------------\n"
+ mysql -u $HZ_TEST_DB_USER -p$HZ_TEST_DB_PASS $HZ_TEST_DB_NAME < ./install/schema_mysql.sql
+ mysql -v -u $HZ_TEST_DB_ROOT_USER -p$HZ_TEST_DB_ROOT_PASS -Ns -e "show databases"
+ mysql -v -u $HZ_TEST_DB_USER -p$HZ_TEST_DB_PASS $HZ_TEST_DB_NAME -Ns -e "show tables"
+fi
diff --git a/tests/fakes/fake_dba.php b/tests/fakes/fake_dba.php
new file mode 100644
index 000000000..2289f5c80
--- /dev/null
+++ b/tests/fakes/fake_dba.php
@@ -0,0 +1,18 @@
+<?php
+namespace Zotlabs\Tests\Fakes;
+
+require_once 'include/dba/dba_pdo.php';
+
+/**
+ * Fake dba_driver implementation.
+ *
+ * This is a subclass of the dba_pdo class, that essentially lets us inject a
+ * stub for the PDO class that is the actual database driver.
+ */
+class FakeDba extends \dba_pdo {
+ public function __construct($stub) {
+ $this->db = $stub;
+ $this->connected = true;
+ }
+}
+
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
index 6b1b33534..a92dd530f 100644
--- a/tests/phpunit.xml
+++ b/tests/phpunit.xml
@@ -1,21 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
-<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="../boot.php" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
- <coverage processUncoveredFiles="false" includeUncoveredFiles="false">
- <include>
- <directory suffix=".php">../Zotlabs/</directory>
- <directory suffix=".php">../include/</directory>
- </include>
- </coverage>
+<phpunit
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ bootstrap="../boot.php"
+ colors="true"
+ xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
+ >
+
<php>
- <var name="db_dsn" value="mysql:dbname=gitlab_ci_hubzilla;host=mysql"/>
- <var name="db_username" value="root"/>
- <var name="db_password" value="mysql"/>
- <env name="hz_db_server" value="mysql"/>
- <env name="hz_db_scheme" value="mysql"/>
- <env name="hz_db_port" value=""/>
- <env name="hz_db_user" value="root"/>
- <env name="hz_db_pass" value="mysql"/>
- <env name="hz_db_database" value="hello_world_test"/>
+ <includePath>..</includePath>
+ <!-- env name="HZ_TEST_DB_HOST" value=""/-->
+ <env name="HZ_TEST_DB_TYPE" value="postgres"/>
+ <!-- env name="HZ_TEST_DB_PORT" value=""/-->
+ <env name="HZ_TEST_DB_USER" value="test_user"/>
+ <env name="HZ_TEST_DB_PASS" value="hubzilla"/>
+ <env name="HZ_TEST_DB_DATABASE" value="hubzilla_test_db"/>
+ <env name="HZ_TEST_DB_CHARSET" value="UTF8"/>
</php>
<testsuites>
<testsuite name="Hubzilla default Test Suite">
@@ -24,14 +23,17 @@
<testsuite name="API Test Suite">
<directory suffix="Test.php" prefix="API">./unit/</directory>
</testsuite>
- <testsuite name="Ex-/Import Test Suite">
- <!--<directory suffix="Test.php">./Unit/eximport/</directory>-->
- </testsuite>
</testsuites>
- <groups>
+ <coverage
+ processUncoveredFiles="false"
+ cacheDirectory=".cache/phpunit"
+ >
+ <include>
+ <directory suffix=".php">../Zotlabs/</directory>
+ <directory suffix=".php">../include/</directory>
+ </include>
<exclude>
- <group>postgresql</group>
+ <directory suffix=".php">../Zotlabs/Update/</directory>
</exclude>
- </groups>
- <!--cover reporting-->
+ </coverage>
</phpunit>
diff --git a/tests/unit/GetTagsTest.php b/tests/unit/GetTagsTest.php
index 418d32c47..ccb88080e 100644
--- a/tests/unit/GetTagsTest.php
+++ b/tests/unit/GetTagsTest.php
@@ -26,6 +26,7 @@ class MockApp {
*
* @param string $sql
*/
+/*
function q($sql) {
$result=array(array('id'=>15,
'attag'=>'', 'network'=>'dfrn',
@@ -55,7 +56,7 @@ function q($sql) {
return $result;
}
}
-
+*/
/**
* Replacement for dbesc.
* I don't want to test dbesc here, so
@@ -68,9 +69,11 @@ function q($sql) {
*
* @return input
*/
+/*
function dbesc($str) {
return $str;
}
+*/
/**
* TestCase for tag handling.
diff --git a/tests/unit/Lib/ActivityTest.php b/tests/unit/Lib/ActivityTest.php
new file mode 100644
index 000000000..c9ce79d8c
--- /dev/null
+++ b/tests/unit/Lib/ActivityTest.php
@@ -0,0 +1,39 @@
+<?php
+namespace Zotlabs\Tests\Unit\Lib;
+
+error_reporting(E_ALL);
+
+use Zotlabs\Tests\Unit\UnitTestCase;
+use Zotlabs\Lib\Activity;
+
+class ActivityTest extends UnitTestCase {
+ /**
+ * Test get a textfield from an activitystreams object
+ *
+ * @dataProvider get_textfield_provider
+ */
+ public function test_get_textfield(array $src, null|string|array $expected): void {
+ $this->assertEquals($expected, Activity::get_textfield($src, 'content'));
+ }
+
+ /**
+ * Dataprovider for test_get_textfield.
+ */
+ private function get_textfield_provider(): array {
+ return [
+ 'get content field' => [
+ ['content' => 'Some content'],
+ 'Some content'
+ ],
+ 'get content from map' => [
+ ['contentMap' => ['en' => 'Some content']],
+ ['en' => 'Some content']
+ ],
+ 'get not available content' => [
+ ['some_field' => 'Some content'],
+ null
+ ]
+ ];
+ }
+
+}
diff --git a/tests/unit/Lib/ConfigTest.php b/tests/unit/Lib/ConfigTest.php
index a8ae3631b..c853cdd87 100644
--- a/tests/unit/Lib/ConfigTest.php
+++ b/tests/unit/Lib/ConfigTest.php
@@ -20,6 +20,7 @@ class ConfigTest extends Zotlabs\Tests\Unit\UnitTestCase {
'php-array' => 'a:3:{i:0;s:3:"one";i:1;s:3:"two";i:2;s:5:"three";}',
'json-array' => 'json:["one","two","three"]',
'object-injection' => 'a:1:{i:0;O:18:"Zotlabs\Lib\Config":0:{}}',
+ 'unserialized-array' => ['one', 'two', 'three'],
'config_loaded' => true,
),
);
@@ -51,6 +52,17 @@ class ConfigTest extends Zotlabs\Tests\Unit\UnitTestCase {
}
/*
+ * Test that we can retreive unserialized arrays which are usually
+ * returned from the existing config cache.
+ */
+ public function testGetPHPUnserializedArray(): void {
+ $this->assertEquals(
+ Zotlabs\Lib\Config::Get('test', 'unserialized-array'),
+ array('one', 'two', 'three')
+ );
+ }
+
+ /*
* Make sure we're not vulnerable to PHP Object injection attacks when
* using the PHP `unserialize()` function.
*/
diff --git a/tests/unit/Lib/JcsEddsa2022Test.php b/tests/unit/Lib/JcsEddsa2022Test.php
new file mode 100644
index 000000000..d18ad01ce
--- /dev/null
+++ b/tests/unit/Lib/JcsEddsa2022Test.php
@@ -0,0 +1,174 @@
+<?php
+
+namespace Zotlabs\Tests\Unit\Lib;
+
+use Zotlabs\Lib\JcsEddsa2022;
+use Zotlabs\Tests\Unit\UnitTestCase;
+
+class JcsEddsa2022Test extends UnitTestCase {
+
+ public function testVerifyFromSpec() {
+ $publicKey = 'z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2';
+ $privateKey = 'z3u2en7t5LR2WtQH5PfFqMqwVHBeXouLzo6haApm8XHqvjxq';
+
+ $document = '{
+ "@context": [
+ "https://www.w3.org/ns/credentials/v2",
+ "https://www.w3.org/ns/credentials/examples/v2"
+ ],
+ "id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
+ "type": [
+ "VerifiableCredential",
+ "AlumniCredential"
+ ],
+ "name": "Alumni Credential",
+ "description": "A minimum viable example of an Alumni Credential.",
+ "issuer": "https://vc.example/issuers/5678",
+ "validFrom": "2023-01-01T00:00:00Z",
+ "credentialSubject": {
+ "id": "did:example:abcdefgh",
+ "alumniOf": "The School of Examples"
+ },
+ "proof": {
+ "type": "DataIntegrityProof",
+ "cryptosuite": "eddsa-jcs-2022",
+ "created": "2023-02-24T23:36:38Z",
+ "verificationMethod": "https://vc.example/issuers/5678#z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2",
+ "proofPurpose": "assertionMethod",
+ "proofValue": "z3P6rHMUaWG6e3Ac6xYFht8aEvoVXndgKTtEY8kzWYXzk8dKmAo2GJeZiJw4qoZ2PGp4ugdaHx3oQiLpeFBLDqP2M"
+ }
+ }';
+
+ $verified = (new JcsEddsa2022())->verify(json_decode($document, true), $publicKey);
+ $this->assertTrue($verified, 'Verify eddsa-jcs-2022 (from specification)');
+
+ }
+
+ public function testSignAndVerify() {
+ $publicKey = 'z6MkfpucGTDbMZADwM6vEa8pS3s8Z9xqSEn6HihijZ4fVs9d';
+ $channel = [
+ 'channel_url' => 'https://example.com/channel/klingon',
+ 'channel_epubkey' => 'FGdbYgr526Swuyya3e8epCBdHahlWNg9I0sBhMKCzpw',
+ 'channel_eprvkey' => 'StLRo8xb7VJ5XdR10OUYQM/uooP7D7fMlgvQFa1wrZIUZ1tiCvnbpLC7LJrd7x6kIF0dqGVY2D0jSwGEwoLOnA',
+ 'channel_address' => 'klingon@example.com',
+ 'channel_system' => false,
+ ];
+
+ $document = '{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ "https://www.w3.org/ns/did/v1",
+ "https://w3id.org/security/multikey/v1",
+ {
+ "nomad": "https://example.com/apschema#",
+ "toot": "http://joinmastodon.org/ns#",
+ "litepub": "http://litepub.social/ns#",
+ "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+ "oauthRegistrationEndpoint": "litepub:oauthRegistrationEndpoint",
+ "sensitive": "as:sensitive",
+ "movedTo": "as:movedTo",
+ "discoverable": "toot:discoverable",
+ "indexable": "toot:indexable",
+ "capabilities": "litepub:capabilities",
+ "acceptsJoins": "litepub:acceptsJoins",
+ "Hashtag": "as:Hashtag",
+ "canReply": "toot:canReply",
+ "canSearch": "nomad:canSearch",
+ "approval": "toot:approval",
+ "expires": "nomad:expires",
+ "directMessage": "nomad:directMessage",
+ "Category": "nomad:Category",
+ "copiedTo": "nomad:copiedTo",
+ "searchContent": "nomad:searchContent",
+ "searchTags": "nomad:searchTags"
+ }
+ ],
+ "type": "Person",
+ "id": "https://example.com/channel/klingon",
+ "preferredUsername": "klingon",
+ "name": "klingon",
+ "created": "2023-07-13T20:23:32Z",
+ "updated": "2023-07-13T20:23:32Z",
+ "icon": {
+ "type": "Image",
+ "mediaType": "image/png",
+ "updated": "2023-07-13T20:23:32Z",
+ "url": "https://example.com/photo/profile/l/2",
+ "height": 300,
+ "width": 300
+ },
+ "url": "https://example.com/channel/klingon",
+ "tag": [
+ {
+ "type": "Note",
+ "name": "Protocol",
+ "content": "zot6"
+ },
+ {
+ "type": "Note",
+ "name": "Protocol",
+ "content": "nomad"
+ },
+ {
+ "type": "Note",
+ "name": "Protocol",
+ "content": "activitypub"
+ }
+ ],
+ "inbox": "https://example.com/inbox/klingon",
+ "outbox": "https://example.com/outbox/klingon",
+ "followers": "https://example.com/followers/klingon",
+ "following": "https://example.com/following/klingon",
+ "wall": "https://example.com/outbox/klingon",
+ "endpoints": {
+ "sharedInbox": "https://example.com/inbox",
+ "oauthRegistrationEndpoint": "https://example.com/api/client/register",
+ "oauthAuthorizationEndpoint": "https://example.com/authorize",
+ "oauthTokenEndpoint": "https://example.com/token",
+ "searchContent": "https://example.com/search/klingon?search={}",
+ "searchTags": "https://example.com/search/klingon?tag={}"
+ },
+ "discoverable": true,
+ "canSearch": [],
+ "indexable": false,
+ "publicKey": {
+ "id": "https://example.com/channel/klingon?operation=rsakey",
+ "owner": "https://example.com/channel/klingon",
+ "signatureAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----
+ MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+LXyOD/bzzVgM/nUOJ5m
+ c4WrQPMlhKqWJvKrumdQw9JJYcyaZp/jmMxDx/w/EwVw+wnV5wZcD0yBVhC7NPRa
+ nYc5OfNhS4MO74xgZrj+VWSTzNo3YooS/dEIIvsu6bhxfooHj17SA6pMRnZkkVpk
+ ykpPRYwJw+NvKcRwzpF06rxMqjZ+Bp0ea/X37j4cHaosRoQTJiHmMKKnpByKdImF
+ TR1juJ69ASh6nh8YVGcz6fz1jBQZPMx05tfNdyN5oZRTr8Nug2CiF3V7yKKS14HD
+ kE9eeFeTMt58Qi+8kprATYxKrlIuTZmI4YdIRgtM+tPQsosKTFmjzbef4dYooutv
+ T7XfrE+wYVZlx2pkaeFiKrJVacpmmFJe8zCIFXrofq1aOagU1kpwnXgjneCttA+M
+ OJ3Y+cPamdfRQDtsBcokJUD40RTwux6OGW9zqkJIpniVB+CZu4nTOHCzMJwbxF0p
+ JmGZd9kc3PR6Uf/IHAb1xeyTi4FyyYTbRDYuJyqRKbe880QUwgCBcogIbNy4xxsH
+ UTMy0ucWaDSBRahKUIHl3FRglvnI754NJSXBDIQOwC9oRRH27Vmm1Jy8sltmFLFr
+ ENJCGgOH8Bhpk+y1jtw1jpTig76wIvw+6zQtgNSfPnrNGIHt5mcoy4pFFXLv2lK2
+ /u26hUGQAq71Ra0DwgXIWFECAwEAAQ==
+ -----END PUBLIC KEY-----
+ "
+ },
+ "assertionMethod": [
+ {
+ "id": "https://example.com/channel/klingon#z6MkfpucGTDbMZADwM6vEa8pS3s8Z9xqSEn6HihijZ4fVs9d",
+ "type": "Multikey",
+ "controller": "https://example.com/channel/klingon",
+ "publicKeyMultibase": "z6MkfpucGTDbMZADwM6vEa8pS3s8Z9xqSEn6HihijZ4fVs9d"
+ }
+ ],
+ "manuallyApprovesFollowers": true
+ }';
+
+ $algorithm = new JcsEddsa2022();
+ $documentArray = json_decode($document,true);
+ $documentArray['proof'] = $algorithm->sign($documentArray, $channel);
+
+ $verified = (new JcsEddsa2022())->verify($documentArray, $publicKey);
+ $this->assertTrue($verified, 'Verify encode and decode eddsa-jcs-2022');
+
+ }
+}
diff --git a/tests/unit/Lib/PermissionDescriptionTest.php b/tests/unit/Lib/PermissionDescriptionTest.php
index 96c381d0c..fdd676f61 100644
--- a/tests/unit/Lib/PermissionDescriptionTest.php
+++ b/tests/unit/Lib/PermissionDescriptionTest.php
@@ -63,11 +63,52 @@ class PermissionDescriptionTest extends UnitTestCase {
$this->assertNotNull($permDescSelf);
}
+ /**
+ * Test fetching permission descriptions for the current channel.
+ */
public function testFromGlobalPermission() {
- //$permDesc = PermissionDescription::fromGlobalPermission('view_profile');
+ // Initiate the global App with a channel_id
+ \App::$channel = array(
+ 'channel_id' => 42,
+ );
+
+ // Make sure the requested permission is set for this channel.
+ \Zotlabs\Access\PermissionLimits::Set(
+ \App::$channel['channel_id'],
+ 'view_profile',
+ PERMS_NETWORK
+ );
+
+ \Zotlabs\Access\PermissionLimits::Set(
+ \App::$channel['channel_id'],
+ 'write_storage',
+ PERMS_SPECIFIC
+ );
+
+ // Set an invalid(?) permission
+ \Zotlabs\Access\PermissionLimits::Set(
+ \App::$channel['channel_id'],
+ 'view_wiki',
+ 1337
+ );
+
+ $permDesc = PermissionDescription::fromGlobalPermission('view_profile');
+ $this->assertEquals(
+ 'Anybody in the Hubzilla network',
+ $permDesc->get_permission_description()
+ );
+
+ $permDesc = PermissionDescription::fromGlobalPermission('write_storage');
+ $this->assertEquals(
+ 'Only connections I specifically allow',
+ $permDesc->get_permission_description()
+ );
- $this->markTestIncomplete(
- 'The method fromGlobalPermission() is not yet testable ...'
+ // Permissions we don't know about will get the fallback description.
+ $permDesc = PermissionDescription::fromGlobalPermission('view_wiki');
+ $this->assertEquals(
+ 'Visible to your default audience',
+ $permDesc->get_permission_description()
);
}
diff --git a/tests/unit/UnitTestCase.php b/tests/unit/UnitTestCase.php
index f6fb28555..a4ea94b13 100644
--- a/tests/unit/UnitTestCase.php
+++ b/tests/unit/UnitTestCase.php
@@ -23,12 +23,14 @@
namespace Zotlabs\Tests\Unit;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestResult;
/*
* Make sure global constants and the global App object is available to the
* tests.
*/
require_once __DIR__ . '/../../boot.php';
+require_once 'include/dba/dba_driver.php' ;
/**
* @brief Base class for our Unit Tests.
@@ -39,6 +41,94 @@ require_once __DIR__ . '/../../boot.php';
*
* @author Klaus Weidenbach
*/
-abstract class UnitTestCase extends TestCase {
- // when needed we can define functionality here which is used in UnitTests.
+class UnitTestCase extends TestCase {
+ protected array $fixtures = array();
+
+ /**
+ * Override the PHPUnit\Framework\TestCase::run method, so we can
+ * wrap it in a database transaction.
+ *
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+ */
+ public function run(TestResult $result = null): TestResult {
+ // $myclass = get_class($this);
+ // logger("[*] Running test: {$myclass}::{$this->getName(true)}", LOGGER_DEBUG);
+
+ if (! \DBA::$dba) {
+ //logger('[*] Connecting to test db...');
+ $this->connect_to_test_db();
+ }
+
+ // The $transactuion variable is needed to hold the transaction until the
+ // function returns.
+ $transaction = new \DbaTransaction(\DBA::$dba);
+
+ $this->loadFixtures();
+
+ // Make sure app config is reset and loaded from fixtures
+ \App::$config = array();
+ \Zotlabs\Lib\Config::Load('system');
+
+ $result = parent::run($result);
+
+ return $result;
+ }
+
+ protected function connect_to_test_db() : void {
+ if ( !\DBA::$dba ) {
+ \DBA::dba_factory(
+ getenv('HZ_TEST_DB_HOST') ?: 'localhost',
+
+ // Use default port for db type if none specified
+ getenv('HZ_TEST_DB_PORT'),
+ getenv('HZ_TEST_DB_USER') ?: 'test_user',
+ getenv('HZ_TEST_DB_PASS') ?: 'hubzilla',
+ getenv('HZ_TEST_DB_DATABASE') ?: 'hubzilla_test_db',
+ self::dbtype(getenv('HZ_TEST_DB_TYPE')),
+ getenv('HZ_TEST_DB_CHARSET') ?: 'UTF8',
+ false);
+
+ if ( !\DBA::$dba->connected ) {
+ $msg = "Unable to connect to db! ";
+ if(file_exists('dbfail.out')) {
+ $msg .= file_get_contents('dbfail.out');
+ }
+
+ throw new \Exception($msg);
+ }
+
+ \DBA::$dba->dbg(true);
+ }
+ }
+
+ private static function dbtype(string $type): int {
+ if (trim(strtolower($type)) === 'postgres') {
+ return DBTYPE_POSTGRES;
+ } else {
+ return DBTYPE_MYSQL;
+ }
+ }
+
+ private function loadFixtures() : void {
+ $files = glob(__DIR__ . '/includes/dba/_files/*.yml');
+ if ($files === false || empty($files)) {
+ error_log('[-] ' . __METHOD__ . ': No fixtures found! :(');
+ }
+ array_walk($files, fn($file) => $this->loadFixture($file));
+ }
+
+ private function loadFixture($file) : void {
+ $table_name = basename($file, '.yml');
+ $this->fixtures[$table_name] = yaml_parse_file($file)[$table_name];
+
+ foreach ($this->fixtures[$table_name] as $entry) {
+ $query = 'INSERT INTO ' . dbesc($table_name) . '('
+ . implode(',', array_keys($entry))
+ . ') VALUES('
+ . implode(',', array_map(fn($val) => "'{$val}'", array_values($entry)))
+ . ')';
+
+ q($query);
+ }
+ }
}
diff --git a/tests/unit/Web/HttpSigTest.php b/tests/unit/Web/HttpSigTest.php
index 5524e0510..0a22b543a 100644
--- a/tests/unit/Web/HttpSigTest.php
+++ b/tests/unit/Web/HttpSigTest.php
@@ -70,9 +70,6 @@ class HttpSigTest extends UnitTestCase {
);
}
- /**
- * @uses ::Crypto::unencapsulate
- */
function testDecrypt_sigheader() {
$header = 'Header: iv="value_iv" key="value_key" alg="value_alg" data="value_data"';
$result = [
@@ -85,9 +82,7 @@ class HttpSigTest extends UnitTestCase {
$this->assertSame($result, HTTPSig::decrypt_sigheader($header, 'site private key'));
}
- /**
- * @uses ::Crypto::unencapsulate
- */
+
function testDecrypt_sigheaderUseSitePrivateKey() {
// Create a stub for global function get_config() with expectation
$t = $this->getFunctionMock('Zotlabs\Web', 'get_config');
diff --git a/tests/unit/includes/AccountTest.php b/tests/unit/includes/AccountTest.php
new file mode 100644
index 000000000..af5bcd3c1
--- /dev/null
+++ b/tests/unit/includes/AccountTest.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Tests for account handling helper functions.
+ */
+
+class AccountTest extends Zotlabs\Tests\Unit\UnitTestCase {
+ public function test_get_account_by_id_returns_existing_account() {
+ $account = get_account_by_id(42);
+ $this->assertNotFalse($account);
+ $this->assertEquals($this->fixtures['account'][0]['account_email'], $account['account_email']);
+ }
+
+ /**
+ * Test the `check_account_email` function.
+ *
+ * @dataProvider check_account_email_provider
+ */
+ public function test_check_account_email(string $email, array $expected) {
+ $this->assertEquals($expected, check_account_email($email));
+ }
+
+ function check_account_email_provider() : array {
+ return [
+ // Empty and valid emails return the same result
+ ['', ['error' => false, 'message' => '']],
+ ['newuser@example.com', ['error' => false, 'message' => '']],
+
+ // Check emails not valid for various readons
+ ['not_an_email', ['error' => true, 'message' => 'The provided email address is not valid']],
+ ['baduser@example.com', ['error' => true, 'message' => 'The provided email domain is not among those allowed on this site']],
+ ['hubzilla@example.com', ['error' => true, 'message' => 'The provided email address is already registered at this site']],
+ ];
+ }
+}
diff --git a/tests/unit/includes/BBCodeTest.php b/tests/unit/includes/BBCodeTest.php
new file mode 100644
index 000000000..fedd2df06
--- /dev/null
+++ b/tests/unit/includes/BBCodeTest.php
@@ -0,0 +1,220 @@
+<?php
+/*
+ * Copyright (c) 2024 Hubzilla
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+namespace Zotlabs\Tests\Unit\includes;
+
+use Zotlabs\Tests\Unit\UnitTestCase;
+
+class BBCodeTest extends UnitTestCase {
+ /**
+ * Test converting BBCode to HTML
+ *
+ * @dataProvider bbcode_to_html_provider
+ */
+ public function test_parsing_bbcode_to_html(string $src, string $expected): void {
+ $this->assertBBCode($expected, $src);
+ }
+
+ /**
+ * Test the `[observer]` BBCode tags.
+ *
+ * @dataProvider bbcode_observer_provider
+ */
+ public function test_bbcode_observer(string $src, bool $logged_in, string $lang, string $expected): void {
+ if ($logged_in) {
+ \App::$observer = [
+ 'xchan_addr' => '',
+ 'xchan_name' => '',
+ 'xchan_connurl' => '',
+ 'xchan_photo_l' => '',
+
+ // port required in xchan url due to bug in get_rpost_path
+ 'xchan_url' => 'https://example.com:666',
+ ];
+ } else {
+ \App::$observer = null;
+ }
+
+ \App::$language = $lang;
+
+ $this->assertBBCode($expected, $src);
+ }
+
+ /**
+ * Test parsing the `[channel]` tag.
+ */
+ public function test_bbcode_channel(): void {
+ $src = '[channel=1]This is only for channels[/channel][channel=0]This is for everyone else[/channel]';
+
+ // Verify that the right part is shown to users _not_ in a channel
+ \App::$channel = null;
+ $this->assertBBCode('This is for everyone else', $src);
+
+ // Now verify that the right part is shown to users _in_ a channel
+ \App::$channel = [42];
+ $this->assertBBCode('This is only for channels', $src);
+ }
+
+ /**
+ * Test converting html to BBCode.
+ *
+ * @dataProvider html2bbcode_provider
+ */
+ public function test_html2bbcode(string $src, string $expected): void {
+ $this->assertEquals($expected, html2bbcode($src));
+ }
+
+ /**
+ * Helper method to validate BBCode conversions.
+ *
+ * @param string $expected The expected result of the conversion.
+ * @param string $src The BBCode to be converted.
+ */
+ private function assertBBCode(string $expected, string $src): void {
+ // Note! We turn off trying to create oembeds, as that will trigger a
+ // network request when running the test.
+ $this->assertEquals($expected, bbcode($src, ['tryoembed' => false]));
+ }
+
+ /**
+ * Dataprovider for test_parsing_bbcode_to_html.
+ *
+ * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
+ */
+ private function bbcode_to_html_provider(): array {
+ return [
+ 'code block' => [
+ "[code]\ntestvar = \"this is a test\"\necho \"the message is \$testvar\"\n[/code]",
+ '<pre><code>testvar = "this is a test"<br />echo "the message is $testvar"</code></pre>',
+ ],
+ 'list with linebreaks \n' => [
+ "some text\n[list]\n[*] item1\n[*] item2\n[/list]\nsome more text",
+ 'some text<br /><ul class="listbullet"><li> item1<li> item2</ul>some more text'
+ ],
+ 'list with linebreaks \r' => [
+ "some text\r[list]\r[*] item1\r[*] item2\r[/list]\rsome more text",
+ 'some text<br /><ul class="listbullet"><li> item1<li> item2</ul>some more text'
+ ],
+ 'list with linebreaks \r\n' => [
+ "some text\r\n[list]\r\n[*] item1\r\n[*] item2\r\n[/list]\r\nsome more text",
+ 'some text<br /><ul class="listbullet"><li> item1<li> item2</ul>some more text'
+ ]
+ ];
+ }
+
+ /**
+ * Dataprovider for test_bbcode_observer
+ *
+ * @returns an array of arrays with the following fields:
+ * * `string $src` - The source string to convert
+ * * `bool $logged_in` - Whether we should test with a logged in user
+ * * `string $lang` - The language code of the simulated user
+ * * `string $expected` - The expecte result of the conversion.
+ *
+ * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
+ */
+ private function bbcode_observer_provider(): array {
+ return [
+ 'authenticated observer' => [
+ '[observer=1]This should be visible[/observer][observer=0]but not this[/observer]',
+ true,
+ 'en',
+ 'This should be visible',
+ ],
+ 'unauthenticated observer' => [
+ '[observer=1]This should not be visible[/observer][observer=0]but this should be![/observer]',
+ false,
+ 'en',
+ 'but this should be!',
+ ],
+ 'authenticated observer.language matching' => [
+ '[observer.language=nb]Kun på norsk[/observer][observer.language!=nb]To everybody else[/observer]',
+ true,
+ 'nb',
+ 'Kun på norsk',
+ ],
+ 'authenticated observer.language no match' => [
+ '[observer.language=nb]Kun på norsk[/observer][observer.language!=nb]To everybody else[/observer]',
+ true,
+ 'en',
+ 'To everybody else',
+ ],
+ 'multiple observer blocks' => [
+ '[observer=1]This should be visible,[/observer][observer=0] but not this,[/observer][observer=1] and this as well.[/observer]',
+ true,
+ 'en',
+ 'This should be visible, and this as well.',
+ ],
+ 'authenticated observer rpost' => [
+ '[rpost=a title]This is the body[/rpost]',
+ true,
+ 'en',
+ '<a href="https://example.com:666/rpost?f=&title=a+title&body=This+is+the+body" target="_blank" rel="nofollow noopener">https://example.com:666/rpost?f=&title=a+title&body=This+is+the+body</a>',
+ ],
+ 'unauthenticated observer rpost' => [
+ '[rpost=a title]This is the body[/rpost]',
+ false,
+ 'en',
+ '',
+ ],
+ ];
+ }
+
+ /**
+ * Dataprovider for test_html2bbcode.
+ *
+ * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
+ */
+ private function html2bbcode_provider(): array {
+ return [
+ 'paragraph over multiple lines' => [
+ "<p>A paragraph over\nmultiple lines\nshould be unwrapped</p>",
+ 'A paragraph over multiple lines should be unwrapped'
+ ],
+ 'image with alt text' => [
+ '<img src="https://example.com/image.jpg" alt="Alt text">',
+ '[img=https://example.com/image.jpg]Alt text[/img]'
+ ],
+ 'code block' => [
+ "<pre><code>some\ncode</code></pre>",
+ "[code]some\ncode[/code]"
+ ],
+ 'code block with indentation' => [
+ "<pre><code>some\n indented\ncode</code></pre>",
+ "[code]some\n indented\ncode[/code]"
+ ],
+ 'paragraph with a mention and some text' => [
+ '<p><span class="h-card" translate="no"><a href="https://example.org/@profile" class="u-url mention">@<span>profile</span></a></span> some content</p>',
+ '[url=https://example.org/@profile]@profile[/url] some content'
+ ],
+ 'nested tags with ampersand and new line' => [
+ "<b>\n<i>foo & bar</i></b>",
+ '[b] [i]foo &amp; bar[/i][/b]'
+ ],
+ 'html reshares from streams' => [
+ '<div><div><a href="https://example.com"><img src="https://example.com/image.jpg" alt="image/photo"></a> shared something</div>something</div>',
+ '[url=https://example.com][img=https://example.com/image.jpg]image/photo[/img][/url] shared something' . "\n" . 'something'
+ ]
+ ];
+ }
+}
diff --git a/tests/unit/includes/MarkdownTest.php b/tests/unit/includes/MarkdownTest.php
index 953305074..960c15139 100644
--- a/tests/unit/includes/MarkdownTest.php
+++ b/tests/unit/includes/MarkdownTest.php
@@ -1,30 +1,29 @@
<?php
/*
* Copyright (c) 2017 Hubzilla
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy
-* of this software and associated documentation files (the "Software"), to deal
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the Software is
-* furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-* SOFTWARE.
-*/
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
namespace Zotlabs\Tests\Unit\includes;
use Zotlabs\Tests\Unit\UnitTestCase;
-use phpmock\phpunit\PHPMock;
require_once 'include/markdown.php';
@@ -32,17 +31,80 @@ require_once 'include/markdown.php';
* @brief Unit Test case for markdown functions.
*/
class MarkdownTest extends UnitTestCase {
- use PHPMock;
+
+ /**
+ * @dataProvider markdown_to_bbcode_provider
+ */
+ public function test_markdown_to_bbcode(string $expected, string $src): void {
+ $this->assertEquals($expected, markdown_to_bb($src));
+ }
+
+ private function markdown_to_bbcode_provider(): array {
+ return [
+ 'empty text' => [
+ '',
+ ''
+ ],
+ 'plain text' => [
+ 'This is a test',
+ 'This is a test'
+ ],
+ 'bold and italic' => [
+ 'This is a test of [b]bold text[/b], [i]italic text[/i] and [b][i]bold and italic text[/i][/b]',
+ 'This is a test of **bold text**, *italic text* and ***bold and italic text***'
+ ],
+ 'multiline text' => [
+ 'This text is text wrapped over multiple lines.',
+ "This text is\ntext wrapped\nover multiple\nlines."
+ ],
+ 'text with hard linebreak' => [
+ "Line one\nLine two",
+ "Line one \nLine two"
+ ],
+ 'paragraphs' => [
+ "Paragraph one\n\nParagraph two",
+ "Paragraph one\n\nParagraph two",
+ ],
+ 'inline image' => [
+ '[img=https://example.com/image.jpg]https://example.com/image.jpg[/img]',
+ '![](https://example.com/image.jpg)'
+ ],
+ 'inline image with alt text' => [
+ '[img=https://example.com/image.jpg]Alt text[/img]',
+ '![Alt text](https://example.com/image.jpg)'
+ ],
+ 'inline code' => [
+ '[code]some code[/code]',
+ '`some code`'
+ ],
+ 'inline code with wrapped text' => [
+ '[code]some code unwrapped[/code]',
+ "`some code\n unwrapped`"
+ ],
+ 'code block no language' => [
+ "[code]some code\nover multiple lines[/code]",
+ "```\nsome code\nover multiple lines\n```"
+ ],
+ 'code block no language indented' => [
+ "[code]some code\n over multiple lines\n with indentation[/code]",
+ "```\nsome code\n over multiple lines\n with indentation\n```"
+ ],
+ 'code block with language' => [
+ "[code=php]&lt;?php\necho phpinfo();[/code]",
+ "```php\n<?php\necho phpinfo();\n```"
+ ],
+ ];
+ }
/**
* @covers ::html2markdown
* @dataProvider html2markdownProvider
*/
- public function testHtml2markdown($html, $markdown) {
+ public function testHtml2markdown(string $html, string $markdown): void {
$this->assertEquals($markdown, html2markdown($html));
}
- public function html2markdownProvider() {
+ public function html2markdownProvider(): array {
return [
'empty text' => [
'',
@@ -125,23 +187,10 @@ class MarkdownTest extends UnitTestCase {
];
}
- /*public function testHtml2markdownException() {
- //$this->expectException(\InvalidArgumentException::class);
- // need to stub logger() for this to work
- $this->assertEquals('', html2markdown('<<invalid'));
- }*/
-
-/* public function testBB2diasporaMardown() {
- //stub bbcode() and return our HTML, we just need to test the HTML2Markdown library.
- $html1 = 'test<b>bold</b><br><i>i</i><ul><li>li1</li><li>li2</li></ul><br>';
- $bb1 = 'test';
-
- // php-mock can not mock global functions which is called by a global function.
- // If the calling function is in a namespace it does work.
- $bbc = $this->getFunctionMock(__NAMESPACE__, "bbcode");
- $bbc->expects($this->once())->willReturn('test<b>bold</b><br><i>i</i><ul><li>li1</li><li>li2</li></ul><br>');
+ public function test_bb_to_markdown(): void {
+ $input = "test[b]bold[/b]\n[i]i[/i][ul][li]li1[/li][li]li2[/li][/ul]\n";
+ $expected = "test**bold** \n*i*\n\n- li1\n- li2";
- $this->assertEquals($bb1, bb2diaspora($html1));
+ $this->assertEquals($expected, bb_to_markdown($input));
}
-*/
}
diff --git a/tests/unit/includes/NetworkTest.php b/tests/unit/includes/NetworkTest.php
index 0b9b42e00..9fb00e9d3 100644
--- a/tests/unit/includes/NetworkTest.php
+++ b/tests/unit/includes/NetworkTest.php
@@ -5,29 +5,68 @@
* @package test.util
*/
-use PHPUnit\Framework\TestCase;
-
-require_once('include/network.php');
-
-class NetworkTest extends TestCase {
-
- public function setup() : void {
- \App::set_baseurl("https://mytest.org");
- }
-
- /**
- * @dataProvider localUrlTestProvider
- */
- public function testIsLocalURL($url, $expected) {
- $this->assertEquals($expected, is_local_url($url));
- }
-
- public function localUrlTestProvider() : array {
- return [
- [ '/some/path', true ],
- [ 'https://mytest.org/some/path', true ],
- [ 'https://other.site/some/path', false ],
- ];
- }
-}
+class NetworkTest extends Zotlabs\Tests\Unit\UnitTestCase {
+
+ public function setUp() : void {
+ parent::setUp();
+
+ \App::set_baseurl("https://mytest.org");
+ }
+
+ /**
+ * @dataProvider localUrlTestProvider
+ */
+ public function testIsLocalURL($url, $expected) {
+ $this->assertEquals($expected, is_local_url($url));
+ }
+
+ public function localUrlTestProvider() : array {
+ return [
+ [ '/some/path', true ],
+ [ 'https://mytest.org/some/path', true ],
+ [ 'https://other.site/some/path', false ],
+ ];
+ }
+
+ /**
+ * Test the validate_email function.
+ *
+ * @dataProvider validate_email_provider
+ */
+ public function test_validate_email(string $email, bool $expected) : void {
+ $this->assertEquals($expected, validate_email($email));
+ }
+ /**
+ * Test that the validate_email function is disabled when configured to.
+ *
+ * @dataProvider validate_email_provider
+ */
+ public function test_disable_validate_email(string $email) : void {
+ \Zotlabs\Lib\Config::Set('system', 'disable_email_validation', true);
+ $this->assertTrue(validate_email($email));
+ }
+
+ function validate_email_provider() : array {
+ return [
+ // First some invalid email addresses
+ ['', false],
+ ['not_an_email', false],
+ ['@not_an_email', false],
+ ['not@an@email', false],
+ ['not@an@email.com', false],
+
+ // then test valid addresses too
+ ['test@example.com', true],
+
+ // Should also work with international domains
+ ['some.email@dømain.net', true],
+
+ // Should also work with the new top-level domains
+ ['some.email@example.cancerresearch', true],
+
+ // And internationalized TLD's
+ ['some.email@example.شبكة', true]
+ ];
+ }
+}
diff --git a/tests/unit/includes/PhotodriverTest.php b/tests/unit/includes/PhotodriverTest.php
index 6f6ad0ffe..34dc058b7 100644
--- a/tests/unit/includes/PhotodriverTest.php
+++ b/tests/unit/includes/PhotodriverTest.php
@@ -2,38 +2,22 @@
namespace Zotlabs\Tests\Unit\includes;
-//use Zotlabs\Photo\PhotoGd;
use Zotlabs\Tests\Unit\UnitTestCase;
-//use phpmock\phpunit\PHPMock;
/**
* @brief Unit Test cases for include/photo/photo_driver.php file.
*/
class PhotodriverTest extends UnitTestCase {
- //use PHPMock;
public function testPhotofactoryReturnsNullForUnsupportedType() {
- // php-mock can not mock global functions which is called by a global function.
- // If the calling function is in a namespace it would work.
- //$logger = $this->getFunctionMock(__NAMESPACE__, 'logger');
- //$logger->expects($this->once());
-
- //$ph = \photo_factory('', 'image/bmp');
- //$this->assertNull($ph);
-
- $this->markTestIncomplete('Need to mock logger(), otherwise not unit testable.');
+ $photo = \photo_factory('', 'image/bmp');
+ $this->assertNull($photo);
}
public function testPhotofactoryReturnsPhotogdIfConfigIgnore_imagickIsSet() {
- // php-mock can not mock global functions which is called by a global function.
- // If the calling function is in a namespace it would work.
- //$gc = $this->getFunctionMock(__NAMESPACE__, 'get_config');
- // simulate get_config('system', 'ignore_imagick') configured
- //$gc->expects($this->once())->willReturn(1)
-
- //$ph = \photo_factory(file_get_contents('images/hz-16.png'), 'image/png');
- //$this->assertInstanceOf(PhotoGd::class, $ph);
+ \Zotlabs\Lib\Config::Set('system', 'ignore_imagick', true);
- $this->markTestIncomplete('Need to mock get_config(), otherwise not unit testable.');
+ $photo = \photo_factory(file_get_contents('images/hz-16.png'), 'image/png');
+ $this->assertInstanceOf('Zotlabs\Photo\PhotoGd', $photo);
}
-} \ No newline at end of file
+}
diff --git a/tests/unit/includes/TextTest.php b/tests/unit/includes/TextTest.php
index 97fa64895..b76b15dcf 100644
--- a/tests/unit/includes/TextTest.php
+++ b/tests/unit/includes/TextTest.php
@@ -30,7 +30,7 @@ empty line above';
$this->assertEquals('Your HTML parser does not support HTML5 audio.', purify_html('<audio controls><source src="movie.ogg" "type="audio/ogg">Your HTML parser does not support HTML5 audio.</audio>'));
// preserve f6 and bootstrap additional data attributes from our own configuration
- $this->assertEquals('<div data-title="title">text</div>', purify_html('<div data-title="title">text</div>'));
+ $this->assertEquals('<div data-bs-title="title">text</div>', purify_html('<div data-bs-title="title">text</div>'));
$this->assertEquals('<ul data-accordion-menu=""><li>item1</li></ul>', purify_html('<ul data-accordion-menu><li>item1</li></ul>'));
$this->assertEquals('<ul><li>item1</li></ul>', purify_html('<ul data-accordion-menu-unknown><li>item1</li></ul>'));
}
diff --git a/tests/unit/includes/dba/TransactionTest.php b/tests/unit/includes/dba/TransactionTest.php
new file mode 100644
index 000000000..99e3f459d
--- /dev/null
+++ b/tests/unit/includes/dba/TransactionTest.php
@@ -0,0 +1,207 @@
+<?php
+/*
+ * Copyright (c) 2024 Hubzilla
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+require_once 'tests/fakes/fake_dba.php';
+require_once 'include/dba/dba_transaction.php';
+
+use \PHPUnit\Framework\TestCase;
+use \Zotlabs\Tests\Fakes\FakeDba;
+
+/**
+ * Test database transactions.
+ *
+ * This class subclass the base PHPUnit TestCase class, since we do _not_
+ * want a real database connection for these tests. We're testing functionality
+ * of the database adapter itself, so we choose to stub the underlying db driver
+ * to be able to assert that the adapter behaves as it should.
+ */
+class DbaTransactionTest extends TestCase {
+ private $pdo_stub;
+
+ public function setUp(): void {
+ $this->pdo_stub = $this->createStub(PDO::class);
+ }
+
+
+ /**
+ * Test that creating a DbaTransaction object initiates a database transaction.
+ *
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+ */
+ public function test_transaction_initialized_on_construction(): void {
+ // Stub PDO::inTransaction()
+ // Expect that it's called once, and return false to simulate that no
+ // transactions are active.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('inTransaction')
+ ->willReturn(false);
+
+ // Stub PDO::beginTransaction to ensure that it is being called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('beginTransaction')
+ ->willReturn(true);
+
+ $dba = new FakeDba($this->pdo_stub);
+
+ $transaction = new DbaTransaction($dba);
+ }
+
+ /**
+ * Test that a transaction is rolled back when the DbaTransaction object
+ * is destroyed.
+ *
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+ */
+ public function test_uncommitted_transaction_is_rolled_back_on_destruction(): void {
+ // Stub PDO::inTransaction()
+ // Expect that it's called once, and return false to simulate that no
+ // transactions are active.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('inTransaction')
+ ->willReturn(false);
+
+ // Stub PDO::beginTransaction to ensure that it is being called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('beginTransaction')
+ ->willReturn(true);
+
+ // Stub PDO::rollBack to make sure we test it is being called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('rollBack')
+ ->willReturn(true);
+
+ $dba = new FakeDba($this->pdo_stub);
+
+ $transaction = new DbaTransaction($dba);
+ }
+
+ /**
+ * Test that a committed transaction is not rolled back when the
+ * DbaTransaction object goes out of scope.
+ */
+ public function test_committed_transaction_is_not_rolled_back(): void {
+ // Stub PDO::inTransaction()
+ // Return false to simulate that no transaction is active when called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('inTransaction')
+ ->willReturn(false);
+
+ // Stub PDO::beginTransaction to ensure that it is being called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('beginTransaction')
+ ->willReturn(true);
+
+ // Stub PDO::rollBack to ensure it is _not_ called
+ $this->pdo_stub
+ ->expects($this->never())
+ ->method('rollBack');
+
+ // Stub PDO::commit to make the test check that it is being called
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('commit')
+ ->willReturn(true);
+
+ $dba = new FakeDba($this->pdo_stub);
+
+ $transaction = new DbaTransaction($dba);
+ $transaction->commit();
+ }
+
+ /**
+ * Test that commiting a transaction more than once is a no-op.
+ */
+ public function test_that_committing_an_already_committed_transaction_does_nothing(): void {
+ // Stub PDO::inTransaction()
+ // Return false to simulate that no transaction is active when called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('inTransaction')
+ ->willReturn(false);
+
+ // Stub PDO::beginTransaction to ensure that it is being called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('beginTransaction')
+ ->willReturn(true);
+
+ // Stub PDO::rollBack to ensure it is _not_ called
+ $this->pdo_stub
+ ->expects($this->never())
+ ->method('rollBack');
+
+ // Stub PDO::commit to make the test check that it is being called
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('commit')
+ ->willReturn(true);
+
+ $dba = new FakeDba($this->pdo_stub);
+
+ $transaction = new DbaTransaction($dba);
+ $transaction->commit();
+ $transaction->commit();
+ }
+
+ /**
+ * Test simulating constructing a DbaTransaction object when a transaction
+ * is already active.
+ *
+ * This should _not_ initiate an actual DB transaction, not call the rollBack
+ * method on destruction.
+ *
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+ */
+ public function test_that_nesting_a_transaction_does_not_create_a_new_transaction_in_db(): void {
+ // Stub PDO::inTransaction()
+ // We simulate that a transaction is already active, by returning true from
+ // this method.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('inTransaction')
+ ->willReturn(true);
+
+ // Stub PDO::beginTransaction
+ // Since a transaction is already active, we should _not_ initiate
+ // a new transaction when the DbaTransaction object is constructed.
+ $this->pdo_stub
+ ->expects($this->never())
+ ->method('beginTransaction');
+
+ // Stub PDO::rollBack to ensure it is _not_ called
+ $this->pdo_stub
+ ->expects($this->never())
+ ->method('rollBack');
+
+ $dba = new FakeDba($this->pdo_stub);
+
+ $transaction = new DbaTransaction($dba);
+ }
+}
diff --git a/tests/unit/includes/dba/_files/config.yml b/tests/unit/includes/dba/_files/config.yml
new file mode 100644
index 000000000..e93486857
--- /dev/null
+++ b/tests/unit/includes/dba/_files/config.yml
@@ -0,0 +1,23 @@
+---
+config:
+ -
+ cat: system
+ k: do_not_check_dns
+ v: true
+ -
+ cat: system
+ k: not_allowed_email
+ v: 'baduser@example.com,baddomain.com,*.evil.org'
+ -
+ cat: system
+ k: debugging
+ v: true
+ -
+ cat: system
+ k: loglevel
+ v: 2
+ -
+ cat: system
+ k: logfile
+ v: tests/results/unit_test.log
+