diff --git a/lib/minitest/thesis.rb b/lib/minitest/thesis.rb index ae42463..44c190e 100644 --- a/lib/minitest/thesis.rb +++ b/lib/minitest/thesis.rb @@ -193,9 +193,9 @@ module Minitest class Possibility attr_reader :produce, :name - def initialize(produce, name: "TODO") - @produce = produce + def initialize(name = "TODO", &produce) @name = name + @produce = produce end def inspect = name @@ -203,41 +203,34 @@ module Minitest # "Returns a `Possibility` where values come from applying `f` to some possible value for `self`." def map(&f) - self.class.new( - ->(test_case) { f.(test_case.any(self)) }, - name: "#{name}.map(TODO)", - ) + self.class.new("#{name}.map(TODO)") {|tc| f.call(tc.any(self)) } end # Returns a `Possibility` where values come from applying `f` (which # should return a new `Possibility` to some possible value for `self` # then returning a possible value from that. def bind(&f) - produce = ->(test_case) { test_case.any(f.(test_case.any(self))) } - self.class.new(produce, name: "#{name}.bind(TODO)") + self.class.new("#{name}.bind(TODO)") {|tc| tc.any(f.(tc.any(self))) } end # Returns a `Possibility` whose values are any possible value of `self` # for which `f` returns True. def satisfying(&f) - produce = ->(test_case) { - 3.times do + self.class.new("#{name}.select(TODO)") {|test_case| + 3.times.first { candidate = test_case.any(self) - return candidate if f.(candidate) - end - test_case.reject + candidate if f.(candidate) + } || test_case.reject } - - self.class.new(produce, name: "#{name}.select(TODO)") end end # Any integer in the range [m, n] is possible - def integers(m, n) = Possibility.new(->(tc) { m + tc.choice(n - m) }, name: "integers(#{m}, #{n})") + def integers(m, n) = Possibility.new("integers(#{m}, #{n})") {|tc| m + tc.choice(n - m) } # Any lists whose elements are possible values from `elements` are possible. def lists(elements, min_size: 0, max_size: Float::INFINITY) - produce = ->(test_case) { + Possibility.new("lists(#{elements.name})") {|test_case| result = [] loop do if result.length < min_size @@ -252,33 +245,29 @@ module Minitest end result } - - Possibility.new(produce, name: "lists(#{elements.name})") end # Only `value` is possible. - def just(value) = Possibility.new(->(_) { value }, name: "just(#{value})") + def just(value) = Possibility.new("just(#{value})") { value } # No possible values. i.e. Any call to `any` will reject the test case. - def nothing = Possibility.new(->(tc) { tc.reject }) + def nothing = Possibility.new {|tc| tc.reject } # Possible values can be any value possible for one of `possibilities`. def mix_of(*possibilities) return nothing if possibilities.empty? - Possibility.new( - ->(tc) { tc.any(possibilities[tc.choice(possibilities.length - 1)]) }, - name: "mix_of(#{possibilities.map(&:name).join(", ")})", - ) + Possibility.new("mix_of(#{possibilities.map(&:name).join(", ")})") {|tc| + tc.any(possibilities[tc.choice(possibilities.length - 1)]) + } end # Any tuple t of of length len(possibilities) such that t[i] is possible # for possibilities[i] is possible. def tuples(*possibilities) - Possibility.new( - ->(tc) { possibilities.map {|p| tc.any(p) } }, - name: "tuples(#{possibilities.map(&:name).join(", ")})", - ) + Possibility.new( "tuples(#{possibilities.map(&:name).join(", ")})") {|tc| + possibilities.map {|p| tc.any(p) } + } end # We cap the maximum amount of entropy a test case can use. diff --git a/test/minitest/thesis_test.rb b/test/minitest/thesis_test.rb index 49a56d6..e6a453b 100644 --- a/test/minitest/thesis_test.rb +++ b/test/minitest/thesis_test.rb @@ -31,10 +31,10 @@ class Minitest::ThesisTest < Minitest::Thesis # 1001]``, and then lowering the length by two, turning it into ``[1001]`` as # desired. def test_finds_small_list_even_with_bad_lists - bad_list = Possibility.new( - ->(tc) { n = tc.choice(10); Array.new(n) { tc.choice(10_000) }}, - name: "bad_list", - ) + bad_list = Possibility.new("bad_list") {|tc| + n = tc.choice(10) + Array.new(n) { tc.choice(10_000) } + } (0...10).each do |seed| out, _ = capture_io do @@ -321,7 +321,10 @@ class Minitest::ThesisTest < Minitest::Thesis def test_selected_possibility run_test("selected_possibility", database: {}) do |tc| - n = tc.any(integers(0, 5).satisfying(&:even?)) + n = tc.any( + integers(0, 5) + .satisfying(&:even?) + ) assert n.even? end end