Translated using Weblate (Portuguese)
[phpmyadmin.git] / tests / unit / Plugins / Export / ExportHtmlwordTest.php
blobe05b19d398f083f4b59a1ca48088d9816d4cfcf9
1 <?php
3 declare(strict_types=1);
5 namespace PhpMyAdmin\Tests\Plugins\Export;
7 use PhpMyAdmin\Column;
8 use PhpMyAdmin\Config;
9 use PhpMyAdmin\ConfigStorage\Relation;
10 use PhpMyAdmin\ConfigStorage\RelationParameters;
11 use PhpMyAdmin\Current;
12 use PhpMyAdmin\Dbal\DatabaseInterface;
13 use PhpMyAdmin\Export\Export;
14 use PhpMyAdmin\Http\Factory\ServerRequestFactory;
15 use PhpMyAdmin\Identifiers\TableName;
16 use PhpMyAdmin\Identifiers\TriggerName;
17 use PhpMyAdmin\Plugins\Export\ExportHtmlword;
18 use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
19 use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
20 use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
21 use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
22 use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
23 use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
24 use PhpMyAdmin\Tests\AbstractTestCase;
25 use PhpMyAdmin\Tests\Stubs\DbiDummy;
26 use PhpMyAdmin\Tests\Stubs\DummyResult;
27 use PhpMyAdmin\Transformations;
28 use PhpMyAdmin\Triggers\Event;
29 use PhpMyAdmin\Triggers\Timing;
30 use PhpMyAdmin\Triggers\Trigger;
31 use PHPUnit\Framework\Attributes\CoversClass;
32 use PHPUnit\Framework\Attributes\Medium;
33 use ReflectionMethod;
34 use ReflectionProperty;
36 use function __;
37 use function ob_get_clean;
38 use function ob_start;
40 #[CoversClass(ExportHtmlword::class)]
41 #[Medium]
42 class ExportHtmlwordTest extends AbstractTestCase
44 protected DatabaseInterface $dbi;
46 protected DbiDummy $dummyDbi;
48 protected ExportHtmlword $object;
50 /**
51 * Configures global environment.
53 protected function setUp(): void
55 parent::setUp();
57 $this->dummyDbi = $this->createDbiDummy();
58 $this->dbi = $this->createDatabaseInterface($this->dummyDbi);
59 DatabaseInterface::$instance = $this->dbi;
60 $this->object = new ExportHtmlword(
61 new Relation($this->dbi),
62 new Export($this->dbi),
63 new Transformations(),
65 Export::$outputKanjiConversion = false;
66 Export::$outputCharsetConversion = false;
67 Export::$bufferNeeded = false;
68 Export::$asFile = true;
69 Export::$saveOnServer = false;
70 Current::$database = '';
71 Current::$table = '';
72 Current::$lang = '';
73 Config::getInstance()->selectedServer['DisableIS'] = true;
76 /**
77 * tearDown for test cases
79 protected function tearDown(): void
81 parent::tearDown();
83 unset($this->object);
86 public function testSetProperties(): void
88 $method = new ReflectionMethod(ExportHtmlword::class, 'setProperties');
89 $method->invoke($this->object, null);
91 $attrProperties = new ReflectionProperty(ExportHtmlword::class, 'properties');
92 $properties = $attrProperties->getValue($this->object);
94 self::assertInstanceOf(ExportPluginProperties::class, $properties);
96 self::assertSame(
97 'Microsoft Word 2000',
98 $properties->getText(),
101 self::assertSame(
102 'doc',
103 $properties->getExtension(),
106 self::assertSame(
107 'application/vnd.ms-word',
108 $properties->getMimeType(),
111 self::assertSame(
112 'Options',
113 $properties->getOptionsText(),
116 self::assertTrue(
117 $properties->getForceFile(),
120 $options = $properties->getOptions();
122 self::assertInstanceOf(OptionsPropertyRootGroup::class, $options);
124 self::assertSame(
125 'Format Specific Options',
126 $options->getName(),
129 $generalOptionsArray = $options->getProperties();
130 $generalOptions = $generalOptionsArray->current();
131 $generalOptionsArray->next();
133 self::assertInstanceOf(OptionsPropertyMainGroup::class, $generalOptions);
135 self::assertSame(
136 'dump_what',
137 $generalOptions->getName(),
140 self::assertSame(
141 'Dump table',
142 $generalOptions->getText(),
145 $generalProperties = $generalOptions->getProperties();
147 $property = $generalProperties->current();
149 self::assertInstanceOf(RadioPropertyItem::class, $property);
151 self::assertSame(
152 'structure_or_data',
153 $property->getName(),
156 self::assertSame(
157 ['structure' => __('structure'), 'data' => __('data'), 'structure_and_data' => __('structure and data')],
158 $property->getValues(),
161 $generalOptions = $generalOptionsArray->current();
163 self::assertInstanceOf(OptionsPropertyMainGroup::class, $generalOptions);
165 self::assertSame(
166 'dump_what',
167 $generalOptions->getName(),
170 self::assertSame(
171 'Data dump options',
172 $generalOptions->getText(),
175 self::assertSame(
176 'structure',
177 $generalOptions->getForce(),
180 $generalProperties = $generalOptions->getProperties();
182 $property = $generalProperties->current();
183 $generalProperties->next();
185 self::assertInstanceOf(TextPropertyItem::class, $property);
187 self::assertSame(
188 'null',
189 $property->getName(),
192 self::assertSame(
193 'Replace NULL with:',
194 $property->getText(),
197 $property = $generalProperties->current();
199 self::assertInstanceOf(BoolPropertyItem::class, $property);
201 self::assertSame(
202 'columns',
203 $property->getName(),
206 self::assertSame(
207 'Put columns names in the first row',
208 $property->getText(),
212 public function testExportHeader(): void
214 ob_start();
215 $this->object->exportHeader();
216 $result = ob_get_clean();
218 $expected = '<html xmlns:o="urn:schemas-microsoft-com:office:office"
219 xmlns:x="urn:schemas-microsoft-com:office:word"
220 xmlns="http://www.w3.org/TR/REC-html40">
222 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
223 . ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
224 <html>
225 <head>
226 <meta http-equiv="Content-type" content="text/html;charset='
227 . 'utf-8" />
228 </head>
229 <body>';
231 self::assertSame($expected, $result);
233 // case 2
235 Current::$charset = 'ISO-8859-1';
236 ob_start();
237 $this->object->exportHeader();
238 $result = ob_get_clean();
240 $expected = '<html xmlns:o="urn:schemas-microsoft-com:office:office"
241 xmlns:x="urn:schemas-microsoft-com:office:word"
242 xmlns="http://www.w3.org/TR/REC-html40">
244 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
245 . ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
246 <html>
247 <head>
248 <meta http-equiv="Content-type" content="text/html;charset='
249 . 'ISO-8859-1" />
250 </head>
251 <body>';
253 self::assertSame($expected, $result);
256 public function testExportFooter(): void
258 ob_start();
259 self::assertTrue(
260 $this->object->exportFooter(),
262 $result = ob_get_clean();
264 self::assertSame('</body></html>', $result);
267 public function testExportDBHeader(): void
269 ob_start();
270 self::assertTrue(
271 $this->object->exportDBHeader('d"b'),
273 $result = ob_get_clean();
275 self::assertSame('<h1>Database d&quot;b</h1>', $result);
278 public function testExportDBFooter(): void
280 self::assertTrue(
281 $this->object->exportDBFooter('testDB'),
285 public function testExportDBCreate(): void
287 self::assertTrue(
288 $this->object->exportDBCreate('testDB'),
292 public function testExportData(): void
294 // case 1
295 Export::$outputKanjiConversion = false;
296 Export::$outputCharsetConversion = false;
297 Export::$bufferNeeded = false;
298 Export::$asFile = true;
299 Export::$saveOnServer = false;
301 $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/')
302 ->withParsedBody(['htmlword_columns' => 'On']);
304 $this->object->setExportOptions($request, []);
306 ob_start();
307 self::assertTrue($this->object->exportData(
308 'test_db',
309 'test_table',
310 'SELECT * FROM `test_db`.`test_table`;',
312 $result = ob_get_clean();
314 self::assertSame(
315 '<h2>Dumping data for table test_table</h2>'
316 . '<table width="100%" cellspacing="1"><tr class="print-category">'
317 . '<td class="print"><strong>id</strong></td>'
318 . '<td class="print"><strong>name</strong></td>'
319 . '<td class="print"><strong>datetimefield</strong></td>'
320 . '</tr><tr class="print-category">'
321 . '<td class="print">1</td><td class="print">abcd</td><td class="print">2011-01-20 02:00:02</td>'
322 . '</tr><tr class="print-category">'
323 . '<td class="print">2</td><td class="print">foo</td><td class="print">2010-01-20 02:00:02</td>'
324 . '</tr><tr class="print-category">'
325 . '<td class="print">3</td><td class="print">Abcd</td><td class="print">2012-01-20 02:00:02</td>'
326 . '</tr></table>',
327 $result,
331 public function testGetTableDefStandIn(): void
333 $this->object = $this->getMockBuilder(ExportHtmlword::class)
334 ->onlyMethods(['formatOneColumnDefinition'])
335 ->disableOriginalConstructor()
336 ->getMock();
338 // case 1
340 $keys = [['Non_unique' => 0, 'Column_name' => 'name1'], ['Non_unique' => 1, 'Column_name' => 'name2']];
342 $dbi = $this->getMockBuilder(DatabaseInterface::class)
343 ->disableOriginalConstructor()
344 ->getMock();
346 $dbi->expects(self::once())
347 ->method('getTableIndexes')
348 ->with('database', 'view')
349 ->willReturn($keys);
351 $column = new Column('column', '', null, false, '', null, '', '', '');
353 $dbi->expects(self::once())
354 ->method('getColumns')
355 ->with('database', 'view')
356 ->willReturn([$column]);
358 DatabaseInterface::$instance = $dbi;
360 $this->object->expects(self::once())
361 ->method('formatOneColumnDefinition')
362 ->with($column, ['name1'], 'column')
363 ->willReturn('1');
365 self::assertSame(
366 '<table width="100%" cellspacing="1">' .
367 '<tr class="print-category"><th class="print">Column</th>' .
368 '<td class="print"><strong>Type</strong></td>' .
369 '<td class="print"><strong>Null</strong></td>' .
370 '<td class="print"><strong>Default</strong></td></tr>' .
371 '1</tr></table>',
372 $this->object->getTableDefStandIn('database', 'view'),
376 public function testGetTableDef(): void
378 $this->object = $this->getMockBuilder(ExportHtmlword::class)
379 ->onlyMethods(['formatOneColumnDefinition'])
380 ->setConstructorArgs([new Relation($this->dbi), new Export($this->dbi), new Transformations()])
381 ->getMock();
383 $keys = [['Non_unique' => 0, 'Column_name' => 'name1'], ['Non_unique' => 1, 'Column_name' => 'name2']];
385 // case 1
387 $resultStub = self::createMock(DummyResult::class);
389 $dbi = $this->getMockBuilder(DatabaseInterface::class)
390 ->disableOriginalConstructor()
391 ->getMock();
393 $dbi->expects(self::exactly(2))
394 ->method('fetchResult')
395 ->willReturn(
397 ['fieldname' => ['values' => 'test-', 'transformation' => 'testfoo', 'mimetype' => 'test<']],
400 $dbi->expects(self::once())
401 ->method('getTableIndexes')
402 ->with('database', '')
403 ->willReturn($keys);
405 $column = new Column('fieldname', '', null, false, '', null, '', '', '');
406 $dbi->expects(self::once())
407 ->method('getColumns')
408 ->with('database', '')
409 ->willReturn([$column]);
411 $dbi->expects(self::once())
412 ->method('tryQueryAsControlUser')
413 ->willReturn($resultStub);
415 $resultStub->expects(self::once())
416 ->method('numRows')
417 ->willReturn(1);
419 $resultStub->expects(self::once())
420 ->method('fetchAssoc')
421 ->willReturn(['comment' => 'testComment']);
423 DatabaseInterface::$instance = $dbi;
424 $this->object->relation = new Relation($dbi);
426 $this->object->expects(self::exactly(3))
427 ->method('formatOneColumnDefinition')
428 ->with($column, ['name1'])
429 ->willReturn('1');
431 $relationParameters = RelationParameters::fromArray([
432 'relwork' => true,
433 'commwork' => true,
434 'mimework' => true,
435 'db' => 'database',
436 'relation' => 'rel',
437 'column_info' => 'col',
439 (new ReflectionProperty(Relation::class, 'cache'))->setValue(null, $relationParameters);
441 $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/')
442 ->withParsedBody(['htmlword_relation' => 'On', 'htmlword_mime' => 'On', 'htmlword_comments' => 'On']);
444 $this->object->setExportOptions($request, []);
446 $result = $this->object->getTableDef('database', '');
448 self::assertSame(
449 '<table width="100%" cellspacing="1">' .
450 '<tr class="print-category"><th class="print">Column</th>' .
451 '<td class="print"><strong>Type</strong></td>' .
452 '<td class="print"><strong>Null</strong></td>' .
453 '<td class="print"><strong>Default</strong></td>' .
454 '<td class="print"><strong>Comments</strong></td>' .
455 '<td class="print"><strong>Media type</strong></td></tr>' .
456 '1<td class="print"></td><td class="print">Test&lt;</td></tr></table>',
457 $result,
460 // case 2
462 $resultStub = self::createMock(DummyResult::class);
464 $dbi = $this->getMockBuilder(DatabaseInterface::class)
465 ->disableOriginalConstructor()
466 ->getMock();
468 $dbi->expects(self::exactly(2))
469 ->method('fetchResult')
470 ->willReturn(
471 ['fieldname' => ['foreign_table' => 'ftable', 'foreign_field' => 'ffield']],
472 ['field' => ['values' => 'test-', 'transformation' => 'testfoo', 'mimetype' => 'test<']],
475 $dbi->expects(self::once())
476 ->method('getTableIndexes')
477 ->with('database', '')
478 ->willReturn($keys);
480 $column = new Column('fieldname', '', null, false, '', null, '', '', '');
482 $dbi->expects(self::once())
483 ->method('getColumns')
484 ->with('database', '')
485 ->willReturn([$column]);
487 $dbi->expects(self::once())
488 ->method('tryQueryAsControlUser')
489 ->willReturn($resultStub);
491 $resultStub->expects(self::once())
492 ->method('numRows')
493 ->willReturn(1);
495 $resultStub->expects(self::once())
496 ->method('fetchAssoc')
497 ->willReturn(['comment' => 'testComment']);
499 DatabaseInterface::$instance = $dbi;
500 $this->object->relation = new Relation($dbi);
502 $relationParameters = RelationParameters::fromArray([
503 'relwork' => true,
504 'commwork' => true,
505 'mimework' => true,
506 'db' => 'database',
507 'relation' => 'rel',
508 'column_info' => 'col',
510 (new ReflectionProperty(Relation::class, 'cache'))->setValue(null, $relationParameters);
512 $result = $this->object->getTableDef('database', '');
514 self::assertStringContainsString('<td class="print">ftable (ffield)</td>', $result);
516 self::assertStringContainsString('<td class="print"></td><td class="print"></td>', $result);
518 // case 3
520 $dbi = $this->getMockBuilder(DatabaseInterface::class)
521 ->disableOriginalConstructor()
522 ->getMock();
524 $dbi->expects(self::once())
525 ->method('getTableIndexes')
526 ->with('database', '')
527 ->willReturn($keys);
529 $column = new Column('fieldname', '', null, false, '', null, '', '', '');
531 $dbi->expects(self::once())
532 ->method('getColumns')
533 ->with('database', '')
534 ->willReturn([$column]);
536 $dbi->expects(self::never())
537 ->method('tryQuery');
539 DatabaseInterface::$instance = $dbi;
541 $relationParameters = RelationParameters::fromArray([
542 'db' => 'database',
543 'relation' => 'rel',
544 'column_info' => 'col',
546 (new ReflectionProperty(Relation::class, 'cache'))->setValue(null, $relationParameters);
548 $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/')
549 ->withParsedBody(['htmlword_relation' => 'On', 'htmlword_mime' => 'On']);
551 $this->object->setExportOptions($request, []);
553 $result = $this->object->getTableDef('database', '');
555 self::assertSame(
556 '<table width="100%" cellspacing="1">' .
557 '<tr class="print-category"><th class="print">Column</th>' .
558 '<td class="print"><strong>Type</strong></td>' .
559 '<td class="print"><strong>Null</strong></td>' .
560 '<td class="print"><strong>Default</strong></td></tr>1</tr></table>',
561 $result,
565 public function testGetTriggers(): void
567 $triggers = [
568 new Trigger(
569 TriggerName::from('tna"me'),
570 Timing::Before,
571 Event::Update,
572 TableName::from('table'),
573 'def',
574 'test_user@localhost',
578 $method = new ReflectionMethod(ExportHtmlword::class, 'getTriggers');
579 $result = $method->invoke($this->object, $triggers);
581 self::assertStringContainsString(
582 '<td class="print">tna&quot;me</td>' .
583 '<td class="print">BEFORE</td>' .
584 '<td class="print">UPDATE</td>' .
585 '<td class="print">def</td>',
586 $result,
590 public function testExportStructure(): void
592 ob_start();
593 $this->dummyDbi->addSelectDb('test_db');
594 self::assertTrue($this->object->exportStructure('test_db', 'test_table', 'create_table'));
595 $this->dummyDbi->assertAllSelectsConsumed();
596 $result = ob_get_clean();
598 self::assertSame(
599 '<h2>Table structure for table test_table</h2>'
600 . '<table width="100%" cellspacing="1"><tr class="print-category">'
601 . '<th class="print">Column</th><td class="print"><strong>Type</strong></td>'
602 . '<td class="print"><strong>Null</strong></td><td class="print"><strong>Default</strong></td></tr>'
603 . '<tr class="print-category"><td class="print"><em><strong>id</strong></em></td>'
604 . '<td class="print">int(11)</td><td class="print">No</td><td class="print">NULL</td></tr>'
605 . '<tr class="print-category"><td class="print">name</td><td class="print">varchar(20)</td>'
606 . '<td class="print">No</td><td class="print">NULL</td></tr><tr class="print-category">'
607 . '<td class="print">datetimefield</td><td class="print">datetime</td>'
608 . '<td class="print">No</td><td class="print">NULL</td></tr></table>',
609 $result,
612 ob_start();
613 self::assertTrue($this->object->exportStructure('test_db', 'test_table', 'triggers'));
614 $result = ob_get_clean();
616 self::assertSame(
617 '<h2>Triggers test_table</h2><table width="100%" cellspacing="1">'
618 . '<tr class="print-category"><th class="print">Name</th>'
619 . '<td class="print"><strong>Time</strong></td><td class="print"><strong>Event</strong></td>'
620 . '<td class="print"><strong>Definition</strong></td></tr><tr class="print-category">'
621 . '<td class="print">test_trigger</td><td class="print">AFTER</td>'
622 . '<td class="print">INSERT</td><td class="print">BEGIN END</td></tr></table>',
623 $result,
626 ob_start();
627 $this->dummyDbi->addSelectDb('test_db');
628 self::assertTrue($this->object->exportStructure('test_db', 'test_table', 'create_view'));
629 $this->dummyDbi->assertAllSelectsConsumed();
630 $result = ob_get_clean();
632 self::assertSame(
633 '<h2>Structure for view test_table</h2>'
634 . '<table width="100%" cellspacing="1"><tr class="print-category">'
635 . '<th class="print">Column</th><td class="print"><strong>Type</strong></td>'
636 . '<td class="print"><strong>Null</strong></td><td class="print"><strong>Default</strong>'
637 . '</td></tr><tr class="print-category"><td class="print"><em><strong>id</strong></em></td>'
638 . '<td class="print">int(11)</td><td class="print">No</td><td class="print">NULL</td></tr>'
639 . '<tr class="print-category"><td class="print">name</td><td class="print">varchar(20)</td>'
640 . '<td class="print">No</td><td class="print">NULL</td></tr><tr class="print-category">'
641 . '<td class="print">datetimefield</td><td class="print">datetime</td>'
642 . '<td class="print">No</td><td class="print">NULL</td></tr></table>',
643 $result,
646 ob_start();
647 self::assertTrue($this->object->exportStructure('test_db', 'test_table', 'stand_in'));
648 $result = ob_get_clean();
650 self::assertSame(
651 '<h2>Stand-in structure for view test_table</h2>'
652 . '<table width="100%" cellspacing="1"><tr class="print-category">'
653 . '<th class="print">Column</th><td class="print"><strong>Type</strong></td>'
654 . '<td class="print"><strong>Null</strong></td><td class="print"><strong>Default</strong></td>'
655 . '</tr><tr class="print-category">'
656 . '<td class="print"><em><strong>id</strong></em></td><td class="print">int(11)</td>'
657 . '<td class="print">No</td><td class="print">NULL</td></tr><tr class="print-category">'
658 . '<td class="print">name</td><td class="print">varchar(20)</td><td class="print">No</td>'
659 . '<td class="print">NULL</td></tr><tr class="print-category">'
660 . '<td class="print">datetimefield</td><td class="print">datetime</td>'
661 . '<td class="print">No</td><td class="print">NULL</td></tr></table>',
662 $result,
666 public function testFormatOneColumnDefinition(): void
668 $method = new ReflectionMethod(ExportHtmlword::class, 'formatOneColumnDefinition');
670 $column = new Column('field', 'set(abc)enum123', null, true, 'PRI', null, '', '', '');
672 $uniqueKeys = ['field'];
674 self::assertSame(
675 '<tr class="print-category"><td class="print"><em>' .
676 '<strong>field</strong></em></td><td class="print">set(abc)</td>' .
677 '<td class="print">Yes</td><td class="print">NULL</td>',
678 $method->invoke($this->object, $column, $uniqueKeys),
681 $column = new Column('fields', '', null, false, 'COMP', 'def', '', '', '');
683 $uniqueKeys = ['field'];
685 self::assertSame(
686 '<tr class="print-category"><td class="print">fields</td>' .
687 '<td class="print">&amp;nbsp;</td><td class="print">No</td>' .
688 '<td class="print">def</td>',
689 $method->invoke($this->object, $column, $uniqueKeys),