value)->toBe('hello'); expect($word2->value)->toBe('Hello123'); expect($word3->value)->toBe('user_name'); expect($word4->value)->toBe('MAX_VALUE'); expect($word5->value)->toBe('_private'); }); it('rejects strings with hyphens', function () { PosixWordString::fromString('user-name'); })->throws(\InvalidArgumentException::class, 'String must contain only POSIX word characters'); it('rejects strings with spaces', function () { PosixWordString::fromString('hello world'); })->throws(\InvalidArgumentException::class, 'String must contain only POSIX word characters'); it('rejects strings with special characters', function () { PosixWordString::fromString('hello@world'); })->throws(\InvalidArgumentException::class, 'String must contain only POSIX word characters'); it('rejects strings with punctuation', function () { PosixWordString::fromString('hello.world'); })->throws(\InvalidArgumentException::class, 'String must contain only POSIX word characters'); it('rejects strings with operators', function () { PosixWordString::fromString('a+b'); })->throws(\InvalidArgumentException::class, 'String must contain only POSIX word characters'); it('rejects empty strings', function () { PosixWordString::fromString(''); })->throws(\InvalidArgumentException::class, 'String must not be empty'); it('rejects strings with parentheses', function () { PosixWordString::fromString('function()'); })->throws(\InvalidArgumentException::class, 'String must contain only POSIX word characters'); it('rejects strings with brackets', function () { PosixWordString::fromString('array[0]'); })->throws(\InvalidArgumentException::class, 'String must contain only POSIX word characters'); }); describe('Conversion Methods', function () { it('converts to TypedString', function () { $word = PosixWordString::fromString('user_id'); $typed = $word->toTypedString(); expect($typed)->toBeInstanceOf(TypedString::class); expect($typed->value)->toBe('user_id'); expect($typed->isAlphanumeric())->toBeFalse(); // Contains underscore }); it('converts to PosixString', function () { $word = PosixWordString::fromString('MAX_VALUE'); $posix = $word->toPosixString(); expect($posix)->toBeInstanceOf(PosixString::class); expect($posix->value)->toBe('MAX_VALUE'); expect($posix->isWord())->toBeTrue(); }); it('converts to string', function () { $word = PosixWordString::fromString('username'); expect($word->toString())->toBe('username'); expect((string) $word)->toBe('username'); }); }); describe('Comparison Methods', function () { it('checks equality', function () { $word1 = PosixWordString::fromString('user_id'); $word2 = PosixWordString::fromString('user_id'); $word3 = PosixWordString::fromString('user_name'); expect($word1->equals($word2))->toBeTrue(); expect($word1->equals($word3))->toBeFalse(); }); it('compares case-sensitive', function () { $lower = PosixWordString::fromString('username'); $upper = PosixWordString::fromString('USERNAME'); expect($lower->equals($upper))->toBeFalse(); }); }); describe('Real World Use Cases', function () { describe('PHP Identifiers', function () { it('validates variable names', function () { $var1 = PosixWordString::fromString('userName'); $var2 = PosixWordString::fromString('user_id'); $var3 = PosixWordString::fromString('_privateVar'); expect($var1->value)->toBe('userName'); expect($var2->value)->toBe('user_id'); expect($var3->value)->toBe('_privateVar'); }); it('validates constant names', function () { $const1 = PosixWordString::fromString('MAX_SIZE'); $const2 = PosixWordString::fromString('API_KEY'); $const3 = PosixWordString::fromString('DEFAULT_TIMEOUT'); expect($const1->value)->toBe('MAX_SIZE'); expect($const2->value)->toBe('API_KEY'); expect($const3->value)->toBe('DEFAULT_TIMEOUT'); }); it('validates function names', function () { $func1 = PosixWordString::fromString('calculateTotal'); $func2 = PosixWordString::fromString('get_user_by_id'); $func3 = PosixWordString::fromString('__construct'); expect($func1->value)->toBe('calculateTotal'); expect($func2->value)->toBe('get_user_by_id'); expect($func3->value)->toBe('__construct'); }); it('rejects invalid PHP identifiers', function () { PosixWordString::fromString('my-function'); })->throws(\InvalidArgumentException::class); }); describe('Database Column Names', function () { it('validates snake_case column names', function () { $col1 = PosixWordString::fromString('user_id'); $col2 = PosixWordString::fromString('created_at'); $col3 = PosixWordString::fromString('email_verified_at'); expect($col1->value)->toBe('user_id'); expect($col2->value)->toBe('created_at'); expect($col3->value)->toBe('email_verified_at'); }); it('rejects kebab-case column names', function () { PosixWordString::fromString('user-id'); })->throws(\InvalidArgumentException::class); }); describe('Usernames', function () { it('validates valid usernames', function () { $user1 = PosixWordString::fromString('john_doe'); $user2 = PosixWordString::fromString('user123'); $user3 = PosixWordString::fromString('admin_user'); expect($user1->value)->toBe('john_doe'); expect($user2->value)->toBe('user123'); expect($user3->value)->toBe('admin_user'); }); it('rejects usernames with special characters', function () { PosixWordString::fromString('john@doe'); })->throws(\InvalidArgumentException::class); it('rejects usernames with hyphens', function () { PosixWordString::fromString('john-doe'); })->throws(\InvalidArgumentException::class); it('rejects usernames with spaces', function () { PosixWordString::fromString('john doe'); })->throws(\InvalidArgumentException::class); }); describe('URL Slugs (with underscore)', function () { it('validates underscore slugs', function () { $slug1 = PosixWordString::fromString('my_blog_post'); $slug2 = PosixWordString::fromString('product_category_1'); $slug3 = PosixWordString::fromString('about_us'); expect($slug1->value)->toBe('my_blog_post'); expect($slug2->value)->toBe('product_category_1'); expect($slug3->value)->toBe('about_us'); }); it('rejects hyphenated slugs', function () { // Note: Hyphenated slugs need different validation PosixWordString::fromString('my-blog-post'); })->throws(\InvalidArgumentException::class); }); }); describe('Single Character Strings', function () { it('accepts single letter', function () { $a = PosixWordString::fromString('a'); $Z = PosixWordString::fromString('Z'); expect($a->value)->toBe('a'); expect($Z->value)->toBe('Z'); }); it('accepts single digit', function () { $five = PosixWordString::fromString('5'); expect($five->value)->toBe('5'); }); it('accepts single underscore', function () { $underscore = PosixWordString::fromString('_'); expect($underscore->value)->toBe('_'); }); it('rejects single special character', function () { PosixWordString::fromString('!'); })->throws(\InvalidArgumentException::class); it('rejects single hyphen', function () { PosixWordString::fromString('-'); })->throws(\InvalidArgumentException::class); }); describe('Edge Cases', function () { it('handles very long word strings', function () { $longString = str_repeat('abc123_', 100); $word = PosixWordString::fromString($longString); expect($word->value)->toBe($longString); expect(strlen($word->value))->toBe(700); }); it('handles mixed case correctly', function () { $mixed = PosixWordString::fromString('CamelCase_With_Underscore123'); expect($mixed->value)->toBe('CamelCase_With_Underscore123'); }); it('accepts strings starting with underscore', function () { $leading = PosixWordString::fromString('_privateMethod'); expect($leading->value)->toBe('_privateMethod'); }); it('accepts strings starting with digit', function () { // Note: Valid for word class, but not valid PHP identifiers $digit = PosixWordString::fromString('123abc'); expect($digit->value)->toBe('123abc'); }); it('accepts strings with only digits', function () { $digits = PosixWordString::fromString('123456'); expect($digits->value)->toBe('123456'); }); it('accepts strings with only underscores', function () { $underscores = PosixWordString::fromString('___'); expect($underscores->value)->toBe('___'); }); }); describe('Boundary Cases', function () { it('handles maximum practical length', function () { // 255 characters - typical database VARCHAR limit $longIdentifier = str_repeat('a', 255); $word = PosixWordString::fromString($longIdentifier); expect(strlen($word->value))->toBe(255); }); it('handles alphanumeric only', function () { $alnum = PosixWordString::fromString('abc123XYZ789'); expect($alnum->value)->toBe('abc123XYZ789'); }); it('handles underscores only', function () { $underscores = PosixWordString::fromString('_____'); expect($underscores->value)->toBe('_____'); }); it('handles mixed content', function () { $mixed = PosixWordString::fromString('a1_B2_c3_D4'); expect($mixed->value)->toBe('a1_B2_c3_D4'); }); }); });