2using System.Collections.Generic;
3using System.Diagnostics;
5using System.Linq.Expressions;
7using System.Reflection;
16using Microsoft.VisualStudio.TestTools.UnitTesting;
21using TestCategory =
NUnit.Framework.CategoryAttribute;
30 private const string TypeName =
"BaseResourceTest";
58 #region Inherited Test Methods
75 #region Collection GET Methods
82 Console.WriteLine(
$"{typeof(T).NiceTypeName()} Collection Name: {typeCollectionName}");
85 "The instance returned a different collection name than what it's type resolves.");
98 $"resource with the id {posted.id}. Found {searchResult.meta.total_count}");
102 #endregion Collection GET Methods
115 Assert.Inconclusive(
"RUN_OFFLINE = true");
118 Assert.AreEqual(1,
response.Count,
"Expected only one key in the response (the id).");
119 Assert.IsTrue(
response.ContainsKey(
"id"),
"Expected the id in the response.");
151 if (copy is IStoredAPIResource)
152 Assert.AreNotEqual(existingId, copy.id,
"The copied resource belongs to a " +
153 $
"collection of persisted resources ({copy.collection_name}) - expected " +
154 "POST to return a copy with a new id, but the id returned is identical.");
157 Assert.AreEqual(existingId, copy.id,
"The copied resource belongs to a " +
158 $
"collection of transient resources ({copy.collection_name}) - expected " +
159 "POST to return the existing resource, but the id returned is different.");
164 #region POST Test Helpers
199 throw new ArgumentException(
"Can only be used on properties whose default type is null.");
218 #region List Attribute Test Helpers
258 #endregion List Attribute Test Helpers
260 #region Reference Attribute Test Helpers
304 #endregion Reference Attribute Test Helpers
305 #endregion POST Test Method Helpers
313 Assert.Inconclusive(
"RUN_OFFLINE = true");
322 Assert.Inconclusive(
"RUN_OFFLINE = true");
338 "Subsequent GET after a successful DELETE of the " +
339 $"{typeof(T).NiceTypeName()} returned the wrong type of error:\n{e}"));
344 #region Utilities and Extension Methods
365 Console.WriteLine(
$"The following resource will be deep copied:\n{TestResource.Serialize(true)}");
390 Console.WriteLine(
$"{type.NiceTypeName()} User-Facing Properties:\n " +
392 $"{p.PropertyType.NiceTypeName()} {p.DeclaringType.NiceTypeName()}.{p.Name} " +
393 (p.CanRead ?
"{get;} " :
"") + (p.CanWrite ?
"{set;} " :
""))));
397 "One or more property names are duplicated in the list of user-facing properties.");
408 [
TestMethod, TestCategory(TypeName), TestCategory(
"Randomized")]
435 [
TestMethod, TestCategory(TypeName), TestCategory(
"Randomized")]
452 [
TestMethod, TestCategory(TypeName), TestCategory(
"Randomized")]
465 "ChangePropertyValueRandomly succeeded, but the value was not changed.");
481 if (
ex.Message.Contains(
"new value generated is equal to the original value"))
487 #region Helper Methods
502 TestSubResourceEndpoints(
copy);
511 private static void TestSubResourceEndpoints(
object owner)
518 $"The {endpoint.GetType().NiceTypeName()} endpoint \"{subResourceProperty.Name}\" " +
519 "is still referencing the old copied resource instead of the new one.");
524 #endregion Helper Methods
525 #endregion Utilities and Extension Methods
526 #endregion Inherited Test Methods
static Reflection Reflection
Shared instance of a class for generating random resources.
void POST_StringAttribute_Empty(Expression< Func< T, string > > PropertyExpression, bool? shouldSucceed=null)
Post a resource with the specified string set to an empty string.
virtual void Test_Resource_POST_FieldsIdOnly()
Test that a user can post a resource and get back only the id using the omit query parameter.
virtual void Test_Resource_TypeReflectionUtilities()
Test reflection utilities meant to get extract information about runtime types.
virtual void Test_Resource_DELETE_NonExistant()
virtual T TestResource_Existing
The resource used for all unit tests that require a prepared and already posted resource....
IInjectableResource< T > TestInjectableResource
Deriving class must override the TestResourceFactory to return a disposable POSTable test resource th...
virtual void Test_Resource_GetCollectionName()
Verify that all runtime types expose their collection name.
bool TryPost_RandomTestResources
Allows deriving classes to disable attempting to POST and validate random resources generated by the ...
void POST_ListAttribute_Duplicates< TItem, TValue >(Expression< Func< T, ICollection< TItem > > > PropertyExpression, TValue valueToDuplicate, bool shouldSucceed)
virtual void Test_Resource_GET_Existing()
virtual void POST_WithValue< TProperty >(Expression< Func< T, TProperty > > PropertyExpression, TProperty newValue, bool shouldSucceed)
Modify a property of the test resource, and then test it.
virtual void Test_Resource_OfflineRandomGeneration()
Test reflection utilities meant to randomly change property values (used for testing comprarer covera...
bool TryRunAdditionalValidResourceTests_RandomTestResources
Similar to TryPost_RandomTestResources - but controls whether these resources have the AdditionalVali...
virtual void Test_Reflection_ChangePropertyValueRandomly()
Test reflection utilities meant to randomly change property values in a way that would pass server va...
static void TestCopyHelper< TCopy >(TCopy original, Func< TCopy, TCopy > copyAction)
virtual void Test_Resource_ShallowCopy()
Test that any resource can be "Shallow Copied", which is a quick copy that does a member-wise clone o...
virtual void Test_Resource_GET_FromBatch()
Test that resources of this type can be retrieved using the collection batch-get feature.
virtual void Test_Resource_DELETE()
void POST_Reference_NonExistantId< TRefType >(Expression< Func< T, IReference< TRefType > > > PropertyExpression)
Posts a reference with a non-existent Id and verifies the correct error is returned.
virtual void Test_Resource_DeepCopy()
Test that any resource can be "Deep Copied", a slower copy method that creates a new duplicate instan...
void POST_ListAttribute_Empty< TItem >(Expression< Func< T, ICollection< TItem > > > PropertyExpression, bool? shouldSucceed=null)
void POST_Attribute_Null< TProperty >(Expression< Func< T, TProperty > > PropertyExpression, bool? shouldSucceed=null)
Post a resource with the specified property set to null.
virtual void Test_Resource_POST_ExistingId()
Verifies that it is okay to post an object with an ID that already exists on the server,...
virtual void Test_Resource_POST_Valid()
virtual void Test_Resource_POST_Id_Ignored()
No matter what string we set the Id property to, POST should succeed because the Id of the posted res...
void POST_Reference_NullId< TRefType >(Expression< Func< T, IReference< TRefType > > > PropertyExpression)
Posts a reference with a null Id and verifies the correct error is returned.
virtual void AdditionalValidResourceTests(T posted)
Deriving classes can optionally override this function to perform additional validation on every succ...
virtual void Test_Resource_GET_AllPropertiesRecognized()
virtual bool DELETE_Allowed
void POST_ReferenceList_NonExistantId< TRefType >(Expression< Func< T, ICollection< IReference< TRefType > > > > PropertyExpression)
Posts a reference list with a non-existent Id and verifies the correct error is returned.
static ICollection< TCollectionItem > NewCollection< TTarget, TCollectionItem >(Expression< Func< TTarget, ICollection< TCollectionItem > > > propertyExpression, IEnumerable< TCollectionItem > initialItems=null)
Helper method to create a new collection instance based on the type of the referenced property expres...
virtual T TestResource
The resource used for all unit tests that require a valid prepared but unPOSTed resource.
virtual void POST_ThenDoAction(T validToPost, Action< T > toExecute)
Post a valid resource under the assumption that it will succeed, then perform an action on the result...
void TestResourceDeleteHelper(T toDelete, bool isDeleteAllowed)
virtual void Test_Resource_OnlineRandomGeneration()
Test reflection utilities meant to randomly change property values in a way that would pass server va...
void POST_Reference_EmptyStringId< TRefType >(Expression< Func< T, IReference< TRefType > > > PropertyExpression)
Posts a reference with a empty string Id and verifies the correct error is returned.
Create a test class that takes care of setting the server URL and cleaning up after each unit test.
Exposes sample resource objects, with built-in methods for injecting dependencies.
static string Valid_NonExistant_UUID
static void MethodIsAllowed(Action request, string methodName, bool methodAllowed=true)
Wrap a request in a tryGet with some formatting for testing purposes.
static void IsValidUUID(string toCheck)
Assert that the string is a valid UUID.
static Action< APIRequestException > ApiExceptionTest(HttpStatusCode expectedStatusCode)
Generate a function that will test a REST request exception in a standard way.
Retrieve settings from environment variables if they exist, or the project settings file otherwise.
static bool RUN_OFFLINE
Controls whether tests that normally require a connection to the server should be allowed to try to r...
Generic Unit test implementations that will test REST methods on arbitrary resources.
An exception throw when a random generation routine fails to produce a POSTable resource.
A collection of filthy hacks to populate some fields of APIResources objects of any type.
object ChangePropertyValueRandomly(IAPIType obj, PropertyInfo prop, int max_attempts=Max_ReRandomize_Attempts, RecursionContext parentRecursionInfo=null)
Randomly change the specified property to some different value.
object CreateRandomizedInstance(Type desiredType, RecursionContext parentRecursionInfo=null)
Generates a new randomized object of the specified type.
A custom exception class that includes the RestSharp.IRestResponse that generated the exception,...
Describes a collection of resources which can be listed.
Describes an additional sub-resource available off a resource which is not actually a property of tha...
Parameters that can be added to your REST requests to access additional API features.
static RequestParameters Fields(IEnumerable< string > fieldNames)
Can be added to your GET requests to return only the specified fields in the response body....
API methods / requests made available to the user.
static string GetCollectionName(Type requestType)
Gets the collection name for the given APIResource type, whether it's instantiable or not.
static ICollectionResponse< IAPIResource > BatchGet(Type resourceType, IEnumerable< string > ids, IEnumerable< Parameter > requestParameters=null, string collectionNameOverride=null, int? timeout=null)
Get a collection of resources from the server that match the set of resource ids specified.
Specifies that the enumerable property with this attribute cannot be empty when POSTing the resource ...
Specifies that the property with this attribute cannot be null when POSTing the resource to the serve...
Indicates that while the current APIResource-derived class can be constructed and potentially inlined...
Specifies that a property is generated by the server and should not be specified on the client side d...
Utilities that reflect on a type or property expression.
T Unposted
The unPOSTed resource definition.
T Posted
The posted resource, ready to be referenced.
Interface for Base class used by all resources.
string id
The resource's unique identifier. It will be used in the request URL when requesting the resource fro...