• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

RonasIT / laravel-helpers / 21712685344

05 Feb 2026 01:07PM UTC coverage: 78.576% (+0.1%) from 78.453%
21712685344

Pull #240

github

web-flow
Merge 7473a6bb4 into bcac70ab6
Pull Request #240: fix: checking the state of a database with a binary field.

13 of 14 new or added lines in 1 file covered. (92.86%)

1148 of 1461 relevant lines covered (78.58%)

13.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.36
/src/Testing/TableTestState.php
1
<?php
2

3
namespace RonasIT\Support\Testing;
4

5
use Illuminate\Support\Arr;
6
use Illuminate\Support\Collection;
7
use Illuminate\Support\Facades\DB;
8
use Illuminate\Support\Str;
9
use PHPUnit\Framework\Assert;
10
use RonasIT\Support\Traits\FixturesTrait;
11

12
class TableTestState extends Assert
13
{
14
    use FixturesTrait;
15

16
    protected string $tableName;
17
    protected array $jsonFields;
18
    protected ?string $connectionName;
19
    protected Collection $state;
20

21
    public function __construct(
22
        string $tableName,
23
        array $jsonFields = [],
24
        ?string $connectionName = null,
25
    ) {
26
        $this->tableName = $tableName;
14✔
27
        $this->jsonFields = $jsonFields;
14✔
28
        $this->connectionName = $connectionName ?? DB::getDefaultConnection();
14✔
29
        $this->state = $this->getDataSet($tableName);
14✔
30
    }
31

32
    public function assertNotChanged(): void
33
    {
34
        $changes = $this->getChanges();
2✔
35

36
        $this->assertEquals([
2✔
37
            'updated' => [],
2✔
38
            'created' => [],
2✔
39
            'deleted' => [],
2✔
40
        ], $changes);
2✔
41
    }
42

43
    public function assertChangesEqualsFixture(string $fixture, bool $exportMode = false): void
44
    {
45
        $changes = $this->getChanges();
6✔
46

47
        $this->assertEqualsFixture($fixture, $changes, $exportMode);
6✔
48
    }
49

50
    protected function getChanges(): array
51
    {
52
        $updatedData = $this->getDataSet($this->tableName);
8✔
53

54
        $updatedRecords = [];
8✔
55
        $deletedRecords = [];
8✔
56

57
        $this->state->each(function ($originItem) use (&$updatedData, &$updatedRecords, &$deletedRecords) {
8✔
58
            $updatedItemIndex = $updatedData->search(fn ($updatedItem) => $updatedItem['id'] === $originItem['id']);
8✔
59

60
            if ($updatedItemIndex === false) {
8✔
61
                $deletedRecords[] = $originItem;
4✔
62
            } else {
63
                $updatedItem = $updatedData->get($updatedItemIndex);
8✔
64
                $changes = array_diff_assoc($updatedItem, $originItem);
8✔
65

66
                if (!empty($changes)) {
8✔
67
                    $changes = Arr::map($changes, fn ($field) => ($this->isBinary($field)) ? bin2hex($field) : $field);
6✔
68

69
                    $updatedRecords[] = array_merge(['id' => $originItem['id']], $changes);
6✔
70
                }
71

72
                $updatedData->forget($updatedItemIndex);
8✔
73
            }
74
        });
8✔
75

76
        return [
8✔
77
            'updated' => $this->prepareChanges($updatedRecords),
8✔
78
            'created' => $this->prepareChanges($updatedData->values()->toArray()),
8✔
79
            'deleted' => $this->prepareChanges($deletedRecords),
8✔
80
        ];
8✔
81
    }
82

83
    protected function isBinary(mixed $value): bool
84
    {
85
        if (!is_string($value) || $value === '') {
6✔
86
            return false;
1✔
87
        }
88

89
        if (str_contains($value, "\0")) {
5✔
NEW
90
            return true;
×
91
        }
92

93
        $sample = substr($value, 0, 8192);
5✔
94

95
        if (strlen($sample) === 0 || mb_check_encoding($sample, 'UTF-8')) {
5✔
96
            return false;
4✔
97
        }
98

99
        return preg_match('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', $sample)
1✔
100
            || !ctype_print($sample);
1✔
101
    }
102

103
    protected function prepareChanges(array $changes): array
104
    {
105
        $jsonFields = Arr::wrap($this->jsonFields);
8✔
106

107
        if (empty($jsonFields)) {
8✔
108
            return $changes;
2✔
109
        }
110

111
        return array_map(function ($item) use ($jsonFields) {
6✔
112
            foreach ($jsonFields as $jsonField) {
4✔
113
                $isJsonField = Arr::has($item, $jsonField)
4✔
114
                    && is_string($item[$jsonField])
4✔
115
                    && json_validate($item[$jsonField]);
4✔
116

117
                if ($isJsonField) {
4✔
118
                    $item[$jsonField] = json_decode($item[$jsonField], true);
2✔
119
                }
120
            }
121

122
            return $item;
4✔
123
        }, $changes);
6✔
124
    }
125

126
    protected function getFixturePath(string $fixtureName): string
127
    {
128
        $testClassTrace = Arr::first(debug_backtrace(), fn ($trace) => str_ends_with($trace['file'], 'Test.php'));
6✔
129
        $testFileName = Arr::last(explode('/', $testClassTrace['file']));
6✔
130
        $testClass = Str::remove('.php', $testFileName);
6✔
131

132
        return base_path("tests/fixtures/{$testClass}/db_changes/{$this->tableName}/{$fixtureName}");
6✔
133
    }
134

135
    protected function getDataSet(string $table, string $orderField = 'id'): Collection
136
    {
137
        return DB::connection($this->connectionName)
14✔
138
            ->table($table)
14✔
139
            ->orderBy($orderField)
14✔
140
            ->get()
14✔
141
            ->map(fn ($record) => (array) $record);
14✔
142
    }
143
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc