Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

- Requires PHP `8.5`

### Fixed

- `Str::takeEnd(0)` would return the exact same string instead of an empty string

## 6.2.0 - 2026-05-14

### Changed
Expand Down
20 changes: 20 additions & 0 deletions docs/structures/str.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,11 @@ Return a new string with only the n first characters.
Str::of('foobar')->take(3)->equals(Str::of('foo')); // true
```

??? warning
When working with `Encoding::utf8` certain sequences of utf8 characters may lead to unexpected results.

Make sure to either use it on trusted input or switch to `Encoding::ascii`.

## `->takeEnd()`

Return a new string with only the n last characters.
Expand All @@ -279,6 +284,11 @@ Return a new string with only the n last characters.
Str::of('foobar')->takeEnd(3)->equals(Str::of('bar')); // true
```

??? warning
When working with `Encoding::utf8` certain sequences of utf8 characters may lead to unexpected results.

Make sure to either use it on trusted input or switch to `Encoding::ascii`.

## `->drop()`

Return a new string without the n first characters.
Expand All @@ -287,6 +297,11 @@ Return a new string without the n first characters.
Str::of('foobar')->drop(3)->equals(Str::of('bar')); // true
```

??? warning
When working with `Encoding::utf8` certain sequences of utf8 characters may lead to unexpected results.

Make sure to either use it on trusted input or switch to `Encoding::ascii`.

## `->dropEnd()`

Return a new string without the n last characters.
Expand All @@ -295,6 +310,11 @@ Return a new string without the n last characters.
Str::of('foobar')->dropEnd(3)->equals(Str::of('foo')); // true
```

??? warning
When working with `Encoding::utf8` certain sequences of utf8 characters may lead to unexpected results.

Make sure to either use it on trusted input or switch to `Encoding::ascii`.

## `->sprintf()`

Return a formatted string.
Expand Down
48 changes: 48 additions & 0 deletions proofs/str.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php
declare(strict_types = 1);

use Innmind\Immutable\Str;
use Properties\Innmind\Immutable\Str as Properties;
use Innmind\BlackBox\{
Set,
Prove,
};

return static function(Prove $prove) {
$ascii = Set::strings()
->between(0, 100_00)
->map(Str::of(...))
->map(static fn($str) => $str->toEncoding(Str\Encoding::ascii))
->map(static fn($str) => static fn() => $str);
$utf8 = Set::strings()
->madeOf(
Set::strings()->chars()->alphanumerical(),
Set::strings()->unicode()->emoticons(),
Set::strings()->unicode()->alchemicalSymbols(),
Set::strings()->unicode()->mathematicalOperators(),
Set::strings()->unicode()->currencySymbols(),
Set::strings()->unicode()->generalPunctuation(),
Set::strings()->unicode()->arabic(),
Set::strings()->unicode()->hebrew(),
Set::strings()->unicode()->cyrillic(),
Set::strings()->unicode()->controlCharater(),
)
->between(0, 100_000)
->map(Str::of(...))
->map(static fn($str) => $str->toEncoding(Str\Encoding::utf8))
->map(static fn($str) => static fn() => $str);
$strings = Set::either($ascii, $utf8);

yield $prove->properties(
'Str',
Properties::properties(),
$strings,
);

foreach (Properties::list() as $property) {
yield $prove->property(
$property,
$strings,
);
}
};
42 changes: 42 additions & 0 deletions properties/Str.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
declare(strict_types = 1);

namespace Properties\Innmind\Immutable;

use Innmind\BlackBox\{
Set,
Property,
Properties,
};

/**
* @internal
*/
final class Str
{
/**
* @return Set<Properties>|Set\Provider<Properties>
*/
public static function properties(): Set|Set\Provider
{
return Set::properties(
...\array_map(
static fn($class) => $class::any(),
self::list(),
),
);
}

/**
* @return non-empty-list<class-string<Property>>
*/
public static function list(): array
{
return [
Str\Take::class,
Str\TakeEnd::class,
Str\Drop::class,
Str\DropEnd::class,
];
}
}
53 changes: 53 additions & 0 deletions properties/Str/Drop.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
declare(strict_types = 1);

