使用Go的“测试/快速”包生成随机数字和字母串

时间:2016-07-06 12:10:13

标签: testing go unicode generator unicode-normalization

我已经在这几天打破了这个局面,似乎无法弄明白。也许它显而易见,但我似乎无法发现它。我已经阅读了unicode,UTF-8,UTF-16,规范化等所有基础知识,但无济于事。希望有人能够帮助我...

我正在使用testing/quick包中的Go Value函数为我的数据结构中的字段生成随机值,以便为所讨论的结构实现Generator interface。具体来说,给定Metadata结构,我已将实现定义如下:

func (m *Metadata) Generate(r *rand.Rand, size int) (value reflect.Value) {
    value = reflect.ValueOf(m).Elem()
    for i := 0; i < value.NumField(); i++ {
        if t, ok := quick.Value(value.Field(i).Type(), r); ok {
            value.Field(i).Set(t)
        }
    }
    return
}

现在,这样做,我最终将接收器和返回值设置为随机生成的相应类型的值(接收器中的字符串,整数等,并在返回的反射中反映。值) .value的)。

现在,Value函数的实现声明它将返回类型[]rune转换为类型string的内容。据我所知,这应该允许我使用runesunicodenorm包中的函数来定义过滤器,过滤掉不属于'Latin','Letter''Number'。我定义了以下过滤器,该过滤器使用变换来过滤掉那些不在rangetable s字符中的字母(如unicode包中所定义):

func runefilter(in reflect.Value) (out reflect.Value) {
    out = in // Make sure you return something
    if in.Kind() == reflect.String {
        instr := in.String()
        t := transform.Chain(norm.NFD, runes.Remove(runes.NotIn(rangetable.Merge(unicode.Letter, unicode.Latin, unicode.Number))), norm.NFC)
        outstr, _, _ := transform.String(t, instr)
        out = reflect.ValueOf(outstr)
    }
    return
}

现在,我认为我已经尝试过任何事情,但我最终会得到一系列远离拉丁语范围的字符串,例如:

똿穊

嚶
秓䝏小䮋
ท솲
䂾

ʋᦸ
堮憨ꥆ
併怃
鯮

⓿ꐠ槹黟
踁퓺
俇


쩈詢


欓

那么,任何人都可以解释我在这里忽略的内容以及如何定义transformer来删除/替换非字母/数字/拉丁字符以便我可以使用Value函数如预期的那样(但是'随机'字符的子集较小?)

谢谢!

2 个答案:

答案 0 :(得分:1)

令人困惑的是,Generate接口需要使用类型而不是指向类型的指针的函数。您希望类型签名看起来像

func (m Metadata) Generate(r *rand.Rand, size int) (value reflect.Value)

您可以使用此here。注意:在该游乐场中最重要的事情是将生成函数的类型从m Metadata切换到m *Metadata并看到嗨妈妈!从不打印。

此外,我认为使用您自己的类型并使用您要使用的所有字符列表为该类型编写generate方法会更好。例如:

type LatinString string
const latin = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01233456789"

然后使用生成器

func (l LatinString) Generate(rand *rand.Rand, size int) reflect.Value {
    var buffer bytes.Buffer
    for i := 0; i < size; i++ {
        buffer.WriteString(string(latin[rand.Intn(len(latin))]))
    }
    s := LatinString(buffer.String())
    return reflect.ValueOf(s)
}

playground

编辑:这个库也很酷,感谢你向我展示

答案 1 :(得分:0)

我自己的问题的答案似乎是@nj_和@jimb评论中提供的答案和@benjaminkadish提供的答案的组合。

简而言之,答案归结为:

  1. 不是一个好主意,因为你认为它是”,或“有点不合时宜的问题
  2. “您使用的是联合 'Letter''Latin''Number'Letter || Number || Latin),而不是'Latin'交集'Letter'的 union '数字'(Letter || Number) && Latin)
  3. 现在是更长版本......

    我使用testing/quick包后面的想法是我想要随机数据进行代码的(模糊)测试。在过去,我总是一次又一次地编写代码来自己做这样的事情。这意味着不同项目中的许多相同代码。现在,我当然可以为它编写自己的软件包,但事实证明,甚至比这更好,实际上有一个标准软件包可以完全满足我的需求。

    现在,事实证明包装完全符合我的要求。它生成的字符串中的代码点实际上是 random ,而不仅限于我们习惯在日常生活中使用的内容。现在,这当然是您在进行模糊测试时想要的,以便使用超出通常假设的值来测试代码。

    实际上,这意味着我遇到了两个问题:

    1. 对于字符串我会考虑合理输入有一些限制。这意味着,在测试Name字段或URL字段的处理时,我可以合理地假设不会出现像'JamesMc⌢'这样的值(让单独的'James Mc'或'www.site.com',但只是'James McFrown'和'www.website.com'。因此,我不能指望合理的系统能够支持它。当然,事情不应该完全崩溃,但也不能指望它没有任何问题处理前面的例子。
    2. 当我在可能认为合理的值上过滤生成的字符串时,以有效字符串结束的可能性非常小。 testing/quick使用的集合中可能的字符集非常大(0x10FFFF),而合理字符的集合如此之小,大多数时候最终会出现空字符串。
    3. 那么,我们需要从中汲取什么呢?

      所以,虽然我希望使用标准testing/quick软件包来替换我经常重复的代码来生成模糊测试的随机数据,但它做得很好,它提供的数据超出了我认为合理的范围使代码能够处理。似乎最终的选择是:

      1. 要么能够真正处理所有模糊选项,这意味着如果有人的名字是'Arnold'('Arnold Moneybags'),那么它就不应该over ass。或...
      2. 将自定义/派生类型与自己的Generator一起使用。这意味着您将不得不在整个代码中使用派生类型而不是基本类型。 (与在C ++中将string定义为wchar_t而不是char并在默认情况下使用testing/quick相比较。或...
      3. 不要使用{{1}}进行模糊测试,因为只要遇到生成的字符串值,就可以(而且应该)获得一个非常随机的字符串。
      4. 与往常一样,进一步的评论当然是受欢迎的,因为我很可能忽略了一些事情。