Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 0 additions & 53 deletions QuickbaseNet.Examples/Program.cs

This file was deleted.

14 changes: 0 additions & 14 deletions QuickbaseNet.Examples/QuickbaseNet.Examples.csproj

This file was deleted.

1 change: 1 addition & 0 deletions QuickbaseNet.UnitTests/QuickbaseNet.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AutoBogus" Version="2.13.1" />
<PackageReference Include="Bogus" Version="35.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="Moq" Version="4.20.70" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
using QuickbaseNet.Responses;
using QuickbaseNet.Services;
using QuickbaseNet.UnitTests.Mocks;
using QuickbaseNet.UnitTests.Utility;

namespace QuickbaseNet.UnitTests.QuickbaseClientTests;
namespace QuickbaseNet.UnitTests.Tests;

public class QuickbaseClientTests
{
Expand All @@ -22,11 +23,37 @@ public QuickbaseClientTests()
_client = CreateConfiguredQuickbaseClient();
}

[Fact]
public async Task Constructor_ThrowsArgumentNullException_WhenRealmIsNull()
{
// Arrange
var realm = string.Empty;

// Act
var exception = await Assert.ThrowsAsync<ArgumentNullException>(() => Task.FromResult(new QuickbaseClient(realm, TestToken)));

// Assert
Assert.Equal("realm", exception.ParamName);
}

[Fact]
public async Task Constructor_ThrowsArgumentNullException_WhenTokenIsNull()
{
// Arrange
var token = string.Empty;

// Act
var exception = await Assert.ThrowsAsync<ArgumentNullException>(() => Task.FromResult(new QuickbaseClient(TestRealm, token)));

// Assert
Assert.Equal("userToken", exception.ParamName);
}

[Fact]
public async Task QueryRecords_ReturnsSuccessResponse_WhenCalled()
{
// Arrange
var request = new QuickbaseQueryRequest();
var request = new Builder().Build<QuickbaseQueryRequest>();

// Act
var response = await _client.QueryRecords(request);
Expand All @@ -40,7 +67,7 @@ public async Task QueryRecords_ReturnsSuccessResponse_WhenCalled()
}

[Fact]
public async Task QueryRecords_ReturnsErrorResponse_WhenBadRequestOccurs()
public async Task QueryRecords_ReturnsErrorResponse_When4xxOccurs()
{
// Arrange
SetupMockHandlerWithErrorResponse();
Expand All @@ -54,6 +81,27 @@ public async Task QueryRecords_ReturnsErrorResponse_WhenBadRequestOccurs()
// Act
var actualResponse = await _client.QueryRecords(request);

// Assert
Assert.False(actualResponse.IsSuccess);
Assert.True(actualResponse.IsFailure);
Assert.NotNull(actualResponse.QuickbaseError);
}

