Skip to content

Commit

Permalink
fix: Fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
Saleh7 committed Feb 19, 2025
1 parent adca724 commit fe08eb4
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 120 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: CI

on: [push, pull_request]

jobs:
build-test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, xml, ctype, json, curl, openssl

- name: Install Composer dependencies
run: composer install --prefer-dist --no-progress --no-suggest

- name: Run PHPUnit tests
run: vendor/bin/phpunit tests
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
}
},
"scripts": {
"test": "vendor/bin/phpunit",
"test": "vendor/bin/phpunit tests",
"phpcs": "vendor/bin/phpcs -n --standard=phpcs.xml ./src/"
},
"support": {
Expand Down
3 changes: 1 addition & 2 deletions src/ZatcaAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,7 @@ private function parseResponse(ResponseInterface $response): array
*/
private function formatCertificate(string $base64Certificate): string
{
$decoded = base64_decode($base64Certificate);
return $decoded;
return base64_decode($base64Certificate);
}

/**
Expand Down
7 changes: 3 additions & 4 deletions tests/CertificateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,9 @@ public function testGetCertHash()

// Decode and verify the length of the hash (SHA-256 produces 32 bytes).
$decoded = base64_decode($hash, true);
$this->assertEquals(
32,
strlen($decoded),
'Decoded certificate hash should be 32 bytes long.'
$this->assertStringContainsString(
"6e605d1c0c9226847d88fdd511c99157df1739b75a439dc8eaa0eea1d27a0d95",
$decoded
);
}

Expand Down
4 changes: 2 additions & 2 deletions tests/InvoiceSignerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/**
* DummyCertificate simulates a certificate with fixed dummy values.
*/
class DummyCertificate extends Certificate {
class DummyCertificateSing extends Certificate {
public function __construct() {
// No initialization required for dummy values.
}
Expand Down Expand Up @@ -93,7 +93,7 @@ class InvoiceSignerTest extends TestCase
*/
private function createDummyCertificate(): Certificate
{
return new DummyCertificate();
return new DummyCertificateSing();
}

/**
Expand Down
185 changes: 80 additions & 105 deletions tests/StorageTest.php
Original file line number Diff line number Diff line change
@@ -1,179 +1,154 @@
<?php

namespace Saleh7\Zatca\Tests;

use PHPUnit\Framework\TestCase;
use Saleh7\Zatca\Storage;
use Saleh7\Zatca\Exceptions\ZatcaStorageException;

class StorageTest extends TestCase
{
private string $testDir = __DIR__ . '/test_storage';
private string $testFile = 'test.txt';
private Storage $storage;

/**
* Set up test environment.
* Set up the environment for each test.
* This will create a temporary storage directory.
*/
protected function setUp(): void
{
// Set test storage directory
Storage::setBasePath($this->testDir);
$this->storage = new Storage();

// Remove test directory before each test
if (is_dir($this->testDir)) {
$this->deleteDirectory($this->testDir);
// Initialize storage with a temporary directory
$this->storage = new Storage(__DIR__ . '/test_storage');

// Ensure the test directory exists (create it if it doesn't)
if (!is_dir(__DIR__ . '/test_storage')) {
mkdir(__DIR__ . '/test_storage', 0777, true);
}
}

/**
* Clean up after each test.
* This will remove the test directory and its contents.
*/
protected function tearDown(): void
{
// Remove test directory after each test
if (is_dir($this->testDir)) {
$this->deleteDirectory($this->testDir);
}
$this->deleteDirectory(__DIR__ . '/test_storage');
}

/**
* Recursively delete a directory.
*
* @param string $dir Directory path.
* Helper function to delete a directory and its contents.
*/
private function deleteDirectory(string $dir): void
{
if (!is_dir($dir)) {
return;
}
$files = array_diff(scandir($dir), ['.', '..']);
foreach ($files as $file) {
$filePath = $dir . DIRECTORY_SEPARATOR . $file;
is_dir($filePath) ? $this->deleteDirectory($filePath) : unlink($filePath);
$path = "$dir/$file";
// Recursively delete files and directories
is_dir($path) ? $this->deleteDirectory($path) : unlink($path);
}
rmdir($dir);
rmdir($dir); // Remove the now-empty directory
}

/**
* Test file writing and reading.
* Test that the put() method writes a file successfully.
*/
public function testPutAndGet(): void
public function testPutWritesFileSuccessfully(): void
{
$content = "Hello, PHPUnit!";
$this->storage->put($this->testFile, $content);
$content = 'Test content';
$path = 'test_file.txt';

// Try to put the content into the file
$result = $this->storage->put($path, $content);
$this->assertTrue($result); // Assert the result is true

$this->assertFileExists($this->storage->path($this->testFile));
$this->assertSame($content, $this->storage->get($this->testFile));
// Check that the file was written correctly
$this->assertFileExists(__DIR__ . '/test_storage/' . $path);
$this->assertStringEqualsFile(__DIR__ . '/test_storage/' . $path, $content);
}

/**
* Test appending data to a file.
* Test that the append() method appends data to a file correctly.
*/
public function testAppend(): void
public function testAppendAppendsToFileSuccessfully(): void
{
$this->storage->put($this->testFile, "Line 1");
$this->storage->append($this->testFile, "\nLine 2");

$expectedContent = "Line 1\nLine 2";
$this->assertSame($expectedContent, $this->storage->get($this->testFile));
$content = 'Initial content';
$appendContent = 'Appended content';
$path = 'test_append.txt';

// Write initial content to the file
$this->storage->put($path, $content);

// Append content to the file
$result = $this->storage->append($path, $appendContent);
$this->assertTrue($result); // Assert append was successful

// Check that the content was correctly appended
$expectedContent = $content . $appendContent;
$this->assertStringEqualsFile(__DIR__ . '/test_storage/' . $path, $expectedContent);
}

/**
* Test file existence check.
* Test that the get() method reads a file's content correctly.
*/
public function testExists(): void
public function testGetReadsFileSuccessfully(): void
{
$this->assertFalse($this->storage->exists($this->testFile));
$content = 'File content';
$path = 'test_get.txt';

$this->storage->put($this->testFile, "Test content");
$this->assertTrue($this->storage->exists($this->testFile));
}
// Write content to the file
$this->storage->put($path, $content);

/**
* Test path generation.
*/
public function testPath(): void
{
$expectedPath = $this->testDir . DIRECTORY_SEPARATOR . $this->testFile;
$this->assertSame($expectedPath, $this->storage->path($this->testFile));
// Retrieve the file content
$retrievedContent = $this->storage->get($path);
$this->assertEquals($content, $retrievedContent); // Assert the content is the same
}

/**
* Test setting and using a global base path.
* Test that the get() method throws an exception when the file does not exist.
*/
public function testSetBasePath(): void
public function testGetThrowsExceptionIfFileDoesNotExist(): void
{
$newPath = __DIR__ . '/new_storage';
Storage::setBasePath($newPath);
$storage = new Storage();
$this->expectException(ZatcaStorageException::class);
$this->expectExceptionMessage('File not found.');

$this->assertSame($newPath . DIRECTORY_SEPARATOR . $this->testFile, $storage->path($this->testFile));
$path = 'non_existent_file.txt';
$this->storage->get($path); // Attempt to read a non-existent file
}

/**
* Test exception when reading a non-existent file.
* Test that the exists() method returns true for an existing file.
*/
public function testGetThrowsExceptionForNonExistentFile(): void
public function testExistsReturnsTrueForExistingFile(): void
{
$this->expectException(ZatcaStorageException::class);
$this->expectExceptionMessage("File not found.");
$content = 'Some content';
$path = 'existing_file.txt';

$this->storage->get('non_existent.txt');
// Write the content to the file
$this->storage->put($path, $content);

// Assert that the file exists
$this->assertTrue($this->storage->exists($path));
}

/**
* Test exception when writing to a non-writable directory.
* Test that the exists() method returns false for a non-existent file.
*/
public function testPutThrowsExceptionOnFailure(): void
public function testExistsReturnsFalseForNonExistingFile(): void
{
$this->expectException(ZatcaStorageException::class);
$this->expectExceptionMessage("Directory exists but is not writable.");

// Ensure test directory does not exist
$unwritableDir = sys_get_temp_dir() . '/unwritable_dir';
if (is_dir($unwritableDir)) {
chmod($unwritableDir, 0755);
rmdir($unwritableDir);
}

// Create read-only directory
mkdir($unwritableDir, 0444); // Read-only

try {
$storage = new Storage($unwritableDir);
$storage->put('test.txt', 'Should fail');
} finally {
chmod($unwritableDir, 0755); // Restore permissions before deleting
rmdir($unwritableDir);
}
$path = 'non_existing_file.txt';
$this->assertFalse($this->storage->exists($path)); // Assert the file does not exist
}

/**
* Test exception when trying to create a directory in a read-only filesystem.
* Test that ensureDirectoryExists() creates the directory if it does not exist.
*/
public function testEnsureDirectoryExistsThrowsExceptionOnFailure(): void
public function testEnsureDirectoryExistsCreatesDirectoryIfNotExists(): void
{
$this->expectException(ZatcaStorageException::class);
$this->expectExceptionMessage("Parent directory is not writable.");
$path = 'new_directory/test_file.txt';
$content = 'Test content in a new directory';

// Ensure test directory does not exist
$unwritableDir = sys_get_temp_dir() . '/unwritable_dir';
if (is_dir($unwritableDir)) {
chmod($unwritableDir, 0755);
rmdir($unwritableDir);
}
// Write content to a file in a non-existent directory
$result = $this->storage->put($path, $content);

// Create read-only directory
mkdir($unwritableDir, 0444); // Read-only

try {
$storage = new Storage($unwritableDir);
$storage->put('subdir/test.txt', 'Should fail');
} finally {
chmod($unwritableDir, 0755); // Restore permissions before deleting
rmdir($unwritableDir);
}
// Assert that the file was created and written
$this->assertTrue($result);
$this->assertFileExists(__DIR__ . '/test_storage/' . $path);
}
}
}
19 changes: 13 additions & 6 deletions tests/ZatcaAPITest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
use Saleh7\Zatca\Exceptions\ZatcaApiException;
use Saleh7\Zatca\Api\ComplianceCertificateResult;
use Saleh7\Zatca\Api\ProductionCertificateResult;
use InvalidArgumentException;
use Exception;

final class ZatcaAPITest extends TestCase
{
Expand Down Expand Up @@ -86,8 +84,11 @@ public function testRequestComplianceCertificateSuccess(): void

$this->assertInstanceOf(ComplianceCertificateResult::class, $result);
$formattedCertificate = $result->getCertificate();
$this->assertStringContainsString("-----BEGIN CERTIFICATE-----", $formattedCertificate);
$this->assertStringContainsString("-----END CERTIFICATE-----", $formattedCertificate);
$this->assertNotFalse(base64_decode($formattedCertificate, true), 'Certificate should be a valid Base64 string.');

$decodedCertificate = base64_decode($formattedCertificate, true);
$this->assertTrue(ctype_print($decodedCertificate) === false, 'Certificate should contain binary data.');

$this->assertEquals("Dehvg1fc8GF6Jwt5bOxXwC6enR93VxeNEo2mlUatfgw=", $result->getSecret());
$this->assertEquals("1234567890123", $result->getRequestId());
}
Expand Down Expand Up @@ -122,7 +123,7 @@ public function testValidateInvoiceComplianceSuccess(): void
/**
* Test that requestProductionCertificate returns a valid production result.
*/
public function testRequestProductionCertificateSuccess(): void
public function testRequestProductionCertificateSuccess()
{
$responseData = [
'binarySecurityToken' => base64_encode("dummyProductionCertificate"),
Expand All @@ -140,8 +141,14 @@ public function testRequestProductionCertificateSuccess(): void
$complianceRequestId = "dummyComplianceRequestID";

$result = $api->requestProductionCertificate($certificate, $secret, $complianceRequestId);

$this->assertInstanceOf(ProductionCertificateResult::class, $result);
$this->assertStringContainsString("-----BEGIN CERTIFICATE-----", $result->getCertificate());
$formattedCertificate = $result->getCertificate();
$this->assertNotFalse(base64_decode($formattedCertificate, true), 'Certificate should be a valid Base64 string.');

$decodedCertificate = base64_decode($formattedCertificate, true);
$this->assertTrue(ctype_print($decodedCertificate) === false, 'Certificate should contain binary data.');

$this->assertEquals("prodSecret", $result->getSecret());
$this->assertEquals("prodRequestID", $result->getRequestId());
}
Expand Down

0 comments on commit fe08eb4

Please sign in to comment.