Skip to content

Commit 42c0ac2

Browse files
committed
Added more coverage for helpers.
1 parent 4796b72 commit 42c0ac2

7 files changed

Lines changed: 260 additions & 50 deletions

File tree

.vortex/tooling/src/notify-slack

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,16 @@ if ($notify_event === 'pre_deployment') {
8484
// Build the message title.
8585
$title = sprintf('%s: %s', $event_label, $notify_project);
8686

87-
// Build fields array - conditionally include Environment and Login for post_deployment only.
87+
// Build fields array - conditionally include Environment and Login for
88+
// post_deployment only.
8889
$fields = [
8990
['title' => 'Deployment', 'value' => $notify_label, 'short' => TRUE],
9091
['title' => 'Time', 'value' => $timestamp, 'short' => TRUE],
9192
];
9293

9394
// Only include Environment and Login links for post-deployment notifications.
94-
// Pre-deployment notifications should not show these as the site is not yet available.
95+
// Pre-deployment notifications should not show these as the site is not yet
96+
// available.
9597
if ($notify_event !== 'pre_deployment') {
9698
array_splice($fields, 1, 0, [
9799
['title' => 'Environment', 'value' => sprintf('<%s|View Site>', $notify_env_url), 'short' => TRUE],
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
/**
5+
* @file
6+
* Fixture for posix_isatty() testing expecting FALSE.
7+
*/
8+
9+
declare(strict_types=1);
10+
11+
namespace DrevOps\VortexTooling;
12+
13+
require_once __DIR__ . '/../../src/helpers.php';
14+
15+
echo 'Calling posix_isatty(STDOUT)' . PHP_EOL;
16+
17+
$result = posix_isatty(STDOUT);
18+
19+
echo 'posix_isatty returned: ' . ($result ? 'true' : 'false') . PHP_EOL;
20+
21+
if ($result === FALSE) {
22+
echo 'SUCCESS: posix_isatty returned false as expected' . PHP_EOL;
23+
}
24+
else {
25+
echo 'FAILURE: posix_isatty returned true, expected false' . PHP_EOL;
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
/**
5+
* @file
6+
* Fixture for posix_isatty() testing expecting TRUE.
7+
*/
8+
9+
declare(strict_types=1);
10+
11+
namespace DrevOps\VortexTooling;
12+
13+
require_once __DIR__ . '/../../src/helpers.php';
14+
15+
echo 'Calling posix_isatty(STDOUT)' . PHP_EOL;
16+
17+
$result = posix_isatty(STDOUT);
18+
19+
echo 'posix_isatty returned: ' . ($result ? 'true' : 'false') . PHP_EOL;
20+
21+
if ($result === TRUE) {
22+
echo 'SUCCESS: posix_isatty returned true as expected' . PHP_EOL;
23+
}
24+
else {
25+
echo 'FAILURE: posix_isatty returned false, expected true' . PHP_EOL;
26+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DrevOps\VortexTooling\Tests\Self;
6+
7+
use DrevOps\VortexTooling\Tests\Unit\UnitTestCase;
8+
use PHPUnit\Framework\AssertionFailedError;
9+
use PHPUnit\Framework\Attributes\CoversClass;
10+
use PHPUnit\Framework\Attributes\DataProvider;
11+
12+
/**
13+
* Self-tests for mocking of the posix_isatty() function.
14+
*
15+
* We test mockPosixIsatty() to ensure it returns the correct boolean value
16+
* that we can use to control terminal color detection in tests.
17+
*/
18+
#[CoversClass(UnitTestCase::class)]
19+
class MockPosixIsattySelfTest extends UnitTestCase {
20+
21+
#[DataProvider('dataProviderMockPosixIsatty')]
22+
public function testMockPosixIsatty(bool $mock_value): void {
23+
$this->mockPosixIsatty($mock_value);
24+
25+
// @phpcs:ignore Drupal.Classes.FullyQualifiedNamespace.UseStatementMissing
26+
$result = \DrevOps\VortexTooling\posix_isatty(STDOUT);
27+
28+
$this->assertEquals($mock_value, $result);
29+
}
30+
31+
public static function dataProviderMockPosixIsatty(): array {
32+
return [
33+
'returns true' => [TRUE],
34+
'returns false' => [FALSE],
35+
];
36+
}
37+
38+
public function testMockPosixIsattyMultipleSuccess(): void {
39+
$this->mockPosixIsatty(TRUE);
40+
$this->mockPosixIsatty(FALSE);
41+
$this->mockPosixIsatty(TRUE);
42+
43+
// @phpcs:ignore Drupal.Classes.FullyQualifiedNamespace.UseStatementMissing
44+
$result1 = \DrevOps\VortexTooling\posix_isatty(STDOUT);
45+
// @phpcs:ignore Drupal.Classes.FullyQualifiedNamespace.UseStatementMissing
46+
$result2 = \DrevOps\VortexTooling\posix_isatty(STDOUT);
47+
// @phpcs:ignore Drupal.Classes.FullyQualifiedNamespace.UseStatementMissing
48+
$result3 = \DrevOps\VortexTooling\posix_isatty(STDOUT);
49+
50+
$this->assertTrue($result1);
51+
$this->assertFalse($result2);
52+
$this->assertTrue($result3);
53+
}
54+
55+
public function testMockPosixIsattyMoreCallsFailure(): void {
56+
$this->mockPosixIsatty(TRUE);
57+
58+
// @phpcs:ignore Drupal.Classes.FullyQualifiedNamespace.UseStatementMissing
59+
$result = \DrevOps\VortexTooling\posix_isatty(STDOUT);
60+
$this->assertTrue($result);
61+
62+
$this->expectException(\RuntimeException::class);
63+
$this->expectExceptionMessage('posix_isatty() called more times than mocked responses. Expected 1 call(s), but attempting call #2.');
64+
65+
// @phpcs:ignore Drupal.Classes.FullyQualifiedNamespace.UseStatementMissing
66+
\DrevOps\VortexTooling\posix_isatty(STDOUT);
67+
}
68+
69+
public function testMockPosixIsattyLessCallsFailure(): void {
70+
$this->mockPosixIsatty(TRUE);
71+
$this->mockPosixIsatty(FALSE);
72+
73+
// @phpcs:ignore Drupal.Classes.FullyQualifiedNamespace.UseStatementMissing
74+
$result = \DrevOps\VortexTooling\posix_isatty(STDOUT);
75+
$this->assertTrue($result);
76+
77+
$this->expectException(AssertionFailedError::class);
78+
$this->expectExceptionMessage('Not all mocked posix_isatty responses were consumed. Expected 2 call(s), but only 1 call(s) were made.');
79+
80+
// Manually trigger the check that normally happens in tearDown().
81+
$this->mockPosixIsattyAssertAllMocksConsumed();
82+
}
83+
84+
#[DataProvider('dataProviderMockPosixIsattyScript')]
85+
public function testMockPosixIsattyScript(bool $mock_value, string $fixture, string $expected): void {
86+
$this->mockPosixIsatty($mock_value);
87+
88+
$output = $this->runScript($fixture);
89+
90+
$this->assertStringContainsString('Calling posix_isatty(STDOUT)', $output);
91+
$this->assertStringContainsString($expected, $output);
92+
}
93+
94+
public static function dataProviderMockPosixIsattyScript(): array {
95+
return [
96+
'true fixture with true mock' => [
97+
TRUE,
98+
'tests/Fixtures/test-posix-isatty-true',
99+
'SUCCESS: posix_isatty returned true as expected',
100+
],
101+
'true fixture with false mock' => [
102+
FALSE,
103+
'tests/Fixtures/test-posix-isatty-true',
104+
'FAILURE: posix_isatty returned false, expected true',
105+
],
106+
'false fixture with false mock' => [
107+
FALSE,
108+
'tests/Fixtures/test-posix-isatty-false',
109+
'SUCCESS: posix_isatty returned false as expected',
110+
],
111+
'false fixture with true mock' => [
112+
TRUE,
113+
'tests/Fixtures/test-posix-isatty-false',
114+
'FAILURE: posix_isatty returned true, expected false',
115+
],
116+
];
117+
}
118+
119+
}

.vortex/tooling/tests/Traits/MockTrait.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,4 +667,39 @@ protected function mockRequestAssertAllMocksConsumed(): void {
667667
$this->assertMockConsumed('request');
668668
}
669669

670+
/**
671+
* Mock posix_isatty function to control terminal color detection.
672+
*
673+
* This mocks the underlying posix_isatty() function that
674+
* term_supports_color() calls, allowing tests to control whether color
675+
* output is enabled.
676+
*
677+
* @param bool $return_value
678+
* The value to return (TRUE for TTY/color support, FALSE for no TTY).
679+
* @param string $namespace
680+
* Namespace to mock the function in (defaults to DrevOps\VortexTooling).
681+
*/
682+
protected function mockPosixIsatty(bool $return_value, string $namespace = 'DrevOps\\VortexTooling'): void {
683+
// Add single response to unified registry.
684+
$this->addMockResponses('posix_isatty', [['value' => $return_value]]);
685+
686+
// Register mock if not already registered.
687+
if (!isset($this->mocks['posix_isatty'])) {
688+
$this->registerMock('posix_isatty', $namespace, function () {
689+
$response = $this->getNextMockResponse('posix_isatty');
690+
return $response['value'];
691+
});
692+
}
693+
}
694+
695+
/**
696+
* Verify all mocked posix_isatty responses were consumed.
697+
*
698+
* @throws \PHPUnit\Framework\AssertionFailedError
699+
* When not all mocked responses were consumed.
700+
*/
701+
protected function mockPosixIsattyAssertAllMocksConsumed(): void {
702+
$this->assertMockConsumed('posix_isatty');
703+
}
704+
670705
}

.vortex/tooling/tests/Unit/FormatterTest.php

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
use PHPUnit\Framework\Attributes\CoversFunction;
99
use PHPUnit\Framework\Attributes\DataProvider;
1010
use PHPUnit\Framework\Attributes\Group;
11+
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
1112

1213
/**
1314
* Tests for output formatter functions.
1415
*
1516
* @phpcs:disable Drupal.Classes.FullyQualifiedNamespace.UseStatementMissing
1617
*/
18+
#[RunTestsInSeparateProcesses]
1719
#[CoversFunction('DrevOps\VortexTooling\note')]
1820
#[CoversFunction('DrevOps\VortexTooling\task')]
1921
#[CoversFunction('DrevOps\VortexTooling\info')]
@@ -24,86 +26,85 @@
2426
#[Group('helpers')]
2527
class FormatterTest extends UnitTestCase {
2628

27-
protected function setUp(): void {
28-
parent::setUp();
29+
#[DataProvider('dataProviderOutputFormatters')]
30+
public function testOutputFormatters(string $function, ?bool $is_tty, string $expected_output): void {
31+
// Mock posix_isatty() BEFORE loading helpers.php.
32+
// Only mock for functions that use term_supports_color (not 'note').
33+
if ($is_tty !== NULL) {
34+
// Set TERM to a valid terminal type (not 'dumb') so color check proceeds.
35+
$this->envSet('TERM', 'xterm-256color');
36+
$this->mockPosixIsatty($is_tty);
37+
}
2938

3039
require_once __DIR__ . '/../../src/helpers.php';
31-
}
32-
33-
#[DataProvider('dataProviderOutputFormatters')]
34-
public function testOutputFormatters(string $function, string $expected_prefix): void {
35-
putenv('TERM=dumb');
3640

3741
ob_start();
3842
$callable = 'DrevOps\\VortexTooling\\' . $function;
3943
// @phpstan-ignore-next-line argument.type
4044
call_user_func($callable, 'Test message %s', 'arg');
4145
$output = ob_get_clean();
42-
$this->assertIsString($output);
43-
44-
if ($function === 'note') {
45-
$this->assertEquals(" Test message arg\n", $output);
46-
}
47-
else {
48-
$this->assertEquals($expected_prefix . "Test message arg\n", $output);
49-
}
50-
}
51-
52-
public static function dataProviderOutputFormatters(): array {
53-
return [
54-
'note' => ['note', ' '],
55-
'task' => ['task', '[TASK] '],
56-
'info' => ['info', '[INFO] '],
57-
'pass' => ['pass', '[ OK ] '],
58-
'fail_no_exit' => ['fail_no_exit', '[FAIL] '],
59-
];
60-
}
6146

62-
#[DataProvider('dataProviderOutputFormattersWithColor')]
63-
public function testOutputFormattersWithColor(string $function, string $expected_prefix): void {
64-
putenv('TERM=xterm-256color');
65-
66-
ob_start();
67-
$callable = 'DrevOps\\VortexTooling\\' . $function;
68-
// @phpstan-ignore-next-line argument.type
69-
call_user_func($callable, 'Test');
70-
$output = ob_get_clean();
7147
$this->assertIsString($output);
72-
73-
$this->assertStringContainsString($expected_prefix, $output);
74-
$this->assertStringContainsString('Test', $output);
48+
$this->assertEquals($expected_output, $output);
7549
}
7650

77-
public static function dataProviderOutputFormattersWithColor(): array {
51+
public static function dataProviderOutputFormatters(): array {
7852
return [
79-
'task' => ['task', '[TASK]'],
80-
'info' => ['info', '[INFO]'],
81-
'pass' => ['pass', '[ OK ]'],
53+
// Note - does not use term_supports_color, always plain output.
54+
'note' => ['note', NULL, " Test message arg\n"],
55+
// Task - blue (34m).
56+
'task, no color' => ['task', FALSE, "[TASK] Test message arg\n"],
57+
'task, with color' => ['task', TRUE, "\033[34m[TASK] Test message arg\033[0m\n"],
58+
// Info - cyan (36m).
59+
'info, no color' => ['info', FALSE, "[INFO] Test message arg\n"],
60+
'info, with color' => ['info', TRUE, "\033[36m[INFO] Test message arg\033[0m\n"],
61+
// Pass - green (32m).
62+
'pass, no color' => ['pass', FALSE, "[ OK ] Test message arg\n"],
63+
'pass, with color' => ['pass', TRUE, "\033[32m[ OK ] Test message arg\033[0m\n"],
64+
// Fail_no_exit - red (31m).
65+
'fail_no_exit, no color' => ['fail_no_exit', FALSE, "[FAIL] Test message arg\n"],
66+
'fail_no_exit, with color' => ['fail_no_exit', TRUE, "\033[31m[FAIL] Test message arg\033[0m\n"],
8267
];
8368
}
8469

85-
public function testFail(): void {
70+
#[DataProvider('dataProviderFail')]
71+
public function testFail(bool $is_tty, string $expected_output): void {
72+
// Set TERM to a valid terminal type and mock posix_isatty BEFORE loading.
73+
$this->envSet('TERM', 'xterm-256color');
74+
$this->mockPosixIsatty($is_tty);
8675
$this->mockQuit(1);
8776

77+
require_once __DIR__ . '/../../src/helpers.php';
78+
8879
$this->expectException(QuitErrorException::class);
8980
$this->expectExceptionCode(1);
9081

9182
try {
9283
ob_start();
93-
\DrevOps\VortexTooling\fail('Test failure');
84+
\DrevOps\VortexTooling\fail('Test failure %s', 'message');
9485
}
9586
finally {
96-
ob_end_clean();
87+
$output = ob_get_clean();
88+
$this->assertEquals($expected_output, $output);
9789
}
9890
}
9991

92+
public static function dataProviderFail(): array {
93+
return [
94+
'no color' => [FALSE, "[FAIL] Test failure message\n"],
95+
'with color' => [TRUE, "\033[31m[FAIL] Test failure message\033[0m\n"],
96+
];
97+
}
98+
10099
#[DataProvider('dataProviderTermSupportsColor')]
101100
public function testTermSupportsColor(string|bool $term_value, bool $expected): void {
101+
require_once __DIR__ . '/../../src/helpers.php';
102+
102103
if ($term_value === FALSE) {
103-
putenv('TERM');
104+
$this->envUnset('TERM');
104105
}
105106
else {
106-
putenv('TERM=' . $term_value);
107+
$this->envSet('TERM', (string) $term_value);
107108
}
108109

109110
$result = \DrevOps\VortexTooling\term_supports_color();

.vortex/tooling/tests/Unit/NotifySlackTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ public function testSuccessfulNotificationPreDeployment(): void {
7575
// Verify pre-deployment styling.
7676
$this->assertEquals('#808080', $payload['attachments'][0]['color']);
7777
$this->assertStringContainsString('Deployment Starting', $payload['attachments'][0]['title']);
78-
// Verify fields - should only have Deployment and Time, not Environment or Login.
78+
// Verify fields - should only have Deployment and Time, not Environment
79+
// or Login.
7980
$fields = $payload['attachments'][0]['fields'];
8081
$this->assertCount(2, $fields, 'Pre-deployment should only have 2 fields');
8182
$this->assertEquals('Deployment', $fields[0]['title']);

0 commit comments

Comments
 (0)