Skip to content

Commit cf508e0

Browse files
tippmar-nrclaude
andcommitted
fix: improve array validation in integration test assertions
- Add support for string[], int[], bool[] typed arrays in test assertions - Extract array validation logic into ValidateArrayAttribute helper method - Handle JArray deserialization from JSON properly - Improve error messages with type information - Add regular attributes to empty array test endpoints to ensure transaction capture Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d1e268e commit cf508e0

3 files changed

Lines changed: 88 additions & 24 deletions

File tree

tests/Agent/IntegrationTests/Applications/AspNetCoreWebApiCustomAttributesApplication/Controllers/AttributeTestingController.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ public string CustomArrayAttributes()
7373
[Route("api/CustomEmptyArrayAttributes")]
7474
public string CustomEmptyArrayAttributes()
7575
{
76+
// Add a regular attribute to ensure transaction gets traced
77+
NewRelic.Api.Agent.NewRelic.GetAgent().CurrentTransaction.AddCustomAttribute("test", "empty-arrays");
78+
79+
// These should be skipped by our array logic
7680
NewRelic.Api.Agent.NewRelic.GetAgent().CurrentTransaction.AddCustomAttribute("emptyArray", new string[] { });
7781
NewRelic.Api.Agent.NewRelic.GetAgent().CurrentTransaction.AddCustomAttribute("nullOnlyArray", new object[] { null, null });
7882

tests/Agent/IntegrationTests/Applications/CustomAttributesWebApi/MyController.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ public string CustomArrayAttributes()
8080
[Route("api/CustomEmptyArrayAttributes")]
8181
public string CustomEmptyArrayAttributes()
8282
{
83+
// Add a regular attribute to ensure transaction gets traced
84+
NewRelic.Api.Agent.NewRelic.GetAgent().CurrentTransaction.AddCustomAttribute("test", "empty-arrays");
85+
86+
// These should be skipped by our array logic
8387
NewRelic.Api.Agent.NewRelic.GetAgent().CurrentTransaction.AddCustomAttribute("emptyArray", new string[] { });
8488
NewRelic.Api.Agent.NewRelic.GetAgent().CurrentTransaction.AddCustomAttribute("nullOnlyArray", new object[] { null, null });
8589

tests/Agent/IntegrationTests/IntegrationTestHelpers/Assertions.cs

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,42 +1083,98 @@ private static bool ValidateAttributeValues(KeyValuePair<string, object> expecte
10831083

10841084
break;
10851085
}
1086+
case string[] expectedStringArray:
1087+
{
1088+
ValidateArrayAttribute(expectedAttribute, rawActualValue, expectedStringArray.Cast<object>().ToArray(), builder, wireModelTypeName, ref succeeded);
1089+
break;
1090+
}
1091+
case int[] expectedIntArray:
1092+
{
1093+
ValidateArrayAttribute(expectedAttribute, rawActualValue, expectedIntArray.Cast<object>().ToArray(), builder, wireModelTypeName, ref succeeded);
1094+
break;
1095+
}
1096+
case bool[] expectedBoolArray:
1097+
{
1098+
ValidateArrayAttribute(expectedAttribute, rawActualValue, expectedBoolArray.Cast<object>().ToArray(), builder, wireModelTypeName, ref succeeded);
1099+
break;
1100+
}
10861101
case object[] expectedArray:
10871102
{
1088-
var actualValue = rawActualValue as object[];
1089-
if (actualValue == null)
1103+
ValidateArrayAttribute(expectedAttribute, rawActualValue, expectedArray, builder, wireModelTypeName, ref succeeded);
1104+
break;
1105+
}
1106+
default:
1107+
throw new NotImplementedException("Attribute handling for your type has not yet been implemented. The method only supports strings and bools. Update to add your type!");
1108+
}
1109+
1110+
return succeeded;
1111+
}
1112+
1113+
private static void ValidateArrayAttribute(KeyValuePair<string, object> expectedAttribute, object rawActualValue, object[] expectedArray, StringBuilder builder, string wireModelTypeName, ref bool succeeded)
1114+
{
1115+
// Handle different possible types of arrays from JSON deserialization
1116+
object[] actualArray = null;
1117+
1118+
if (rawActualValue is object[] directArray)
1119+
{
1120+
actualArray = directArray;
1121+
}
1122+
else if (rawActualValue is Newtonsoft.Json.Linq.JArray jArray)
1123+
{
1124+
actualArray = jArray.ToObject<object[]>();
1125+
}
1126+
else if (rawActualValue is System.Collections.IEnumerable enumerable)
1127+
{
1128+
actualArray = enumerable.Cast<object>().ToArray();
1129+
}
1130+
1131+
if (actualArray == null)
1132+
{
1133+
builder.AppendFormat("Attribute named {0} in the {3} had an unexpected type. Expected: array [{1}], Actual type: {2}",
1134+
expectedAttribute.Key, string.Join(", ", expectedArray), rawActualValue?.GetType()?.Name ?? "null", wireModelTypeName);
1135+
builder.AppendLine();
1136+
succeeded = false;
1137+
}
1138+
else if (actualArray.Length != expectedArray.Length)
1139+
{
1140+
builder.AppendFormat("Attribute named {0} in the {3} had an unexpected array length. Expected: {1}, Actual: {2}",
1141+
expectedAttribute.Key, expectedArray.Length, actualArray.Length, wireModelTypeName);
1142+
builder.AppendLine();
1143+
succeeded = false;
1144+
}
1145+
else
1146+
{
1147+
// Compare array elements
1148+
for (int i = 0; i < expectedArray.Length; i++)
1149+
{
1150+
var expectedElement = expectedArray[i];
1151+
var actualElement = actualArray[i];
1152+
1153+
// Handle different JSON number types (long vs int)
1154+
bool elementsEqual = false;
1155+
if (expectedElement is int expectedInt && actualElement is long actualLong)
10901156
{
1091-
builder.AppendFormat("Attribute named {0} in the {3} had an unexpected value. Expected: array [{1}], Actual: {2}", expectedAttribute.Key, string.Join(", ", expectedArray), rawActualValue, wireModelTypeName);
1092-
builder.AppendLine();
1093-
succeeded = false;
1157+
elementsEqual = expectedInt == actualLong;
10941158
}
1095-
else if (actualValue.Length != expectedArray.Length)
1159+
else if (expectedElement is long expectedLong && actualElement is int actualInt)
10961160
{
1097-
builder.AppendFormat("Attribute named {0} in the {3} had an unexpected array length. Expected: {1}, Actual: {2}", expectedAttribute.Key, expectedArray.Length, actualValue.Length, wireModelTypeName);
1098-
builder.AppendLine();
1099-
succeeded = false;
1161+
elementsEqual = expectedLong == actualInt;
11001162
}
11011163
else
11021164
{
1103-
// Compare array elements
1104-
for (int i = 0; i < expectedArray.Length; i++)
1105-
{
1106-
if (!Equals(expectedArray[i], actualValue[i]))
1107-
{
1108-
builder.AppendFormat("Attribute named {0} in the {3} had an unexpected value at index {4}. Expected: {1}, Actual: {2}", expectedAttribute.Key, expectedArray[i], actualValue[i], wireModelTypeName, i);
1109-
builder.AppendLine();
1110-
succeeded = false;
1111-
}
1112-
}
1165+
elementsEqual = Equals(expectedElement, actualElement);
11131166
}
11141167

1115-
break;
1168+
if (!elementsEqual)
1169+
{
1170+
builder.AppendFormat("Attribute named {0} in the {3} had an unexpected value at index {4}. Expected: {1} ({5}), Actual: {2} ({6})",
1171+
expectedAttribute.Key, expectedElement, actualElement, wireModelTypeName, i,
1172+
expectedElement?.GetType()?.Name ?? "null", actualElement?.GetType()?.Name ?? "null");
1173+
builder.AppendLine();
1174+
succeeded = false;
1175+
}
11161176
}
1117-
default:
1118-
throw new NotImplementedException("Attribute handling for your type has not yet been implemented. The method only supports strings and bools. Update to add your type!");
11191177
}
1120-
1121-
return succeeded;
11221178
}
11231179

11241180
private static bool IsNullOrEqual(string expectedValue, string actualValue)

0 commit comments

Comments
 (0)