dither 0.1.5 → 0.2.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -1
- data/README.md +3 -0
- data/Rakefile +4 -0
- data/dither.gemspec +4 -0
- data/ext/dither/README.md +2 -0
- data/ext/dither/base_constraint_handler.h +36 -0
- data/ext/dither/combinations.h +127 -0
- data/ext/dither/dither.cc +47 -0
- data/ext/dither/dither.h +31 -0
- data/ext/dither/dither_types.h +32 -0
- data/ext/dither/extconf.rb +4 -0
- data/ext/dither/ipog.cc +451 -0
- data/ext/dither/ipog.h +128 -0
- data/ext/dither/simple_constraint_handler.cc +119 -0
- data/ext/dither/simple_constraint_handler.h +38 -0
- data/lib/dither/api.rb +20 -0
- data/lib/dither/version.rb +1 -1
- data/lib/dither.rb +64 -13
- data/spec/dither/dither_spec.rb +27 -96
- metadata +47 -12
- data/lib/dither/ipog.rb +0 -58
- data/lib/dither/ipog_helper.rb +0 -161
- data/lib/dither/mipog.rb +0 -85
- data/lib/dither/param.rb +0 -19
- data/lib/dither/test_case.rb +0 -80
- data/lib/dither/unbound_param.rb +0 -17
@@ -0,0 +1,38 @@
|
|
1
|
+
/*
|
2
|
+
*
|
3
|
+
* Copyright (C) 2015 Jason Gowan
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* This software may be modified and distributed under the terms
|
7
|
+
* of the BSD license. See the LICENSE file for details.
|
8
|
+
*/
|
9
|
+
|
10
|
+
#ifndef SIMPLE_CONSTRAINT_HANDLER_H_
|
11
|
+
#define SIMPLE_CONSTRAINT_HANDLER_H_
|
12
|
+
|
13
|
+
#include <vector>
|
14
|
+
#include <utility>
|
15
|
+
#include <algorithm>
|
16
|
+
#include "dither_types.h"
|
17
|
+
#include "base_constraint_handler.h"
|
18
|
+
|
19
|
+
namespace dither {
|
20
|
+
|
21
|
+
class SimpleConstraintHandler : public BaseConstraintHandler {
|
22
|
+
protected:
|
23
|
+
std::vector<std::vector<std::pair<std::size_t, dval>>> constraints;
|
24
|
+
std::vector<dval> params;
|
25
|
+
|
26
|
+
inline bool violate_constraint(const dtest_case& test_case, const std::vector<std::pair<std::size_t, dval>>& constraint);
|
27
|
+
inline bool violate_constraint(const std::vector<param>& test_case, const std::vector<std::pair<std::size_t, dval>>& constraint);
|
28
|
+
|
29
|
+
public:
|
30
|
+
SimpleConstraintHandler(std::vector<dval>& ranges, std::vector<std::vector<dval>>& pconstraints);
|
31
|
+
bool violate_constraints(const dtest_case &test_case);
|
32
|
+
bool violate_constraints(const std::vector<param> &test_case);
|
33
|
+
bool ground(dtest_case &test_case);
|
34
|
+
};
|
35
|
+
}
|
36
|
+
|
37
|
+
#endif // SIMPLE_CONSTRAINT_HANDLER_H_
|
38
|
+
|
data/lib/dither/api.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
require 'ffi'
|
3
|
+
|
4
|
+
# Interface to the c++ api.
|
5
|
+
module Dither
|
6
|
+
module API
|
7
|
+
extend FFI::Library
|
8
|
+
ffi_lib %w[lib/dither.so lib/dither.dll]
|
9
|
+
|
10
|
+
attach_function :dither_ipog_new, [:int], :pointer
|
11
|
+
attach_function :dither_ipog_add_parameter_int, [:pointer, :int, :pointer, :int], :void
|
12
|
+
attach_function :dither_ipog_run, [:pointer], :void
|
13
|
+
attach_function :dither_ipog_size, [:pointer], :int
|
14
|
+
attach_function :dither_ipog_display_raw_solution, [:pointer], :void
|
15
|
+
attach_function :dither_ipog_fill, [:pointer, :pointer], :void
|
16
|
+
attach_function :dither_ipog_add_constraint, [:pointer, :pointer, :int], :void
|
17
|
+
attach_function :dither_ipog_add_previously_tested, [:pointer, :pointer, :int], :void
|
18
|
+
# attach_function :dither_ipog_delete, [:pointer], :void
|
19
|
+
end
|
20
|
+
end
|
data/lib/dither/version.rb
CHANGED
data/lib/dither.rb
CHANGED
@@ -12,18 +12,73 @@ module Dither
|
|
12
12
|
# deprecated
|
13
13
|
def self.all_pairs(params, t = 2, opts = {})
|
14
14
|
opts[:t] = t
|
15
|
-
|
15
|
+
ipog(params, opts)
|
16
16
|
end
|
17
17
|
|
18
18
|
def self.ipog(params, opts = {})
|
19
19
|
opts = DEFUALT_OPTS.dup.merge(opts)
|
20
|
-
|
21
|
-
|
20
|
+
t = opts[:t] || 2
|
21
|
+
if t < 2
|
22
|
+
raise Dither::Error,'t must be >= 2'
|
23
|
+
end
|
24
|
+
raise Dither::Error, 'param length must be > 1' if params.any? { |a| a.size <= 1 }
|
25
|
+
if t > params.size
|
26
|
+
raise Dither::Error, 't must be <= params.length'
|
27
|
+
end
|
22
28
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
29
|
+
pointer = Dither::API.dither_ipog_new(t)
|
30
|
+
c_params = (0..params.max { |a| a.size }.size).to_a
|
31
|
+
c_int_params = FFI::MemoryPointer.new(:int, c_params.size)
|
32
|
+
c_int_params.write_array_of_int(c_params)
|
33
|
+
|
34
|
+
params.each_with_index do |param, i|
|
35
|
+
Dither::API.dither_ipog_add_parameter_int(pointer, i, c_int_params, param.size)
|
36
|
+
end
|
37
|
+
|
38
|
+
if opts[:constraints]
|
39
|
+
constraint_scratch = FFI::MemoryPointer.new(:int, params.size)
|
40
|
+
opts[:constraints].each do |constraint|
|
41
|
+
arr = Array.new(params.size, -1)
|
42
|
+
constraint.each do |k, v|
|
43
|
+
if k >= params.size
|
44
|
+
raise Dither::Error, "Invalid constraint #{k} > #{params.size}"
|
45
|
+
end
|
46
|
+
if v >= params[k].size
|
47
|
+
raise Dither::Error, "Invalid constraint #{k} > #{params[k].size}"
|
48
|
+
|
49
|
+
end
|
50
|
+
arr[k] = v
|
51
|
+
end
|
52
|
+
constraint_scratch.write_array_of_int(arr)
|
53
|
+
Dither::API.dither_ipog_add_constraint(pointer, constraint_scratch, params.size)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if opts[:previously_tested]
|
58
|
+
tested_scratch = FFI::MemoryPointer.new(:int, params.size)
|
59
|
+
opts[:previously_tested].each do |test_case|
|
60
|
+
if test_case.size != params.size
|
61
|
+
raise Dither::Error
|
62
|
+
end
|
63
|
+
arr = Array.new(params.size)
|
64
|
+
(0...params.size).each do |i|
|
65
|
+
arr[i] = params[i].find(test_case[i]).first
|
66
|
+
end
|
67
|
+
tested_scratch.write_array_of_int(arr)
|
68
|
+
Dither::API.dither_ipog_add_previously_tested(pointer, tested_scratch, params.size)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
Dither::API.dither_ipog_run(pointer)
|
73
|
+
result_size = Dither::API.dither_ipog_size(pointer)
|
74
|
+
solution = FFI::MemoryPointer.new(:int, params.size * result_size)
|
75
|
+
Dither::API.dither_ipog_fill(pointer, solution)
|
76
|
+
|
77
|
+
results = solution.read_array_of_int(params.size * result_size)
|
78
|
+
.enum_for(:each_slice, params.size)
|
79
|
+
.map do |test_case|
|
80
|
+
test_case.zip(params).map { |a, b| b[a] }
|
81
|
+
end
|
27
82
|
end
|
28
83
|
|
29
84
|
def self.aetg(params, opts = {})
|
@@ -34,12 +89,6 @@ module Dither
|
|
34
89
|
class << self; alias_method :ateg, :aetg end
|
35
90
|
end # Dither
|
36
91
|
|
37
|
-
require 'dither/param'
|
38
|
-
require 'dither/unbound_param'
|
39
|
-
require 'dither/test_case'
|
40
|
-
require 'dither/ipog_helper'
|
41
|
-
require 'dither/ipog'
|
42
|
-
require 'dither/mipog'
|
43
92
|
require 'dither/chinese_postman_problem'
|
44
93
|
require 'dither/aetg'
|
45
94
|
require 'dither/aetg_pairwise'
|
@@ -51,4 +100,6 @@ if RUBY_PLATFORM =~ /java/
|
|
51
100
|
require 'dither-0.1.3.jar'
|
52
101
|
|
53
102
|
require 'dither/java_ext/dither'
|
103
|
+
else
|
104
|
+
require 'dither/api'
|
54
105
|
end
|
data/spec/dither/dither_spec.rb
CHANGED
@@ -2,10 +2,6 @@ require File.expand_path('../../spec_helper.rb', __FILE__)
|
|
2
2
|
|
3
3
|
describe Dither do
|
4
4
|
|
5
|
-
it 'mipog does not support constraints' do
|
6
|
-
expect { Dither.mipog([[1,1],[1,2]], 2, :constraints => []) }.to raise_error(Dither::Error, 'mipog does not support constraints')
|
7
|
-
end
|
8
|
-
|
9
5
|
it 't must be >= 2' do
|
10
6
|
expect { Dither.ipog([], :t => 0) }.to raise_error(Dither::Error, 't must be >= 2')
|
11
7
|
end
|
@@ -20,63 +16,15 @@ describe Dither do
|
|
20
16
|
|
21
17
|
it 'can compute 2-way ipog using symbols' do
|
22
18
|
params = [[:a, :b, :c], [:d, :e, :f], [:h, :i]]
|
23
|
-
expect(Dither.
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'can compute 3-way mipog' do
|
35
|
-
params = [(0...2).to_a, (0...2).to_a, (0..3).to_a]
|
36
|
-
expect(Dither.mipog(params, 3)).to eq([[0, 0, 0],
|
37
|
-
[1, 0, 0],
|
38
|
-
[0, 1, 0],
|
39
|
-
[1, 1, 0],
|
40
|
-
[0, 0, 1],
|
41
|
-
[1, 0, 1],
|
42
|
-
[0, 1, 1],
|
43
|
-
[1, 1, 1],
|
44
|
-
[0, 0, 2],
|
45
|
-
[1, 0, 2],
|
46
|
-
[0, 1, 2],
|
47
|
-
[1, 1, 2],
|
48
|
-
[0, 0, 3],
|
49
|
-
[1, 0, 3],
|
50
|
-
[0, 1, 3],
|
51
|
-
[1, 1, 3],
|
52
|
-
])
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'can compute 2-way mipog using symbols' do
|
56
|
-
params = [[:a, :b, :c], [:d, :e, :f], [:h, :i]]
|
57
|
-
expect(Dither.mipog(params).to_set).to eq([[:a, :d, :h],
|
58
|
-
[:a, :e, :i],
|
59
|
-
[:a, :f, :h],
|
60
|
-
[:b, :d, :i],
|
61
|
-
[:b, :e, :h],
|
62
|
-
[:b, :f, :i],
|
63
|
-
[:c, :d, :h],
|
64
|
-
[:c, :e, :i],
|
65
|
-
[:c, :f, :h]].to_set)
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'can compute 2-way mipog' do
|
69
|
-
params = [(0...2).to_a, (0..3).to_a]
|
70
|
-
expect(Dither.mipog(params)).to eq([
|
71
|
-
[0, 0],
|
72
|
-
[1, 0],
|
73
|
-
[0, 1],
|
74
|
-
[1, 1],
|
75
|
-
[0, 2],
|
76
|
-
[1, 2],
|
77
|
-
[0, 3],
|
78
|
-
[1, 3],
|
79
|
-
])
|
19
|
+
expect(Dither.all_pairs(params)).to eq([[:c, :f, :h],
|
20
|
+
[:b, :f, :i],
|
21
|
+
[:a, :f, :h],
|
22
|
+
[:c, :e, :i],
|
23
|
+
[:b, :e, :h],
|
24
|
+
[:a, :e, :i],
|
25
|
+
[:c, :d, :h],
|
26
|
+
[:b, :d, :i],
|
27
|
+
[:a, :d, :h]])
|
80
28
|
end
|
81
29
|
|
82
30
|
it 'can compute 2-way ipog' do
|
@@ -90,7 +38,7 @@ describe Dither do
|
|
90
38
|
[1, 2],
|
91
39
|
[0, 3],
|
92
40
|
[1, 3],
|
93
|
-
|
41
|
+
].reverse)
|
94
42
|
end
|
95
43
|
|
96
44
|
it 'can compute 3-way ipog' do
|
@@ -116,54 +64,37 @@ describe Dither do
|
|
116
64
|
|
117
65
|
it 'can compute 3-way ipog with constraints' do
|
118
66
|
params = [(0...2).to_a, (0...2).to_a, (0..3).to_a]
|
119
|
-
|
67
|
+
results = Dither.ipog(params, :t => 3,
|
120
68
|
:constraints => [
|
121
69
|
{0 => 0,
|
122
70
|
2 => 2},
|
123
71
|
{0 => 0,
|
124
72
|
1 => 1,
|
125
73
|
2 => 0}],
|
126
|
-
:previously_tested => [[0, 0, 0]]
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
[0, 1, 3],
|
138
|
-
[1, 1, 3],
|
139
|
-
].to_set)
|
74
|
+
:previously_tested => [[0, 0, 0]]
|
75
|
+
)
|
76
|
+
results.each do |result|
|
77
|
+
expect(result[0] == 0 && result[1] == 1 && result[2] == 0).to be false
|
78
|
+
end
|
79
|
+
results.each do |result|
|
80
|
+
expect(result[0] == 0 && result[1] == 2).to be false
|
81
|
+
end
|
82
|
+
results.each do |result|
|
83
|
+
expect(result[0] == 0 && result[1] == 0 && result[2] == 0).to be false
|
84
|
+
end
|
140
85
|
end
|
141
86
|
|
142
87
|
it 'another 3-way ipog with constraints' do
|
143
88
|
params = [(0...2).to_a, (0...2).to_a, (0...2).to_a, (0..3).to_a]
|
144
|
-
|
89
|
+
results = Dither.ipog(params, :t => 3,
|
145
90
|
:constraints => [
|
146
91
|
{0 => 0,
|
147
92
|
1 => 1,
|
148
93
|
2 => 0}
|
149
|
-
])
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
[1, 0, 0, 1],
|
154
|
-
[1, 1, 0, 1],
|
155
|
-
[0, 0, 1, 1],
|
156
|
-
[1, 1, 1, 1],
|
157
|
-
[0, 0, 0, 2],
|
158
|
-
[1, 1, 0, 2],
|
159
|
-
[1, 0, 1, 2],
|
160
|
-
[0, 1, 1, 2],
|
161
|
-
[0, 0, 0, 3],
|
162
|
-
[1, 1, 0, 3],
|
163
|
-
[1, 0, 1, 3],
|
164
|
-
[0, 1, 1, 3],
|
165
|
-
[0, 0, 0, 1],
|
166
|
-
[0, 1, 1, 1]].to_set)
|
94
|
+
])
|
95
|
+
results.each do |result|
|
96
|
+
expect(result[0] == 0 && result[1] == 1 && result[2] == 0).to be false
|
97
|
+
end
|
167
98
|
end
|
168
99
|
|
169
100
|
it 'can run 2-way aetg' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dither
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0.rc3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Gowan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.9.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake-compiler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: coveralls
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,11 +66,26 @@ dependencies:
|
|
52
66
|
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ffi
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.0'
|
55
83
|
description: Efficient test generation strategies
|
56
84
|
email:
|
57
85
|
- gowanjason@gmail.com
|
58
86
|
executables: []
|
59
|
-
extensions:
|
87
|
+
extensions:
|
88
|
+
- ext/dither/extconf.rb
|
60
89
|
extra_rdoc_files: []
|
61
90
|
files:
|
62
91
|
- ".gitignore"
|
@@ -68,18 +97,24 @@ files:
|
|
68
97
|
- README.md
|
69
98
|
- Rakefile
|
70
99
|
- dither.gemspec
|
100
|
+
- ext/dither/README.md
|
101
|
+
- ext/dither/base_constraint_handler.h
|
102
|
+
- ext/dither/combinations.h
|
103
|
+
- ext/dither/dither.cc
|
104
|
+
- ext/dither/dither.h
|
105
|
+
- ext/dither/dither_types.h
|
106
|
+
- ext/dither/extconf.rb
|
107
|
+
- ext/dither/ipog.cc
|
108
|
+
- ext/dither/ipog.h
|
109
|
+
- ext/dither/simple_constraint_handler.cc
|
110
|
+
- ext/dither/simple_constraint_handler.h
|
71
111
|
- lib/dither.rb
|
72
112
|
- lib/dither/aetg.rb
|
73
113
|
- lib/dither/aetg_pairwise.rb
|
114
|
+
- lib/dither/api.rb
|
74
115
|
- lib/dither/chinese_postman_problem.rb
|
75
116
|
- lib/dither/graph.rb
|
76
|
-
- lib/dither/ipog.rb
|
77
|
-
- lib/dither/ipog_helper.rb
|
78
117
|
- lib/dither/java_ext/dither.rb
|
79
|
-
- lib/dither/mipog.rb
|
80
|
-
- lib/dither/param.rb
|
81
|
-
- lib/dither/test_case.rb
|
82
|
-
- lib/dither/unbound_param.rb
|
83
118
|
- lib/dither/version.rb
|
84
119
|
- spec/dither/chinese_postman_problem_spec.rb
|
85
120
|
- spec/dither/dither_spec.rb
|
@@ -100,12 +135,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
135
|
version: '0'
|
101
136
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
137
|
requirements:
|
103
|
-
- - "
|
138
|
+
- - ">"
|
104
139
|
- !ruby/object:Gem::Version
|
105
|
-
version:
|
140
|
+
version: 1.3.1
|
106
141
|
requirements: []
|
107
142
|
rubyforge_project: dither
|
108
|
-
rubygems_version: 2.
|
143
|
+
rubygems_version: 2.4.5.1
|
109
144
|
signing_key:
|
110
145
|
specification_version: 4
|
111
146
|
summary: Collection of test generation strategies
|
data/lib/dither/ipog.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
module Dither
|
4
|
-
class IPOG
|
5
|
-
include IPOGHelper
|
6
|
-
|
7
|
-
def run
|
8
|
-
# add into test set a test for each combination of values
|
9
|
-
# of the first t parameter
|
10
|
-
test_set = comb
|
11
|
-
|
12
|
-
(t...params.length).each do |i|
|
13
|
-
# let pi
|
14
|
-
# be the set of t-way combinations of values involving
|
15
|
-
# parameter Pi and t -1 parameters among the first i – 1
|
16
|
-
# parameters
|
17
|
-
pi = comb_i(i)
|
18
|
-
|
19
|
-
# horizontal extension for parameter i
|
20
|
-
test_set.each do |test_case|
|
21
|
-
cover = maximize_coverage(i, test_case, pi)
|
22
|
-
|
23
|
-
if cover.nil?
|
24
|
-
test_set.delete(test_case)
|
25
|
-
else
|
26
|
-
pi -= cover
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# vertical extension for parameter i
|
31
|
-
pi.each do |a|
|
32
|
-
if test_set.any? { |b| a.subset?(b) }
|
33
|
-
pi.delete(a)
|
34
|
-
else
|
35
|
-
|
36
|
-
test_case = nil
|
37
|
-
test_set.each do |b|
|
38
|
-
test_case = b.merge_without_conflict(i, a) do |a|
|
39
|
-
violates_constraints?(a)
|
40
|
-
end
|
41
|
-
break unless test_case.nil?
|
42
|
-
end
|
43
|
-
|
44
|
-
if test_case.nil?
|
45
|
-
test_set << a.create_unbound(i)
|
46
|
-
end
|
47
|
-
pi.delete(a)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
@test_set = test_set.map { |a| fill_unbound(a) }
|
53
|
-
.delete_if(&:nil?)
|
54
|
-
.to_a
|
55
|
-
@test_set
|
56
|
-
end
|
57
|
-
end # IPOG
|
58
|
-
end # Dither
|
data/lib/dither/ipog_helper.rb
DELETED
@@ -1,161 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
module Dither
|
4
|
-
module IPOGHelper
|
5
|
-
attr_reader :params, :t, :constraints, :test_set, :orig_params, :unbound_param_pool, :tested
|
6
|
-
private :params, :t, :constraints, :test_set, :orig_params, :unbound_param_pool, :tested
|
7
|
-
|
8
|
-
def initialize(params, opts = {})
|
9
|
-
init_params(params, (opts[:previously_tested] || []))
|
10
|
-
@t = opts[:t]
|
11
|
-
unless opts[:constraints].nil?
|
12
|
-
@constraints = opts[:constraints].map(&:to_a)
|
13
|
-
.map { |a| a.map { |b| @params[@map_to_orig_index.key(b[0])][b[1]] } }
|
14
|
-
.map(&:to_set)
|
15
|
-
end
|
16
|
-
|
17
|
-
raise Dither::Error, 't must be >= 2' if opts[:t] < 2
|
18
|
-
raise Dither::Error, 't must be <= params.length' if opts[:t] > params.length
|
19
|
-
params.each do |param|
|
20
|
-
raise Dither::Error, 'param length must be > 1' if param.length < 2
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def init_params(user_params, previously_tested)
|
25
|
-
tmp = []
|
26
|
-
@input_params = user_params
|
27
|
-
user_params.each_with_index { |e, i| tmp << [i, e] }
|
28
|
-
@orig_params = tmp.sort_by { |a| a[1].length }
|
29
|
-
.reverse!
|
30
|
-
|
31
|
-
orig_param_map = {}
|
32
|
-
@map_to_orig_index = {}
|
33
|
-
@orig_params.each_with_index do |e, i|
|
34
|
-
@map_to_orig_index[i] = e[0]
|
35
|
-
orig_param_map[e[0]] = {}
|
36
|
-
end
|
37
|
-
|
38
|
-
@params = []
|
39
|
-
@unbound_param_pool = []
|
40
|
-
orig_params.each_with_index do |e, i|
|
41
|
-
@params << (0...e[1].length).map do |j|
|
42
|
-
local_param = Param.new(i, j)
|
43
|
-
orig_param_map[e[0]][e[1][j]] = local_param
|
44
|
-
local_param
|
45
|
-
end
|
46
|
-
@unbound_param_pool << UnboundParam.new(i)
|
47
|
-
end
|
48
|
-
|
49
|
-
@tested = []
|
50
|
-
previously_tested.each do |a|
|
51
|
-
local_params = []
|
52
|
-
a.each_with_index do |e, i|
|
53
|
-
local_params << orig_param_map[i][e]
|
54
|
-
end
|
55
|
-
@tested << TestCase.create(params, unbound_param_pool, local_params)
|
56
|
-
end
|
57
|
-
|
58
|
-
params
|
59
|
-
end
|
60
|
-
|
61
|
-
# return nil if unable to satisfy constraints
|
62
|
-
def maximize_coverage(i, test_case, pi)
|
63
|
-
current_max = 0
|
64
|
-
current_max_j = 0
|
65
|
-
current_matches = []
|
66
|
-
|
67
|
-
(0...params[i].length).each do |j|
|
68
|
-
current_param = params[i][j]
|
69
|
-
test_case << current_param
|
70
|
-
unless violates_constraints?(test_case)
|
71
|
-
matches = pi.select { |a| a.subset?(test_case) }
|
72
|
-
count = matches.count
|
73
|
-
|
74
|
-
if count > current_max
|
75
|
-
current_max = count
|
76
|
-
current_max_j = j
|
77
|
-
current_matches = matches
|
78
|
-
end
|
79
|
-
end
|
80
|
-
test_case.delete(current_param)
|
81
|
-
end
|
82
|
-
|
83
|
-
return nil if violates_constraints?(test_case)
|
84
|
-
test_case << params[i][current_max_j]
|
85
|
-
|
86
|
-
current_matches
|
87
|
-
end
|
88
|
-
|
89
|
-
def violates_constraints?(params)
|
90
|
-
return false if constraints.nil?
|
91
|
-
constraints.any? { |b| b.subset?(params) }
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
def comb
|
97
|
-
ranges = (0...t).to_a.inject([]) do |a, i|
|
98
|
-
a << (0...params[i].length).map { |j| params[i][j] }
|
99
|
-
end
|
100
|
-
|
101
|
-
products = ranges[1..-1].inject(ranges[0]) do |a, b|
|
102
|
-
a = a.product(b)
|
103
|
-
end
|
104
|
-
|
105
|
-
result = products.map(&:flatten)
|
106
|
-
.map { |a| TestCase.create(params, unbound_param_pool, a) }
|
107
|
-
result.reject { |a| tested?(a) }
|
108
|
-
end
|
109
|
-
|
110
|
-
def comb_i(param_i)
|
111
|
-
values = (0...param_i).to_a.combination((t-1)).to_a
|
112
|
-
values.each do |a|
|
113
|
-
a << param_i
|
114
|
-
end
|
115
|
-
result = []
|
116
|
-
values.each do |a|
|
117
|
-
result += a[1..-1]
|
118
|
-
.inject((0...params[a[0]].length).map { |b| params[a[0]][b] }) { |p, i| p.product((0...params[i].length).to_a.map { |c| params[i][c] }) }
|
119
|
-
.map(&:flatten)
|
120
|
-
.map { |b| TestCase.create(params, unbound_param_pool, b) }
|
121
|
-
end
|
122
|
-
result.reject { |a| tested?(a) }.to_set
|
123
|
-
end
|
124
|
-
|
125
|
-
def tested?(test_case)
|
126
|
-
@tested.any? { |a| test_case.subset?(a) }
|
127
|
-
end
|
128
|
-
|
129
|
-
def fill_unbound(data)
|
130
|
-
arr = Array.new(params.length)
|
131
|
-
data.each do |param|
|
132
|
-
unless param.unbound?
|
133
|
-
i = @map_to_orig_index[param.i]
|
134
|
-
arr[i] = @input_params[i][param.j]
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
arr.each_with_index do |e, i|
|
139
|
-
next unless e.nil?
|
140
|
-
|
141
|
-
orig_param = @input_params[i]
|
142
|
-
(0...orig_param.length).each do |j|
|
143
|
-
data << params[@map_to_orig_index.key(i)][j]
|
144
|
-
if violates_constraints?(data)
|
145
|
-
data.delete(params[@map_to_orig_index.key(i)][j])
|
146
|
-
next
|
147
|
-
else
|
148
|
-
arr[i] = orig_param[j]
|
149
|
-
break
|
150
|
-
end
|
151
|
-
end
|
152
|
-
return nil if arr[i].nil?
|
153
|
-
end
|
154
|
-
|
155
|
-
return nil if violates_constraints?(data)
|
156
|
-
return nil if tested?(data)
|
157
|
-
|
158
|
-
arr
|
159
|
-
end
|
160
|
-
end # IPOGHelper
|
161
|
-
end # Dither
|