bcpm 0.11
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/CHANGELOG +133 -0
- data/Manifest +23 -0
- data/README +292 -0
- data/Rakefile +23 -0
- data/bcpm.gemspec +35 -0
- data/bin/bcpm +5 -0
- data/lib/bcpm.rb +23 -0
- data/lib/bcpm/cleanup.rb +24 -0
- data/lib/bcpm/cli.rb +262 -0
- data/lib/bcpm/config.rb +100 -0
- data/lib/bcpm/dist.rb +133 -0
- data/lib/bcpm/duel.rb +153 -0
- data/lib/bcpm/git.rb +93 -0
- data/lib/bcpm/match.rb +275 -0
- data/lib/bcpm/player.rb +410 -0
- data/lib/bcpm/regen.rb +102 -0
- data/lib/bcpm/socket.rb +8 -0
- data/lib/bcpm/tests/assertion_error.rb +13 -0
- data/lib/bcpm/tests/assertions.rb +102 -0
- data/lib/bcpm/tests/case_base.rb +166 -0
- data/lib/bcpm/tests/environment.rb +256 -0
- data/lib/bcpm/tests/suite.rb +114 -0
- data/lib/bcpm/tests/test_match.rb +166 -0
- data/lib/bcpm/update.rb +38 -0
- metadata +129 -0
data/lib/bcpm/socket.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# :nodoc: namespace
|
2
|
+
module Bcpm
|
3
|
+
|
4
|
+
# :nodoc: namespace
|
5
|
+
module Tests
|
6
|
+
|
7
|
+
# Raised when a test assertion fails.
|
8
|
+
class AssertionError < RuntimeError
|
9
|
+
end # class Bcpm::Tests::AssertionError
|
10
|
+
|
11
|
+
end # namespace Bcpm::Tests
|
12
|
+
|
13
|
+
end # namespace Bcpm
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# :nodoc: namespace
|
2
|
+
module Bcpm
|
3
|
+
|
4
|
+
# :nodoc: namespace
|
5
|
+
module Tests
|
6
|
+
|
7
|
+
# Assertions for match tests.
|
8
|
+
module Assertions
|
9
|
+
# Fails unless the match was won.
|
10
|
+
def should_win
|
11
|
+
return if match.winner == :a
|
12
|
+
raise Bcpm::Tests::AssertionError, "Player was expected to win, but didn't! " + match.outcome
|
13
|
+
end
|
14
|
+
|
15
|
+
# Fails unless the match was won, and the Reason: line includes the argument text.
|
16
|
+
def should_win_by(reason)
|
17
|
+
should_win
|
18
|
+
|
19
|
+
return if match.reason.index(reason)
|
20
|
+
raise Bcpm::Tests::AssertionError, "Player was expected to win by #{reason} and didn't. " +
|
21
|
+
match.reason
|
22
|
+
end
|
23
|
+
|
24
|
+
# Fails unless the match was lost.
|
25
|
+
def should_lose
|
26
|
+
return if match.winner == :b
|
27
|
+
raise Bcpm::Tests::AssertionError, "Player was expected to lose, but didn't! " + match.outcome
|
28
|
+
end
|
29
|
+
|
30
|
+
# Fails unless the match was lost, and the Reason: line includes the argument text.
|
31
|
+
def should_lose_by(reason)
|
32
|
+
should_lose
|
33
|
+
|
34
|
+
return if match.reason.index(reason)
|
35
|
+
raise Bcpm::Tests::AssertionError, "Player was expected to win by #{reason} and didn't. " +
|
36
|
+
match.reason
|
37
|
+
end
|
38
|
+
|
39
|
+
# Fails if the player code threw any exception.
|
40
|
+
def should_not_throw
|
41
|
+
if match.output.index(/\n(\S*)Exception(.*?)\n\S/m)
|
42
|
+
raise Bcpm::Tests::AssertionError, "Player should not have thrown exceptions! " +
|
43
|
+
"It threw #{$1}Exception#{$2}"
|
44
|
+
end
|
45
|
+
if match.chatter.index(/\n(\S*)Exception(.*?)\n\S/m)
|
46
|
+
raise Bcpm::Tests::AssertionError, "Player should not have thrown exceptions! " +
|
47
|
+
"It threw #{$1}Exception#{$2}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Always fails. Useful for obtaining the game log.
|
52
|
+
def fail(reason = 'Test case called fail!')
|
53
|
+
raise Bcpm::Tests::AssertionError, reason
|
54
|
+
end
|
55
|
+
|
56
|
+
# Fails unless a unit's output matches the given regular expression.
|
57
|
+
#
|
58
|
+
# If a block is given, yields to the block for every match.
|
59
|
+
def should_match_unit_output(pattern)
|
60
|
+
matched = false
|
61
|
+
|
62
|
+
match.output_lines.each do |line|
|
63
|
+
next unless unit_output = _parse_unit_output(line)
|
64
|
+
if match = pattern.match(unit_output[:output])
|
65
|
+
matched = true
|
66
|
+
if Kernel.block_given?
|
67
|
+
yield unit_output, match
|
68
|
+
else
|
69
|
+
break
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
raise Bcpm::Tests::AssertionError, "No unit output matched #{pattern.inspect}!" unless matched
|
75
|
+
end
|
76
|
+
|
77
|
+
# Parses a unit's console output (usually via System.out.print*).
|
78
|
+
#
|
79
|
+
# If the given line looks like a unit's console output, returns a hash with the following keys:
|
80
|
+
# :team:: 'A' or 'B' (should always be 'A', unless the case enables team B's console output)
|
81
|
+
# :unit_type:: e.g., 'ARCHON'
|
82
|
+
# :unit_id:: the robot ID of the unit who wrote the line, parsed as an Integer
|
83
|
+
# :round:: the round when the line was output, parsed as an Integer
|
84
|
+
# :output:: the (first line of the) string that the unit produced
|
85
|
+
#
|
86
|
+
# If the line doesn't parse out, returns nil.
|
87
|
+
def _parse_unit_output(line)
|
88
|
+
line_match = /^\[([AB])\:([A-Z]+)\#(\d+)\@(\d+)\](.*)$/.match line
|
89
|
+
return nil unless line_match
|
90
|
+
{
|
91
|
+
:team => line_match[1],
|
92
|
+
:unit_type => line_match[2],
|
93
|
+
:unit_id => line_match[3].to_i,
|
94
|
+
:round => line_match[4].to_i,
|
95
|
+
:output => line_match[5]
|
96
|
+
}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end # namespace Bcpm::Tests
|
101
|
+
|
102
|
+
end # namespace Bcpm
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# :nodoc: namespace
|
2
|
+
module Bcpm
|
3
|
+
|
4
|
+
# :nodoc: namespace
|
5
|
+
module Tests
|
6
|
+
|
7
|
+
# Base class for test cases.
|
8
|
+
#
|
9
|
+
# Each test case is its own anonymous class.
|
10
|
+
class CaseBase
|
11
|
+
class <<self
|
12
|
+
# Called before any code is evaluated in the class context.
|
13
|
+
def _setup
|
14
|
+
@map = nil
|
15
|
+
@suite_map = false
|
16
|
+
@vs = nil
|
17
|
+
@side = :a
|
18
|
+
@match = nil
|
19
|
+
@options = {}
|
20
|
+
@env = Bcpm::Tests::Environment.new
|
21
|
+
@env_used = false
|
22
|
+
|
23
|
+
@tests = []
|
24
|
+
@environments = []
|
25
|
+
@matches = []
|
26
|
+
end
|
27
|
+
|
28
|
+
# Called after all code is evaluated in the class context.
|
29
|
+
def _post_eval
|
30
|
+
@environments << @env if @env_used
|
31
|
+
@env = nil
|
32
|
+
@options = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
# Called by public methods before they change the environment.
|
36
|
+
def _env_change
|
37
|
+
if @env_used
|
38
|
+
@environments << @env
|
39
|
+
@env = Bcpm::Tests::Environment.new
|
40
|
+
@env_used = false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Set the map for following matches.
|
45
|
+
def map(map_name)
|
46
|
+
@map = map_name.dup.to_s
|
47
|
+
@suite_map = false
|
48
|
+
end
|
49
|
+
|
50
|
+
# Set the map for the following match. Use a map in the player's test suite.
|
51
|
+
def suite_map(map_name)
|
52
|
+
@map = map_name.dup.to_s
|
53
|
+
@suite_map = true
|
54
|
+
end
|
55
|
+
|
56
|
+
# Set the enemy for following matches.
|
57
|
+
def vs(player_name)
|
58
|
+
@vs = player_name.dup.to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
# Set our side for the following matches.
|
62
|
+
def side(side)
|
63
|
+
@side = side.to_s.downcase.to_sym
|
64
|
+
end
|
65
|
+
|
66
|
+
# Set a simulation option.
|
67
|
+
def option(key, value)
|
68
|
+
key = Bcpm::Match.engine_options[key.to_s] if key.kind_of? Symbol
|
69
|
+
|
70
|
+
if value.nil?
|
71
|
+
@options.delete key
|
72
|
+
else
|
73
|
+
@options[key] = value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Replaces a class implementation file (.java) with another one (presumably from tests).
|
78
|
+
def replace_class(target, source)
|
79
|
+
_env_change
|
80
|
+
@env.file_op [:file, target, source]
|
81
|
+
end
|
82
|
+
|
83
|
+
# Replaces all fragments labeled with target_fragment in target_class with another fragment.
|
84
|
+
def replace_code(target_class, target_fragment, source_class, source_fragment)
|
85
|
+
_env_change
|
86
|
+
@env.file_op [:fragment, [target_class, target_fragment], [source_class, source_fragment]]
|
87
|
+
end
|
88
|
+
|
89
|
+
# Redirects all method calls using a method name to a static method.
|
90
|
+
#
|
91
|
+
# Assumes the target method is a member method, and passes "this" to the static method.
|
92
|
+
def stub_member_call(source, target)
|
93
|
+
_env_change
|
94
|
+
@env.patch_op [:stub_member, target, source]
|
95
|
+
end
|
96
|
+
|
97
|
+
# Redirects all method calls using a method name to a static method.
|
98
|
+
#
|
99
|
+
# Assumes the target method is a static method, and ignores the call target.
|
100
|
+
def stub_static_call(source, target)
|
101
|
+
_env_change
|
102
|
+
@env.patch_op [:stub_static, target, source]
|
103
|
+
end
|
104
|
+
|
105
|
+
# Create a test match. The block contains test cases for the match.
|
106
|
+
def match(&block)
|
107
|
+
begin
|
108
|
+
@env_used = true
|
109
|
+
map = @suite_map ? @env.suite_map_path(@map) : @map
|
110
|
+
@match = Bcpm::Tests::TestMatch.new @side, @vs, map, @env, @options
|
111
|
+
self.class_eval(&block)
|
112
|
+
@matches << @match
|
113
|
+
ensure
|
114
|
+
@match = nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Create a test match.
|
119
|
+
def it(label, &block)
|
120
|
+
raise "it can only be called within match blocks!" if @match.nil?
|
121
|
+
@tests << self.new(label, @match, block)
|
122
|
+
end
|
123
|
+
|
124
|
+
# All the environments used in the tests.
|
125
|
+
attr_reader :environments
|
126
|
+
# All the matches used in the tests.
|
127
|
+
attr_reader :matches
|
128
|
+
# All test cases.
|
129
|
+
attr_reader :tests
|
130
|
+
end
|
131
|
+
|
132
|
+
# Descriptive label for the test case.
|
133
|
+
attr_reader :label
|
134
|
+
# Test match used by the test case.
|
135
|
+
attr_reader :match
|
136
|
+
|
137
|
+
# Called by match.
|
138
|
+
def initialize(label, match, block)
|
139
|
+
@label = label
|
140
|
+
@match = match
|
141
|
+
@block = block
|
142
|
+
end
|
143
|
+
|
144
|
+
# User-readable description of test conditions.
|
145
|
+
def description
|
146
|
+
"#{match.description} #{label}"
|
147
|
+
end
|
148
|
+
|
149
|
+
# Verifies the match output against the test case.
|
150
|
+
#
|
151
|
+
# Returns nil for success, or an AssertionError exception if the case failed.
|
152
|
+
def check_output
|
153
|
+
begin
|
154
|
+
self.instance_eval &@block
|
155
|
+
return nil
|
156
|
+
rescue Bcpm::Tests::AssertionError => e
|
157
|
+
return e
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
include Bcpm::Tests::Assertions
|
162
|
+
end # class Bcpm::Tests::CaseBase
|
163
|
+
|
164
|
+
end # namespace Bcpm::Tests
|
165
|
+
|
166
|
+
end # namespace Bcpm
|
@@ -0,0 +1,256 @@
|
|
1
|
+
require 'English'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
# :nodoc: namespace
|
6
|
+
module Bcpm
|
7
|
+
|
8
|
+
# :nodoc: namespace
|
9
|
+
module Tests
|
10
|
+
|
11
|
+
# A match run for simulation purposes.
|
12
|
+
#
|
13
|
+
# Each test case is its own anonymous class.
|
14
|
+
class Environment
|
15
|
+
# Name of the player container for the enviornment.
|
16
|
+
attr_reader :player_name
|
17
|
+
|
18
|
+
# The build log, if the build happened.
|
19
|
+
attr_reader :build_log
|
20
|
+
|
21
|
+
# Creates a new environment blueprint.
|
22
|
+
#
|
23
|
+
# Args:
|
24
|
+
# prebuilt_name:: if given, the created blueprint points to an already-built environment
|
25
|
+
def initialize(prebuilt_name = nil)
|
26
|
+
@file_ops = []
|
27
|
+
@patch_ops = []
|
28
|
+
@build_log = nil
|
29
|
+
|
30
|
+
if prebuilt_name
|
31
|
+
@player_name = prebuilt_name
|
32
|
+
@available = true
|
33
|
+
else
|
34
|
+
@player_name = self.class.new_player_name
|
35
|
+
@available = false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Puts together an environment according to the blueprint.
|
40
|
+
def setup(suite_path)
|
41
|
+
return true if @available
|
42
|
+
|
43
|
+
begin
|
44
|
+
test_player = File.basename suite_path
|
45
|
+
|
46
|
+
@player_path = Bcpm::Player.checkpoint test_player, 'master', player_name
|
47
|
+
raise "Failed to checkpoint player at #{suite_path}" unless @player_path
|
48
|
+
@player_src = Bcpm::Player.package_path(@player_path)
|
49
|
+
|
50
|
+
file_ops
|
51
|
+
patch_ops
|
52
|
+
|
53
|
+
unless build
|
54
|
+
print "Test environment build failed! Some tests will not run!\n"
|
55
|
+
print "#{@build_log}\n"
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
rescue Exception => e
|
59
|
+
print "Failed setting up test environment! Some tests will not run!\n"
|
60
|
+
print "#{e.class.name}: #{e.to_s}\n#{e.backtrace.join("\n")}\n\n"
|
61
|
+
return false
|
62
|
+
end
|
63
|
+
@available = true
|
64
|
+
end
|
65
|
+
|
66
|
+
# True if the environment has been setup and can be used to run tests.
|
67
|
+
def available?
|
68
|
+
@available
|
69
|
+
end
|
70
|
+
|
71
|
+
# Undoes the effects of setup.
|
72
|
+
def teardown
|
73
|
+
Bcpm::Player.uninstall player_name
|
74
|
+
@available = false
|
75
|
+
end
|
76
|
+
|
77
|
+
# Path to the maps in the test suite for the player.
|
78
|
+
def suite_map_path(map_name)
|
79
|
+
File.join Bcpm::Player.local_root, player_name, 'suite', 'maps',
|
80
|
+
map_name + '.xml'
|
81
|
+
end
|
82
|
+
|
83
|
+
# Queue an operation that adds a file.
|
84
|
+
def file_op(op)
|
85
|
+
@file_ops << op
|
86
|
+
end
|
87
|
+
|
88
|
+
# Queue an operation that patches all source files.
|
89
|
+
def patch_op(op)
|
90
|
+
@patch_ops << op
|
91
|
+
end
|
92
|
+
|
93
|
+
# Copies files from the test suite to the environment.
|
94
|
+
#
|
95
|
+
# Called by setup, uses its environment.
|
96
|
+
def file_ops
|
97
|
+
@file_ops.each do |op|
|
98
|
+
op_type, target, source = *op
|
99
|
+
|
100
|
+
if op_type == :fragment
|
101
|
+
target, target_fragment = *target
|
102
|
+
source, source_fragment = *source
|
103
|
+
end
|
104
|
+
|
105
|
+
target = "#{@player_name}.#{target}"
|
106
|
+
source = "#{@player_name}.#{source}"
|
107
|
+
file_path = java_path @player_src, source
|
108
|
+
|
109
|
+
next unless File.exist? file_path
|
110
|
+
source_contents = File.read file_path
|
111
|
+
|
112
|
+
case op_type
|
113
|
+
when :file
|
114
|
+
contents = source_contents
|
115
|
+
when :fragment
|
116
|
+
next unless fragment_match = fragment_regexp(source_fragment).match(source_contents)
|
117
|
+
contents = fragment_match[0]
|
118
|
+
end
|
119
|
+
|
120
|
+
source_pkg = java_package source
|
121
|
+
target_pkg = java_package target
|
122
|
+
unless source_pkg == target_pkg
|
123
|
+
contents.gsub! /(^|[^A-Za-z0-9_.])#{source_pkg}([^A-Za-z0-9_]|$)/, "\\1#{target_pkg}\\2"
|
124
|
+
end
|
125
|
+
|
126
|
+
source_class = java_class source
|
127
|
+
target_class = java_class target
|
128
|
+
unless source_class == target_class
|
129
|
+
contents.gsub! /(^|[^A-Za-z0-9_])#{source_class}([^A-Za-z0-9_]|$)/, "\\1#{target_class}\\2"
|
130
|
+
end
|
131
|
+
|
132
|
+
file_path = java_path @player_src, target
|
133
|
+
|
134
|
+
case op_type
|
135
|
+
when :file
|
136
|
+
next unless File.exist?(File.dirname(file_path))
|
137
|
+
when :fragment
|
138
|
+
next unless File.exist?(file_path)
|
139
|
+
source_contents = File.read file_path
|
140
|
+
# Not using a string because source code might contain \1 which would confuse gsub.
|
141
|
+
source_contents.gsub! fragment_regexp(target_fragment) do |match|
|
142
|
+
"#{$1}\n#{contents}\n#{$3}"
|
143
|
+
end
|
144
|
+
contents = source_contents
|
145
|
+
end
|
146
|
+
|
147
|
+
File.open(file_path, 'wb') { |f| f.write contents }
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Applies the patch operations to the source code in the environment.
|
152
|
+
#
|
153
|
+
# Called by setup, uses its environment.
|
154
|
+
def patch_ops
|
155
|
+
return if @patch_ops.empty?
|
156
|
+
|
157
|
+
Dir.glob(File.join(@player_src, '**', '*.java')).each do |file|
|
158
|
+
old_contents = File.read file
|
159
|
+
lines = old_contents.split("\n")
|
160
|
+
|
161
|
+
stubs_enabled = true
|
162
|
+
|
163
|
+
0.upto(lines.count - 1) do |i|
|
164
|
+
line = lines[i]
|
165
|
+
if directive_match = /^\s*\/\/\$(.*)$/.match(line)
|
166
|
+
directive = directive_match[1]
|
167
|
+
case directive.strip.downcase
|
168
|
+
when '+stubs', '-stubs'
|
169
|
+
stubs_enabled = directive[0] == ?+
|
170
|
+
end
|
171
|
+
else
|
172
|
+
@patch_ops.each do |op|
|
173
|
+
op_type, target, source = *op
|
174
|
+
|
175
|
+
case op_type
|
176
|
+
when :stub_member
|
177
|
+
if stubs_enabled
|
178
|
+
line.gsub!(/(^|[^A-Za-z0-9_.])([A-Za-z0-9_.]*\.)?#{source}\(/) do |match|
|
179
|
+
arg = ($2.nil? || $2.empty?) ? 'this' : $2[0..-2]
|
180
|
+
"#{$1}#{player_name}.#{target}(#{arg}, "
|
181
|
+
end
|
182
|
+
end
|
183
|
+
when :stub_static
|
184
|
+
if stubs_enabled
|
185
|
+
line.gsub! /(^|[^A-Za-z0-9_.])([A-Za-z0-9_.]*\.)?#{source}\(/,
|
186
|
+
"\\1#{player_name}.#{target}("
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
contents = lines.join("\n")
|
193
|
+
File.open(file, 'wb') { |f| f.write contents } unless contents == old_contents
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Builds the binaries for the player in this environment.
|
198
|
+
#
|
199
|
+
# Called by setup, uses its environment.
|
200
|
+
#
|
201
|
+
# Returns true for success, false for failure.
|
202
|
+
def build
|
203
|
+
uid = "bcpmbuild_#{Socket.hostname}_#{(Time.now.to_f * 1000).to_i}_#{$PID}"
|
204
|
+
tempdir = File.expand_path File.join(Dir.tmpdir, 'bcpm', uid)
|
205
|
+
FileUtils.mkdir_p tempdir
|
206
|
+
build_log = File.join tempdir, 'build.log'
|
207
|
+
build_file = File.join tempdir, 'build.xml'
|
208
|
+
Bcpm::Match.write_build build_file, 'bc.conf'
|
209
|
+
|
210
|
+
Bcpm::Match.run_build_script tempdir, build_file, build_log, 'build'
|
211
|
+
@build_log = File.exist?(build_log) ? File.open(build_log, 'rb') { |f| f.read } : ''
|
212
|
+
FileUtils.rm_rf tempdir
|
213
|
+
|
214
|
+
@build_log.index("\nBUILD SUCCESSFUL\n") ? true : false
|
215
|
+
end
|
216
|
+
|
217
|
+
# Regular expression matching a code fragment.
|
218
|
+
#
|
219
|
+
# The expression captures three groups: the fragment start marker, the fragment, and the fragment
|
220
|
+
# end marker.
|
221
|
+
def fragment_regexp(label)
|
222
|
+
/^([ \t]*\/\/\$[ \t]*\+mark\:[ \t]*#{label}\s)(.*)(\n[ \t]*\/\/\$[ \t]*\-mark\:[ \t]*#{label}\s)/m
|
223
|
+
end
|
224
|
+
|
225
|
+
# Path to .java source for a class.
|
226
|
+
def java_path(package_path, class_name)
|
227
|
+
File.join(File.dirname(package_path), class_name.gsub('.', '/') + '.java')
|
228
|
+
end
|
229
|
+
|
230
|
+
# Package for a Java class given its fully qualified name.
|
231
|
+
def java_package(class_name)
|
232
|
+
index = class_name.rindex '.'
|
233
|
+
index ? class_name[0, index] : ''
|
234
|
+
end
|
235
|
+
|
236
|
+
# Short class name for a Java class given its fully qualified name.
|
237
|
+
def java_class(class_name)
|
238
|
+
index = class_name.rindex '.'
|
239
|
+
index ? class_name[index + 1, class_name.length - index - 1] : class_name
|
240
|
+
end
|
241
|
+
|
242
|
+
# A player name guaranteed to be unique across the systme.
|
243
|
+
def self.new_player_name
|
244
|
+
# NOTE: Java doesn't like .s in it package names :)
|
245
|
+
host = Socket.hostname.gsub(/[^A-Za-z_]/, '_')
|
246
|
+
@prefix ||=
|
247
|
+
"bcpmtest_#{host}_#{(Time.now.to_f * 1000).to_i}_#{$PID}"
|
248
|
+
@counter ||= 0
|
249
|
+
@counter += 1
|
250
|
+
"#{@prefix}_#{@counter}"
|
251
|
+
end
|
252
|
+
end # class Bcpm::Tests::TestMatch
|
253
|
+
|
254
|
+
end # namespace Bcpm::Tests
|
255
|
+
|
256
|
+
end # namespace Bcpm
|