biopsy 0.1.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +7 -0
- data/README.md +49 -0
- data/Rakefile +8 -0
- data/lib/biopsy/base_extensions.rb +64 -0
- data/lib/biopsy/domain.rb +156 -0
- data/lib/biopsy/experiment.rb +103 -0
- data/lib/biopsy/objective_function.rb +38 -0
- data/lib/biopsy/objective_handler.rb +170 -0
- data/lib/biopsy/objectives/fastest_optimum.rb +26 -0
- data/lib/biopsy/opt_algorithm.rb +0 -0
- data/lib/biopsy/optimisers/genetic_algorithm.rb +244 -0
- data/lib/biopsy/optimisers/parameter_sweeper.rb +66 -0
- data/lib/biopsy/optimisers/tabu_search.rb +437 -0
- data/lib/biopsy/settings.rb +110 -0
- data/lib/biopsy/target.rb +113 -0
- data/lib/biopsy/version.rb +12 -0
- data/lib/biopsy.rb +13 -0
- data/test/helper.rb +187 -0
- data/test/test_domain.rb +61 -0
- data/test/test_experiment.rb +84 -0
- data/test/test_file.rb +20 -0
- data/test/test_hash.rb +55 -0
- data/test/test_objective_handler.rb +99 -0
- data/test/test_settings.rb +74 -0
- data/test/test_string.rb +14 -0
- data/test/test_target.rb +89 -0
- metadata +198 -0
data/test/helper.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
SimpleCov::Formatter::HTMLFormatter,
|
6
|
+
Coveralls::SimpleCov::Formatter
|
7
|
+
]
|
8
|
+
SimpleCov.start
|
9
|
+
|
10
|
+
require 'test/unit'
|
11
|
+
begin; require 'turn/autorun'; rescue LoadError; end
|
12
|
+
require 'shoulda-context'
|
13
|
+
require 'biopsy'
|
14
|
+
|
15
|
+
Turn.config.format = :pretty
|
16
|
+
Turn.config.trace = 10
|
17
|
+
|
18
|
+
Biopsy::Settings.instance.set_defaults
|
19
|
+
|
20
|
+
# Helper class provides methods for setting up test data.
|
21
|
+
class Helper
|
22
|
+
|
23
|
+
require 'fileutils'
|
24
|
+
|
25
|
+
attr_reader :tmp_dir
|
26
|
+
attr_reader :target_dir
|
27
|
+
attr_reader :domain_dir
|
28
|
+
attr_reader :domain_path
|
29
|
+
attr_reader :target_path
|
30
|
+
attr_reader :objective_dir
|
31
|
+
attr_reader :objective_path
|
32
|
+
|
33
|
+
def cleanup
|
34
|
+
self.instance_variables.each do |ivar|
|
35
|
+
if ivar =~ /_dir/
|
36
|
+
dir = self.instance_variable_get(ivar)
|
37
|
+
FileUtils.rm_rf dir if File.exists? dir
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Create a tmp directory for test data
|
43
|
+
def setup_tmp_dir
|
44
|
+
@tmp_dir = File.expand_path('.tmp')
|
45
|
+
Dir.mkdir @tmp_dir
|
46
|
+
end
|
47
|
+
|
48
|
+
# Return a hash of valid target data
|
49
|
+
def target_data
|
50
|
+
{
|
51
|
+
:input_files => {
|
52
|
+
:in => 'input.txt'
|
53
|
+
},
|
54
|
+
:output_files => {
|
55
|
+
:params => 'output.txt'
|
56
|
+
},
|
57
|
+
:parameter_ranges => {
|
58
|
+
:a => (-40..40).step(2).to_a,
|
59
|
+
:b => (0..100).step(2).to_a,
|
60
|
+
:c => (-50..50).to_a
|
61
|
+
},
|
62
|
+
:constructor_path => 'test_constructor.rb'
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
# Setup the directory for target
|
67
|
+
def setup_target
|
68
|
+
@target_dir = File.join(@tmp_dir, 'targets')
|
69
|
+
Dir.mkdir @target_dir
|
70
|
+
Biopsy::Settings.instance.target_dir = [@target_dir]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Create a valid target definition in the target dir
|
74
|
+
def create_valid_target
|
75
|
+
data = self.target_data
|
76
|
+
name = 'test_target'
|
77
|
+
@target_path = File.join(@target_dir, name + '.yml')
|
78
|
+
self.yaml_dump data, @target_path
|
79
|
+
File.open(File.join(@target_dir, data[:constructor_path]), 'w') do |f|
|
80
|
+
f.puts %Q{
|
81
|
+
class TestConstructor
|
82
|
+
|
83
|
+
require 'yaml'
|
84
|
+
|
85
|
+
def run(params)
|
86
|
+
File.open('output.txt', 'w') do |f|
|
87
|
+
f.puts(params.to_yaml)
|
88
|
+
end
|
89
|
+
{ :params => File.expand_path('output.txt') }
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
}
|
94
|
+
end
|
95
|
+
name
|
96
|
+
end
|
97
|
+
|
98
|
+
# Return a hash of valid domain data
|
99
|
+
def domain_data
|
100
|
+
{
|
101
|
+
:input_filetypes => [
|
102
|
+
{
|
103
|
+
:n => 1,
|
104
|
+
:allowed_extensions => [
|
105
|
+
'.txt'
|
106
|
+
]
|
107
|
+
}
|
108
|
+
],
|
109
|
+
:output_filetypes => [
|
110
|
+
{
|
111
|
+
:n => 1,
|
112
|
+
:allowed_extensions => [
|
113
|
+
'.txt'
|
114
|
+
]
|
115
|
+
}
|
116
|
+
],
|
117
|
+
:objectives => [
|
118
|
+
'test1', 'test2'
|
119
|
+
]
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
def setup_domain
|
124
|
+
@domain_dir = File.join(@tmp_dir, 'domains')
|
125
|
+
Dir.mkdir @domain_dir
|
126
|
+
Biopsy::Settings.instance.domain_dir = [@domain_dir]
|
127
|
+
end
|
128
|
+
|
129
|
+
def create_valid_domain
|
130
|
+
data = domain_data
|
131
|
+
name = 'test_domain'
|
132
|
+
@domain_path = File.join(@domain_dir, name + '.yml')
|
133
|
+
self.yaml_dump data, @domain_path
|
134
|
+
name
|
135
|
+
end
|
136
|
+
|
137
|
+
def setup_objective
|
138
|
+
@objective_dir = File.join(@tmp_dir, 'objectives')
|
139
|
+
Dir.mkdir @objective_dir
|
140
|
+
Biopsy::Settings.instance.objectives_dir = [@objective_dir]
|
141
|
+
end
|
142
|
+
|
143
|
+
def create_valid_objective
|
144
|
+
objective = %Q{
|
145
|
+
class TestObjective < Biopsy::ObjectiveFunction
|
146
|
+
|
147
|
+
require 'yaml'
|
148
|
+
|
149
|
+
def initialize
|
150
|
+
@optimum = 0
|
151
|
+
@max = 0
|
152
|
+
@weighting = 1
|
153
|
+
end
|
154
|
+
|
155
|
+
def run(input, threads)
|
156
|
+
file = input[:params]
|
157
|
+
input = YAML::load_file(file)
|
158
|
+
a = input[:a].to_i
|
159
|
+
b = input[:b].to_i
|
160
|
+
c = input[:c].to_i
|
161
|
+
value = - Math.sqrt((a-4)**2) - Math.sqrt((b-4)**2) - Math.sqrt((c-4)**2)
|
162
|
+
{
|
163
|
+
:optimum => @optimum,
|
164
|
+
:max => @max,
|
165
|
+
:weighting => @weighting,
|
166
|
+
:result => value
|
167
|
+
}
|
168
|
+
end
|
169
|
+
end
|
170
|
+
}
|
171
|
+
@objective_path = File.join(@objective_dir, 'test_objective.rb')
|
172
|
+
self.string_dump objective, @objective_path
|
173
|
+
end
|
174
|
+
|
175
|
+
# Dump +:object+ as YAML to +:file+
|
176
|
+
def yaml_dump object, file
|
177
|
+
self.string_dump object.to_yaml, file
|
178
|
+
end
|
179
|
+
|
180
|
+
# Dump +:string+ to +:file+
|
181
|
+
def string_dump string, file
|
182
|
+
File.open(file, 'w') do |f|
|
183
|
+
f.puts string
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
data/test/test_domain.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestDomain < Test::Unit::TestCase
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
context "Domain" do
|
8
|
+
|
9
|
+
setup do
|
10
|
+
@h = Helper.new
|
11
|
+
@h.setup_tmp_dir
|
12
|
+
|
13
|
+
# we need a domain
|
14
|
+
@h.setup_domain
|
15
|
+
domain_name = @h.create_valid_domain
|
16
|
+
@domain = Biopsy::Domain.new domain_name
|
17
|
+
end
|
18
|
+
|
19
|
+
teardown do
|
20
|
+
@h.cleanup
|
21
|
+
end
|
22
|
+
|
23
|
+
should "be able to find the current domain" do
|
24
|
+
assert_equal 'test_domain', @domain.get_current_domain
|
25
|
+
end
|
26
|
+
|
27
|
+
should "be able to find a definition" do
|
28
|
+
assert_equal @h.domain_path, @domain.locate_definition('test_domain')
|
29
|
+
end
|
30
|
+
|
31
|
+
should "fail to find a non-existent definition" do
|
32
|
+
assert_equal nil, @domain.locate_definition('fake_filename')
|
33
|
+
end
|
34
|
+
|
35
|
+
should "reject any invalid config" do
|
36
|
+
# generate all trivial invalid configs
|
37
|
+
@h.domain_data.keys.each do |key|
|
38
|
+
d = @h.domain_data.clone
|
39
|
+
d.delete key
|
40
|
+
filepath = File.join(@h.domain_dir, 'broken_thing.yml')
|
41
|
+
File.open(filepath, 'w') do |f|
|
42
|
+
f.puts d.to_yaml
|
43
|
+
end
|
44
|
+
|
45
|
+
assert_raise Biopsy::DomainLoadError do
|
46
|
+
@domain.load_by_name 'broken_thing'
|
47
|
+
end
|
48
|
+
|
49
|
+
File.delete filepath if File.exists? filepath
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
should "write a template that can be loaded as a valid definition" do
|
54
|
+
@domain.write_template File.join(@h.domain_dir, 'template.yml')
|
55
|
+
@domain.load_by_name 'template'
|
56
|
+
assert_equal ['objective1', 'objective2'], @domain.objectives
|
57
|
+
end
|
58
|
+
|
59
|
+
end # Domain context
|
60
|
+
|
61
|
+
end # TestDomain
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestExperiment < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Experiment" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@h = Helper.new
|
9
|
+
@h.setup_tmp_dir
|
10
|
+
|
11
|
+
# we need a domain
|
12
|
+
@h.setup_domain
|
13
|
+
domain_name = @h.create_valid_domain
|
14
|
+
@domain = Biopsy::Domain.new domain_name
|
15
|
+
|
16
|
+
# and a target
|
17
|
+
@h.setup_target
|
18
|
+
target_name = @h.create_valid_target
|
19
|
+
@target = Biopsy::Target.new @domain
|
20
|
+
@target.load_by_name target_name
|
21
|
+
|
22
|
+
# and an objective
|
23
|
+
@h.setup_objective
|
24
|
+
@h.create_valid_objective
|
25
|
+
end
|
26
|
+
|
27
|
+
teardown do
|
28
|
+
@h.cleanup
|
29
|
+
end
|
30
|
+
|
31
|
+
should "fail to init when passed a non existent target" do
|
32
|
+
assert_raise Biopsy::TargetLoadError do
|
33
|
+
Biopsy::Experiment.new('fake_target', 'test_domain')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
should "fail to init when passed a non existent domain" do
|
38
|
+
assert_raise Biopsy::DomainLoadError do
|
39
|
+
Biopsy::Experiment.new('test_target', 'fake_domain')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
should "be able to select a valid point from the parameter space" do
|
44
|
+
e = Biopsy::Experiment.new('test_target', 'test_domain')
|
45
|
+
start_point = e.random_start_point
|
46
|
+
start_point.each_pair do |param, value|
|
47
|
+
assert @h.target_data[:parameter_ranges][param].include? value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
should "be able to select a starting point" do
|
52
|
+
e = Biopsy::Experiment.new('test_target', 'test_domain')
|
53
|
+
start_point = e.start
|
54
|
+
start_point.each_pair do |param, value|
|
55
|
+
assert @h.target_data[:parameter_ranges][param].include? value
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
should "respect user's choice of starting point" do
|
60
|
+
s = {:a => 2, :b => 4}
|
61
|
+
e = Biopsy::Experiment.new('test_target', 'test_domain', s)
|
62
|
+
assert_equal s, e.start
|
63
|
+
end
|
64
|
+
|
65
|
+
should "automatically select an optimiser if none is specified" do
|
66
|
+
e = Biopsy::Experiment.new('test_target', 'test_domain')
|
67
|
+
assert e.algorithm.kind_of? Biopsy::TabuSearch
|
68
|
+
end
|
69
|
+
|
70
|
+
should "return an optimal set of parameters and score when run" do
|
71
|
+
# Kernel.srand 123
|
72
|
+
e = Biopsy::Experiment.new('test_target', 'test_domain')
|
73
|
+
known_best = {
|
74
|
+
:a => 4,
|
75
|
+
:b => 4,
|
76
|
+
:c => 4
|
77
|
+
}
|
78
|
+
best_found = e.run[:parameters]
|
79
|
+
assert_equal known_best, best_found
|
80
|
+
end
|
81
|
+
|
82
|
+
end # Experiment context
|
83
|
+
|
84
|
+
end # TestExperiment
|
data/test/test_file.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestFile < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "File" do
|
6
|
+
|
7
|
+
should "return full path to executable in $PATH" do
|
8
|
+
filename = 'testfile'
|
9
|
+
path = ENV['PATH'].split(File::PATH_SEPARATOR).first
|
10
|
+
filepath = File.join(path, filename)
|
11
|
+
File.open(filepath, 'w') do |f|
|
12
|
+
f.puts 'test'
|
13
|
+
end
|
14
|
+
File.chmod(0777, filepath)
|
15
|
+
assert_equal filepath, File.which(filename)
|
16
|
+
end
|
17
|
+
|
18
|
+
end # File context
|
19
|
+
|
20
|
+
end # TestFile
|
data/test/test_hash.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestHash < Test::Unit::TestCase
|
4
|
+
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
context "Hash" do
|
8
|
+
|
9
|
+
setup do
|
10
|
+
@a = {
|
11
|
+
'a' => {
|
12
|
+
'b' => 1,
|
13
|
+
'c' => {
|
14
|
+
'd' => [2, 3, 4]
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
should "recursively symbolise keys" do
|
21
|
+
b = {
|
22
|
+
:a => {
|
23
|
+
:b => 1,
|
24
|
+
:c => {
|
25
|
+
:d => [2, 3, 4]
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
assert @a != b, "hash with string keys not equal to hash with symbol keys"
|
30
|
+
assert_equal @a.deep_symbolize, b, "symbolized string key hash equals symbol key hash"
|
31
|
+
end
|
32
|
+
|
33
|
+
should "recursively merge hashes" do
|
34
|
+
b = {
|
35
|
+
'a' => {
|
36
|
+
'c' => {
|
37
|
+
'e' => 'new value'
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
c = {
|
42
|
+
'a' => {
|
43
|
+
'b' => 1,
|
44
|
+
'c' => {
|
45
|
+
'd' => [2, 3, 4],
|
46
|
+
'e' => 'new value'
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
assert_equal @a.deep_merge(b), c
|
51
|
+
end
|
52
|
+
|
53
|
+
end # Hash context
|
54
|
+
|
55
|
+
end # TestHash
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestObjectiveHandler < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "ObjectiveHandler" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@h = Helper.new
|
9
|
+
@h.setup_tmp_dir
|
10
|
+
|
11
|
+
# we need a domain
|
12
|
+
@h.setup_domain
|
13
|
+
domain_name = @h.create_valid_domain
|
14
|
+
@domain = Biopsy::Domain.new domain_name
|
15
|
+
|
16
|
+
# and a target
|
17
|
+
@h.setup_target
|
18
|
+
target_name = @h.create_valid_target
|
19
|
+
@target = Biopsy::Target.new @domain
|
20
|
+
@target.load_by_name target_name
|
21
|
+
|
22
|
+
# and an objective
|
23
|
+
@h.setup_objective
|
24
|
+
objective_name = @h.create_valid_objective
|
25
|
+
end
|
26
|
+
|
27
|
+
teardown do
|
28
|
+
@h.cleanup
|
29
|
+
end
|
30
|
+
|
31
|
+
should "return loaded objectives on init" do
|
32
|
+
oh = Biopsy::ObjectiveHandler.new @domain, @target
|
33
|
+
refute oh.objectives.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
should "prefer local objective list to full set" do
|
37
|
+
Dir.chdir(@h.objective_dir) do
|
38
|
+
objective = %{
|
39
|
+
class AnotherObjective < Biopsy::ObjectiveFunction
|
40
|
+
def run(input, threads)
|
41
|
+
10
|
42
|
+
end
|
43
|
+
end
|
44
|
+
}
|
45
|
+
File.open('another_objective.rb', 'w') do |f|
|
46
|
+
f.puts objective
|
47
|
+
end
|
48
|
+
File.open('objectives.txt', 'w') do |f|
|
49
|
+
f.puts 'another_objective'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
oh = Biopsy::ObjectiveHandler.new @domain, @target
|
53
|
+
assert_equal 1, oh.objectives.length
|
54
|
+
assert_equal 'AnotherObjective', oh.objectives.keys.first
|
55
|
+
end
|
56
|
+
|
57
|
+
should "run an objective and return the result" do
|
58
|
+
oh = Biopsy::ObjectiveHandler.new @domain, @target
|
59
|
+
values = {
|
60
|
+
:a => 4,
|
61
|
+
:b => 4,
|
62
|
+
:c => 4
|
63
|
+
}
|
64
|
+
file = File.expand_path(File.join(@h.tmp_dir, 'output.txt'))
|
65
|
+
File.open(file, 'w') do |f|
|
66
|
+
f.puts values.to_yaml
|
67
|
+
end
|
68
|
+
result = oh.run_for_output({:params => file}, 0, 1, allresults=true)
|
69
|
+
assert_equal 0, result[:results]["TestObjective"][:result]
|
70
|
+
end
|
71
|
+
|
72
|
+
should "perform euclidean distance dimension reduction" do
|
73
|
+
oh = Biopsy::ObjectiveHandler.new @domain, @target
|
74
|
+
results = {
|
75
|
+
:a => {
|
76
|
+
:optimum => 100,
|
77
|
+
:weighting => 1,
|
78
|
+
:result => 49,
|
79
|
+
:max => 100
|
80
|
+
},
|
81
|
+
:b => {
|
82
|
+
:optimum => 1,
|
83
|
+
:weighting => 1,
|
84
|
+
:result => 62,
|
85
|
+
:max => 100
|
86
|
+
},
|
87
|
+
:c => {
|
88
|
+
:optimum => 0,
|
89
|
+
:weighting => 1,
|
90
|
+
:result => 33,
|
91
|
+
:max => 66
|
92
|
+
}
|
93
|
+
}
|
94
|
+
assert_equal 0.47140452079103173, oh.dimension_reduce(results)
|
95
|
+
end
|
96
|
+
|
97
|
+
end # Experiment context
|
98
|
+
|
99
|
+
end # TestExperiment
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestSettings < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Settings" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@data = {
|
9
|
+
:domain => 'test_domain',
|
10
|
+
:objectives_dir => './objectives',
|
11
|
+
}
|
12
|
+
@config_file = File.expand_path 'testconfig.yml'
|
13
|
+
@settings = Biopsy::Settings.instance
|
14
|
+
File.open(@config_file, 'w') do |f|
|
15
|
+
f.puts @data.to_yaml
|
16
|
+
end
|
17
|
+
@settings.load @config_file
|
18
|
+
end
|
19
|
+
|
20
|
+
teardown do
|
21
|
+
File.delete @config_file if File.exists? @config_file
|
22
|
+
end
|
23
|
+
|
24
|
+
should "load the specified config file" do
|
25
|
+
assert @settings.domain == @data[:domain]
|
26
|
+
assert @settings.objectives_dir == @data[:objectives_dir]
|
27
|
+
end
|
28
|
+
|
29
|
+
should "complain about malformed config file" do
|
30
|
+
# write non-YAML data to file
|
31
|
+
File.open(@config_file, 'w') do |f|
|
32
|
+
f.puts @test
|
33
|
+
end
|
34
|
+
assert_raise RuntimeError do
|
35
|
+
@settings.load @config_file
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
should "be able to save settings and load them identically" do
|
40
|
+
@settings.save @config_file
|
41
|
+
@settings.load @config_file
|
42
|
+
@data.each_pair do |key, value|
|
43
|
+
varname = "@#{key.to_s}".to_sym
|
44
|
+
assert_equal value, @settings.instance_variable_get(varname)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
should "be a singleton" do
|
49
|
+
assert_equal @settings.object_id, Biopsy::Settings.instance.object_id
|
50
|
+
end
|
51
|
+
|
52
|
+
should "make loaded settings available as methods" do
|
53
|
+
assert @settings.domain == @data[:domain], 'domain key not loaded as method'
|
54
|
+
assert @settings.objectives_dir == @data[:objectives_dir], 'objectives_dir key not loaded as method'
|
55
|
+
end
|
56
|
+
|
57
|
+
should "produce a YAML string representation" do
|
58
|
+
s = @settings.to_s
|
59
|
+
h = YAML.load(s)
|
60
|
+
@data.each_pair do |key, value|
|
61
|
+
varname = "@#{key.to_s}".to_sym
|
62
|
+
assert_equal value, @settings.instance_variable_get(varname)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
should "error when a non-existent config is requested" do
|
67
|
+
assert_raise Biopsy::SettingsError do
|
68
|
+
@settings.locate_config :fake_key, 'blah'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end # RunHandler context
|
73
|
+
|
74
|
+
end # TestRunHandler
|
data/test/test_string.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestString < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "String" do
|
6
|
+
|
7
|
+
should "return CamelCase version of snake_case" do
|
8
|
+
assert_equal "snake_case".camelize, "SnakeCase"
|
9
|
+
assert_equal "a_b_c_d".camelize, "ABCD"
|
10
|
+
end
|
11
|
+
|
12
|
+
end # String context
|
13
|
+
|
14
|
+
end # TestString
|
data/test/test_target.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestTarget < Test::Unit::TestCase
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
context "Target" do
|
8
|
+
|
9
|
+
setup do
|
10
|
+
@h = Helper.new
|
11
|
+
@h.setup_tmp_dir
|
12
|
+
|
13
|
+
# we need a domain
|
14
|
+
@h.setup_domain
|
15
|
+
domain_name = @h.create_valid_domain
|
16
|
+
@domain = Biopsy::Domain.new domain_name
|
17
|
+
|
18
|
+
# and a target
|
19
|
+
@h.setup_target
|
20
|
+
target_name = @h.create_valid_target
|
21
|
+
@target = Biopsy::Target.new @domain
|
22
|
+
@target.load_by_name target_name
|
23
|
+
end
|
24
|
+
|
25
|
+
teardown do
|
26
|
+
@h.cleanup
|
27
|
+
end
|
28
|
+
|
29
|
+
should "be able to find an existing definition" do
|
30
|
+
filepath = File.join(@h.target_dir, 'fake_thing.yml')
|
31
|
+
File.open(filepath, 'w') do |f|
|
32
|
+
f.puts "this doesn't matter"
|
33
|
+
end
|
34
|
+
|
35
|
+
assert_equal filepath, @target.locate_definition('fake_thing')
|
36
|
+
end
|
37
|
+
|
38
|
+
should "fail to find a non-existent definition" do
|
39
|
+
assert_equal nil, @target.locate_definition('not_real')
|
40
|
+
end
|
41
|
+
|
42
|
+
should "reject any invalid config" do
|
43
|
+
# generate all trivial invalid configs
|
44
|
+
@h.target_data.keys.each do |key|
|
45
|
+
d = @h.target_data.clone
|
46
|
+
d.delete key
|
47
|
+
filepath = File.join(@h.target_dir, 'broken_thing.yml')
|
48
|
+
File.open(filepath, 'w') do |f|
|
49
|
+
f.puts d.to_yaml
|
50
|
+
end
|
51
|
+
|
52
|
+
assert_raise Biopsy::TargetLoadError do
|
53
|
+
@target.load_by_name 'broken_thing'
|
54
|
+
end
|
55
|
+
|
56
|
+
File.delete filepath if File.exists? filepath
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
should "reject a config that doesn't match the domain spec" do
|
61
|
+
d = @h.target_data
|
62
|
+
d[:input_files][:fake] = 'another.file'
|
63
|
+
assert @target.validate_config(d).length > 0
|
64
|
+
end
|
65
|
+
|
66
|
+
should "be able to store a loaded config file" do
|
67
|
+
config = YAML::load_file(@h.target_path).deep_symbolize
|
68
|
+
@target.store_config config
|
69
|
+
@h.target_data.each_pair do |key, value|
|
70
|
+
assert_equal value, @target.instance_variable_get('@' + key.to_s)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
should "recognise a malformed or missing constructor" do
|
75
|
+
config = YAML::load_file(@h.target_path).deep_symbolize
|
76
|
+
@target.store_config config
|
77
|
+
|
78
|
+
assert !@target.check_constructor, "missing constructor is invalid"
|
79
|
+
|
80
|
+
File.open(@h.target_data[:constructor_path], 'w') do |f|
|
81
|
+
f.puts '[x**2 for x in range(10)]' # python :)
|
82
|
+
end
|
83
|
+
assert !@target.check_constructor, "invalid ruby is invalid"
|
84
|
+
File.delete @h.target_data[:constructor_path]
|
85
|
+
end
|
86
|
+
|
87
|
+
end # Target context
|
88
|
+
|
89
|
+
end # TestTarget context
|