C# 生成对UTF-8编码和解码有效的随机字符串
出于测试目的,我需要生成一个随机字符串,然后将其编码到字节数组中,以便通过Web传输并解码回结果字符串。测试使用NUnit框架将原始字符串与结果字符串进行比较。由于编码的字节数组必须对Web友好,因此使用UTF-8编码 字符串由C# 生成对UTF-8编码和解码有效的随机字符串,c#,string,random,utf-8,encode,C#,String,Random,Utf 8,Encode,出于测试目的,我需要生成一个随机字符串,然后将其编码到字节数组中,以便通过Web传输并解码回结果字符串。测试使用NUnit框架将原始字符串与结果字符串进行比较。由于编码的字节数组必须对Web友好,因此使用UTF-8编码 字符串由Encoder.GetBytes从UTF8Encoding编码到字节数组中。字节数组由解码器解码为字符串。GetChars来自UTF8Encoding 原始字符串需要随机生成并包含任意字符序列,可以使用UTF-8编码对其进行编码/解码 我第一次尝试生成字符串是: p
Encoder.GetBytes
从UTF8Encoding
编码到字节数组中。字节数组由解码器解码为字符串。GetChars
来自UTF8Encoding
原始字符串需要随机生成并包含任意字符序列,可以使用UTF-8编码对其进行编码/解码
我第一次尝试生成字符串是:
public static String RandomString(Random rnd, Int32 length) {
StringBuilder str = new StringBuilder(length);
for (int i = 0; i < length; i++)
str.Append((char)rnd.Next(char.MinValue, char.MaxValue));
return str.ToString();
}
我使用下面的代码生成随机的UTF-8字符字节序列。我不能保证它捕获了UTF-8规范的任何方面,但它对于我的测试目的是有价值的,所以我将它发布在这里
private static readonly (int, int)[] HeadByteDefinitions =
{
(1 << 7, 0b0000_0000),
(1 << 5, 0b1100_0000),
(1 << 4, 0b1110_0000),
(1 << 3, 0b1111_0000)
};
static byte[] RandomUtf8Char(Random gen)
{
const int totalNumberOfUtf8Chars = (1 << 7) + (1 << 11) + (1 << 16) + (1 << 21);
int tailByteCnt;
var rnd = gen.Next(totalNumberOfUtf8Chars);
if (rnd < (1 << 7))
tailByteCnt = 0;
else if (rnd < (1 << 7) + (1 << 11))
tailByteCnt = 1;
else if (rnd < (1 << 7) + (1 << 11) + (1 << 16))
tailByteCnt = 2;
else
tailByteCnt = 3;
var (range, offset) = HeadByteDefinitions[tailByteCnt];
var headByte = Convert.ToByte(gen.Next(range) + offset);
var tailBytes = Enumerable.Range(0, tailByteCnt)
.Select(_ => Convert.ToByte(gen.Next(1 << 6) + 0b1000_0000));
return new[] {headByte}.Concat(tailBytes).ToArray();
}
private static readonly(int,int)[]头字节定义=
{
(1)我不认为随机字符串是单元测试的好方法,它从理论上打破了可重复的原则:测试每次都应该产生相同的结果。每次。测试不应该依赖于不可控的参数。我认为随机测试来自懒惰,为边缘情况创建实际测试。随机生成器是alw使用相同的密封值创建数组,因此每次测试运行时都会产生相同的结果,即测试是可重复的。如果它是有效的Unicode字符串,最好只使用U+0000和U+D7FF之间的值,因为U+E000上还有其他非法值。无论如何,您说“解码字节数组”。您能显示字节数组吗?在您的示例中只有UTF-16字符串。当然,U+FFFF以上的值对于任何Unicode测试都是必要的。如果只是随机噪声,则将每个字符创建为0到10FFFF之间的随机元素,并拒绝代理字符和非字符。列出了后者的所有66个。然后转换为UTF-8。不包括v高于0xE000的值有助于解决解码失败的问题。
public static Encoder Utf8Encode = new UTF8Encoding(false, true).GetEncoder();
public static Decoder Utf8Decode = new UTF8Encoding(false, true).GetDecoder();
public unsafe void TestString(Random rnd, int length, byte* byteArray,
int arrayLenght) {
int encodedLen;
String str = RandomString(rnd, length);
fixed (char* pStr = str) {
encodedLen = Utf8Encode.GetBytes(pStr, str.Length, byteArray,
arrayLenght, true);
}
char* buffer = stackalloc char[8192];
int decodedLen = Utf8Decode.GetChars(byteArray, encodedLen, buffer,
8192, true);
String res = new String(buffer, 0, decodedLen);
Assert.AreEqual(str, res);
}
private static readonly (int, int)[] HeadByteDefinitions =
{
(1 << 7, 0b0000_0000),
(1 << 5, 0b1100_0000),
(1 << 4, 0b1110_0000),
(1 << 3, 0b1111_0000)
};
static byte[] RandomUtf8Char(Random gen)
{
const int totalNumberOfUtf8Chars = (1 << 7) + (1 << 11) + (1 << 16) + (1 << 21);
int tailByteCnt;
var rnd = gen.Next(totalNumberOfUtf8Chars);
if (rnd < (1 << 7))
tailByteCnt = 0;
else if (rnd < (1 << 7) + (1 << 11))
tailByteCnt = 1;
else if (rnd < (1 << 7) + (1 << 11) + (1 << 16))
tailByteCnt = 2;
else
tailByteCnt = 3;
var (range, offset) = HeadByteDefinitions[tailByteCnt];
var headByte = Convert.ToByte(gen.Next(range) + offset);
var tailBytes = Enumerable.Range(0, tailByteCnt)
.Select(_ => Convert.ToByte(gen.Next(1 << 6) + 0b1000_0000));
return new[] {headByte}.Concat(tailBytes).ToArray();
}