[shared] Remove TagTransformer and improve TagWriter (#5602)
This commit is contained in:
parent
a578ed3f9b
commit
cf8ca09a55
|
|
@ -259,8 +259,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A49299
|
|||
src\Shared\SemanticConventions.cs = src\Shared\SemanticConventions.cs
|
||||
src\Shared\SpanAttributeConstants.cs = src\Shared\SpanAttributeConstants.cs
|
||||
src\Shared\StatusHelper.cs = src\Shared\StatusHelper.cs
|
||||
src\Shared\TagTransformer.cs = src\Shared\TagTransformer.cs
|
||||
src\Shared\TagTransformerJsonHelper.cs = src\Shared\TagTransformerJsonHelper.cs
|
||||
src\Shared\ThreadSafeRandom.cs = src\Shared\ThreadSafeRandom.cs
|
||||
EndProjectSection
|
||||
EndProject
|
||||
|
|
|
|||
|
|
@ -51,10 +51,10 @@ internal sealed class ConsoleTagWriter : JsonStringArrayTagWriter<ConsoleTagWrit
|
|||
consoleTag.Value = value ? "true" : "false";
|
||||
}
|
||||
|
||||
protected override void WriteStringTag(ref ConsoleTag consoleTag, string key, string value)
|
||||
protected override void WriteStringTag(ref ConsoleTag consoleTag, string key, ReadOnlySpan<char> value)
|
||||
{
|
||||
consoleTag.Key = key;
|
||||
consoleTag.Value = value;
|
||||
consoleTag.Value = value.ToString();
|
||||
}
|
||||
|
||||
protected override void WriteArrayTag(ref ConsoleTag consoleTag, string key, ArraySegment<byte> arrayUtf8JsonBytes)
|
||||
|
|
|
|||
|
|
@ -45,9 +45,9 @@ internal sealed class OtlpTagWriter : TagWriter<RepeatedField<OtlpCommon.KeyValu
|
|||
tags.Add(new OtlpCommon.KeyValue { Key = key, Value = ToAnyValue(value) });
|
||||
}
|
||||
|
||||
protected override void WriteStringTag(ref RepeatedField<OtlpCommon.KeyValue> tags, string key, string value)
|
||||
protected override void WriteStringTag(ref RepeatedField<OtlpCommon.KeyValue> tags, string key, ReadOnlySpan<char> value)
|
||||
{
|
||||
tags.Add(new OtlpCommon.KeyValue { Key = key, Value = ToAnyValue(value) });
|
||||
tags.Add(new OtlpCommon.KeyValue { Key = key, Value = ToAnyValue(value.ToString()) });
|
||||
}
|
||||
|
||||
protected override void WriteArrayTag(ref RepeatedField<OtlpCommon.KeyValue> tags, string key, ref OtlpCommon.ArrayValue value)
|
||||
|
|
@ -95,9 +95,9 @@ internal sealed class OtlpTagWriter : TagWriter<RepeatedField<OtlpCommon.KeyValu
|
|||
array.Values.Add(ToAnyValue(value));
|
||||
}
|
||||
|
||||
public override void WriteStringValue(ref OtlpCommon.ArrayValue array, string value)
|
||||
public override void WriteStringValue(ref OtlpCommon.ArrayValue array, ReadOnlySpan<char> value)
|
||||
{
|
||||
array.Values.Add(ToAnyValue(value));
|
||||
array.Values.Add(ToAnyValue(value.ToString()));
|
||||
}
|
||||
|
||||
public override void EndWriteArray(ref OtlpCommon.ArrayValue array)
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ internal sealed class ZipkinTagWriter : JsonStringArrayTagWriter<Utf8JsonWriter>
|
|||
protected override void WriteBooleanTag(ref Utf8JsonWriter writer, string key, bool value)
|
||||
=> writer.WriteString(key, value ? "true" : "false");
|
||||
|
||||
protected override void WriteStringTag(ref Utf8JsonWriter writer, string key, string value)
|
||||
protected override void WriteStringTag(ref Utf8JsonWriter writer, string key, ReadOnlySpan<char> value)
|
||||
=> writer.WriteString(key, value);
|
||||
|
||||
protected override void WriteArrayTag(ref Utf8JsonWriter writer, string key, ArraySegment<byte> arrayUtf8JsonBytes)
|
||||
|
|
|
|||
|
|
@ -1,208 +0,0 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OpenTelemetry.Internal;
|
||||
|
||||
internal abstract class TagTransformer<T>
|
||||
where T : notnull
|
||||
{
|
||||
protected TagTransformer()
|
||||
{
|
||||
}
|
||||
|
||||
public bool TryTransformTag(
|
||||
KeyValuePair<string, object> tag,
|
||||
[NotNullWhen(true)] out T? result,
|
||||
int? tagValueMaxLength = null)
|
||||
{
|
||||
if (tag.Value == null)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (tag.Value)
|
||||
{
|
||||
case char:
|
||||
case string:
|
||||
result = this.TransformStringTag(tag.Key, TruncateString(Convert.ToString(tag.Value)!, tagValueMaxLength));
|
||||
break;
|
||||
case bool b:
|
||||
result = this.TransformBooleanTag(tag.Key, b);
|
||||
break;
|
||||
case byte:
|
||||
case sbyte:
|
||||
case short:
|
||||
case ushort:
|
||||
case int:
|
||||
case uint:
|
||||
case long:
|
||||
result = this.TransformIntegralTag(tag.Key, Convert.ToInt64(tag.Value));
|
||||
break;
|
||||
case float:
|
||||
case double:
|
||||
result = this.TransformFloatingPointTag(tag.Key, Convert.ToDouble(tag.Value));
|
||||
break;
|
||||
case Array array:
|
||||
try
|
||||
{
|
||||
result = this.TransformArrayTagInternal(tag.Key, array, tagValueMaxLength);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If an exception is thrown when calling ToString
|
||||
// on any element of the array, then the entire array value
|
||||
// is ignored.
|
||||
return this.LogUnsupportedTagTypeAndReturnDefault(tag.Key, tag.Value, out result);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// All other types are converted to strings including the following
|
||||
// built-in value types:
|
||||
// case nint: Pointer type.
|
||||
// case nuint: Pointer type.
|
||||
// case ulong: May throw an exception on overflow.
|
||||
// case decimal: Converting to double produces rounding errors.
|
||||
default:
|
||||
try
|
||||
{
|
||||
var stringValue = TruncateString(Convert.ToString(tag.Value), tagValueMaxLength);
|
||||
if (stringValue == null)
|
||||
{
|
||||
return this.LogUnsupportedTagTypeAndReturnDefault(tag.Key, tag.Value, out result);
|
||||
}
|
||||
|
||||
result = this.TransformStringTag(tag.Key, stringValue);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If ToString throws an exception then the tag is ignored.
|
||||
return this.LogUnsupportedTagTypeAndReturnDefault(tag.Key, tag.Value, out result);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract T TransformIntegralTag(string key, long value);
|
||||
|
||||
protected abstract T TransformFloatingPointTag(string key, double value);
|
||||
|
||||
protected abstract T TransformBooleanTag(string key, bool value);
|
||||
|
||||
protected abstract T TransformStringTag(string key, string value);
|
||||
|
||||
protected abstract T TransformArrayTag(string key, Array array);
|
||||
|
||||
protected abstract void OnUnsupportedTagDropped(
|
||||
string tagKey,
|
||||
string tagValueTypeFullName);
|
||||
|
||||
[return: NotNullIfNotNull(nameof(value))]
|
||||
private static string? TruncateString(string? value, int? maxLength)
|
||||
{
|
||||
return maxLength.HasValue && value?.Length > maxLength
|
||||
? value.Substring(0, maxLength.Value)
|
||||
: value;
|
||||
}
|
||||
|
||||
private T TransformArrayTagInternal(string key, Array array, int? tagValueMaxLength)
|
||||
{
|
||||
// This switch ensures the values of the resultant array-valued tag are of the same type.
|
||||
return array switch
|
||||
{
|
||||
char[] => this.TransformArrayTag(key, array),
|
||||
string[] => this.ConvertToStringArrayThenTransformArrayTag(key, array, tagValueMaxLength),
|
||||
bool[] => this.TransformArrayTag(key, array),
|
||||
byte[] => this.TransformArrayTag(key, array),
|
||||
sbyte[] => this.TransformArrayTag(key, array),
|
||||
short[] => this.TransformArrayTag(key, array),
|
||||
ushort[] => this.TransformArrayTag(key, array),
|
||||
#if NETFRAMEWORK
|
||||
int[] => this.TransformArrayTagIntNetFramework(key, array, tagValueMaxLength),
|
||||
#else
|
||||
int[] => this.TransformArrayTag(key, array),
|
||||
#endif
|
||||
uint[] => this.TransformArrayTag(key, array),
|
||||
#if NETFRAMEWORK
|
||||
long[] => this.TransformArrayTagLongNetFramework(key, array, tagValueMaxLength),
|
||||
#else
|
||||
long[] => this.TransformArrayTag(key, array),
|
||||
#endif
|
||||
float[] => this.TransformArrayTag(key, array),
|
||||
double[] => this.TransformArrayTag(key, array),
|
||||
_ => this.ConvertToStringArrayThenTransformArrayTag(key, array, tagValueMaxLength),
|
||||
};
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
private T TransformArrayTagIntNetFramework(string key, Array array, int? tagValueMaxLength)
|
||||
{
|
||||
// Note: On .NET Framework x86 nint[] & nuint[] fall into int[] case
|
||||
|
||||
var arrayType = array.GetType();
|
||||
if (arrayType == typeof(nint[])
|
||||
|| arrayType == typeof(nuint[]))
|
||||
{
|
||||
return this.ConvertToStringArrayThenTransformArrayTag(key, array, tagValueMaxLength);
|
||||
}
|
||||
|
||||
return this.TransformArrayTag(key, array);
|
||||
}
|
||||
|
||||
private T TransformArrayTagLongNetFramework(string key, Array array, int? tagValueMaxLength)
|
||||
{
|
||||
// Note: On .NET Framework x64 nint[] & nuint[] fall into long[] case
|
||||
|
||||
var arrayType = array.GetType();
|
||||
if (arrayType == typeof(nint[])
|
||||
|| arrayType == typeof(nuint[]))
|
||||
{
|
||||
return this.ConvertToStringArrayThenTransformArrayTag(key, array, tagValueMaxLength);
|
||||
}
|
||||
|
||||
return this.TransformArrayTag(key, array);
|
||||
}
|
||||
#endif
|
||||
|
||||
private T ConvertToStringArrayThenTransformArrayTag(string key, Array array, int? tagValueMaxLength)
|
||||
{
|
||||
string?[] stringArray;
|
||||
|
||||
if (array is string?[] arrayAsStringArray
|
||||
&& (!tagValueMaxLength.HasValue || !arrayAsStringArray.Any(s => s?.Length > tagValueMaxLength)))
|
||||
{
|
||||
stringArray = arrayAsStringArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
stringArray = new string?[array.Length];
|
||||
for (var i = 0; i < array.Length; ++i)
|
||||
{
|
||||
var item = array.GetValue(i);
|
||||
stringArray[i] = item == null
|
||||
? null
|
||||
: TruncateString(Convert.ToString(item), tagValueMaxLength);
|
||||
}
|
||||
}
|
||||
|
||||
return this.TransformArrayTag(key, stringArray);
|
||||
}
|
||||
|
||||
private bool LogUnsupportedTagTypeAndReturnDefault(string key, object value, out T? result)
|
||||
{
|
||||
Debug.Assert(value != null, "value was null");
|
||||
|
||||
this.OnUnsupportedTagDropped(key, value!.GetType().ToString());
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System.Text.Json;
|
||||
#if NET6_0_OR_GREATER
|
||||
using System.Text.Json.Serialization;
|
||||
#endif
|
||||
|
||||
namespace OpenTelemetry.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// This class has to be partial so that JSON source generator can provide code for the JsonSerializerContext.
|
||||
/// </summary>
|
||||
internal static partial class TagTransformerJsonHelper
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
// In net6.0 or higher ships System.Text.Json "in box" as part of the base class libraries;
|
||||
// meaning the consumer automatically got upgraded to use v6.0 System.Text.Json
|
||||
// which has support for using source generators for JSON serialization.
|
||||
// The source generator makes the serialization faster and also AOT compatible.
|
||||
|
||||
internal static string JsonSerializeArrayTag(Array array)
|
||||
{
|
||||
return JsonSerializer.Serialize(array, typeof(Array), ArrayTagJsonContext.Default);
|
||||
}
|
||||
|
||||
[JsonSerializable(typeof(Array))]
|
||||
[JsonSerializable(typeof(char))]
|
||||
[JsonSerializable(typeof(string))]
|
||||
[JsonSerializable(typeof(bool))]
|
||||
[JsonSerializable(typeof(byte))]
|
||||
[JsonSerializable(typeof(sbyte))]
|
||||
[JsonSerializable(typeof(short))]
|
||||
[JsonSerializable(typeof(ushort))]
|
||||
[JsonSerializable(typeof(int))]
|
||||
[JsonSerializable(typeof(uint))]
|
||||
[JsonSerializable(typeof(long))]
|
||||
[JsonSerializable(typeof(ulong))]
|
||||
[JsonSerializable(typeof(float))]
|
||||
[JsonSerializable(typeof(double))]
|
||||
private sealed partial class ArrayTagJsonContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
internal static string JsonSerializeArrayTag(Array array)
|
||||
{
|
||||
return JsonSerializer.Serialize(array);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ internal abstract class ArrayTagWriter<TArrayState>
|
|||
|
||||
public abstract void WriteBooleanValue(ref TArrayState state, bool value);
|
||||
|
||||
public abstract void WriteStringValue(ref TArrayState state, string value);
|
||||
public abstract void WriteStringValue(ref TArrayState state, ReadOnlySpan<char> value);
|
||||
|
||||
public abstract void EndWriteArray(ref TArrayState state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ internal abstract class JsonStringArrayTagWriter<TTagState> : TagWriter<TTagStat
|
|||
state.Writer.WriteNullValue();
|
||||
}
|
||||
|
||||
public override void WriteStringValue(ref JsonArrayTagWriterState state, string value)
|
||||
public override void WriteStringValue(ref JsonArrayTagWriterState state, ReadOnlySpan<char> value)
|
||||
{
|
||||
state.Writer.WriteStringValue(value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
|
||||
#nullable enable
|
||||
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OpenTelemetry.Internal;
|
||||
|
||||
|
|
@ -35,9 +33,14 @@ internal abstract class TagWriter<TTagState, TArrayState>
|
|||
|
||||
switch (tag.Value)
|
||||
{
|
||||
case char:
|
||||
case string:
|
||||
this.WriteStringTag(ref state, tag.Key, TruncateString(Convert.ToString(tag.Value)!, tagValueMaxLength));
|
||||
case char c:
|
||||
this.WriteCharTag(ref state, tag.Key, c);
|
||||
break;
|
||||
case string s:
|
||||
this.WriteStringTag(
|
||||
ref state,
|
||||
tag.Key,
|
||||
TruncateString(s.AsSpan(), tagValueMaxLength));
|
||||
break;
|
||||
case bool b:
|
||||
this.WriteBooleanTag(ref state, tag.Key, b);
|
||||
|
|
@ -79,13 +82,16 @@ internal abstract class TagWriter<TTagState, TArrayState>
|
|||
default:
|
||||
try
|
||||
{
|
||||
var stringValue = TruncateString(Convert.ToString(tag.Value/*TODO: , CultureInfo.InvariantCulture*/), tagValueMaxLength);
|
||||
var stringValue = Convert.ToString(tag.Value/*TODO: , CultureInfo.InvariantCulture*/);
|
||||
if (stringValue == null)
|
||||
{
|
||||
return this.LogUnsupportedTagTypeAndReturnFalse(tag.Key, tag.Value);
|
||||
}
|
||||
|
||||
this.WriteStringTag(ref state, tag.Key, stringValue);
|
||||
this.WriteStringTag(
|
||||
ref state,
|
||||
tag.Key,
|
||||
TruncateString(stringValue.AsSpan(), tagValueMaxLength));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
@ -105,7 +111,7 @@ internal abstract class TagWriter<TTagState, TArrayState>
|
|||
|
||||
protected abstract void WriteBooleanTag(ref TTagState state, string key, bool value);
|
||||
|
||||
protected abstract void WriteStringTag(ref TTagState state, string key, string value);
|
||||
protected abstract void WriteStringTag(ref TTagState state, string key, ReadOnlySpan<char> value);
|
||||
|
||||
protected abstract void WriteArrayTag(ref TTagState state, string key, ref TArrayState value);
|
||||
|
||||
|
|
@ -113,14 +119,27 @@ internal abstract class TagWriter<TTagState, TArrayState>
|
|||
string tagKey,
|
||||
string tagValueTypeFullName);
|
||||
|
||||
[return: NotNullIfNotNull(nameof(value))]
|
||||
private static string? TruncateString(string? value, int? maxLength)
|
||||
private static ReadOnlySpan<char> TruncateString(ReadOnlySpan<char> value, int? maxLength)
|
||||
{
|
||||
return maxLength.HasValue && value?.Length > maxLength
|
||||
? value.Substring(0, maxLength.Value)
|
||||
return maxLength.HasValue && value.Length > maxLength
|
||||
? value.Slice(0, maxLength.Value)
|
||||
: value;
|
||||
}
|
||||
|
||||
private void WriteCharTag(ref TTagState state, string key, char value)
|
||||
{
|
||||
Span<char> destination = stackalloc char[1];
|
||||
destination[0] = value;
|
||||
this.WriteStringTag(ref state, key, destination);
|
||||
}
|
||||
|
||||
private void WriteCharValue(ref TArrayState state, char value)
|
||||
{
|
||||
Span<char> destination = stackalloc char[1];
|
||||
destination[0] = value;
|
||||
this.arrayWriter.WriteStringValue(ref state, destination);
|
||||
}
|
||||
|
||||
private void WriteArrayTagInternal(ref TTagState state, string key, Array array, int? tagValueMaxLength)
|
||||
{
|
||||
var arrayState = this.arrayWriter.BeginWriteArray();
|
||||
|
|
@ -128,24 +147,21 @@ internal abstract class TagWriter<TTagState, TArrayState>
|
|||
// This switch ensures the values of the resultant array-valued tag are of the same type.
|
||||
switch (array)
|
||||
{
|
||||
case char[] charArray: this.WriteToArray(ref arrayState, charArray); break;
|
||||
case string[]: this.ConvertToStringArrayThenWriteArrayTag(ref arrayState, array, tagValueMaxLength); break;
|
||||
case bool[] boolArray: this.WriteToArray(ref arrayState, boolArray); break;
|
||||
case byte[] byteArray: this.WriteToArray(ref arrayState, byteArray); break;
|
||||
case sbyte[] sbyteArray: this.WriteToArray(ref arrayState, sbyteArray); break;
|
||||
case short[] shortArray: this.WriteToArray(ref arrayState, shortArray); break;
|
||||
case ushort[] ushortArray: this.WriteToArray(ref arrayState, ushortArray); break;
|
||||
case uint[] uintArray: this.WriteToArray(ref arrayState, uintArray); break;
|
||||
case char[] charArray: this.WriteStructToArray(ref arrayState, charArray); break;
|
||||
case string?[] stringArray: this.WriteStringsToArray(ref arrayState, stringArray, tagValueMaxLength); break;
|
||||
case bool[] boolArray: this.WriteStructToArray(ref arrayState, boolArray); break;
|
||||
case byte[] byteArray: this.WriteToArrayCovariant(ref arrayState, byteArray); break;
|
||||
case short[] shortArray: this.WriteToArrayCovariant(ref arrayState, shortArray); break;
|
||||
#if NETFRAMEWORK
|
||||
case int[]: this.WriteArrayTagIntNetFramework(ref arrayState, array, tagValueMaxLength); break;
|
||||
case long[]: this.WriteArrayTagLongNetFramework(ref arrayState, array, tagValueMaxLength); break;
|
||||
#else
|
||||
case int[] intArray: this.WriteToArray(ref arrayState, intArray); break;
|
||||
case long[] longArray: this.WriteToArray(ref arrayState, longArray); break;
|
||||
case int[] intArray: this.WriteToArrayCovariant(ref arrayState, intArray); break;
|
||||
case long[] longArray: this.WriteToArrayCovariant(ref arrayState, longArray); break;
|
||||
#endif
|
||||
case float[] floatArray: this.WriteToArray(ref arrayState, floatArray); break;
|
||||
case double[] doubleArray: this.WriteToArray(ref arrayState, doubleArray); break;
|
||||
default: this.ConvertToStringArrayThenWriteArrayTag(ref arrayState, array, tagValueMaxLength); break;
|
||||
case float[] floatArray: this.WriteStructToArray(ref arrayState, floatArray); break;
|
||||
case double[] doubleArray: this.WriteStructToArray(ref arrayState, doubleArray); break;
|
||||
default: this.WriteToArrayTypeChecked(ref arrayState, array, tagValueMaxLength); break;
|
||||
}
|
||||
|
||||
this.arrayWriter.EndWriteArray(ref arrayState);
|
||||
|
|
@ -162,11 +178,11 @@ internal abstract class TagWriter<TTagState, TArrayState>
|
|||
if (arrayType == typeof(nint[])
|
||||
|| arrayType == typeof(nuint[]))
|
||||
{
|
||||
this.ConvertToStringArrayThenWriteArrayTag(ref arrayState, array, tagValueMaxLength);
|
||||
this.WriteToArrayTypeChecked(ref arrayState, array, tagValueMaxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
this.WriteToArray(ref arrayState, (int[])array);
|
||||
this.WriteToArrayCovariant(ref arrayState, (int[])array);
|
||||
}
|
||||
|
||||
private void WriteArrayTagLongNetFramework(ref TArrayState arrayState, Array array, int? tagValueMaxLength)
|
||||
|
|
@ -177,51 +193,143 @@ internal abstract class TagWriter<TTagState, TArrayState>
|
|||
if (arrayType == typeof(nint[])
|
||||
|| arrayType == typeof(nuint[]))
|
||||
{
|
||||
this.ConvertToStringArrayThenWriteArrayTag(ref arrayState, array, tagValueMaxLength);
|
||||
this.WriteToArrayTypeChecked(ref arrayState, array, tagValueMaxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
this.WriteToArray(ref arrayState, (long[])array);
|
||||
this.WriteToArrayCovariant(ref arrayState, (long[])array);
|
||||
}
|
||||
#endif
|
||||
|
||||
private void ConvertToStringArrayThenWriteArrayTag(ref TArrayState arrayState, Array array, int? tagValueMaxLength)
|
||||
private void WriteToArrayTypeChecked(ref TArrayState arrayState, Array array, int? tagValueMaxLength)
|
||||
{
|
||||
if (array is string?[] arrayAsStringArray
|
||||
&& (!tagValueMaxLength.HasValue || !arrayAsStringArray.Any(s => s?.Length > tagValueMaxLength)))
|
||||
for (var i = 0; i < array.Length; ++i)
|
||||
{
|
||||
this.WriteStringsToArray(ref arrayState, arrayAsStringArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
string?[] stringArray = ArrayPool<string?>.Shared.Rent(array.Length);
|
||||
try
|
||||
var item = array.GetValue(i);
|
||||
if (item == null)
|
||||
{
|
||||
for (var i = 0; i < array.Length; ++i)
|
||||
{
|
||||
var item = array.GetValue(i);
|
||||
stringArray[i] = item == null
|
||||
? null
|
||||
: TruncateString(Convert.ToString(item/*TODO: , CultureInfo.InvariantCulture*/), tagValueMaxLength);
|
||||
}
|
||||
|
||||
this.WriteStringsToArray(ref arrayState, new(stringArray, 0, array.Length));
|
||||
this.arrayWriter.WriteNullValue(ref arrayState);
|
||||
continue;
|
||||
}
|
||||
finally
|
||||
|
||||
switch (item)
|
||||
{
|
||||
ArrayPool<string?>.Shared.Return(stringArray);
|
||||
case char c:
|
||||
this.WriteCharValue(ref arrayState, c);
|
||||
break;
|
||||
case string s:
|
||||
this.arrayWriter.WriteStringValue(
|
||||
ref arrayState,
|
||||
TruncateString(s.AsSpan(), tagValueMaxLength));
|
||||
break;
|
||||
case bool b:
|
||||
this.arrayWriter.WriteBooleanValue(ref arrayState, b);
|
||||
break;
|
||||
case byte:
|
||||
case sbyte:
|
||||
case short:
|
||||
case ushort:
|
||||
case int:
|
||||
case uint:
|
||||
case long:
|
||||
this.arrayWriter.WriteIntegralValue(ref arrayState, Convert.ToInt64(item));
|
||||
break;
|
||||
case float:
|
||||
case double:
|
||||
this.arrayWriter.WriteFloatingPointValue(ref arrayState, Convert.ToDouble(item));
|
||||
break;
|
||||
|
||||
// All other types are converted to strings including the following
|
||||
// built-in value types:
|
||||
// case Array: Nested array.
|
||||
// case nint: Pointer type.
|
||||
// case nuint: Pointer type.
|
||||
// case ulong: May throw an exception on overflow.
|
||||
// case decimal: Converting to double produces rounding errors.
|
||||
default:
|
||||
var stringValue = Convert.ToString(item/*TODO: , CultureInfo.InvariantCulture*/);
|
||||
if (stringValue == null)
|
||||
{
|
||||
this.arrayWriter.WriteNullValue(ref arrayState);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.arrayWriter.WriteStringValue(
|
||||
ref arrayState,
|
||||
TruncateString(stringValue.AsSpan(), tagValueMaxLength));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteToArray<TItem>(ref TArrayState arrayState, TItem[] array)
|
||||
private void WriteToArrayCovariant<TItem>(ref TArrayState arrayState, TItem[] array)
|
||||
where TItem : struct
|
||||
{
|
||||
// Note: The runtime treats int[]/uint[], byte[]/sbyte[],
|
||||
// short[]/ushort[], and long[]/ulong[] as covariant.
|
||||
|
||||
if (typeof(TItem) == typeof(byte))
|
||||
{
|
||||
if (array.GetType() == typeof(sbyte[]))
|
||||
{
|
||||
this.WriteStructToArray(ref arrayState, (sbyte[])(object)array);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WriteStructToArray(ref arrayState, (byte[])(object)array);
|
||||
}
|
||||
}
|
||||
else if (typeof(TItem) == typeof(short))
|
||||
{
|
||||
if (array.GetType() == typeof(ushort[]))
|
||||
{
|
||||
this.WriteStructToArray(ref arrayState, (ushort[])(object)array);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WriteStructToArray(ref arrayState, (short[])(object)array);
|
||||
}
|
||||
}
|
||||
else if (typeof(TItem) == typeof(int))
|
||||
{
|
||||
if (array.GetType() == typeof(uint[]))
|
||||
{
|
||||
this.WriteStructToArray(ref arrayState, (uint[])(object)array);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WriteStructToArray(ref arrayState, (int[])(object)array);
|
||||
}
|
||||
}
|
||||
else if (typeof(TItem) == typeof(long))
|
||||
{
|
||||
if (array.GetType() == typeof(ulong[]))
|
||||
{
|
||||
this.WriteToArrayTypeChecked(ref arrayState, array, tagValueMaxLength: null);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WriteStructToArray(ref arrayState, (long[])(object)array);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Fail("Unexpected type encountered");
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteStructToArray<TItem>(ref TArrayState arrayState, TItem[] array)
|
||||
where TItem : struct
|
||||
{
|
||||
foreach (TItem item in array)
|
||||
{
|
||||
if (typeof(TItem) == typeof(char))
|
||||
{
|
||||
this.arrayWriter.WriteStringValue(ref arrayState, Convert.ToString((char)(object)item)!);
|
||||
this.WriteCharValue(ref arrayState, (char)(object)item);
|
||||
}
|
||||
else if (typeof(TItem) == typeof(bool))
|
||||
{
|
||||
|
|
@ -272,9 +380,9 @@ internal abstract class TagWriter<TTagState, TArrayState>
|
|||
}
|
||||
}
|
||||
|
||||
private void WriteStringsToArray(ref TArrayState arrayState, ReadOnlySpan<string?> data)
|
||||
private void WriteStringsToArray(ref TArrayState arrayState, string?[] array, int? tagValueMaxLength)
|
||||
{
|
||||
foreach (var item in data)
|
||||
foreach (var item in array)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
|
|
@ -282,7 +390,9 @@ internal abstract class TagWriter<TTagState, TArrayState>
|
|||
}
|
||||
else
|
||||
{
|
||||
this.arrayWriter.WriteStringValue(ref arrayState, item);
|
||||
this.arrayWriter.WriteStringValue(
|
||||
ref arrayState,
|
||||
TruncateString(item.AsSpan(), tagValueMaxLength));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,6 +137,44 @@ public class OtlpAttributeTests
|
|||
Assert.Equal(Convert.ToString(value), attribute.Value.StringValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObjectArrayTypesSupported()
|
||||
{
|
||||
var obj = new object();
|
||||
var objectArray = new object[] { null, "a", 'b', true, int.MaxValue, long.MaxValue, float.MaxValue, double.MaxValue, obj };
|
||||
|
||||
var kvp = new KeyValuePair<string, object>("key", objectArray);
|
||||
|
||||
Assert.True(TryTransformTag(kvp, out var attribute));
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.ArrayValue, attribute.Value.ValueCase);
|
||||
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.None, attribute.Value.ArrayValue.Values[0].ValueCase);
|
||||
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.StringValue, attribute.Value.ArrayValue.Values[1].ValueCase);
|
||||
Assert.Equal("a", attribute.Value.ArrayValue.Values[1].StringValue);
|
||||
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.StringValue, attribute.Value.ArrayValue.Values[2].ValueCase);
|
||||
Assert.Equal("b", attribute.Value.ArrayValue.Values[2].StringValue);
|
||||
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.BoolValue, attribute.Value.ArrayValue.Values[3].ValueCase);
|
||||
Assert.True(attribute.Value.ArrayValue.Values[3].BoolValue);
|
||||
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.IntValue, attribute.Value.ArrayValue.Values[4].ValueCase);
|
||||
Assert.Equal(int.MaxValue, attribute.Value.ArrayValue.Values[4].IntValue);
|
||||
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.IntValue, attribute.Value.ArrayValue.Values[5].ValueCase);
|
||||
Assert.Equal(long.MaxValue, attribute.Value.ArrayValue.Values[5].IntValue);
|
||||
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.DoubleValue, attribute.Value.ArrayValue.Values[6].ValueCase);
|
||||
Assert.Equal(float.MaxValue, attribute.Value.ArrayValue.Values[6].DoubleValue);
|
||||
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.DoubleValue, attribute.Value.ArrayValue.Values[7].ValueCase);
|
||||
Assert.Equal(double.MaxValue, attribute.Value.ArrayValue.Values[7].DoubleValue);
|
||||
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.StringValue, attribute.Value.ArrayValue.Values[8].ValueCase);
|
||||
Assert.Equal(obj.ToString(), attribute.Value.ArrayValue.Values[8].StringValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StringArrayTypesSupported()
|
||||
{
|
||||
|
|
@ -183,7 +221,7 @@ public class OtlpAttributeTests
|
|||
new nint[] { 1, 2, 3 },
|
||||
new nuint[] { 1, 2, 3 },
|
||||
new decimal[] { 1, 2, 3 },
|
||||
new object[] { 1, new object(), false, null },
|
||||
new object[] { new object[3], new object(), null },
|
||||
};
|
||||
|
||||
foreach (var value in testValues)
|
||||
|
|
|
|||
|
|
@ -4,10 +4,9 @@
|
|||
#nullable enable
|
||||
|
||||
using System.Reflection;
|
||||
using OpenTelemetry.Internal;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenTelemetry.Tests;
|
||||
namespace OpenTelemetry.Internal.Tests;
|
||||
|
||||
public class AssemblyVersionExtensionsTests
|
||||
{
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System.Text;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenTelemetry.Internal.Tests;
|
||||
|
||||
public class JsonStringArrayTagWriterTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(new object[] { new char[] { }, "[]" })]
|
||||
[InlineData(new object[] { new char[] { 'a' }, """["a"]""" })]
|
||||
[InlineData(new object[] { new char[] { '1', '2', '3' }, """["1","2","3"]""" })]
|
||||
public void CharArray(char[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new string[] { }, "[]" })]
|
||||
[InlineData(new object[] { new string[] { "one" }, """["one"]""" })]
|
||||
[InlineData(new object[] { new string[] { "" }, """[""]""" })]
|
||||
[InlineData(new object[] { new string[] { "a", "b", "c", "d" }, """["a","b","c","d"]""" })]
|
||||
[InlineData(new object[] { new string[] { "\r\n", "\t", "\"" }, """["\r\n","\t","\u0022"]""" })]
|
||||
[InlineData(new object[] { new string[] { "longlonglonglonglonglonglonglonglong" }, """["longlonglonglonglonglonglonglonglong"]""" })]
|
||||
public void StringArray(string[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new bool[] { }, "[]" })]
|
||||
[InlineData(new object[] { new bool[] { true }, "[true]" })]
|
||||
[InlineData(new object[] { new bool[] { true, false, false, true }, "[true,false,false,true]" })]
|
||||
public void BooleanArray(bool[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new byte[] { }, "[]" })]
|
||||
[InlineData(new object[] { new byte[] { 0 }, "[0]" })]
|
||||
[InlineData(new object[] { new byte[] { byte.MaxValue, byte.MinValue, 4, 13 }, "[255,0,4,13]" })]
|
||||
public void ByteArray(byte[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new sbyte[] { }, "[]" })]
|
||||
[InlineData(new object[] { new sbyte[] { 0 }, "[0]" })]
|
||||
[InlineData(new object[] { new sbyte[] { sbyte.MaxValue, sbyte.MinValue, 4, 13 }, "[127,-128,4,13]" })]
|
||||
public void SByteArray(sbyte[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new short[] { }, "[]" })]
|
||||
[InlineData(new object[] { new short[] { 0 }, "[0]" })]
|
||||
[InlineData(new object[] { new short[] { short.MaxValue, short.MinValue, 4, 13 }, "[32767,-32768,4,13]" })]
|
||||
public void ShortArray(short[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new ushort[] { }, "[]" })]
|
||||
[InlineData(new object[] { new ushort[] { 0 }, "[0]" })]
|
||||
[InlineData(new object[] { new ushort[] { ushort.MaxValue, ushort.MinValue, 4, 13 }, "[65535,0,4,13]" })]
|
||||
public void UShortArray(ushort[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new int[] { }, "[]" })]
|
||||
[InlineData(new object[] { new int[] { 0 }, "[0]" })]
|
||||
[InlineData(new object[] { new int[] { int.MaxValue, int.MinValue, 4, 13 }, "[2147483647,-2147483648,4,13]" })]
|
||||
public void IntArray(int[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new uint[] { }, "[]" })]
|
||||
[InlineData(new object[] { new uint[] { 0 }, "[0]" })]
|
||||
[InlineData(new object[] { new uint[] { uint.MaxValue, uint.MinValue, 4, 13 }, "[4294967295,0,4,13]" })]
|
||||
public void UIntArray(uint[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new long[] { }, "[]" })]
|
||||
[InlineData(new object[] { new long[] { 0 }, "[0]" })]
|
||||
[InlineData(new object[] { new long[] { long.MaxValue, long.MinValue, 4, 13 }, "[9223372036854775807,-9223372036854775808,4,13]" })]
|
||||
public void LongArray(long[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new ulong[] { }, "[]" })]
|
||||
[InlineData(new object[] { new ulong[] { 0 }, """["0"]""" })]
|
||||
[InlineData(new object[] { new ulong[] { ulong.MaxValue, ulong.MinValue, 4, 13 }, """["18446744073709551615","0","4","13"]""" })]
|
||||
public void ULongArray(ulong[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new float[] { }, "[]" })]
|
||||
[InlineData(new object[] { new float[] { 0 }, "[0]" })]
|
||||
[InlineData(new object[] { new float[] { float.MaxValue, float.MinValue, 4, 13 }, "[3.4028234663852886E+38,-3.4028234663852886E+38,4,13]" })]
|
||||
#if NETFRAMEWORK
|
||||
[InlineData(new object[] { new float[] { float.Epsilon }, "[1.4012984643248171E-45]" })]
|
||||
#else
|
||||
[InlineData(new object[] { new float[] { float.Epsilon }, "[1.401298464324817E-45]" })]
|
||||
#endif
|
||||
public void FloatArray(float[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new double[] { }, "[]" })]
|
||||
[InlineData(new object[] { new double[] { 0 }, "[0]" })]
|
||||
[InlineData(new object[] { new double[] { double.MaxValue, double.MinValue, 4, 13 }, "[1.7976931348623157E+308,-1.7976931348623157E+308,4,13]" })]
|
||||
#if NETFRAMEWORK
|
||||
[InlineData(new object[] { new double[] { double.Epsilon }, "[4.9406564584124654E-324]" })]
|
||||
#else
|
||||
[InlineData(new object[] { new double[] { double.Epsilon }, "[5E-324]" })]
|
||||
#endif
|
||||
public void DoubleArray(double[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new object?[] { }, "[]" })]
|
||||
[InlineData(new object[] { new object?[] { null, float.MinValue, float.MaxValue, double.MinValue, double.MaxValue, int.MinValue, int.MaxValue, long.MinValue, long.MaxValue, true, false, "Hello world", new object[] { "inner array" } }, """[null,-3.4028234663852886E+38,3.4028234663852886E+38,-1.7976931348623157E+308,1.7976931348623157E+308,-2147483648,2147483647,-9223372036854775808,9223372036854775807,true,false,"Hello world","System.Object[]"]""" })]
|
||||
public void ObjectArray(object?[] data, string expectedValue)
|
||||
{
|
||||
VerifySerialization(data, expectedValue);
|
||||
}
|
||||
|
||||
private static void VerifySerialization(Array data, string expectedValue)
|
||||
{
|
||||
TestTagWriter.Tag tag = default;
|
||||
var result = TestTagWriter.Instance.TryWriteTag(ref tag, new KeyValuePair<string, object?>("array", data));
|
||||
|
||||
Assert.True(result);
|
||||
Assert.Equal(expectedValue, tag.Value);
|
||||
}
|
||||
|
||||
private sealed class TestTagWriter : JsonStringArrayTagWriter<TestTagWriter.Tag>
|
||||
{
|
||||
private TestTagWriter()
|
||||
{
|
||||
}
|
||||
|
||||
public static TestTagWriter Instance { get; } = new();
|
||||
|
||||
protected override void WriteIntegralTag(ref Tag tag, string key, long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void WriteFloatingPointTag(ref Tag tag, string key, double value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void WriteBooleanTag(ref Tag tag, string key, bool value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void WriteStringTag(ref Tag tag, string key, ReadOnlySpan<char> value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void WriteArrayTag(ref Tag tag, string key, ArraySegment<byte> arrayUtf8JsonBytes)
|
||||
{
|
||||
tag.Key = key;
|
||||
tag.Value = Encoding.UTF8.GetString(arrayUtf8JsonBytes.Array!, 0, arrayUtf8JsonBytes.Count);
|
||||
}
|
||||
|
||||
protected override void OnUnsupportedTagDropped(string tagKey, string tagValueTypeFullName)
|
||||
{
|
||||
}
|
||||
|
||||
public struct Tag
|
||||
{
|
||||
public string? Key;
|
||||
public string? Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
<Compile Include="$(RepoRoot)\src\Shared\PeriodicExportingMetricReaderHelper.cs" Link="Includes\PeriodicExportingMetricReaderHelper.cs" />
|
||||
<Compile Include="$(RepoRoot)\src\Shared\RedactionHelper.cs" Link="Includes\RedactionHelper.cs" />
|
||||
<Compile Include="$(RepoRoot)\src\Shared\PooledList.cs" Link="Includes\PooledList.cs" />
|
||||
<Compile Include="$(RepoRoot)\src\Shared\TagTransformerJsonHelper.cs" Link="Includes\TagTransformerJsonHelper.cs" />
|
||||
<Compile Include="$(RepoRoot)\src\Shared\TagWriter\*.cs" Link="Includes\TagWriter\%(Filename).cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,140 +0,0 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
using OpenTelemetry.Internal;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenTelemetry.Tests.Shared;
|
||||
|
||||
public class TagTransformerJsonHelperTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(new object[] { new char[] { } })]
|
||||
[InlineData(new object[] { new char[] { 'a' } })]
|
||||
[InlineData(new object[] { new char[] { '1', '2', '3' } })]
|
||||
public void CharArray(char[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new string[] { } })]
|
||||
[InlineData(new object[] { new string[] { "one" } })]
|
||||
[InlineData(new object[] { new string[] { "" } })]
|
||||
[InlineData(new object[] { new string[] { "a", "b", "c", "d" } })]
|
||||
[InlineData(new object[] { new string[] { "\r\n", "\t", "\"" } })]
|
||||
[InlineData(new object[] { new string[] { "longlonglonglonglonglonglonglonglong" } })]
|
||||
public void StringArray(string[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new bool[] { } })]
|
||||
[InlineData(new object[] { new bool[] { true } })]
|
||||
[InlineData(new object[] { new bool[] { true, false, false, true } })]
|
||||
public void BooleanArray(bool[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new byte[] { } })]
|
||||
[InlineData(new object[] { new byte[] { 0 } })]
|
||||
[InlineData(new object[] { new byte[] { byte.MaxValue, byte.MinValue, 4, 13 } })]
|
||||
public void ByteArray(byte[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new sbyte[] { } })]
|
||||
[InlineData(new object[] { new sbyte[] { 0 } })]
|
||||
[InlineData(new object[] { new sbyte[] { sbyte.MaxValue, sbyte.MinValue, 4, 13 } })]
|
||||
public void SByteArray(sbyte[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new short[] { } })]
|
||||
[InlineData(new object[] { new short[] { 0 } })]
|
||||
[InlineData(new object[] { new short[] { short.MaxValue, short.MinValue, 4, 13 } })]
|
||||
public void ShortArray(short[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new ushort[] { } })]
|
||||
[InlineData(new object[] { new ushort[] { 0 } })]
|
||||
[InlineData(new object[] { new ushort[] { ushort.MaxValue, ushort.MinValue, 4, 13 } })]
|
||||
public void UShortArray(ushort[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new int[] { } })]
|
||||
[InlineData(new object[] { new int[] { 0 } })]
|
||||
[InlineData(new object[] { new int[] { int.MaxValue, int.MinValue, 4, 13 } })]
|
||||
public void IntArray(int[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new uint[] { } })]
|
||||
[InlineData(new object[] { new uint[] { 0 } })]
|
||||
[InlineData(new object[] { new uint[] { uint.MaxValue, uint.MinValue, 4, 13 } })]
|
||||
public void UIntArray(uint[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new long[] { } })]
|
||||
[InlineData(new object[] { new long[] { 0 } })]
|
||||
[InlineData(new object[] { new long[] { long.MaxValue, long.MinValue, 4, 13 } })]
|
||||
public void LongArray(long[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new ulong[] { } })]
|
||||
[InlineData(new object[] { new ulong[] { 0 } })]
|
||||
[InlineData(new object[] { new ulong[] { ulong.MaxValue, ulong.MinValue, 4, 13 } })]
|
||||
public void ULongArray(ulong[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new float[] { } })]
|
||||
[InlineData(new object[] { new float[] { 0 } })]
|
||||
[InlineData(new object[] { new float[] { float.MaxValue, float.MinValue, 4, 13 } })]
|
||||
[InlineData(new object[] { new float[] { float.Epsilon } })]
|
||||
public void FloatArray(float[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new double[] { } })]
|
||||
[InlineData(new object[] { new double[] { 0 } })]
|
||||
[InlineData(new object[] { new double[] { double.MaxValue, double.MinValue, 4, 13 } })]
|
||||
[InlineData(new object[] { new double[] { double.Epsilon } })]
|
||||
public void DoubleArray(double[] data)
|
||||
{
|
||||
VerifySerialization(data);
|
||||
}
|
||||
|
||||
private static void VerifySerialization(Array data)
|
||||
{
|
||||
var reflectionBasedResult = System.Text.Json.JsonSerializer.Serialize(data);
|
||||
var rawResult = TagTransformerJsonHelper.JsonSerializeArrayTag(data);
|
||||
|
||||
Assert.Equal(reflectionBasedResult, rawResult);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue