Skip to content

Commit b78e83b

Browse files
committed
WIP coverage
1 parent b378d70 commit b78e83b

File tree

4 files changed

+314
-10
lines changed

4 files changed

+314
-10
lines changed

src/VerifiableCredentials/Factories/CredentialOfferFactory.php

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,7 @@ public function from(
2929
?array $parameters = null,
3030
?string $uri = null,
3131
): CredentialOffer {
32-
if (
33-
($parameters !== null && $uri !== null) ||
34-
($parameters === null && $uri === null)
35-
) {
36-
throw new CredentialOfferException('Only one of parameters or uri must be provided.');
37-
}
38-
39-
if ($parameters !== null) {
32+
if ($parameters !== null && $uri === null) {
4033
$credentialIssuer = $parameters[ClaimsEnum::CredentialIssuer->value] ?? null;
4134
$credentialIssuer = $this->helpers->type()->ensureNonEmptyString(
4235
$credentialIssuer,
@@ -75,12 +68,12 @@ public function from(
7568
);
7669
}
7770

78-
if ($uri !== null) {
71+
if ($uri !== null && $parameters === null) {
7972
return new CredentialOffer(
8073
uri: $uri,
8174
);
8275
}
8376

84-
throw new CredentialOfferException('Invalid parameters or uri.');
77+
throw new CredentialOfferException('Only one of parameters or uri must be provided.');
8578
}
8679
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\Test\OpenID\VerifiableCredentials\CredentialOffer;
6+
7+
use PHPUnit\Framework\MockObject\MockObject;
8+
use PHPUnit\Framework\TestCase;
9+
use SimpleSAML\OpenID\VerifiableCredentials\CredentialOffer\CredentialOfferGrantsBag;
10+
use SimpleSAML\OpenID\VerifiableCredentials\CredentialOffer\CredentialOfferParameters;
11+
12+
#[\PHPUnit\Framework\Attributes\CoversClass(CredentialOfferParameters::class)]
13+
final class CredentialOfferParametersTest extends TestCase
14+
{
15+
protected string $credentialIssuer = 'https://example.com/issuer';
16+
17+
protected array $credentialConfigurationIds = ['credential-1', 'credential-2'];
18+
19+
protected MockObject $credentialOfferGrantsBag;
20+
21+
22+
protected function setUp(): void
23+
{
24+
$this->credentialOfferGrantsBag = $this->createMock(CredentialOfferGrantsBag::class);
25+
}
26+
27+
28+
protected function sut(
29+
?string $credentialIssuer = null,
30+
?array $credentialConfigurationIds = null,
31+
false|null|CredentialOfferGrantsBag $credentialOfferGrantsBag = null,
32+
): CredentialOfferParameters {
33+
$credentialIssuer ??= $this->credentialIssuer;
34+
$credentialConfigurationIds ??= $this->credentialConfigurationIds;
35+
$credentialOfferGrantsBag = $credentialOfferGrantsBag === false ?
36+
null :
37+
$credentialOfferGrantsBag ?? $this->credentialOfferGrantsBag;
38+
39+
return new CredentialOfferParameters(
40+
$credentialIssuer,
41+
$credentialConfigurationIds,
42+
$credentialOfferGrantsBag,
43+
);
44+
}
45+
46+
47+
public function testCanCreateInstance(): void
48+
{
49+
$this->assertInstanceOf(CredentialOfferParameters::class, $this->sut());
50+
}
51+
52+
53+
public function testCanJsonSerialize(): void
54+
{
55+
$this->credentialOfferGrantsBag->expects($this->once())->method('jsonSerialize');
56+
57+
$this->assertNotEmpty($this->sut()->jsonSerialize());
58+
}
59+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\Test\OpenID\VerifiableCredentials\Factories;
6+
7+
use PHPUnit\Framework\MockObject\MockObject;
8+
use PHPUnit\Framework\TestCase;
9+
use SimpleSAML\OpenID\Exceptions\CredentialOfferException;
10+
use SimpleSAML\OpenID\Helpers;
11+
use SimpleSAML\OpenID\VerifiableCredentials\CredentialOffer;
12+
use SimpleSAML\OpenID\VerifiableCredentials\CredentialOffer\CredentialOfferGrantsBag;
13+
use SimpleSAML\OpenID\VerifiableCredentials\CredentialOffer\CredentialOfferGrantsValue;
14+
use SimpleSAML\OpenID\VerifiableCredentials\CredentialOffer\CredentialOfferParameters;
15+
use SimpleSAML\OpenID\VerifiableCredentials\Factories\CredentialOfferFactory;
16+
17+
#[\PHPUnit\Framework\Attributes\CoversClass(CredentialOfferFactory::class)]
18+
#[\PHPUnit\Framework\Attributes\UsesClass(CredentialOffer::class)]
19+
#[\PHPUnit\Framework\Attributes\UsesClass(CredentialOfferParameters::class)]
20+
#[\PHPUnit\Framework\Attributes\UsesClass(CredentialOfferGrantsBag::class)]
21+
#[\PHPUnit\Framework\Attributes\UsesClass(CredentialOfferGrantsValue::class)]
22+
final class CredentialOfferFactoryTest extends TestCase
23+
{
24+
protected MockObject $helpersMock;
25+
26+
protected array $sampleParameters = [
27+
'credential_issuer' => 'https://example.com/issuer',
28+
'credential_configuration_ids' => ['credential-1', 'credential-2'],
29+
'grants' => [
30+
'urn:ietf:params:oauth:grant-type:pre-authorized_code' => [
31+
"pre-authorized_code" => "oaKazRN8I0IbtZ0C7JuMn5",
32+
"tx_code" => [
33+
"length" => 4,
34+
"input_mode" => "numeric",
35+
"description" => "Please provide the one-time code that was sent via e-mail",
36+
],
37+
],
38+
],
39+
];
40+
41+
42+
protected function setUp(): void
43+
{
44+
$this->helpersMock = $this->createMock(Helpers::class);
45+
}
46+
47+
48+
protected function sut(
49+
?Helpers $helpers = null,
50+
): CredentialOfferFactory {
51+
$helpers ??= $this->helpersMock;
52+
53+
return new CredentialOfferFactory($helpers);
54+
}
55+
56+
57+
public function testCanCreateInstance(): void
58+
{
59+
$this->assertInstanceOf(CredentialOfferFactory::class, $this->sut());
60+
}
61+
62+
63+
public function testCanBuildFromParameters(): void
64+
{
65+
$this->assertInstanceOf(
66+
CredentialOffer::class,
67+
$this->sut()->from($this->sampleParameters),
68+
);
69+
}
70+
71+
72+
public function testFromThrowsForInvalidGrantData(): void
73+
{
74+
$this->expectException(CredentialOfferException::class);
75+
$this->expectExceptionMessage('Grants');
76+
77+
$parameters = $this->sampleParameters;
78+
$parameters['grants']['urn:ietf:params:oauth:grant-type:pre-authorized_code'] = 123;
79+
$this->sut()->from($parameters);
80+
}
81+
82+
83+
public function testFromUri(): void
84+
{
85+
$this->assertInstanceOf(
86+
CredentialOffer::class,
87+
$this->sut()->from(uri: 'https://example.com/offer'),
88+
);
89+
}
90+
91+
92+
public function testFromThrowsIfBothParametersAndUriIsProvided(): void
93+
{
94+
$this->expectException(CredentialOfferException::class);
95+
$this->expectExceptionMessage('Only one');
96+
97+
$this->sut()->from($this->sampleParameters, 'https://example.com/offer');
98+
}
99+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\Test\OpenID\VerifiableCredentials\Factories;
6+
7+
use Jose\Component\Signature\JWS;
8+
use Jose\Component\Signature\Signature;
9+
use PHPUnit\Framework\MockObject\MockObject;
10+
use PHPUnit\Framework\TestCase;
11+
use SimpleSAML\OpenID\Algorithms\SignatureAlgorithmEnum;
12+
use SimpleSAML\OpenID\Decorators\DateIntervalDecorator;
13+
use SimpleSAML\OpenID\Factories\ClaimFactory;
14+
use SimpleSAML\OpenID\Helpers;
15+
use SimpleSAML\OpenID\Jwks\Factories\JwksDecoratorFactory;
16+
use SimpleSAML\OpenID\Jws\JwsDecorator;
17+
use SimpleSAML\OpenID\Jws\JwsDecoratorBuilder;
18+
use SimpleSAML\OpenID\Jws\JwsVerifierDecorator;
19+
use SimpleSAML\OpenID\Jws\ParsedJws;
20+
use SimpleSAML\OpenID\Serializers\JwsSerializerManagerDecorator;
21+
use SimpleSAML\OpenID\VerifiableCredentials\Factories\OpenId4VciProofFactory;
22+
use SimpleSAML\OpenID\VerifiableCredentials\OpenId4VciProof;
23+
24+
#[\PHPUnit\Framework\Attributes\CoversClass(OpenId4VciProofFactory::class)]
25+
#[\PHPUnit\Framework\Attributes\UsesClass(SignatureAlgorithmEnum::class)]
26+
#[\PHPUnit\Framework\Attributes\UsesClass(ParsedJws::class)]
27+
#[\PHPUnit\Framework\Attributes\UsesClass(OpenId4VciProof::class)]
28+
final class OpenId4VciProofFactoryTest extends TestCase
29+
{
30+
protected MockObject $signatureMock;
31+
32+
protected MockObject $jwsDecoratorBuilderMock;
33+
34+
protected MockObject $jwsVerifierDecoratorMock;
35+
36+
protected MockObject $jwksDecoratorFactoryMock;
37+
38+
protected MockObject $jwsSerializerManagerDecoratorMock;
39+
40+
protected MockObject $dateIntervalDecoratorMock;
41+
42+
protected MockObject $helpersMock;
43+
44+
protected MockObject $jsonHelperMock;
45+
46+
protected MockObject $claimFactoryMock;
47+
48+
protected array $sampleHeader = [
49+
"typ" => "openid4vci-proof+jwt",
50+
"alg" => "ES256",
51+
"jwk" => [
52+
"kty" => "EC",
53+
"crv" => "P-256",
54+
"x" => "nUWAoAv3XZith8E7i19OdaxOLYFOwM-Z2EuM02TirT4",
55+
"y" => "HskHU8BjUi1U9Xqi7Swmj8gwAK_0xkcDjEW_71SosEY",
56+
],
57+
];
58+
59+
protected array $expiredPayload = [
60+
'iat' => 1734009487,
61+
'nbf' => 1734009487,
62+
'exp' => 1734009487,
63+
"iss" => "s6BhdRkqt3",
64+
"aud" => "https://server.example.com",
65+
"nonce" => "tZignsnFbp",
66+
];
67+
68+
protected array $validPayload;
69+
70+
71+
protected function setUp(): void
72+
{
73+
$this->signatureMock = $this->createMock(Signature::class);
74+
75+
$jwsMock = $this->createMock(JWS::class);
76+
$jwsMock->method('getPayload')
77+
->willReturn('json-payload-string'); // Just so we have non-empty value.
78+
$jwsMock->method('getSignature')->willReturn($this->signatureMock);
79+
80+
$jwsDecoratorMock = $this->createMock(JwsDecorator::class);
81+
$jwsDecoratorMock->method('jws')->willReturn($jwsMock);
82+
83+
$this->jwsDecoratorBuilderMock = $this->createMock(JwsDecoratorBuilder::class);
84+
$this->jwsDecoratorBuilderMock->method('fromToken')->willReturn($jwsDecoratorMock);
85+
$this->jwsDecoratorBuilderMock->method('fromData')->willReturn($jwsDecoratorMock);
86+
87+
$this->jwsVerifierDecoratorMock = $this->createMock(JwsVerifierDecorator::class);
88+
$this->jwksDecoratorFactoryMock = $this->createMock(JwksDecoratorFactory::class);
89+
$this->jwsSerializerManagerDecoratorMock = $this->createMock(JwsSerializerManagerDecorator::class);
90+
$this->dateIntervalDecoratorMock = $this->createMock(DateIntervalDecorator::class);
91+
92+
$this->helpersMock = $this->createMock(Helpers::class);
93+
$this->jsonHelperMock = $this->createMock(Helpers\Json::class);
94+
$this->helpersMock->method('json')->willReturn($this->jsonHelperMock);
95+
$typeHelperMock = $this->createMock(Helpers\Type::class);
96+
$this->helpersMock->method('type')->willReturn($typeHelperMock);
97+
98+
$typeHelperMock->method('ensureNonEmptyString')->willReturnArgument(0);
99+
$typeHelperMock->method('ensureInt')->willReturnArgument(0);
100+
101+
$this->claimFactoryMock = $this->createMock(ClaimFactory::class);
102+
103+
$this->validPayload = $this->expiredPayload;
104+
$this->validPayload['exp'] = time() + 3600;
105+
}
106+
107+
108+
protected function sut(
109+
?JwsDecoratorBuilder $jwsDecoratorBuilder = null,
110+
?JwsVerifierDecorator $jwsVerifierDecorator = null,
111+
?JwksDecoratorFactory $jwksDecoratorFactory = null,
112+
?JwsSerializerManagerDecorator $jwsSerializerManagerDecorator = null,
113+
?DateIntervalDecorator $dateIntervalDecorator = null,
114+
?Helpers $helpers = null,
115+
?ClaimFactory $claimFactory = null,
116+
): OpenId4VciProofFactory {
117+
$jwsDecoratorBuilder ??= $this->jwsDecoratorBuilderMock;
118+
$jwsVerifierDecorator ??= $this->jwsVerifierDecoratorMock;
119+
$jwksDecoratorFactory ??= $this->jwksDecoratorFactoryMock;
120+
$jwsSerializerManagerDecorator ??= $this->jwsSerializerManagerDecoratorMock;
121+
$dateIntervalDecorator ??= $this->dateIntervalDecoratorMock;
122+
$helpers ??= $this->helpersMock;
123+
$claimFactory ??= $this->claimFactoryMock;
124+
125+
return new OpenId4VciProofFactory(
126+
$jwsDecoratorBuilder,
127+
$jwsVerifierDecorator,
128+
$jwksDecoratorFactory,
129+
$jwsSerializerManagerDecorator,
130+
$dateIntervalDecorator,
131+
$helpers,
132+
$claimFactory,
133+
);
134+
}
135+
136+
137+
public function testCanCreateInstance(): void
138+
{
139+
$this->assertInstanceOf(OpenId4VciProofFactory::class, $this->sut());
140+
}
141+
142+
143+
public function testCanBuildFromToken(): void
144+
{
145+
$this->jsonHelperMock->method('decode')->willReturn($this->validPayload);
146+
$this->signatureMock->method('getProtectedHeader')->willReturn($this->sampleHeader);
147+
148+
$this->assertInstanceOf(
149+
OpenId4VciProof::class,
150+
$this->sut()->fromToken('token'),
151+
);
152+
}
153+
}

0 commit comments

Comments
 (0)