Passed
Push — master ( b100c0...62ec1b )
by Maurício
11:38 queued 13s
created

InsertEditTest::testGetNullifyCodeForNullColumn()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 71
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 56
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 71
rs 8.9599

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpMyAdmin\Tests;
6
7
use PhpMyAdmin\ColumnFull;
8
use PhpMyAdmin\ConfigStorage\Relation;
9
use PhpMyAdmin\Core;
10
use PhpMyAdmin\DatabaseInterface;
0 ignored issues
show
Bug introduced by
The type PhpMyAdmin\DatabaseInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use PhpMyAdmin\Dbal\Warning;
12
use PhpMyAdmin\EditField;
13
use PhpMyAdmin\FileListing;
14
use PhpMyAdmin\InsertEdit;
15
use PhpMyAdmin\InsertEditColumn;
16
use PhpMyAdmin\ResponseRenderer;
0 ignored issues
show
Bug introduced by
The type PhpMyAdmin\ResponseRenderer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use PhpMyAdmin\Table;
18
use PhpMyAdmin\Template;
19
use PhpMyAdmin\Tests\Stubs\DbiDummy;
20
use PhpMyAdmin\Tests\Stubs\DummyResult;
21
use PhpMyAdmin\Transformations;
22
use PhpMyAdmin\Url;
23
use ReflectionProperty;
24
25
use function hash;
26
use function is_object;
27
use function is_scalar;
28
use function is_string;
29
use function mb_substr;
30
use function md5;
31
use function password_verify;
32
use function sprintf;
33
use function strval;
34
35
use const MYSQLI_PRI_KEY_FLAG;
36
use const MYSQLI_TYPE_DECIMAL;
37
use const MYSQLI_TYPE_TIMESTAMP;
38
use const MYSQLI_TYPE_TINY;
39
40
/**
41
 * @covers \PhpMyAdmin\InsertEdit
42
 * @group medium
43
 */
