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
@@ -0,0 +1,114 @@
|
|
1
|
+
# :nodoc: namespace
|
2
|
+
module Bcpm
|
3
|
+
|
4
|
+
# :nodoc: namespace
|
5
|
+
module Tests
|
6
|
+
|
7
|
+
# Collection of test cases.
|
8
|
+
class Suite
|
9
|
+
# All the environments used in the tests.
|
10
|
+
attr_reader :environments
|
11
|
+
# All the matches used in the tests.
|
12
|
+
attr_reader :matches
|
13
|
+
# All test cases.
|
14
|
+
attr_reader :tests
|
15
|
+
# Path to the suite's local repository.
|
16
|
+
attr_reader :local_path
|
17
|
+
|
18
|
+
# Blank suite.
|
19
|
+
def initialize(local_path)
|
20
|
+
@local_path = local_path
|
21
|
+
@tests = []
|
22
|
+
@matches = []
|
23
|
+
@environments = []
|
24
|
+
end
|
25
|
+
|
26
|
+
# Adds the given test cases to the suite.
|
27
|
+
def add_cases(case_files)
|
28
|
+
case_files.each do |file|
|
29
|
+
code = File.read file
|
30
|
+
klass = Class.new Bcpm::Tests::CaseBase
|
31
|
+
klass._setup
|
32
|
+
begin
|
33
|
+
klass.class_eval code, file
|
34
|
+
rescue Exception => e
|
35
|
+
trace = short_backtrace e.backtrace
|
36
|
+
print "Error in test case #{file}\n"
|
37
|
+
print "#{e.class.name}: #{e.to_s}\n#{trace.join("\n")}\n\n"
|
38
|
+
next
|
39
|
+
end
|
40
|
+
klass._post_eval
|
41
|
+
@tests += klass.tests
|
42
|
+
@matches += klass.matches
|
43
|
+
@environments += klass.environments
|
44
|
+
end
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
# Runs all the tests in the suite.
|
49
|
+
def run(live = false)
|
50
|
+
environments.each { |e| e.setup local_path }
|
51
|
+
|
52
|
+
wins, fails, errors, skipped, totals = 0, 0, 0, 0, 0
|
53
|
+
failures = []
|
54
|
+
tests.each_with_index do |test, i|
|
55
|
+
unless test.match.environment.available?
|
56
|
+
skipped += 1
|
57
|
+
next
|
58
|
+
end
|
59
|
+
|
60
|
+
unless test.match.ran?
|
61
|
+
test.match.run live
|
62
|
+
# Only one match can run live, otherwise all hell will break loose.
|
63
|
+
live = false
|
64
|
+
end
|
65
|
+
failure_string = nil
|
66
|
+
begin
|
67
|
+
if failure = test.check_output
|
68
|
+
trace = short_backtrace failure.backtrace
|
69
|
+
failure_string = "#{failure.to_s}\n#{trace.join("\n")}"
|
70
|
+
fails += 1
|
71
|
+
print 'F'
|
72
|
+
else
|
73
|
+
wins += 1
|
74
|
+
print '.'
|
75
|
+
end
|
76
|
+
rescue Exception => e
|
77
|
+
errors += 1
|
78
|
+
failure_string = "#{e.class.name}: #{e.to_s}\n#{e.backtrace.join("\n")}"
|
79
|
+
end
|
80
|
+
totals += 1
|
81
|
+
if failure_string
|
82
|
+
failures << [test, failure_string]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
print "\n#{totals} tests, #{wins} passed, #{fails} failures, #{errors} errors\n\n"
|
86
|
+
failures.each_with_index do |failure, i|
|
87
|
+
test, string = *failure
|
88
|
+
print "#{'%3d' % (i + 1)}) Failed #{test.description}\n"
|
89
|
+
|
90
|
+
print test.match.stash_data
|
91
|
+
print "#{string}\n\n"
|
92
|
+
end
|
93
|
+
|
94
|
+
environments.each { |e| e.teardown }
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
# Trims backtrace to the confines of the test suite.
|
99
|
+
def short_backtrace(backtrace)
|
100
|
+
trace = backtrace
|
101
|
+
first_line = trace.find_index { |line| line.index local_path }
|
102
|
+
last_line = trace.length - 1 - trace.reverse.find_index { |line| line.index local_path }
|
103
|
+
# Leave the trace untouched if it doesn't go through the test suite.
|
104
|
+
if first_line && last_line
|
105
|
+
trace = trace[first_line..last_line]
|
106
|
+
trace[-1] = trace[-1].sub /in `.*'/, 'in (test case)'
|
107
|
+
end
|
108
|
+
trace
|
109
|
+
end
|
110
|
+
end # class Bcpm::Tests::Suite
|
111
|
+
|
112
|
+
end # namespace Bcpm::Tests
|
113
|
+
|
114
|
+
end # namespace Bcpm
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
# :nodoc: namespace
|
4
|
+
module Bcpm
|
5
|
+
|
6
|
+
# :nodoc: namespace
|
7
|
+
module Tests
|
8
|
+
|
9
|
+
# A match run for simulation purposes.
|
10
|
+
#
|
11
|
+
# Each test case is its own anonymous class.
|
12
|
+
class TestMatch
|
13
|
+
# Side of the tested player in the match.
|
14
|
+
attr_reader :side
|
15
|
+
# Name of opposing player in the match.
|
16
|
+
attr_reader :vs
|
17
|
+
# Name of map for the match.
|
18
|
+
attr_reader :map
|
19
|
+
# Custom options for the battlecode simulator.
|
20
|
+
attr_reader :options
|
21
|
+
|
22
|
+
# The environment that the match runs in.
|
23
|
+
attr_reader :environment
|
24
|
+
|
25
|
+
# Match output. Nil if the match hasn't completed.
|
26
|
+
attr_reader :output
|
27
|
+
|
28
|
+
# Detailed match data.
|
29
|
+
attr_reader :data
|
30
|
+
|
31
|
+
# Skeleton for a match.
|
32
|
+
def initialize(side, vs, map, environment, options = {})
|
33
|
+
@side = side
|
34
|
+
@vs = vs
|
35
|
+
@map = map
|
36
|
+
@options = options.clone
|
37
|
+
@environment = environment
|
38
|
+
@output = nil
|
39
|
+
@data = nil
|
40
|
+
|
41
|
+
@output_lines = nil
|
42
|
+
@outcome = nil
|
43
|
+
@winner = nil
|
44
|
+
@reason = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
# Run the game.
|
48
|
+
def run(live = false)
|
49
|
+
case @side
|
50
|
+
when :a
|
51
|
+
@data = Bcpm::Match.match_data @environment.player_name, @vs, true, @map, live, @options
|
52
|
+
when :b
|
53
|
+
@data = Bcpm::Match.match_data @vs, @environment.player_name, false, @map, live, @options
|
54
|
+
end
|
55
|
+
@output = data[:ant]
|
56
|
+
end
|
57
|
+
|
58
|
+
# True if the test match has run, and its results are available.
|
59
|
+
def ran?
|
60
|
+
!output.nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
# User-readable description of match conditions.
|
64
|
+
def description
|
65
|
+
if File.basename(map) == map
|
66
|
+
map_name = map
|
67
|
+
else
|
68
|
+
map_name = "suite/maps/#{File.basename(map).sub(/\.xml$/, '')}"
|
69
|
+
end
|
70
|
+
desc = "as team #{side.to_s.upcase} vs #{vs} on #{map_name}"
|
71
|
+
unless @options.empty?
|
72
|
+
desc += ' with ' + options.map { |k, v| "#{k}=#{v}" }.join(",")
|
73
|
+
end
|
74
|
+
desc
|
75
|
+
end
|
76
|
+
|
77
|
+
# The match output, split into lines.
|
78
|
+
def output_lines
|
79
|
+
@output_lines ||= output.split("\n")
|
80
|
+
end
|
81
|
+
|
82
|
+
# The output printed by map units, without the [source] prefixess.
|
83
|
+
def chatter
|
84
|
+
@chatter ||= output_lines.map { |line| line.gsub /^\[[^\]]+\]\s/, '' }.reject(&:empty?).join("\n")
|
85
|
+
end
|
86
|
+
|
87
|
+
# The output line showing who won the game.
|
88
|
+
def outcome
|
89
|
+
return @outcome if @outcome
|
90
|
+
@outcome = output_lines[-3] || ''
|
91
|
+
@outcome = '(no victory)' unless outcome.index('wins')
|
92
|
+
@outcome
|
93
|
+
end
|
94
|
+
|
95
|
+
# The side that own the game
|
96
|
+
def winner
|
97
|
+
return @winner if @winner
|
98
|
+
win_match = /\((.)\) wins/.match outcome
|
99
|
+
@winner = if win_match
|
100
|
+
(win_match[1] == 'A') ? :a : :b
|
101
|
+
else
|
102
|
+
:error
|
103
|
+
end
|
104
|
+
@winner
|
105
|
+
end
|
106
|
+
|
107
|
+
# The output line showing the reason the game ended.
|
108
|
+
def reason
|
109
|
+
return @reason if @reason
|
110
|
+
@reason = output_lines[-2] || ''
|
111
|
+
@reason = '(no reason)' unless reason.index('Reason:')
|
112
|
+
@reason
|
113
|
+
end
|
114
|
+
|
115
|
+
# Stashes the match data somewhere on the system.
|
116
|
+
#
|
117
|
+
# Returns a string containing user-friendly instructions for accessing the match data.
|
118
|
+
def stash_data
|
119
|
+
path = self.class.gamesave_path
|
120
|
+
FileUtils.mkdir_p path
|
121
|
+
|
122
|
+
txt_path = File.join path, data[:uid] + '.txt'
|
123
|
+
File.open(txt_path, 'wb') { |f| f.write output } unless File.exist?(txt_path)
|
124
|
+
rms_path = File.join path, data[:uid] + '.rms'
|
125
|
+
File.open(rms_path, 'wb') { |f| f.write data[:rms] } unless File.exist?(rms_path)
|
126
|
+
|
127
|
+
"Output: #{open_binary} #{txt_path}\nReplay: bcpm replay #{rms_path}\n"
|
128
|
+
end
|
129
|
+
|
130
|
+
# All game replays saved by calls to stash_data.
|
131
|
+
def self.stashed_replays
|
132
|
+
Dir.glob File.join(gamesave_path, '*.rms')
|
133
|
+
end
|
134
|
+
|
135
|
+
# All game outputs saved by calls to stash_data.
|
136
|
+
def self.stashed_outputs
|
137
|
+
Dir.glob File.join(gamesave_path, '*.txt')
|
138
|
+
end
|
139
|
+
|
140
|
+
# Path where game data (output, replay binlog) is saved.
|
141
|
+
def self.gamesave_path
|
142
|
+
Bcpm::Config[:gamesave_path] ||= default_gamesave_path
|
143
|
+
end
|
144
|
+
|
145
|
+
# Path where game data (output, replay binlog) is saved.
|
146
|
+
def self.default_gamesave_path
|
147
|
+
File.join Dir.tmpdir, 'bcpm'
|
148
|
+
end
|
149
|
+
|
150
|
+
# Name of program for opening text files.
|
151
|
+
def open_binary
|
152
|
+
return ENV['EDITOR'] if ENV['EDITOR']
|
153
|
+
case RUBY_PLATFORM
|
154
|
+
when /darwin/
|
155
|
+
'open'
|
156
|
+
when /win/
|
157
|
+
'notepad'
|
158
|
+
when /linux/
|
159
|
+
'gedit'
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end # class Bcpm::Tests::TestMatch
|
163
|
+
|
164
|
+
end # namespace Bcpm::Tests
|
165
|
+
|
166
|
+
end # namespace Bcpm
|
data/lib/bcpm/update.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
# :nodoc: namespace
|
5
|
+
module Bcpm
|
6
|
+
|
7
|
+
# Bcpm updating code.
|
8
|
+
module Update
|
9
|
+
# Updates bcpm to the latest version.
|
10
|
+
def self.upgrade(branch = 'master')
|
11
|
+
source_path = tempdir
|
12
|
+
return false unless Bcpm::Git.clone_repo(repo_uri, 'master', source_path)
|
13
|
+
success = nil
|
14
|
+
Dir.chdir source_path do
|
15
|
+
success = Kernel.system 'rake', 'install'
|
16
|
+
end
|
17
|
+
FileUtils.rm_r source_path
|
18
|
+
success
|
19
|
+
end
|
20
|
+
|
21
|
+
# Temporary directory name.
|
22
|
+
def self.tempdir
|
23
|
+
File.join Dir.tmpdir, 'bcpm',
|
24
|
+
"update_#{Socket.hostname}_#{(Time.now.to_f * 1000).to_i}_#{$PID}"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Git URI to the bcpm repository.
|
28
|
+
def self.repo_uri
|
29
|
+
Bcpm::Config[:bcpm_repo_uri] ||= default_repo_uri
|
30
|
+
end
|
31
|
+
|
32
|
+
# Git URI to the bcpm repository.
|
33
|
+
def self.default_repo_uri
|
34
|
+
'git@git.pwnb.us:six370/bcpm.git'
|
35
|
+
end
|
36
|
+
end # module Bcpm::Update
|
37
|
+
|
38
|
+
end # module Bcpm
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bcpm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 11
|
9
|
+
version: "0.11"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Victor Costan
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-01-26 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: echoe
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 3
|
31
|
+
- 2
|
32
|
+
version: "3.2"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
description: Battlecode (MIT 6.370) package manager.
|
36
|
+
email: victor@costan.us
|
37
|
+
executables:
|
38
|
+
- bcpm
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- CHANGELOG
|
43
|
+
- README
|
44
|
+
- bin/bcpm
|
45
|
+
- lib/bcpm.rb
|
46
|
+
- lib/bcpm/cleanup.rb
|
47
|
+
- lib/bcpm/cli.rb
|
48
|
+
- lib/bcpm/config.rb
|
49
|
+
- lib/bcpm/dist.rb
|
50
|
+
- lib/bcpm/duel.rb
|
51
|
+
- lib/bcpm/git.rb
|
52
|
+
- lib/bcpm/match.rb
|
53
|
+
- lib/bcpm/player.rb
|
54
|
+
- lib/bcpm/regen.rb
|
55
|
+
- lib/bcpm/socket.rb
|
56
|
+
- lib/bcpm/tests/assertion_error.rb
|
57
|
+
- lib/bcpm/tests/assertions.rb
|
58
|
+
- lib/bcpm/tests/case_base.rb
|
59
|
+
- lib/bcpm/tests/environment.rb
|
60
|
+
- lib/bcpm/tests/suite.rb
|
61
|
+
- lib/bcpm/tests/test_match.rb
|
62
|
+
- lib/bcpm/update.rb
|
63
|
+
files:
|
64
|
+
- CHANGELOG
|
65
|
+
- Manifest
|
66
|
+
- README
|
67
|
+
- Rakefile
|
68
|
+
- bin/bcpm
|
69
|
+
- lib/bcpm.rb
|
70
|
+
- lib/bcpm/cleanup.rb
|
71
|
+
- lib/bcpm/cli.rb
|
72
|
+
- lib/bcpm/config.rb
|
73
|
+
- lib/bcpm/dist.rb
|
74
|
+
- lib/bcpm/duel.rb
|
75
|
+
- lib/bcpm/git.rb
|
76
|
+
- lib/bcpm/match.rb
|
77
|
+
- lib/bcpm/player.rb
|
78
|
+
- lib/bcpm/regen.rb
|
79
|
+
- lib/bcpm/socket.rb
|
80
|
+
- lib/bcpm/tests/assertion_error.rb
|
81
|
+
- lib/bcpm/tests/assertions.rb
|
82
|
+
- lib/bcpm/tests/case_base.rb
|
83
|
+
- lib/bcpm/tests/environment.rb
|
84
|
+
- lib/bcpm/tests/suite.rb
|
85
|
+
- lib/bcpm/tests/test_match.rb
|
86
|
+
- lib/bcpm/update.rb
|
87
|
+
- bcpm.gemspec
|
88
|
+
has_rdoc: true
|
89
|
+
homepage: http://git.pwnb.us/six370
|
90
|
+
licenses: []
|
91
|
+
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options:
|
94
|
+
- --line-numbers
|
95
|
+
- --inline-source
|
96
|
+
- --title
|
97
|
+
- Bcpm
|
98
|
+
- --main
|
99
|
+
- README
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
hash: 3
|
108
|
+
segments:
|
109
|
+
- 0
|
110
|
+
version: "0"
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
hash: 11
|
117
|
+
segments:
|
118
|
+
- 1
|
119
|
+
- 2
|
120
|
+
version: "1.2"
|
121
|
+
requirements: []
|
122
|
+
|
123
|
+
rubyforge_project: bcpm
|
124
|
+
rubygems_version: 1.3.7
|
125
|
+
signing_key:
|
126
|
+
specification_version: 3
|
127
|
+
summary: Battlecode (MIT 6.370) package manager.
|
128
|
+
test_files: []
|
129
|
+
|