seed(); }); describe('BrandCodeGenerator Domain Service', function (): void { it('generates a valid brand code conforming to BrandCode invariants', function (): void { // GIVEN $generator = new BrandCodeGenerator(); $brandName = new BrandName(fake()->company()); // WHEN $code = $generator->generate($brandName); // THEN expect($code)->toBeInstanceOf(BrandCode::class) ->and($code->value)->toMatch('/^[A-Z]{3}\d{2}$/') ->and($code->value[3])->not->toBe($code->value[4]); })->repeat(100); it('handles short names and names with accents or special characters', function (string $input, string $expectedTrigram): void { // GIVEN $generator = new BrandCodeGenerator(); $brandName = new BrandName($input); // WHEN $code = $generator->generate($brandName); // THEN expect($code)->toBeInstanceOf(BrandCode::class) ->and(str_starts_with($code->value, $expectedTrigram))->toBeTrue(); })->with([ ['Le Gaulois', 'LGL'], ['Maître CoQ', 'MCQ'], ['Tradition d\'Asie', 'TDA'], ['Loué', 'LOU'], ['Marie', 'MAR'], ['Réghalal', 'REG'], ['Pierre Martinet', 'PMT'], ['Galina', 'GAL'], ['Matines', 'MAT'], ['Nature & Respect', 'NRP'], ['Poule et Toque', 'PET'], ['Doux', 'DOU'], ['Domaine de Lanvaux', 'DDL'], ['Cailles Robin', 'CRB'], ['Régalette', 'REG'], ['Trégalette', 'TRE'], ['La Toque Angevine', 'LTA'], ['Calibra', 'CAL'], ['Agis', 'AGI'], ['Drosed', 'DRO'], ['Indykpol', 'IND'], ['Goldenfood', 'GOL'], ['Les Grands Domaines Agricoles', 'GDA'], ['Fermiers Bio Français', 'FBF'], ['LU', 'LUX'], ['K', 'KXX'], ]); });