C# Client Library
A C# Client Library for the AnalyzeRe REST API
Loading...
Searching...
No Matches
AssertApi.cs
Go to the documentation of this file.
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Diagnostics;
5using System.Linq;
6using System.Net;
7using System.Reflection;
8
9using AnalyzeRe;
14
15using RestSharp;
16#if MSTEST
17using Microsoft.VisualStudio.TestTools.UnitTesting;
18#elif NUNIT
19using NUnit.Framework;
20using AssertFailedException = NUnit.Framework.AssertionException;
21#endif
22
24{
25 public static class AssertApi
26 {
27 public const double DEFAULT_DOUBLE_EQUIVALENCE_TOLERANCE = 1E-14;
28
35 public static bool TryFindException<T>(Exception ex, out T foundException) where T : Exception
36 {
37 do
38 {
40 if (foundException != null) return true;
41 ex = ex.InnerException;
42 } while (ex != null);
43
44 return false;
45 }
46
51 public static void LogExceptionDetails(Exception ex)
52 {
54 apiError.RestResponse is IRestResponse response)
55 Console.WriteLine("Error response from the URL: " +
56 (response.ResponseUri?.ToString() ?? response.Request.Resource) +
57 $"\n{response.Request.PrettyPrint()}\n{response.PrettyPrint()}");
58 else
59 Console.WriteLine($"Unexpected exception: \"{ex.Message}\". Details:\n{ex}");
60 }
61
69 where T : Exception
70 {
71 try
72 {
73 action.Invoke();
74 }
75 catch (T e)
76 {
77 Console.WriteLine($"Assert ExceptionThrown<{typeof(T).NiceTypeName()}> " +
78 $"Successfully caught an exception of the expected type. Details:\n{e}");
79 exceptionTest?.Invoke(e);
80 return;
81 }
82 catch (Exception e)
83 {
85 Assert.Fail("Exception of the wrong type was thrown. " +
86 $"Expected type {typeof(T).NiceTypeName()}, " +
87 $"but received {e.GetType().NiceTypeName()}.");
88 }
89 Assert.Fail("The action ran without raising an exception. " +
90 $"Expected: {typeof(T).NiceTypeName()} to be thrown.");
91 }
92
98 public static void MethodIsAllowed(Action request, string methodName, bool methodAllowed = true)
99 {
100 try
101 {
102 request();
103 }
104 catch (APIRequestException e)
105 {
106 if (e.RestResponse?.StatusCode == HttpStatusCode.MethodNotAllowed)
107 {
108 Debug.WriteLine($"{(methodAllowed ? "Test Failed" : "Test Passed")}: " +
109 $"{methodName} method is not allowed.");
110 Assert.IsFalse(methodAllowed, $"{methodName} method is not allowed (Returned 405), " +
111 $"but it should be for this test to pass.\nDetails:\n{e}");
112 return;
113 }
114 // Any other APIRequestException is unexpected and should be logged in detail.
116 Assert.Fail($"{methodName} method failed" + (methodAllowed ? ". Expected Success" :
117 " for an unexpected reason. Expected 405 - MethodNotAllowed") +
118 $", Received status: {e.RestResponse?.StatusCode.ToString() ?? "(No Response)"}, " +
119 $"and error message: {e.Message}\nDetails:\n{e}");
120 }
121 Assert.IsTrue(methodAllowed, $"{methodName} is allowed, " +
122 "but should not be for this test to pass. (Expected 405 - MethodNotAllowed)");
123 }
124
130 {
131 try
132 {
133 AllPropertiesEqual_Helper(typeof(T), objExpected, objActual, objExpected);
134 }
135 catch
136 {
137 // Before allowing the test failure to bubble up, serialize both objects.
138 Console.WriteLine("\nOne or more sub-properties of these two resources were not equal:" +
139 $"\nExpected: {objExpected.Serialize()}" +
140 $"\n Actual: {objActual.Serialize()}");
141 throw;
142 }
143 }
144
151 {
152 try
153 {
154 AllPropertiesEqual_Helper(typeof(T), objPosted, objReturned, objPosted, isPOST: true);
155 }
156 catch
157 {
158 // Before allowing the test failure to bubble up, serialize both objects.
159 Console.WriteLine("\nOne or more sub-properties of the POST response did not match:" +
160 $"\nPOST Body: {objPosted.Serialize()}" +
161 $"\n Response: {objReturned.Serialize()}");
162 throw;
163 }
164 }
165
173 {
174 try
175 {
176 AllPropertiesEqual_Helper(typeof(T), objPut, objReturned, original, isPUT: true);
177 }
178 catch
179 {
180 // Before allowing the test failure to bubble up, serialize all objects involved
181 Console.WriteLine("\nOne or more sub-properties of the PUT response did not match expectations:" +
182 $"\nOriginal: {original.Serialize()}" +
183 $"\nPUT Body: {objPut.Serialize()}" +
184 $"\n Result: {objReturned.Serialize()}");
185 throw;
186 }
187 }
188
190 private static void AllPropertiesEqual_Helper(Type runtimeType,
191 object fromClient, object fromServer, object originalObject,
192 string propertyName = null, HashSet<object> stack = null,
193 bool isPOST = false, bool isPUT = false)
194 {
195 if (fromClient == null && fromServer == null)
196 return;
197 // Fill in default values
198 if (propertyName == null)
199 propertyName = runtimeType.NiceTypeName();
200 // Keep track of all objects recursed on, to avoid recursing on circular references.
201 if (stack == null)
203 else if (stack.Contains(fromClient))
204 return;
205 else
207
208 Assert.IsNotNull(fromClient, $"The expected \"{propertyName}\" attribute value is null, " +
209 $"but the result was not null, it was: {Output.AutoFormat(fromServer)}");
210 Assert.IsNotNull(fromServer, $"The resulting \"{propertyName}\" attribute value was null, " +
211 $"but it was expected to have the following value: {Output.AutoFormat(fromClient)}");
212
213 // Determine the common property type
214 Type sharedType = runtimeType;
215 Type clientType = fromClient.GetType();
216 Type serverType = fromServer.GetType();
217 // Find the most strongly typed instance and treat that as the shared type
218 if (clientType == serverType || serverType.IsInstanceOfType(fromClient))
220 else if (clientType.IsInstanceOfType(fromServer))
222 // Special case, Newtonsoft Deserializer returns all numeric types as Int64
223 else if (clientType.IsIntegerType() && fromServer is long)
224 {
226 fromServer = Convert.ChangeType((long)fromServer, clientType);
227 Assert.IsNotNull(fromServer,
228 $"The value {fromServer} could not be converted to the type {clientType}.");
229 }
230 // Raise an error if both objects aren't an instance of the shared type
231 if (!(sharedType.IsInstanceOfType(fromClient) && sharedType.IsInstanceOfType(fromServer)))
232 {
233 Assert.Fail("The objects being compared are of fundamentally different types: " +
234 $"objPosted is a {clientType.NiceTypeName()}, " +
235 $"objReturned is a {fromServer.GetType().NiceTypeName()}. " +
236 $"Expected type is {sharedType.NiceTypeName()}");
237 }
238
239 // Comparing doubles
241 {
242 DoublesAreEqual((double)fromClient, (double)fromServer,
243 () => GetNoValueMatchErrorMessage(propertyName, fromClient, fromServer));
244 }
245 // Comparing dates
247 {
251 }
252 // Comparing other simple types (int, string, bool, enum, etc)
253 else if (sharedType == typeof(string) || sharedType.IsPrimitive || sharedType.IsEnum)
254 {
255 if (!Equals(fromClient, fromServer))
256 Assert.Fail(GetNoValueMatchErrorMessage(propertyName, fromClient, fromServer));
257 }
258 // Comparing Reference Objects
260 {
261 // Assert that at the very least, the reference type returned is compatible with that POSTED
262 if (isPOST)
263 {
264 Assert.IsTrue(fromServer.GetType().GetGenericArguments()[0].IsAssignableFrom(
265 clientType.GetGenericArguments()[0]),
266 $"{propertyName} reference types do not match. " +
267 $"Expected: \"{clientType.NiceTypeName()}\", " +
268 $"Actual: \"{fromServer.GetType().NiceTypeName()}\".");
269 }
270
271 // If comparing two inlined references to objects, compare just the object definitions.
274 {
275 AllPropertiesEqual_Helper(typeof(IAPIResource),
276 refPosted.GetValue(), refReturned.GetValue(), originalObject, $"{propertyName} inlined reference", stack, isPOST, isPUT);
277 }
278 // Otherwise, just use the reference equality test
279 else
280 {
281 Assert.AreEqual(fromClient, fromServer,
282 $"{propertyName} reference objects do not match: " +
283 $"Expected: {(IReference)fromClient}, " +
284 $"Actual: {(IReference)fromServer}");
285 }
286 }
287 // Comparing collection types
289 {
292 // Testing if collections are the same size.
293 Assert.AreEqual(expectedCollection.Count, returnedCollection.Count,
294 $"{propertyName} collections do not contain the same number of elements. " +
295 $"Expected: \"{expectedCollection.Count}\", " +
296 $"Actual: \"{returnedCollection.Count}\".");
298 // Test that the resulting collection contains all the same objects
299 // (but not necessarily in the same order)
300 // TODO: Define an attribute which indicates whether collection order is maintained.
301 int expectedIndex = -1;
302 bool outOfOrder = false;
303 foreach (object expectedElement in expectedCollection)
304 {
306 bool matchFound = FindCollectionElement(element => AllPropertiesEqual_Helper(
307 collectionItemsSharedType, expectedElement, element, originalObject, $"{propertyName}[{expectedIndex}]", stack, isPOST, isPUT),
310 outOfOrder = true;
311 if (matchFound)
312 continue;
313 // If no match was found, build a meaningful error message
314 Assert.Fail(GetNoValueMatchErrorMessage(propertyName, fromClient, fromServer) +
315 $"\nSpecifically - collection element number {expectedIndex} had no matching " +
316 "element in the resulting collection. Results from each comparison attempt:\n " +
317 String.Join("\n ", errors.Select(ex => ex.Message.Replace("\n", "\n "))));
318 }
319 if(outOfOrder)
320 Debug.WriteLine($"All \"{propertyName}\" collection elements were found, " +
321 "but they appeared in a different order than what was originally posted.");
322 }
323 // Other Analyze Re custom types, try comparing all readable sub-properties for equivalence
325 {
326 int subPropertiesCompared = 0;
327 foreach (PropertyInfo property in sharedType.GetUserFacingProperties(
328 // Ignore server generated properties (like id),
329 // since they change at the server's discretion.
331 {
333 object propExpected, propActual;
334 try
335 {
336 propExpected = property.GetValue(fromClient);
337 propActual = property.GetValue(fromServer);
338 }
339 catch (Exception ex)
340 {
341 Console.WriteLine("Fatal error encountered while getting the property from " +
342 $"one or both {sharedType.NiceTypeName()} resources being compared. " +
343 $"Property was: {property.PropertyType.NiceTypeName()} " +
344 $"{property.DeclaringType.NiceTypeName()}.{property.Name} \nError was: {ex}");
345 throw;
346 }
347
348 // Indicates whether the "expected" value has been changed from what was submitted
349 // to the server to some different expected value based on defaults/server behaviour.
350 bool expectedValueSet = false;
351
352 // When PUTing a resource, the server will not change top-level properties
353 // if they are omitted from the PUT body.
354 // BUG ARE-2618 - These PUT expectation are violated almost all the time.
355 // The most common behaviour is that the property is "reset" to its default.
356 //if (isPUT && propExpected == null)
357 //{
358 // // Only applies if we are checking top-level properties
359 // if (fromClient is IAPIResource asResource &&
360 // originalObject is IAPIResource originalResource &&
361 // asResource.id != null && asResource.id == originalResource.id &&
362 // // EXCEPT if the NullValueHanlding JsonProperty is set to "Include" nulls,
363 // // in which case the server will actually override the original value with 'null'
364 // !(property.GetCustomAttributeFast<JsonPropertyAttribute>() is
365 // JsonPropertyAttribute jsonProperty &&
366 // jsonProperty.NullValueHandling == NullValueHandling.Include))
367 // {
368 // propExpected = property.GetValue(originalResource);
369 // expectedValueSet = true;
370 // }
371 //}
372 // When POSTing, the server may have a default value for
373 // certain properties when set to null. Check for that here.
374 if ((isPOST || isPUT) && property.IsAttributeDefinedFast<ServerHasDefault>() &&
375 // else if (isPOST && property.IsAttributeDefinedFast<ServerHasDefault>() &&
376 (propExpected == null ||
377 // Yet another special case - the portfolio_view.layer_views property
378 // will be defaulted if it is null *or an empty list* due to special logic
379 // coded into "AnalyzeRe.JsonConverters.PortfolioViewSerializer"
380 Reflection.IsProperty<PortfolioView>(property, pv => pv.layer_views) &&
382 {
383 ServerHasDefault defaultAttribute = property.GetCustomAttributeFast<ServerHasDefault>();
384 if (defaultAttribute.HasDefaultValue(fromClient))
385 propExpected = defaultAttribute.GetDefaultValue(fromClient);
386 else
387 {
388 // If the attribute doesn't specify an expected default, we just have to trust
389 // that whatever the server has returned is the correct default value,
390 // whether it's null or otherwise.
391 Console.WriteLine("Warning: The server is known to provide a default value " +
392 $"when \"{property.Name}\" is set to null, but the defaulted value returned " +
393 $"({propActual ?? "null"}) could not be verified. Assuming it is valid.");
395 }
396 expectedValueSet = true;
397 }
398 // The server may convert some references to inlined objects. Handle these special cases.
400 {
401 // The API will inline any layer references appearing as part of a nested layer definition.
402 // We can verify this by resolving the reference and setting the propExpected value.
404 reference.DeepCopy().GetValue().Change(r => r.id, null).ToReference(true);
405
406 // Note: As of ARE-5975 we can encounter non-layer references, but only
407 // layer references are expected to be converted to inlined layers.
408 if(property.PropertyType == typeof(Nested.Sources))
411 else if (property.PropertyType == typeof(IReference<ILayerSource>) &&
414 }
415
416 // Assert the resulting objects' value for this property matches the expected value
417 // Set POST_Comparison_Mode to false since only root level objects
418 AllPropertiesEqual_Helper(property.PropertyType, propExpected, propActual, originalObject, $"{propertyName}.{property.Name}", stack, isPOST && !expectedValueSet, isPUT && !expectedValueSet);
419 }
420 // If the above reflection method found no readable sub-properties to compare, then we must
421 // rely on the objects own equivalency test.
422 if (subPropertiesCompared == 0)
423 {
424 Assert.AreEqual(fromClient, fromServer,
425 GetNoValueMatchErrorMessage(propertyName, fromClient, fromServer));
426 }
427 }
428 // We probably don't even need to compare SubResourceEndpoint instances, since they
429 // are "defined" properties, not mutable attributes. Still, we can test that
430 // SubResourceEndpoint objects are equivalent if they share the same path.
432 {
433 // Note that we cannot compare paths if the original object was a resource without an id.
434 if (isPOST || originalObject is IAPIResource resource && resource.id == null) return;
435 Assert.AreEqual(((IEndpoint)fromClient).Path, ((IEndpoint)fromServer).Path);
436 }
437 // Comparing dictionary elements
438 else if (sharedType.IsSubclassOfRawGeneric(typeof(KeyValuePair<,>)))
439 {
440 AllPropertiesEqual_Helper(sharedType.GetGenericArguments()[0],
441 fromClient.GetType().GetProperty("Key").GetValue(fromClient),
442 fromServer.GetType().GetProperty("Key").GetValue(fromServer), originalObject, $"{sharedType.NiceTypeName()}.Key", stack, isPOST, isPUT);
443 AllPropertiesEqual_Helper(sharedType.GetGenericArguments()[1],
444 fromClient.GetType().GetProperty("Value").GetValue(fromClient),
445 fromServer.GetType().GetProperty("Value").GetValue(fromServer), originalObject, $"{sharedType.NiceTypeName()}.Value", stack, isPOST, isPUT);
446 }
447 // Any other types can't safely be compared.
448 // Fail if the standard equals method doesn't consider the two objects equivalent.
449 else if(!fromClient.Equals(fromServer))
450 {
451 Assert.Fail("This routine doesn't know how to compare the following two objects:\n" +
452 $"Expected: {fromClient.GetType().NiceTypeName()} \"{fromClient}\"\n" +
453 $"Actual: {fromServer.GetType().NiceTypeName()} \"{fromServer}\"");
454 }
455 }
456
459 private static bool FindCollectionElement(Action<object> elementTest, int expectedIndex,
461 {
462#if NUNIT
463 // NUnit does not allow assertion failures to be suppressed via try/catch,
464 // they must be suppressed by creating and discarding an isolated test context.
465 // TODO: Refactor the AllPropertiesEqual_Helper to not use assertions, so that the caller
466 // can decide whether to handle differences with a failed assertion or not.
467 using (new NUnit.Framework.Internal.TestExecutionContext.IsolatedContext())
468#endif
469 {
470 foundIndex = -1;
471 errors = new List<Exception>();
472 // 1. Assume order was maintained: Compare the current enumerable element
473 // to the element at the same index in the returned collection
474 try
475 {
478 return true; // Found the matching element
479 }
480 catch (Exception ex)
481 {
482 // If there is only one element in each collection, the above test should have passed
483 // Otherwise, if this collection element isn't a match, it's possible the server has just
484 // changed the order. See if any element in the collection matches it.
485 // TODO: Also fail here given some attribute that specifies that the collection order matters.
486 if (returnedCollection.Count == 1)
487 {
488 errors.Add(ex);
489 return false;
490 }
491 }
492
493 // 2. Either the collections are different, or they are not in the same order.
494 // If order doesn't matter, try to find any returned collection element that matches.
495 foreach (object element in returnedCollection)
496 {
497 foundIndex++;
498 try
499 {
501 return true; // Found a matching element
502 }
504 {
505 errors.Add(ex);
506 }
507 }
508
509 return false;
510 }
511 }
512
513 // Used to generate an error message that comes up in a few cases if assertions fail.
514 private static string GetNoValueMatchErrorMessage(string propertyName, object expected, object actual)
515 {
516 return $"{propertyName} values do not match. " +
517 $"Type: \"{expected?.GetType().NiceTypeName() ?? "(null)"}\"." +
518 $"\nExpected: {Output.AutoFormat(expected)}," +
519 $"\nActual: {Output.AutoFormat(actual)}.";
520 }
521
528 public static bool FileContentsAreEqual(string expected, string actual,
530 {
531 string mod_expected = String.Join("\n", expected.Split('\n').Select(s => s.Trim())).Trim();
532 string mod_actual = String.Join("\n", actual.Split('\n').Select(s => s.Trim())).Trim();
533 return mod_expected.Equals(mod_actual, comparisonType);
534 }
535
540 {
542 {
543 Assert.IsNotNull(ex, "Expected some APIRequestException, got null.");
544 string message = "Expected an APIRequestException to contain a RestResponse " +
545 "with the HTTP Status: " + expectedStatusCode;
546 string messageEnd = "\nReceived Exception Details:\n" + ex;
547 Assert.IsNotNull(ex.RestResponse, message +
548 ", but the exception contained no RestResponse." + messageEnd);
549 Assert.IsNotNull(ex.ServerError, message +
550 ", but the exception contained no ServerError." + messageEnd);
551 message += ". Received Status: " + ex.RestResponse.StatusCode + " and Message: \"" +
552 (String.IsNullOrWhiteSpace(ex.ServerError.message) ? "(null)" : ex.ServerError.message) + "\"";
553 Assert.AreEqual(expectedStatusCode, ex.RestResponse.StatusCode, message + messageEnd);
554 };
555 }
556
557 // Asserts that all IReference properties within an object have been resolved.
558 public static void ReferencesResolved(object obj)
559 {
560 // Ensure that all reference properties with a non-null value have been resolved.
561 foreach (IReference<IAPIResource> reference in obj.GetType().GetUserFacingProperties()
562 .Where(p => typeof(IReference<IAPIResource>).IsAssignableFrom(p.PropertyType))
564 {
565 ReferencesResolvedHelper(reference);
566 }
567 // Ensure that any lists of references have every item in the list resolved.
568 foreach (IEnumerable<IReference<IAPIResource>> refList in obj.GetType().GetUserFacingProperties()
569 .Where(p => typeof(IEnumerable<IReference<IAPIResource>>).IsAssignableFrom(p.PropertyType))
571 {
572 if (refList == null || !refList.Any())
573 continue;
575 ReferencesResolvedHelper(reference);
576 }
577 }
578
579 // Checks that a specific instance of a reference property has been resolved.
580 private static void ReferencesResolvedHelper(IReference<IAPIResource> reference)
581 {
582 if (reference == null)
583 return;
584 Assert.IsTrue(reference.resolved, $"A {reference.GetType().NiceTypeName()} reference " +
585 "that has not been resolved was encountered.");
586 ReferencesResolved(reference.GetValue());
587 }
588
594 public static void DoublesAreEqual(double expected, double actual, Func<string> message,
595 double? relative_tolerance = null)
596 {
597 bool isTrue = relative_tolerance.HasValue ?
599 if (!isTrue)
600 Assert.Fail(message());
601 }
602
608 public static void DoublesAreEqual(double expected, double actual, string message = null,
609 double? relative_tolerance = null)
610 {
611 DoublesAreEqual(expected, actual, () => $"Expected: {Output.AutoFormat(expected)} and " +
612 $"Actual: {Output.AutoFormat(actual)} do not match within a tolerance of: " +
613 $"{relative_tolerance ?? DEFAULT_DOUBLE_EQUIVALENCE_TOLERANCE:G17}. " +
614 $"{message}", relative_tolerance);
615 }
616
622 public static bool AlmostEquals(double d1, double d2,
624 {
625 return d1.AlmostEquals(d2, tolerance);
626 }
627
628
635 public static void DatesAreEqual(DateTime? dt1, DateTime? dt2, string propertyName = "DateTime")
636 {
637 if (!dt1.HasValue && !dt2.HasValue) return;
638 if (!dt1.HasValue || !dt2.HasValue || !dt1.Value.AlmostEquals(dt2.Value))
639 Assert.Fail(GetNoValueMatchErrorMessage(propertyName, dt1, dt2));
640 }
641
644 public static void IsValidUUID(string toCheck)
645 {
646 Assert.IsNotNull(toCheck, "Expected a UUID but the result was empty.");
647 Assert.IsTrue(Guid.TryParseExact(toCheck, "D", out Guid _),
648 "The Id \"" + toCheck + "\" was not a valid UUID.");
649 }
650 }
651}
static void PostResponseMatches< T >(T objPosted, T objReturned)
Check that all properties of POST response matches expectations of how the API responds to requests....
Definition AssertApi.cs:150
static bool AlmostEquals(double d1, double d2, double tolerance=DEFAULT_DOUBLE_EQUIVALENCE_TOLERANCE)
Determines if two doubles are equivalent within the specified tolerance.
Definition AssertApi.cs:622
static bool TryFindException< T >(Exception ex, out T foundException)
Convert the current exception to the specified Exception type T , or check if any InnerExceptions mat...
Definition AssertApi.cs:35
static void ReferencesResolved(object obj)
Definition AssertApi.cs:558
static void LogExceptionDetails(Exception ex)
Creates a useful log of the exception details, and in request/response resulting in the error if any ...
Definition AssertApi.cs:51
const double DEFAULT_DOUBLE_EQUIVALENCE_TOLERANCE
Definition AssertApi.cs:27
static void MethodIsAllowed(Action request, string methodName, bool methodAllowed=true)
Wrap a request in a tryGet with some formatting for testing purposes.
Definition AssertApi.cs:98
static void ExceptionThrown< T >(Action action, Action< T > exceptionTest=null)
Asserts that an exception is thrown while invoking an action, and optionally performs an additional t...
Definition AssertApi.cs:68
static bool FileContentsAreEqual(string expected, string actual, StringComparison comparisonType=StringComparison.InvariantCulture)
Determines whether the two strings are equal, ignoring differences in line ending styles and trailing...
Definition AssertApi.cs:528
static void DoublesAreEqual(double expected, double actual, string message=null, double? relative_tolerance=null)
Determines if two doubles are equivalent within the accepted tolerance.
Definition AssertApi.cs:608
static void DatesAreEqual(DateTime? dt1, DateTime? dt2, string propertyName="DateTime")
Asserts that two dates are equal within the supported precision. Analyze Re only supports a precision...
Definition AssertApi.cs:635
static void IsValidUUID(string toCheck)
Assert that the string is a valid UUID.
Definition AssertApi.cs:644
static Action< APIRequestException > ApiExceptionTest(HttpStatusCode expectedStatusCode)
Generate a function that will test a REST request exception in a standard way.
Definition AssertApi.cs:539
static void DoublesAreEqual(double expected, double actual, Func< string > message, double? relative_tolerance=null)
Determines if two doubles are equivalent within the accepted tolerance.
Definition AssertApi.cs:594
static void PutResponseMatches< T >(T original, T objPut, T objReturned)
Check that all properties of a PUT response matches expectations of how the API responds to requests....
Definition AssertApi.cs:172
static void AllPropertiesEqual< T >(T objExpected, T objActual)
Check that all properties of the two objects match. A deep object value equivalency test.
Definition AssertApi.cs:129
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...
Indicates that the property, if left null, will have a default value generated and filled in by the s...
A wrapper for a List<T> of IReference<ILayerSource> references that simplifies the construction and u...
Definition Nested.cs:67
Allows one or more source layers or layer_views to be attached as loss sources to some other layer de...
Definition Nested.cs:22
Represents the Analysis of a Portfolio.
Utility for resolving types given only the types name (Useful for parsing ambiguous JSON objects).
static Type GetEnumerableType(Type type)
If the specified type implements IEnumerable<T>, returns the generic type argument....
Describes an endpoint on the server that can be interacted with. Inheriting from this interface means...
Definition IEndpoint.cs:10
PortfolioView and LayerView interface.
Interface for Base class used by all resources.
Interface shared by all object types and resources returned by the Analyze Re server.
Definition IAPIType.cs:6
Base interface for all reference entities.
@ Failed
Data has already been uploaded but failed processing.