Forcing Encoding.UTF8.GetString to throw an ArgumentException

Viewed 683

From the Encoding.GetString(Byte[]) MSDN documentation I find that it can throw an ArgumentException if:

The byte array contains invalid Unicode code points.

What test data can I throw at the method to cause such an exception?

I started trying a couple of inputs based on this other question about "invalid unicode characters", e.g.:

[Fact]
public void Checkit()
{
    // Does not throw an ArgumentException :'(
    var result = Encoding.UTF8.GetString(new byte[] { 0x80, 0x81 });
}

and

[Fact]
public void Checkit()
{
    // Does not throw an ArgumentException :'(
    var result = Encoding.UTF8.GetString(new byte[] { 0xc2, 0xc2 });
}

but neither Fact fails with an ArgumentException.

I also found a whole bunch of supposedly invalid byte sequences in the dotnet runtime repo tests which won't throw said ArgumentException (upon testing a couple).

The trigger for me asking is that I have code that uses GetString(Byte[]) and I want to see how it handles bad input by writing a unit test for it. But the reason for me asking is really curiosity (I can surely rewrite my unit test slightly to fix my immediate problem).

What "invalid Unicode code points" can I throw at Encoding.UTF8.GetString(Byte[]) to cause an ArgumentException?

1 Answers

The UTF8Encoding class is capable of throwing an exception but apparently it doesn't mention that you need an instance configured to throw one, and the default instance (Encoding.UTF8) is not configured that way.

Modifying your Facts ever so slightly...

[Fact]
public void Checkit()
{
    // Throws DecoderFallbackException
    var result = new UTF8Encoding(false, true).GetString(new byte[] { 0x80, 0x81 });
}

[Fact]
public void Checkit()
{
    // Throws DecoderFallbackException
    var result = new UTF8Encoding(false, true).GetString(new byte[] { 0xc2, 0xc2 });
}

The first argument (encoderShouldEmitUTF8Identifier) won't affect these tests because it has to do with the inverse operation. If you're also looking at how GetBytes works, pass false to omit the preamble or true to include it (which is how Encoding.UTF8 is configured).

The exception type you'll get is one of the other exception types documented, DecoderFallbackException, which is thrown when:

A fallback occurred (for more information, see Character Encoding in .NET)
-and-
DecoderFallback is set to DecoderExceptionFallback.

So if you can change whatever DecoderFallback is, you might be able to get that ArgumentException you were looking for.

Apparently, as you discovered on your own, DecoderFallbackException is a subclass of ArgumentException, so you're all set.

Related