theft 0.0.1.placeholder → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +13 -5
- data/examples/stable_sort.rb +116 -0
- data/lib/theft.rb +90 -2
- data/lib/theft/version.rb +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YjBiNDUwODExOTFjYjM4NzVhYmRjZGM2OWFjNmVlOTE5NGU4YzM1Zg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YzRmM2UyZmJkNWUwOTUxZmQwYzY2MzM2OTA1NTZlNjNlNTQ2NDU3YQ==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NTY0NDg0N2I5ZGRjYTIwYjc1OWJiN2QzMzhiYmUzZjhlYmZkNWQ5MmYyODY0
|
10
|
+
ZTMyMDQ1ODczN2U5Zjk1ZjE3MDJkOGRmOTg1MGI1M2I1ZTk3ZjMzZGMyYWY3
|
11
|
+
YTNiNzVlZDUyYWIxMmUwZDQ0OWE2YjBkYjFkZDNlMjk3MjU4ZGY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NTcxMGM5NzU4Y2NiNTdjODhmZGUwNzVkZTdlOTg1MjEzYTFhMjBiZTY4Njlh
|
14
|
+
YzJjMjY0NDFjMWIxODdjYTlmZjFjY2UzNTJhNWIzYmE0NjQ1ODkzNjFlNDgy
|
15
|
+
MTA5NGE1YzRhMzg2YjZmNTAzMGE3MmNjMGU3ZmFmNmU5MTE3Mzg=
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require_relative '../lib/theft'
|
3
|
+
|
4
|
+
class BoxedFixNum
|
5
|
+
attr_reader :n
|
6
|
+
def initialize(n)
|
7
|
+
@n = n
|
8
|
+
end
|
9
|
+
|
10
|
+
def <=>(other)
|
11
|
+
@n <=> other.n
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class BoxedFixNumArgDescriptor
|
16
|
+
class << self
|
17
|
+
def setup(rng, args={})
|
18
|
+
[].tap do |ar|
|
19
|
+
rng.rand(0..100).times do |i|
|
20
|
+
ar << b(rng.rand(0..100))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def teardown(list)
|
26
|
+
# do stuff
|
27
|
+
end
|
28
|
+
|
29
|
+
def hash(list)
|
30
|
+
Digest::MD5.new.digest to_s(list)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s(list)
|
34
|
+
"[#{list.size}] " + list.map(&:n).map(&:to_s).join(",")
|
35
|
+
end
|
36
|
+
|
37
|
+
def shrink(list, tactic)
|
38
|
+
size = list.size
|
39
|
+
if size < 2
|
40
|
+
puts "#shrink .. dead end"
|
41
|
+
return :dead_end
|
42
|
+
end
|
43
|
+
case tactic
|
44
|
+
when 0
|
45
|
+
return list[0..size/2]
|
46
|
+
when 1
|
47
|
+
return list[size/2..-1]
|
48
|
+
when 2
|
49
|
+
return list[1..-1]
|
50
|
+
when 3
|
51
|
+
return list[0..-2]
|
52
|
+
when 4
|
53
|
+
mid = size/2
|
54
|
+
return list[0..mid-1] + list[mid+1..-1]
|
55
|
+
end
|
56
|
+
|
57
|
+
return :tried_all_tactics
|
58
|
+
end
|
59
|
+
|
60
|
+
def b(n)
|
61
|
+
BoxedFixNum.new n
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Sorter
|
67
|
+
def self.sort(items)
|
68
|
+
unstable items
|
69
|
+
# stable items
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.stable(items)
|
73
|
+
items.sort_by.with_index { |x, idx| [x, idx] }
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.unstable(items)
|
77
|
+
items.sort
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
if $0 == __FILE__
|
82
|
+
t = Theft::Runner.new autosize: true
|
83
|
+
|
84
|
+
property_sorting_should_be_stable = lambda do |generated_arg| # , other_generated_arg, etc
|
85
|
+
sorted = Sorter.sort(generated_arg)
|
86
|
+
|
87
|
+
sorted.chunk{|item| item.n}.each do |n, items|
|
88
|
+
if items.size > 1
|
89
|
+
# lazily spot check
|
90
|
+
first = items.first
|
91
|
+
last = items.last
|
92
|
+
|
93
|
+
if generated_arg.index(first) > generated_arg.index(last)
|
94
|
+
return :fail unless sorted.index(first) > sorted.index(last)
|
95
|
+
else
|
96
|
+
return :fail unless sorted.index(first) < sorted.index(last)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
:pass
|
102
|
+
end
|
103
|
+
|
104
|
+
config = {
|
105
|
+
description: "sorting should be stable",
|
106
|
+
property: property_sorting_should_be_stable,
|
107
|
+
arg_descriptors: [BoxedFixNumArgDescriptor],
|
108
|
+
trials: 3,
|
109
|
+
# must_have_seeds: [],
|
110
|
+
# seed: 1408486348,
|
111
|
+
progress: lambda{|trial_num, args, status| STDOUT.write '.' if trial_num % 2 == 0 },
|
112
|
+
env: :whatevs
|
113
|
+
}
|
114
|
+
|
115
|
+
t.run config
|
116
|
+
end
|
data/lib/theft.rb
CHANGED
@@ -1,5 +1,93 @@
|
|
1
|
-
|
1
|
+
require_relative "theft/version"
|
2
|
+
require 'set'
|
2
3
|
|
3
4
|
module Theft
|
4
|
-
|
5
|
+
class Runner
|
6
|
+
def initialize(args={})
|
7
|
+
@auto_size = args.has_key?(:auto_size) ? args[:auto_size] : true
|
8
|
+
@evaluated_inputs = Set.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def run(config)
|
12
|
+
@seed = config[:seed] || Time.now.to_i
|
13
|
+
@rng = Random.new(@seed)
|
14
|
+
puts "seed: #{@seed}"
|
15
|
+
|
16
|
+
@trials = config[:trials] || 100
|
17
|
+
|
18
|
+
property = config[:property]
|
19
|
+
|
20
|
+
fails = 0
|
21
|
+
passes = 0
|
22
|
+
@trials.times do |trial_num|
|
23
|
+
@descriptors = config[:arg_descriptors]
|
24
|
+
args = @descriptors.map do |desc|
|
25
|
+
desc.setup(@rng, config[:env])
|
26
|
+
end
|
27
|
+
|
28
|
+
unless has_been_tried?(@descriptors, args)
|
29
|
+
result = property.call(*args)
|
30
|
+
|
31
|
+
case result
|
32
|
+
when :fail
|
33
|
+
fails += 1
|
34
|
+
|
35
|
+
args = try_to_shrink(args, property)
|
36
|
+
|
37
|
+
puts "failed on trial: #{trial_num}"
|
38
|
+
@descriptors.each.with_index do |desc, i|
|
39
|
+
puts desc.to_s(args[i])
|
40
|
+
end
|
41
|
+
when :pass
|
42
|
+
passes += 1
|
43
|
+
end
|
44
|
+
|
45
|
+
config[:progress].call(trial_num, args, :passing_for_now)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
puts
|
50
|
+
puts "FAILS: #{fails}"
|
51
|
+
puts "PASSES: #{passes}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def try_to_shrink(args, property)
|
55
|
+
|
56
|
+
@descriptors.each.with_index do |desc, i|
|
57
|
+
tactic_counter = 0
|
58
|
+
|
59
|
+
shrink_result = desc.shrink(args[i], tactic_counter)
|
60
|
+
while shrink_result != :tried_all_tactics
|
61
|
+
#puts desc.to_s(args[i])
|
62
|
+
if shrink_result == :dead_end
|
63
|
+
tactic_counter += 1
|
64
|
+
else
|
65
|
+
copy_args = args.dup
|
66
|
+
copy_args[i] = shrink_result
|
67
|
+
result = property.call(*copy_args)
|
68
|
+
if result == :fail
|
69
|
+
args[i] = shrink_result
|
70
|
+
else
|
71
|
+
tactic_counter += 1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
shrink_result = desc.shrink(args[i], tactic_counter)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
args
|
79
|
+
end
|
80
|
+
|
81
|
+
def has_been_tried?(descriptors, args)
|
82
|
+
@evaluated_inputs.include? hash_inputs(descriptors, args)
|
83
|
+
end
|
84
|
+
|
85
|
+
def hash_inputs(descriptors, args)
|
86
|
+
hashes = descriptors.map.with_index do |desc, i|
|
87
|
+
desc.hash(args[i])
|
88
|
+
end
|
89
|
+
hash = Digest::MD5.new.digest hashes.join(",")
|
90
|
+
@evaluated_inputs << hash
|
91
|
+
end
|
92
|
+
end
|
5
93
|
end
|
data/lib/theft/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: theft
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Vokes
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-09-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -29,14 +29,14 @@ dependencies:
|
|
29
29
|
name: rake
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - '>='
|
32
|
+
- - ! '>='
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '0'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - '>='
|
39
|
+
- - ! '>='
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '0'
|
42
42
|
description: Ruby port of the theft C library.
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- LICENSE.txt
|
53
53
|
- README.md
|
54
54
|
- Rakefile
|
55
|
+
- examples/stable_sort.rb
|
55
56
|
- lib/theft.rb
|
56
57
|
- lib/theft/version.rb
|
57
58
|
- theft.gemspec
|
@@ -65,14 +66,14 @@ require_paths:
|
|
65
66
|
- lib
|
66
67
|
required_ruby_version: !ruby/object:Gem::Requirement
|
67
68
|
requirements:
|
68
|
-
- - '>='
|
69
|
+
- - ! '>='
|
69
70
|
- !ruby/object:Gem::Version
|
70
71
|
version: '0'
|
71
72
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
73
|
requirements:
|
73
|
-
- - '
|
74
|
+
- - ! '>='
|
74
75
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
76
|
+
version: '0'
|
76
77
|
requirements: []
|
77
78
|
rubyforge_project:
|
78
79
|
rubygems_version: 2.2.2
|