From f502892c9d250c42213f698d692fa7da2e28f57c Mon Sep 17 00:00:00 2001 From: Christian Benthake Date: Mon, 7 Sep 2020 18:33:23 +0200 Subject: [PATCH 1/2] BC: add conditionals for builder and command --- composer.json | 2 +- src/ShellBuilder.php | 6 ++-- src/ShellCommand.php | 2 ++ src/ShellConditional.php | 28 ++++++++++++++++ tests/ShellBuilderTest.php | 67 +++++++++++++++++++++++++++++++++----- tests/ShellCommandTest.php | 13 ++++++++ 6 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 src/ShellConditional.php diff --git a/composer.json b/composer.json index ce55505..a329fbb 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "license": "MIT", "authors": [ { - "name": "Chris Ben", + "name": "Christian Rodriguez Benthake", "email": "git@cben.co" } ], diff --git a/src/ShellBuilder.php b/src/ShellBuilder.php index 4e30e3d..707168f 100644 --- a/src/ShellBuilder.php +++ b/src/ShellBuilder.php @@ -17,6 +17,8 @@ final class ShellBuilder implements ShellInterface, \JsonSerializable { + use ShellConditional; + /** @var array */ private $commandList = []; /** @var int */ @@ -282,7 +284,7 @@ public function createCommandSubstition(): self public function hasCommands(): bool { - return empty($this->commandList) && empty($this->variables); + return empty($this->commandList) === false || empty($this->variables) === false; } /** @@ -352,7 +354,7 @@ public function __toString(): string } if ($this->groupType === GroupType::SAMESHELL_GROUP) { return sprintf( - '%s%s;%s', + '%s %s;%s', ControlOperator::CURLY_BLOCK_DEFINITON_OPEN, $result, ControlOperator::CURLY_BLOCK_DEFINITON_CLOSE diff --git a/src/ShellCommand.php b/src/ShellCommand.php index 32dddbc..3e8751d 100644 --- a/src/ShellCommand.php +++ b/src/ShellCommand.php @@ -18,6 +18,8 @@ */ final class ShellCommand implements ShellInterface { + use ShellConditional; + /** * @var ShellWord * @psalm-readonly diff --git a/src/ShellConditional.php b/src/ShellConditional.php new file mode 100644 index 0000000..96c0a89 --- /dev/null +++ b/src/ShellConditional.php @@ -0,0 +1,28 @@ +if($callOnThis($this) === true, $callback, $alternativeCallback); + } +} diff --git a/tests/ShellBuilderTest.php b/tests/ShellBuilderTest.php index a44a81f..dd023f3 100644 --- a/tests/ShellBuilderTest.php +++ b/tests/ShellBuilderTest.php @@ -17,7 +17,7 @@ final class ShellBuilderTest extends TestCase { public function testBuilderConcept(): void { - $result = 'a && b | c || d |& f && (g && h) || {i || j;}'; + $result = 'a && b | c || d |& f && (g && h) || { i || j;}'; $builder = new ShellBuilder(); $a = $builder->createCommand('a'); $b = $builder->createCommand('b'); @@ -46,7 +46,7 @@ public function testBuilderConcept(): void public function testBuilderConceptWithShortcut(): void { - $result = 'a && b | c || d |& f && (g && h) || {i || j;}'; + $result = 'a && b | c || d |& f && (g && h) || { i || j;}'; $builder = new ShellBuilder(); $builder ->add('a') @@ -146,7 +146,7 @@ public function testShellBuilderGroupSameShell(): void ->add( $builder->createCommand('echo')->addArgument('hello') )->and('cat')); - $this->assertEquals("{echo 'hello' && cat;}", (string)$builder); + $this->assertEquals("{ echo 'hello' && cat;}", (string)$builder); } public function testSimpleSshCommand(): void @@ -669,7 +669,7 @@ public function testCoprocessWithShellGroupAndRedirections(): void ->addToBuilder() ->redirectDescriptor('', true, null, 3); $this->assertEquals( - '{coproc tee {tee logfile;} >&3 ;} 3>&1', + '{ coproc tee { tee logfile;} >&3 ;} 3>&1', (string)ShellBuilder::new()->add($builder)->redirectDescriptor('', true, 3, 1) ); } @@ -686,11 +686,60 @@ public function testNamedCoprocessWithShellGroupAndRedirections(): void ->addToBuilder()) ->redirectDescriptor('', true, null, 3); $this->assertEquals( - '{coproc mycoproc {awk \'{print "foo" $0;fflush()}\';} >&3 ;} 3>&1', + '{ coproc mycoproc { awk \'{print "foo" $0;fflush()}\';} >&3 ;} 3>&1', (string)ShellBuilder::new()->add($builder)->redirectDescriptor('', true, 3, 1) ); } + public function testCondiditionalArguments(): void + { + // if false + $builder = ShellBuilder::new() + ->if(false, static function (ShellBuilder $builder) { + return $builder->add('echo'); + }) + ->ifThis(static function (ShellBuilder $builder) { + return $builder->hasCommands() === false; + }, static function (ShellBuilder $builder) { + return $builder->add('print'); + }); + static::assertEquals('print', (string)$builder); + + // if true + $builder = ShellBuilder::new() + ->if(true, static function (ShellBuilder $builder) { + return $builder->add('echo'); + }) + ->ifThis(static function (ShellBuilder $builder) { + return $builder->hasCommands() === false; + }, static function (ShellBuilder $builder) { + return $builder->add('print'); + }); + static::assertEquals('echo', (string)$builder); + } + + public function testComplexCondiditionalArguments(): void + { + $builder = ShellBuilder::new() + ->if( + false, + static function (ShellBuilder $builder) { + return $builder->add('echo'); + }, + static function (ShellBuilder $builder) { + return $builder->add('awk'); + } + ) + ->ifThis(static function (ShellBuilder $builder) { + return $builder->hasCommands() === false; + }, static function (ShellBuilder $builder) { + return $builder->add('print'); + }, static function (ShellBuilder $builder) { + return $builder->and('print'); + }); + static::assertEquals('awk && print', (string)$builder); + } + public function testSimpleAsyncShellBuilder(): void { $this->assertEquals( @@ -775,18 +824,18 @@ public function testCommandVariableWithConditionalAndCommand(): void public function testShellBuilderIsEmpty(): void { $builder = ShellBuilder::new(); - $this->assertTrue($builder->hasCommands()); + $this->assertFalse($builder->hasCommands()); } public function testShellBuilderIsNotEmpty(): void { $builder = ShellBuilder::new(); $builder->addVariable('a', 'b'); - $this->assertFalse($builder->hasCommands()); - $builder->removeVariable('a'); $this->assertTrue($builder->hasCommands()); - $builder->add('echo'); + $builder->removeVariable('a'); $this->assertFalse($builder->hasCommands()); + $builder->add('echo'); + $this->assertTrue($builder->hasCommands()); } public function testAddVariableWithoutSemicolon(): void diff --git a/tests/ShellCommandTest.php b/tests/ShellCommandTest.php index e19d9ee..06287e7 100644 --- a/tests/ShellCommandTest.php +++ b/tests/ShellCommandTest.php @@ -6,6 +6,7 @@ use PHPSu\ShellCommandBuilder\Definition\GroupType; use PHPSu\ShellCommandBuilder\Exception\ShellBuilderException; +use PHPSu\ShellCommandBuilder\ShellBuilder; use PHPSu\ShellCommandBuilder\ShellCommand; use PHPUnit\Framework\TestCase; @@ -171,6 +172,18 @@ public function testShellCommandWithCommandSubstitutionToArray(): void ], $command['arguments']); } + public function testConditionalArguments() + { + $command = ShellBuilder::command('test') + ->if(1 + 1 === 3, static function (ShellCommand $command) { + return $command->addOption('f', '1 + 1 = 3'); + }) + ->if(1 + 1 === 2, static function (ShellCommand $command) { + return $command->addOption('t', '1 + 1 = 2'); + }); + static::assertEquals((string)$command, 'test --t \'1 + 1 = 2\''); + } + public function testUnEscapedOption(): void { $command = (new ShellCommand('ls'))->addOption('color', 'true', false, true); From 9570ffd0f20ecffee6a585ea84e183aabc79215b Mon Sep 17 00:00:00 2001 From: Christian Benthake Date: Mon, 7 Sep 2020 18:49:31 +0200 Subject: [PATCH 2/2] improve infection / add tests --- src/ShellConditional.php | 8 ++++---- tests/ShellBuilderTest.php | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/ShellConditional.php b/src/ShellConditional.php index 96c0a89..64e580c 100644 --- a/src/ShellConditional.php +++ b/src/ShellConditional.php @@ -10,13 +10,13 @@ public function if(bool $condition, callable $callback, callable $alternativeCal { if ($condition) { $result = $callback($this); - assert($result instanceof self || $result === null); - return $result ?? $this; + assert($result instanceof self); + return $result; } if ($alternativeCallback) { $alternativeResult = $alternativeCallback($this); - assert($alternativeResult instanceof self || $alternativeResult === null); - return $alternativeResult ?? $this; + assert($alternativeResult instanceof self); + return $alternativeResult; } return $this; } diff --git a/tests/ShellBuilderTest.php b/tests/ShellBuilderTest.php index dd023f3..5df705e 100644 --- a/tests/ShellBuilderTest.php +++ b/tests/ShellBuilderTest.php @@ -740,6 +740,31 @@ static function (ShellBuilder $builder) { static::assertEquals('awk && print', (string)$builder); } + public function testComplexCondiditionalArgumentsWithWrongArguments(): void + { + self::expectException(\ErrorException::class); + ShellBuilder::new() + ->ifThis(static function (ShellBuilder $builder) { + return 'world'; + }, static function (ShellBuilder $builder) { + return $builder->add('print'); + }, static function (ShellBuilder $builder) { + return 'bla'; + }); + } + + public function testCondiditionalArgumentsWithWrongArguments(): void + { + self::expectException(\ErrorException::class); + ShellBuilder::new() + ->if( + true, + static function (ShellBuilder $builder) { + return 'hello world'; + } + ); + } + public function testSimpleAsyncShellBuilder(): void { $this->assertEquals(