comp_tree 0.5.0
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.
- data/README +153 -0
- data/Rakefile +152 -0
- data/comp_tree.gemspec +38 -0
- data/contrib/quix/Rakefile +16 -0
- data/contrib/quix/install.rb +3 -0
- data/contrib/quix/lib/quix/builtin/dir/casefold_brackets.rb +7 -0
- data/contrib/quix/lib/quix/builtin/kernel/tap.rb +9 -0
- data/contrib/quix/lib/quix/builtin/module/include.rb +21 -0
- data/contrib/quix/lib/quix/builtin/module/private.rb +41 -0
- data/contrib/quix/lib/quix/config.rb +37 -0
- data/contrib/quix/lib/quix/cygwin.rb +60 -0
- data/contrib/quix/lib/quix/diagnostic.rb +44 -0
- data/contrib/quix/lib/quix/enumerable.rb +33 -0
- data/contrib/quix/lib/quix/fileutils.rb +37 -0
- data/contrib/quix/lib/quix/hash_struct.rb +27 -0
- data/contrib/quix/lib/quix/kernel.rb +61 -0
- data/contrib/quix/lib/quix/lazy_struct.rb +55 -0
- data/contrib/quix/lib/quix/simple_installer.rb +87 -0
- data/contrib/quix/lib/quix/string.rb +38 -0
- data/contrib/quix/lib/quix/subpackager.rb +52 -0
- data/contrib/quix/lib/quix/thread_local.rb +32 -0
- data/contrib/quix/lib/quix/vars.rb +138 -0
- data/contrib/quix/lib/quix.rb +32 -0
- data/contrib/quix/test/all.rb +12 -0
- data/contrib/quix/test/test_deps.rb +25 -0
- data/contrib/quix/test/test_include.rb +47 -0
- data/contrib/quix/test/test_private.rb +86 -0
- data/contrib/quix/test/test_root.rb +19 -0
- data/contrib/quix/test/test_struct.rb +48 -0
- data/contrib/quix/test/test_vars.rb +187 -0
- data/install.rb +3 -0
- data/lib/comp_tree/algorithm.rb +210 -0
- data/lib/comp_tree/bucket_ipc.rb +151 -0
- data/lib/comp_tree/driver.rb +267 -0
- data/lib/comp_tree/error.rb +27 -0
- data/lib/comp_tree/node.rb +165 -0
- data/lib/comp_tree/quix/builtin/kernel/tap.rb +33 -0
- data/lib/comp_tree/quix/diagnostic.rb +68 -0
- data/lib/comp_tree/quix/kernel.rb +85 -0
- data/lib/comp_tree/retriable_fork.rb +42 -0
- data/lib/comp_tree/task_node.rb +22 -0
- data/lib/comp_tree.rb +23 -0
- data/test/all.rb +12 -0
- data/test/test_bucketipc.rb +72 -0
- data/test/test_circular.rb +36 -0
- data/test/test_comp_tree.rb +364 -0
- data/test/test_exception.rb +97 -0
- metadata +120 -0
data/lib/comp_tree.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2008 James M. Lawrence. All rights reserved.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
|
23
|
+
require 'comp_tree/driver'
|
data/test/all.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
Dir["#{File.dirname(__FILE__)}/test_*.rb"].map { |file|
|
5
|
+
File.expand_path(file)
|
6
|
+
}.each { |file|
|
7
|
+
# spawn separate processes to avoid EAGAIN signals on fork
|
8
|
+
ruby = File.join(
|
9
|
+
Config::CONFIG["bindir"],
|
10
|
+
Config::CONFIG["RUBY_INSTALL_NAME"])
|
11
|
+
system(ruby, file)
|
12
|
+
}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
|
2
|
+
$LOAD_PATH.unshift(File.expand_path("#{File.dirname(__FILE__)}/../lib"))
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'comp_tree/bucket_ipc'
|
6
|
+
|
7
|
+
Thread.abort_on_exception = true
|
8
|
+
|
9
|
+
class BucketTest < Test::Unit::TestCase
|
10
|
+
include CompTree::RetriableFork
|
11
|
+
|
12
|
+
def each_bucket(num_buckets, &block)
|
13
|
+
if HAVE_FORK
|
14
|
+
CompTree::BucketIPC::Driver.new(num_buckets) { |buckets|
|
15
|
+
buckets.each { |bucket|
|
16
|
+
yield bucket
|
17
|
+
}
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_1_no_fork
|
23
|
+
each_bucket(10) { |bucket|
|
24
|
+
local = bucket.contents = :before
|
25
|
+
bucket.contents = :after
|
26
|
+
assert_equal(local, :before)
|
27
|
+
assert_equal(bucket.contents, :after)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_2_fork
|
32
|
+
each_bucket(10) { |bucket|
|
33
|
+
local = bucket.contents = :before
|
34
|
+
process_id = fork {
|
35
|
+
bucket.contents = :after
|
36
|
+
}
|
37
|
+
Process.wait(process_id)
|
38
|
+
assert_equal(local, :before)
|
39
|
+
assert_equal(bucket.contents, :after)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def each_base_test
|
44
|
+
[
|
45
|
+
:test_1_no_fork,
|
46
|
+
:test_2_fork,
|
47
|
+
].each { |method|
|
48
|
+
yield method
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_3_thread
|
53
|
+
each_base_test { |method|
|
54
|
+
Thread.new {
|
55
|
+
send(method)
|
56
|
+
}.join
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_4_thread_flood
|
61
|
+
each_base_test { |method|
|
62
|
+
(0...10).map {
|
63
|
+
Thread.new {
|
64
|
+
send(method)
|
65
|
+
}
|
66
|
+
}.each { |thread|
|
67
|
+
thread.join
|
68
|
+
}
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path("#{File.dirname(__FILE__)}/../lib"))
|
2
|
+
|
3
|
+
require 'comp_tree'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
module CompTree
|
7
|
+
class TestCircular < Test::Unit::TestCase
|
8
|
+
def test_1
|
9
|
+
CompTree::Driver.new { |driver|
|
10
|
+
driver.define(:area, :width, :height, :offset) { |width, height, offset|
|
11
|
+
width*height - offset
|
12
|
+
}
|
13
|
+
|
14
|
+
driver.define(:width, :border) { |border|
|
15
|
+
2 + border
|
16
|
+
}
|
17
|
+
|
18
|
+
driver.define(:height, :border) { |border|
|
19
|
+
3 + border
|
20
|
+
}
|
21
|
+
|
22
|
+
driver.define(:border) {
|
23
|
+
5
|
24
|
+
}
|
25
|
+
|
26
|
+
driver.define(:offset, :area) {
|
27
|
+
7
|
28
|
+
}
|
29
|
+
|
30
|
+
assert_raises(Error::CircularError) {
|
31
|
+
driver.check_circular(:area)
|
32
|
+
}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,364 @@
|
|
1
|
+
|
2
|
+
$LOAD_PATH.unshift(File.expand_path("#{File.dirname(__FILE__)}/../lib"))
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'benchmark'
|
6
|
+
|
7
|
+
require 'comp_tree'
|
8
|
+
|
9
|
+
srand(22)
|
10
|
+
|
11
|
+
module CompTree
|
12
|
+
Thread.abort_on_exception = true
|
13
|
+
HAVE_FORK = RetriableFork::HAVE_FORK
|
14
|
+
DO_FORK = (HAVE_FORK and not ARGV.include?("--no-fork"))
|
15
|
+
|
16
|
+
module TestCommon
|
17
|
+
include Quix::Diagnostic
|
18
|
+
|
19
|
+
if ARGV.include?("--bench")
|
20
|
+
def separator
|
21
|
+
trace ""
|
22
|
+
trace "-"*60
|
23
|
+
end
|
24
|
+
else
|
25
|
+
def separator ; end
|
26
|
+
def trace(*args) ; end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module TestBase
|
31
|
+
include TestCommon
|
32
|
+
|
33
|
+
def test_1_syntax
|
34
|
+
CompTree::Driver.new { |driver|
|
35
|
+
driver.define(:area, :width, :height, :offset) { |width, height, offset|
|
36
|
+
width*height - offset
|
37
|
+
}
|
38
|
+
|
39
|
+
driver.define(:width, :border) { |border|
|
40
|
+
2 + border
|
41
|
+
}
|
42
|
+
|
43
|
+
driver.define(:height, :border) { |border|
|
44
|
+
3 + border
|
45
|
+
}
|
46
|
+
|
47
|
+
driver.define(:border) {
|
48
|
+
5
|
49
|
+
}
|
50
|
+
|
51
|
+
driver.define(:offset) {
|
52
|
+
7
|
53
|
+
}
|
54
|
+
|
55
|
+
assert_equal((2 + 5)*(3 + 5) - 7,
|
56
|
+
driver.compute(:area, opts(6)))
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_2_syntax
|
61
|
+
CompTree::Driver.new { |driver|
|
62
|
+
driver.define_area(:width, :height, :offset) { |width, height, offset|
|
63
|
+
width*height - offset
|
64
|
+
}
|
65
|
+
|
66
|
+
driver.define_width(:border) { |border|
|
67
|
+
2 + border
|
68
|
+
}
|
69
|
+
|
70
|
+
driver.define_height(:border) { |border|
|
71
|
+
3 + border
|
72
|
+
}
|
73
|
+
|
74
|
+
driver.define_border {
|
75
|
+
5
|
76
|
+
}
|
77
|
+
|
78
|
+
driver.define_offset {
|
79
|
+
7
|
80
|
+
}
|
81
|
+
|
82
|
+
assert_equal((2 + 5)*(3 + 5) - 7,
|
83
|
+
driver.compute(:area, opts(6)))
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_3_syntax
|
88
|
+
CompTree::Driver.new { |driver|
|
89
|
+
driver.define_area :width, :height, :offset, %{
|
90
|
+
width*height - offset
|
91
|
+
}
|
92
|
+
|
93
|
+
driver.define_width :border, %{
|
94
|
+
2 + border
|
95
|
+
}
|
96
|
+
|
97
|
+
driver.define_height :border, %{
|
98
|
+
3 + border
|
99
|
+
}
|
100
|
+
|
101
|
+
driver.define_border %{
|
102
|
+
5
|
103
|
+
}
|
104
|
+
|
105
|
+
driver.define_offset %{
|
106
|
+
7
|
107
|
+
}
|
108
|
+
|
109
|
+
assert_equal((2 + 5)*(3 + 5) - 7,
|
110
|
+
driver.compute(:area, opts(6)))
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_thread_flood
|
115
|
+
max =
|
116
|
+
if use_fork?
|
117
|
+
16
|
118
|
+
else
|
119
|
+
200
|
120
|
+
end
|
121
|
+
(1..max).each { |threads|
|
122
|
+
CompTree::Driver.new { |driver|
|
123
|
+
drain = lambda {
|
124
|
+
1.times { }
|
125
|
+
}
|
126
|
+
driver.define_a(:b, &drain)
|
127
|
+
driver.define_b(&drain)
|
128
|
+
driver.compute(:a, opts(threads))
|
129
|
+
}
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_malformed
|
134
|
+
CompTree::Driver.new { |driver|
|
135
|
+
assert_raise(CompTree::Error::ArgumentError) {
|
136
|
+
driver.define {
|
137
|
+
}
|
138
|
+
}
|
139
|
+
assert_raise(CompTree::Error::RedefinitionError) {
|
140
|
+
driver.define(:a) {
|
141
|
+
}
|
142
|
+
driver.define(:a) {
|
143
|
+
}
|
144
|
+
}
|
145
|
+
assert_raise(CompTree::Error::ArgumentError) {
|
146
|
+
driver.define(:b) {
|
147
|
+
}
|
148
|
+
driver.compute(:b, :threads => 0)
|
149
|
+
}
|
150
|
+
assert_raise(CompTree::Error::ArgumentError) {
|
151
|
+
driver.define(:c) {
|
152
|
+
}
|
153
|
+
driver.compute(:c, :threads => -1)
|
154
|
+
}
|
155
|
+
}
|
156
|
+
end
|
157
|
+
|
158
|
+
def generate_comp_tree(num_levels, num_children, drain_iterations)
|
159
|
+
CompTree::Driver.new { |driver|
|
160
|
+
root = :aaa
|
161
|
+
last_name = root
|
162
|
+
pick_names = lambda {
|
163
|
+
(0..rand(num_children)).map {
|
164
|
+
last_name = last_name.to_s.succ.to_sym
|
165
|
+
}
|
166
|
+
}
|
167
|
+
drain = lambda {
|
168
|
+
drain_iterations.times {
|
169
|
+
}
|
170
|
+
}
|
171
|
+
build_tree = lambda { |parent, children, level|
|
172
|
+
trace "building #{parent} --> #{children.join(' ')}"
|
173
|
+
|
174
|
+
driver.define(parent, *children, &drain)
|
175
|
+
|
176
|
+
if level < num_levels
|
177
|
+
children.each { |child|
|
178
|
+
build_tree.call(child, pick_names.call, level + 1)
|
179
|
+
}
|
180
|
+
else
|
181
|
+
children.each { |child|
|
182
|
+
driver.define(child, &drain)
|
183
|
+
}
|
184
|
+
end
|
185
|
+
}
|
186
|
+
build_tree.call(root, pick_names.call, drain_iterations)
|
187
|
+
}
|
188
|
+
end
|
189
|
+
|
190
|
+
def run_generated_tree(args)
|
191
|
+
args[:level_range].each { |num_levels|
|
192
|
+
args[:children_range].each { |num_children|
|
193
|
+
separator
|
194
|
+
trace {%{num_levels}}
|
195
|
+
trace {%{num_children}}
|
196
|
+
trace {%{use_fork?}}
|
197
|
+
driver = generate_comp_tree(
|
198
|
+
num_levels,
|
199
|
+
num_children,
|
200
|
+
args[:drain_iterations])
|
201
|
+
args[:thread_range].each { |threads|
|
202
|
+
trace {%{threads}}
|
203
|
+
2.times {
|
204
|
+
driver.reset(:aaa)
|
205
|
+
result = nil
|
206
|
+
trace Benchmark.measure {
|
207
|
+
result = driver.compute(:aaa, opts(threads))
|
208
|
+
}
|
209
|
+
assert_equal(result, args[:drain_iterations])
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
}
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_generated_tree
|
217
|
+
if use_fork?
|
218
|
+
run_generated_tree(
|
219
|
+
:level_range => 4..4,
|
220
|
+
:children_range => 4..4,
|
221
|
+
:thread_range => 8..8,
|
222
|
+
:drain_iterations => 0)
|
223
|
+
else
|
224
|
+
run_generated_tree(
|
225
|
+
:level_range => 4..4,
|
226
|
+
:children_range => 4..4,
|
227
|
+
:thread_range => 8..8,
|
228
|
+
:drain_iterations => 0)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def use_fork?
|
233
|
+
not opts(0)[:fork].nil?
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
module NoForkTestBase
|
238
|
+
include TestBase
|
239
|
+
def opts(threads)
|
240
|
+
{
|
241
|
+
:threads => threads,
|
242
|
+
}
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
module ForkTestBase
|
247
|
+
include TestBase
|
248
|
+
def opts(threads)
|
249
|
+
{
|
250
|
+
:threads => threads,
|
251
|
+
:fork => HAVE_FORK,
|
252
|
+
}
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
class Test_1_NoFork < Test::Unit::TestCase
|
257
|
+
include NoForkTestBase
|
258
|
+
end
|
259
|
+
|
260
|
+
if DO_FORK
|
261
|
+
class Test_2_Fork < Test::Unit::TestCase
|
262
|
+
include ForkTestBase
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
class Test_Task < Test::Unit::TestCase
|
267
|
+
def test_task
|
268
|
+
CompTree::Driver.new(:discard_result => true) { |driver|
|
269
|
+
visit = 0
|
270
|
+
mutex = Mutex.new
|
271
|
+
func = lambda {
|
272
|
+
mutex.synchronize {
|
273
|
+
visit += 1
|
274
|
+
}
|
275
|
+
}
|
276
|
+
driver.define_a(:b, :c, &func)
|
277
|
+
driver.define_b(&func)
|
278
|
+
driver.define_c(:d, &func)
|
279
|
+
driver.define_d(&func)
|
280
|
+
|
281
|
+
(2..10).each { |threads|
|
282
|
+
assert_equal(
|
283
|
+
true,
|
284
|
+
driver.compute(
|
285
|
+
:a,
|
286
|
+
:threads => threads))
|
287
|
+
assert_equal(visit, 4)
|
288
|
+
driver.reset(:a)
|
289
|
+
visit = 0
|
290
|
+
}
|
291
|
+
|
292
|
+
(2..10).each { |threads|
|
293
|
+
assert_equal(
|
294
|
+
true,
|
295
|
+
driver.compute(
|
296
|
+
:a,
|
297
|
+
:threads => threads,
|
298
|
+
:fork => HAVE_FORK))
|
299
|
+
if HAVE_FORK
|
300
|
+
assert_equal(visit, 0)
|
301
|
+
else
|
302
|
+
assert_equal(visit, 4)
|
303
|
+
end
|
304
|
+
driver.reset(:a)
|
305
|
+
visit = 0
|
306
|
+
}
|
307
|
+
}
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
class Test_Drainer < Test::Unit::TestCase
|
312
|
+
include TestCommon
|
313
|
+
|
314
|
+
def drain(opts)
|
315
|
+
code = %{ 5000.times { } }
|
316
|
+
if opts[:fork]
|
317
|
+
eval code
|
318
|
+
else
|
319
|
+
system("ruby", "-e", code)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def run_drain(opts)
|
324
|
+
CompTree::Driver.new { |driver|
|
325
|
+
func = lambda {
|
326
|
+
drain(opts)
|
327
|
+
}
|
328
|
+
driver.define_area(:width, :height, :offset, &func)
|
329
|
+
driver.define_width(:border, &func)
|
330
|
+
driver.define_height(:border, &func)
|
331
|
+
driver.define_border(&func)
|
332
|
+
driver.define_offset(&func)
|
333
|
+
trace "number of threads: #{opts[:threads]}"
|
334
|
+
trace Benchmark.measure {
|
335
|
+
driver.compute(:area, opts)
|
336
|
+
}
|
337
|
+
}
|
338
|
+
end
|
339
|
+
|
340
|
+
def each_drain
|
341
|
+
(1..10).each { |threads|
|
342
|
+
yield threads
|
343
|
+
}
|
344
|
+
end
|
345
|
+
|
346
|
+
def test_no_fork
|
347
|
+
separator
|
348
|
+
trace "Subrocess test."
|
349
|
+
each_drain { |threads|
|
350
|
+
run_drain({:threads => threads})
|
351
|
+
}
|
352
|
+
end
|
353
|
+
|
354
|
+
if DO_FORK
|
355
|
+
def test_fork
|
356
|
+
separator
|
357
|
+
trace "Forking test."
|
358
|
+
each_drain { |threads|
|
359
|
+
run_drain({:threads => threads, :fork => HAVE_FORK})
|
360
|
+
}
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Mean workaround using separate processes due to assert_raise causing
|
4
|
+
# problems with threads.
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
|
9
|
+
module WorkaroundConfig
|
10
|
+
HERE = File.dirname(__FILE__)
|
11
|
+
LIB_DIR = File.expand_path("#{HERE}/../lib")
|
12
|
+
QUIX_LIB_DIR = File.expand_path("#{HERE}/../contrib/quix/lib")
|
13
|
+
OUTPUT_FILE = "#{HERE}/#{File.basename(__FILE__)}.output"
|
14
|
+
|
15
|
+
$LOAD_PATH.unshift LIB_DIR
|
16
|
+
$LOAD_PATH.unshift QUIX_LIB_DIR
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'comp_tree'
|
20
|
+
require 'quix/config'
|
21
|
+
|
22
|
+
module CompTree
|
23
|
+
class TestRaises < Test::Unit::TestCase
|
24
|
+
include WorkaroundConfig
|
25
|
+
|
26
|
+
def test_exception
|
27
|
+
if RUBY_PLATFORM =~ %r!java!
|
28
|
+
puts "skipping #{File.basename(__FILE__)}."
|
29
|
+
else
|
30
|
+
[true, false].each { |use_fork|
|
31
|
+
[true, false].each { |define_all|
|
32
|
+
assert(
|
33
|
+
!system(
|
34
|
+
::Quix::Config.ruby_executable,
|
35
|
+
"-e",
|
36
|
+
code(use_fork, define_all)))
|
37
|
+
|
38
|
+
output = File.read(OUTPUT_FILE)
|
39
|
+
|
40
|
+
if define_all
|
41
|
+
assert_match(%r!CompTreeTestError!, output)
|
42
|
+
else
|
43
|
+
assert_match(%r!NoFunctionError!, output)
|
44
|
+
end
|
45
|
+
|
46
|
+
File.unlink(OUTPUT_FILE) # leave when exception raised above
|
47
|
+
}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def code(use_fork, define_all)
|
53
|
+
%Q(
|
54
|
+
$LOAD_PATH.unshift '#{LIB_DIR}'
|
55
|
+
require 'comp_tree'
|
56
|
+
require 'open3'
|
57
|
+
|
58
|
+
class CompTreeTestError < Exception ; end
|
59
|
+
|
60
|
+
CompTree::Driver.new { |driver|
|
61
|
+
driver.define(:area, :width, :height, :offset) {
|
62
|
+
|width, height, offset|
|
63
|
+
width*height - offset
|
64
|
+
}
|
65
|
+
|
66
|
+
driver.define(:width, :border) { |border|
|
67
|
+
2 + border
|
68
|
+
}
|
69
|
+
|
70
|
+
driver.define(:height, :border) { |border|
|
71
|
+
3 + border
|
72
|
+
}
|
73
|
+
) +
|
74
|
+
if define_all
|
75
|
+
%Q(
|
76
|
+
driver.define(:border) {
|
77
|
+
raise CompTreeTestError
|
78
|
+
}
|
79
|
+
)
|
80
|
+
else
|
81
|
+
""
|
82
|
+
end +
|
83
|
+
%Q(
|
84
|
+
driver.define(:offset) {
|
85
|
+
7
|
86
|
+
}
|
87
|
+
|
88
|
+
File.open('#{OUTPUT_FILE}', "w") { |out|
|
89
|
+
$stderr = out
|
90
|
+
driver.compute(
|
91
|
+
:area, :threads => 99, :fork => #{use_fork.inspect})
|
92
|
+
}
|
93
|
+
}
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|