diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 186d1d7..4926913 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -49,10 +49,9 @@ jobs:
path: artifacts
- name: Create release
- env:
- GitHub_Access_Token: ${{ secrets.GITHUB_TOKEN }}
- GitHub_Repository: ${{ github.repository }}
- run: ./build.sh --target PublishToGitHub --skip PublishArtifacts
-
-
-
+ run: >
+ ./build.sh
+ --target PublishToGitHub
+ --skip PublishArtifacts
+ --github-access-token ${{ secrets.GITHUB_TOKEN }}
+ --github-repository ${{ github.repository }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index dd3363f..f4d5601 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -29,8 +29,10 @@ jobs:
path: ./artifacts
token: ${{ secrets.GITHUB_TOKEN }}
- - name: Push assets to NuGet
- env:
- NuGet_Source: ${{ secrets.NUGET_SOURCE }}
- NuGet_ApiKey: ${{ secrets.NUGET_APIKEY }}
- run: ./build.sh --target PublishToNuGetFeed --skip PublishArtifacts
\ No newline at end of file
+ - name: Push assets to NuGet
+ run: >
+ ./build.sh
+ --target PublishToNuGetFeed
+ --skip PublishArtifacts
+ --nuget-api-key ${{ secrets.NUGET_APIKEY }}
+ --nuget-source ${{ secrets.NUGET_SOURCE }}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index dfcfd56..667a9e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -348,3 +348,6 @@ MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
+
+# VerifyTests files
+*.received.*
diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json
index 0d5d962..b1137cd 100644
--- a/.nuke/build.schema.json
+++ b/.nuke/build.schema.json
@@ -20,7 +20,8 @@
},
"GitHubAccessToken": {
"type": "string",
- "description": "GitHub access token used for creating a new or updating an existing release"
+ "description": "GitHub access token used for creating a new or updating an existing release",
+ "default": "Secrets must be entered via 'nuke :secrets [profile]'"
},
"GitHubRepository": {
"type": "string",
@@ -57,7 +58,8 @@
},
"NuGetApiKey": {
"type": "string",
- "description": "NuGet API key used to pushing the NuGet package"
+ "description": "NuGet API key used to pushing the NuGet package",
+ "default": "Secrets must be entered via 'nuke :secrets [profile]'"
},
"NuGetSource": {
"type": "string",
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..787c3b8
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,26 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "name": ".NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ // If you have changed target frameworks, make sure to update the program path.
+ "program": "${workspaceFolder}/build/bin/Debug/net6.0/Build.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/build",
+ // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
+ "console": "internalConsole",
+ "stopAtEntry": false
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..eb9110d
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,41 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/build/Build.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/build/Build.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "--project",
+ "${workspaceFolder}/build/Build.csproj"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/build/Build.cs b/build/Build.cs
index 197d570..bcb730b 100644
--- a/build/Build.cs
+++ b/build/Build.cs
@@ -7,6 +7,7 @@ class Build : NukeBuild
readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;
[Parameter("GitHub access token used for creating a new or updating an existing release.")]
+ [Secret]
readonly string GitHubAccessToken;
[Parameter("GitHub repository owner and name used for creating a new or updating an existing release. For example: 'stevenkuhn/openiddict-litedb'.")]
@@ -16,6 +17,7 @@ class Build : NukeBuild
readonly string NuGetSource = "https://api.nuget.org/v3/index.json";
[Parameter("NuGet API key used to pushing the NuGet package.")]
+ [Secret]
readonly string NuGetApiKey;
[Solution] readonly Solution Solution;
diff --git a/build/Build.v3.ncrunchproject b/build/Build.v3.ncrunchproject
new file mode 100644
index 0000000..319cd52
--- /dev/null
+++ b/build/Build.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBApplication.cs b/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBApplication.cs
index d61a228..cc2c797 100644
--- a/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBApplication.cs
+++ b/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBApplication.cs
@@ -57,8 +57,8 @@ public class OpenIddictLiteDBApplication
/// Gets or sets the localized display names associated with the current application.
///
[BsonField("display_names")]
- public virtual IReadOnlyDictionary? DisplayNames { get; set; }
- = ImmutableDictionary.Create();
+ public virtual ImmutableDictionary? DisplayNames { get; set; }
+ = ImmutableDictionary.Create();
///
/// Gets or sets the unique identifier associated with the current application.
@@ -70,35 +70,34 @@ public class OpenIddictLiteDBApplication
/// Gets or sets the permissions associated with the current application.
///
[BsonField("permissions")]
- public virtual IReadOnlyList? Permissions { get; set; } = ImmutableList.Create();
+ public virtual ImmutableArray? Permissions { get; set; } = ImmutableArray.Create();
///
/// Gets or sets the logout callback URLs associated with the current application.
///
[BsonField("post_logout_redirect_uris")]
- public virtual IReadOnlyList? PostLogoutRedirectUris { get; set; } = ImmutableList.Create();
+ public virtual ImmutableArray? PostLogoutRedirectUris { get; set; } = ImmutableArray.Create();
///
/// Gets or sets the additional properties associated with the current application.
///
[BsonField("properties")]
- public virtual IReadOnlyDictionary? Properties { get; set; }
+ public virtual ImmutableDictionary? Properties { get; set; }
///
/// Gets or sets the callback URLs associated with the current application.
///
[BsonField("redirect_uris")]
- public virtual IReadOnlyList? RedirectUris { get; set; } = ImmutableList.Create();
+ public virtual ImmutableArray? RedirectUris { get; set; } = ImmutableArray.Create();
///
/// Gets or sets the requirements associated with the current application.
///
[BsonField("requirements")]
- public virtual IReadOnlyList? Requirements { get; set; } = ImmutableList.Create();
+ public virtual ImmutableArray? Requirements { get; set; } = ImmutableArray.Create();
///
- /// Gets or sets the application type
- /// associated with the current application.
+ /// Gets or sets the application type associated with the current application.
///
[BsonField("type")]
public virtual string? Type { get; set; }
diff --git a/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBAuthorization.cs b/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBAuthorization.cs
index 82c13d6..00bced4 100644
--- a/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBAuthorization.cs
+++ b/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBAuthorization.cs
@@ -37,7 +37,7 @@ public class OpenIddictLiteDBAuthorization
/// Gets or sets the UTC creation date of the current authorization.
///
[BsonField("creation_date")]
- public virtual DateTime? CreationDate { get; set; }
+ public virtual DateTimeOffset? CreationDate { get; set; }
///
/// Gets or sets the unique identifier associated with the current authorization.
@@ -49,13 +49,13 @@ public class OpenIddictLiteDBAuthorization
/// Gets or sets the additional properties associated with the current authorization.
///
[BsonField("properties")]
- public virtual IReadOnlyDictionary? Properties { get; set; }
+ public virtual ImmutableDictionary? Properties { get; set; }
///
/// Gets or sets the scopes associated with the current authorization.
///
[BsonField("scopes")]
- public virtual IReadOnlyList? Scopes { get; set; } = ImmutableList.Create();
+ public virtual ImmutableArray? Scopes { get; set; } = ImmutableArray.Create();
///
/// Gets or sets the status of the current authorization.
diff --git a/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBScope.cs b/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBScope.cs
index 8f76a80..dad8b94 100644
--- a/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBScope.cs
+++ b/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBScope.cs
@@ -37,8 +37,8 @@ public class OpenIddictLiteDBScope
/// Gets or sets the localized public descriptions associated with the current scope.
///
[BsonField("descriptions")]
- public virtual IReadOnlyDictionary? Descriptions { get; set; }
- = ImmutableDictionary.Create();
+ public virtual ImmutableDictionary? Descriptions { get; set; }
+ = ImmutableDictionary.Create();
///
/// Gets or sets the display name associated with the current scope.
@@ -50,8 +50,8 @@ public class OpenIddictLiteDBScope
/// Gets or sets the localized display names associated with the current scope.
///
[BsonField("display_names")]
- public virtual IReadOnlyDictionary? DisplayNames { get; set; }
- = ImmutableDictionary.Create();
+ public virtual ImmutableDictionary? DisplayNames { get; set; }
+ = ImmutableDictionary.Create();
///
/// Gets or sets the unique identifier associated with the current scope.
@@ -69,11 +69,11 @@ public class OpenIddictLiteDBScope
/// Gets or sets the additional properties associated with the current scope.
///
[BsonField("properties")]
- public virtual IReadOnlyDictionary? Properties { get; set; }
+ public virtual ImmutableDictionary? Properties { get; set; }
///
/// Gets or sets the resources associated with the current scope.
///
[BsonField("resources")]
- public virtual IReadOnlyList? Resources { get; set; } = ImmutableList.Create();
+ public virtual ImmutableArray? Resources { get; set; } = ImmutableArray.Create();
}
diff --git a/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBToken.cs b/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBToken.cs
index 859b9e3..a118030 100644
--- a/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBToken.cs
+++ b/src/Sknet.OpenIddict.LiteDB.Models/OpenIddictLiteDBToken.cs
@@ -43,13 +43,13 @@ public class OpenIddictLiteDBToken
/// Gets or sets the UTC creation date of the current token.
///
[BsonField("creation_date")]
- public virtual DateTime? CreationDate { get; set; }
+ public virtual DateTimeOffset? CreationDate { get; set; }
///
/// Gets or sets the UTC expiration date of the current token.
///
[BsonField("expiration_date")]
- public virtual DateTime? ExpirationDate { get; set; }
+ public virtual DateTimeOffset? ExpirationDate { get; set; }
///
/// Gets or sets the unique identifier associated with the current token.
@@ -69,13 +69,13 @@ public class OpenIddictLiteDBToken
/// Gets or sets the additional properties associated with the current token.
///
[BsonField("properties")]
- public virtual IReadOnlyDictionary? Properties { get; set; }
+ public virtual ImmutableDictionary? Properties { get; set; }
///
/// Gets or sets the UTC redemption date of the current token.
///
[BsonField("redemption_date")]
- public virtual DateTime? RedemptionDate { get; set; }
+ public virtual DateTimeOffset? RedemptionDate { get; set; }
///
/// Gets or sets the reference identifier associated
diff --git a/src/Sknet.OpenIddict.LiteDB.Models/Sknet.OpenIddict.LiteDB.Models.csproj b/src/Sknet.OpenIddict.LiteDB.Models/Sknet.OpenIddict.LiteDB.Models.csproj
index 8c0f9ab..4d1a1dd 100644
--- a/src/Sknet.OpenIddict.LiteDB.Models/Sknet.OpenIddict.LiteDB.Models.csproj
+++ b/src/Sknet.OpenIddict.LiteDB.Models/Sknet.OpenIddict.LiteDB.Models.csproj
@@ -40,7 +40,7 @@
-
+
diff --git a/src/Sknet.OpenIddict.LiteDB.Models/Usings.cs b/src/Sknet.OpenIddict.LiteDB.Models/Usings.cs
index 954fe3d..5b02c7d 100644
--- a/src/Sknet.OpenIddict.LiteDB.Models/Usings.cs
+++ b/src/Sknet.OpenIddict.LiteDB.Models/Usings.cs
@@ -1,4 +1,5 @@
global using LiteDB;
global using System.Collections.Immutable;
global using System.Diagnostics;
-global using System.Text.Json;
\ No newline at end of file
+global using System.Globalization;
+global using System.Text.Json;
diff --git a/src/Sknet.OpenIddict.LiteDB/IOpenIddictLiteDBContext.cs b/src/Sknet.OpenIddict.LiteDB/IOpenIddictLiteDBContext.cs
index 68a872f..7fa816c 100644
--- a/src/Sknet.OpenIddict.LiteDB/IOpenIddictLiteDBContext.cs
+++ b/src/Sknet.OpenIddict.LiteDB/IOpenIddictLiteDBContext.cs
@@ -24,7 +24,7 @@ public interface IOpenIddictLiteDBContext
/// Gets the .
///
///
- /// A that can be used to monitor the
+ /// A that can be used to monitor the
/// asynchronous operation, whose result returns the LiteDB database.
///
ValueTask GetDatabaseAsync(CancellationToken cancellationToken);
diff --git a/src/Sknet.OpenIddict.LiteDB/OpenIddictLiteDBExtensions.cs b/src/Sknet.OpenIddict.LiteDB/OpenIddictLiteDBExtensions.cs
index 05b6f5f..fb0d6d2 100644
--- a/src/Sknet.OpenIddict.LiteDB/OpenIddictLiteDBExtensions.cs
+++ b/src/Sknet.OpenIddict.LiteDB/OpenIddictLiteDBExtensions.cs
@@ -15,7 +15,6 @@
*/
namespace Microsoft.Extensions.DependencyInjection;
-
///
/// Exposes extensions allowing to register the OpenIddict LiteDB services.
///
diff --git a/src/Sknet.OpenIddict.LiteDB/OpenIddictLiteDBOptions.cs b/src/Sknet.OpenIddict.LiteDB/OpenIddictLiteDBOptions.cs
index 1c2dbb3..99501a4 100644
--- a/src/Sknet.OpenIddict.LiteDB/OpenIddictLiteDBOptions.cs
+++ b/src/Sknet.OpenIddict.LiteDB/OpenIddictLiteDBOptions.cs
@@ -21,14 +21,14 @@ namespace Sknet.OpenIddict.LiteDB;
public class OpenIddictLiteDBOptions
{
///
- /// Gets or sets the name of the applications collection (by default, openiddict.applications).
+ /// Gets or sets the name of the applications collection (by default, openiddict_applications).
///
- public string ApplicationsCollectionName { get; set; } = "openiddict.applications";
+ public string ApplicationsCollectionName { get; set; } = "openiddict_applications";
///
- /// Gets or sets the name of the authorizations collection (by default, openiddict.authorizations).
+ /// Gets or sets the name of the authorizations collection (by default, openiddict_authorizations).
///
- public string AuthorizationsCollectionName { get; set; } = "openiddict.authorizations";
+ public string AuthorizationsCollectionName { get; set; } = "openiddict_authorizations";
///
/// Gets or sets the used by the OpenIddict stores.
@@ -37,12 +37,12 @@ public class OpenIddictLiteDBOptions
public ILiteDatabase? Database { get; set; }
///
- /// Gets or sets the name of the scopes collection (by default, openiddict.scopes).
+ /// Gets or sets the name of the scopes collection (by default, openiddict_scopes).
///
- public string ScopesCollectionName { get; set; } = "openiddict.scopes";
+ public string ScopesCollectionName { get; set; } = "openiddict_scopes";
///
- /// Gets or sets the name of the tokens collection (by default, openiddict.tokens).
+ /// Gets or sets the name of the tokens collection (by default, openiddict_tokens).
///
- public string TokensCollectionName { get; set; } = "openiddict.tokens";
+ public string TokensCollectionName { get; set; } = "openiddict_tokens";
}
\ No newline at end of file
diff --git a/src/Sknet.OpenIddict.LiteDB/OpenIddictLiteDatabase.cs b/src/Sknet.OpenIddict.LiteDB/OpenIddictLiteDatabase.cs
new file mode 100644
index 0000000..ec0eb81
--- /dev/null
+++ b/src/Sknet.OpenIddict.LiteDB/OpenIddictLiteDatabase.cs
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2022 Steven Kuhn and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using LiteDB.Engine;
+using JsonSerializer = System.Text.Json.JsonSerializer;
+
+namespace Sknet.OpenIddict.LiteDB;
+
+///
+public class OpenIddictLiteDatabase : LiteDatabase
+{
+ ///
+ public OpenIddictLiteDatabase(string connectionString, BsonMapper? mapper = null)
+ : base(connectionString, mapper)
+ {
+ ConfigureMapper();
+ }
+
+ ///
+ public OpenIddictLiteDatabase(ConnectionString connectionString, BsonMapper? mapper = null)
+ : base(connectionString, mapper)
+ {
+ ConfigureMapper();
+ }
+
+ ///
+ public OpenIddictLiteDatabase(Stream stream, BsonMapper? mapper = null, Stream? logStream = null)
+ : base(stream, mapper, logStream)
+ {
+ ConfigureMapper();
+ }
+
+ ///
+ public OpenIddictLiteDatabase(ILiteEngine engine, BsonMapper? mapper = null, bool disposeOnClose = true)
+ : base(engine, mapper, disposeOnClose)
+ {
+ ConfigureMapper();
+ }
+
+ private void ConfigureMapper()
+ {
+ if (Mapper == null)
+ {
+ throw new NotImplementedException();
+ }
+
+ Mapper.RegisterType>
+ (
+ serialize: dictionary =>
+ {
+ if (dictionary == null) { return null; }
+
+ var document = new BsonDocument();
+ foreach (var pair in dictionary)
+ {
+ document.Add(pair.Key.Name, pair.Value);
+ }
+ return document;
+ },
+ deserialize: bson => bson.AsDocument.ToImmutableDictionary(
+ pair => new CultureInfo(pair.Key),
+ pair => pair.Value.AsString)
+ );
+ Mapper.RegisterType>
+ (
+ serialize: items => items != null
+ ? new BsonArray(items.Select(x => new BsonValue(x)))
+ : null,
+ deserialize: bson => bson.AsArray.Select(x => x.AsString).ToImmutableArray()
+ );
+ Mapper.RegisterType>
+ (
+ serialize: dictionary => dictionary != null
+ ? JsonSerializer.Serialize(dictionary)
+ : null,
+ deserialize: bson => JsonSerializer.Deserialize>(bson.AsString)
+ ?? ImmutableDictionary.Empty
+ );
+ }
+}
diff --git a/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBApplicationStore.cs b/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBApplicationStore.cs
index 836bdae..fdaf287 100644
--- a/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBApplicationStore.cs
+++ b/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBApplicationStore.cs
@@ -133,7 +133,7 @@ public virtual async ValueTask DeleteAsync(TApplication application, Cancellatio
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection(Options.CurrentValue.ApplicationsCollectionName);
- return collection.FindById(identifier);
+ return collection.FindById(new ObjectId(identifier));
}
///
@@ -273,12 +273,10 @@ public virtual ValueTask> GetDisplayNam
if (application.DisplayNames is not { Count: > 0 })
{
- return new(ImmutableDictionary.Create());
+ return new(ImmutableDictionary.Empty);
}
- return new(application.DisplayNames.ToImmutableDictionary(
- pair => CultureInfo.GetCultureInfo(pair.Key),
- pair => pair.Value));
+ return new(application.DisplayNames);
}
///
@@ -301,12 +299,12 @@ public virtual ValueTask> GetPermissionsAsync(
throw new ArgumentNullException(nameof(application));
}
- if (application.Permissions is not { Count: > 0 })
+ if (application.Permissions is not { Length: > 0 })
{
- return new(ImmutableArray.Create());
+ return new(ImmutableArray.Empty);
}
- return new(application.Permissions.ToImmutableArray());
+ return new(application.Permissions.Value);
}
///
@@ -318,12 +316,12 @@ public virtual ValueTask> GetPostLogoutRedirectUrisAsync(
throw new ArgumentNullException(nameof(application));
}
- if (application.PostLogoutRedirectUris is not { Count: > 0 })
+ if (application.PostLogoutRedirectUris is not { Length: > 0 })
{
- return new(ImmutableArray.Create());
+ return new(ImmutableArray.Empty);
}
- return new(application.PostLogoutRedirectUris.ToImmutableArray());
+ return new(application.PostLogoutRedirectUris.Value);
}
///
@@ -336,10 +334,10 @@ public virtual ValueTask> GetProperties
if (application.Properties is null || application.Properties.Count == 0)
{
- return new(ImmutableDictionary.Create());
+ return new(ImmutableDictionary.Empty);
}
- return new(application.Properties.ToImmutableDictionary());
+ return new(application.Properties);
}
///
@@ -351,12 +349,12 @@ public virtual ValueTask> GetRedirectUrisAsync(
throw new ArgumentNullException(nameof(application));
}
- if (application.RedirectUris is not { Count: > 0 })
+ if (application.RedirectUris is not { Length: > 0 })
{
- return new(ImmutableArray.Create());
+ return new(ImmutableArray.Empty);
}
- return new(application.RedirectUris.ToImmutableArray());
+ return new(application.RedirectUris.Value);
}
///
@@ -367,12 +365,12 @@ public virtual ValueTask> GetRequirementsAsync(TApplicati
throw new ArgumentNullException(nameof(application));
}
- if (application.Requirements is not { Count: > 0 })
+ if (application.Requirements is not { Length: > 0 })
{
- return new(ImmutableArray.Create());
+ return new(ImmutableArray.Empty);
}
- return new(application.Requirements.ToImmutableArray());
+ return new(application.Requirements.Value);
}
///
@@ -515,14 +513,10 @@ public virtual ValueTask SetDisplayNamesAsync(TApplication application,
if (names is not { Count: > 0 })
{
application.DisplayNames = null;
-
return default;
}
- application.DisplayNames = names.ToImmutableDictionary(
- pair => pair.Key.Name,
- pair => pair.Value);
-
+ application.DisplayNames = names;
return default;
}
@@ -537,12 +531,10 @@ public virtual ValueTask SetPermissionsAsync(TApplication application, Immutable
if (permissions.IsDefaultOrEmpty)
{
application.Permissions = null;
-
return default;
}
- application.Permissions = permissions.ToImmutableList();
-
+ application.Permissions = permissions;
return default;
}
@@ -558,12 +550,10 @@ public virtual ValueTask SetPostLogoutRedirectUrisAsync(TApplication application
if (addresses.IsDefaultOrEmpty)
{
application.PostLogoutRedirectUris = null;
-
return default;
}
- application.PostLogoutRedirectUris = addresses.ToImmutableList();
-
+ application.PostLogoutRedirectUris = addresses;
return default;
}
@@ -579,12 +569,10 @@ public virtual ValueTask SetPropertiesAsync(TApplication application,
if (properties is not { Count: > 0 })
{
application.Properties = null;
-
return default;
}
application.Properties = properties;
-
return default;
}
@@ -600,12 +588,10 @@ public virtual ValueTask SetRedirectUrisAsync(TApplication application,
if (addresses.IsDefaultOrEmpty)
{
application.RedirectUris = null;
-
return default;
}
- application.RedirectUris = addresses.ToImmutableList();
-
+ application.RedirectUris = addresses;
return default;
}
@@ -621,12 +607,10 @@ public virtual ValueTask SetRequirementsAsync(TApplication application,
if (requirements.IsDefaultOrEmpty)
{
application.Requirements = null;
-
return default;
}
- application.Requirements = requirements.ToImmutableList();
-
+ application.Requirements = requirements;
return default;
}
diff --git a/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBAuthorizationStore.cs b/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBAuthorizationStore.cs
index 3a29104..7270a3f 100644
--- a/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBAuthorizationStore.cs
+++ b/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBAuthorizationStore.cs
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+using static OpenIddict.Abstractions.OpenIddictConstants;
+
namespace Sknet.OpenIddict.LiteDB;
///
@@ -140,8 +142,8 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Can
///
public virtual IAsyncEnumerable FindAsync(
- string subject, string client,
- string status, CancellationToken cancellationToken)
+ string subject, string client, string status,
+ CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@@ -181,8 +183,8 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Can
///
public virtual IAsyncEnumerable FindAsync(
- string subject, string client,
- string status, string type, CancellationToken cancellationToken)
+ string subject, string client, string status, string type,
+ CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
@@ -228,8 +230,7 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Can
///
public virtual IAsyncEnumerable FindAsync(
- string subject, string client,
- string status, string type,
+ string subject, string client, string status, string type,
ImmutableArray scopes, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
@@ -246,7 +247,7 @@ public virtual IAsyncEnumerable FindAsync(
{
throw new ArgumentException("The status cannot be null or empty.", nameof(status));
}
-
+
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException("The type cannot be null or empty.", nameof(type));
@@ -258,15 +259,16 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Can
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection(Options.CurrentValue.AuthorizationsCollectionName);
-
+
var authorizations = collection.Query()
.Where(entity =>
entity.Subject == subject &&
entity.ApplicationId == new ObjectId(client) &&
entity.Status == status &&
- entity.Type == type &&
- Enumerable.All(scopes, scope => entity.Scopes != null && entity.Scopes.Contains(scope)))
- .ToEnumerable().ToAsyncEnumerable();
+ entity.Type == type)
+ .ToEnumerable()
+ .Where(entity => scopes.All(scope => entity.Scopes!.Contains(scope)))
+ .ToAsyncEnumerable();
await foreach (var authorization in authorizations)
{
@@ -313,7 +315,7 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Can
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection(Options.CurrentValue.AuthorizationsCollectionName);
- return collection.FindById(identifier);
+ return collection.FindById(new ObjectId(identifier));
}
///
@@ -390,7 +392,7 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Can
return new(result: null);
}
- return new(DateTime.SpecifyKind(authorization.CreationDate.Value, DateTimeKind.Utc));
+ return new(authorization.CreationDate);
}
///
@@ -414,10 +416,10 @@ public virtual ValueTask> GetProperties
if (authorization.Properties is null || authorization.Properties.Count == 0)
{
- return new(ImmutableDictionary.Create());
+ return new(ImmutableDictionary.Empty);
}
- return new(authorization.Properties.ToImmutableDictionary());
+ return new(authorization.Properties);
}
///
@@ -428,12 +430,12 @@ public virtual ValueTask> GetScopesAsync(TAuthorization a
throw new ArgumentNullException(nameof(authorization));
}
- if (authorization.Scopes is not { Count: > 0 })
+ if (authorization.Scopes is not { Length: > 0 })
{
- return new(ImmutableArray.Create());
+ return new(ImmutableArray.Empty);
}
- return new(authorization.Scopes.ToImmutableArray());
+ return new(authorization.Scopes.Value);
}
///
@@ -526,57 +528,46 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Cancellati
}
}
}
-
+
///
- public virtual ValueTask PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
+ public async virtual ValueTask PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
{
- throw new NotImplementedException();
-
- //var database = await Context.GetDatabaseAsync(cancellationToken);
- //var collection = database.GetCollection(Options.CurrentValue.AuthorizationsCollectionName);
-
- // Note: directly deleting the resulting set of an aggregate query is not supported by MongoDb
- // To work around this limitation, the authorization identifiers are stored in an intermediate
- // list and delete requests are sent to remove the documents corresponding to these identifiers.
-
- //var identifiers =
- // await (from authorization in collection.AsQueryable()
- // join token in database.GetCollection(Options.CurrentValue.TokensCollectionName).AsQueryable()
- // on authorization.Id equals token.AuthorizationId into tokens
- // where authorization.CreationDate < threshold.UtcDateTime
- // where authorization.Status != Statuses.Valid ||
- // (authorization.Type == AuthorizationTypes.AdHoc && !tokens.Any())
- // select authorization.Id).ToListAsync(cancellationToken);
-
- // Note: to avoid generating delete requests with very large filters, a buffer is used here and the
- // maximum number of elements that can be removed by a single call to PruneAsync() is deliberately limited.
- //foreach (var buffer in Buffer(identifiers.Take(1_000_000), 1_000))
- //{
- // await collection.DeleteManyAsync(authorization => buffer.Contains(authorization.Id), cancellationToken);
- //}
+ var database = await Context.GetDatabaseAsync(cancellationToken);
+ var authorizationCollection = database.GetCollection(Options.CurrentValue.AuthorizationsCollectionName);
- //static IEnumerable> Buffer(IEnumerable source, int count)
- //{
- // List? buffer = null;
+ var query = from auth in authorizationCollection.Query()
+ // only prune authorizations created before threshold
+ where auth.CreationDate < threshold.UtcDateTime
+ // prune tokens that are not valid
+ where auth.Status != Statuses.Valid
+ select auth.Id;
+ var authorizations = query.ToList();
- // foreach (var element in source)
- // {
- // buffer ??= new List(capacity: 1);
- // buffer.Add(element);
+ // prune adhoc authorizations that have no tokens
+ query = from auth in authorizationCollection.Query()
+ where auth.CreationDate < threshold.UtcDateTime
+ where auth.Status == Statuses.Valid
+ where auth.Type == AuthorizationTypes.AdHoc
+ select auth.Id;
+ var adhocAuthorizations = new HashSet(query.ToEnumerable());
- // if (buffer.Count == count)
- // {
- // yield return buffer;
+ var tokenCollection = database.GetCollection(Options.CurrentValue.TokensCollectionName);
+ var adhocAuthorizationsWithTokens = new HashSet(tokenCollection.Query()
+ .GroupBy("authorization_id")
+ .Where(x => adhocAuthorizations.Contains(x["authorization_id"]))
+ .Select("{authorization_id:@key}")
+ .ToEnumerable()
+ .Select(x => x["authorization_id"].AsObjectId));
- // buffer = null;
- // }
- // }
+ adhocAuthorizations.SymmetricExceptWith(adhocAuthorizationsWithTokens);
+ authorizations.AddRange(adhocAuthorizations);
- // if (buffer is not null)
- // {
- // yield return buffer;
- // }
- //}
+ database.BeginTrans();
+ foreach (var authorization in authorizations)
+ {
+ authorizationCollection.Delete(authorization);
+ }
+ database.Commit();
}
///
@@ -592,7 +583,6 @@ public virtual ValueTask SetApplicationIdAsync(TAuthorization authorization,
{
authorization.ApplicationId = new ObjectId(identifier);
}
-
else
{
authorization.ApplicationId = ObjectId.Empty;
@@ -611,7 +601,6 @@ public virtual ValueTask SetCreationDateAsync(TAuthorization authorization,
}
authorization.CreationDate = date?.UtcDateTime;
-
return default;
}
@@ -627,12 +616,10 @@ public virtual ValueTask SetPropertiesAsync(TAuthorization authorization,
if (properties is not { Count: > 0 })
{
authorization.Properties = null;
-
return default;
}
authorization.Properties = properties;
-
return default;
}
@@ -648,12 +635,10 @@ public virtual ValueTask SetScopesAsync(TAuthorization authorization,
if (scopes.IsDefaultOrEmpty)
{
authorization.Scopes = null;
-
return default;
}
- authorization.Scopes = scopes.ToImmutableList();
-
+ authorization.Scopes = scopes;
return default;
}
@@ -666,7 +651,6 @@ public virtual ValueTask SetStatusAsync(TAuthorization authorization, string? st
}
authorization.Status = status;
-
return default;
}
@@ -679,7 +663,6 @@ public virtual ValueTask SetSubjectAsync(TAuthorization authorization, string? s
}
authorization.Subject = subject;
-
return default;
}
@@ -692,7 +675,6 @@ public virtual ValueTask SetTypeAsync(TAuthorization authorization, string? type
}
authorization.Type = type;
-
return default;
}
diff --git a/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBScopeStore.cs b/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBScopeStore.cs
index b154f67..29a9b3a 100644
--- a/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBScopeStore.cs
+++ b/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBScopeStore.cs
@@ -111,7 +111,7 @@ public virtual async ValueTask DeleteAsync(TScope scope, CancellationToken cance
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection(Options.CurrentValue.ScopesCollectionName);
- return collection.FindById(identifier);
+ return collection.FindById(new ObjectId(identifier));
}
///
@@ -221,12 +221,10 @@ public virtual ValueTask> GetDescriptio
if (scope.Descriptions is not { Count: > 0 })
{
- return new(ImmutableDictionary.Create());
+ return new(ImmutableDictionary.Empty);
}
- return new(scope.Descriptions.ToImmutableDictionary(
- pair => CultureInfo.GetCultureInfo(pair.Key),
- pair => pair.Value));
+ return new(scope.Descriptions);
}
///
@@ -250,12 +248,10 @@ public virtual ValueTask> GetDisplayNam
if (scope.DisplayNames is not { Count: > 0 })
{
- return new(ImmutableDictionary.Create());
+ return new(ImmutableDictionary.Empty);
}
- return new(scope.DisplayNames.ToImmutableDictionary(
- pair => CultureInfo.GetCultureInfo(pair.Key),
- pair => pair.Value));
+ return new(scope.DisplayNames);
}
///
@@ -290,10 +286,10 @@ public virtual ValueTask> GetProperties
if (scope.Properties is null || scope.Properties.Count == 0)
{
- return new(ImmutableDictionary.Create());
+ return new(ImmutableDictionary.Empty);
}
- return new(scope.Properties.ToImmutableDictionary());
+ return new(scope.Properties);
}
///
@@ -304,12 +300,12 @@ public virtual ValueTask> GetResourcesAsync(TScope scope,
throw new ArgumentNullException(nameof(scope));
}
- if (scope.Resources is not { Count: > 0 })
+ if (scope.Resources is not { Length: > 0 })
{
- return new(ImmutableArray.Create());
+ return new(ImmutableArray.Empty);
}
- return new(scope.Resources.ToImmutableArray());
+ return new(scope.Resources.Value);
}
///
@@ -319,7 +315,6 @@ public virtual ValueTask InstantiateAsync(CancellationToken cancellation
{
return new(Activator.CreateInstance());
}
-
catch (MemberAccessException exception)
{
return new(Task.FromException(
@@ -379,7 +374,6 @@ public virtual ValueTask SetDescriptionAsync(TScope scope, string? description,
}
scope.Description = description;
-
return default;
}
@@ -395,14 +389,10 @@ public virtual ValueTask SetDescriptionsAsync(TScope scope,
if (descriptions is not { Count: > 0 })
{
scope.Descriptions = null;
-
return default;
}
- scope.Descriptions = descriptions.ToImmutableDictionary(
- pair => pair.Key.Name,
- pair => pair.Value);
-
+ scope.Descriptions = descriptions;
return default;
}
@@ -418,14 +408,10 @@ public virtual ValueTask SetDisplayNamesAsync(TScope scope,
if (names is not { Count: > 0 })
{
scope.DisplayNames = null;
-
return default;
}
- scope.DisplayNames = names.ToImmutableDictionary(
- pair => pair.Key.Name,
- pair => pair.Value);
-
+ scope.DisplayNames = names;
return default;
}
@@ -438,7 +424,6 @@ public virtual ValueTask SetDisplayNameAsync(TScope scope, string? name, Cancell
}
scope.DisplayName = name;
-
return default;
}
@@ -451,7 +436,6 @@ public virtual ValueTask SetNameAsync(TScope scope, string? name, CancellationTo
}
scope.Name = name;
-
return default;
}
@@ -467,12 +451,10 @@ public virtual ValueTask SetPropertiesAsync(TScope scope,
if (properties is not { Count: > 0 })
{
scope.Properties = null;
-
return default;
}
scope.Properties = properties;
-
return default;
}
@@ -487,12 +469,10 @@ public virtual ValueTask SetResourcesAsync(TScope scope, ImmutableArray
if (resources.IsDefaultOrEmpty)
{
scope.Resources = null;
-
return default;
}
- scope.Resources = resources.ToImmutableList();
-
+ scope.Resources = resources;
return default;
}
diff --git a/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBTokenStore.cs b/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBTokenStore.cs
index b9a1d40..78dd796 100644
--- a/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBTokenStore.cs
+++ b/src/Sknet.OpenIddict.LiteDB/Stores/OpenIddictLiteDBTokenStore.cs
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+using static OpenIddict.Abstractions.OpenIddictConstants;
+
namespace Sknet.OpenIddict.LiteDB;
///
@@ -285,7 +287,7 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Cancellatio
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection(Options.CurrentValue.TokensCollectionName);
- return collection.FindById(identifier);
+ return collection.FindById(new ObjectId(identifier));
}
///
@@ -393,7 +395,7 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Cancellatio
return new(result: null);
}
- return new(DateTime.SpecifyKind(token.CreationDate.Value, DateTimeKind.Utc));
+ return new(token.CreationDate);
}
///
@@ -409,7 +411,7 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Cancellatio
return new(result: null);
}
- return new(DateTime.SpecifyKind(token.ExpirationDate.Value, DateTimeKind.Utc));
+ return new(token.ExpirationDate);
}
///
@@ -444,10 +446,10 @@ public virtual ValueTask> GetProperties
if (token.Properties is null || token.Properties.Count == 0)
{
- return new(ImmutableDictionary.Create());
+ return new(ImmutableDictionary.Empty);
}
- return new(token.Properties.ToImmutableDictionary());
+ return new(token.Properties);
}
///
@@ -463,7 +465,7 @@ public virtual ValueTask> GetProperties
return new(result: null);
}
- return new(DateTime.SpecifyKind(token.RedemptionDate.Value, DateTimeKind.Utc));
+ return new(token.RedemptionDate);
}
///
@@ -569,56 +571,38 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Cancellati
}
///
- public virtual ValueTask PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
+ public async virtual ValueTask PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
{
- throw new NotImplementedException();
-
- //var database = await Context.GetDatabaseAsync(cancellationToken);
- //var collection = database.GetCollection(Options.CurrentValue.TokensCollectionName);
-
- //// Note: directly deleting the resulting set of an aggregate query is not supported by MongoDb.
- //// To work around this limitation, the token identifiers are stored in an intermediate list
- //// and delete requests are sent to remove the documents corresponding to these identifiers.
-
- //var identifiers =
- // await (from token in collection.AsQueryable()
- // join authorization in database.GetCollection(Options.CurrentValue.AuthorizationsCollectionName).AsQueryable()
- // on token.AuthorizationId equals authorization.Id into authorizations
- // where token.CreationDate < threshold.UtcDateTime
- // where (token.Status != Statuses.Inactive && token.Status != Statuses.Valid) ||
- // token.ExpirationDate < DateTime.UtcNow ||
- // authorizations.Any(authorization => authorization.Status != Statuses.Valid)
- // select token.Id).ToListAsync(cancellationToken);
-
- //// Note: to avoid generating delete requests with very large filters, a buffer is used here and the
- //// maximum number of elements that can be removed by a single call to PruneAsync() is deliberately limited.
- //foreach (var buffer in Buffer(identifiers.Take(1_000_000), 1_000))
- //{
- // await collection.DeleteManyAsync(token => buffer.Contains(token.Id), cancellationToken);
- //}
-
- //static IEnumerable> Buffer(IEnumerable source, int count)
- //{
- // List? buffer = null;
-
- // foreach (var element in source)
- // {
- // buffer ??= new List(capacity: 1);
- // buffer.Add(element);
-
- // if (buffer.Count == count)
- // {
- // yield return buffer;
-
- // buffer = null;
- // }
- // }
+ var database = await Context.GetDatabaseAsync(cancellationToken);
- // if (buffer is not null)
- // {
- // yield return buffer;
- // }
- //}
+ // Get invalid authorizations from which tokens can be pruned
+ var invalidAuthorizations = database
+ .GetCollection(Options.CurrentValue.AuthorizationsCollectionName)
+ .Query()
+ .Where("$.Status != @0", Statuses.Valid)
+ .Select(x => x["_id"].AsObjectId)
+ .ToList();
+
+ var tokenCollection = database.GetCollection(Options.CurrentValue.TokensCollectionName);
+ var query = from token in tokenCollection.Query()
+ // only prune tokens created before threshold
+ where token.CreationDate < threshold.UtcDateTime
+ // prune tokens that either
+ // 1. not inactive and not valid,
+ // 2. past expiration date, OR
+ // 3. belong to an invalid authorization
+ where (token.Status != Statuses.Inactive && token.Status != Statuses.Valid)
+ || token.ExpirationDate < DateTimeOffset.UtcNow
+ || invalidAuthorizations.Contains(token.AuthorizationId)
+ select token.Id;
+ var tokens = query.ToList();
+
+ database.BeginTrans();
+ foreach (var token in tokens)
+ {
+ tokenCollection.Delete(token);
+ }
+ database.Commit();
}
///
@@ -633,7 +617,6 @@ public virtual ValueTask SetApplicationIdAsync(TToken token, string? identifier,
{
token.ApplicationId = new ObjectId(identifier);
}
-
else
{
token.ApplicationId = ObjectId.Empty;
@@ -654,7 +637,6 @@ public virtual ValueTask SetAuthorizationIdAsync(TToken token, string? identifie
{
token.AuthorizationId = new ObjectId(identifier);
}
-
else
{
token.AuthorizationId = ObjectId.Empty;
@@ -672,7 +654,6 @@ public virtual ValueTask SetCreationDateAsync(TToken token, DateTimeOffset? date
}
token.CreationDate = date?.UtcDateTime;
-
return default;
}
@@ -685,7 +666,6 @@ public virtual ValueTask SetExpirationDateAsync(TToken token, DateTimeOffset? da
}
token.ExpirationDate = date?.UtcDateTime;
-
return default;
}
@@ -698,7 +678,6 @@ public virtual ValueTask SetPayloadAsync(TToken token, string? payload, Cancella
}
token.Payload = payload;
-
return default;
}
@@ -714,12 +693,10 @@ public virtual ValueTask SetPropertiesAsync(TToken token,
if (properties is not { Count: > 0 })
{
token.Properties = null;
-
return default;
}
token.Properties = properties;
-
return default;
}
@@ -732,7 +709,6 @@ public virtual ValueTask SetRedemptionDateAsync(TToken token, DateTimeOffset? da
}
token.RedemptionDate = date?.UtcDateTime;
-
return default;
}
@@ -745,7 +721,6 @@ public virtual ValueTask SetReferenceIdAsync(TToken token, string? identifier, C
}
token.ReferenceId = identifier;
-
return default;
}
@@ -758,7 +733,6 @@ public virtual ValueTask SetStatusAsync(TToken token, string? status, Cancellati
}
token.Status = status;
-
return default;
}
@@ -771,7 +745,6 @@ public virtual ValueTask SetSubjectAsync(TToken token, string? subject, Cancella
}
token.Subject = subject;
-
return default;
}
@@ -784,7 +757,6 @@ public virtual ValueTask SetTypeAsync(TToken token, string? type, CancellationTo
}
token.Type = type;
-
return default;
}
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBApplicationFaker.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBApplicationFaker.cs
new file mode 100644
index 0000000..4495957
--- /dev/null
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBApplicationFaker.cs
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2022 Steven Kuhn and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Sknet.OpenIddict.LiteDB.Tests.Builders;
+
+public class OpenIddictLiteDBApplicationFaker : Faker
+{
+ public OpenIddictLiteDBApplicationFaker()
+ {
+ UseSeed(1);
+
+ RuleFor(x => x.Id, f => new ObjectId(f.Random.Hexadecimal(24, prefix: "")))
+ .RuleFor(x => x.ClientId, f => f.Random.AlphaNumeric(32))
+ .RuleFor(x => x.ClientSecret, f => f.Random.AlphaNumeric(32))
+ .RuleFor(x => x.ConcurrencyToken, f => f.Random.Guid().ToString())
+ .RuleFor(x => x.ConsentType, f => f.PickRandom(new[] { ConsentTypes.Explicit, ConsentTypes.External, ConsentTypes.Implicit, ConsentTypes.Systematic }))
+ .RuleFor(x => x.DisplayName, f => f.Commerce.ProductName())
+ .RuleFor(x => x.DisplayNames, f => f.Random.ListItems<(CultureInfo Culture, string DisplayName)>(new()
+ {
+ (CultureInfo.GetCultureInfo("en"), f.Commerce.ProductName()),
+ (CultureInfo.GetCultureInfo("fr"), f.Commerce.ProductName()),
+ (CultureInfo.GetCultureInfo("de"), f.Commerce.ProductName()),
+ (CultureInfo.GetCultureInfo("es"), f.Commerce.ProductName())
+ })
+ .OrderBy(x => x.Culture.Name)
+ .ToImmutableDictionary(x => x.Culture, x => x.DisplayName))
+ .RuleFor(x => x.Permissions, f => f.Random.ListItems(new() { "permission1", "permission2", "permission3" })
+ .ToImmutableArray())
+ .RuleFor(x => x.PostLogoutRedirectUris, f => f.Random.ListItems(new()
+ {
+ f.Internet.UrlWithPath(),
+ f.Internet.UrlWithPath(),
+ f.Internet.UrlWithPath()
+ })
+ .ToImmutableArray())
+ .RuleFor(x => x.Properties, f => f.Random.ListItems<(string PropertyName, JsonElement JsonValue)>(new()
+ {
+ ("property1", JsonDocument.Parse("true").RootElement),
+ ("property2", JsonDocument.Parse("false").RootElement),
+ ("property3", JsonDocument.Parse("null").RootElement),
+ ("property4", JsonDocument.Parse("1").RootElement),
+ ("property5", JsonDocument.Parse("1.1").RootElement),
+ ("property6", JsonDocument.Parse(@"""""").RootElement),
+ ("property7", JsonDocument.Parse(@"""value""").RootElement),
+ ("property8", JsonDocument.Parse(@"[""value1"", ""value2""]").RootElement),
+ ("property9", JsonDocument.Parse(@"{""key"": ""value""}").RootElement)
+ })
+ .OrderBy(x => x.PropertyName)
+ .ToImmutableDictionary(x => x.PropertyName, x => x.JsonValue))
+ .RuleFor(x => x.RedirectUris, f => f.Random.ListItems(new()
+ {
+ f.Internet.UrlWithPath(),
+ f.Internet.UrlWithPath(),
+ f.Internet.UrlWithPath()
+ })
+ .ToImmutableArray())
+ .RuleFor(x => x.Requirements, f => ImmutableArray.Create())
+ .RuleFor(x => x.Type, f => f.PickRandom(new[] { ClientTypes.Confidential, ClientTypes.Public }));
+ }
+}
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBApplicationStoreBuilder.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBApplicationStoreBuilder.cs
new file mode 100644
index 0000000..7a1c76e
--- /dev/null
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBApplicationStoreBuilder.cs
@@ -0,0 +1,126 @@
+/*
+* Copyright (c) 2022 Steven Kuhn and contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+namespace Sknet.OpenIddict.LiteDB.Tests.Builders;
+
+public class OpenIddictLiteDBApplicationStoreBuilder
+{
+ private readonly List _applications = new();
+ private readonly List _authorizations = new();
+ private readonly List _scopes = new();
+ private readonly List _tokens = new();
+ private ILiteDatabase? _database;
+
+ public OpenIddictLiteDBApplicationStoreBuilder WithApplications(params OpenIddictLiteDBApplication[] applications)
+ {
+ _applications.AddRange(applications);
+ return this;
+ }
+
+ public OpenIddictLiteDBApplicationStoreBuilder WithApplications(IEnumerable applications)
+ {
+ _applications.AddRange(applications);
+ return this;
+ }
+
+ public OpenIddictLiteDBApplicationStoreBuilder WithAuthorizations(params OpenIddictLiteDBAuthorization[] authorizations)
+ {
+ _authorizations.AddRange(authorizations);
+ return this;
+ }
+
+ public OpenIddictLiteDBApplicationStoreBuilder WithAuthorizations(IEnumerable authorizations)
+ {
+ _authorizations.AddRange(authorizations);
+ return this;
+ }
+
+ public OpenIddictLiteDBApplicationStoreBuilder WithDatabase(ILiteDatabase database)
+ {
+ _database = database;
+ return this;
+ }
+
+ public OpenIddictLiteDBApplicationStoreBuilder WithScopes(params OpenIddictLiteDBScope[] scopes)
+ {
+ _scopes.AddRange(scopes);
+ return this;
+ }
+
+ public OpenIddictLiteDBApplicationStoreBuilder WithScopes(IEnumerable scopes)
+ {
+ _scopes.AddRange(scopes);
+ return this;
+ }
+
+ public OpenIddictLiteDBApplicationStoreBuilder WithTokens(params OpenIddictLiteDBToken[] tokens)
+ {
+ _tokens.AddRange(tokens);
+ return this;
+ }
+
+ public OpenIddictLiteDBApplicationStoreBuilder WithTokens(IEnumerable tokens)
+ {
+ _tokens.AddRange(tokens);
+ return this;
+ }
+
+
+ public OpenIddictLiteDBApplicationStore Build()
+ {
+ var database = _database ?? new OpenIddictLiteDatabase(":memory:");
+ var options = new OpenIddictLiteDBOptions();
+
+ if (_applications.Count > 0)
+ {
+ database
+ .GetCollection(options.ApplicationsCollectionName)
+ .InsertBulk(_applications);
+ }
+
+ if (_authorizations.Count > 0)
+ {
+ database
+ .GetCollection(options.AuthorizationsCollectionName)
+ .InsertBulk(_authorizations);
+ }
+
+ if (_scopes.Count > 0)
+ {
+ database
+ .GetCollection(options.ScopesCollectionName)
+ .InsertBulk(_scopes);
+ }
+
+ if (_tokens.Count > 0)
+ {
+ database
+ .GetCollection(options.TokensCollectionName)
+ .InsertBulk(_tokens);
+ }
+
+ var contextMock = new Mock();
+ contextMock
+ .Setup(x => x.GetDatabaseAsync(It.IsAny()))
+ .ReturnsAsync(database);
+
+ var optionsMock = new Mock>();
+ optionsMock
+ .SetupGet(x => x.CurrentValue)
+ .Returns(options);
+
+ return new OpenIddictLiteDBApplicationStore(contextMock.Object, optionsMock.Object);
+ }
+}
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBAuthorizationFaker.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBAuthorizationFaker.cs
new file mode 100644
index 0000000..1ff23fd
--- /dev/null
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBAuthorizationFaker.cs
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022 Steven Kuhn and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Sknet.OpenIddict.LiteDB.Tests.Builders;
+
+public class OpenIddictLiteDBAuthorizationFaker : Faker
+{
+ public OpenIddictLiteDBAuthorizationFaker()
+ {
+ UseSeed(1);
+
+ RuleFor(x => x.Id, f => new ObjectId(f.Random.Hexadecimal(24, prefix: "")))
+ .RuleFor(x => x.ApplicationId, f => new ObjectId(f.Random.Hexadecimal(24, prefix: "")))
+ .RuleFor(x => x.ConcurrencyToken, f => f.Random.Guid().ToString())
+ .RuleFor(x => x.CreationDate, f => f.Date.PastOffset())
+ .RuleFor(x => x.Properties, f => f.Random.ListItems<(string PropertyName, JsonElement JsonValue)>(new()
+ {
+ ("property1", JsonDocument.Parse("true").RootElement),
+ ("property2", JsonDocument.Parse("false").RootElement),
+ ("property3", JsonDocument.Parse("null").RootElement),
+ ("property4", JsonDocument.Parse("1").RootElement),
+ ("property5", JsonDocument.Parse("1.1").RootElement),
+ ("property6", JsonDocument.Parse(@"""""").RootElement),
+ ("property7", JsonDocument.Parse(@"""value""").RootElement),
+ ("property8", JsonDocument.Parse(@"[""value1"", ""value2""]").RootElement),
+ ("property9", JsonDocument.Parse(@"{""key"": ""value""}").RootElement)
+ })
+ .OrderBy(x => x.PropertyName)
+ .ToImmutableDictionary(x => x.PropertyName, x => x.JsonValue))
+ .RuleFor(x => x.Scopes, f => f.Random.ListItems(new() { "scope1", "scope2", "scope3" })
+ .ToImmutableArray())
+ .RuleFor(x => x.Status, f => f.PickRandom(new[]
+ {
+ Statuses.Inactive,
+ Statuses.Redeemed,
+ Statuses.Rejected,
+ Statuses.Revoked,
+ Statuses.Valid
+ }))
+ .RuleFor(x => x.Subject, f => f.Person.UserName)
+ .RuleFor(x => x.Type, f => f.PickRandom(new[] { AuthorizationTypes.AdHoc, AuthorizationTypes.Permanent }));
+ }
+}
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBAuthorizationStoreBuilder.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBAuthorizationStoreBuilder.cs
new file mode 100644
index 0000000..c0604a0
--- /dev/null
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBAuthorizationStoreBuilder.cs
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2022 Steven Kuhn and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Sknet.OpenIddict.LiteDB.Tests.Builders;
+
+public class OpenIddictLiteDBAuthorizationStoreBuilder
+{
+ private readonly List _authorizations = new();
+ private readonly List _tokens = new();
+ private ILiteDatabase? _database;
+
+ public OpenIddictLiteDBAuthorizationStoreBuilder WithAuthorizations(params OpenIddictLiteDBAuthorization[] authorizations)
+ {
+ _authorizations.AddRange(authorizations);
+ return this;
+ }
+
+ public OpenIddictLiteDBAuthorizationStoreBuilder WithAuthorizations(IEnumerable authorizations)
+ {
+ _authorizations.AddRange(authorizations);
+ return this;
+ }
+
+ public OpenIddictLiteDBAuthorizationStoreBuilder WithDatabase(ILiteDatabase database)
+ {
+ _database = database;
+ return this;
+ }
+
+ public OpenIddictLiteDBAuthorizationStoreBuilder WithTokens(params OpenIddictLiteDBToken[] tokens)
+ {
+ _tokens.AddRange(tokens);
+ return this;
+ }
+
+ public OpenIddictLiteDBAuthorizationStoreBuilder WithTokens(IEnumerable tokens)
+ {
+ _tokens.AddRange(tokens);
+ return this;
+ }
+
+ public OpenIddictLiteDBAuthorizationStore Build()
+ {
+ var database = _database ?? new OpenIddictLiteDatabase(":memory:");
+ var options = new OpenIddictLiteDBOptions();
+
+ if (_authorizations.Count > 0)
+ {
+ database
+ .GetCollection(options.AuthorizationsCollectionName)
+ .InsertBulk(_authorizations);
+ }
+
+ if (_tokens.Count > 0)
+ {
+ database
+ .GetCollection(options.TokensCollectionName)
+ .InsertBulk(_tokens);
+ }
+
+ var contextMock = new Mock();
+ contextMock
+ .Setup(x => x.GetDatabaseAsync(It.IsAny()))
+ .ReturnsAsync(database);
+
+ var optionsMock = new Mock>();
+ optionsMock
+ .SetupGet(x => x.CurrentValue)
+ .Returns(options);
+
+ return new OpenIddictLiteDBAuthorizationStore(contextMock.Object, optionsMock.Object);
+ }
+}
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBScopeFaker.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBScopeFaker.cs
new file mode 100644
index 0000000..9c1abdb
--- /dev/null
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBScopeFaker.cs
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022 Steven Kuhn and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Sknet.OpenIddict.LiteDB.Tests.Builders;
+
+public class OpenIddictLiteDBScopeFaker : Faker
+{
+ public OpenIddictLiteDBScopeFaker()
+ {
+ UseSeed(1);
+
+ RuleFor(x => x.Id, f => new ObjectId(f.Random.Hexadecimal(24, prefix: "")))
+ .RuleFor(x => x.ConcurrencyToken, f => f.Random.Guid().ToString())
+ .RuleFor(x => x.Description, f => f.Lorem.Sentence())
+ .RuleFor(x => x.Descriptions, f => f.Random.ListItems<(CultureInfo Culture, string Description)>(new()
+ {
+ (CultureInfo.GetCultureInfo("en"), f.Lorem.Sentence()),
+ (CultureInfo.GetCultureInfo("fr"), f.Lorem.Sentence()),
+ (CultureInfo.GetCultureInfo("de"), f.Lorem.Sentence()),
+ (CultureInfo.GetCultureInfo("es"), f.Lorem.Sentence())
+ })
+ .OrderBy(x => x.Culture.Name)
+ .ToImmutableDictionary(x => x.Culture, x => x.Description))
+ .RuleFor(x => x.DisplayName, f => f.Commerce.ProductName())
+ .RuleFor(x => x.DisplayNames, f => f.Random.ListItems<(CultureInfo Culture, string DisplayName)>(new()
+ {
+ (CultureInfo.GetCultureInfo("en"), f.Commerce.ProductName()),
+ (CultureInfo.GetCultureInfo("fr"), f.Commerce.ProductName()),
+ (CultureInfo.GetCultureInfo("de"), f.Commerce.ProductName()),
+ (CultureInfo.GetCultureInfo("es"), f.Commerce.ProductName())
+ })
+ .OrderBy(x => x.Culture.Name)
+ .ToImmutableDictionary(x => x.Culture, x => x.DisplayName))
+ .RuleFor(x => x.Name, f => f.Commerce.ProductName())
+ .RuleFor(x => x.Properties, f => f.Random.ListItems<(string PropertyName, JsonElement JsonValue)>(new()
+ {
+ ("property1", JsonDocument.Parse("true").RootElement),
+ ("property2", JsonDocument.Parse("false").RootElement),
+ ("property3", JsonDocument.Parse("null").RootElement),
+ ("property4", JsonDocument.Parse("1").RootElement),
+ ("property5", JsonDocument.Parse("1.1").RootElement),
+ ("property6", JsonDocument.Parse(@"""""").RootElement),
+ ("property7", JsonDocument.Parse(@"""value""").RootElement),
+ ("property8", JsonDocument.Parse(@"[""value1"", ""value2""]").RootElement),
+ ("property9", JsonDocument.Parse(@"{""key"": ""value""}").RootElement)
+ })
+ .OrderBy(x => x.PropertyName)
+ .ToImmutableDictionary(x => x.PropertyName, x => x.JsonValue))
+ .RuleFor(x => x.Resources, f => f.Random.ListItems(new()
+ {
+ "resource1",
+ "resource2",
+ "resource3",
+ "resource4",
+ "resource5"
+ })
+ .ToImmutableArray());
+ }
+}
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBScopeStoreBuilder.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBScopeStoreBuilder.cs
new file mode 100644
index 0000000..671851e
--- /dev/null
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBScopeStoreBuilder.cs
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2022 Steven Kuhn and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Sknet.OpenIddict.LiteDB.Tests.Builders;
+
+public class OpenIddictLiteDBScopeStoreBuilder
+{
+ private ILiteDatabase? _database;
+ private readonly List _scopes = new();
+
+ public OpenIddictLiteDBScopeStoreBuilder WithDatabase(ILiteDatabase database)
+ {
+ _database = database;
+ return this;
+ }
+
+ public OpenIddictLiteDBScopeStoreBuilder WithScopes(params OpenIddictLiteDBScope[] scopes)
+ {
+ _scopes.AddRange(scopes);
+ return this;
+ }
+
+ public OpenIddictLiteDBScopeStoreBuilder WithScopes(IEnumerable scopes)
+ {
+ _scopes.AddRange(scopes);
+ return this;
+ }
+
+ public OpenIddictLiteDBScopeStore Build()
+ {
+ var database = _database ?? new OpenIddictLiteDatabase(":memory:");
+ var options = new OpenIddictLiteDBOptions();
+
+ if (_scopes.Count > 0)
+ {
+ database
+ .GetCollection(options.ScopesCollectionName)
+ .InsertBulk(_scopes);
+ }
+
+ var contextMock = new Mock();
+ contextMock
+ .Setup(x => x.GetDatabaseAsync(It.IsAny()))
+ .ReturnsAsync(database);
+
+ var optionsMock = new Mock>();
+ optionsMock
+ .SetupGet(x => x.CurrentValue)
+ .Returns(options);
+
+ return new OpenIddictLiteDBScopeStore(contextMock.Object, optionsMock.Object);
+ }
+}
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBTokenFaker.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBTokenFaker.cs
new file mode 100644
index 0000000..10dfcc4
--- /dev/null
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBTokenFaker.cs
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2022 Steven Kuhn and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Sknet.OpenIddict.LiteDB.Tests.Builders;
+
+public class OpenIddictLiteDBTokenFaker : Faker
+{
+ public OpenIddictLiteDBTokenFaker()
+ {
+ UseSeed(1);
+
+ RuleFor(x => x.Id, f => new ObjectId(f.Random.Hexadecimal(24, prefix: "")))
+ .RuleFor(x => x.ApplicationId, f => new ObjectId(f.Random.Hexadecimal(24, prefix: "")))
+ .RuleFor(x => x.AuthorizationId, f => new ObjectId(f.Random.Hexadecimal(24, prefix: "")))
+ .RuleFor(x => x.ConcurrencyToken, f => f.Random.Guid().ToString())
+ .RuleFor(x => x.CreationDate, f => f.Date.PastOffset())
+ .RuleFor(x => x.ExpirationDate, f => f.Date.FutureOffset())
+ .RuleFor(x => x.Properties, f => f.Random.ListItems<(string PropertyName, JsonElement JsonValue)>(new()
+ {
+ ("property1", JsonDocument.Parse("true").RootElement),
+ ("property2", JsonDocument.Parse("false").RootElement),
+ ("property3", JsonDocument.Parse("null").RootElement),
+ ("property4", JsonDocument.Parse("1").RootElement),
+ ("property5", JsonDocument.Parse("1.1").RootElement),
+ ("property6", JsonDocument.Parse(@"""""").RootElement),
+ ("property7", JsonDocument.Parse(@"""value""").RootElement),
+ ("property8", JsonDocument.Parse(@"[""value1"", ""value2""]").RootElement),
+ ("property9", JsonDocument.Parse(@"{""key"": ""value""}").RootElement)
+ })
+ .OrderBy(x => x.PropertyName)
+ .ToImmutableDictionary(x => x.PropertyName, x => x.JsonValue))
+ .RuleFor(x => x.ReferenceId, f => f.Random.Guid().ToString())
+ .RuleFor(x => x.Status, f => f.PickRandom(new[]
+ {
+ Statuses.Inactive,
+ Statuses.Redeemed,
+ Statuses.Rejected,
+ Statuses.Revoked,
+ Statuses.Valid
+ }))
+ .RuleFor(x => x.Subject, f => f.Person.UserName)
+ .RuleFor(x => x.Type, f => f.PickRandom(new[] { TokenTypes.Bearer }));
+ }
+}
\ No newline at end of file
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBTokenStoreBuilder.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBTokenStoreBuilder.cs
new file mode 100644
index 0000000..3a5f085
--- /dev/null
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Builders/OpenIddictLiteDBTokenStoreBuilder.cs
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2022 Steven Kuhn and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Sknet.OpenIddict.LiteDB.Tests.Builders;
+
+public class OpenIddictLiteDBTokenStoreBuilder
+{
+ private ILiteDatabase? _database;
+ private readonly List _authorizations = new();
+ private readonly List _tokens = new();
+
+ public OpenIddictLiteDBTokenStoreBuilder WithAuthorizations(IEnumerable authorizations)
+ {
+ _authorizations.AddRange(authorizations);
+ return this;
+ }
+
+ public OpenIddictLiteDBTokenStoreBuilder WithDatabase(ILiteDatabase database)
+ {
+ _database = database;
+ return this;
+ }
+
+ public OpenIddictLiteDBTokenStoreBuilder WithTokens(params OpenIddictLiteDBToken[] tokens)
+ {
+ _tokens.AddRange(tokens);
+ return this;
+ }
+
+ public OpenIddictLiteDBTokenStoreBuilder WithTokens(IEnumerable tokens)
+ {
+ _tokens.AddRange(tokens);
+ return this;
+ }
+
+ public OpenIddictLiteDBTokenStore Build()
+ {
+ var database = _database ?? new OpenIddictLiteDatabase(":memory:");
+ var options = new OpenIddictLiteDBOptions();
+
+ if (_authorizations.Count > 0)
+ {
+ database
+ .GetCollection(options.AuthorizationsCollectionName)
+ .InsertBulk(_authorizations);
+ }
+
+ if (_tokens.Count > 0)
+ {
+ database
+ .GetCollection(options.TokensCollectionName)
+ .InsertBulk(_tokens);
+ }
+
+ var contextMock = new Mock();
+ contextMock
+ .Setup(x => x.GetDatabaseAsync(It.IsAny()))
+ .ReturnsAsync(database);
+
+ var optionsMock = new Mock>();
+ optionsMock
+ .SetupGet(x => x.CurrentValue)
+ .Returns(options);
+
+ return new OpenIddictLiteDBTokenStore(contextMock.Object, optionsMock.Object);
+ }
+}
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBApplicationStoreResolverTests.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBApplicationStoreResolverTests.cs
index 10517f9..a4de1f2 100644
--- a/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBApplicationStoreResolverTests.cs
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBApplicationStoreResolverTests.cs
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-namespace Sknet.OpenIddict.LiteDB.Tests;
+namespace Sknet.OpenIddict.LiteDB.Tests.Resolvers;
public class OpenIddictLiteDBApplicationStoreResolverTests
{
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBAuthorizationStoreResolverTests.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBAuthorizationStoreResolverTests.cs
index d182976..626062f 100644
--- a/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBAuthorizationStoreResolverTests.cs
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBAuthorizationStoreResolverTests.cs
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-namespace Sknet.OpenIddict.LiteDB.Tests;
+namespace Sknet.OpenIddict.LiteDB.Tests.Resolvers;
public class OpenIddictLiteDBAuthorizationStoreResolverTests
{
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBScopeStoreResolverTests.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBScopeStoreResolverTests.cs
index 892afd9..dcd1b63 100644
--- a/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBScopeStoreResolverTests.cs
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBScopeStoreResolverTests.cs
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-namespace Sknet.OpenIddict.LiteDB.Tests;
+namespace Sknet.OpenIddict.LiteDB.Tests.Resolvers;
public class OpenIddictLiteDBScopeStoreResolverTests
{
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBTokenStoreResolverTests.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBTokenStoreResolverTests.cs
index c420e1e..0782634 100644
--- a/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBTokenStoreResolverTests.cs
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Resolvers/OpenIddictLiteDBTokenStoreResolverTests.cs
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-namespace Sknet.OpenIddict.LiteDB.Tests;
+namespace Sknet.OpenIddict.LiteDB.Tests.Resolvers;
public class OpenIddictLiteDBTokenStoreResolverTests
{
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Sknet.OpenIddict.LiteDB.Tests.csproj b/test/Sknet.OpenIddict.LiteDB.Tests/Sknet.OpenIddict.LiteDB.Tests.csproj
index a0a75a7..ad0dda9 100644
--- a/test/Sknet.OpenIddict.LiteDB.Tests/Sknet.OpenIddict.LiteDB.Tests.csproj
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Sknet.OpenIddict.LiteDB.Tests.csproj
@@ -10,9 +10,12 @@
-
-
+
+
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -27,5 +30,5 @@
-
+
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Stores/ILiteDatabaseExtensions.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Stores/ILiteDatabaseExtensions.cs
new file mode 100644
index 0000000..225aa1e
--- /dev/null
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Stores/ILiteDatabaseExtensions.cs
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022 Steven Kuhn and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Sknet.OpenIddict.LiteDB.Tests;
+
+static class ILiteDatabaseExtensions
+{
+ public static ILiteCollection Applications(this ILiteDatabase database)
+ {
+ var options = new OpenIddictLiteDBOptions();
+
+ return database.GetCollection(options.ApplicationsCollectionName);
+ }
+
+ public static ILiteCollection Authorizations(this ILiteDatabase database)
+ {
+ var options = new OpenIddictLiteDBOptions();
+
+ return database.GetCollection(options.AuthorizationsCollectionName);
+ }
+
+ public static ILiteCollection Scopes(this ILiteDatabase database)
+ {
+ var options = new OpenIddictLiteDBOptions();
+
+ return database.GetCollection(options.ScopesCollectionName);
+ }
+
+ public static ILiteCollection Tokens(this ILiteDatabase database)
+ {
+ var options = new OpenIddictLiteDBOptions();
+
+ return database.GetCollection(options.TokensCollectionName);
+ }
+}
\ No newline at end of file
diff --git a/test/Sknet.OpenIddict.LiteDB.Tests/Stores/OpenIddictLiteDBApplicationStoreTests.cs b/test/Sknet.OpenIddict.LiteDB.Tests/Stores/OpenIddictLiteDBApplicationStoreTests.cs
new file mode 100644
index 0000000..e6fc6e8
--- /dev/null
+++ b/test/Sknet.OpenIddict.LiteDB.Tests/Stores/OpenIddictLiteDBApplicationStoreTests.cs
@@ -0,0 +1,567 @@
+/*
+ * Copyright (c) 2022 Steven Kuhn and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Sknet.OpenIddict.LiteDB.Tests.Stores;
+
+public class OpenIddictLiteDBApplicationStoreTests
+{
+ [Fact]
+ public async Task CountAsync_WithZeroItems_ReturnsZero()
+ {
+ // Arrange
+ var store = new OpenIddictLiteDBApplicationStoreBuilder().Build();
+
+ // Act
+ var result = await store.CountAsync(default);
+
+ // Assert
+ Assert.Equal(0, result);
+
+ }
+
+ [Fact]
+ public async Task CountAsync_WithThreeItems_ReturnsThree()
+ {
+ // Arrange
+ var applications = new OpenIddictLiteDBApplicationFaker().Generate(3);
+ var store = new OpenIddictLiteDBApplicationStoreBuilder()
+ .WithApplications(applications)
+ .Build();
+
+ // Act
+ var result = await store.CountAsync(default);
+
+ // Assert
+ Assert.Equal(3, result);
+ }
+
+ [Fact]
+ public async Task CountAync_WithNullQuery_ThrowsException()
+ {
+ // Arrange
+ var store = new OpenIddictLiteDBApplicationStoreBuilder().Build();
+
+ // Act/Assert
+ var exception = await Assert.ThrowsAsync(
+ "query",
+ () => store.CountAsync