Генерация произвольного (законного) символа Unicode с помощью scalacheck?

Я пытаюсь создать генератор, который создает допустимые строки Unicode (не нулевой длины) со scalacheck 1.6.6 и спецификациями 1.7 (scala 2.8.1).

Я надеялся, что смогу просто создать такие генераторы, как:

object Generators {
  def unicodeChar: Gen[Char] = 
    choose(Math.MIN_CHAR, Math.MAX_CHAR).map(_.toChar).filter(
      c => Character.isDefined(c))
  def unicodeStr: Gen[String] = for(cs <- listOf1(unicodeChar)) yield cs.mkString
}

... затем используйте их из спецификаций, таких как:

import org.specs.Specification
import org.specs.matcher.ScalaCheckMatchers

object CoreSpec extends Specification with ScalaCheckMatchers {        
  "The core" should {    
    "pass trivially" in {
      Generators.unicodeStr must pass((s: String) => s == s)
    }
  }
}

Но кажется, что использование фильтра в unicodeChar вызывает проблему:

Specification "CoreSpec"
  The core should
  x pass trivially
    Gave up after only 64 passed tests. 500 tests were discarded.

Если я удалю фильтр из unicodeChar, мой тест пройдет успешно, но позже я столкнусь с другими проблемами, поскольку мои строки не всегда четко определены в юникоде.

Заранее благодарим за любые предложения о том, как этого добиться.


person Eric Bowman - abstracto -    schedule 07.12.2010    source источник
comment
Кажется немного проще, если я не использую Specs и предоставляю новый неявный экземпляр Params. Но это устраняет только симптом, а не устраняет основную причину.   -  person Eric Bowman - abstracto -    schedule 07.12.2010


Ответы (4)


Попробуйте отфильтровать символы перед созданием генератора:

val unicodeChar: Gen[Char] = Gen.oneOf((Math.MIN_CHAR to Math.MAX_CHAR).filter(Character.isDefined(_)))

Это потребует больше памяти, так как полный список символов Юникода будет выделен при создании генератора, но будет использоваться только один экземпляр этого списка, так что это не должно быть большой проблемой.

person rickynils    schedule 07.12.2010
comment
А, это имеет смысл. Спасибо! - person Eric Bowman - abstracto -; 07.12.2010
comment
вот альтернатива: val unicodeChar = Gen.choose(Char.MinValue, Char.MaxValue).filter(Character.isDefined) - person Channing Walton; 16.01.2015

Не знаю, как было в 2010 году, но сейчас можно использовать Arbitrary:

  import org.scalacheck.Arbitrary
  import org.scalacheck.Gen

  val unicodeChar: Gen[Char] = Arbitrary.arbChar.arbitrary
  val unicodeString: Gen[String] = Arbitrary.arbString.arbitrary
person mattelacchiato    schedule 23.02.2016

Хорошо, я понял это. Это то, что работает для меня:

def unicodeChar = Gen((p: Gen.Params) => {
    var c = 0
    do {
      c = util.Random.nextInt(0xFFFF)
    } while (!Character.isDefined(c))
    Some(c.toChar)
  })

На самом деле довольно просто. Чего я не понял, так это того, что вы можете создать произвольный генератор типа T, передав функцию Gen.Params => T в Gen.apply().

person Eric Bowman - abstracto -    schedule 07.12.2010

Вы пробовали suchThat вместо filter?

person Daniel C. Sobral    schedule 07.12.2010
comment
Я попробовал это, прочитав немного дальше; у него такой же симптом. - person Eric Bowman - abstracto -; 07.12.2010
comment
На самом деле, такой-то это просто оболочка для фильтра: def такой-то (p: T => Boolean): Gen[T] = filter(p) - person Eric Bowman - abstracto -; 08.12.2010