44
class InsertEditTest extends AbstractTestCase
45
{
46
    protected DatabaseInterface $dbi;
47
48
    protected DbiDummy $dummyDbi;
49
50
    private InsertEdit $insertEdit;
51
52
    /**
53
     * Setup for test cases
54
     */
55
    protected function setUp(): void
56
    {
57
        parent::setUp();
58
59
        parent::setLanguage();
60
61
        parent::setGlobalConfig();
62
63
        parent::setTheme();
64
65
        $this->dummyDbi = $this->createDbiDummy();
66
        $this->dbi = $this->createDatabaseInterface($this->dummyDbi);
67
        $GLOBALS['dbi'] = $this->dbi;
68
        $GLOBALS['server'] = 1;
69
        $GLOBALS['cfg']['ServerDefault'] = 1;
70
        $GLOBALS['text_dir'] = 'ltr';
71
        $GLOBALS['db'] = 'db';
72
        $GLOBALS['table'] = 'table';
73
        $GLOBALS['cfg']['LimitChars'] = 50;
74
        $GLOBALS['cfg']['LongtextDoubleTextarea'] = false;
75
        $GLOBALS['cfg']['ShowFieldTypesInDataEditView'] = true;
76
        $GLOBALS['cfg']['ShowFunctionFields'] = true;
77
        $GLOBALS['cfg']['ProtectBinary'] = 'blob';
78
        $GLOBALS['cfg']['MaxSizeForInputField'] = 10;
79
        $GLOBALS['cfg']['MinSizeForInputField'] = 2;
80
        $GLOBALS['cfg']['TextareaRows'] = 5;
81
        $GLOBALS['cfg']['TextareaCols'] = 4;
82
        $GLOBALS['cfg']['CharTextareaRows'] = 5;
83
        $GLOBALS['cfg']['CharTextareaCols'] = 6;
84
        $GLOBALS['cfg']['AllowThirdPartyFraming'] = false;
85
        $GLOBALS['cfg']['SendErrorReports'] = 'ask';
86
        $GLOBALS['cfg']['DefaultTabDatabase'] = 'structure';
87
        $GLOBALS['cfg']['ShowDatabasesNavigationAsTree'] = true;
88
        $GLOBALS['cfg']['DefaultTabTable'] = 'browse';
89
        $GLOBALS['cfg']['NavigationTreeDefaultTabTable'] = 'structure';
90
        $GLOBALS['cfg']['NavigationTreeDefaultTabTable2'] = '';
91
        $GLOBALS['cfg']['Confirm'] = true;
92
        $GLOBALS['cfg']['LoginCookieValidity'] = 1440;
93
        $GLOBALS['cfg']['enable_drag_drop_import'] = true;
94
        $this->insertEdit = new InsertEdit(
95
            $this->dbi,
96
            new Relation($this->dbi),
97
            new Transformations(),
98
            new FileListing(),
99
            new Template(),
100
        );
101
102
        $this->dbi->setVersion([
103
            '@@version' => '10.9.3-MariaDB-1:10.9.3+maria~ubu2204',
104
            '@@version_comment' => 'mariadb.org binary distribution',
105
        ]);
106
    }
107
108
    /**
109
     * Teardown all objects
110
     */
111
    protected function tearDown(): void
112
    {
113
        parent::tearDown();
114
115
        $response = new ReflectionProperty(ResponseRenderer::class, 'instance');
116
        $response->setValue(null);
117
    }
118
119
    /**
120
     * Test for getFormParametersForInsertForm
121
     */
122
    public function testGetFormParametersForInsertForm(): void
123
    {
124
        $whereClause = ['foo' => 'bar ', '1' => ' test'];
125
        $_POST['clause_is_unique'] = false;
126
        $_POST['sql_query'] = 'SELECT a';
127
        $GLOBALS['goto'] = 'index.php';
128
129
        $result = $this->insertEdit->getFormParametersForInsertForm(
130
            'dbname',
131
            'tablename',
132
            [],
133
            $whereClause,
134
            'localhost',
135
        );
136
137
        $this->assertEquals(
138
            [
139
                'db' => 'dbname',
140
                'table' => 'tablename',
141
                'goto' => 'index.php',
142
                'err_url' => 'localhost',
143
                'sql_query' => 'SELECT a',
144
                'where_clause[foo]' => 'bar',
145
                'where_clause[1]' => 'test',
146
                'clause_is_unique' => false,
147
            ],
148
            $result,
149
        );
150
    }
151
152
    /**
153
     * Test for getFormParametersForInsertForm
154
     */
155
    public function testGetFormParametersForInsertFormGet(): void
156
    {
157
        $whereClause = ['foo' => 'bar ', '1' => ' test'];
158
        $_GET['clause_is_unique'] = false;
159
        $_GET['sql_query'] = 'SELECT a';
160
        $_GET['sql_signature'] = Core::signSqlQuery($_GET['sql_query']);
161
        $GLOBALS['goto'] = 'index.php';
162
163
        $result = $this->insertEdit->getFormParametersForInsertForm(
164
            'dbname',
165
            'tablename',
166
            [],
167
            $whereClause,
168
            'localhost',
169
        );
170
171
        $this->assertEquals(
172
            [
173
                'db' => 'dbname',
174
                'table' => 'tablename',
175
                'goto' => 'index.php',
176
                'err_url' => 'localhost',
177
                'sql_query' => 'SELECT a',
178
                'where_clause[foo]' => 'bar',
179
                'where_clause[1]' => 'test',
180
                'clause_is_unique' => false,
181
            ],
182
            $result,
183
        );
184
    }
185
186
    /**
187
     * Test for analyzeWhereClauses
188
     */
189
    public function testAnalyzeWhereClause(): void
190
    {
191
        $clauses = ['a=1', 'b="fo\o"'];
192
193
        $resultStub1 = $this->createMock(DummyResult::class);
194
        $resultStub2 = $this->createMock(DummyResult::class);
195
196
        $dbi = $this->getMockBuilder(DatabaseInterface::class)
197
            ->disableOriginalConstructor()
198
            ->getMock();
199
200
        $dbi->expects($this->exactly(2))
201
            ->method('query')
202
            ->willReturnOnConsecutiveCalls($resultStub1, $resultStub2);
203
204
        $resultStub1->expects($this->once())
205
            ->method('fetchAssoc')
206
            ->will($this->returnValue(['assoc1']));
207
208
        $resultStub2->expects($this->once())
209
            ->method('fetchAssoc')
210
            ->will($this->returnValue(['assoc2']));
211
212
        $dbi->expects($this->exactly(2))
213
            ->method('getFieldsMeta')
214
            ->willReturnOnConsecutiveCalls(
215
                [],
216
                [],
217
            );
218
219
        $GLOBALS['dbi'] = $dbi;
220
        $this->insertEdit = new InsertEdit(
221
            $GLOBALS['dbi'],
222
            new Relation($GLOBALS['dbi']),
223
            new Transformations(),
224
            new FileListing(),
225
            new Template(),
226
        );
227
        $result = $this->callFunction(
228
            $this->insertEdit,
229
            InsertEdit::class,
230
            'analyzeWhereClauses',
231
            [$clauses, 'table', 'db'],
232
        );
233
234
        $this->assertSame(
235
            [['a=1', 'b="fo\\\\o"'], [$resultStub1, $resultStub2], [['assoc1'], ['assoc2']], false],
236
            $result,
237
        );
238
    }
239
240
    /**
241
     * Test for showEmptyResultMessageOrSetUniqueCondition
242
     */
243
    public function testShowEmptyResultMessageOrSetUniqueCondition(): void
244
    {
245
        $meta = FieldHelper::fromArray([
246
            'type' => MYSQLI_TYPE_DECIMAL,
247
            'flags' => MYSQLI_PRI_KEY_FLAG,
248
            'table' => 'table',
249
            'orgname' => 'orgname',
250
        ]);
251
252
        $resultStub = $this->createMock(DummyResult::class);
253
254
        $dbi = $this->getMockBuilder(DatabaseInterface::class)
255
            ->disableOriginalConstructor()
256
            ->getMock();
257
258
        $dbi->expects($this->once())
259
            ->method('getFieldsMeta')
260
            ->with($resultStub)
261
            ->will($this->returnValue([$meta]));
262
263
        $GLOBALS['dbi'] = $dbi;
264
        $this->insertEdit = new InsertEdit(
265
            $GLOBALS['dbi'],
266
            new Relation($GLOBALS['dbi']),
267
            new Transformations(),
268
            new FileListing(),
269
            new Template(),
270
        );
271
272
        $result = $this->callFunction(
273
            $this->insertEdit,
274
            InsertEdit::class,
275
            'showEmptyResultMessageOrSetUniqueCondition',
276
            [['1' => ['1' => 1]], 1, [], 'SELECT', ['1' => $resultStub]],
277
        );
278
279
        $this->assertTrue($result);
280
281
        // case 2
282
        $GLOBALS['cfg']['ShowSQL'] = false;
283
284
        $responseMock = $this->getMockBuilder(ResponseRenderer::class)
285
            ->disableOriginalConstructor()
286
            ->onlyMethods(['addHtml'])
287
            ->getMock();
288
289
        $restoreInstance = ResponseRenderer::getInstance();
290
        $response = new ReflectionProperty(ResponseRenderer::class, 'instance');
291
        $response->setValue($responseMock);
292
293
        $result = $this->callFunction(
294
            $this->insertEdit,
295
            InsertEdit::class,
296
            'showEmptyResultMessageOrSetUniqueCondition',
297
            [[false], 0, ['1'], 'SELECT', ['1' => 'result1']],
298
        );
299
300
        $response->setValue($restoreInstance);
301
302
        $this->assertFalse($result);
303
    }
304
305
    public function testLoadFirstRow(): void
306
    {
307
        $resultStub = $this->createMock(DummyResult::class);
308
309
        $dbi = $this->getMockBuilder(DatabaseInterface::class)
310
            ->disableOriginalConstructor()
311
            ->getMock();
312
313
        $dbi->expects($this->once())
314
            ->method('query')
315
            ->with('SELECT * FROM `db`.`table` LIMIT 1;')
316
            ->will($this->returnValue($resultStub));
317
318
        $GLOBALS['dbi'] = $dbi;
319
        $this->insertEdit = new InsertEdit(
320
            $GLOBALS['dbi'],
321
            new Relation($GLOBALS['dbi']),
322
            new Transformations(),
323
            new FileListing(),
324
            new Template(),
325
        );
326
327
        $result = $this->callFunction(
328
            $this->insertEdit,
329
            InsertEdit::class,
330
            'loadFirstRow',
331
            ['table', 'db'],
332
        );
333
334
        $this->assertEquals($resultStub, $result);
335
    }
336
337
    /** @return list<array{int|string, array<false>}> */
338
    public static function dataProviderConfigValueInsertRows(): array
339
    {
340
        return [[2, [false, false]], ['2', [false, false]], [3, [false, false, false]], ['3', [false, false, false]]];
341
    }
342
343
    /**
344
     * Test for loadFirstRow
345
     *
346
     * @param array<false> $rowsValue
347
     *
348
     * @dataProvider dataProviderConfigValueInsertRows
349
     */
350
    public function testGetInsertRows(string|int $configValue, array $rowsValue): void
351
    {
352
        $GLOBALS['cfg']['InsertRows'] = $configValue;
353
354
        $result = $this->callFunction(
355
            $this->insertEdit,
356
            InsertEdit::class,
357
            'getInsertRows',
358
            [],
359
        );
360
361
        $this->assertEquals($rowsValue, $result);
362
    }
363
364
    /**
365
     * Test for showTypeOrFunction
366
     */
367
    public function testShowTypeOrFunction(): void
368
    {
369
        $GLOBALS['cfg']['ShowFieldTypesInDataEditView'] = true;
370
        $GLOBALS['cfg']['ServerDefault'] = 1;
371
        $urlParams = ['ShowFunctionFields' => 2];
372
373
        $result = $this->insertEdit->showTypeOrFunction('function', $urlParams, false);
374
375
        $this->assertStringContainsString('index.php?route=/table/change', $result);
376
        $this->assertStringContainsString(
377
            'ShowFunctionFields=1&ShowFieldTypesInDataEditView=1&goto=index.php%3Froute%3D%2Fsql',
378
            $result,
379
        );
380
        $this->assertStringContainsString('Function', $result);
381
382
        // case 2
383
        $result = $this->insertEdit->showTypeOrFunction('function', $urlParams, true);
384
385
        $this->assertStringContainsString('index.php?route=/table/change', $result);
386
        $this->assertStringContainsString(
387
            'ShowFunctionFields=0&ShowFieldTypesInDataEditView=1&goto=index.php%3Froute%3D%2Fsql',
388
            $result,
389
        );
390
        $this->assertStringContainsString('Function', $result);
391
392
        // case 3
393
        $result = $this->insertEdit->showTypeOrFunction('type', $urlParams, false);
394
395
        $this->assertStringContainsString('index.php?route=/table/change', $result);
396
        $this->assertStringContainsString(
397
            'ShowFunctionFields=1&ShowFieldTypesInDataEditView=1&goto=index.php%3Froute%3D%2Fsql',
398
            $result,
399
        );
400
        $this->assertStringContainsString('Type', $result);
401
402
        // case 4
403
        $result = $this->insertEdit->showTypeOrFunction('type', $urlParams, true);
404
405
        $this->assertStringContainsString('index.php?route=/table/change', $result);
406
        $this->assertStringContainsString(
407
            'ShowFunctionFields=1&ShowFieldTypesInDataEditView=0&goto=index.php%3Froute%3D%2Fsql',
408
            $result,
409
        );
410
        $this->assertStringContainsString('Type', $result);
411
    }
412
413
    /**
414
     * Test for getColumnTitle
415
     */
416
    public function testGetColumnTitle(): void
417
    {
418
        $fieldName = 'f1<';
419
420
        $this->assertEquals(
421
            $this->callFunction(
422
                $this->insertEdit,
423
                InsertEdit::class,
424
                'getColumnTitle',
425
                [$fieldName, []],
426
            ),
427
            'f1&lt;',
428
        );
429
430
        $comments = [];
431
        $comments['f1<'] = 'comment>';
432
433
        $result = $this->callFunction(
434
            $this->insertEdit,
435
            InsertEdit::class,
436
            'getColumnTitle',
437
            [$fieldName, $comments],
438
        );
439
440
        $result = $this->parseString($result);
441
442
        $this->assertStringContainsString('title="comment&gt;"', $result);
443
444
        $this->assertStringContainsString('f1&lt;', $result);
445
    }
446
447
    /**
448
     * Test for isColumn
449
     */
450
    public function testIsColumn(): void
451
    {
452
        $types = ['binary', 'varbinary'];
453
454
        $columnType = 'binaryfoo';
455
        $this->assertTrue($this->insertEdit->isColumn($columnType, $types));
456
457
        $columnType = 'Binaryfoo';
458
        $this->assertTrue($this->insertEdit->isColumn($columnType, $types));
459
460
        $columnType = 'varbinaryfoo';
461
        $this->assertTrue($this->insertEdit->isColumn($columnType, $types));
462
463
        $columnType = 'barbinaryfoo';
464
        $this->assertFalse($this->insertEdit->isColumn($columnType, $types));
465
466
        $types = ['char', 'varchar'];
467
468
        $columnType = 'char(10)';
469
        $this->assertTrue($this->insertEdit->isColumn($columnType, $types));
470
471
        $columnType = 'VarChar(20)';
472
        $this->assertTrue($this->insertEdit->isColumn($columnType, $types));
473
474
        $columnType = 'foochar';
475
        $this->assertFalse($this->insertEdit->isColumn($columnType, $types));
476
477
        $types = ['blob', 'tinyblob', 'mediumblob', 'longblob'];
478
479
        $columnType = 'blob';
480
        $this->assertTrue($this->insertEdit->isColumn($columnType, $types));
481
482
        $columnType = 'bloB';
483
        $this->assertTrue($this->insertEdit->isColumn($columnType, $types));
484
485
        $columnType = 'mediumBloB';
486
        $this->assertTrue($this->insertEdit->isColumn($columnType, $types));
487
488
        $columnType = 'tinyblobabc';
489
        $this->assertTrue($this->insertEdit->isColumn($columnType, $types));
490
491
        $columnType = 'longblob';
492
        $this->assertTrue($this->insertEdit->isColumn($columnType, $types));
493
494
        $columnType = 'foolongblobbar';
495
        $this->assertFalse($this->insertEdit->isColumn($columnType, $types));
496
    }
497
498
    /**
499
     * Test for getNullifyCodeForNullColumn
500
     */
501
    public function testGetNullifyCodeForNullColumn(): void
502
    {
503
        $foreignData = [];
504
        $foreigners = ['foreign_keys_data' => []];
505
        $column = new InsertEditColumn(
506
            'f',
507
            'enum(ababababababababababa)',
508
            false,
509
            '',
510
            null,
511
            '',
512
            -1,
513
            false,
514
            false,
515
            false,
516
            false,
517
        );
518
        $this->assertEquals(
519
            '1',
520
            $this->callFunction(
521
                $this->insertEdit,
522
                InsertEdit::class,
523
                'getNullifyCodeForNullColumn',
524
                [$column, $foreigners, []],
525
            ),
526
        );
527
528
        $column = new InsertEditColumn(
529
            'f',
530
            'enum(abababababab20)',
531
            false,
532
            '',
533
            null,
534
            '',
535
            -1,
536
            false,
537
            false,
538
            false,
539
            false,
540
        );
541
        $this->assertEquals(
542
            '2',
543
            $this->callFunction(
544
                $this->insertEdit,
545
                InsertEdit::class,
546
                'getNullifyCodeForNullColumn',
547
                [$column, $foreigners, []],
548
            ),
549
        );
550
551
        $column = new InsertEditColumn('f', 'set', false, '', null, '', -1, false, false, false, false);
552
        $this->assertEquals(
553
            '3',
554
            $this->callFunction(
555
                $this->insertEdit,
556
                InsertEdit::class,
557
                'getNullifyCodeForNullColumn',
558
                [$column, $foreigners, []],
559
            ),
560
        );
561
562
        $column = new InsertEditColumn('f', '', false, '', null, '', -1, false, false, false, false);
563
        $foreigners['f'] = ['something'/* What should the mocked value actually be? */];
564
        $foreignData['foreign_link'] = '';
565
        $this->assertEquals(
566
            '4',
567
            $this->callFunction(
568
                $this->insertEdit,
569
                InsertEdit::class,
570
                'getNullifyCodeForNullColumn',
571
                [$column, $foreigners, $foreignData],
572
            ),
573
        );
574
    }
575
576
    /**
577
     * Test for getTextarea
578
     */
579
    public function testGetTextarea(): void
580
    {
581
        $GLOBALS['cfg']['TextareaRows'] = 20;
582
        $GLOBALS['cfg']['TextareaCols'] = 10;
583
        $GLOBALS['cfg']['CharTextareaRows'] = 7;
584
        $GLOBALS['cfg']['CharTextareaCols'] = 1;
585
        $GLOBALS['cfg']['LimitChars'] = 20;
586
587
        $column = new InsertEditColumn(
588
            'f',
589
            'char(10)',
590
            false,
591
            '',
592
            null,
593
            'auto_increment',
594
            20,
595
            false,
596
            false,
597
            true,
598
            false,
599
        );
600
        (new ReflectionProperty(InsertEdit::class, 'fieldIndex'))->setValue($this->insertEdit, 2);
601
        $result = $this->callFunction(
602
            $this->insertEdit,
603
            InsertEdit::class,
604
            'getTextarea',
605
            [$column, 'a', 'b', '', 'abc/', 'foobar', 'CHAR'],
606
        );
607
608
        $result = $this->parseString($result);
609
610
        $this->assertStringContainsString(
611
            '<textarea name="fieldsb" class="char charField" '
612
            . 'data-maxlength="10" rows="7" cols="1" dir="abc/" '
613
            . 'id="field_2_3" tabindex="2" data-type="CHAR">',
614
            $result,
615
        );
616
    }
617
618
    /**
619
     * Test for getHtmlInput
620
     */
621
    public function testGetHTMLinput(): void
622
    {
623
        $GLOBALS['cfg']['ShowFunctionFields'] = true;
624
        $column = new InsertEditColumn('f', 'date', false, 'PRI', null, '', -1, false, false, false, false);
625
        (new ReflectionProperty(InsertEdit::class, 'fieldIndex'))->setValue($this->insertEdit, 23);
626
        $result = $this->callFunction(
627
            $this->insertEdit,
628
            InsertEdit::class,
629
            'getHtmlInput',
630
            [$column, 'a', 'b', 30, 'c', 'DATE'],
631
        );
632
633
        $this->assertEquals(
634
            '<input type="text" name="fieldsa" value="b" size="30" data-type="DATE"'
635
            . ' class="textfield datefield" onchange="c" tabindex="23" id="field_23_3">',
636
            $result,
637
        );
638
639
        // case 2 datetime
640
        $column = new InsertEditColumn('f', 'datetime', false, 'PRI', null, '', -1, false, false, false, false);
641
        $result = $this->callFunction(
642
            $this->insertEdit,
643
            InsertEdit::class,
644
            'getHtmlInput',
645
            [$column, 'a', 'b', 30, 'c', 'DATE'],
646
        );
647
        $this->assertEquals(
648
            '<input type="text" name="fieldsa" value="b" size="30" data-type="DATE"'
649
            . ' class="textfield datetimefield" onchange="c" tabindex="23" id="field_23_3">',
650
            $result,
651
        );
652
653
        // case 3 timestamp
654
        $column = new InsertEditColumn('f', 'timestamp', false, 'PRI', null, '', -1, false, false, false, false);
655
        $result = $this->callFunction(
656
            $this->insertEdit,
657
            InsertEdit::class,
658
            'getHtmlInput',
659
            [$column, 'a', 'b', 30, 'c', 'DATE'],
660
        );
661
        $this->assertEquals(
662
            '<input type="text" name="fieldsa" value="b" size="30" data-type="DATE"'
663
            . ' class="textfield datetimefield" onchange="c" tabindex="23" id="field_23_3">',
664
            $result,
665
        );
666
667
        // case 4 int
668
        $column = new InsertEditColumn('f', 'int(11)', false, 'PRI', null, '', -1, false, false, false, false);
669
        $result = $this->callFunction(
670
            $this->insertEdit,
671
            InsertEdit::class,
672
            'getHtmlInput',
673
            [$column, 'a', 'b', 11, 'c', 'INT'],
674
        );
675
        $this->assertEquals(
676
            '<input type="text" name="fieldsa" value="b" size="11" min="-2147483648" max="2147483647" data-type="INT"'
677
            . ' class="textfield" onchange="c" tabindex="23" inputmode="numeric" id="field_23_3">',
678
            $result,
679
        );
680
    }
681
682
    /**
683
     * Test for getMaxUploadSize
684
     */
685
    public function testGetMaxUploadSize(): void
686
    {
687
        $GLOBALS['config']->set('max_upload_size', 257);
688
        $pmaType = 'tinyblob';
689
        $result = $this->callFunction(
690
            $this->insertEdit,
691
            InsertEdit::class,
692
            'getMaxUploadSize',
693
            [$pmaType],
694
        );
695
696
        $this->assertEquals("(Max: 256B)\n", $result);
697
698
        // case 2
699
        $GLOBALS['config']->set('max_upload_size', 250);
700
        $pmaType = 'tinyblob';
701
        $result = $this->callFunction(
702
            $this->insertEdit,
703
            InsertEdit::class,
704
            'getMaxUploadSize',
705
            [$pmaType],
706
        );
707
708
        $this->assertEquals("(Max: 250B)\n", $result);
709
    }
710
711
    /**
712
     * Test for getValueColumnForOtherDatatypes
713
     */
714
    public function testGetValueColumnForOtherDatatypes(): void
715
    {
716
        $column = new InsertEditColumn('f', 'char(25)', false, '', null, '', 20, false, false, true, false);
717
        $GLOBALS['cfg']['CharEditing'] = '';
718
        $GLOBALS['cfg']['MaxSizeForInputField'] = 30;
719
        $GLOBALS['cfg']['MinSizeForInputField'] = 10;
720
        $GLOBALS['cfg']['TextareaRows'] = 20;
721
        $GLOBALS['cfg']['TextareaCols'] = 10;
722
        $GLOBALS['cfg']['CharTextareaRows'] = 7;
723
        $GLOBALS['cfg']['CharTextareaCols'] = 1;
724
        $GLOBALS['cfg']['LimitChars'] = 50;
725
        $GLOBALS['cfg']['ShowFunctionFields'] = true;
726
727
        $extractedColumnSpec = [];
728
        $extractedColumnSpec['spec_in_brackets'] = '25';
729
        (new ReflectionProperty(InsertEdit::class, 'fieldIndex'))->setValue($this->insertEdit, 22);
730
        $result = $this->callFunction(
731
            $this->insertEdit,
732
            InsertEdit::class,
733
            'getValueColumnForOtherDatatypes',
734
            [
735
                $column,
736
                'defchar',
737
                'a',
738
                'b',
739
                'c',
740
                '&lt;',
741
                '/',
742
                '&lt;',
743
                "foo\nbar",
744
                $extractedColumnSpec,
745
            ],
746
        );
747
748
        $this->assertEquals(
749
            "a\na\n"
750
            . '<textarea name="fieldsb" class="char charField" '
751
            . 'data-maxlength="25" rows="7" cols="1" dir="/" '
752
            . 'id="field_22_3" onchange="c" tabindex="22" data-type="CHAR">'
753
            . '&lt;</textarea>',
754
            $result,
755
        );
756
757
        // case 2: (else)
758
        $column = new InsertEditColumn(
759
            'f',
760
            'timestamp',
761
            false,
762
            '',
763
            null,
764
            'auto_increment',
765
            20,
766
            false,
767
            false,
768
            false,
769
            false,
770
        );
771
        $result = $this->callFunction(
772
            $this->insertEdit,
773
            InsertEdit::class,
774
            'getValueColumnForOtherDatatypes',
775
            [
776
                $column,
777
                'defchar',
778
                'a',
779
                'b',
780
                'c',
781
                '&lt;',
782
                '/',
783
                '&lt;',
784
                "foo\nbar",
785
                $extractedColumnSpec,
786
            ],
787
        );
788
789
        $this->assertEquals(
790
            "a\n"
791
            . '<input type="text" name="fieldsb" value="&lt;" size="20" data-type="'
792
            . 'DATE" class="textfield datetimefield" onchange="c" tabindex="22" id="field_22_3"'
793
            . '><input type="hidden" name="auto_incrementb" value="1">'
794
            . '<input type="hidden" name="fields_typeb" value="timestamp">',
795
            $result,
796
        );
797
798
        // case 3: (else -> datetime)
799
        $column = new InsertEditColumn(
800
            'f',
801
            'datetime',
802
            false,
803
            '',
804
            null,
805
            'auto_increment',
806
            20,
807
            false,
808
            false,
809
            false,
810
            false,
811
        );
812
        $result = $this->callFunction(
813
            $this->insertEdit,
814
            InsertEdit::class,
815
            'getValueColumnForOtherDatatypes',
816
            [
817
                $column,
818
                'defchar',
819
                'a',
820
                'b',
821
                'c',
822
                '&lt;',
823
                '/',
824
                '&lt;',
825
                "foo\nbar",
826
                $extractedColumnSpec,
827
            ],
828
        );
829
830
        $result = $this->parseString($result);
831
832
        $this->assertStringContainsString('<input type="hidden" name="fields_typeb" value="datetime">', $result);
833
834
        // case 4: (else -> date)
835
        $column = new InsertEditColumn('f', 'date', false, '', null, 'auto_increment', 20, false, false, false, false);
836
        $result = $this->callFunction(
837
            $this->insertEdit,
838
            InsertEdit::class,
839
            'getValueColumnForOtherDatatypes',
840
            [
841
                $column,
842
                'defchar',
843
                'a',
844
                'b',
845
                'c',
846
                '&lt;',
847
                '/',
848
                '&lt;',
849
                "foo\nbar",
850
                $extractedColumnSpec,
851
            ],
852
        );
853
854
        $result = $this->parseString($result);
855
856
        $this->assertStringContainsString('<input type="hidden" name="fields_typeb" value="date">', $result);
857
858
        // case 5: (else -> bit)
859
        $column = new InsertEditColumn('f', 'bit', false, '', null, 'auto_increment', 20, false, false, false, false);
860
        $result = $this->callFunction(
861
            $this->insertEdit,
862
            InsertEdit::class,
863
            'getValueColumnForOtherDatatypes',
864
            [
865
                $column,
866
                'defchar',
867
                'a',
868
                'b',
869
                'c',
870
                '&lt;',
871
                '/',
872
                '&lt;',
873
                "foo\nbar",
874
                $extractedColumnSpec,
875
            ],
876
        );
877
878
        $result = $this->parseString($result);
879
880
        $this->assertStringContainsString('<input type="hidden" name="fields_typeb" value="bit">', $result);
881
882
        // case 6: (else -> uuid)
883
        $column = new InsertEditColumn('f', 'uuid', false, '', null, 'auto_increment', 20, false, false, false, false);
884
        $result = $this->callFunction(
885
            $this->insertEdit,
886
            InsertEdit::class,
887
            'getValueColumnForOtherDatatypes',
888
            [
889
                $column,
890
                'defchar',
891
                'a',
892
                'b',
893
                'c',
894
                '&lt;',
895
                '/',
896
                '&lt;',
897
                "foo\nbar",
898
                $extractedColumnSpec,
899
            ],
900
        );
901
902
        $result = $this->parseString($result);
903
904
        $this->assertStringContainsString('<input type="hidden" name="fields_typeb" value="uuid">', $result);
905
    }
906
907
    /**
908
     * Test for getColumnSize
909
     */
910
    public function testGetColumnSize(): void
911
    {
912
        $column = new InsertEditColumn(
913
            'f',
914
            'char(10)',
915
            false,
916
            '',
917
            null,
918
            'auto_increment',
919
            20,
920
            false,
921
            false,
922
            true,
923
            false,
924
        );
925
        $specInBrackets = '45';
926
        $GLOBALS['cfg']['MinSizeForInputField'] = 30;
927
        $GLOBALS['cfg']['MaxSizeForInputField'] = 40;
928
929
        $this->assertEquals(
930
            40,
931
            $this->callFunction(
932
                $this->insertEdit,
933
                InsertEdit::class,
934
                'getColumnSize',
935
                [$column, $specInBrackets],
936
            ),
937
        );
938
939
        $this->assertEquals('textarea', $GLOBALS['cfg']['CharEditing']);
940
941
        // case 2
942
        $column = new InsertEditColumn(
943
            'f',
944
            'char(10)',
945
            false,
946
            '',
947
            null,
948
            'auto_increment',
949
            20,
950
            false,
951
            false,
952
            false,
953
            false,
954
        );
955
        $this->assertEquals(
956
            30,
957
            $this->callFunction(
958
                $this->insertEdit,
959
                InsertEdit::class,
960
                'getColumnSize',
961
                [$column, $specInBrackets],
962
            ),
963
        );
964
    }
965
966
    /**
967
     * Test for getContinueInsertionForm
968
     */
969
    public function testGetContinueInsertionForm(): void
970
    {
971
        $whereClauseArray = ['a<b'];
972
        $GLOBALS['cfg']['InsertRows'] = 1;
973
        $GLOBALS['cfg']['ServerDefault'] = 1;
974
        $GLOBALS['goto'] = 'index.php';
975
        $_POST['where_clause'] = true;
976
        $_POST['sql_query'] = 'SELECT 1';
977
978
        $result = $this->insertEdit->getContinueInsertionForm('tbl', 'db', $whereClauseArray, 'localhost');
979
980
        $this->assertStringContainsString(
981
            '<form id="continueForm" method="post" action="' . Url::getFromRoute('/table/replace')
982
            . '" name="continueForm">',
983
            $result,
984
        );
985
986
        $this->assertStringContainsString('<input type="hidden" name="db" value="db">', $result);
987
988
        $this->assertStringContainsString('<input type="hidden" name="table" value="tbl">', $result);
989
990
        $this->assertStringContainsString('<input type="hidden" name="goto" value="index.php">', $result);
991
992
        $this->assertStringContainsString('<input type="hidden" name="err_url" value="localhost">', $result);
993
994
        $this->assertStringContainsString('<input type="hidden" name="sql_query" value="SELECT 1">', $result);
995
996
        $this->assertStringContainsString('<input type="hidden" name="where_clause[0]" value="a&lt;b">', $result);
997
    }
998
999
    public function testIsWhereClauseNumeric(): void
1000
    {
1001
        $this->assertFalse(InsertEdit::isWhereClauseNumeric(null));
1002
        $this->assertFalse(InsertEdit::isWhereClauseNumeric(''));
1003
        $this->assertFalse(InsertEdit::isWhereClauseNumeric([]));
1004
        $this->assertTrue(InsertEdit::isWhereClauseNumeric('`actor`.`actor_id` = 1'));
1005
        $this->assertTrue(InsertEdit::isWhereClauseNumeric(['`actor`.`actor_id` = 1']));
1006
        $this->assertFalse(InsertEdit::isWhereClauseNumeric('`actor`.`first_name` = \'value\''));
1007
        $this->assertFalse(InsertEdit::isWhereClauseNumeric(['`actor`.`first_name` = \'value\'']));
1008
    }
1009
1010
    /**
1011
     * Test for getHeadAndFootOfInsertRowTable
1012
     */
1013
    public function testGetHeadAndFootOfInsertRowTable(): void
1014
    {
1015
        $GLOBALS['cfg']['ShowFieldTypesInDataEditView'] = true;
1016
        $GLOBALS['cfg']['ShowFunctionFields'] = true;
1017
        $GLOBALS['cfg']['ServerDefault'] = 1;
1018
        $urlParams = ['ShowFunctionFields' => 2];
1019
1020
        $result = $this->callFunction(
1021
            $this->insertEdit,
1022
            InsertEdit::class,
1023
            'getHeadAndFootOfInsertRowTable',
1024
            [$urlParams],
1025
        );
1026
1027
        $result = $this->parseString($result);
1028
1029
        $this->assertStringContainsString('index.php?route=/table/change', $result);
1030
1031
        $this->assertStringContainsString('ShowFunctionFields=1&ShowFieldTypesInDataEditView=0', $result);
1032
1033
        $this->assertStringContainsString('ShowFunctionFields=0&ShowFieldTypesInDataEditView=1', $result);
1034
    }
1035
1036
    /**
1037
     * Test for getSpecialCharsAndBackupFieldForExistingRow
1038
     */
1039
    public function testGetSpecialCharsAndBackupFieldForExistingRow(): void
1040
    {
1041
        $currentRow = $extractedColumnSpec = [];
1042
        $currentRow['f'] = null;
1043
        $_POST['default_action'] = 'insert';
1044
        $column = new InsertEditColumn(
1045
            'f',
1046
            'char(10)',
1047
            false,
1048
            'PRI',
1049
            null,
1050
            'fooauto_increment',
1051
            20,
1052
            false,
1053
            false,
1054
            true,
1055
            false,
1056
        );
1057
1058
        $result = $this->callFunction(
1059
            $this->insertEdit,
1060
            InsertEdit::class,
1061
            'getSpecialCharsAndBackupFieldForExistingRow',
1062
            [$currentRow, $column, [], [], 'a', false],
1063
        );
1064
1065
        $this->assertEquals(
1066
            [true, null, null, null, '<input type="hidden" name="fields_preva" value="">'],
1067
            $result,
1068
        );
1069
1070
        // Case 2 (bit)
1071
        unset($_POST['default_action']);
1072
1073
        $currentRow['f'] = '123';
1074
        $extractedColumnSpec['spec_in_brackets'] = '20';
1075
        $column = new InsertEditColumn(
1076
            'f',
1077
            'bit',
1078
            false,
1079
            'PRI',
1080
            null,
1081
            'fooauto_increment',
1082
            20,
1083
            false,
1084
            false,
1085
            true,
1086
            false,
1087
        );
1088
1089
        $result = $this->callFunction(
1090
            $this->insertEdit,
1091
            InsertEdit::class,
1092
            'getSpecialCharsAndBackupFieldForExistingRow',
1093
            [$currentRow, $column, $extractedColumnSpec, [], 'a', false],
1094
        );
1095
1096
        $this->assertEquals(
1097
            [false, '', '00000000000001111011', null, '<input type="hidden" name="fields_preva" value="123">'],
1098
            $result,
1099
        );
1100
1101
        $currentRow['f'] = 'abcd';
1102
        $result = $this->callFunction(
1103
            $this->insertEdit,
1104
            InsertEdit::class,
1105
            'getSpecialCharsAndBackupFieldForExistingRow',
1106
            [$currentRow, $column, $extractedColumnSpec, [], 'a', true],
1107
        );
1108
1109
        $this->assertEquals(
1110
            [false, '', 'abcd', null, '<input type="hidden" name="fields_preva" value="abcd">'],
1111
            $result,
1112
        );
1113
1114
        // Case 3 (bit)
1115
        $dbi = $this->getMockBuilder(DatabaseInterface::class)
1116
            ->disableOriginalConstructor()
1117
            ->getMock();
1118
1119
        $GLOBALS['dbi'] = $dbi;
1120
        $this->insertEdit = new InsertEdit(
1121
            $GLOBALS['dbi'],
1122
            new Relation($GLOBALS['dbi']),
1123
            new Transformations(),
1124
            new FileListing(),
1125
            new Template(),
1126
        );
1127
1128
        $currentRow['f'] = '123';
1129
        $extractedColumnSpec['spec_in_brackets'] = '20';
1130
        $column = new InsertEditColumn(
1131
            'f',
1132
            'int',
1133
            false,
1134
            'PRI',
1135
            null,
1136
            'fooauto_increment',
1137
            20,
1138
            false,
1139
            false,
1140
            true,
1141
            false,
1142
        );
1143
1144
        $result = $this->callFunction(
1145
            $this->insertEdit,
1146
            InsertEdit::class,
1147
            'getSpecialCharsAndBackupFieldForExistingRow',
1148
            [$currentRow, $column, $extractedColumnSpec, ['int'], 'a', false],
1149
        );
1150
1151
        $this->assertEquals(
1152
            [false, '', "'',", null, '<input type="hidden" name="fields_preva" value="\'\',">'],
1153
            $result,
1154
        );
1155
1156
        // Case 4 (else)
1157
        $column = new InsertEditColumn(
1158
            'f',
1159
            'char',
1160
            false,
1161
            'PRI',
1162
            null,
1163
            'fooauto_increment',
1164
            20,
1165
            false,
1166
            true,
1167
            true,
1168
            false,
1169
        );
1170
        $GLOBALS['cfg']['ProtectBinary'] = false;
1171
        $currentRow['f'] = '11001';
1172
        $extractedColumnSpec['spec_in_brackets'] = '20';
1173
        $GLOBALS['cfg']['ShowFunctionFields'] = true;
1174
1175
        $result = $this->callFunction(
1176
            $this->insertEdit,
1177
            InsertEdit::class,
1178
            'getSpecialCharsAndBackupFieldForExistingRow',
1179
            [$currentRow, $column, $extractedColumnSpec, ['int'], 'a', false],
1180
        );
1181
1182
        $this->assertEquals(
1183
            [
1184
                false,
1185
                '3131303031',
1186
                '3131303031',
1187
                '3131303031',
1188
                '<input type="hidden" name="fields_preva" value="3131303031">',
1189
            ],
1190
            $result,
1191
        );
1192
1193
        // Case 5
1194
        $currentRow['f'] = "11001\x00";
1195
1196
        $result = $this->callFunction(
1197
            $this->insertEdit,
1198
            InsertEdit::class,
1199
            'getSpecialCharsAndBackupFieldForExistingRow',
1200
            [$currentRow, $column, $extractedColumnSpec, ['int'], 'a', false],
1201
        );
1202
1203
        $this->assertEquals(
1204
            [
1205
                false,
1206
                '313130303100',
1207
                '313130303100',
1208
                '313130303100',
1209
                '<input type="hidden" name="fields_preva" value="313130303100">',
1210
            ],
1211
            $result,
1212
        );
1213
    }
1214
1215
    /**
1216
     * Test for getSpecialCharsForInsertingMode
1217
     *
1218
     * @dataProvider providerForTestGetSpecialCharsForInsertingMode
1219
     */
1220
    public function testGetSpecialCharsForInsertingMode(
1221
        string|null $defaultValue,
1222
        string $trueType,
1223
        string $expected,
1224
    ): void {
1225
        $GLOBALS['cfg']['ProtectBinary'] = false;
1226
        $GLOBALS['cfg']['ShowFunctionFields'] = true;
1227
1228
        /** @var string $result */
1229
        $result = $this->callFunction(
1230
            $this->insertEdit,
1231
            InsertEdit::class,
1232
            'getSpecialCharsForInsertingMode',
1233
            [$defaultValue, $trueType],
1234
        );
1235
1236
        $this->assertEquals($expected, $result);
1237
    }
1238
1239
    /**
1240
     * Data provider for test getSpecialCharsForInsertingMode()
1241
     *
1242
     * @return array<string, array{string|null, string, string}>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string, array{string|null, string, string}> at position 6 could not be parsed: Expected ':' at position 6, but found 'string'.
Loading history...
1243
     */
1244
    public static function providerForTestGetSpecialCharsForInsertingMode(): array
1245
    {
1246
        return [
1247
            'bit' => [
1248
                'b\'101\'',
1249
                'bit',
1250
                '101',
1251
            ],
1252
            'char' => [
1253
                null,
1254
                'char',
1255
                '',
1256
            ],
1257
            'time with CURRENT_TIMESTAMP value' => [
1258
                'CURRENT_TIMESTAMP',
1259
                'time',
1260
                'CURRENT_TIMESTAMP',
1261
            ],
1262
            'time with current_timestamp() value' => [
1263
                'current_timestamp()',
1264
                'time',
1265
                'current_timestamp()',
1266
            ],
1267
            'time with no dot value' => [
1268
                '10',
1269
                'time',
1270
                '10.000000',
1271
            ],
1272
            'time with dot value' => [
1273
                '10.08',
1274
                'time',
1275
                '10.080000',
1276
            ],
1277
            'any text with escape text default' => [
1278
                '"lorem\"ipsem"',
1279
                'text',
1280
                'lorem"ipsem',
1281
            ],
1282
            'varchar with html special chars' => [
1283
                'hello world<br><b>lorem</b> ipsem',
1284
                'varchar',
1285
                'hello world&lt;br&gt;&lt;b&gt;lorem&lt;/b&gt; ipsem',
1286
            ],
1287
        ];
1288
    }
1289
1290
    /**
1291
     * Test for setSessionForEditNext
1292
     */
1293
    public function testSetSessionForEditNext(): void
1294
    {
1295
        $meta = FieldHelper::fromArray([
1296
            'type' => MYSQLI_TYPE_DECIMAL,
1297
            'flags' => MYSQLI_PRI_KEY_FLAG,
1298
            'orgname' => 'orgname',
1299
            'table' => 'table',
1300
            'orgtable' => 'table',
1301
        ]);
1302
1303
        $row = ['1' => 1];
1304
1305
        $resultStub = $this->createMock(DummyResult::class);
1306
1307
        $dbi = $this->getMockBuilder(DatabaseInterface::class)
1308
            ->disableOriginalConstructor()
1309
            ->getMock();
1310
1311
        $dbi->expects($this->once())
1312
            ->method('query')
1313
            ->with('SELECT * FROM `db`.`table` WHERE `a` > 2 LIMIT 1;')
1314
            ->will($this->returnValue($resultStub));
1315
1316
        $resultStub->expects($this->once())
1317
            ->method('fetchRow')
1318
            ->will($this->returnValue($row));
1319
1320
        $dbi->expects($this->once())
1321
            ->method('getFieldsMeta')
1322
            ->with($resultStub)
1323
            ->will($this->returnValue([$meta]));
1324
1325
        $GLOBALS['dbi'] = $dbi;
1326
        $GLOBALS['db'] = 'db';
1327
        $GLOBALS['table'] = 'table';
1328
        $this->insertEdit = new InsertEdit(
1329
            $GLOBALS['dbi'],
1330
            new Relation($GLOBALS['dbi']),
1331
            new Transformations(),
1332
            new FileListing(),
1333
            new Template(),
1334
        );
1335
        $this->insertEdit->setSessionForEditNext('`a` = 2');
1336
1337
        $this->assertEquals('CONCAT(`table`.`orgname`) IS NULL', $_SESSION['edit_next']);
1338
    }
1339
1340
    /**
1341
     * Test for getGotoInclude
1342
     */
1343
    public function testGetGotoInclude(): void
1344
    {
1345
        $GLOBALS['goto'] = '123.php';
1346
        $GLOBALS['table'] = '';
1347
1348
        $this->assertEquals(
1349
            '/database/sql',
1350
            $this->insertEdit->getGotoInclude('index'),
1351
        );
1352
1353
        $GLOBALS['table'] = 'tbl';
1354
        $this->assertEquals(
1355
            '/table/sql',
1356
            $this->insertEdit->getGotoInclude('index'),
1357
        );
1358
1359
        $GLOBALS['goto'] = 'index.php?route=/database/sql';
1360
1361
        $this->assertEquals(
1362
            '/database/sql',
1363
            $this->insertEdit->getGotoInclude('index'),
1364
        );
1365
1366
        $this->assertEquals('', $GLOBALS['table']);
1367
1368
        $_POST['after_insert'] = 'new_insert';
1369
        $this->assertEquals(
1370
            '/table/change',
1371
            $this->insertEdit->getGotoInclude('index'),
1372
        );
1373
    }
1374
1375
    /**
1376
     * Test for getErrorUrl
1377
     */
1378
    public function testGetErrorUrl(): void
1379
    {
1380
        $GLOBALS['cfg']['ServerDefault'] = 1;
1381
        $this->assertEquals(
1382
            'index.php?route=/table/change&lang=en',
1383
            $this->insertEdit->getErrorUrl([]),
1384
        );
1385
1386
        $_POST['err_url'] = 'localhost';
1387
        $this->assertEquals(
1388
            'localhost',
1389
            $this->insertEdit->getErrorUrl([]),
1390
        );
1391
    }
1392
1393
    /**
1394
     * Test for executeSqlQuery
1395
     */
1396
    public function testExecuteSqlQuery(): void
1397
    {
1398
        $query = ['SELECT * FROM `test_db`.`test_table`;', 'SELECT * FROM `test_db`.`test_table_yaml`;'];
1399
        $GLOBALS['cfg']['IgnoreMultiSubmitErrors'] = false;
1400
        $_POST['submit_type'] = '';
1401
1402
        $this->insertEdit = new InsertEdit(
1403
            $GLOBALS['dbi'],
1404
            new Relation($GLOBALS['dbi']),
1405
            new Transformations(),
1406
            new FileListing(),
1407
            new Template(),
1408
        );
1409
        $result = $this->insertEdit->executeSqlQuery($query);
1410
1411
        $this->assertEquals([], $result[3]);
1412
    }
1413
1414
    /**
1415
     * Test for executeSqlQuery
1416
     */
1417
    public function testExecuteSqlQueryWithTryQuery(): void
1418
    {
1419
        $query = ['SELECT * FROM `test_db`.`test_table`;', 'SELECT * FROM `test_db`.`test_table_yaml`;'];
1420
        $GLOBALS['cfg']['IgnoreMultiSubmitErrors'] = true;
1421
        $_POST['submit_type'] = '';
1422
1423
        $this->insertEdit = new InsertEdit(
1424
            $GLOBALS['dbi'],
1425
            new Relation($GLOBALS['dbi']),
1426
            new Transformations(),
1427
            new FileListing(),
1428
            new Template(),
1429
        );
1430
        $result = $this->insertEdit->executeSqlQuery($query);
1431
1432
        $this->assertEquals([], $result[3]);
1433
    }
1434
1435
    /**
1436
     * Test for getWarningMessages
1437
     */
1438
    public function testGetWarningMessages(): void
1439
    {
1440
        $warnings = [
1441
            Warning::fromArray(['Level' => 'Error', 'Code' => '1001', 'Message' => 'Message 1']),
1442
            Warning::fromArray(['Level' => 'Warning', 'Code' => '1002', 'Message' => 'Message 2']),
1443
        ];
1444
1445
        $dbi = $this->getMockBuilder(DatabaseInterface::class)
1446
            ->disableOriginalConstructor()
1447
            ->getMock();
1448
1449
        $dbi->expects($this->once())
1450
            ->method('getWarnings')
1451
            ->will($this->returnValue($warnings));
1452
1453
        $GLOBALS['dbi'] = $dbi;
1454
        $this->insertEdit = new InsertEdit(
1455
            $GLOBALS['dbi'],
1456
            new Relation($GLOBALS['dbi']),
1457
            new Transformations(),
1458
            new FileListing(),
1459
            new Template(),
1460
        );
1461
1462
        $result = (array) $this->callFunction(
1463
            $this->insertEdit,
1464
            InsertEdit::class,
1465
            'getWarningMessages',
1466
            [],
1467
        );
1468
1469
        $this->assertEquals(['Error: #1001 Message 1', 'Warning: #1002 Message 2'], $result);
1470
    }
1471
1472
    /**
1473
     * Test for getDisplayValueForForeignTableColumn
1474
     */
1475
    public function testGetDisplayValueForForeignTableColumn(): void
1476
    {
1477
        $map = [];
1478
        $map['f']['foreign_db'] = 'information_schema';
1479
        $map['f']['foreign_table'] = 'TABLES';
1480
        $map['f']['foreign_field'] = 'f';
1481
1482
        $resultStub = $this->createMock(DummyResult::class);
1483
1484
        $dbi = $this->getMockBuilder(DatabaseInterface::class)
1485
            ->disableOriginalConstructor()
1486
            ->getMock();
1487
1488
        $dbi->expects($this->once())
1489
            ->method('tryQuery')
1490
            ->with('SELECT `TABLE_COMMENT` FROM `information_schema`.`TABLES` WHERE `f`=1')
1491
            ->will($this->returnValue($resultStub));
1492
1493
        $resultStub->expects($this->once())
1494
            ->method('numRows')
1495
            ->will($this->returnValue(2));
1496
1497
        $resultStub->expects($this->once())
1498
            ->method('fetchValue')
1499
            ->with(0)
1500
            ->will($this->returnValue('2'));
1501
1502
        $GLOBALS['dbi'] = $dbi;
1503
        $this->insertEdit = new InsertEdit(
1504
            $GLOBALS['dbi'],
1505
            new Relation($GLOBALS['dbi']),
1506
            new Transformations(),
1507
            new FileListing(),
1508
            new Template(),
1509
        );
1510
1511
        $result = $this->insertEdit->getDisplayValueForForeignTableColumn('=1', $map, 'f');
1512
1513
        $this->assertEquals(2, $result);
1514
    }
1515
1516
    /**
1517
     * Test for getLinkForRelationalDisplayField
1518
     */
1519
    public function testGetLinkForRelationalDisplayField(): void
1520
    {
1521
        $GLOBALS['cfg']['ServerDefault'] = 1;
1522
        $_SESSION['tmpval']['relational_display'] = 'K';
1523
        $map = [];
1524
        $map['f']['foreign_db'] = 'information_schema';
1525
        $map['f']['foreign_table'] = 'TABLES';
1526
        $map['f']['foreign_field'] = 'f';
1527
1528
        $result = $this->insertEdit->getLinkForRelationalDisplayField($map, 'f', '=1', 'a>', 'b<');
1529
1530
        $sqlSignature = Core::signSqlQuery('SELECT * FROM `information_schema`.`TABLES` WHERE `f`=1');
1531
1532
        $this->assertEquals(
1533
            '<a href="index.php?route=/sql&db=information_schema&table=TABLES&pos=0&'
1534
            . 'sql_signature=' . $sqlSignature . '&'
1535
            . 'sql_query=SELECT+%2A+FROM+%60information_schema%60.%60TABLES%60+WHERE'
1536
            . '+%60f%60%3D1&lang=en" title="a&gt;">b&lt;</a>',
1537
            $result,
1538
        );
1539
1540
        $_SESSION['tmpval']['relational_display'] = 'D';
1541
        $result = $this->insertEdit->getLinkForRelationalDisplayField($map, 'f', '=1', 'a>', 'b<');
1542
1543
        $this->assertEquals(
1544
            '<a href="index.php?route=/sql&db=information_schema&table=TABLES&pos=0&'
1545
            . 'sql_signature=' . $sqlSignature . '&'
1546
            . 'sql_query=SELECT+%2A+FROM+%60information_schema%60.%60TABLES%60+WHERE'
1547
            . '+%60f%60%3D1&lang=en" title="b&lt;">a&gt;</a>',
1548
            $result,
1549
        );
1550
    }
1551
1552
    /**
1553
     * Test for transformEditedValues
1554
     */
1555
    public function testTransformEditedValues(): void
1556
    {
1557
        $_SESSION[' HMAC_secret '] = hash('sha1', 'test');
1558
        $editedValues = [['c' => 'cname']];
1559
        $GLOBALS['cfg']['DefaultTransformations']['PreApPend'] = ['', ''];
1560
        $GLOBALS['cfg']['ServerDefault'] = 1;
1561
        $_POST['where_clause'] = '1';
1562
        $_POST['where_clause_sign'] = Core::signSqlQuery($_POST['where_clause']);
1563
        $transformation = ['transformation_options' => "'','option ,, quoted',abd"];
1564
        $result = $this->insertEdit->transformEditedValues(
1565
            'db',
1566
            'table',
1567
            $transformation,
1568
            $editedValues,
1569
            'Text_Plain_PreApPend.php',
1570
            'c',
1571
            ['a' => 'b'],
1572
            'transformation',
1573
        );
1574
1575
        $this->assertEquals(
1576
            ['a' => 'b', 'transformations' => ['cnameoption ,, quoted']],
1577
            $result,
1578
        );
1579
    }
1580
1581
    /**
1582
     * Test for getQueryValuesForInsert
1583
     */
1584
    public function testGetQueryValuesForInsert(): void
1585
    {
1586
        // Simple insert
1587
        $result = $this->insertEdit->getQueryValueForInsert(
1588
            new EditField(
1589
                'fld',
1590
                'foo',
1591
                '',
1592
                false,
1593
                false,
1594
                false,
1595
                '',
1596
                null,
1597
                null,
1598
                false,
1599
            ),
1600
            false,
1601
            '',
1602
        );
1603
        $this->assertEquals("'foo'", $result);
1604
1605
        // Test for file upload
1606
        $result = $this->insertEdit->getQueryValueForInsert(
1607
            new EditField(
1608
                '',
1609
                '0x123',
1610
                '',
1611
                false,
1612
                false,
1613
                false,
1614
                '',
1615
                null,
1616
                null,
1617
                true,
1618
            ),
1619
            false,
1620
            '',
1621
        );
1622
1623
        $this->assertEquals('0x123', $result);
1624
1625
        // Test functions
1626
        $this->dummyDbi->addResult(
1627
            'SELECT UUID()',
1628
            [
1629
                ['uuid1234'],// Minimal working setup for 2FA
1630
            ],
1631
        );
1632
1633
        // case 1
1634
        $result = $this->insertEdit->getQueryValueForInsert(
1635
            new EditField(
1636
                '',
1637
                '',
1638
                '',
1639
                false,
1640
                false,
1641
                false,
1642
                'UUID',
1643
                null,
1644
                null,
1645
                false,
1646
            ),
1647
            false,
1648
            '',
1649
        );
1650
1651
        $this->assertEquals("'uuid1234'", $result);
1652
1653
        // case 2
1654
        $result = $this->insertEdit->getQueryValueForInsert(
1655
            new EditField(
1656
                '',
1657
                "'",
1658
                '',
1659
                false,
1660
                false,
1661
                false,
1662
                'AES_ENCRYPT',
1663
                '',
1664
                null,
1665
                false,
1666
            ),
1667
            false,
1668
            '',
1669
        );
1670
        $this->assertEquals("AES_ENCRYPT('\\'','')", $result);
1671
1672
        // case 3
1673
        $result = $this->insertEdit->getQueryValueForInsert(
1674
            new EditField(
1675
                '',
1676
                "'",
1677
                '',
1678
                false,
1679
                false,
1680
                false,
1681
                'ABS',
1682
                null,
1683
                null,
1684
                false,
1685
            ),
1686
            false,
1687
            '',
1688
        );
1689
        $this->assertEquals("ABS('\\'')", $result);
1690
1691
        // case 4
1692
        $result = $this->insertEdit->getQueryValueForInsert(
1693
            new EditField(
1694
                '',
1695
                '',
1696
                '',
1697
                false,
1698
                false,
1699
                false,
1700
                'RAND',
1701
                null,
1702
                null,
1703
                false,
1704
            ),
1705
            false,
1706
            '',
1707
        );
1708
        $this->assertEquals('RAND()', $result);
1709
1710
        // case 5
1711
        $result = $this->insertEdit->getQueryValueForInsert(
1712
            new EditField(
1713
                '',
1714
                "a'c",
1715
                '',
1716
                false,
1717
                false,
1718
                false,
1719
                'PHP_PASSWORD_HASH',
1720
                null,
1721
                null,
1722
                false,
1723
            ),
1724
            false,
1725
            '',
1726
        );
1727
        $this->assertTrue(password_verify("a'c", mb_substr($result, 1, -1)));
1728
1729
        // case 7
1730
        $result = $this->insertEdit->getQueryValueForInsert(
1731
            new EditField('', "'POINT(3 4)',4326", '', true, false, false, 'ST_GeomFromText', null, null, false),
1732
            false,
1733
            '',
1734
        );
1735
        $this->assertEquals('ST_GeomFromText(\'POINT(3 4)\',4326)', $result);
1736
1737
        // case 8
1738
        $result = $this->insertEdit->getQueryValueForInsert(
1739
            new EditField('', 'POINT(3 4),4326', '', true, false, false, 'ST_GeomFromText', null, null, false),
1740
            false,
1741
            '',
1742
        );
1743
        $this->assertEquals('ST_GeomFromText(\'POINT(3 4)\',4326)', $result);
1744
1745
        // case 9
1746
        $result = $this->insertEdit->getQueryValueForInsert(
1747
            new EditField('', "'POINT(3 4)'", '', true, false, false, 'ST_GeomFromText', null, null, false),
1748
            false,
1749
            '',
1750
        );
1751
        $this->assertEquals('ST_GeomFromText(\'POINT(3 4)\')', $result);
1752
1753
        // case 10
1754
        $result = $this->insertEdit->getQueryValueForInsert(
1755
            new EditField('', 'POINT(3 4)', '', true, false, false, 'ST_GeomFromText', null, null, false),
1756
            false,
1757
            '',
1758
        );
1759
        $this->assertEquals('ST_GeomFromText(\'POINT(3 4)\')', $result);
1760
1761
        // Test different data types
1762
1763
        // Datatype: protected copied from the databse
1764
        $GLOBALS['table'] = 'test_table';
1765
        $result = $this->insertEdit->getQueryValueForInsert(
1766
            new EditField(
1767
                'name',
1768
                '',
1769
                'protected',
1770
                false,
1771
                false,
1772
                false,
1773
                '',
1774
                null,
1775
                null,
1776
                false,
1777
            ),
1778
            true,
1779
            '`id` = 4',
1780
        );
1781
        $this->assertEquals('0x313031', $result);
1782
1783
        // An empty value for auto increment column should be converted to NULL
1784
        $result = $this->insertEdit->getQueryValueForInsert(
1785
            new EditField(
1786
                '',
1787
                '', // empty for null
1788
                '',
1789
                true,
1790
                false,
1791
                false,
1792
                '',
1793
                null,
1794
                null,
1795
                false,
1796
            ),
1797
            false,
1798
            '',
1799
        );
1800
        $this->assertEquals('NULL', $result);
1801
1802
        // Simple empty value
1803
        $result = $this->insertEdit->getQueryValueForInsert(
1804
            new EditField(
1805
                '',
1806
                '',
1807
                '',
1808
                false,
1809
                false,
1810
                false,
1811
                '',
1812
                null,
1813
                null,
1814
                false,
1815
            ),
1816
            false,
1817
            '',
1818
        );
1819
        $this->assertEquals("''", $result);
1820
1821
        // Datatype: set
1822
        $result = $this->insertEdit->getQueryValueForInsert(
1823
            new EditField(
1824
                '',
1825
                '', // doesn't matter what the value is
1826
                'set',
1827
                false,
1828
                false,
1829
                false,
1830
                '',
1831
                null,
1832
                null,
1833
                false,
1834
            ),
1835
            false,
1836
            '',
1837
        );
1838
        $this->assertEquals("''", $result);
1839
1840
        // Datatype: protected with no value should produce an empty string
1841
        $result = $this->insertEdit->getQueryValueForInsert(
1842
            new EditField(
1843
                '',
1844
                '',
1845
                'protected',
1846
                false,
1847
                false,
1848
                false,
1849
                '',
1850
                null,
1851
                null,
1852
                false,
1853
            ),
1854
            false,
1855
            '',
1856
        );
1857
        $this->assertEquals('', $result);
1858
1859
        // Datatype: protected with null flag set
1860
        $result = $this->insertEdit->getQueryValueForInsert(
1861
            new EditField(
1862
                '',
1863
                '',
1864
                'protected',
1865
                false,
1866
                true,
1867
                false,
1868
                '',
1869
                null,
1870
                null,
1871
                false,
1872
            ),
1873
            false,
1874
            '',
1875
        );
1876
        $this->assertEquals('NULL', $result);
1877
1878
        // Datatype: bit
1879
        $result = $this->insertEdit->getQueryValueForInsert(
1880
            new EditField(
1881
                '',
1882
                '20\'12',
1883
                'bit',
1884
                false,
1885
                false,
1886
                false,
1887
                '',
1888
                null,
1889
                null,
1890
                false,
1891
            ),
1892
            false,
1893
            '',
1894
        );
1895
        $this->assertEquals("b'00010'", $result);
1896
1897
        // Datatype: date
1898
        $result = $this->insertEdit->getQueryValueForInsert(
1899
            new EditField(
1900
                '',
1901
                '20\'12',
1902
                'date',
1903
                false,
1904
                false,
1905
                false,
1906
                '',
1907
                null,
1908
                null,
1909
                false,
1910
            ),
1911
            false,
1912
            '',
1913
        );
1914
        $this->assertEquals("'20\\'12'", $result);
1915
1916
        // A NULL checkbox
1917
        $result = $this->insertEdit->getQueryValueForInsert(
1918
            new EditField(
1919
                '',
1920
                '',
1921
                'set',
1922
                false,
1923
                true,
1924
                false,
1925
                '',
1926
                null,
1927
                null,
1928
                false,
1929
            ),
1930
            false,
1931
            '',
1932
        );
1933
        $this->assertEquals('NULL', $result);
1934
1935
        // Datatype: protected but NULL checkbox was unchecked without uploading a file
1936
        $result = $this->insertEdit->getQueryValueForInsert(
1937
            new EditField(
1938
                '',
1939
                '',
1940
                'protected',
1941
                false,
1942
                false,
1943
                true, // was previously NULL
1944
                '',
1945
                null,
1946
                null,
1947
                false, // no upload
1948
            ),
1949
            false,
1950
            '',
1951
        );
1952
        $this->assertEquals("''", $result);
1953
1954
        // Datatype: date with default value
1955
        $result = $this->insertEdit->getQueryValueForInsert(
1956
            new EditField(
1957
                '',
1958
                'current_timestamp()',
1959
                'date',
1960
                false,
1961
                false,
1962
                true, // NULL should be ignored
1963
                '',
1964
                null,
1965
                null,
1966
                false,
1967
            ),
1968
            false,
1969
            '',
1970
        );
1971
        $this->assertEquals('current_timestamp()', $result);
1972
1973
        // Datatype: hex without 0x
1974
        $result = $this->insertEdit->getQueryValueForInsert(
1975
            new EditField(
1976
                '',
1977
                '222aaafff',
1978
                'hex',
1979
                false,
1980
                false,
1981
                false,
1982
                '',
1983
                null,
1984
                null,
1985
                false,
1986
            ),
1987
            false,
1988
            '',
1989
        );
1990
        $this->assertEquals('0x222aaafff', $result);
1991
1992
        // Datatype: hex with 0x
1993
        $result = $this->insertEdit->getQueryValueForInsert(
1994
            new EditField(
1995
                '',
1996
                '0x222aaafff',
1997
                'hex',
1998
                false,
1999
                false,
2000
                false,
2001
                '',
2002
                null,
2003
                null,
2004
                false,
2005
            ),
2006
            false,
2007
            '',
2008
        );
2009
        $this->assertEquals('0x222aaafff', $result);
2010
    }
2011
2012
    /**
2013
     * Test for getQueryValuesForUpdate
2014
     */
2015
    public function testGetQueryValuesForUpdate(): void
2016
    {
2017
        // Simple update
2018
        $result = $this->insertEdit->getQueryValueForUpdate(
2019
            new EditField(
2020
                'fld',
2021
                'foo',
2022
                '',
2023
                false,
2024
                false,
2025
                false,
2026
                '',
2027
                null,
2028
                null,
2029
                false,
2030
            ),
2031
        );
2032
        $this->assertEquals("`fld` = 'foo'", $result);
2033
2034
        // Update of null when it was null previously
2035
        $result = $this->insertEdit->getQueryValueForUpdate(
2036
            new EditField(
2037
                'fld',
2038
                '', // null fields will have no value
2039
                '',
2040
                false,
2041
                true,
2042
                true,
2043
                '',
2044
                null,
2045
                null,
2046
                false,
2047
            ),
2048
        );
2049
        $this->assertEquals('', $result);
2050
2051
        // Update of null when it was NOT null previously
2052
        $result = $this->insertEdit->getQueryValueForUpdate(
2053
            new EditField(
2054
                'fld',
2055
                '', // null fields will have no value
2056
                '',
2057
                false,
2058
                true,
2059
                false,
2060
                '',
2061
                null,
2062
                '', // in edit mode the previous value will be empty string
2063
                false,
2064
            ),
2065
        );
2066
        $this->assertEquals('`fld` = NULL', $result);
2067
2068
        // Update to NOT null when it was null previously
2069
        $result = $this->insertEdit->getQueryValueForUpdate(
2070
            new EditField(
2071
                'fld',
2072
                "ab'c",
2073
                '',
2074
                false,
2075
                false,
2076
                true,
2077
                '',
2078
                null,
2079
                null,
2080
                false,
2081
            ),
2082
        );
2083
        $this->assertEquals("`fld` = 'ab\'c'", $result);
2084
2085
        // Test to see if a zero-string is not ignored
2086
        $result = $this->insertEdit->getQueryValueForUpdate(
2087
            new EditField(
2088
                'fld',
2089
                '0', // zero-string provided as value
2090
                '',
2091
                false,
2092
                false,
2093
                false,
2094
                '',
2095
                null,
2096
                null,
2097
                false,
2098
            ),
2099
        );
2100
        $this->assertEquals("`fld` = '0'", $result);
2101
2102
        // Test to check if blob field that was left unchanged during edit will be ignored
2103
        $result = $this->insertEdit->getQueryValueForUpdate(
2104
            new EditField(
2105
                'fld',
2106
                '', // no value
2107
                'protected',
2108
                false,
2109
                false,
2110
                false,
2111
                '',
2112
                null,
2113
                null,
2114
                false,
2115
            ),
2116
        );
2117
        $this->assertEquals('', $result);
2118
2119
        // Test to see if a field will be ignored if it the value is unchanged
2120
        $result = $this->insertEdit->getQueryValueForUpdate(
2121
            new EditField(
2122
                'fld',
2123
                "a'b",
2124
                '',
2125
                false,
2126
                false,
2127
                false,
2128
                '',
2129
                null,
2130
                "a'b",
2131
                false,
2132
            ),
2133
        );
2134
2135
        $this->assertEquals('', $result);
2136
2137
        // Test that an empty value uses the uuid function to generate a value
2138
        $result = $this->insertEdit->getQueryValueForUpdate(
2139
            new EditField(
2140
                'fld',
2141
                "''",
2142
                'uuid',
2143
                false,
2144
                false,
2145
                false,
2146
                '',
2147
                null,
2148
                '',
2149
                false,
2150
            ),
2151
        );
2152
2153
        $this->assertEquals('`fld` = uuid()', $result);
2154
2155
        // Test that the uuid function as a value uses the uuid function to generate a value
2156
        $result = $this->insertEdit->getQueryValueForUpdate(
2157
            new EditField(
2158
                'fld',
2159
                "'uuid()'",
2160
                'uuid',
2161
                false,
2162
                false,
2163
                false,
2164
                '',
2165
                null,
2166
                '',
2167
                false,
2168
            ),
2169
        );
2170
2171
        $this->assertEquals('`fld` = uuid()', $result);
2172
2173
        // Test that the uuid function as a value uses the uuid function to generate a value
2174
        $result = $this->insertEdit->getQueryValueForUpdate(
2175
            new EditField(
2176
                'fld',
2177
                'uuid()',
2178
                'uuid',
2179
                false,
2180
                false,
2181
                false,
2182
                '',
2183
                null,
2184
                '',
2185
                false,
2186
            ),
2187
        );
2188
2189
        $this->assertEquals('`fld` = uuid()', $result);
2190
2191
        // Test that the uuid type does not have a default value other than null when it is nullable
2192
        $result = $this->insertEdit->getQueryValueForUpdate(
2193
            new EditField(
2194
                'fld',
2195
                '',
2196
                'uuid',
2197
                false,
2198
                true,
2199
                false,
2200
                '',
2201
                null,
2202
                '',
2203
                false,
2204
            ),
2205
        );
2206
2207
        $this->assertEquals('`fld` = NULL', $result);
2208
    }
2209
2210
    /**
2211
     * Test for verifyWhetherValueCanBeTruncatedAndAppendExtraData
2212
     */
2213
    public function testVerifyWhetherValueCanBeTruncatedAndAppendExtraData(): void
2214
    {
2215
        $extraData = ['isNeedToRecheck' => true];
2216
2217
        $_POST['where_clause'] = [];
2218
        $_POST['where_clause'][0] = 1;
2219
2220
        $dbi = $this->getMockBuilder(DatabaseInterface::class)
2221
            ->disableOriginalConstructor()
2222
            ->getMock();
2223
2224
        $resultStub = $this->createMock(DummyResult::class);
2225
2226
        $dbi->expects($this->exactly(3))
2227
            ->method('tryQuery')
2228
            ->with('SELECT `table`.`a` FROM `db`.`table` WHERE 1')
2229
            ->willReturn($resultStub);
2230
2231
        $meta1 = FieldHelper::fromArray(['type' => MYSQLI_TYPE_TINY]);
2232
        $meta2 = FieldHelper::fromArray(['type' => MYSQLI_TYPE_TINY]);
2233
        $meta3 = FieldHelper::fromArray(['type' => MYSQLI_TYPE_TIMESTAMP]);
2234
        $dbi->expects($this->exactly(3))
2235
            ->method('getFieldsMeta')
2236
            ->will($this->onConsecutiveCalls([$meta1], [$meta2], [$meta3]));
2237
2238
        $resultStub->expects($this->exactly(3))
2239
            ->method('fetchValue')
2240
            ->will($this->onConsecutiveCalls(false, '123', '2013-08-28 06:34:14'));
2241
2242
        $GLOBALS['dbi'] = $dbi;
2243
        $this->insertEdit = new InsertEdit(
2244
            $GLOBALS['dbi'],
2245
            new Relation($GLOBALS['dbi']),
2246
            new Transformations(),
2247
            new FileListing(),
2248
            new Template(),
2249
        );
2250
2251
        $this->insertEdit->verifyWhetherValueCanBeTruncatedAndAppendExtraData('db', 'table', 'a', $extraData);
2252
2253
        $this->assertFalse($extraData['isNeedToRecheck']);
2254
2255
        $this->insertEdit->verifyWhetherValueCanBeTruncatedAndAppendExtraData('db', 'table', 'a', $extraData);
2256
2257
        $this->assertEquals('123', $extraData['truncatableFieldValue']);
2258
        $this->assertTrue($extraData['isNeedToRecheck']);
2259
2260
        $this->insertEdit->verifyWhetherValueCanBeTruncatedAndAppendExtraData('db', 'table', 'a', $extraData);
2261
2262
        $this->assertEquals('2013-08-28 06:34:14.000000', $extraData['truncatableFieldValue']);
2263
        $this->assertTrue($extraData['isNeedToRecheck']);
2264
    }
2265
2266
    /**
2267
     * Test for getTableColumns
2268
     */
2269
    public function testGetTableColumns(): void
2270
    {
2271
        $dbi = $this->getMockBuilder(DatabaseInterface::class)
2272
            ->disableOriginalConstructor()
2273
            ->getMock();
2274
2275
        $dbi->expects($this->once())
2276
            ->method('selectDb')
2277
            ->with('db');
2278
2279
        $dbi->expects($this->once())
2280
            ->method('getColumns')
2281
            ->with('db', 'table')
2282
            ->will($this->returnValue([
2283
                [
2284
                    'Field' => 'b',
2285
                    'Type' => 'd',
2286
                    'Collation' => null,
2287
                    'Null' => 'NO',
2288
                    'Key' => '',
2289
                    'Default' => null,
2290
                    'Extra' => '',
2291
                    'Privileges' => '',
2292
                    'Comment' => '',
2293
                ],
2294
                [
2295
                    'Field' => 'f',
2296
                    'Type' => 'h',
2297
                    'Collation' => null,
2298
                    'Null' => 'YES',
2299
                    'Key' => '',
2300
                    'Default' => null,
2301
                    'Extra' => '',
2302
                    'Privileges' => '',
2303
                    'Comment' => '',
2304
                ],
2305
            ]));
2306
2307
        $GLOBALS['dbi'] = $dbi;
2308
        $this->insertEdit = new InsertEdit(
2309
            $GLOBALS['dbi'],
2310
            new Relation($GLOBALS['dbi']),
2311
            new Transformations(),
2312
            new FileListing(),
2313
            new Template(),
2314
        );
2315
2316
        $result = $this->insertEdit->getTableColumns('db', 'table');
2317
2318
        $this->assertEquals(
2319
            [
2320
                new ColumnFull('b', 'd', null, false, '', null, '', '', ''),
2321
                new ColumnFull('f', 'h', null, true, '', null, '', '', ''),
2322
            ],
2323
            $result,
2324
        );
2325
    }
2326
2327
    /**
2328
     * Test for determineInsertOrEdit
2329
     */
2330
    public function testDetermineInsertOrEdit(): void
2331
    {
2332
        $dbi = $this->getMockBuilder(DatabaseInterface::class)
2333
            ->disableOriginalConstructor()
2334
            ->getMock();
2335
2336
        $resultStub = $this->createMock(DummyResult::class);
2337
2338
        $dbi->expects($this->exactly(2))
2339
            ->method('query')
2340
            ->will($this->returnValue($resultStub));
2341
2342
        $GLOBALS['dbi'] = $dbi;
2343
        $_POST['where_clause'] = '1';
2344
        $_SESSION['edit_next'] = '1';
2345
        $_POST['ShowFunctionFields'] = true;
2346
        $_POST['ShowFieldTypesInDataEditView'] = true;
2347
        $_POST['after_insert'] = 'edit_next';
2348
        $GLOBALS['cfg']['InsertRows'] = 2;
2349
        $GLOBALS['cfg']['ShowSQL'] = false;
2350
        $_POST['default_action'] = 'insert';
2351
2352
        $responseMock = $this->getMockBuilder(ResponseRenderer::class)
2353
            ->disableOriginalConstructor()
2354
            ->onlyMethods(['addHtml'])
2355
            ->getMock();
2356
2357
        $restoreInstance = ResponseRenderer::getInstance();
2358
        $response = new ReflectionProperty(ResponseRenderer::class, 'instance');
2359
        $response->setValue($responseMock);
2360
2361
        $this->insertEdit = new InsertEdit(
2362
            $GLOBALS['dbi'],
2363
            new Relation($GLOBALS['dbi']),
2364
            new Transformations(),
2365
            new FileListing(),
2366
            new Template(),
2367
        );
2368
2369
        $result = $this->insertEdit->determineInsertOrEdit('1', 'db', 'table');
2370
2371
        $this->assertEquals(
2372
            [false, null, [1], null, [$resultStub], [[]], false, 'edit_next'],
2373
            $result,
2374
        );
2375
2376
        // case 2
2377
        unset($_POST['where_clause']);
2378
        unset($_SESSION['edit_next']);
2379
        $_POST['default_action'] = '';
2380
2381
        $result = $this->insertEdit->determineInsertOrEdit(null, 'db', 'table');
2382
2383
        $response->setValue($restoreInstance);
2384
2385
        $this->assertEquals(
2386
            [true, null, [], null, $resultStub, [false, false], false, 'edit_next'],
2387
            $result,
2388
        );
2389
    }
2390
2391
    /**
2392
     * Test for getCommentsMap
2393
     */
2394
    public function testGetCommentsMap(): void
2395
    {
2396
        $GLOBALS['cfg']['ShowPropertyComments'] = false;
2397
2398
        $dbi = $this->getMockBuilder(DatabaseInterface::class)
2399
            ->disableOriginalConstructor()
2400
            ->getMock();
2401
2402
        $dbi->expects($this->once())
2403
            ->method('getColumns')
2404
            ->with('db', 'table', true)
2405
            ->will(
2406
                $this->returnValue(
2407
                    [['Comment' => 'b', 'Field' => 'd']],
2408
                ),
2409
            );
2410
2411
        $dbi->expects($this->any())
2412
            ->method('getTable')
2413
            ->will(
2414
                $this->returnValue(
2415
                    new Table('table', 'db', $GLOBALS['dbi']),
2416
                ),
2417
            );
2418
2419
        $GLOBALS['dbi'] = $dbi;
2420
        $this->insertEdit = new InsertEdit(
2421
            $GLOBALS['dbi'],
2422
            new Relation($GLOBALS['dbi']),
2423
            new Transformations(),
2424
            new FileListing(),
2425
            new Template(),
2426
        );
2427
2428
        $this->assertEquals(
2429
            [],
2430
            $this->insertEdit->getCommentsMap('db', 'table'),
2431
        );
2432
2433
        $GLOBALS['cfg']['ShowPropertyComments'] = true;
2434
2435
        $this->assertEquals(
2436
            ['d' => 'b'],
2437
            $this->insertEdit->getCommentsMap('db', 'table'),
2438
        );
2439
    }
2440
2441
    /**
2442
     * Test for getHtmlForIgnoreOption
2443
     */
2444
    public function testGetHtmlForIgnoreOption(): void
2445
    {
2446
        $expected = '<input type="checkbox" %sname="insert_ignore_1"'
2447
            . ' id="insert_ignore_1"><label for="insert_ignore_1">'
2448
            . 'Ignore</label><br>' . "\n";
2449
        $checked = 'checked="checked" ';
2450
        $this->assertEquals(
2451
            sprintf($expected, $checked),
2452
            $this->insertEdit->getHtmlForIgnoreOption(1),
2453
        );
2454
2455
        $this->assertEquals(
2456
            sprintf($expected, ''),
2457
            $this->insertEdit->getHtmlForIgnoreOption(1, false),
2458
        );
2459
    }
2460
2461
    /**
2462
     * Test for getHtmlForInsertEditFormColumn
2463
     */
2464
    public function testGetHtmlForInsertEditFormColumn(): void
2465
    {
2466
        $_SESSION[' HMAC_secret '] = hash('sha1', 'test');
2467
        $GLOBALS['plugin_scripts'] = [];
2468
        $foreigners = ['foreign_keys_data' => []];
2469
        $tableColumn = new ColumnFull('col', 'varchar(20)', null, true, '', null, '', 'insert,update,select', '');
2470
        $repopulate = [md5('col') => 'val'];
2471
        $columnMime = [
2472
            'input_transformation' => 'Input/Image_JPEG_Upload.php',
2473
            'input_transformation_options' => '150',
2474
        ];
2475
2476
        // Test w/ input transformation
2477
        $actual = $this->callFunction(
2478
            $this->insertEdit,
2479
            InsertEdit::class,
2480
            'getHtmlForInsertEditFormColumn',
2481
            [
2482
                $tableColumn,
2483
                0,
2484
                [],
2485
                -1,
2486
                false,
2487
                [],
2488
                0,
2489
                false,
2490
                $foreigners,
2491
                'table',
2492
                'db',
2493
                0,
2494
                '',
2495
                '',
2496
                $repopulate,
2497
                $columnMime,
2498
                '',
2499
            ],
2500
        );
2501
2502
        $actual = $this->parseString($actual);
2503
2504
        $this->assertStringContainsString('col', $actual);
2505
        $this->assertStringContainsString('<option>AES_ENCRYPT</option>', $actual);
2506
        $this->assertStringContainsString('<span class="column_type" dir="ltr">varchar(20)</span>', $actual);
2507
        $this->assertStringContainsString('<tr class="noclick">', $actual);
2508
        $this->assertStringContainsString('<span class="default_value hide">', $actual);
2509
        $this->assertStringContainsString('<img src="" width="150" height="100" alt="Image preview here">', $actual);
2510
        $this->assertStringContainsString(
2511
            '<input type="file" '
2512
            . 'name="fields_upload[multi_edit][0][d89e2ddb530bb8953b290ab0793aecb0]" '
2513
            . 'accept="image/*" '
2514
            . 'class="image-upload"'
2515
            . '>',
2516
            $actual,
2517
        );
2518
2519
        // Test w/o input_transformation
2520
        $tableColumn = new ColumnFull('qwerty', 'datetime', null, true, '', null, '', 'insert,update,select', '');
2521
        $repopulate = [md5('qwerty') => '12-10-14'];
2522
        $actual = $this->callFunction(
2523
            $this->insertEdit,
2524
            InsertEdit::class,
2525
            'getHtmlForInsertEditFormColumn',
2526
            [
2527
                $tableColumn,
2528
                0,
2529
                [],
2530
                -1,
2531
                true,
2532
                [],
2533
                0,
2534
                false,
2535
                $foreigners,
2536
                'table',
2537
                'db',
2538
                0,
2539
                '',
2540
                '',
2541
                $repopulate,
2542
                [],
2543
                '',
2544
            ],
2545
        );
2546
2547
        $actual = $this->parseString($actual);
2548
2549
        $this->assertStringContainsString('qwerty', $actual);
2550
        $this->assertStringContainsString('<option>UUID</option>', $actual);
2551
        $this->assertStringContainsString('<span class="column_type" dir="ltr">datetime</span>', $actual);
2552
        $this->assertStringContainsString(
2553
            '<input type="text" name="fields[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]" value="12-10-14.000000"',
2554
            $actual,
2555
        );
2556
2557
        $this->assertStringContainsString(
2558
            '<select name="funcs[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]"'
2559
            . ' onchange="return verificationsAfterFieldChange(\'d8578edf8458ce06fbc5bb76a58c5ca4\','
2560
            . ' \'0\', \'datetime\')" id="field_1_1">',
2561
            $actual,
2562
        );
2563
        $this->assertStringContainsString('<option>DATE</option>', $actual);
2564
2565
        $this->assertStringContainsString(
2566
            '<input type="hidden" name="fields_null_prev[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]">',
2567
            $actual,
2568
        );
2569
2570
        $this->assertStringContainsString(
2571
            '<input type="checkbox" class="checkbox_null"'
2572
            . ' name="fields_null[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]" id="field_1_2"'
2573
            . ' aria-label="Use the NULL value for this column.">',
2574
            $actual,
2575
        );
2576
2577
        $this->assertStringContainsString(
2578
            '<input type="hidden" class="nullify_code"'
2579
            . ' name="nullify_code[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]" value="5"',
2580
            $actual,
2581
        );
2582
2583
        $this->assertStringContainsString(
2584
            '<input type="hidden" class="hashed_field"'
2585
            . ' name="hashed_field[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]" '
2586
            . 'value="d8578edf8458ce06fbc5bb76a58c5ca4">',
2587
            $actual,
2588
        );
2589
2590
        $this->assertStringContainsString(
2591
            '<input type="hidden" class="multi_edit"'
2592
            . ' name="multi_edit[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]" value="[multi_edit][0]"',
2593
            $actual,
2594
        );
2595
    }
2596
2597
    /**
2598
     * Test for getHtmlForInsertEditRow
2599
     */
2600
    public function testGetHtmlForInsertEditRow(): void
2601
    {
2602
        $GLOBALS['plugin_scripts'] = [];
2603
        $GLOBALS['cfg']['LongtextDoubleTextarea'] = true;
2604
        $GLOBALS['cfg']['CharEditing'] = 'input';
2605
        $GLOBALS['cfg']['TextareaRows'] = 10;
2606
        $GLOBALS['cfg']['TextareaCols'] = 11;
2607
        $foreigners = ['foreign_keys_data' => []];
2608
        $tableColumns = [
2609
            new ColumnFull('test', 'longtext', null, true, '', null, '', 'select,insert,update,references', ''),
2610
        ];
2611
2612
        $resultStub = $this->createMock(DummyResult::class);
2613
        $resultStub->expects($this->any())
2614
            ->method('getFieldsMeta')
2615
            ->will($this->returnValue([FieldHelper::fromArray(['type' => 0, 'length' => -1])]));
2616
2617
        $actual = $this->insertEdit->getHtmlForInsertEditRow(
2618
            [],
2619
            $tableColumns,
2620
            [],
2621
            $resultStub,
2622
            false,
2623
            [],
2624
            false,
2625
            $foreigners,
2626
            'table',
2627
            'db',
2628
            0,
2629
            'ltr',
2630
            [],
2631
            ['wc'],
2632
        );
2633
        $this->assertStringContainsString('test', $actual);
2634
        $this->assertStringContainsString('<th>Column</th>', $actual);
2635
        $this->assertStringContainsString('<a', $actual);
2636
        $this->assertStringContainsString('<th class="w-50">Value</th>', $actual);
2637
        $this->assertStringContainsString('<span class="column_type" dir="ltr">longtext</span>', $actual);
2638
        $this->assertStringContainsString(
2639
            '<textarea name="fields[multi_edit][0][098f6bcd4621d373cade4e832627b4f6]" id="field_1_3"'
2640
                . ' data-type="CHAR" dir="ltr" rows="20" cols="22"',
2641
            $actual,
2642
        );
2643
    }
2644
2645
    /**
2646
     * Test for getHtmlForInsertEditRow based on the column privilges
2647
     */
2648
    public function testGetHtmlForInsertEditRowBasedOnColumnPrivileges(): void
2649
    {
2650
        $GLOBALS['plugin_scripts'] = [];
2651
        $GLOBALS['cfg']['LongtextDoubleTextarea'] = true;
2652
        $GLOBALS['cfg']['CharEditing'] = 'input';
2653
        $foreigners = ['foreign_keys_data' => []];
2654
2655
        // edit
2656
        $tableColumns = [
2657
            new ColumnFull('foo', 'longtext', null, true, '', null, '', 'select,insert,update,references', ''),
2658
            new ColumnFull('bar', 'longtext', null, true, '', null, '', 'select,insert,references', ''),
2659
        ];
2660
2661
        $resultStub = $this->createMock(DummyResult::class);
2662
        $resultStub->expects($this->any())
2663
            ->method('getFieldsMeta')
2664
            ->will($this->returnValue([
2665
                FieldHelper::fromArray(['type' => 0, 'length' => -1]),
2666
                FieldHelper::fromArray(['type' => 0, 'length' => -1]),
2667
                FieldHelper::fromArray(['type' => 0, 'length' => -1]),
2668
            ]));
2669
2670
        $actual = $this->insertEdit->getHtmlForInsertEditRow(
2671
            [],
2672
            $tableColumns,
2673
            [],
2674
            $resultStub,
2675
            false,
2676
            [],
2677
            false,
2678
            $foreigners,
2679
            'table',
2680
            'db',
2681
            0,
2682
            '',
2683
            [],
2684
            ['wc'],
2685
        );
2686
        $this->assertStringContainsString('foo', $actual);
2687
        $this->assertStringContainsString('bar', $actual);
2688
2689
        // insert
2690
        $tableColumns = [
2691
            new ColumnFull('foo', 'longtext', null, true, '', null, '', 'select,insert,update,references', ''),
2692
            new ColumnFull('bar', 'longtext', null, true, '', null, '', 'select,update,references', ''),
2693
            new ColumnFull('point', 'point', null, false, '', null, '', 'select,update,references', ''),
2694
        ];
2695
        $actual = $this->insertEdit->getHtmlForInsertEditRow(
2696
            [],
2697
            $tableColumns,
2698
            [],
2699
            $resultStub,
2700
            true,
2701
            [],
2702
            false,
2703
            $foreigners,
2704
            'table',
2705
            'db',
2706
            0,
2707
            '',
2708
            [],
2709
            ['wc'],
2710
        );
2711
        $this->assertStringContainsString('foo', $actual);
2712
        $this->assertStringContainsString(
2713
            '<textarea name="fields[multi_edit][0][37b51d194a7513e45b56f6524f2d51f2]"',
2714
            $actual,
2715
        );
2716
        $this->assertStringContainsString(
2717
            '<a href="#" target="_blank"><span class="text-nowrap"><img src="themes/dot.'
2718
            . 'gif" title="Edit/Insert" alt="Edit/Insert" class="icon ic_b_edit">&nbsp;Edit/Insert'
2719
            . '</span></a>',
2720
            $actual,
2721
        );
2722
    }
2723
2724
    /**
2725
     * Convert mixed type value to string
2726
     */
2727
    private function parseString(mixed $value): string
2728
    {
2729
        if (is_string($value)) {
2730
            return $value;
2731
        }
2732
2733
        if (is_object($value) || is_scalar($value)) {
2734
            return strval($value);
2735
        }
2736
2737
        return '';
2738
    }
2739
}
2740