diff --git a/Kinde.Api.Test/Integration/BaseIntegrationTest.cs b/Kinde.Api.Test/Integration/BaseIntegrationTest.cs
new file mode 100644
index 0000000..975a963
--- /dev/null
+++ b/Kinde.Api.Test/Integration/BaseIntegrationTest.cs
@@ -0,0 +1,200 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using Kinde.Api.Client;
+using Microsoft.Extensions.Configuration;
+using Xunit;
+
+namespace Kinde.Api.Test.Integration
+{
+ ///
+ /// Base class for integration tests that support both real and mock modes
+ ///
+ public abstract class BaseIntegrationTest : IClassFixture, IDisposable
+ {
+ protected readonly IntegrationTestFixture Fixture;
+ protected readonly Configuration ApiConfiguration;
+ protected readonly bool IsConfigured;
+ protected readonly bool UseMockMode;
+ protected readonly HttpClient? MockHttpClient;
+
+ protected BaseIntegrationTest(IntegrationTestFixture fixture)
+ {
+ Fixture = fixture;
+ IsConfigured = fixture.IsConfigured;
+ UseMockMode = fixture.UseMockMode;
+
+ if (UseMockMode)
+ {
+ // Create mock HTTP client
+ // Don't set BaseAddress - let ApiClient handle the full URL construction
+ var mockHandler = new MockHttpHandler();
+ MockHttpClient = new HttpClient(mockHandler);
+
+ ApiConfiguration = new Configuration
+ {
+ BasePath = "https://mock.kinde.com",
+ AccessToken = "mock_token"
+ };
+ }
+ else if (IsConfigured)
+ {
+ ApiConfiguration = new Configuration
+ {
+ BasePath = fixture.Domain,
+ AccessToken = fixture.AccessToken
+ };
+ }
+ else
+ {
+ ApiConfiguration = new Configuration();
+ }
+ }
+
+ ///
+ /// Skips the test if neither mock mode nor real credentials are configured
+ ///
+ protected void SkipIfNotConfigured()
+ {
+ if (!UseMockMode && !IsConfigured)
+ {
+ // Fail the test with a clear message about missing configuration
+ Assert.True(false,
+ "Test mode not configured. " +
+ "Either set USE_MOCK_MODE=true for CI/CD testing, " +
+ "or configure real credentials: KINDE_DOMAIN, KINDE_CLIENT_ID, KINDE_CLIENT_SECRET, and KINDE_AUDIENCE environment variables, " +
+ "or configure appsettings.json with KindeManagementApi section.");
+ }
+ }
+
+ ///
+ /// Creates an API client instance, using mock HTTP client if in mock mode
+ ///
+ protected T CreateApiClient(Func factory) where T : class
+ {
+ if (UseMockMode && MockHttpClient != null)
+ {
+ return factory(ApiConfiguration, MockHttpClient);
+ }
+ return factory(ApiConfiguration, null);
+ }
+
+ public virtual void Dispose()
+ {
+ // Override in derived classes if cleanup is needed
+ }
+ }
+
+ ///
+ /// Test fixture that handles M2M authentication once per test run
+ /// Supports both real API mode and mock mode for CI/CD
+ ///
+ public class IntegrationTestFixture : IDisposable
+ {
+ public string? Domain { get; private set; }
+ public string? AccessToken { get; private set; }
+ public bool IsConfigured { get; private set; }
+ public bool UseMockMode { get; private set; }
+
+ public IntegrationTestFixture()
+ {
+ LoadConfiguration();
+ }
+
+ private void LoadConfiguration()
+ {
+ // Check for mock mode first (for CI/CD)
+ var useMockMode = Environment.GetEnvironmentVariable("USE_MOCK_MODE");
+ if (!string.IsNullOrWhiteSpace(useMockMode) &&
+ (useMockMode.Equals("true", StringComparison.OrdinalIgnoreCase) ||
+ useMockMode == "1"))
+ {
+ UseMockMode = true;
+ IsConfigured = true; // Mock mode is always "configured"
+ Console.WriteLine("✓ Using MOCK mode for integration tests (CI/CD mode)");
+ return;
+ }
+
+ // Try to load from appsettings.json first
+ var configuration = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: true)
+ .AddJsonFile("appsettings.Development.json", optional: true)
+ .AddEnvironmentVariables()
+ .Build();
+
+ // Check config file for mock mode
+ var configMockMode = configuration["KindeManagementApi:UseMockMode"];
+ if (!string.IsNullOrWhiteSpace(configMockMode) &&
+ (configMockMode.Equals("true", StringComparison.OrdinalIgnoreCase) ||
+ configMockMode == "1"))
+ {
+ UseMockMode = true;
+ IsConfigured = true;
+ Console.WriteLine("✓ Using MOCK mode for integration tests (from config)");
+ return;
+ }
+
+ // Real API mode - load credentials
+ var domain = configuration["KindeManagementApi:Domain"]
+ ?? Environment.GetEnvironmentVariable("KINDE_DOMAIN");
+ var clientId = configuration["KindeManagementApi:ClientId"]
+ ?? Environment.GetEnvironmentVariable("KINDE_CLIENT_ID");
+ var clientSecret = configuration["KindeManagementApi:ClientSecret"]
+ ?? Environment.GetEnvironmentVariable("KINDE_CLIENT_SECRET");
+ var audience = configuration["KindeManagementApi:Audience"]
+ ?? Environment.GetEnvironmentVariable("KINDE_AUDIENCE");
+ var scope = configuration["KindeManagementApi:Scope"]
+ ?? Environment.GetEnvironmentVariable("KINDE_SCOPE");
+
+ if (string.IsNullOrWhiteSpace(domain) ||
+ string.IsNullOrWhiteSpace(clientId) ||
+ string.IsNullOrWhiteSpace(clientSecret) ||
+ string.IsNullOrWhiteSpace(audience))
+ {
+ IsConfigured = false;
+ Console.WriteLine("WARNING: M2M credentials not configured. Integration tests will be skipped.");
+ Console.WriteLine("Configure via appsettings.json or environment variables:");
+ Console.WriteLine(" - KINDE_DOMAIN");
+ Console.WriteLine(" - KINDE_CLIENT_ID");
+ Console.WriteLine(" - KINDE_CLIENT_SECRET");
+ Console.WriteLine(" - KINDE_AUDIENCE");
+ Console.WriteLine("Or set USE_MOCK_MODE=true for CI/CD testing");
+ return;
+ }
+
+ Domain = domain;
+ IsConfigured = true;
+ UseMockMode = false;
+
+ // Get access token synchronously (xUnit doesn't support async in constructor)
+ try
+ {
+ var task = M2MAuthenticationHelper.GetAccessTokenAsync(
+ domain, clientId, clientSecret, audience, scope);
+ AccessToken = task.GetAwaiter().GetResult();
+
+ if (string.IsNullOrWhiteSpace(AccessToken))
+ {
+ IsConfigured = false;
+ Console.WriteLine("WARNING: Failed to obtain access token. Integration tests will be skipped.");
+ }
+ else
+ {
+ Console.WriteLine("✓ M2M authentication successful for integration tests (REAL API mode)");
+ }
+ }
+ catch (Exception ex)
+ {
+ IsConfigured = false;
+ Console.WriteLine($"WARNING: Failed to authenticate: {ex.Message}. Integration tests will be skipped.");
+ }
+ }
+
+ public void Dispose()
+ {
+ // Cleanup if needed
+ }
+ }
+}
+
diff --git a/Kinde.Api.Test/Integration/ConverterIntegrationTests.cs b/Kinde.Api.Test/Integration/ConverterIntegrationTests.cs
new file mode 100644
index 0000000..06c8f92
--- /dev/null
+++ b/Kinde.Api.Test/Integration/ConverterIntegrationTests.cs
@@ -0,0 +1,667 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Kinde.Api.Api;
+using Kinde.Api.Client;
+using Kinde.Api.Model;
+using Newtonsoft.Json;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Kinde.Api.Test.Integration
+{
+ ///
+ /// Comprehensive integration tests for all Newtonsoft.Json converters
+ /// Tests serialization/deserialization round-trips for all API responses
+ ///
+ [Collection("Integration Tests")]
+ public class ConverterIntegrationTests : BaseIntegrationTest
+ {
+ private readonly ITestOutputHelper _output;
+
+ public ConverterIntegrationTests(IntegrationTestFixture fixture, ITestOutputHelper output)
+ : base(fixture)
+ {
+ _output = output;
+ }
+
+ #region Read-Only Endpoint Tests
+
+ [Fact]
+ public async Task TestGetAPIs_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new APIsApi(MockHttpClient, ApiConfiguration)
+ : new APIsApi(ApiConfiguration);
+
+ var result = await api.GetAPIsAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetAPIs", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetAPIs");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetAPIs", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetApplications_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new ApplicationsApi(MockHttpClient, ApiConfiguration)
+ : new ApplicationsApi(ApiConfiguration);
+
+ var result = await api.GetApplicationsAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetApplications", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetApplications");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetApplications", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetRoles_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new RolesApi(MockHttpClient, ApiConfiguration)
+ : new RolesApi(ApiConfiguration);
+
+ var result = await api.GetRolesAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetRoles", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetRoles");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetRoles", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetPermissions_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new PermissionsApi(MockHttpClient, ApiConfiguration)
+ : new PermissionsApi(ApiConfiguration);
+
+ var result = await api.GetPermissionsAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetPermissions", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetPermissions");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetPermissions", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetProperties_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new PropertiesApi(MockHttpClient, ApiConfiguration)
+ : new PropertiesApi(ApiConfiguration);
+
+ var result = await api.GetPropertiesAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetProperties", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetProperties");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetProperties", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetOrganizations_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new OrganizationsApi(MockHttpClient, ApiConfiguration)
+ : new OrganizationsApi(ApiConfiguration);
+
+ var result = await api.GetOrganizationsAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetOrganizations", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetOrganizations");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetOrganizations", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetConnections_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new ConnectionsApi(MockHttpClient, ApiConfiguration)
+ : new ConnectionsApi(ApiConfiguration);
+
+ var result = await api.GetConnectionsAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetConnections", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetConnections");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetConnections", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetEnvironment_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new EnvironmentsApi(MockHttpClient, ApiConfiguration)
+ : new EnvironmentsApi(ApiConfiguration);
+
+ var result = await api.GetEnvironmentAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetEnvironment", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetEnvironment");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetEnvironment", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetEnvironmentVariables_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new EnvironmentVariablesApi(MockHttpClient, ApiConfiguration)
+ : new EnvironmentVariablesApi(ApiConfiguration);
+
+ var result = await api.GetEnvironmentVariablesAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetEnvironmentVariables", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetEnvironmentVariables");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetEnvironmentVariables", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetBusiness_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new BusinessApi(MockHttpClient, ApiConfiguration)
+ : new BusinessApi(ApiConfiguration);
+
+ var result = await api.GetBusinessAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetBusiness", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetBusiness");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetBusiness", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetIndustries_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new IndustriesApi(MockHttpClient, ApiConfiguration)
+ : new IndustriesApi(ApiConfiguration);
+
+ var result = await api.GetIndustriesAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetIndustries", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetIndustries");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetIndustries", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetTimezones_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new TimezonesApi(MockHttpClient, ApiConfiguration)
+ : new TimezonesApi(ApiConfiguration);
+
+ var result = await api.GetTimezonesAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetTimezones", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetTimezones");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetTimezones", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetCategories_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new PropertyCategoriesApi(MockHttpClient, ApiConfiguration)
+ : new PropertyCategoriesApi(ApiConfiguration);
+
+ var result = await api.GetCategoriesAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetCategories", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetCategories");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetCategories", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetSubscribers_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var api = UseMockMode && MockHttpClient != null
+ ? new SubscribersApi(MockHttpClient, ApiConfiguration)
+ : new SubscribersApi(ApiConfiguration);
+
+ var result = await api.GetSubscribersAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetSubscribers", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetSubscribers");
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetSubscribers", ex);
+ throw;
+ }
+ }
+
+ #endregion
+
+ #region Parameterized Endpoint Tests
+
+ [Fact]
+ public async Task TestGetAPI_WithId_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var apisApi = UseMockMode && MockHttpClient != null
+ ? new APIsApi(MockHttpClient, ApiConfiguration)
+ : new APIsApi(ApiConfiguration);
+
+ var apis = await apisApi.GetAPIsAsync();
+
+ if (apis?.Apis != null && apis.Apis.Count > 0)
+ {
+ var apiId = apis.Apis[0].Id;
+ var result = await apisApi.GetAPIAsync(apiId);
+
+ Assert.NotNull(result);
+ TestSerializationRoundTrip(result, $"GetAPI-{apiId}");
+ }
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetAPI_WithId", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetAPIScopes_WithId_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var apisApi = UseMockMode && MockHttpClient != null
+ ? new APIsApi(MockHttpClient, ApiConfiguration)
+ : new APIsApi(ApiConfiguration);
+
+ var apis = await apisApi.GetAPIsAsync();
+
+ if (apis?.Apis != null && apis.Apis.Count > 0)
+ {
+ var apiId = apis.Apis[0].Id;
+ var result = await apisApi.GetAPIScopesAsync(apiId);
+
+ Assert.NotNull(result);
+ TestSerializationRoundTrip(result, $"GetAPIScopes-{apiId}");
+ }
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetAPIScopes_WithId", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetApplication_WithId_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var appsApi = UseMockMode && MockHttpClient != null
+ ? new ApplicationsApi(MockHttpClient, ApiConfiguration)
+ : new ApplicationsApi(ApiConfiguration);
+
+ var applications = await appsApi.GetApplicationsAsync();
+
+ if (applications?.Applications != null && applications.Applications.Count > 0)
+ {
+ var appId = applications.Applications[0].Id;
+ var result = await appsApi.GetApplicationAsync(appId);
+
+ Assert.NotNull(result);
+ TestSerializationRoundTrip(result, $"GetApplication-{appId}");
+ }
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetApplication_WithId", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetRole_WithId_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var rolesApi = UseMockMode && MockHttpClient != null
+ ? new RolesApi(MockHttpClient, ApiConfiguration)
+ : new RolesApi(ApiConfiguration);
+
+ var roles = await rolesApi.GetRolesAsync();
+
+ if (roles?.Roles != null && roles.Roles.Count > 0)
+ {
+ var roleId = roles.Roles[0].Id;
+ var result = await rolesApi.GetRoleAsync(roleId);
+
+ Assert.NotNull(result);
+ TestSerializationRoundTrip(result, $"GetRole-{roleId}");
+ }
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetRole_WithId", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetRoleScopes_WithId_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var rolesApi = UseMockMode && MockHttpClient != null
+ ? new RolesApi(MockHttpClient, ApiConfiguration)
+ : new RolesApi(ApiConfiguration);
+
+ var roles = await rolesApi.GetRolesAsync();
+
+ if (roles?.Roles != null && roles.Roles.Count > 0)
+ {
+ var roleId = roles.Roles[0].Id;
+ var result = await rolesApi.GetRoleScopesAsync(roleId);
+
+ Assert.NotNull(result);
+ TestSerializationRoundTrip(result, $"GetRoleScopes-{roleId}");
+ }
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetRoleScopes_WithId", ex);
+ throw;
+ }
+ }
+
+ [Fact]
+ public async Task TestGetRolePermissions_WithId_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+ var rolesApi = UseMockMode && MockHttpClient != null
+ ? new RolesApi(MockHttpClient, ApiConfiguration)
+ : new RolesApi(ApiConfiguration);
+
+ var roles = await rolesApi.GetRolesAsync();
+
+ if (roles?.Roles != null && roles.Roles.Count > 0)
+ {
+ var roleId = roles.Roles[0].Id;
+ var result = await rolesApi.GetRolePermissionsAsync(roleId);
+
+ Assert.NotNull(result);
+ TestSerializationRoundTrip(result, $"GetRolePermissions-{roleId}");
+ }
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetRolePermissions_WithId", ex);
+ throw;
+ }
+ }
+
+ #endregion
+
+ #region Helper Methods
+
+ ///
+ /// Tests serialization/deserialization round-trip for a response object
+ ///
+ private void TestSerializationRoundTrip(T original, string testName) where T : class
+ {
+ try
+ {
+ // Get the standard converters from ApiClient using reflection
+ var apiClientType = typeof(Kinde.Api.Client.ApiClient);
+ var helperType = apiClientType.Assembly.GetType("Kinde.Api.Client.JsonConverterHelper");
+ IList converters;
+ if (helperType != null)
+ {
+ var method = helperType.GetMethod("CreateStandardConverters",
+ System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
+ if (method != null)
+ {
+ converters = (IList)method.Invoke(null, null)!;
+ }
+ else
+ {
+ throw new InvalidOperationException("Could not find CreateStandardConverters method");
+ }
+ }
+ else
+ {
+ throw new InvalidOperationException("Could not find JsonConverterHelper type");
+ }
+ var settings = new JsonSerializerSettings
+ {
+ Converters = converters,
+ NullValueHandling = NullValueHandling.Ignore
+ };
+
+ // Serialize
+ var json = JsonConvert.SerializeObject(original, settings);
+ Assert.False(string.IsNullOrEmpty(json),
+ $"{testName}: Serialization produced empty JSON");
+
+ _output.WriteLine($"{testName}: Serialized to {json.Length} characters");
+
+ // Deserialize
+ var deserialized = JsonConvert.DeserializeObject(json, settings);
+ Assert.NotNull(deserialized);
+
+ // Round-trip comparison
+ var originalJson = JsonConvert.SerializeObject(original, settings);
+ var deserializedJson = JsonConvert.SerializeObject(deserialized, settings);
+
+ Assert.Equal(originalJson, deserializedJson);
+
+ _output.WriteLine($"✓ {testName}: Converter test passed");
+ }
+ catch (Exception ex)
+ {
+ _output.WriteLine($"✗ {testName}: Converter test failed - {ex.Message}");
+ throw;
+ }
+ }
+
+ #endregion
+ }
+}
+
diff --git a/Kinde.Api.Test/Integration/GeneratedConverterIntegrationTests.cs b/Kinde.Api.Test/Integration/GeneratedConverterIntegrationTests.cs
new file mode 100644
index 0000000..d7c0c1a
--- /dev/null
+++ b/Kinde.Api.Test/Integration/GeneratedConverterIntegrationTests.cs
@@ -0,0 +1,3146 @@
+//
+// This file is automatically generated by the test generator.
+// DO NOT EDIT THIS FILE MANUALLY - your changes will be overwritten.
+// To regenerate this file, run: python generate_integration_tests.py --spec --output
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using Kinde.Api.Api;
+using Kinde.Api.Client;
+using Kinde.Api.Model;
+using Newtonsoft.Json;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Kinde.Api.Test.Integration
+{
+ ///
+ /// Auto-generated integration tests for all API endpoints
+ /// Tests serialization/deserialization round-trips for all converters
+ ///
+ [Collection("Integration Tests")]
+ public class GeneratedConverterIntegrationTests : BaseIntegrationTest
+ {
+ private readonly ITestOutputHelper _output;
+
+ public GeneratedConverterIntegrationTests(IntegrationTestFixture fixture, ITestOutputHelper output)
+ : base(fixture)
+ {
+ _output = output;
+ }
+
+
+ #region APIsApi Tests
+
+
+ [Fact]
+ public async Task TestGetAPIs_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetAPIs - requires parameters: expand");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetAPIs", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestAddAPIs_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping AddAPIs - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "AddAPIs", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteAPI_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteAPI - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteAPI", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetAPI_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetAPI - requires parameters: api_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetAPI", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetAPIScopes_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetAPIScopes - requires parameters: api_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetAPIScopes", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestAddAPIScope_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping AddAPIScope - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "AddAPIScope", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteAPIScope_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteAPIScope - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteAPIScope", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetAPIScope_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetAPIScope - requires parameters: api_id, scope_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetAPIScope", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateAPIScope_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateAPIScope - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateAPIScope", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteAPIAppliationScope_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteAPIAppliationScope - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteAPIAppliationScope", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region ApplicationsApi Tests
+
+
+ [Fact]
+ public async Task TestUpdateAPIApplications_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateAPIApplications - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateAPIApplications", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestAddAPIApplicationScope_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping AddAPIApplicationScope - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "AddAPIApplicationScope", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetApplications_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetApplications - requires parameters: sort, page_size, next_token");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetApplications", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateApplication_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateApplication - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateApplication", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteApplication_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteApplication - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteApplication", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetApplication_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetApplication - requires parameters: application_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetApplication", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateApplication_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateApplication - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateApplication", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetApplicationConnections_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetApplicationConnections - requires parameters: application_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetApplicationConnections", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetApplicationPropertyValues_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetApplicationPropertyValues - requires parameters: application_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetApplicationPropertyValues", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateApplicationsProperty_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateApplicationsProperty - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateApplicationsProperty", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateApplicationTokens_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateApplicationTokens - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateApplicationTokens", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region ConnectionsApi Tests
+
+
+ [Fact]
+ public async Task TestRemoveConnection_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping RemoveConnection - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "RemoveConnection", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestEnableConnection_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping EnableConnection - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "EnableConnection", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetConnections_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetConnections - requires parameters: page_size, home_realm_domain, starting_after, ending_before");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetConnections", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateConnection_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateConnection - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateConnection", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteConnection_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteConnection - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteConnection", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetConnection_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetConnection - requires parameters: connection_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetConnection", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateConnection_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateConnection - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateConnection", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestReplaceConnection_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping ReplaceConnection - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "ReplaceConnection", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestRemoveOrgConnection_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping RemoveOrgConnection - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "RemoveOrgConnection", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestEnableOrgConnection_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping EnableOrgConnection - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "EnableOrgConnection", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region BillingEntitlementsApi Tests
+
+
+ [Fact]
+ public async Task TestGetBillingEntitlements_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetBillingEntitlements - requires parameters: page_size, starting_after, ending_before, customer_id, max_value, expand");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetBillingEntitlements", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region BillingAgreementsApi Tests
+
+
+ [Fact]
+ public async Task TestGetBillingAgreements_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetBillingAgreements - requires parameters: page_size, starting_after, ending_before, customer_id, feature_code");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetBillingAgreements", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateBillingAgreement_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateBillingAgreement - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateBillingAgreement", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region BillingMeterUsageApi Tests
+
+
+ [Fact]
+ public async Task TestCreateMeterUsageRecord_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateMeterUsageRecord - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateMeterUsageRecord", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region BusinessApi Tests
+
+
+ [Fact]
+ public async Task TestGetBusiness_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Create API instance with mock HTTP client if in mock mode
+ var api = UseMockMode && MockHttpClient != null
+ ? new BusinessApi(MockHttpClient, ApiConfiguration)
+ : new BusinessApi(ApiConfiguration);
+
+ var result = await api.GetBusinessAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetBusiness", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetBusiness");
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetBusiness", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateBusiness_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateBusiness - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateBusiness", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region TimezonesApi Tests
+
+
+ [Fact]
+ public async Task TestGetTimezones_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Create API instance with mock HTTP client if in mock mode
+ var api = UseMockMode && MockHttpClient != null
+ ? new TimezonesApi(MockHttpClient, ApiConfiguration)
+ : new TimezonesApi(ApiConfiguration);
+
+ var result = await api.GetTimezonesAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetTimezones", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetTimezones");
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetTimezones", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region CallbacksApi Tests
+
+
+ [Fact]
+ public async Task TestDeleteCallbackURLs_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteCallbackURLs - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteCallbackURLs", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetCallbackURLs_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetCallbackURLs - requires parameters: app_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetCallbackURLs", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestAddRedirectCallbackURLs_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping AddRedirectCallbackURLs - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "AddRedirectCallbackURLs", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestReplaceRedirectCallbackURLs_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping ReplaceRedirectCallbackURLs - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "ReplaceRedirectCallbackURLs", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region EnvironmentsApi Tests
+
+
+ [Fact]
+ public async Task TestGetEnvironment_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Create API instance with mock HTTP client if in mock mode
+ var api = UseMockMode && MockHttpClient != null
+ ? new EnvironmentsApi(MockHttpClient, ApiConfiguration)
+ : new EnvironmentsApi(ApiConfiguration);
+
+ var result = await api.GetEnvironmentAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetEnvironment", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetEnvironment");
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetEnvironment", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region EnvironmentVariablesApi Tests
+
+
+ [Fact]
+ public async Task TestGetEnvironmentVariables_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Create API instance with mock HTTP client if in mock mode
+ var api = UseMockMode && MockHttpClient != null
+ ? new EnvironmentVariablesApi(MockHttpClient, ApiConfiguration)
+ : new EnvironmentVariablesApi(ApiConfiguration);
+
+ var result = await api.GetEnvironmentVariablesAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetEnvironmentVariables", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetEnvironmentVariables");
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetEnvironmentVariables", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateEnvironmentVariable_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateEnvironmentVariable - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateEnvironmentVariable", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteEnvironmentVariable_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteEnvironmentVariable - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteEnvironmentVariable", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetEnvironmentVariable_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetEnvironmentVariable - requires parameters: variable_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetEnvironmentVariable", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateEnvironmentVariable_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateEnvironmentVariable - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateEnvironmentVariable", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region IdentitiesApi Tests
+
+
+ [Fact]
+ public async Task TestDeleteIdentity_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteIdentity - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteIdentity", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetIdentity_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetIdentity - requires parameters: identity_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetIdentity", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateIdentity_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateIdentity - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateIdentity", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateUserIdentity_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateUserIdentity - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateUserIdentity", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region MFAApi Tests
+
+
+ [Fact]
+ public async Task TestReplaceMFA_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping ReplaceMFA - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "ReplaceMFA", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region OrganizationsApi Tests
+
+
+ [Fact]
+ public async Task TestGetOrganization_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetOrganization - requires parameters: code");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetOrganization", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateOrganization_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateOrganization - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateOrganization", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetOrganizations_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetOrganizations - requires parameters: sort, page_size, next_token");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetOrganizations", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteOrganization_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteOrganization - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteOrganization", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateOrganization_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateOrganization - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateOrganization", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetOrganizationUsers_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetOrganizationUsers - requires parameters: sort, page_size, next_token, org_code, permissions, roles");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetOrganizationUsers", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateOrganizationUsers_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateOrganizationUsers - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateOrganizationUsers", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestAddOrganizationUsers_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping AddOrganizationUsers - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "AddOrganizationUsers", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetOrganizationUserRoles_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetOrganizationUserRoles - requires parameters: org_code, user_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetOrganizationUserRoles", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateOrganizationUserRole_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateOrganizationUserRole - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateOrganizationUserRole", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteOrganizationUserRole_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteOrganizationUserRole - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteOrganizationUserRole", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetOrganizationUserPermissions_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetOrganizationUserPermissions - requires parameters: org_code, user_id, expand");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetOrganizationUserPermissions", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateOrganizationUserPermission_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateOrganizationUserPermission - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateOrganizationUserPermission", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteOrganizationUserPermission_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteOrganizationUserPermission - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteOrganizationUserPermission", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestRemoveOrganizationUser_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping RemoveOrganizationUser - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "RemoveOrganizationUser", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteOrganizationUserAPIScope_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteOrganizationUserAPIScope - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteOrganizationUserAPIScope", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestAddOrganizationUserAPIScope_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping AddOrganizationUserAPIScope - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "AddOrganizationUserAPIScope", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteOrganizationFeatureFlagOverrides_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteOrganizationFeatureFlagOverrides - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteOrganizationFeatureFlagOverrides", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetOrganizationFeatureFlags_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetOrganizationFeatureFlags - requires parameters: org_code");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetOrganizationFeatureFlags", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteOrganizationFeatureFlagOverride_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteOrganizationFeatureFlagOverride - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteOrganizationFeatureFlagOverride", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateOrganizationFeatureFlagOverride_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping UpdateOrganizationFeatureFlagOverride - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateOrganizationFeatureFlagOverride", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateOrganizationProperty_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping UpdateOrganizationProperty - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateOrganizationProperty", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetOrganizationPropertyValues_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetOrganizationPropertyValues - requires parameters: org_code");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetOrganizationPropertyValues", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateOrganizationProperties_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateOrganizationProperties - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateOrganizationProperties", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestReplaceOrganizationMFA_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping ReplaceOrganizationMFA - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "ReplaceOrganizationMFA", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteOrganizationHandle_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteOrganizationHandle - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteOrganizationHandle", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestReadOrganizationLogo_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping ReadOrganizationLogo - requires parameters: org_code");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "ReadOrganizationLogo", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteOrganizationLogo_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteOrganizationLogo - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteOrganizationLogo", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestAddOrganizationLogo_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping AddOrganizationLogo - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "AddOrganizationLogo", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetOrganizationConnections_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetOrganizationConnections - requires parameters: organization_code");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetOrganizationConnections", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateOrganizationSessions_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateOrganizationSessions - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateOrganizationSessions", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region UsersApi Tests
+
+
+ [Fact]
+ public async Task TestResetOrgUserMFAAll_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping ResetOrgUserMFAAll - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "ResetOrgUserMFAAll", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetOrgUserMFA_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetOrgUserMFA - requires parameters: org_code, user_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetOrgUserMFA", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestResetOrgUserMFA_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping ResetOrgUserMFA - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "ResetOrgUserMFA", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetUsers_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetUsers - requires parameters: page_size, user_id, next_token, email, username, expand, has_organization");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetUsers", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestRefreshUserClaims_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping RefreshUserClaims - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "RefreshUserClaims", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteUser_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteUser - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteUser", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetUserData_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetUserData - requires parameters: id, expand");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetUserData", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateUser_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateUser - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateUser", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateUser_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateUser - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateUser", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateUserFeatureFlagOverride_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping UpdateUserFeatureFlagOverride - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateUserFeatureFlagOverride", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateUserProperties_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateUserProperties - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateUserProperties", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestSetUserPassword_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping SetUserPassword - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "SetUserPassword", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetUserIdentities_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetUserIdentities - requires parameters: user_id, starting_after, ending_before");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetUserIdentities", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteUserSessions_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteUserSessions - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteUserSessions", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetUserSessions_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetUserSessions - requires parameters: user_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetUserSessions", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestResetUsersMFAAll_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping ResetUsersMFAAll - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "ResetUsersMFAAll", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetUsersMFA_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetUsersMFA - requires parameters: user_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetUsersMFA", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestResetUsersMFA_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping ResetUsersMFA - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "ResetUsersMFA", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region PermissionsApi Tests
+
+
+ [Fact]
+ public async Task TestGetPermissions_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetPermissions - requires parameters: sort, page_size, next_token");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetPermissions", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreatePermission_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreatePermission - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreatePermission", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeletePermission_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeletePermission - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeletePermission", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdatePermissions_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdatePermissions - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdatePermissions", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetRolePermissions_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetRolePermissions - requires parameters: role_id, sort, page_size, next_token");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetRolePermissions", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateRolePermissions_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateRolePermissions - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateRolePermissions", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestRemoveRolePermission_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping RemoveRolePermission - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "RemoveRolePermission", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region PropertiesApi Tests
+
+
+ [Fact]
+ public async Task TestCreateProperty_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateProperty - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateProperty", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteProperty_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteProperty - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteProperty", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateProperty_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateProperty - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateProperty", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateUserProperty_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping UpdateUserProperty - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateUserProperty", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetUserPropertyValues_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetUserPropertyValues - requires parameters: user_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetUserPropertyValues", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region PropertyCategoriesApi Tests
+
+
+ [Fact]
+ public async Task TestCreateCategory_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateCategory - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateCategory", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateCategory_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateCategory - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateCategory", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region RolesApi Tests
+
+
+ [Fact]
+ public async Task TestGetRoles_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetRoles - requires parameters: sort, page_size, next_token");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetRoles", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateRole_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateRole - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateRole", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteRole_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteRole - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteRole", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetRole_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetRole - requires parameters: role_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetRole", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateRoles_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateRoles - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateRoles", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetRoleScopes_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetRoleScopes - requires parameters: role_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetRoleScopes", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestAddRoleScope_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping AddRoleScope - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "AddRoleScope", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestDeleteRoleScope_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteRoleScope - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteRoleScope", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region SearchApi Tests
+
+
+ [Fact]
+ public async Task TestSearchUsers_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping SearchUsers - requires parameters: page_size, query, properties, starting_after, ending_before, expand");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "SearchUsers", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region SubscribersApi Tests
+
+
+ [Fact]
+ public async Task TestGetSubscribers_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetSubscribers - requires parameters: sort, page_size, next_token");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetSubscribers", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateSubscriber_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping CreateSubscriber - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateSubscriber", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetSubscriber_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // This endpoint requires parameters - skipping automatic test
+ // TODO: Add manual test with appropriate parameters
+ _output.WriteLine($"Skipping GetSubscriber - requires parameters: subscriber_id");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetSubscriber", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region WebhooksApi Tests
+
+
+ [Fact]
+ public async Task TestDeleteWebHook_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Unknown operation type
+ _output.WriteLine($"Skipping DeleteWebHook - unknown operation type");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "DeleteWebHook", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestUpdateWebHook_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping UpdateWebHook - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "UpdateWebHook", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestGetWebHooks_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Create API instance with mock HTTP client if in mock mode
+ var api = UseMockMode && MockHttpClient != null
+ ? new WebhooksApi(MockHttpClient, ApiConfiguration)
+ : new WebhooksApi(ApiConfiguration);
+
+ var result = await api.GetWebHooksAsync();
+
+ Assert.NotNull(result);
+
+ // Show detailed output
+ TestOutputHelper.WriteResponseDetails(_output, "GetWebHooks", result);
+
+ // Test serialization round-trip
+ TestSerializationRoundTrip(result, "GetWebHooks");
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "GetWebHooks", ex);
+ throw;
+ }
+ }
+
+
+ [Fact]
+ public async Task TestCreateWebHook_Converter()
+ {
+ SkipIfNotConfigured();
+
+ try
+ {
+
+ // Write operation - skipping to avoid modifying data
+ // TODO: Add manual test with appropriate request object
+ _output.WriteLine($"Skipping CreateWebHook - write operation");
+ return;
+
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteError(_output, "CreateWebHook", ex);
+ throw;
+ }
+ }
+
+
+ #endregion
+
+
+ #region Helper Methods
+
+ ///
+ /// Tests serialization/deserialization round-trip for a response object
+ ///
+ private void TestSerializationRoundTrip(T original, string testName) where T : class
+ {
+ try
+ {
+ // Get the standard converters from ApiClient using reflection
+ var apiClientType = typeof(Kinde.Api.Client.ApiClient);
+ var helperType = apiClientType.Assembly.GetType("Kinde.Api.Client.JsonConverterHelper");
+ IList converters;
+ if (helperType != null)
+ {
+ var method = helperType.GetMethod("CreateStandardConverters",
+ System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
+ if (method != null)
+ {
+ converters = (IList)method.Invoke(null, null)!;
+ }
+ else
+ {
+ throw new InvalidOperationException("Could not find CreateStandardConverters method");
+ }
+ }
+ else
+ {
+ throw new InvalidOperationException("Could not find JsonConverterHelper type");
+ }
+
+ var settings = new JsonSerializerSettings
+ {
+ Converters = converters,
+ NullValueHandling = NullValueHandling.Ignore
+ };
+
+ // Serialize
+ var json = JsonConvert.SerializeObject(original, settings);
+ Assert.False(string.IsNullOrEmpty(json),
+ $"{testName}: Serialization produced empty JSON");
+
+ // Deserialize
+ var deserialized = JsonConvert.DeserializeObject(json, settings);
+ Assert.NotNull(deserialized);
+
+ // Round-trip comparison
+ var originalJson = JsonConvert.SerializeObject(original, settings);
+ var deserializedJson = JsonConvert.SerializeObject(deserialized, settings);
+
+ Assert.Equal(originalJson, deserializedJson);
+
+ // Use enhanced output helper
+ TestOutputHelper.WriteSerializationTest(_output, testName, json.Length, true);
+ }
+ catch (Exception ex)
+ {
+ TestOutputHelper.WriteSerializationTest(_output, testName, 0, false);
+ _output.WriteLine($"Serialization error: {ex.Message}");
+ throw;
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/Kinde.Api.Test/Integration/GeneratedMockResponses.cs b/Kinde.Api.Test/Integration/GeneratedMockResponses.cs
new file mode 100644
index 0000000..776a863
--- /dev/null
+++ b/Kinde.Api.Test/Integration/GeneratedMockResponses.cs
@@ -0,0 +1,32 @@
+//
+// This file is automatically generated by the mock response generator.
+// DO NOT EDIT THIS FILE MANUALLY - your changes will be overwritten.
+// To regenerate this file, run: python generate_mock_responses.py --spec --output
+//
+
+using System;
+using System.Net;
+
+namespace Kinde.Api.Test.Integration
+{
+ ///
+ /// Auto-generated mock response data for integration tests.
+ /// This class is automatically generated - do not edit manually.
+ ///
+ public static class GeneratedMockResponses
+ {
+ ///
+ /// Sets up all mock responses in the provided MockHttpHandler.
+ /// This method is automatically generated - do not edit manually.
+ ///
+ public static void SetupResponses(MockHttpHandler handler)
+ {
+ if (handler == null)
+ throw new ArgumentNullException(nameof(handler));
+
+ // This file will be populated when generate-all-apis.sh is run
+ // Mock responses are generated from the OpenAPI specification
+ }
+ }
+}
+
diff --git a/Kinde.Api.Test/Integration/HOW_TO_RUN_TESTS.md b/Kinde.Api.Test/Integration/HOW_TO_RUN_TESTS.md
new file mode 100644
index 0000000..e05fe3e
--- /dev/null
+++ b/Kinde.Api.Test/Integration/HOW_TO_RUN_TESTS.md
@@ -0,0 +1,258 @@
+# How to Run Integration Tests
+
+This guide explains how to run integration tests in both **Mock Mode** (for CI/CD) and **Real API Mode** (for local development).
+
+## Quick Reference
+
+### Mock Mode (CI/CD - No Credentials Required)
+```bash
+USE_MOCK_MODE=true dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+```
+
+### Real API Mode (Local Development - Requires Credentials)
+```bash
+dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+```
+
+---
+
+## Mock Mode (CI/CD Testing)
+
+Mock mode uses predefined mock HTTP responses. **No Kinde credentials required.** Perfect for:
+- GitHub Actions
+- CI/CD pipelines
+- Quick local testing without API access
+- Testing converter logic without network calls
+
+### Option 1: Environment Variable (Recommended for CI/CD)
+
+```bash
+# Linux/macOS
+export USE_MOCK_MODE=true
+dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+
+# Windows PowerShell
+$env:USE_MOCK_MODE="true"
+dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+
+# Windows CMD
+set USE_MOCK_MODE=true
+dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+
+# Inline (all platforms)
+USE_MOCK_MODE=true dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+```
+
+### Option 2: Configuration File
+
+Create or update `Kinde.Api.Test/appsettings.json`:
+
+```json
+{
+ "KindeManagementApi": {
+ "UseMockMode": true
+ }
+}
+```
+
+Then run:
+```bash
+dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+```
+
+### GitHub Actions Example
+
+```yaml
+- name: Run Integration Tests (Mock Mode)
+ env:
+ USE_MOCK_MODE: "true"
+ run: |
+ dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+```
+
+---
+
+## Real API Mode (Local Development)
+
+Real API mode makes actual HTTP requests to Kinde servers. **Requires M2M credentials.**
+
+### Step 1: Configure Credentials
+
+Choose one method:
+
+#### Method A: Environment Variables
+
+```bash
+# Linux/macOS
+export KINDE_DOMAIN="https://your-business.kinde.com"
+export KINDE_CLIENT_ID="your_m2m_client_id"
+export KINDE_CLIENT_SECRET="your_m2m_client_secret"
+export KINDE_AUDIENCE="https://your-business.kinde.com/api"
+export KINDE_SCOPE="read:users read:organizations read:applications read:roles read:permissions read:properties"
+
+# Windows PowerShell
+$env:KINDE_DOMAIN="https://your-business.kinde.com"
+$env:KINDE_CLIENT_ID="your_m2m_client_id"
+$env:KINDE_CLIENT_SECRET="your_m2m_client_secret"
+$env:KINDE_AUDIENCE="https://your-business.kinde.com/api"
+$env:KINDE_SCOPE="read:users read:organizations read:applications read:roles read:permissions read:properties"
+```
+
+#### Method B: Configuration File
+
+Create `Kinde.Api.Test/appsettings.json`:
+
+```json
+{
+ "KindeManagementApi": {
+ "UseMockMode": false,
+ "Domain": "https://your-business.kinde.com",
+ "ClientId": "your_m2m_client_id_here",
+ "ClientSecret": "your_m2m_client_secret_here",
+ "Audience": "https://your-business.kinde.com/api",
+ "Scope": "read:users read:organizations read:applications read:roles read:permissions read:properties"
+ }
+}
+```
+
+**Note:** Make sure `UseMockMode` is `false` or not set.
+
+### Step 2: Run Tests
+
+```bash
+dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+```
+
+---
+
+## Test Output
+
+Both modes provide enhanced output showing:
+- Response type information
+- Key properties from API responses
+- Full JSON response (truncated if > 2000 chars)
+- Serialization round-trip test results
+- Error details with stack traces
+
+### Example Output (Mock Mode)
+
+```
+═══════════════════════════════════════════════════════════════
+Test: GetBusiness
+═══════════════════════════════════════════════════════════════
+Response Type: GetBusinessResponse
+
+Key Properties:
+ code: OK
+ message: Success
+ business: {...}
+
+Full Response JSON:
+{
+ "code": "OK",
+ "message": "Success",
+ "business": {
+ "code": "bus_test123",
+ "name": "Test Business",
+ ...
+ }
+}
+═══════════════════════════════════════════════════════════════
+✓ GetBusiness: Success
+```
+
+---
+
+## Verifying Mode
+
+The test output will indicate which mode is active:
+
+### Mock Mode
+```
+✓ Using MOCK mode for integration tests (CI/CD mode)
+```
+
+### Real API Mode
+```
+✓ M2M authentication successful for integration tests (REAL API mode)
+```
+
+---
+
+## Troubleshooting
+
+### Tests Skipped / Not Configured
+
+If you see:
+```
+WARNING: M2M credentials not configured. Integration tests will be skipped.
+```
+
+**Solutions:**
+1. For mock mode: Set `USE_MOCK_MODE=true` or `UseMockMode: true` in config
+2. For real mode: Configure credentials (see "Real API Mode" above)
+
+### Authentication Failed (Real Mode)
+
+If you see:
+```
+WARNING: Failed to obtain access token. Integration tests will be skipped.
+```
+
+**Check:**
+- Credentials are correct
+- Domain URL is correct (include `https://`)
+- M2M application is properly configured in Kinde
+- Scopes are correct for your M2M application
+
+### Mock Mode Not Working
+
+If mock mode isn't activating:
+
+1. **Check environment variable:**
+ ```bash
+ echo $USE_MOCK_MODE # Should output "true"
+ ```
+
+2. **Check config file:**
+ ```bash
+ cat Kinde.Api.Test/appsettings.json | grep UseMockMode
+ ```
+
+3. **Ensure it's not overridden:**
+ - Real credentials will take precedence if configured
+ - Remove real credentials if you want mock mode
+
+---
+
+## Running Specific Tests
+
+### All Integration Tests
+```bash
+dotnet test --filter "FullyQualifiedName~Integration"
+```
+
+### Only Generated Tests
+```bash
+dotnet test --filter "FullyQualifiedName~GeneratedConverterIntegrationTests"
+```
+
+### Only Manual Tests
+```bash
+dotnet test --filter "FullyQualifiedName~ConverterIntegrationTests"
+```
+
+### Specific Test Method
+```bash
+dotnet test --filter "FullyQualifiedName~TestGetBusiness_Converter"
+```
+
+---
+
+## Summary
+
+| Mode | Command | Credentials Required | Use Case |
+|------|---------|---------------------|----------|
+| **Mock** | `USE_MOCK_MODE=true dotnet test ...` | ❌ No | CI/CD, quick testing |
+| **Real** | `dotnet test ...` | ✅ Yes | Local development, full validation |
+
diff --git a/Kinde.Api.Test/Integration/M2MAuthenticationHelper.cs b/Kinde.Api.Test/Integration/M2MAuthenticationHelper.cs
new file mode 100644
index 0000000..d0b0331
--- /dev/null
+++ b/Kinde.Api.Test/Integration/M2MAuthenticationHelper.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace Kinde.Api.Test.Integration
+{
+ ///
+ /// Helper class for M2M (Machine-to-Machine) authentication with Kinde Management API
+ ///
+ public static class M2MAuthenticationHelper
+ {
+ ///
+ /// Gets an access token using client credentials flow
+ ///
+ /// Kinde business domain (e.g., https://your-business.kinde.com)
+ /// M2M application client ID
+ /// M2M application client secret
+ /// API audience (typically https://your-business.kinde.com/api)
+ /// Optional scope string
+ /// Access token or null if authentication failed
+ public static async Task GetAccessTokenAsync(
+ string domain,
+ string clientId,
+ string clientSecret,
+ string audience,
+ string? scope = null)
+ {
+ if (string.IsNullOrWhiteSpace(domain))
+ throw new ArgumentException("Domain cannot be null or empty", nameof(domain));
+ if (string.IsNullOrWhiteSpace(clientId))
+ throw new ArgumentException("ClientId cannot be null or empty", nameof(clientId));
+ if (string.IsNullOrWhiteSpace(clientSecret))
+ throw new ArgumentException("ClientSecret cannot be null or empty", nameof(clientSecret));
+ if (string.IsNullOrWhiteSpace(audience))
+ throw new ArgumentException("Audience cannot be null or empty", nameof(audience));
+
+ try
+ {
+ using var httpClient = new HttpClient();
+ var tokenUrl = $"{domain.TrimEnd('/')}/oauth2/token";
+
+ var requestParams = new List>
+ {
+ new("grant_type", "client_credentials"),
+ new("client_id", clientId),
+ new("client_secret", clientSecret),
+ new("audience", audience)
+ };
+
+ if (!string.IsNullOrWhiteSpace(scope))
+ {
+ requestParams.Add(new KeyValuePair("scope", scope));
+ }
+
+ var requestContent = new FormUrlEncodedContent(requestParams);
+ var response = await httpClient.PostAsync(tokenUrl, requestContent);
+
+ response.EnsureSuccessStatusCode();
+
+ var jsonResponse = await response.Content.ReadAsStringAsync();
+ var tokenData = JsonConvert.DeserializeObject(jsonResponse);
+
+ return tokenData?["access_token"]?.ToString();
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException(
+ $"Failed to obtain access token: {ex.Message}", ex);
+ }
+ }
+ }
+}
+
diff --git a/Kinde.Api.Test/Integration/MockHttpHandler.cs b/Kinde.Api.Test/Integration/MockHttpHandler.cs
new file mode 100644
index 0000000..753f0ec
--- /dev/null
+++ b/Kinde.Api.Test/Integration/MockHttpHandler.cs
@@ -0,0 +1,428 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace Kinde.Api.Test.Integration
+{
+ ///
+ /// Mock HTTP message handler for integration tests
+ /// Returns predefined responses based on request patterns
+ ///
+ public class MockHttpHandler : HttpMessageHandler
+ {
+ // Store JSON strings instead of HttpResponseMessage to avoid content reuse issues
+ private readonly Dictionary _responses = new();
+ private readonly Dictionary> _responseFactories = new();
+
+ public MockHttpHandler()
+ {
+ SetupDefaultResponses();
+ // Load auto-generated mock responses
+ GeneratedMockResponses.SetupResponses(this);
+ }
+
+ ///
+ /// Sets up default mock responses for common endpoints
+ ///
+ private void SetupDefaultResponses()
+ {
+ // GetBusiness endpoint
+ AddResponse("GET", "/api/v1/business", new
+ {
+ code = "OK",
+ message = "Success",
+ business = new
+ {
+ code = "bus_test123",
+ name = "Test Business",
+ phone = "+1234567890",
+ email = "test@example.com",
+ industry = "Technology",
+ timezone = "America/Los_Angeles",
+ privacy_url = "https://example.com/privacy",
+ terms_url = "https://example.com/terms",
+ has_clickwrap = true,
+ has_kinde_branding = false,
+ created_on = "2024-01-01T00:00:00Z"
+ }
+ });
+
+ // GetEnvironment endpoint
+ AddResponse("GET", "/api/v1/environment", new
+ {
+ code = "OK",
+ message = "Success",
+ environment = new
+ {
+ code = "production",
+ name = "Production",
+ is_default = true,
+ is_live = true,
+ kinde_domain = "test.kinde.com",
+ created_on = "2024-01-01T00:00:00Z"
+ }
+ });
+
+ // GetEnvironmentVariables endpoint
+ AddResponse("GET", "/api/v1/environment-variables", new
+ {
+ code = "OK",
+ message = "Success",
+ environment_variables = new[]
+ {
+ new { key = "API_KEY", value = "secret_value", is_secret = true },
+ new { key = "DEBUG_MODE", value = "false", is_secret = false }
+ }
+ });
+
+ // GetOrganizations endpoint
+ AddResponse("GET", "/api/v1/organizations", new
+ {
+ code = "OK",
+ message = "Success",
+ organizations = new[]
+ {
+ new { code = "org_001", name = "Organization 1", is_default = true },
+ new { code = "org_002", name = "Organization 2", is_default = false }
+ },
+ next_token = (string?)null
+ });
+
+ // GetAPIs endpoint
+ AddResponse("GET", "/api/v1/apis", new
+ {
+ code = "OK",
+ message = "Success",
+ apis = new[]
+ {
+ new
+ {
+ id = "api_001",
+ name = "Test API",
+ audience = "https://api.example.com",
+ is_management_api = true
+ }
+ }
+ });
+
+ // GetApplications endpoint
+ AddResponse("GET", "/api/v1/applications", new
+ {
+ code = "OK",
+ message = "Success",
+ applications = new[]
+ {
+ new
+ {
+ id = "app_001",
+ name = "Test Application",
+ type = "reg",
+ client_id = "client_123"
+ }
+ }
+ });
+
+ // GetRoles endpoint
+ AddResponse("GET", "/api/v1/roles", new
+ {
+ code = "OK",
+ message = "Success",
+ roles = new[]
+ {
+ new { id = "role_001", name = "Admin", key = "admin" },
+ new { id = "role_002", name = "User", key = "user" }
+ }
+ });
+
+ // GetPermissions endpoint
+ AddResponse("GET", "/api/v1/permissions", new
+ {
+ code = "OK",
+ message = "Success",
+ permissions = new[]
+ {
+ new { id = "perm_001", name = "read:users", key = "read:users" },
+ new { id = "perm_002", name = "write:users", key = "write:users" }
+ }
+ });
+
+ // GetProperties endpoint
+ AddResponse("GET", "/api/v1/properties", new
+ {
+ code = "OK",
+ message = "Success",
+ properties = new[]
+ {
+ new { id = "prop_001", name = "theme", key = "theme", type = "str" }
+ }
+ });
+
+ // GetTimezones endpoint
+ AddResponse("GET", "/api/v1/timezones", new
+ {
+ code = "OK",
+ message = "Success",
+ timezones = new[]
+ {
+ new { key = "America/Los_Angeles", name = "Pacific Time" },
+ new { key = "America/New_York", name = "Eastern Time" }
+ }
+ });
+
+ // GetIndustries endpoint
+ AddResponse("GET", "/api/v1/industries", new
+ {
+ code = "OK",
+ message = "Success",
+ industries = new[]
+ {
+ new { name = "Technology" },
+ new { name = "Healthcare" }
+ }
+ });
+
+ // GetConnections endpoint
+ AddResponse("GET", "/api/v1/connections", new
+ {
+ code = "OK",
+ message = "Success",
+ connections = new[]
+ {
+ new
+ {
+ id = "conn_001",
+ name = "Test Connection",
+ type = "saml"
+ }
+ }
+ });
+
+ // GetWebHooks endpoint
+ AddResponse("GET", "/api/v1/webhooks", new
+ {
+ code = "OK",
+ message = "Success",
+ webhooks = new[]
+ {
+ new
+ {
+ id = "webhook_001",
+ endpoint = "https://example.com/webhook",
+ events = new[] { "user.created", "user.updated" }
+ }
+ }
+ });
+
+ // GetCategories endpoint (Property Categories)
+ AddResponse("GET", "/api/v1/property_categories", new
+ {
+ code = "OK",
+ message = "Success",
+ property_categories = new[]
+ {
+ new { id = "cat_001", name = "User Properties" },
+ new { id = "cat_002", name = "Organization Properties" }
+ }
+ });
+
+ // GetSubscribers endpoint
+ AddResponse("GET", "/api/v1/subscribers", new
+ {
+ code = "OK",
+ message = "Success",
+ subscribers = new[]
+ {
+ new
+ {
+ id = "sub_001",
+ email = "subscriber@example.com",
+ full_name = "Test Subscriber"
+ }
+ }
+ });
+
+ // Parameterized endpoints - use more specific path patterns
+ // GetAPIScopes by ID - /api/v1/apis/{api_id}/scopes (more specific, check first)
+ AddResponse("GET", "/api/v1/apis/", new
+ {
+ code = "OK",
+ message = "Success",
+ scopes = new[]
+ {
+ new { id = "scope_001", name = "read:users" },
+ new { id = "scope_002", name = "write:users" }
+ }
+ }, pathContains: "/scopes");
+
+ // GetAPI by ID - /api/v1/apis/{api_id} (less specific, check after scopes)
+ AddResponse("GET", "/api/v1/apis/", new
+ {
+ code = "OK",
+ message = "Success",
+ api = new
+ {
+ id = "api_001",
+ name = "Test API",
+ audience = "https://api.example.com",
+ is_management_api = true
+ }
+ });
+
+ // GetRolePermissions by ID - /api/v1/roles/{role_id}/permissions (most specific)
+ AddResponse("GET", "/api/v1/roles/", new
+ {
+ code = "OK",
+ message = "Success",
+ permissions = new[]
+ {
+ new { id = "perm_001", name = "read:users", key = "read:users" }
+ }
+ }, pathContains: "/permissions");
+
+ // GetRoleScopes by ID - /api/v1/roles/{role_id}/scopes
+ AddResponse("GET", "/api/v1/roles/", new
+ {
+ code = "OK",
+ message = "Success",
+ scopes = new[]
+ {
+ new { id = "scope_001", name = "read:users" }
+ }
+ }, pathContains: "/scopes");
+
+ // GetRole by ID - /api/v1/roles/{role_id}
+ AddResponse("GET", "/api/v1/roles/", new
+ {
+ code = "OK",
+ message = "Success",
+ role = new
+ {
+ id = "role_001",
+ name = "Admin",
+ key = "admin"
+ }
+ });
+
+ // GetApplication by ID - /api/v1/applications/{application_id}
+ AddResponse("GET", "/api/v1/applications/", new
+ {
+ code = "OK",
+ message = "Success",
+ application = new
+ {
+ id = "app_001",
+ name = "Test Application",
+ type = "reg",
+ client_id = "client_123"
+ }
+ });
+ }
+
+ ///
+ /// Adds a mock response for a specific HTTP method and path pattern
+ ///
+ public void AddResponse(string method, string pathPattern, object responseData, HttpStatusCode statusCode = HttpStatusCode.OK, string? pathContains = null)
+ {
+ var key = $"{method.ToUpper()}:{pathPattern}";
+ if (!string.IsNullOrEmpty(pathContains))
+ {
+ key += $":{pathContains}";
+ }
+ var json = JsonConvert.SerializeObject(responseData);
+ // Store JSON string to avoid content reuse issues
+ _responses[key] = (statusCode, json);
+ }
+
+ ///
+ /// Adds a mock response from a JSON string (used by generated mock responses)
+ ///
+ public void AddResponseFromJson(string method, string pathPattern, string jsonContent, HttpStatusCode statusCode = HttpStatusCode.OK)
+ {
+ var key = $"{method.ToUpper()}:{pathPattern}";
+ _responses[key] = (statusCode, jsonContent);
+ }
+
+ ///
+ /// Adds a dynamic response factory for a specific HTTP method and path pattern
+ ///
+ public void AddResponseFactory(string method, string pathPattern, Func factory)
+ {
+ var key = $"{method.ToUpper()}:{pathPattern}";
+ _responseFactories[key] = factory;
+ }
+
+ protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ var method = request.Method.Method;
+ var path = request.RequestUri?.AbsolutePath ?? "";
+ var fullUrl = request.RequestUri?.ToString() ?? "";
+
+ // Debug: Log the request (can be removed later)
+ System.Diagnostics.Debug.WriteLine($"MockHttpHandler: {method} {path} (full: {fullUrl})");
+
+ // Try to find exact match first
+ var exactKey = $"{method}:{path}";
+ if (_responses.TryGetValue(exactKey, out var exactResponse))
+ {
+ System.Diagnostics.Debug.WriteLine($"MockHttpHandler: Found exact match for {exactKey}");
+ var response = new HttpResponseMessage(exactResponse.StatusCode)
+ {
+ Content = new StringContent(exactResponse.JsonContent, Encoding.UTF8, "application/json")
+ };
+ return Task.FromResult(response);
+ }
+
+ // Try to find path pattern match (check most specific patterns first)
+ // Sort by key length descending to check more specific patterns first
+ var sortedResponses = _responses.OrderByDescending(kvp => kvp.Key.Length);
+ foreach (var kvp in sortedResponses)
+ {
+ var keyParts = kvp.Key.Split(':');
+ if (keyParts.Length >= 2 && keyParts[0] == method && path.StartsWith(keyParts[1]))
+ {
+ // If there's a pathContains requirement (keyParts[2]), check it
+ if (keyParts.Length >= 3)
+ {
+ var pathContains = keyParts[2];
+ if (!path.Contains(pathContains))
+ {
+ continue; // Skip this response, path doesn't contain required substring
+ }
+ }
+
+ System.Diagnostics.Debug.WriteLine($"MockHttpHandler: Found pattern match for {kvp.Key}");
+ var response = new HttpResponseMessage(kvp.Value.StatusCode)
+ {
+ Content = new StringContent(kvp.Value.JsonContent, Encoding.UTF8, "application/json")
+ };
+ return Task.FromResult(response);
+ }
+ }
+
+ // Try response factories
+ foreach (var kvp in _responseFactories)
+ {
+ var keyParts = kvp.Key.Split(':', 2);
+ if (keyParts.Length == 2 && keyParts[0] == method && path.StartsWith(keyParts[1]))
+ {
+ System.Diagnostics.Debug.WriteLine($"MockHttpHandler: Using factory for {kvp.Key}");
+ return Task.FromResult(kvp.Value(request));
+ }
+ }
+
+ // Default: return 404 with JSON (not HTML)
+ System.Diagnostics.Debug.WriteLine($"MockHttpHandler: No match found for {method} {path}, returning 404");
+ return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound)
+ {
+ Content = new StringContent(JsonConvert.SerializeObject(new { error = "Not found", path, method }), Encoding.UTF8, "application/json")
+ });
+ }
+ }
+}
+
diff --git a/Kinde.Api.Test/Integration/README.md b/Kinde.Api.Test/Integration/README.md
new file mode 100644
index 0000000..50627c9
--- /dev/null
+++ b/Kinde.Api.Test/Integration/README.md
@@ -0,0 +1,94 @@
+# Integration Tests
+
+This directory contains integration tests for the Kinde .NET SDK. The tests support two modes:
+
+## Test Modes
+
+### 1. Real API Mode (Local Development)
+
+Tests run against actual Kinde API servers. Requires M2M credentials.
+
+**Configuration:**
+
+Set environment variables or configure `appsettings.json`:
+
+```json
+{
+ "KindeManagementApi": {
+ "UseMockMode": false,
+ "Domain": "https://your-business.kinde.com",
+ "ClientId": "your_m2m_client_id_here",
+ "ClientSecret": "your_m2m_client_secret_here",
+ "Audience": "https://your-business.kinde.com/api",
+ "Scope": "read:users read:organizations read:applications read:roles read:permissions read:properties"
+ }
+}
+```
+
+Or set environment variables:
+- `KINDE_DOMAIN`
+- `KINDE_CLIENT_ID`
+- `KINDE_CLIENT_SECRET`
+- `KINDE_AUDIENCE`
+- `KINDE_SCOPE` (optional)
+
+**Running:**
+
+```bash
+dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+```
+
+### 2. Mock Mode (CI/CD)
+
+Tests use mock HTTP responses. No credentials required. Perfect for GitHub Actions and CI/CD pipelines.
+
+**Configuration:**
+
+Set environment variable:
+```bash
+export USE_MOCK_MODE=true
+```
+
+Or in `appsettings.json`:
+```json
+{
+ "KindeManagementApi": {
+ "UseMockMode": true
+ }
+}
+```
+
+**Running:**
+
+```bash
+USE_MOCK_MODE=true dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+```
+
+## Test Output
+
+Tests provide detailed output including:
+- Response type information
+- Key properties from API responses
+- Full JSON response (truncated if > 2000 chars)
+- Serialization round-trip test results
+- Error details with stack traces
+
+## Files
+
+- `BaseIntegrationTest.cs` - Base class supporting both test modes
+- `MockHttpHandler.cs` - Mock HTTP handler for CI/CD testing
+- `TestOutputHelper.cs` - Enhanced test output formatting
+- `ConverterIntegrationTests.cs` - Manual integration tests
+- `GeneratedConverterIntegrationTests.cs` - Auto-generated integration tests
+- `M2MAuthenticationHelper.cs` - M2M authentication helper
+
+## GitHub Actions Example
+
+```yaml
+- name: Run Integration Tests (Mock Mode)
+ env:
+ USE_MOCK_MODE: "true"
+ run: |
+ dotnet test Kinde.Api.Test/Kinde.Api.Test.csproj --filter "FullyQualifiedName~Integration"
+```
+
diff --git a/Kinde.Api.Test/Integration/TEST_GENERATION_IMPACT.md b/Kinde.Api.Test/Integration/TEST_GENERATION_IMPACT.md
new file mode 100644
index 0000000..5f97ca9
--- /dev/null
+++ b/Kinde.Api.Test/Integration/TEST_GENERATION_IMPACT.md
@@ -0,0 +1,134 @@
+# Impact of Auto-Generation on Integration Tests
+
+## Overview
+
+The integration test infrastructure supports both **manually written tests** and **auto-generated tests**. This document explains how the auto-generation process affects the test infrastructure.
+
+## Test Files
+
+### Manually Maintained (NOT affected by regeneration)
+
+These files are **never overwritten** by the generation process:
+
+- ✅ `BaseIntegrationTest.cs` - Base class with mock mode support
+- ✅ `MockHttpHandler.cs` - Mock HTTP handler for CI/CD
+- ✅ `TestOutputHelper.cs` - Enhanced output formatting
+- ✅ `ConverterIntegrationTests.cs` - Manually written integration tests
+- ✅ `M2MAuthenticationHelper.cs` - M2M authentication helper
+- ✅ `IntegrationTestFixture.cs` - Test fixture (part of BaseIntegrationTest.cs)
+
+### Auto-Generated (OVERWRITTEN on regeneration)
+
+This file is **completely regenerated** each time you run the test generator:
+
+- ⚠️ `GeneratedConverterIntegrationTests.cs` - Auto-generated from OpenAPI spec
+
+## What Happens When Tests Are Regenerated?
+
+### ✅ Safe - Won't Break
+
+1. **Base Class Compatibility**: The generated tests inherit from `BaseIntegrationTest`, which we've enhanced with:
+ - Mock mode support (`UseMockMode`, `MockHttpClient`)
+ - Enhanced configuration handling
+ - Both real and mock mode support
+
+2. **Template Updates**: The test generator template (`tools/test-generator/templates/integration_test.cs.j2`) has been updated to:
+ - Use mock HTTP client when in mock mode
+ - Use `TestOutputHelper` for enhanced output
+ - Follow the same patterns as manually written tests
+
+### ⚠️ What Gets Regenerated
+
+When you run `generate-all-apis.sh` or manually run the test generator:
+
+1. **`GeneratedConverterIntegrationTests.cs`** is completely rewritten
+2. All test methods are regenerated based on the current OpenAPI spec
+3. New endpoints get new test methods automatically
+4. Removed endpoints have their test methods removed
+
+### ✅ What Stays the Same
+
+1. **Manually written tests** in `ConverterIntegrationTests.cs` are never touched
+2. **Test infrastructure** (BaseIntegrationTest, MockHttpHandler, etc.) remains unchanged
+3. **Configuration** (appsettings.json) is not modified
+
+## Regeneration Process
+
+### Current State (After Updates)
+
+The test generator template now generates tests that:
+
+```csharp
+// ✅ Uses mock mode when available
+var api = UseMockMode && MockHttpClient != null
+ ? new BusinessApi(MockHttpClient, ApiConfiguration)
+ : new BusinessApi(ApiConfiguration);
+
+// ✅ Uses enhanced output
+TestOutputHelper.WriteResponseDetails(_output, "GetBusiness", result);
+
+// ✅ Uses enhanced serialization test output
+TestSerializationRoundTrip(result, "GetBusiness");
+```
+
+### Before Template Updates
+
+The old template generated:
+
+```csharp
+// ❌ Didn't use mock mode
+var api = new BusinessApi(ApiConfiguration);
+
+// ❌ Basic output only
+_output.WriteLine($"✓ {testName}: Converter test passed");
+```
+
+## Best Practices
+
+### 1. Don't Edit Generated Tests
+
+**Never manually edit** `GeneratedConverterIntegrationTests.cs`. Your changes will be lost on regeneration.
+
+### 2. Add Custom Tests to Manual File
+
+If you need custom test logic, add it to `ConverterIntegrationTests.cs` instead.
+
+### 3. Update Template for Changes
+
+If you want to change how **all** generated tests work, update:
+- `tools/test-generator/templates/integration_test.cs.j2`
+
+### 4. Regenerate After API Changes
+
+After updating the OpenAPI spec or regenerating API clients:
+```bash
+./generate-all-apis.sh
+```
+
+This will:
+- Regenerate converters
+- Regenerate API clients
+- **Regenerate integration tests** (with latest template)
+
+## Verification
+
+After regeneration, verify:
+
+1. ✅ Tests compile: `dotnet build Kinde.Api.Test/Kinde.Api.Test.csproj`
+2. ✅ Mock mode works: `USE_MOCK_MODE=true dotnet test --filter "FullyQualifiedName~Generated"`
+3. ✅ Real mode works: `dotnet test --filter "FullyQualifiedName~Generated"`
+4. ✅ Enhanced output appears in test results
+
+## Summary
+
+| Component | Regenerated? | Impact |
+|-----------|--------------|--------|
+| `BaseIntegrationTest.cs` | ❌ No | Safe - manually maintained |
+| `MockHttpHandler.cs` | ❌ No | Safe - manually maintained |
+| `TestOutputHelper.cs` | ❌ No | Safe - manually maintained |
+| `ConverterIntegrationTests.cs` | ❌ No | Safe - manually maintained |
+| `GeneratedConverterIntegrationTests.cs` | ✅ Yes | Regenerated with latest template |
+| Test Generator Template | ❌ No | Update manually when needed |
+
+**Bottom Line**: The auto-generation process is now **fully compatible** with the enhanced test infrastructure. Regenerating tests will use mock mode and enhanced output automatically.
+
diff --git a/Kinde.Api.Test/Integration/TestOutputHelper.cs b/Kinde.Api.Test/Integration/TestOutputHelper.cs
new file mode 100644
index 0000000..772e330
--- /dev/null
+++ b/Kinde.Api.Test/Integration/TestOutputHelper.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Xunit.Abstractions;
+
+namespace Kinde.Api.Test.Integration
+{
+ ///
+ /// Helper class for formatting test output with detailed API response information
+ ///
+ public static class TestOutputHelper
+ {
+ ///
+ /// Formats and outputs detailed information about an API response
+ ///
+ public static void WriteResponseDetails(ITestOutputHelper output, string testName, T result) where T : class
+ {
+ output.WriteLine("");
+ output.WriteLine($"═══════════════════════════════════════════════════════════════");
+ output.WriteLine($"Test: {testName}");
+ output.WriteLine($"═══════════════════════════════════════════════════════════════");
+
+ try
+ {
+ // Serialize to JSON for display
+ // Get converters using reflection (JsonConverterRegistry is internal)
+ var apiClientType = typeof(Kinde.Api.Client.ApiClient);
+ var helperType = apiClientType.Assembly.GetType("Kinde.Api.Client.JsonConverterHelper");
+ IList converters;
+ if (helperType != null)
+ {
+ var method = helperType.GetMethod("CreateStandardConverters",
+ System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
+ if (method != null)
+ {
+ converters = (IList)method.Invoke(null, null)!;
+ }
+ else
+ {
+ converters = new List();
+ }
+ }
+ else
+ {
+ converters = new List();
+ }
+
+ var settings = new JsonSerializerSettings
+ {
+ Formatting = Formatting.Indented,
+ NullValueHandling = NullValueHandling.Include,
+ Converters = converters
+ };
+
+ var json = JsonConvert.SerializeObject(result, settings);
+ var jsonObj = JObject.Parse(json);
+
+ // Display summary
+ output.WriteLine($"Response Type: {typeof(T).Name}");
+ output.WriteLine($"");
+
+ // Display key properties
+ output.WriteLine("Key Properties:");
+ DisplayProperties(output, jsonObj, 0, maxDepth: 2);
+
+ // Display full JSON (truncated if too long)
+ output.WriteLine("");
+ output.WriteLine("Full Response JSON:");
+ if (json.Length > 2000)
+ {
+ output.WriteLine(json.Substring(0, 2000) + "... (truncated)");
+ output.WriteLine($"Total length: {json.Length} characters");
+ }
+ else
+ {
+ output.WriteLine(json);
+ }
+
+ output.WriteLine($"═══════════════════════════════════════════════════════════════");
+ output.WriteLine($"✓ {testName}: Success");
+ output.WriteLine("");
+ }
+ catch (Exception ex)
+ {
+ output.WriteLine($"Error formatting response: {ex.Message}");
+ output.WriteLine($"Response Type: {typeof(T).Name}");
+ output.WriteLine($"Response: {result?.ToString() ?? "null"}");
+ }
+ }
+
+ private static void DisplayProperties(ITestOutputHelper output, JToken token, int depth, int maxDepth)
+ {
+ if (depth > maxDepth) return;
+
+ var indent = new string(' ', depth * 2);
+
+ if (token is JObject obj)
+ {
+ foreach (var prop in obj.Properties().Take(10)) // Limit to first 10 properties
+ {
+ if (prop.Value is JObject || prop.Value is JArray)
+ {
+ output.WriteLine($"{indent}{prop.Name}: {{...}}");
+ if (depth < maxDepth)
+ {
+ DisplayProperties(output, prop.Value, depth + 1, maxDepth);
+ }
+ }
+ else
+ {
+ var value = prop.Value?.ToString() ?? "null";
+ if (value.Length > 100)
+ {
+ value = value.Substring(0, 100) + "...";
+ }
+ output.WriteLine($"{indent}{prop.Name}: {value}");
+ }
+ }
+
+ if (obj.Properties().Count() > 10)
+ {
+ output.WriteLine($"{indent}... ({obj.Properties().Count() - 10} more properties)");
+ }
+ }
+ else if (token is JArray array)
+ {
+ output.WriteLine($"{indent}[Array with {array.Count} items]");
+ if (array.Count > 0 && depth < maxDepth)
+ {
+ output.WriteLine($"{indent} First item:");
+ DisplayProperties(output, array[0], depth + 1, maxDepth);
+ }
+ }
+ }
+
+ ///
+ /// Formats error output
+ ///
+ public static void WriteError(ITestOutputHelper output, string testName, Exception ex)
+ {
+ output.WriteLine("");
+ output.WriteLine($"═══════════════════════════════════════════════════════════════");
+ output.WriteLine($"✗ {testName}: FAILED");
+ output.WriteLine($"═══════════════════════════════════════════════════════════════");
+ output.WriteLine($"Error: {ex.Message}");
+ output.WriteLine($"Type: {ex.GetType().Name}");
+ if (ex.InnerException != null)
+ {
+ output.WriteLine($"Inner Exception: {ex.InnerException.Message}");
+ }
+ output.WriteLine($"Stack Trace:");
+ output.WriteLine(ex.StackTrace);
+ output.WriteLine($"═══════════════════════════════════════════════════════════════");
+ output.WriteLine("");
+ }
+
+ ///
+ /// Formats serialization round-trip test results
+ ///
+ public static void WriteSerializationTest(ITestOutputHelper output, string testName, int jsonLength, bool success)
+ {
+ if (success)
+ {
+ output.WriteLine($"✓ {testName}: Serialization round-trip successful ({jsonLength} bytes)");
+ }
+ else
+ {
+ output.WriteLine($"✗ {testName}: Serialization round-trip failed");
+ }
+ }
+ }
+}
+
diff --git a/Kinde.Api.Test/Kinde.Api.Test.csproj b/Kinde.Api.Test/Kinde.Api.Test.csproj
index a753ace..182bd4f 100644
--- a/Kinde.Api.Test/Kinde.Api.Test.csproj
+++ b/Kinde.Api.Test/Kinde.Api.Test.csproj
@@ -9,6 +9,9 @@
+
+
+
all
@@ -20,6 +23,15 @@
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
enable
diff --git a/Kinde.Api.Test/appsettings.json b/Kinde.Api.Test/appsettings.json
new file mode 100644
index 0000000..a333a3b
--- /dev/null
+++ b/Kinde.Api.Test/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "KindeManagementApi": {
+ "Domain": "https://burntjam.kinde.com",
+ "ClientId": "9891928d4e20445e8d42e92831e0d89a",
+ "ClientSecret": "1U6leJtMm1lMRc3b7ZGXeIGKdOnCQJkkPKWrlgw3oajBvTQ5OJI2",
+ "Audience": "https://burntjam.kinde.com/api"
+ }
+}
+
diff --git a/Kinde.Api.Test/appsettings.json.example b/Kinde.Api.Test/appsettings.json.example
new file mode 100644
index 0000000..363c12f
--- /dev/null
+++ b/Kinde.Api.Test/appsettings.json.example
@@ -0,0 +1,11 @@
+{
+ "KindeManagementApi": {
+ "UseMockMode": false,
+ "Domain": "https://your-business.kinde.com",
+ "ClientId": "your_m2m_client_id_here",
+ "ClientSecret": "your_m2m_client_secret_here",
+ "Audience": "https://your-business.kinde.com/api",
+ "Scope": "read:users read:organizations read:applications read:roles read:permissions read:properties"
+ }
+}
+
diff --git a/Kinde.Api.Test/packages.lock.json b/Kinde.Api.Test/packages.lock.json
index d638e4f..24110d3 100644
--- a/Kinde.Api.Test/packages.lock.json
+++ b/Kinde.Api.Test/packages.lock.json
@@ -2,6 +2,39 @@
"version": 1,
"dependencies": {
"net8.0": {
+ "Microsoft.Extensions.Configuration": {
+ "type": "Direct",
+ "requested": "[9.0.4, )",
+ "resolved": "9.0.4",
+ "contentHash": "KIVBrMbItnCJDd1RF4KEaE8jZwDJcDUJW5zXpbwQ05HNYTK1GveHxHK0B3SjgDJuR48GRACXAO+BLhL8h34S7g==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "9.0.4",
+ "Microsoft.Extensions.Primitives": "9.0.4"
+ }
+ },
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": {
+ "type": "Direct",
+ "requested": "[9.0.4, )",
+ "resolved": "9.0.4",
+ "contentHash": "2IGiG3FtVnD83IA6HYGuNei8dOw455C09yEhGl8bjcY6aGZgoC6yhYvDnozw8wlTowfoG9bxVrdTsr2ACZOYHg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "9.0.4",
+ "Microsoft.Extensions.Configuration.Abstractions": "9.0.4"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Json": {
+ "type": "Direct",
+ "requested": "[9.0.4, )",
+ "resolved": "9.0.4",
+ "contentHash": "vVXI70CgT/dmXV3MM+n/BR2rLXEoAyoK0hQT+8MrbCMuJBiLRxnTtSrksNiASWCwOtxo/Tyy7CO8AGthbsYxnw==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "9.0.4",
+ "Microsoft.Extensions.Configuration.Abstractions": "9.0.4",
+ "Microsoft.Extensions.Configuration.FileExtensions": "9.0.4",
+ "Microsoft.Extensions.FileProviders.Abstractions": "9.0.4",
+ "System.Text.Json": "9.0.4"
+ }
+ },
"Microsoft.NET.Test.Sdk": {
"type": "Direct",
"requested": "[17.14.1, )",
@@ -66,15 +99,6 @@
"Microsoft.Extensions.ObjectPool": "8.0.19"
}
},
- "Microsoft.Extensions.Configuration": {
- "type": "Transitive",
- "resolved": "9.0.4",
- "contentHash": "KIVBrMbItnCJDd1RF4KEaE8jZwDJcDUJW5zXpbwQ05HNYTK1GveHxHK0B3SjgDJuR48GRACXAO+BLhL8h34S7g==",
- "dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "9.0.4",
- "Microsoft.Extensions.Primitives": "9.0.4"
- }
- },
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "9.0.4",
@@ -91,6 +115,18 @@
"Microsoft.Extensions.Configuration.Abstractions": "9.0.4"
}
},
+ "Microsoft.Extensions.Configuration.FileExtensions": {
+ "type": "Transitive",
+ "resolved": "9.0.4",
+ "contentHash": "UY864WQ3AS2Fkc8fYLombWnjrXwYt+BEHHps0hY4sxlgqaVW06AxbpgRZjfYf8PyRbplJqruzZDB/nSLT+7RLQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "9.0.4",
+ "Microsoft.Extensions.Configuration.Abstractions": "9.0.4",
+ "Microsoft.Extensions.FileProviders.Abstractions": "9.0.4",
+ "Microsoft.Extensions.FileProviders.Physical": "9.0.4",
+ "Microsoft.Extensions.Primitives": "9.0.4"
+ }
+ },
"Microsoft.Extensions.DependencyInjection": {
"type": "Transitive",
"resolved": "9.0.4",
@@ -148,6 +184,21 @@
"Microsoft.Extensions.Primitives": "9.0.4"
}
},
+ "Microsoft.Extensions.FileProviders.Physical": {
+ "type": "Transitive",
+ "resolved": "9.0.4",
+ "contentHash": "qkQ9V7KFZdTWNThT7ke7E/Jad38s46atSs3QUYZB8f3thBTrcrousdY4Y/tyCtcH5YjsPSiByjuN+L8W/ThMQg==",
+ "dependencies": {
+ "Microsoft.Extensions.FileProviders.Abstractions": "9.0.4",
+ "Microsoft.Extensions.FileSystemGlobbing": "9.0.4",
+ "Microsoft.Extensions.Primitives": "9.0.4"
+ }
+ },
+ "Microsoft.Extensions.FileSystemGlobbing": {
+ "type": "Transitive",
+ "resolved": "9.0.4",
+ "contentHash": "05Lh2ItSk4mzTdDWATW9nEcSybwprN8Tz42Fs5B+jwdXUpauktdAQUI1Am4sUQi2C63E5hvQp8gXvfwfg9mQGQ=="
+ },
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "Transitive",
"resolved": "9.0.4",
diff --git a/Kinde.Api/Accounts/Api/BillingApi.cs b/Kinde.Api/Accounts/Api/BillingApi.cs
index 361969a..6565781 100644
--- a/Kinde.Api/Accounts/Api/BillingApi.cs
+++ b/Kinde.Api/Accounts/Api/BillingApi.cs
@@ -62,7 +62,7 @@ public interface IBillingApi : IApi
/// Get entitlements
///
///
- /// Returns all the entitlements a the user currently has access to
+ /// Returns all the entitlements the user currently has access to
///
/// Thrown when fails to make API call
/// Number of results per page. Defaults to 10 if parameter not sent. (optional)
@@ -75,7 +75,7 @@ public interface IBillingApi : IApi
/// Get entitlements
///
///
- /// Returns all the entitlements a the user currently has access to
+ /// Returns all the entitlements the user currently has access to
///
/// Number of results per page. Defaults to 10 if parameter not sent. (optional)
/// The ID of the entitlement to start after. (optional)
@@ -542,7 +542,7 @@ private void OnErrorGetEntitlementsDefaultImplementation(Exception exceptionLoca
partial void OnErrorGetEntitlements(ref bool suppressDefaultLogLocalVar, Exception exceptionLocalVar, string pathFormatLocalVar, string pathLocalVar, Option pageSize, Option startingAfter);
///
- /// Get entitlements Returns all the entitlements a the user currently has access to
+ /// Get entitlements Returns all the entitlements the user currently has access to
///
/// Number of results per page. Defaults to 10 if parameter not sent. (optional)
/// The ID of the entitlement to start after. (optional)
@@ -561,7 +561,7 @@ private void OnErrorGetEntitlementsDefaultImplementation(Exception exceptionLoca
}
///
- /// Get entitlements Returns all the entitlements a the user currently has access to
+ /// Get entitlements Returns all the entitlements the user currently has access to
///
/// Thrown when fails to make API call
/// Number of results per page. Defaults to 10 if parameter not sent. (optional)
diff --git a/Kinde.Api/Accounts/Converters/ErrorNewtonsoftConverter.cs b/Kinde.Api/Accounts/Converters/ErrorNewtonsoftConverter.cs
new file mode 100644
index 0000000..066478f
--- /dev/null
+++ b/Kinde.Api/Accounts/Converters/ErrorNewtonsoftConverter.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Kinde.Accounts.Model;
+using Kinde.Accounts.Client;
+
+namespace Kinde.Api.Accounts.Converters
+{
+ ///
+ /// Newtonsoft.Json converter for Error that handles the Option<> structure
+ ///
+ public class ErrorNewtonsoftConverter : Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanRead => true;
+ public override bool CanWrite => true;
+
+ public override Error ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, Error existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
+ {
+ if (reader.TokenType != Newtonsoft.Json.JsonToken.StartObject)
+ {
+ throw new Newtonsoft.Json.JsonException($"Expected StartObject, got {reader.TokenType}");
+ }
+
+ var jsonObject = JObject.Load(reader);
+
+ string? code = default(string?);
+ if (jsonObject["code"] != null)
+ {
+ code = jsonObject["code"].ToObject();
+ }
+ string? message = default(string?);
+ if (jsonObject["message"] != null)
+ {
+ message = jsonObject["message"].ToObject();
+ }
+
+ return new Error(
+ code: code != null ? new Option(code) : default, message: message != null ? new Option(message) : default );
+ }
+
+ public override void WriteJson(Newtonsoft.Json.JsonWriter writer, Error value, Newtonsoft.Json.JsonSerializer serializer)
+ {
+ writer.WriteStartObject();
+
+ if (value.CodeOption.IsSet && value.Code != null)
+ {
+ writer.WritePropertyName("code");
+ serializer.Serialize(writer, value.Code);
+ }
+ if (value.MessageOption.IsSet && value.Message != null)
+ {
+ writer.WritePropertyName("message");
+ serializer.Serialize(writer, value.Message);
+ }
+
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Kinde.Api/Accounts/Converters/GetEntitlementResponseDataEntitlementNewtonsoftConverter.cs b/Kinde.Api/Accounts/Converters/GetEntitlementResponseDataEntitlementNewtonsoftConverter.cs
new file mode 100644
index 0000000..31e4e16
--- /dev/null
+++ b/Kinde.Api/Accounts/Converters/GetEntitlementResponseDataEntitlementNewtonsoftConverter.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Kinde.Accounts.Model;
+using Kinde.Accounts.Client;
+
+namespace Kinde.Api.Accounts.Converters
+{
+ ///
+ /// Newtonsoft.Json converter for GetEntitlementResponseDataEntitlement that handles the Option<> structure
+ ///
+ public class GetEntitlementResponseDataEntitlementNewtonsoftConverter : Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanRead => true;
+ public override bool CanWrite => true;
+
+ public override GetEntitlementResponseDataEntitlement ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, GetEntitlementResponseDataEntitlement existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
+ {
+ if (reader.TokenType != Newtonsoft.Json.JsonToken.StartObject)
+ {
+ throw new Newtonsoft.Json.JsonException($"Expected StartObject, got {reader.TokenType}");
+ }
+
+ var jsonObject = JObject.Load(reader);
+
+ string? id = default(string?);
+ if (jsonObject["id"] != null)
+ {
+ id = jsonObject["id"].ToObject();
+ }
+ int? fixedCharge = default(int?);
+ if (jsonObject["fixed_charge"] != null)
+ {
+ fixedCharge = jsonObject["fixed_charge"].ToObject(serializer);
+ }
+ string? priceName = default(string?);
+ if (jsonObject["price_name"] != null)
+ {
+ priceName = jsonObject["price_name"].ToObject();
+ }
+ int? unitAmount = default(int?);
+ if (jsonObject["unit_amount"] != null)
+ {
+ unitAmount = jsonObject["unit_amount"].ToObject(serializer);
+ }
+ string? featureKey = default(string?);
+ if (jsonObject["feature_key"] != null)
+ {
+ featureKey = jsonObject["feature_key"].ToObject();
+ }
+ string? featureName = default(string?);
+ if (jsonObject["feature_name"] != null)
+ {
+ featureName = jsonObject["feature_name"].ToObject();
+ }
+ int? entitlementLimitMax = default(int?);
+ if (jsonObject["entitlement_limit_max"] != null)
+ {
+ entitlementLimitMax = jsonObject["entitlement_limit_max"].ToObject(serializer);
+ }
+ int? entitlementLimitMin = default(int?);
+ if (jsonObject["entitlement_limit_min"] != null)
+ {
+ entitlementLimitMin = jsonObject["entitlement_limit_min"].ToObject(serializer);
+ }
+
+ return new GetEntitlementResponseDataEntitlement(
+ id: id != null ? new Option(id) : default, fixedCharge: fixedCharge != null ? new Option(fixedCharge) : default, priceName: priceName != null ? new Option(priceName) : default, unitAmount: unitAmount != null ? new Option(unitAmount) : default, featureKey: featureKey != null ? new Option(featureKey) : default, featureName: featureName != null ? new Option(featureName) : default, entitlementLimitMax: entitlementLimitMax != null ? new Option(entitlementLimitMax) : default, entitlementLimitMin: entitlementLimitMin != null ? new Option(entitlementLimitMin) : default );
+ }
+
+ public override void WriteJson(Newtonsoft.Json.JsonWriter writer, GetEntitlementResponseDataEntitlement value, Newtonsoft.Json.JsonSerializer serializer)
+ {
+ writer.WriteStartObject();
+
+ if (value.IdOption.IsSet && value.Id != null)
+ {
+ writer.WritePropertyName("id");
+ serializer.Serialize(writer, value.Id);
+ }
+ if (value.FixedChargeOption.IsSet && value.FixedCharge != null)
+ {
+ writer.WritePropertyName("fixed_charge");
+ serializer.Serialize(writer, value.FixedCharge);
+ }
+ if (value.PriceNameOption.IsSet && value.PriceName != null)
+ {
+ writer.WritePropertyName("price_name");
+ serializer.Serialize(writer, value.PriceName);
+ }
+ if (value.UnitAmountOption.IsSet && value.UnitAmount != null)
+ {
+ writer.WritePropertyName("unit_amount");
+ serializer.Serialize(writer, value.UnitAmount);
+ }
+ if (value.FeatureKeyOption.IsSet && value.FeatureKey != null)
+ {
+ writer.WritePropertyName("feature_key");
+ serializer.Serialize(writer, value.FeatureKey);
+ }
+ if (value.FeatureNameOption.IsSet && value.FeatureName != null)
+ {
+ writer.WritePropertyName("feature_name");
+ serializer.Serialize(writer, value.FeatureName);
+ }
+ if (value.EntitlementLimitMaxOption.IsSet && value.EntitlementLimitMax != null)
+ {
+ writer.WritePropertyName("entitlement_limit_max");
+ serializer.Serialize(writer, value.EntitlementLimitMax);
+ }
+ if (value.EntitlementLimitMinOption.IsSet && value.EntitlementLimitMin != null)
+ {
+ writer.WritePropertyName("entitlement_limit_min");
+ serializer.Serialize(writer, value.EntitlementLimitMin);
+ }
+
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Kinde.Api/Accounts/Converters/GetEntitlementResponseDataNewtonsoftConverter.cs b/Kinde.Api/Accounts/Converters/GetEntitlementResponseDataNewtonsoftConverter.cs
new file mode 100644
index 0000000..1802130
--- /dev/null
+++ b/Kinde.Api/Accounts/Converters/GetEntitlementResponseDataNewtonsoftConverter.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Kinde.Accounts.Model;
+using Kinde.Accounts.Client;
+
+namespace Kinde.Api.Accounts.Converters
+{
+ ///
+ /// Newtonsoft.Json converter for GetEntitlementResponseData that handles the Option<> structure
+ ///
+ public class GetEntitlementResponseDataNewtonsoftConverter : Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanRead => true;
+ public override bool CanWrite => true;
+
+ public override GetEntitlementResponseData ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, GetEntitlementResponseData existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
+ {
+ if (reader.TokenType != Newtonsoft.Json.JsonToken.StartObject)
+ {
+ throw new Newtonsoft.Json.JsonException($"Expected StartObject, got {reader.TokenType}");
+ }
+
+ var jsonObject = JObject.Load(reader);
+
+ string? orgCode = default(string?);
+ if (jsonObject["org_code"] != null)
+ {
+ orgCode = jsonObject["org_code"].ToObject();
+ }
+ GetEntitlementResponseDataEntitlement? entitlement = default(GetEntitlementResponseDataEntitlement?);
+ if (jsonObject["entitlement"] != null)
+ {
+ entitlement = jsonObject["entitlement"].ToObject(serializer);
+ }
+
+ return new GetEntitlementResponseData(
+ orgCode: orgCode != null ? new Option(orgCode) : default, entitlement: entitlement != null ? new Option(entitlement) : default );
+ }
+
+ public override void WriteJson(Newtonsoft.Json.JsonWriter writer, GetEntitlementResponseData value, Newtonsoft.Json.JsonSerializer serializer)
+ {
+ writer.WriteStartObject();
+
+ if (value.OrgCodeOption.IsSet && value.OrgCode != null)
+ {
+ writer.WritePropertyName("org_code");
+ serializer.Serialize(writer, value.OrgCode);
+ }
+ if (value.EntitlementOption.IsSet && value.Entitlement != null)
+ {
+ writer.WritePropertyName("entitlement");
+ serializer.Serialize(writer, value.Entitlement);
+ }
+
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Kinde.Api/Accounts/Converters/GetEntitlementResponseNewtonsoftConverter.cs b/Kinde.Api/Accounts/Converters/GetEntitlementResponseNewtonsoftConverter.cs
new file mode 100644
index 0000000..4054bf4
--- /dev/null
+++ b/Kinde.Api/Accounts/Converters/GetEntitlementResponseNewtonsoftConverter.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Kinde.Accounts.Model;
+using Kinde.Accounts.Client;
+
+namespace Kinde.Api.Accounts.Converters
+{
+ ///
+ /// Newtonsoft.Json converter for GetEntitlementResponse that handles the Option<> structure
+ ///
+ public class GetEntitlementResponseNewtonsoftConverter : Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanRead => true;
+ public override bool CanWrite => true;
+
+ public override GetEntitlementResponse ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, GetEntitlementResponse existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
+ {
+ if (reader.TokenType != Newtonsoft.Json.JsonToken.StartObject)
+ {
+ throw new Newtonsoft.Json.JsonException($"Expected StartObject, got {reader.TokenType}");
+ }
+
+ var jsonObject = JObject.Load(reader);
+
+ GetEntitlementResponseData? data = default(GetEntitlementResponseData?);
+ if (jsonObject["data"] != null)
+ {
+ data = jsonObject["data"].ToObject(serializer);
+ }
+ Object? metadata = default(Object?);
+ if (jsonObject["metadata"] != null)
+ {
+ metadata = jsonObject["metadata"].ToObject