Fuzzing用ファイルジェネレータ

30分プログラム、その424。ファジング:ブルートフォースによる脆弱性発見手法を読んでいるときに、テスト用のテストデータのルールをもっと宣言的に書ければいいのに、と思ったので試してみる。
例えば、

def point  = "(" ~ digit ~ "," ~ digit ~ ")"

と書くと、"(<数字>,<数字>)"という形のデータを大量に生成できるようにしたい。書き方はscala.util.parsing.combinator._にあるコンビネータパーサを意識してる。
最初は、設定を受けとってT型のデータを生成する、みたいにすごい抽象的なクラスも作っていたけど、だんだん分けがわからなくなってきたので、思い切って引数なし、生成するのはList[String]固定にしてみた。

使い方

class Points extends Fuzzings {
  def point = "(" ~ digit ~ "," ~ digit ~ ")"
}

val points = new Points
for(p <- points.point()){
  println(p)
}

ソースコード

class Fuzzings {
  // Abstract Fuzzing
  abstract class Fuzz { p =>
    def apply() : List[String]

    def ~(q : Fuzz) : Fuzz = 
      new Fuzz{
	def apply =
	  for(x <- p(); y <- q()) yield (x+y)
      }

    def |(q : Fuzz) : Fuzz =
      new Fuzz{
	def apply =
	  p() ::: q()
      }
  }

  // String
  def string(s : String) : Fuzz =
    new Fuzz{
      def apply() = List(s)
    }

  implicit def literal(s : String) : Fuzz =
    string(s)

  // Digit
  
  def digit : Fuzz =
    new Fuzz{
      def apply() = 
	(0 to 9).map(_.toString).toList
    }

  def lower() : Fuzz =
    new Fuzz{
      def apply() =
	('a' to 'z').map(_.toString).toList
    }


  def upper() : Fuzz =
    new Fuzz{
      def apply() = 
	('A' to 'Z').map(_.toString).toList
    }
}

class Points extends Fuzzings {
  def point = "(" ~ digit ~ "," ~ digit ~ ")"
}

val points = new Points
for(p <- points.point()){
  println(p)
}