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

johnykvsky / dummygenerator / 22286702151

22 Feb 2026 10:27PM UTC coverage: 99.419% (+0.6%) from 98.778%
22286702151

Pull #38

github

web-flow
Merge 556021dd2 into 4286d41f2
Pull Request #38: Version 0.2.0

309 of 310 new or added lines in 37 files covered. (99.68%)

1 existing line in 1 file now uncovered.

1027 of 1033 relevant lines covered (99.42%)

65.94 hits per line

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

98.31
/src/Core/Payment.php
1
<?php
2

3
declare(strict_types = 1);
4

5
namespace DummyGenerator\Core;
6

7
use DummyGenerator\Definitions\Calculator\IbanCalculatorInterface;
8
use DummyGenerator\Definitions\Calculator\LuhnCalculatorInterface;
9
use DummyGenerator\Definitions\Extension\PaymentExtensionInterface;
10
use DummyGenerator\Definitions\Randomizer\RandomizerInterface;
11
use DummyGenerator\Definitions\Replacer\ReplacerInterface;
12
use DummyGenerator\GeneratorInterface;
13

14
class Payment implements PaymentExtensionInterface
15
{
16
    public function __construct(
17
        protected RandomizerInterface $randomizer,
18
        protected ReplacerInterface $replacer,
19
        protected IbanCalculatorInterface $ibanCalculator,
20
        protected LuhnCalculatorInterface $luhnCalculator,
21
        protected GeneratorInterface $generator
22
    ) {
23
    }
15✔
24

25
    public string $expirationDateFormat = 'm/y';
26

27
    /** @var string[] */
28
    protected array $cardVendors = [
29
        'Visa', 'Visa', 'Visa', 'Visa', 'Visa',
30
        'MasterCard', 'MasterCard', 'MasterCard', 'MasterCard', 'MasterCard',
31
        'American Express', 'Discover Card', 'Visa Retired', 'JCB',
32
    ];
33

34
    /**
35
     * @var array<string, mixed> List of card brand masks for generating valid credit card numbers
36
     *
37
     * @see https://en.wikipedia.org/wiki/Payment_card_number Reference for existing prefixes
38
     * @see https://www.mastercard.us/en-us/issuers/get-support/2-series-bin-expansion.html MasterCard 2017 2-Series BIN Expansion
39
     */
40
    protected array $cardParams = [
41
        'Visa' => [
42
            '4539###########',
43
            '4556###########',
44
            '4916###########',
45
            '4532###########',
46
            '4929###########',
47
            '40240071#######',
48
            '4485###########',
49
            '4716###########',
50
            '4##############',
51
        ],
52
        'Visa Retired' => [
53
            '4539########',
54
            '4556########',
55
            '4916########',
56
            '4532########',
57
            '4929########',
58
            '40240071####',
59
            '4485########',
60
            '4716########',
61
            '4###########',
62
        ],
63
        'MasterCard' => [
64
            '2221###########',
65
            '23#############',
66
            '24#############',
67
            '25#############',
68
            '26#############',
69
            '2720###########',
70
            '51#############',
71
            '52#############',
72
            '53#############',
73
            '54#############',
74
            '55#############',
75
        ],
76
        'American Express' => [
77
            '34############',
78
            '37############',
79
        ],
80
        'Discover Card' => [
81
            '6011###########',
82
        ],
83
        'JCB' => [
84
            '3528###########',
85
            '3589###########',
86
        ],
87
    ];
88

89
    /** @var array<string, mixed> list of IBAN formats, source: @see https://www.swift.com/standards/data-standards/iban */
90
    protected array $ibanFormats = [
91
        'AD' => [['n', 4], ['n', 4], ['c', 12]],
92
        'AE' => [['n', 3], ['n', 16]],
93
        'AL' => [['n', 8], ['c', 16]],
94
        'AT' => [['n', 5], ['n', 11]],
95
        'AZ' => [['a', 4], ['c', 20]],
96
        'BA' => [['n', 3], ['n', 3], ['n', 8], ['n', 2]],
97
        'BE' => [['n', 3], ['n', 7], ['n', 2]],
98
        'BG' => [['a', 4], ['n', 4], ['n', 2], ['c', 8]],
99
        'BH' => [['a', 4], ['c', 14]],
100
        'BR' => [['n', 8], ['n', 5], ['n', 10], ['a', 1], ['c', 1]],
101
        'CH' => [['n', 5], ['c', 12]],
102
        'CR' => [['n', 4], ['n', 14]],
103
        'CY' => [['n', 3], ['n', 5], ['c', 16]],
104
        'CZ' => [['n', 4], ['n', 6], ['n', 10]],
105
        'DE' => [['n', 8], ['n', 10]],
106
        'DK' => [['n', 4], ['n', 9], ['n', 1]],
107
        'DO' => [['c', 4], ['n', 20]],
108
        'EE' => [['n', 2], ['n', 2], ['n', 11], ['n', 1]],
109
        'EG' => [['n', 4], ['n', 4], ['n', 17]],
110
        'ES' => [['n', 4], ['n', 4], ['n', 1], ['n', 1], ['n', 10]],
111
        'FI' => [['n', 6], ['n', 7], ['n', 1]],
112
        'FR' => [['n', 5], ['n', 5], ['c', 11], ['n', 2]],
113
        'GB' => [['a', 4], ['n', 6], ['n', 8]],
114
        'GE' => [['a', 2], ['n', 16]],
115
        'GI' => [['a', 4], ['c', 15]],
116
        'GR' => [['n', 3], ['n', 4], ['c', 16]],
117
        'GT' => [['c', 4], ['c', 20]],
118
        'HR' => [['n', 7], ['n', 10]],
119
        'HU' => [['n', 3], ['n', 4], ['n', 1], ['n', 15], ['n', 1]],
120
        'IE' => [['a', 4], ['n', 6], ['n', 8]],
121
        'IL' => [['n', 3], ['n', 3], ['n', 13]],
122
        'IS' => [['n', 4], ['n', 2], ['n', 6], ['n', 10]],
123
        'IT' => [['a', 1], ['n', 5], ['n', 5], ['c', 12]],
124
        'KW' => [['a', 4], ['n', 22]],
125
        'KZ' => [['n', 3], ['c', 13]],
126
        'LB' => [['n', 4], ['c', 20]],
127
        'LI' => [['n', 5], ['c', 12]],
128
        'LT' => [['n', 5], ['n', 11]],
129
        'LU' => [['n', 3], ['c', 13]],
130
        'LV' => [['a', 4], ['c', 13]],
131
        'MC' => [['n', 5], ['n', 5], ['c', 11], ['n', 2]],
132
        'MD' => [['c', 2], ['c', 18]],
133
        'ME' => [['n', 3], ['n', 13], ['n', 2]],
134
        'MK' => [['n', 3], ['c', 10], ['n', 2]],
135
        'MR' => [['n', 5], ['n', 5], ['n', 11], ['n', 2]],
136
        'MT' => [['a', 4], ['n', 5], ['c', 18]],
137
        'MU' => [['a', 4], ['n', 2], ['n', 2], ['n', 12], ['n', 3], ['a', 3]],
138
        'NL' => [['a', 4], ['n', 10]],
139
        'NO' => [['n', 4], ['n', 6], ['n', 1]],
140
        'PK' => [['a', 4], ['c', 16]],
141
        'PL' => [['n', 8], ['n', 16]],
142
        'PS' => [['a', 4], ['c', 21]],
143
        'PT' => [['n', 4], ['n', 4], ['n', 11], ['n', 2]],
144
        'RO' => [['a', 4], ['c', 16]],
145
        'RS' => [['n', 3], ['n', 13], ['n', 2]],
146
        'SA' => [['n', 2], ['c', 18]],
147
        'SE' => [['n', 3], ['n', 16], ['n', 1]],
148
        'SI' => [['n', 5], ['n', 8], ['n', 2]],
149
        'SK' => [['n', 4], ['n', 6], ['n', 10]],
150
        'SM' => [['a', 1], ['n', 5], ['n', 5], ['c', 12]],
151
        'TN' => [['n', 2], ['n', 3], ['n', 13], ['n', 2]],
152
        'TR' => [['n', 5], ['n', 1], ['c', 16]],
153
        'VG' => [['a', 4], ['n', 16]],
154
    ];
155

156
    /**
157
     * @var string[]
158
     *
159
     * @link https://en.wikipedia.org/wiki/ISO_4217
160
     * On date of 2019-09-27
161
     *
162
     * With the following exceptions:
163
     * SVC has been replaced by the USD in 2001: https://en.wikipedia.org/wiki/Salvadoran_col%C3%B3n
164
     * ZWL has been suspended since 2009: https://en.wikipedia.org/wiki/Zimbabwean_dollar
165
     */
166
    protected array $currencyCode = array(
167
        'AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN',
168
        'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BOV',
169
        'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BZD', 'CAD', 'CDF', 'CHE', 'CHF',
170
        'CHW', 'CLF', 'CLP', 'CNY', 'COP', 'COU', 'CRC', 'CUC', 'CUP', 'CVE',
171
        'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD',
172
        'FKP', 'GBP', 'GEL', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD',
173
        'HNL', 'HTG', 'HUF', 'IDR', 'ILS', 'INR', 'IQD', 'IRR', 'ISK', 'JMD',
174
        'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD',
175
        'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA',
176
        'MKD', 'MMK', 'MNT', 'MOP', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MXV',
177
        'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB',
178
        'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB',
179
        'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLE', 'SOS',
180
        'SRD', 'SSP', 'STN', 'SVC', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND',
181
        'TOP', 'TRY', 'TTD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'USN', 'UYI',
182
        'UYU', 'UYW', 'UZS', 'VED', 'VES', 'VND', 'VUV', 'WST', 'XAF', 'XAG',
183
        'XAU', 'XBA', 'XBB', 'XBC', 'XBD', 'XCD', 'XDR', 'XOF', 'XPD', 'XPF',
184
        'XPT', 'XSU', 'XTS', 'XUA', 'XXX', 'YER', 'ZAR', 'ZMW', 'ZWG',
185
    );
186

187
    public function creditCardType(): string
188
    {
189
        return $this->randomizer->randomElement($this->cardVendors);
3✔
190
    }
191

192
    public function creditCardNumber(?string $type = null, bool $formatted = false, string $separator = '-'): string
193
    {
194

195
        if (null === $type || !array_key_exists($type, $this->cardParams)) {
3✔
196
            $type = $this->creditCardType();
2✔
197
        }
198

199
        $mask = $this->randomizer->randomElement($this->cardParams[$type]);
3✔
200

201
        $number = $this->replacer->numerify($mask);
3✔
202
        $number .= $this->luhnCalculator->computeCheckDigit($number);
3✔
203

204
        if ($formatted) {
3✔
205
            $p1 = substr($number, 0, 4);
1✔
206
            $p2 = substr($number, 4, 4);
1✔
207
            $p3 = substr($number, 8, 4);
1✔
208
            $p4 = substr($number, 12);
1✔
209
            $number = $p1 . $separator . $p2 . $separator . $p3 . $separator . $p4;
1✔
210
        }
211

212
        return $number;
3✔
213
    }
214

215
    public function currencyCode(): string
216
    {
217
        return $this->randomizer->randomElement($this->currencyCode);
2✔
218
    }
219

220
    public function creditCardExpirationDate(bool $inFuture = true): string
221
    {
222
        if ($inFuture) {
2✔
223
            // @phpstan-ignore-next-line
224
            return $this->generator->dateTimeBetween('now', '36 months')->format($this->expirationDateFormat);
1✔
225
        }
226

227
        // @phpstan-ignore-next-line
228
        return $this->generator->dateTimeBetween('-36 months', '36 months')->format($this->expirationDateFormat);
1✔
229
    }
230

231
    public function creditCardDetails(bool $valid = true): array
232
    {
233
        $type = $this->creditCardType();
1✔
234

235
        return [
1✔
236
            'type' => $type,
1✔
237
            'number' => $this->creditCardNumber($type),
1✔
238
            // @phpstan-ignore-next-line
239
            'name' => $this->generator->name(),
1✔
240
            'expirationDate' => $this->creditCardExpirationDate($valid),
1✔
241
        ];
1✔
242
    }
243

244
    public function iban(?string $alpha2 = null, string $prefix = ''): string
245
    {
246
        $countryCode = $alpha2 === null
4✔
NEW
247
            ? $this->randomizer->randomKey($this->ibanFormats)
×
248
            : $this->replacer->toUpper($alpha2);
4✔
249

250
        $format = $countryCode === null ? null : $this->ibanFormats[$countryCode] ?? null;
4✔
251

252
        if ($format === null) {
4✔
253
            $length = 24;
1✔
254
            $format = [['n', $length]];
1✔
255
        } else {
256
            $length = 0;
3✔
257

258
            foreach ($format as $part) {
3✔
259
                [$class, $groupCount] = $part;
3✔
260
                $length += $groupCount;
3✔
261
            }
262
        }
263

264
        $expandedFormat = '';
4✔
265

266
        foreach ($format as $item) {
4✔
267
            [$class, $length] = $item;
4✔
268
            $expandedFormat .= str_repeat($class, $length);
4✔
269
        }
270

271
        $result = $prefix;
4✔
272
        $expandedFormat = substr($expandedFormat, $this->replacer->strlen($result));
4✔
273

274
        foreach (str_split($expandedFormat) as $class) {
4✔
275
            switch ($class) {
276
                default:
277
                case 'c':
4✔
278
                    $result .= $this->randomizer->getBool() ? $this->randomizer->getInt(0, 9) : $this->replacer->toUpper($this->randomizer->randomLetter());
2✔
279

280
                    break;
2✔
281

282
                case 'a':
3✔
283
                    $result .= $this->replacer->toUpper($this->randomizer->randomLetter());
1✔
284

285
                    break;
1✔
286

287
                case 'n':
2✔
288
                    $result .= $this->randomizer->getInt(0, 9);
2✔
289

290
                    break;
2✔
291
            }
292
        }
293

294
        $checksum = $this->ibanCalculator->checksum($countryCode . '00' . $result);
4✔
295

296
        return $countryCode . $checksum . $result;
4✔
297
    }
298

299
    public function swiftBicNumber(): string
300
    {
301
        $bankCode = $this->replacer->lexify('????');
1✔
302
        $countryCode = $this->randomizer->randomElement(array_keys($this->ibanFormats));
1✔
303
        $locationCode = $this->replacer->lexify('??');
1✔
304
        $branchCode = $this->randomizer->getInt(100, 999);
1✔
305

306
        return $this->replacer->toUpper($bankCode . $countryCode . $locationCode) . $branchCode;
1✔
307
    }
308
}
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