Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 178
0.00% covered (danger)
0.00%
0 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
phpbb_functional_posting_test
0.00% covered (danger)
0.00%
0 / 178
0.00% covered (danger)
0.00%
0 / 16
420
0.00% covered (danger)
0.00%
0 / 1
 test_post_new_topic
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 test_unsupported_characters
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 test_supported_unicode_characters
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 test_html_entities
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 test_quote
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 test_edit
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 test_quote_depth_form
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
6
 test_quote_depth_submit
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
20
 test_post_poll
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 set_quote_depth
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 test_ticket_8420
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 test_old_signature_in_preview
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
2
 test_www_links_preview
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
 test_allowed_schemes_links
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
2
 nonexistent_post_id_data
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 test_nonexistent_post_id
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14/**
15* @group functional
16*/
17class phpbb_functional_posting_test extends phpbb_functional_test_case
18{
19    public function test_post_new_topic()
20    {
21        $this->login();
22
23        // Test creating topic
24        $post = $this->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.');
25
26        $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}");
27        $this->assertStringContainsString('This is a test topic posted by the testing framework.', $crawler->filter('html')->text());
28
29        // Test creating a reply with bbcode
30        $post2 = $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', 'This is a test [b]post[/b] posted by the testing framework.');
31
32        $crawler = self::request('GET', "viewtopic.php?p={$post2['post_id']}&sid={$this->sid}");
33        $this->assertStringContainsString('This is a test post posted by the testing framework.', $crawler->filter('html')->text());
34
35        // Test quoting a message
36        $crawler = self::request('GET', "posting.php?mode=quote&p={$post2['post_id']}&sid={$this->sid}");
37        $this->assertStringContainsString('This is a test post posted by the testing framework.', $crawler->filter('html')->text());
38    }
39
40    public function test_unsupported_characters()
41    {
42        $this->login();
43
44        $post = $this->create_topic(2, "Test Topic \xF0\x9F\xA4\x94 3\xF0\x9D\x94\xBB\xF0\x9D\x95\x9A", 'This is a test with emoji character in the topic title.');
45        $this->create_post(2, $post['topic_id'], "Re: Test Topic 1 \xF0\x9F\xA4\x94 3\xF0\x9D\x94\xBB\xF0\x9D\x95\x9A", 'This is a test with emoji characters in the topic title.');
46        $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}");
47        $this->assertStringContainsString("\xF0\x9F\xA4\x94 3\xF0\x9D\x94\xBB\xF0\x9D\x95\x9A", $crawler->text());
48    }
49
50    public function test_supported_unicode_characters()
51    {
52        $this->login();
53
54        $post = $this->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.');
55        $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', "This is a test with these weird characters: \xF0\x9F\x84\x90 \xF0\x9F\x84\x91");
56        $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}");
57        $this->assertStringContainsString("\xF0\x9F\x84\x90 \xF0\x9F\x84\x91", $crawler->text());
58    }
59
60    public function test_html_entities()
61    {
62        $this->login();
63
64        $post = $this->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.');
65        $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', '&#128512;');
66        $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}");
67        $this->assertStringContainsString('&#128512;', $crawler->text());
68    }
69
70    public function test_quote()
71    {
72        $text     = 'Test post </textarea>"\' &&amp;amp;';
73        $expected = "(\[quote=admin[^\]]*\]\s?" . preg_quote($text) . "\s?\[\/quote\])";
74
75        $this->login();
76        $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic');
77        $post  = $this->create_post(2, $topic['topic_id'], 'Re: Test Topic 1', $text);
78
79        $crawler = self::request('GET', "posting.php?mode=quote&p={$post['post_id']}&sid={$this->sid}");
80
81        $this->assertMatchesRegularExpression($expected, $crawler->filter('textarea#message')->text());
82    }
83
84    /**
85     * @see https://tracker.phpbb.com/browse/PHPBB3-14962
86     */
87    public function test_edit()
88    {
89        $this->login();
90        $this->create_topic(2, 'Test Topic post', 'Test topic post');
91
92        $url =  self::$client->getCrawler()->selectLink('Edit')->link()->getUri();
93        $post_id = $this->get_parameter_from_link($url, 'p');
94        $crawler = self::request('GET', "posting.php?mode=edit&p={$post_id}&sid={$this->sid}");
95        $form = $crawler->selectButton('Submit')->form();
96        $form->setValues(array('message' => 'Edited post'));
97        $crawler = self::submit($form);
98
99        $this->assertStringContainsString('Edited post', $crawler->filter("#post_content{$post_id} .content")->text());
100    }
101
102    /**
103    * @testdox max_quote_depth is applied to the text populating the posting form
104    */
105    public function test_quote_depth_form()
106    {
107        $text = '0[quote]1[quote]2[/quote]1[/quote]0';
108        $expected = array(
109            0 => '0[quote]1[quote]2[/quote]1[/quote]0',
110            1 => '00',
111            2 => '0[quote]11[/quote]0',
112            3 => '0[quote]1[quote]2[/quote]1[/quote]0',
113        );
114
115        $this->login();
116        $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic');
117        $post  = $this->create_post(2, $topic['topic_id'], 'Re: Test Topic 1', $text);
118        $quote_url = "posting.php?mode=quote&p={$post['post_id']}&sid={$this->sid}";
119
120        $this->admin_login();
121        foreach ($expected as $quote_depth => $expected_text)
122        {
123            $this->set_quote_depth($quote_depth);
124            $crawler = self::request('GET', $quote_url);
125            $this->assertMatchesRegularExpression(
126                "(\[quote=admin[^\]]*\]\s?" . preg_quote($expected_text) . "\s?\[\/quote\])",
127                $crawler->filter('textarea#message')->text()
128            );
129        }
130    }
131
132    /**
133    * @testdox max_quote_depth is applied to the submitted text
134    */
135    public function test_quote_depth_submit()
136    {
137        $text = 'depth:0[quote]depth:1[quote]depth:2[quote]depth:3[/quote][/quote][/quote]';
138        $contains = array(
139            0 => array('depth:0', 'depth:1', 'depth:2', 'depth:3'),
140            1 => array('depth:0', 'depth:1'),
141            2 => array('depth:0', 'depth:1', 'depth:2'),
142            3 => array('depth:0', 'depth:1', 'depth:2', 'depth:3'),
143        );
144        $not_contains = array(
145            0 => array(),
146            1 => array('depth:2', 'depth:3'),
147            2 => array('depth:3'),
148            3 => array(),
149        );
150
151        $this->login();
152        $this->admin_login();
153        $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic');
154
155        for ($quote_depth = 0; $quote_depth <= 2; ++$quote_depth)
156        {
157            $this->set_quote_depth($quote_depth);
158
159            $post = $this->create_post(2, $topic['topic_id'], "Re: Test Topic 1#$quote_depth", $text);
160            $url  = "viewtopic.php?p={$post['post_id']}&sid={$this->sid}";
161
162            $crawler = self::request('GET', $url);
163            $text_content = $crawler->filter('#p' . $post['post_id'])->text();
164            foreach ($contains[$quote_depth] as $contains_text)
165            {
166                $this->assertStringContainsString($contains_text, $text_content);
167            }
168            foreach ($not_contains[$quote_depth] as $not_contains_text)
169            {
170                $this->assertStringNotContainsString($not_contains_text, $text_content);
171            }
172        }
173    }
174
175    public function test_post_poll()
176    {
177        $this->login();
178
179        $post = $this->create_topic(
180            2,
181            '[ticket/14802] Test Poll Option Spacing',
182            'Empty/blank lines should not be additional poll options.',
183            array('poll_title' => 'Poll Title', 'poll_option_text' => "\n A \nB\n\nC \n D\nE\n\n \n")
184        );
185
186        $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}");
187        $this->assertEquals('Poll Title', $crawler->filter('.poll-title')->text());
188        $this->assertEquals(5, $crawler->filter('*[data-poll-option-id]')->count());
189    }
190
191    protected function set_quote_depth($depth)
192    {
193        $crawler = self::request('GET', 'adm/index.php?sid=' . $this->sid . '&i=acp_board&mode=post');
194        $form = $crawler->selectButton('Submit')->form();
195        $values = $form->getValues();
196        $values['config[max_quote_depth]'] = $depth;
197        $form->setValues($values);
198        $crawler = self::submit($form);
199        $this->assertEquals(1, $crawler->filter('.successbox')->count());
200    }
201
202    public function test_ticket_8420()
203    {
204        $text = '[b][url=http://example.org] :arrow: here[/url][/b]';
205
206        $this->login();
207        $crawler = self::request('GET', 'posting.php?mode=post&f=2');
208        $form = $crawler->selectButton('Preview')->form(array(
209            'subject' => 'Test subject',
210            'message' => $text
211        ));
212        $crawler = self::submit($form);
213        $this->assertEquals($text, $crawler->filter('#message')->text());
214    }
215
216    public function test_old_signature_in_preview()
217    {
218        $sql = 'UPDATE ' . USERS_TABLE . "
219            SET user_sig = '[b:2u8sdcwb]My signature[/b:2u8sdcwb]',
220                user_sig_bbcode_uid = '2u8sdcwb',
221                user_sig_bbcode_bitfield = 'QA=='
222            WHERE user_id = 2";
223        $this->get_db()->sql_query($sql);
224
225        $this->login();
226        $crawler = self::request('GET', 'posting.php?mode=post&f=2');
227        $form = $crawler->selectButton('Preview')->form(array(
228            'subject' => 'Test subject',
229            'message' => 'My post',
230        ));
231        $crawler = self::submit($form);
232        $this->assertStringContainsString(
233            '<strong class="text-strong">My signature</strong>',
234            $crawler->filter('#preview .signature')->html()
235        );
236    }
237
238    /**
239    * @ticket PHPBB3-10628
240    */
241    public function test_www_links_preview()
242    {
243        $text = 'www.example.org';
244        $url  = 'http://' . $text;
245
246        $this->add_lang('posting');
247        $this->login();
248
249        $crawler = self::request('GET', 'posting.php?mode=post&f=2');
250        $form = $crawler->selectButton('Preview')->form(array(
251            'subject' => 'Test subject',
252            'message' => $text
253        ));
254        $crawler = self::submit($form);
255
256        // Test that the textarea remains unchanged
257        $this->assertEquals($text, $crawler->filter('#message')->text());
258
259        // Test that the preview contains the correct link
260        $this->assertEquals($url, $crawler->filter('#preview a')->attr('href'));
261    }
262
263    public function test_allowed_schemes_links()
264    {
265        $text = 'http://example.org/ tcp://localhost:22/ServiceName';
266
267        $this->login();
268        $this->admin_login();
269
270        // Post with default settings
271        $crawler = self::request('GET', 'posting.php?mode=post&f=2');
272        $form = $crawler->selectButton('Preview')->form(array(
273            'subject' => 'Test subject',
274            'message' => $text,
275        ));
276        $crawler = self::submit($form);
277        $this->assertStringContainsString(
278            '<a href="http://example.org/" class="postlink">http://example.org/</a> tcp://localhost:22/ServiceName',
279            $crawler->filter('#preview .content')->html()
280        );
281
282        // Update allowed schemes
283        $crawler = self::request('GET', 'adm/index.php?sid=' . $this->sid . '&i=acp_board&mode=post');
284        $form = $crawler->selectButton('Submit')->form();
285        $values = $form->getValues();
286        $values['config[allowed_schemes_links]'] = 'https,tcp';
287        $form->setValues($values);
288        $crawler = self::submit($form);
289        $this->assertEquals(1, $crawler->filter('.successbox')->count());
290
291        // Post with new settings
292        $crawler = self::request('GET', 'posting.php?mode=post&f=2');
293        $form = $crawler->selectButton('Preview')->form(array(
294            'subject' => 'Test subject',
295            'message' => $text,
296        ));
297        $crawler = self::submit($form);
298        $this->assertStringContainsString(
299            'http://example.org/ <a href="tcp://localhost:22/ServiceName" class="postlink">tcp://localhost:22/ServiceName</a>',
300            $crawler->filter('#preview .content')->html()
301        );
302    }
303
304    public static function nonexistent_post_id_data()
305    {
306        $nonexistent_post_id = 999999; // Random value
307        return [
308            ['edit', $nonexistent_post_id],
309            ['delete', $nonexistent_post_id],
310            ['quote', $nonexistent_post_id],
311            ['soft_delete', $nonexistent_post_id],
312        ];
313    }
314
315    /**
316     * @dataProvider nonexistent_post_id_data
317     */
318    public function test_nonexistent_post_id($mode, $nonexistent_post_id)
319    {
320        $this->add_lang('posting');
321        $this->login();
322        $crawler = self::request('GET', "posting.php?mode={$mode}&p={$nonexistent_post_id}&sid={$this->sid}");
323        $this->assertContainsLang('NO_POST', $crawler->text());
324    }
325}