diff options
Diffstat (limited to 'tests/unit/includes')
-rw-r--r-- | tests/unit/includes/AccountTest.php | 34 | ||||
-rw-r--r-- | tests/unit/includes/BBCodeTest.php | 220 | ||||
-rw-r--r-- | tests/unit/includes/MarkdownTest.php | 129 | ||||
-rw-r--r-- | tests/unit/includes/NetworkTest.php | 89 | ||||
-rw-r--r-- | tests/unit/includes/PhotodriverTest.php | 28 | ||||
-rw-r--r-- | tests/unit/includes/TextTest.php | 2 | ||||
-rw-r--r-- | tests/unit/includes/dba/TransactionTest.php | 207 | ||||
-rw-r--r-- | tests/unit/includes/dba/_files/config.yml | 23 |
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 & 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]<?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 + |