namespace Properties\Innmind\Immutable\Str;

use Innmind\Immutable\Str;
use Innmind\BlackBox\{
Set,
Property,
Runner\Assert,
};

/**
* @implements Property<Str>
*/
final class Drop implements Property
{
private function __construct(
private int $size,
) {
}

public static function any(): Set
{
// Upper bound is 100 to avoid having too much a probability that the
// resulting Str will be the same one as the input one.
return Set::integers()
->between(0, 100)
->map(static fn($size) => new self($size));
}

public function applicableTo(object $systemUnderTest): bool
{
return true;
}

public function ensureHeldBy(Assert $assert, object $systemUnderTest): object
{
$result = $systemUnderTest->drop($this->size);
$assert->same(
$result->length(),
\max(
0,
$systemUnderTest->length() - $this->size,
),
);
$assert->true(
$systemUnderTest->endsWith($result->toString()),
);

return $result;
}
}
53 changes: 53 additions & 0 deletions properties/Str/DropEnd.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
declare(strict_types = 1);

namespace Properties\Innmind\Immutable\Str;

use Innmind\Immutable\Str;
use Innmind\BlackBox\{
Set,
Property,
Runner\Assert,
};

/**
* @implements Property<Str>
*/
final class DropEnd implements Property
{
private function __construct(
private int $size,
) {
}

public static function any(): Set
{
// Upper bound is 100 to avoid having too much a probability that the
// resulting Str will be the same one as the input one.
return Set::integers()
->between(0, 100)
->map(static fn($size) => new self($size));
}

public function applicableTo(object $systemUnderTest): bool
{
return true;
}

public function ensureHeldBy(Assert $assert, object $systemUnderTest): object
{
$result = $systemUnderTest->dropEnd($this->size);
$assert->same(
$result->length(),
\max(
0,
$systemUnderTest->length() - $this->size,
),
);
$assert->true(
$systemUnderTest->startsWith($result->toString()),
);

return $result;
}
}
50 changes: 50 additions & 0 deletions properties/Str/Take.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
declare(strict_types = 1);

namespace Properties\Innmind\Immutable\Str;

use Innmind\Immutable\Str;
use Innmind\BlackBox\{
Set,
Property,
Runner\Assert,
};

/**
* @implements Property<Str>
*/
final class Take implements Property
{
private function __construct(
private int $size,
) {
}

public static function any(): Set
{
// Upper bound is 100 to avoid having too much a probability that the
// resulting Str will be the same one as the input one.
return Set::integers()
->between(0, 100)
->map(static fn($size) => new self($size));
}

public function applicableTo(object $systemUnderTest): bool
{
return true;
}

public function ensureHeldBy(Assert $assert, object $systemUnderTest): object
{
$result = $systemUnderTest->take($this->size);
$assert
->number($result->length())
->int()
->lessThanOrEqual($this->size);
$assert->true(
$systemUnderTest->startsWith($result->toString()),
);

return $result;
}
}
50 changes: 50 additions & 0 deletions properties/Str/TakeEnd.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
declare(strict_types = 1);

namespace Properties\Innmind\Immutable\Str;

use Innmind\Immutable\Str;
use Innmind\BlackBox\{
Set,
Property,
Runner\Assert,
};

/**
* @implements Property<Str>
*/
final class TakeEnd implements Property
{
private function __construct(
private int $size,
) {
}

public static function any(): Set
{
// Upper bound is 100 to avoid having too much a probability that the
// resulting Str will be the same one as the input one.
return Set::integers()
->between(0, 100)
->map(static fn($size) => new self($size));
}

public function applicableTo(object $systemUnderTest): bool
{
return true;
}

public function ensureHeldBy(Assert $assert, object $systemUnderTest): object
{
$result = $systemUnderTest->takeEnd($this->size);
$assert
->number($result->length())
->int()
->lessThanOrEqual($this->size);
$assert->true(
$systemUnderTest->endsWith($result->toString()),
);

return $result;
}
}
Loading
Loading