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.
@@ -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
@@ -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
+