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 CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d9754d686554bf448a4a1bd0c2a627297f02bd1f
4
- data.tar.gz: e194b2fdad009fc005565298b57160aa1a7ba6eb
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjBiNDUwODExOTFjYjM4NzVhYmRjZGM2OWFjNmVlOTE5NGU4YzM1Zg==
5
+ data.tar.gz: !binary |-
6
+ YzRmM2UyZmJkNWUwOTUxZmQwYzY2MzM2OTA1NTZlNjNlNTQ2NDU3YQ==
5
7
  SHA512:
6
- metadata.gz: f65798710c7982acc15c63ad5180f9b5c08ed63810cd4891595bef598700489bd51cc08e52f388abc709d47e3fdde12f99a5a879f42550f9ab3b1c0ef937ad65
7
- data.tar.gz: 45c6d36f65e56246d59bfb595000373ea9ce5eb43b01469c8066854ad939d51432157ecfe0790baaceb89f16d8c1350685cd974a9a92d73d44639697bebd78d0
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
@@ -1,5 +1,93 @@
1
- require "theft/version"
1
+ require_relative "theft/version"
2
+ require 'set'
2
3
 
3
4
  module Theft
4
- # Your code goes here...
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
@@ -1,3 +1,3 @@
1
1
  module Theft
2
- VERSION = "0.0.1.placeholder"
2
+ VERSION = "0.0.1"
3
3
  end
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.placeholder
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-08-04 00:00:00.000000000 Z
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: 1.3.1
76
+ version: '0'
76
77
  requirements: []
77
78
  rubyforge_project:
78
79
  rubygems_version: 2.2.2