TWFY_Database_TestCase::setUpBeforeClass()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
3
use PHPUnit\Framework\TestCase;
4
5
/**
6
 * Provides acceptance(ish) tests for API functions.
7
 */
8
abstract class TWFY_Database_TestCase extends TestCase {
9
    /**
10
     * database handle for database queries in tests
11
     */
12
    protected static $db;
13
14
    /**
15
     * Connects to the testing database.
16
     */
17
    public static function setUpBeforeClass(): void {
18
        $dsn = 'mysql:dbname=' . OPTION_TWFY_DB_NAME . ';charset=utf8';
19
        if (OPTION_TWFY_DB_HOST) {
20
            $dsn .= ';host=' . OPTION_TWFY_DB_HOST;
21
        }
22
        $username = OPTION_TWFY_DB_USER;
23
        $password = OPTION_TWFY_DB_PASS;
24
        $pdo = new PDO($dsn, $username, $password);
25
        self::$db = $pdo;
26
    }
27
28
    public function setUp(): void {
29
        parent::setUp();
30
        $dataset = $this->getDataSet();
0 ignored issues
show
Bug introduced by
The method getDataSet() does not exist on TWFY_Database_TestCase. Did you maybe mean getDataSetAsString()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

30
        /** @scrutinizer ignore-call */ 
31
        $dataset = $this->getDataSet();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Unused Code introduced by
The assignment to $dataset is dead and can be removed.
Loading history...
31
    }
32
33
    private $xmlFileContents;
34
35
    public function createMySQLXMLDataSet($xmlFile) {
36
        $this->xmlFileContents = \simplexml_load_file($xmlFile, 'SimpleXMLElement', LIBXML_COMPACT | LIBXML_PARSEHUGE);
37
        if (!$this->xmlFileContents) {
38
            $message = '';
39
            foreach (\libxml_get_errors() as $error) {
40
                $message .= \print_r($error, true);
41
            }
42
            throw new RuntimeException($message);
43
        }
44
45
        \libxml_clear_errors();
46
        $tableColumns = [];
47
        $tableValues  = [];
48
        $this->getTableInfo($tableColumns, $tableValues);
49
        $this->createTables($tableColumns, $tableValues);
50
    }
51
52
    protected function getTableInfo(array &$tableColumns, array &$tableValues): void {
53
        if ($this->xmlFileContents->getName() != 'mysqldump') {
54
            throw new RuntimeException('The root element of a MySQL XML data set file must be called <mysqldump>');
55
        }
56
57
        foreach ($this->xmlFileContents->xpath('./database/table_data') as $tableElement) {
58
            if (empty($tableElement['name'])) {
59
                throw new RuntimeException('<table_data> elements must include a name attribute');
60
            }
61
62
            $tableName = (string) $tableElement['name'];
63
64
            if (!isset($tableColumns[$tableName])) {
65
                $tableColumns[$tableName] = [];
66
            }
67
68
            if (!isset($tableValues[$tableName])) {
69
                $tableValues[$tableName] = [];
70
            }
71
72
            foreach ($tableElement->xpath('./row') as $rowElement) {
73
                $rowValues = [];
74
75
                foreach ($rowElement->xpath('./field') as $columnElement) {
76
                    if (empty($columnElement['name'])) {
77
                        throw new RuntimeException('<field> element name attributes cannot be empty');
78
                    }
79
80
                    $columnName = (string) $columnElement['name'];
81
82
                    if (!\in_array($columnName, $tableColumns[$tableName])) {
83
                        $tableColumns[$tableName][] = $columnName;
84
                    }
85
                }
86
87
                foreach ($tableColumns[$tableName] as $columnName) {
88
                    $fields = $rowElement->xpath('./field[@name="' . $columnName . '"]');
89
90
                    if (!isset($fields[0])) {
91
                        throw new RuntimeException(
92
                            \sprintf(
93
                                '%s column doesn\'t exist in current row for table %s',
94
                                $columnName,
95
                                $tableName
96
                            )
97
                        );
98
                    }
99
100
                    $column = $fields[0];
101
                    $attr   = $column->attributes('http://www.w3.org/2001/XMLSchema-instance');
102
103
                    if (isset($attr['type']) && (string) $attr['type'] === 'xs:hexBinary') {
104
                        $columnValue = \pack('H*', (string) $column);
105
                    } else {
106
                        $null        = isset($column['nil']) || isset($attr[0]);
107
                        $columnValue = $null ? null : (string) $column;
108
                    }
109
110
                    $rowValues[$columnName] = $columnValue;
111
                }
112
113
                $tableValues[$tableName][] = $rowValues;
114
            }
115
        }
116
117
        foreach ($this->xmlFileContents->xpath('./database/table_structure') as $tableElement) {
118
            if (empty($tableElement['name'])) {
119
                throw new RuntimeException('<table_structure> elements must include a name attribute');
120
            }
121
122
            $tableName = (string) $tableElement['name'];
123
124
            foreach ($tableElement->xpath('./field') as $fieldElement) {
125
                if (empty($fieldElement['Field']) && empty($fieldElement['field'])) {
126
                    throw new RuntimeException('<field> elements must include a Field attribute');
127
                }
128
129
                $columnName = (string) (empty($fieldElement['Field']) ? $fieldElement['field'] : $fieldElement['Field']);
130
131
                if (!\in_array($columnName, $tableColumns[$tableName])) {
132
                    $tableColumns[$tableName][] = $columnName;
133
                }
134
            }
135
        }
136
    }
137
138
    protected function createTables(array &$tableColumns, array &$tableValues): void {
0 ignored issues
show
Unused Code introduced by
The parameter $tableColumns is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

138
    protected function createTables(/** @scrutinizer ignore-unused */ array &$tableColumns, array &$tableValues): void {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
139
        foreach ($tableValues as $tableName => $values) {
140
            self::$db->query("TRUNCATE TABLE $tableName");
141
            foreach ($values as $value) {
142
                $sth = self::$db->prepare("INSERT INTO $tableName (`" . join('`,`', array_keys($value)) . "`) VALUES (" . str_repeat('?,', count($value) - 1) . '?)');
143
                $sth->execute(array_values($value));
144
            }
145
        }
146
    }
147
148
    protected function getRowCount($table, $where) {
149
        $sth = self::$db->prepare("SELECT COUNT(*) FROM $table WHERE $where");
150
        $sth->execute();
151
        return $sth->fetch()[0];
152
    }
153
154
    public static function tearDownAfterClass(): void {
155
        self::$db = null;
156
    }
157
}
158