[Fact]
public async Task QueryRecords_ReturnsErrorResponse_When5xxOccurs()
{
// Arrange
_mockHandler.ResponseStatusCode = HttpStatusCode.InternalServerError;
var request = new QuickbaseQueryRequest
{
From = "tableId",
Where = "{1.CT.'query'}",
Select = [1, 2, 3]
};

// Act
var actualResponse = await _client.QueryRecords(request);

// Assert
Assert.False(actualResponse.IsSuccess);
Assert.NotNull(actualResponse.QuickbaseError);
Expand Down
37 changes: 37 additions & 0 deletions QuickbaseNet.UnitTests/Tests/QuickbaseResultTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using QuickbaseNet.Errors;

namespace QuickbaseNet.UnitTests.Tests;

public class QuickbaseResultTests
{
[Fact]
public void Constructor_ThrowsArgumentException_WhenInvalidErrorForSuccess()
{
// Arrange
var isSuccess = true;
var invalidError = QuickbaseError.ClientError("InvalidError", "Invalid error occurred", "Description");

// Act & Assert
Assert.Throws<ArgumentException>(() => new TestableQuickbaseResult(isSuccess, invalidError));
}

[Fact]
public void Constructor_ThrowsArgumentException_WhenInvalidErrorForFailure()
{
// Arrange
var isSuccess = false;
var invalidError = QuickbaseError.None;

// Act & Assert
Assert.Throws<ArgumentException>(() => new TestableQuickbaseResult(isSuccess, invalidError));
}
}

internal class TestableQuickbaseResult : QuickbaseResult
{
public TestableQuickbaseResult(bool isSuccess, QuickbaseError quickbaseError)
: base(isSuccess, quickbaseError)
{
// This constructor allows access to the protected internal constructor of QuickbaseResult
}
}
130 changes: 130 additions & 0 deletions QuickbaseNet.UnitTests/Utility/Builder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
namespace QuickbaseNet.UnitTests.Utility;

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;

using AutoBogus;

using Bogus;

[ExcludeFromCodeCoverage]
public class Builder
{
public T Build<T>() where T : class
{
var binder = new AutoBinder();

Faker<T> model = new AutoFaker<T>(binder)
.RuleForType(typeof(uint), rule => rule.Random.UInt(1, int.MaxValue))
.RuleForType(typeof(uint?), rule => (uint?)rule.Random.UInt(1, int.MaxValue))
.RuleForType(typeof(int), rule => rule.Random.Int())
.RuleForType(typeof(int?), rule => (int?)rule.Random.Int())
.RuleForType(typeof(DateTime), rule =>
{
DateTime date = rule.Date.Recent();
return new DateTime(
date.Year,
date.Month,
date.Day
);
})
.RuleForType(typeof(DateTime?), rule =>
{
DateTime date = rule.Date.Recent();
return (DateTime?)new DateTime(
date.Year,
date.Month,
date.Day
);
})
.RuleForType(typeof(DateTimeOffset?), rule =>
{
DateTimeOffset date = rule.Date.Recent();
return (DateTimeOffset?)new DateTime(
date.Year,
date.Month,
date.Day
);
})
.RuleForType(typeof(byte), rule => rule.Random.Byte())
.RuleForType(typeof(byte?), rule => (byte?)rule.Random.Byte())
.RuleForType(typeof(sbyte), rule => rule.Random.SByte())
.RuleForType(typeof(string), rule => rule.Random.AlphaNumeric(10))
.RuleForType(typeof(decimal), rule => rule.Finance.Amount(min: 0.01M, max: 99999.99M, decimals: 2))
.RuleForType(typeof(decimal?), rule => (decimal?)rule.Finance.Amount(min: 0.01M, max: 99999.99M, decimals: 2))
.RuleForType(typeof(ushort), rule => rule.Random.UShort())
.RuleForType(typeof(short), rule => rule.Random.Short())
.RuleForType(typeof(long), rule => rule.Random.Long())
.RuleForType(typeof(ulong), rule => rule.Random.ULong())
.RuleForType(typeof(bool), rule => rule.Random.Bool())
.RuleForType(typeof(bool?), rule => (bool?)rule.Random.Bool());

model = AddEnumRules(model, binder);

//int seed = DateTime.UtcNow.Millisecond;
//return model.UseSeed(seed).Generate();
return model.Generate();
}

/// <summary>
/// Adds the ability to generate random valid enum values
/// </summary>
/// <remarks>
/// Bogus currently doesn't appear to have a way to create rules for types that aren't well known at compile time. To generate random values for enum properties
/// we have to find properties on <typeparamref name="T"/> that are enum and get a list of valid values for that enum and pick one of those randomly.
///
/// Bogus appears to do similar things when creating rules for well known types too, so this is at least similar.
///
/// This also excludes enum members whose name is "None" when it is the first member of the enum as that is usually not a valid value.
/// This follows the convention for other nubmer types not generating zeroes
/// </remarks>
private Faker<T> AddEnumRules<T>(Faker<T> faker, IBinder binder) where T : class
{
// find enum properties using the binder
IEnumerable<PropertyInfo> enumProperties = binder.GetMembers(typeof(T))
.Select(item => item.Value)
.OfType<PropertyInfo>()
.Where(item => item.PropertyType.IsEnum);

Faker<T> result = faker;
if (enumProperties.Any())
{
result = result.FinishWith((fk, target) =>
{
foreach (PropertyInfo enumProperty in enumProperties)
{
// None = 0 is typically not a valid value, so for the sake of generating sane values it will be skipped
var minIndex = 0;
string[] enumNames = Enum.GetNames(enumProperty.PropertyType);
if (enumNames[0].ToLower() == "none")
{
minIndex = 1;
}

Array enumValues = Enum.GetValues(enumProperty.PropertyType);
var randomIndex = fk.Random.Int(minIndex, enumValues.Length - 1);
object randomEnumValue = enumValues.GetValue(randomIndex);

enumProperty.SetValue(target, randomEnumValue);
}
});
}

return result;
}

public IEnumerable<T> Build<T>(int howMany) where T : class
{
var models = new List<T>();
for (int i = 0; i < howMany; i++)
{
T model = Build<T>();
models.Add(model);
}

return models;
}
}
8 changes: 1 addition & 7 deletions QuickbaseNet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ VisualStudioVersion = 17.8.34322.80
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuickbaseNet", "QuickbaseNet\QuickbaseNet.csproj", "{375B33E5-C837-4915-844C-52057055E84C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuickbaseNet.Examples", "QuickbaseNet.Examples\QuickbaseNet.Examples.csproj", "{F92A2FF7-450E-4672-8781-BC648ACE2ACF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickbaseNet.UnitTests", "QuickbaseNet.UnitTests\QuickbaseNet.UnitTests.csproj", "{E2654CA5-971C-43D0-912E-D4445F1EB4B0}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuickbaseNet.UnitTests", "QuickbaseNet.UnitTests\QuickbaseNet.UnitTests.csproj", "{E2654CA5-971C-43D0-912E-D4445F1EB4B0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -19,10 +17,6 @@ Global
{375B33E5-C837-4915-844C-52057055E84C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{375B33E5-C837-4915-844C-52057055E84C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{375B33E5-C837-4915-844C-52057055E84C}.Release|Any CPU.Build.0 = Release|Any CPU
{F92A2FF7-450E-4672-8781-BC648ACE2ACF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F92A2FF7-450E-4672-8781-BC648ACE2ACF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F92A2FF7-450E-4672-8781-BC648ACE2ACF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F92A2FF7-450E-4672-8781-BC648ACE2ACF}.Release|Any CPU.Build.0 = Release|Any CPU
{E2654CA5-971C-43D0-912E-D4445F1EB4B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2654CA5-971C-43D0-912E-D4445F1EB4B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2654CA5-971C-43D0-912E-D4445F1EB4B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down
Loading