aboutsummaryrefslogtreecommitdiffstats
path: root/tests/unit/includes
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/includes')
-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
8 files changed, 644 insertions, 88 deletions
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
+