typelevel / scalacheck

Property-based testing for Scala
http://www.scalacheck.org
BSD 3-Clause "New" or "Revised" License
1.94k stars 404 forks source link

Feature request: lazy labels #969

Open noresttherein opened 1 year ago

noresttherein commented 1 year ago

Evaluating labels, if they contain formatted input data, can be somewhat expensive. I'd love to see sibling methods, which take a => String argument. I solved it with a very ugly - but working - hack, but it would be great to see it integrated propely.

    private class LazySet[T](lzy : => Set[T]) extends AbstractSet[T] {
        private lazy val evaluated = lzy
        override def contains(elem :T) :Boolean = evaluated.contains(elem)
        override def incl(elem :T) :Set[T] = new LazySet(evaluated + elem)
        override def excl(elem :T) :Set[T] = new LazySet(evaluated - elem)
        override def iterator :Iterator[T] = evaluated.iterator
        override def empty = new LazySet[T](Set.empty[T])
    }

    implicit class PropExtension(private val self :Prop) extends AnyVal {
        def lbl(l : => String) :Prop = self.map { res =>
            res.copy(labels = new LazySet(res.labels + l))
        }
        @inline def lbl_:(l: => String) :Prop = lbl(l)

        def orElse(p : => Prop) = 
            self.combine(Prop.secure(p)) { (first, second) =>
            if (first.failure && second.status.isInstanceOf[Prop.Exception])
                err.println(first.toString + " orElse " + second)
            if (first.success) first
            else second
        }
    }

    implicit class BooleanExtension(private val self :Boolean) extends AnyVal {
        private def prop = Prop(self)

        def lbl(l : => String) :Prop = prop.map { res =>
            res.copy(labels = new LazySet(res.labels + l))
        }
        @inline def lbl_:(l : => String) :Prop = lbl(l)

        def orElse(p : => Prop) = 
            prop.combine(Prop.secure(p)) { (first, second) =>
                if (first.failure && second.status.isInstanceOf[Prop.Exception])
                    err.println(first.toString + " orElse " + second)
                if (first.success) first
                else second
            }
    }
mrdziuban commented 1 year ago

@noresttherein I had the same thought! Opened a PR at #979