From 0e63a14e183cabf3f2c29e13fc484c67c25b1f22 Mon Sep 17 00:00:00 2001 From: Tomas Matousek Date: Thu, 16 Jun 2016 16:01:05 -0700 Subject: [PATCH] Add more encoder tests and polish APIs Commit migrated from https://github.com/dotnet/corefx/commit/869c71aac74d31218a72a05d29d081655b2ce29d --- .../src/Resources/Strings.resx | 3 + .../src/System.Reflection.Metadata.csproj | 1 + .../src/System/Reflection/Metadata/BlobBuilder.cs | 4 +- .../src/System/Reflection/Metadata/BlobWriter.cs | 4 +- .../System/Reflection/Metadata/BlobWriterImpl.cs | 13 +- .../Metadata/Ecma335/Encoding/BlobEncoders.cs | 117 +++- .../Ecma335/Encoding/FunctionPointerAttributes.cs | 13 + .../Reflection/Metadata/Ecma335/MetadataTokens.cs | 3 +- .../src/System/Reflection/Throw.cs | 12 + .../tests/Metadata/BlobTests.cs | 16 + .../Metadata/Ecma335/Encoding/BlobEncodersTests.cs | 709 ++++++++++++++++++++- 11 files changed, 856 insertions(+), 39 deletions(-) create mode 100644 src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/FunctionPointerAttributes.cs diff --git a/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx b/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx index 49d2139..dd0eb43 100644 --- a/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx +++ b/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx @@ -402,6 +402,9 @@ Expected non-empty list. + + Expected non-empty string. + Specified readers must be minimal delta metadata readers. diff --git a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj index 7d662d8..7d32f56 100644 --- a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj +++ b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj @@ -37,6 +37,7 @@ + diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs index 5f3aa8e..2b08bc5 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs @@ -1114,11 +1114,11 @@ namespace System.Reflection.Metadata /// /// Otherwise, encode as a 4-byte integer, with bit 31 set, bit 30 set, bit 29 clear (value held in bits 28 through 0). /// - /// can't be represented as a compressed integer. + /// can't be represented as a compressed unsigned integer. /// Builder is not writable, it has been linked with another one. public void WriteCompressedInteger(int value) { - BlobWriterImpl.WriteCompressedInteger(this, value); + BlobWriterImpl.WriteCompressedInteger(this, unchecked((uint)value)); } /// diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriter.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriter.cs index 0093d8c..0dbf790 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriter.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriter.cs @@ -511,10 +511,10 @@ namespace System.Reflection.Metadata /// /// Otherwise, encode as a 4-byte integer, with bit 31 set, bit 30 set, bit 29 clear (value held in bits 28 through 0). /// - /// can't be represented as a compressed signed integer. + /// can't be represented as a compressed unsigned integer. public void WriteCompressedInteger(int value) { - BlobWriterImpl.WriteCompressedInteger(ref this, value); + BlobWriterImpl.WriteCompressedInteger(ref this, unchecked((uint)value)); } /// diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriterImpl.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriterImpl.cs index 1436f986a..d2dd33c 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriterImpl.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriterImpl.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Diagnostics; -using System.Reflection; -using System.Runtime.CompilerServices; namespace System.Reflection.Metadata { @@ -14,6 +11,8 @@ namespace System.Reflection.Metadata internal const int SingleByteCompressedIntegerMaxValue = 0x7f; internal const int TwoByteCompressedIntegerMaxValue = 0x3fff; internal const int MaxCompressedIntegerValue = 0x1fffffff; + internal const int MinSignedCompressedIntegerValue = unchecked((int)0xF0000000); + internal const int MaxSignedCompressedIntegerValue = 0x0FFFFFFF; internal static int GetCompressedIntegerSize(int value) { @@ -32,7 +31,7 @@ namespace System.Reflection.Metadata return 4; } - internal static void WriteCompressedInteger(ref BlobWriter writer, int value) + internal static void WriteCompressedInteger(ref BlobWriter writer, uint value) { unchecked { @@ -46,7 +45,7 @@ namespace System.Reflection.Metadata } else if (value <= MaxCompressedIntegerValue) { - writer.WriteUInt32BE(0xc0000000 | (uint)value); + writer.WriteUInt32BE(0xc0000000 | value); } else { @@ -55,7 +54,7 @@ namespace System.Reflection.Metadata } } - internal static void WriteCompressedInteger(BlobBuilder writer, int value) + internal static void WriteCompressedInteger(BlobBuilder writer, uint value) { unchecked { @@ -69,7 +68,7 @@ namespace System.Reflection.Metadata } else if (value <= MaxCompressedIntegerValue) { - writer.WriteUInt32BE(0xc0000000 | (uint)value); + writer.WriteUInt32BE(0xc0000000 | value); } else { diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/BlobEncoders.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/BlobEncoders.cs index 0aa02cc..b1a13ed 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/BlobEncoders.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/BlobEncoders.cs @@ -406,11 +406,35 @@ namespace System.Reflection.Metadata.Ecma335 Builder = builder; } + /// + /// Encodes null literal of type . + /// public void NullArray() { Builder.WriteInt32(-1); } + /// + /// Encodes constant literal. + /// + /// + /// Constant of type + /// , + /// , + /// , + /// , + /// , + /// , + /// , + /// , + /// , + /// , + /// , + /// (encoded as two-byte Unicode character), + /// (encoded as SerString), or + /// (encoded as the underlying integer value). + /// + /// Unexpected constant type. public void Constant(object value) { string str = value as string; @@ -424,8 +448,18 @@ namespace System.Reflection.Metadata.Ecma335 } } + /// + /// Encodes literal of type (possibly null). + /// + /// The name of the type, or null. + /// is empty. public void SystemType(string serializedTypeName) { + if (serializedTypeName != null && serializedTypeName.Length == 0) + { + Throw.ArgumentEmptyString(nameof(serializedTypeName)); + } + String(serializedTypeName); } @@ -461,6 +495,11 @@ namespace System.Reflection.Metadata.Ecma335 public LiteralsEncoder Count(int count) { + if (count < 0) + { + Throw.ArgumentOutOfRange(nameof(count)); + } + Builder.WriteUInt32((uint)count); return new LiteralsEncoder(Builder); } @@ -477,6 +516,9 @@ namespace System.Reflection.Metadata.Ecma335 public void Name(string name) { + if (name == null) Throw.ArgumentNull(nameof(name)); + if (name.Length == 0) Throw.ArgumentEmptyString(nameof(name)); + Builder.WriteSerializedString(name); } } @@ -492,7 +534,7 @@ namespace System.Reflection.Metadata.Ecma335 public NamedArgumentsEncoder Count(int count) { - if (unchecked((ushort)count) > ushort.MaxValue) + if (unchecked((uint)count) > ushort.MaxValue) { Throw.ArgumentOutOfRange(nameof(count)); } @@ -643,18 +685,14 @@ namespace System.Reflection.Metadata.Ecma335 public void Enum(string enumTypeName) { + if (enumTypeName == null) Throw.ArgumentNull(nameof(enumTypeName)); + if (enumTypeName.Length == 0) Throw.ArgumentEmptyString(nameof(enumTypeName)); + WriteTypeCode(SerializationTypeCode.Enum); Builder.WriteSerializedString(enumTypeName); } } - public enum FunctionPointerAttributes - { - None = SignatureAttributes.None, - HasThis = SignatureAttributes.Instance, - HasExplicitThis = SignatureAttributes.Instance | SignatureAttributes.ExplicitThis - } - public struct SignatureTypeEncoder { public BlobBuilder Builder { get; } @@ -905,8 +943,20 @@ namespace System.Reflection.Metadata.Ecma335 Builder = builder; } - public CustomModifiersEncoder AddModifier(bool isOptional, EntityHandle typeDefRefSpec) + /// + /// Encodes a custom modifier. + /// + /// , or . + /// Is optional modifier. + /// Encoder of subsequent modifiers. + /// is nil or of an unexpected kind. + public CustomModifiersEncoder AddModifier(EntityHandle type, bool isOptional) { + if (type.IsNil) + { + Throw.InvalidArgument_Handle(nameof(type)); + } + if (isOptional) { Builder.WriteByte((byte)SignatureTypeCode.OptionalModifier); @@ -916,7 +966,7 @@ namespace System.Reflection.Metadata.Ecma335 Builder.WriteByte((byte)SignatureTypeCode.RequiredModifier); } - Builder.WriteCompressedInteger(CodedIndex.TypeDefOrRefOrSpec(typeDefRefSpec)); + Builder.WriteCompressedInteger(CodedIndex.TypeDefOrRefOrSpec(type)); return this; } } @@ -930,16 +980,54 @@ namespace System.Reflection.Metadata.Ecma335 Builder = builder; } + /// + /// Encodes array shape. + /// + /// The number of dimensions in the array (shall be 1 or more). + /// + /// Dimension sizes. The array may be shorter than but not longer. + /// + /// + /// Dimension lower bounds, or default() to set all lower bounds to 0. + /// The array may be shorter than but not longer. + /// + /// + /// is outside of range [1, 0xffff], + /// smaller than .Length, or + /// smaller than .Length. + /// + /// is null. public void Shape(int rank, ImmutableArray sizes, ImmutableArray lowerBounds) { + // The specification doesn't impose a limit on the max number of array dimensions. + // The CLR supports <64. More than 0xffff is causing crashes in various tools (ildasm). + if (unchecked((uint)(rank - 1)) > ushort.MaxValue - 1) + { + Throw.ArgumentOutOfRange(nameof(rank)); + } + + if (sizes.IsDefault) + { + Throw.ArgumentNull(nameof(sizes)); + } + + // rank Builder.WriteCompressedInteger(rank); + + // sizes + if (sizes.Length > rank) + { + Throw.ArgumentOutOfRange(nameof(rank)); + } + Builder.WriteCompressedInteger(sizes.Length); foreach (int size in sizes) { Builder.WriteCompressedInteger(size); } - if (lowerBounds.IsDefault) + // lower bounds + if (lowerBounds.IsDefault) // TODO: remove -- update Roslyn { Builder.WriteCompressedInteger(rank); for (int i = 0; i < rank; i++) @@ -949,6 +1037,11 @@ namespace System.Reflection.Metadata.Ecma335 } else { + if (lowerBounds.Length > rank) + { + Throw.ArgumentOutOfRange(nameof(rank)); + } + Builder.WriteCompressedInteger(lowerBounds.Length); foreach (int lowerBound in lowerBounds) { @@ -998,7 +1091,7 @@ namespace System.Reflection.Metadata.Ecma335 public BlobBuilder Builder { get; } public bool HasVarArgs { get; } - public ParametersEncoder(BlobBuilder builder, bool hasVarArgs) + public ParametersEncoder(BlobBuilder builder, bool hasVarArgs = false) { Builder = builder; HasVarArgs = hasVarArgs; diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/FunctionPointerAttributes.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/FunctionPointerAttributes.cs new file mode 100644 index 0000000..d3f9c03 --- /dev/null +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/FunctionPointerAttributes.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Reflection.Metadata.Ecma335 +{ + public enum FunctionPointerAttributes + { + None = SignatureAttributes.None, + HasThis = SignatureAttributes.Instance, + HasExplicitThis = SignatureAttributes.Instance | SignatureAttributes.ExplicitThis + } +} diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataTokens.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataTokens.cs index 4a8d106..60f0c85 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataTokens.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataTokens.cs @@ -108,7 +108,8 @@ namespace System.Reflection.Metadata.Ecma335 throw new NotSupportedException(SR.CantGetOffsetForVirtualHeapHandle); default: - throw new ArgumentException(SR.InvalidHandle, nameof(handle)); + Throw.InvalidArgument_UnexpectedHandleKind(handle.Kind); + return 0; } } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Throw.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Throw.cs index d2fff4c..145bf87 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Throw.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Throw.cs @@ -37,6 +37,12 @@ namespace System.Reflection } [MethodImpl(MethodImplOptions.NoInlining)] + internal static Exception InvalidArgument_Handle(string parameterName) + { + throw new ArgumentException(SR.Format(SR.InvalidHandle), parameterName); + } + + [MethodImpl(MethodImplOptions.NoInlining)] internal static void SignatureNotVarArg() { throw new InvalidOperationException(SR.SignatureNotVarArg); @@ -85,6 +91,12 @@ namespace System.Reflection } [MethodImpl(MethodImplOptions.NoInlining)] + internal static void ArgumentEmptyString(string parameterName) + { + throw new ArgumentException(SR.ExpectedNonEmptyString, parameterName); + } + + [MethodImpl(MethodImplOptions.NoInlining)] internal static void ValueArgumentNull() { throw new ArgumentNullException("value"); diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/BlobTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/BlobTests.cs index 50d6b70..701a421 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Metadata/BlobTests.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/BlobTests.cs @@ -688,6 +688,14 @@ namespace System.Reflection.Metadata.Tests TestCompressedUnsignedInteger(new byte[] { 0xBF, 0xFF }, 0x3FFF); TestCompressedUnsignedInteger(new byte[] { 0xC0, 0x00, 0x40, 0x00 }, 0x4000); TestCompressedUnsignedInteger(new byte[] { 0xDF, 0xFF, 0xFF, 0xFF }, 0x1FFFFFFF); + + var writer = new BlobWriter(4); + var builder = new BlobBuilder(); + + Assert.Throws(() => writer.WriteCompressedInteger(-1)); + Assert.Throws(() => writer.WriteCompressedInteger(BlobWriterImpl.MaxCompressedIntegerValue + 1)); + Assert.Throws(() => builder.WriteCompressedInteger(-1)); + Assert.Throws(() => builder.WriteCompressedInteger(BlobWriterImpl.MaxCompressedIntegerValue + 1)); } [Fact] @@ -705,6 +713,14 @@ namespace System.Reflection.Metadata.Tests TestCompressedSignedInteger(new byte[] { 0x80, 0x01 }, -8192); TestCompressedSignedInteger(new byte[] { 0xDF, 0xFF, 0xFF, 0xFE }, 268435455); TestCompressedSignedInteger(new byte[] { 0xC0, 0x00, 0x00, 0x01 }, -268435456); + + var writer = new BlobWriter(4); + var builder = new BlobBuilder(); + + Assert.Throws(() => writer.WriteCompressedSignedInteger(BlobWriterImpl.MinSignedCompressedIntegerValue - 1)); + Assert.Throws(() => writer.WriteCompressedSignedInteger(BlobWriterImpl.MaxSignedCompressedIntegerValue + 1)); + Assert.Throws(() => builder.WriteCompressedSignedInteger(BlobWriterImpl.MinSignedCompressedIntegerValue - 1)); + Assert.Throws(() => builder.WriteCompressedSignedInteger(BlobWriterImpl.MaxSignedCompressedIntegerValue + 1)); } [Fact] diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/BlobEncodersTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/BlobEncodersTests.cs index 680724f..299c7f5 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/BlobEncodersTests.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/BlobEncodersTests.cs @@ -21,6 +21,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new BlobEncoder(b); + Assert.Same(b, e.Builder); var s = e.FieldSignature(); AssertEx.Equal(new byte[] { 0x06 }, b.ToArray()); @@ -32,6 +33,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new BlobEncoder(b); + Assert.Same(b, e.Builder); var s = e.MethodSpecificationSignature(genericArgumentCount: 0); AssertEx.Equal(new byte[] { 0x0A, 0x00 }, b.ToArray()); @@ -51,6 +53,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new BlobEncoder(b); + Assert.Same(b, e.Builder); var s = e.MethodSignature(); AssertEx.Equal(new byte[] { 0x00 }, b.ToArray()); @@ -85,6 +88,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new BlobEncoder(b); + Assert.Same(b, e.Builder); var s = e.PropertySignature(); AssertEx.Equal(new byte[] { 0x08 }, b.ToArray()); @@ -103,6 +107,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new BlobEncoder(b); + Assert.Same(b, e.Builder); FixedArgumentsEncoder fixedArgs; CustomAttributeNamedArgumentsEncoder namedArgs; @@ -129,6 +134,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new BlobEncoder(b); + Assert.Same(b, e.Builder); var s = e.LocalVariableSignature(variableCount: 0); AssertEx.Equal(new byte[] { 0x07, 0x00 }, b.ToArray()); @@ -148,6 +154,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new BlobEncoder(b); + Assert.Same(b, e.Builder); var s = e.TypeSpecificationSignature(); AssertEx.Equal(new byte[0], b.ToArray()); @@ -159,6 +166,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new BlobEncoder(b); + Assert.Same(b, e.Builder); var s = e.PermissionSetBlob(attributeCount: 0); AssertEx.Equal(new byte[] { 0x2e, 0x00 }, b.ToArray()); @@ -179,6 +187,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new BlobEncoder(b); + Assert.Same(b, e.Builder); var s = e.PermissionSetArguments(argumentCount: 0); AssertEx.Equal(new byte[] { 0x00 }, b.ToArray()); @@ -199,6 +208,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new MethodSignatureEncoder(b, hasVarArgs: false); + Assert.Same(b, e.Builder); ReturnTypeEncoder returnType; ParametersEncoder parameters; @@ -229,6 +239,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new LocalVariablesEncoder(b); + Assert.Same(b, e.Builder); var s = e.AddVariable(); AssertEx.Equal(new byte[0], b.ToArray()); @@ -240,6 +251,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new LocalVariableTypeEncoder(b); + Assert.Same(b, e.Builder); var s = e.CustomModifiers(); AssertEx.Equal(new byte[0], b.ToArray()); @@ -251,6 +263,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new LocalVariableTypeEncoder(b); + Assert.Same(b, e.Builder); var s = e.Type(); AssertEx.Equal(new byte[0], b.ToArray()); @@ -278,6 +291,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new LocalVariableTypeEncoder(b); + Assert.Same(b, e.Builder); e.TypedReference(); AssertEx.Equal(new byte[] { 0x16 }, b.ToArray()); @@ -288,6 +302,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new ParameterTypeEncoder(b); + Assert.Same(b, e.Builder); var s = e.CustomModifiers(); AssertEx.Equal(new byte[0], b.ToArray()); @@ -299,6 +314,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new ParameterTypeEncoder(b); + Assert.Same(b, e.Builder); var s = e.Type(); AssertEx.Equal(new byte[0], b.ToArray()); @@ -316,6 +332,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new ParameterTypeEncoder(b); + Assert.Same(b, e.Builder); e.TypedReference(); AssertEx.Equal(new byte[] { 0x16 }, b.ToArray()); @@ -326,6 +343,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new PermissionSetEncoder(b); + Assert.Same(b, e.Builder); var s = e.AddPermission("ABCD", ImmutableArray.Create(1, 2, 3)); Assert.Same(b, s.Builder); @@ -360,6 +378,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new GenericTypeArgumentsEncoder(b); + Assert.Same(b, e.Builder); var s = e.AddArgument(); AssertEx.Equal(new byte[0], b.ToArray()); @@ -371,23 +390,506 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new FixedArgumentsEncoder(b); + Assert.Same(b, e.Builder); var s = e.AddArgument(); AssertEx.Equal(new byte[0], b.ToArray()); Assert.Same(b, s.Builder); } - // TODO: - // LiteralEncoder - // ScalarEncoder - // LiteralsEncoder - // VectorEncoder - // NameEncoder - // CustomAttributeNamedArgumentsEncoder - // NamedArgumentsEncoder - // NamedArgumentTypeEncoder - // CustomAttributeArrayTypeEncoder - // CustomAttributeElementTypeEncoder + [Fact] + public void LiteralEncoder_Vector() + { + var b = new BlobBuilder(); + var e = new LiteralEncoder(b); + Assert.Same(b, e.Builder); + + var s = e.Vector(); + AssertEx.Equal(new byte[0], b.ToArray()); + Assert.Same(b, s.Builder); + } + + [Fact] + public void LiteralEncoder_TaggedVector() + { + var b = new BlobBuilder(); + var e = new LiteralEncoder(b); + Assert.Same(b, e.Builder); + + CustomAttributeArrayTypeEncoder arrayType; + VectorEncoder vector; + e.TaggedVector(out arrayType, out vector); + + AssertEx.Equal(new byte[0], b.ToArray()); + Assert.Same(b, arrayType.Builder); + Assert.Same(b, vector.Builder); + b.Clear(); + + e.TaggedVector( + at => Assert.Same(b, at.Builder), + v => Assert.Same(b, v.Builder)); + + Assert.Throws(() => e.TaggedVector(null, v => { })); + Assert.Throws(() => e.TaggedVector(at => { }, null)); + } + + [Fact] + public void LiteralEncoder_Scalar() + { + var b = new BlobBuilder(); + var e = new LiteralEncoder(b); + Assert.Same(b, e.Builder); + + var s = e.Scalar(); + AssertEx.Equal(new byte[0], b.ToArray()); + Assert.Same(b, s.Builder); + } + + [Fact] + public void LiteralEncoder_TaggedScalar() + { + var b = new BlobBuilder(); + var e = new LiteralEncoder(b); + Assert.Same(b, e.Builder); + + CustomAttributeElementTypeEncoder elementType; + ScalarEncoder scalar; + e.TaggedScalar(out elementType, out scalar); + + AssertEx.Equal(new byte[0], b.ToArray()); + Assert.Same(b, elementType.Builder); + Assert.Same(b, scalar.Builder); + b.Clear(); + + e.TaggedScalar( + et => Assert.Same(b, et.Builder), + s => Assert.Same(b, s.Builder)); + + Assert.Throws(() => e.TaggedScalar(null, s => { })); + Assert.Throws(() => e.TaggedScalar(et => { }, null)); + } + + [Fact] + public void ScalarEncoder_NullArray() + { + var b = new BlobBuilder(); + var e = new ScalarEncoder(b); + Assert.Same(b, e.Builder); + + e.NullArray(); + AssertEx.Equal(new byte[] { 0xff, 0xff, 0xff, 0xff }, b.ToArray()); + } + + [Fact] + public void ScalarEncoder_Constant() + { + var b = new BlobBuilder(); + var e = new ScalarEncoder(b); + Assert.Same(b, e.Builder); + + e.Constant(null); + AssertEx.Equal(new byte[] { 0xff }, b.ToArray()); + b.Clear(); + + e.Constant(""); + AssertEx.Equal(new byte[] { 0x00 }, b.ToArray()); + b.Clear(); + + e.Constant("abc"); + AssertEx.Equal(new byte[] { 0x03, 0x61, 0x62, 0x63 }, b.ToArray()); + b.Clear(); + + e.Constant("\ud800"); // unpaired surrogate + AssertEx.Equal(new byte[] { 0x03, 0xED, 0xA0, 0x80 }, b.ToArray()); + b.Clear(); + + e.Constant(true); + AssertEx.Equal(new byte[] { 0x01 }, b.ToArray()); + b.Clear(); + + e.Constant(HandleKind.UserString); + AssertEx.Equal(new byte[] { 0x70 }, b.ToArray()); + b.Clear(); + + e.Constant((byte)0xAB); + AssertEx.Equal(new byte[] { 0xAB }, b.ToArray()); + b.Clear(); + + e.Constant((sbyte)0x12); + AssertEx.Equal(new byte[] { 0x12 }, b.ToArray()); + b.Clear(); + + e.Constant((ushort)0xABCD); + AssertEx.Equal(new byte[] { 0xCD, 0xAB }, b.ToArray()); + b.Clear(); + + e.Constant((short)0x1234); + AssertEx.Equal(new byte[] { 0x34, 0x12 }, b.ToArray()); + b.Clear(); + + e.Constant((char)0xABCD); + AssertEx.Equal(new byte[] { 0xCD, 0xAB }, b.ToArray()); + b.Clear(); + + e.Constant(0xABCD); + AssertEx.Equal(new byte[] { 0xCD, 0xAB, 0x00, 0x00 }, b.ToArray()); + b.Clear(); + + e.Constant((uint)0xABCD); + AssertEx.Equal(new byte[] { 0xCD, 0xAB, 0x00, 0x00 }, b.ToArray()); + b.Clear(); + + e.Constant(0x1122334455667788); + AssertEx.Equal(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, b.ToArray()); + b.Clear(); + + e.Constant(0xAABBCCDDEEFF1122); + AssertEx.Equal(new byte[] { 0x22, 0x11, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA }, b.ToArray()); + b.Clear(); + + e.Constant(0.1f); + AssertEx.Equal(new byte[] { 0xCD, 0xCC, 0xCC, 0x3D }, b.ToArray()); + b.Clear(); + + e.Constant(0.1); + AssertEx.Equal(new byte[] { 0x9A, 0x99, 0x99, 0x99, 0x99, 0x99, 0xB9, 0x3F }, b.ToArray()); + b.Clear(); + } + + [Fact] + public void ScalarEncoder_Type() + { + var b = new BlobBuilder(); + var e = new ScalarEncoder(b); + Assert.Same(b, e.Builder); + + e.SystemType(null); + AssertEx.Equal(new byte[] { 0xff }, b.ToArray()); + b.Clear(); + + e.SystemType("abc"); + AssertEx.Equal(new byte[] { 0x03, 0x61, 0x62, 0x63 }, b.ToArray()); + b.Clear(); + + e.SystemType("\ud800"); // unpaired surrogate + AssertEx.Equal(new byte[] { 0x03, 0xED, 0xA0, 0x80 }, b.ToArray()); + b.Clear(); + + Assert.Throws(() => e.SystemType("")); + } + + [Fact] + public void LiteralsEncoder_Scalar() + { + var b = new BlobBuilder(); + var e = new LiteralsEncoder(b); + Assert.Same(b, e.Builder); + + var s = e.AddLiteral(); + AssertEx.Equal(new byte[0], b.ToArray()); + Assert.Same(b, s.Builder); + } + + [Fact] + public void VectorEncoder_Count() + { + var b = new BlobBuilder(); + var e = new VectorEncoder(b); + Assert.Same(b, e.Builder); + + var s = e.Count(0); + AssertEx.Equal(new byte[] { 0x00, 0x00, 0x00, 0x00 }, b.ToArray()); + Assert.Same(b, s.Builder); + b.Clear(); + + s = e.Count(int.MaxValue); + AssertEx.Equal(new byte[] { 0xFF, 0xFF, 0xFF, 0x7F }, b.ToArray()); + Assert.Same(b, s.Builder); + b.Clear(); + + Assert.Throws(() => e.Count(-1)); + } + + [Fact] + public void NameEncoder_Name() + { + var b = new BlobBuilder(); + var e = new NameEncoder(b); + Assert.Same(b, e.Builder); + + e.Name("abc"); + AssertEx.Equal(new byte[] { 0x03, 0x61, 0x62, 0x63 }, b.ToArray()); + b.Clear(); + + e.Name("\ud800"); // unpaired surrogate + AssertEx.Equal(new byte[] { 0x03, 0xED, 0xA0, 0x80 }, b.ToArray()); + b.Clear(); + + Assert.Throws(() => e.Name(null)); + Assert.Throws(() => e.Name("")); + } + + [Fact] + public void CustomAttributeNamedArgumentsEncoder_Count() + { + var b = new BlobBuilder(); + var e = new CustomAttributeNamedArgumentsEncoder(b); + Assert.Same(b, e.Builder); + + e.Count(0); + AssertEx.Equal(new byte[] { 0x00, 0x00 }, b.ToArray()); + b.Clear(); + + e.Count(ushort.MaxValue); + AssertEx.Equal(new byte[] { 0xff, 0xff }, b.ToArray()); + b.Clear(); + + Assert.Throws(() => e.Count(-1)); + Assert.Throws(() => e.Count(ushort.MaxValue + 1)); + } + + [Fact] + public void NamedArgumentsEncoder_AddArgument() + { + var b = new BlobBuilder(); + var e = new NamedArgumentsEncoder(b); + Assert.Same(b, e.Builder); + + NamedArgumentTypeEncoder type; + NameEncoder name; + LiteralEncoder literal; + e.AddArgument(true, out type, out name, out literal); + + AssertEx.Equal(new byte[] { 0x53 }, b.ToArray()); + Assert.Same(b, type.Builder); + Assert.Same(b, name.Builder); + Assert.Same(b, literal.Builder); + b.Clear(); + + e.AddArgument(false, + t => Assert.Same(b, t.Builder), + n => Assert.Same(b, n.Builder), + l => Assert.Same(b, l.Builder)); + AssertEx.Equal(new byte[] { 0x54 }, b.ToArray()); + b.Clear(); + + Assert.Throws(() => e.AddArgument(true, null, _ => { }, _ => { })); + Assert.Throws(() => e.AddArgument(true, _ => { }, null, _ => { })); + Assert.Throws(() => e.AddArgument(true, _ => { }, _ => { }, null)); + } + + [Fact] + public void NamedArgumentTypeEncoder_ScalarType() + { + var b = new BlobBuilder(); + var e = new NamedArgumentTypeEncoder(b); + Assert.Same(b, e.Builder); + + e.ScalarType(); + AssertEx.Equal(new byte[0], b.ToArray()); + b.Clear(); + } + + [Fact] + public void NamedArgumentTypeEncoder_Object() + { + var b = new BlobBuilder(); + var e = new NamedArgumentTypeEncoder(b); + Assert.Same(b, e.Builder); + + e.Object(); + AssertEx.Equal(new byte[] { 0x51 }, b.ToArray()); + b.Clear(); + } + + [Fact] + public void NamedArgumentTypeEncoder_SZArray() + { + var b = new BlobBuilder(); + var e = new NamedArgumentTypeEncoder(b); + Assert.Same(b, e.Builder); + + e.SZArray(); + AssertEx.Equal(new byte[0], b.ToArray()); + b.Clear(); + } + + [Fact] + public void CustomAttributeArrayTypeEncoder_ObjectArray() + { + var b = new BlobBuilder(); + var e = new CustomAttributeArrayTypeEncoder(b); + Assert.Same(b, e.Builder); + + e.ObjectArray(); + AssertEx.Equal(new byte[] { 0x1D, 0x51 }, b.ToArray()); + b.Clear(); + } + + [Fact] + public void CustomAttributeArrayTypeEncoder_ElementType() + { + var b = new BlobBuilder(); + var e = new CustomAttributeArrayTypeEncoder(b); + Assert.Same(b, e.Builder); + + var s = e.ElementType(); + AssertEx.Equal(new byte[] { 0x1D }, b.ToArray()); + Assert.Same(b, s.Builder); + b.Clear(); + } + + [Fact] + public void CustomAttributeElementTypeEncoder_Primitives() + { + var b = new BlobBuilder(); + var e = new CustomAttributeElementTypeEncoder(b); + Assert.Same(b, e.Builder); + + e.Boolean(); + AssertEx.Equal(new byte[] { 0x02 }, b.ToArray()); + b.Clear(); + + e.Char(); + AssertEx.Equal(new byte[] { 0x03 }, b.ToArray()); + b.Clear(); + + e.SByte(); + AssertEx.Equal(new byte[] { 0x04 }, b.ToArray()); + b.Clear(); + + e.Byte(); + AssertEx.Equal(new byte[] { 0x05 }, b.ToArray()); + b.Clear(); + + e.Int16(); + AssertEx.Equal(new byte[] { 0x06 }, b.ToArray()); + b.Clear(); + + e.UInt16(); + AssertEx.Equal(new byte[] { 0x07 }, b.ToArray()); + b.Clear(); + + e.Int32(); + AssertEx.Equal(new byte[] { 0x08 }, b.ToArray()); + b.Clear(); + + e.UInt32(); + AssertEx.Equal(new byte[] { 0x09 }, b.ToArray()); + b.Clear(); + + e.Int64(); + AssertEx.Equal(new byte[] { 0x0A }, b.ToArray()); + b.Clear(); + + e.UInt64(); + AssertEx.Equal(new byte[] { 0x0B }, b.ToArray()); + b.Clear(); + + e.Single(); + AssertEx.Equal(new byte[] { 0x0C }, b.ToArray()); + b.Clear(); + + e.Double(); + AssertEx.Equal(new byte[] { 0x0D }, b.ToArray()); + b.Clear(); + + e.String(); + AssertEx.Equal(new byte[] { 0x0E }, b.ToArray()); + b.Clear(); + } + + [Fact] + public void CustomAttributeElementTypeEncoder_PrimitiveType() + { + var b = new BlobBuilder(); + var e = new CustomAttributeElementTypeEncoder(b); + Assert.Same(b, e.Builder); + + e.PrimitiveType(PrimitiveSerializationTypeCode.Boolean); + AssertEx.Equal(new byte[] { 0x02 }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.Char); + AssertEx.Equal(new byte[] { 0x03 }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.SByte); + AssertEx.Equal(new byte[] { 0x04 }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.Byte); + AssertEx.Equal(new byte[] { 0x05 }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.Int16); + AssertEx.Equal(new byte[] { 0x06 }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.UInt16); + AssertEx.Equal(new byte[] { 0x07 }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.Int32); + AssertEx.Equal(new byte[] { 0x08 }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.UInt32); + AssertEx.Equal(new byte[] { 0x09 }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.Int64); + AssertEx.Equal(new byte[] { 0x0A }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.UInt64); + AssertEx.Equal(new byte[] { 0x0B }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.Single); + AssertEx.Equal(new byte[] { 0x0C }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.Double); + AssertEx.Equal(new byte[] { 0x0D }, b.ToArray()); + b.Clear(); + + e.PrimitiveType(PrimitiveSerializationTypeCode.String); + AssertEx.Equal(new byte[] { 0x0E }, b.ToArray()); + b.Clear(); + + Assert.Throws(() => e.PrimitiveType((PrimitiveSerializationTypeCode)255)); + } + + [Fact] + public void CustomAttributeElementTypeEncoder_SystemType() + { + var b = new BlobBuilder(); + var e = new CustomAttributeElementTypeEncoder(b); + Assert.Same(b, e.Builder); + + e.SystemType(); + AssertEx.Equal(new byte[] { 0x50 }, b.ToArray()); + } + + [Fact] + public void CustomAttributeElementTypeEncoder_Enum() + { + var b = new BlobBuilder(); + var e = new CustomAttributeElementTypeEncoder(b); + Assert.Same(b, e.Builder); + + e.Enum("abc"); + AssertEx.Equal(new byte[] { 0x55, 0x03, 0x61, 0x62, 0x63 }, b.ToArray()); + b.Clear(); + + e.Enum("\ud800"); // unpaired surrogate + AssertEx.Equal(new byte[] { 0x55, 0x03, 0xED, 0xA0, 0x80 }, b.ToArray()); + b.Clear(); + + Assert.Throws(() => e.Enum(null)); + Assert.Throws(() => e.Enum("")); + } [Fact] public void SignatureTypeEncoder_Primitives() @@ -567,6 +1069,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new SignatureTypeEncoder(b); + Assert.Same(b, e.Builder); e.Type(MetadataTokens.TypeDefinitionHandle(1), isValueType: true); AssertEx.Equal(new byte[] { 0x11, 0x04 }, b.ToArray()); @@ -590,6 +1093,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new SignatureTypeEncoder(b); + Assert.Same(b, e.Builder); var m = e.FunctionPointer( SignatureCallingConvention.CDecl, @@ -625,6 +1129,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new SignatureTypeEncoder(b); + Assert.Same(b, e.Builder); var m = e.GenericInstantiation(MetadataTokens.TypeDefinitionHandle(1), 1, true); Assert.Same(b, m.Builder); @@ -656,6 +1161,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new SignatureTypeEncoder(b); + Assert.Same(b, e.Builder); e.GenericMethodTypeParameter(0); AssertEx.Equal(new byte[] { 0x1E, 0x00 }, b.ToArray()); @@ -675,6 +1181,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new SignatureTypeEncoder(b); + Assert.Same(b, e.Builder); e.GenericTypeParameter(0); AssertEx.Equal(new byte[] { 0x13, 0x00 }, b.ToArray()); @@ -694,6 +1201,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new SignatureTypeEncoder(b); + Assert.Same(b, e.Builder); var p = e.Pointer(); AssertEx.Equal(new byte[] { 0x0F }, b.ToArray()); @@ -705,6 +1213,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new SignatureTypeEncoder(b); + Assert.Same(b, e.Builder); e.VoidPointer(); AssertEx.Equal(new byte[] { 0x0F, 0x01 }, b.ToArray()); @@ -715,6 +1224,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new SignatureTypeEncoder(b); + Assert.Same(b, e.Builder); var a = e.SZArray(); AssertEx.Equal(new byte[] { 0x1D }, b.ToArray()); @@ -726,15 +1236,184 @@ namespace System.Reflection.Metadata.Ecma335.Tests { var b = new BlobBuilder(); var e = new SignatureTypeEncoder(b); + Assert.Same(b, e.Builder); var a = e.CustomModifiers(); AssertEx.Equal(new byte[0], b.ToArray()); Assert.Same(b, a.Builder); } - // CustomModifiersEncoder - // ArrayShapeEncoder - // ReturnTypeEncoder - // ParametersEncoder + [Fact] + public void CustomModifiersEncoder_AddModifier() + { + var b = new BlobBuilder(); + var e = new CustomModifiersEncoder(b); + Assert.Same(b, e.Builder); + + var a = e.AddModifier(MetadataTokens.TypeDefinitionHandle(1), true); + AssertEx.Equal(new byte[] { 0x20, 0x04 }, b.ToArray()); + Assert.Same(b, a.Builder); + b.Clear(); + + e.AddModifier(MetadataTokens.TypeReferenceHandle(1), false); + AssertEx.Equal(new byte[] { 0x1f, 0x05 }, b.ToArray()); + b.Clear(); + + e.AddModifier(MetadataTokens.TypeSpecificationHandle(1), false); + AssertEx.Equal(new byte[] { 0x1f, 0x06 }, b.ToArray()); + b.Clear(); + + Assert.Throws(() => e.AddModifier(default(EntityHandle), true)); + Assert.Throws(() => e.AddModifier(default(TypeDefinitionHandle), true)); + Assert.Throws(() => e.AddModifier(default(TypeReferenceHandle), true)); + Assert.Throws(() => e.AddModifier(default(TypeSpecificationHandle), true)); + Assert.Throws(() => e.AddModifier(MetadataTokens.FieldDefinitionHandle(1), true)); + } + + [Fact] + public void ArrayShapeEncoder_Shape() + { + var b = new BlobBuilder(); + var e = new ArrayShapeEncoder(b); + Assert.Same(b, e.Builder); + + e.Shape(ushort.MaxValue, ImmutableArray.Empty, ImmutableArray.Empty); + AssertEx.Equal(new byte[] + { + 0xC0, 0x00, 0xFF, 0xFF, + 0x00, + 0x00 + }, b.ToArray()); + b.Clear(); + + e.Shape(3, ImmutableArray.Create(0x0A), ImmutableArray.Empty); + AssertEx.Equal(new byte[] + { + 0x03, + 0x01, 0x0A, + 0x00 + }, b.ToArray()); + b.Clear(); + + e.Shape(3, ImmutableArray.Create(0x0A, 0x0B), ImmutableArray.Create(0x02, 0x03)); + AssertEx.Equal(new byte[] + { + 0x03, + 0x02, 0x0A, 0x0B, + 0x02, 0x04, 0x06 + }, b.ToArray()); + b.Clear(); + + e.Shape(3, ImmutableArray.Empty, ImmutableArray.Create(-2, -1)); + AssertEx.Equal(new byte[] + { + 0x03, + 0x00, + 0x02, 0x7D, 0x7F + }, b.ToArray()); + b.Clear(); + + e.Shape(3, ImmutableArray.Create(BlobWriterImpl.MaxCompressedIntegerValue), ImmutableArray.Create(BlobWriterImpl.MinSignedCompressedIntegerValue, BlobWriterImpl.MaxSignedCompressedIntegerValue)); + AssertEx.Equal(new byte[] + { + 0x03, + 0x01, 0xDF, 0xFF, 0xFF, 0xFF, + 0x02, 0xC0, 0x00, 0x00, 0x01, 0xDF, 0xFF, 0xFF, 0xFE + }, b.ToArray()); + b.Clear(); + + Assert.Throws(() => e.Shape(1, default(ImmutableArray), ImmutableArray.Empty)); + Assert.Throws(() => e.Shape(0, ImmutableArray.Empty, ImmutableArray.Empty)); + Assert.Throws(() => e.Shape(-1, ImmutableArray.Empty, ImmutableArray.Empty)); + Assert.Throws(() => e.Shape(ushort.MaxValue + 1, ImmutableArray.Empty, ImmutableArray.Empty)); + Assert.Throws(() => e.Shape(1, ImmutableArray.Create(1,2,3), ImmutableArray.Empty)); + Assert.Throws(() => e.Shape(1, ImmutableArray.Empty, ImmutableArray.Create(1,2,3))); + Assert.Throws(() => e.Shape(1, ImmutableArray.Create(-1), ImmutableArray.Empty)); + Assert.Throws(() => e.Shape(1, ImmutableArray.Create(BlobWriterImpl.MaxCompressedIntegerValue + 1), ImmutableArray.Empty)); + Assert.Throws(() => e.Shape(1, ImmutableArray.Empty, ImmutableArray.Create(BlobWriterImpl.MinSignedCompressedIntegerValue - 1))); + Assert.Throws(() => e.Shape(1, ImmutableArray.Empty, ImmutableArray.Create(BlobWriterImpl.MaxSignedCompressedIntegerValue + 1))); + } + + [Fact] + public void ReturnTypeEncoder_CustomModifiers() + { + var b = new BlobBuilder(); + var e = new ReturnTypeEncoder(b); + Assert.Same(b, e.Builder); + + var s = e.CustomModifiers(); + AssertEx.Equal(new byte[0], b.ToArray()); + Assert.Same(b, s.Builder); + } + + [Fact] + public void ReturnTypeEncoder_Type() + { + var b = new BlobBuilder(); + var e = new ReturnTypeEncoder(b); + Assert.Same(b, e.Builder); + + var s = e.Type(true); + AssertEx.Equal(new byte[] { 0x10 }, b.ToArray()); + Assert.Same(b, s.Builder); + b.Clear(); + + e.Type(false); + AssertEx.Equal(new byte[0], b.ToArray()); + b.Clear(); + + e.Type(); + AssertEx.Equal(new byte[0], b.ToArray()); + b.Clear(); + } + + [Fact] + public void ReturnTypeEncoder_TypedReference() + { + var b = new BlobBuilder(); + var e = new ReturnTypeEncoder(b); + Assert.Same(b, e.Builder); + + e.TypedReference(); + AssertEx.Equal(new byte[] { 0x16 }, b.ToArray()); + } + + [Fact] + public void ReturnTypeEncoder_Void() + { + var b = new BlobBuilder(); + var e = new ReturnTypeEncoder(b); + Assert.Same(b, e.Builder); + + e.Void(); + AssertEx.Equal(new byte[] { 0x01 }, b.ToArray()); + } + + [Fact] + public void ParametersEncoder_AddParameter() + { + var b = new BlobBuilder(); + var e = new ParametersEncoder(b); + Assert.Same(b, e.Builder); + + var s = e.AddParameter(); + AssertEx.Equal(new byte[0], b.ToArray()); + Assert.Same(b, s.Builder); + } + + [Fact] + public void ParametersEncoder_StartVarArgs() + { + var b = new BlobBuilder(); + var e = new ParametersEncoder(b, hasVarArgs: true); + Assert.Same(b, e.Builder); + + var s = e.StartVarArgs(); + AssertEx.Equal(new byte[] { 0x41 }, b.ToArray()); + Assert.Same(b, s.Builder); + Assert.False(s.HasVarArgs); + + Assert.Throws(() => s.StartVarArgs()); + } } } -- 2.7.4