theft 0.0.1.placeholder → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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