modsvaskr 0.1.11 → 0.2.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.
- checksums.yaml +4 -4
- data/bin/modsvaskr +11 -11
- data/lib/modsvaskr/config.rb +78 -79
- data/lib/modsvaskr/encoding.rb +3 -1
- data/lib/modsvaskr/game.rb +208 -203
- data/lib/modsvaskr/games/skyrim_se.rb +110 -106
- data/lib/modsvaskr/in_game_tests_runner.rb +348 -348
- data/lib/modsvaskr/logger.rb +45 -44
- data/lib/modsvaskr/run_cmd.rb +23 -22
- data/lib/modsvaskr/tests_runner.rb +204 -205
- data/lib/modsvaskr/tests_suite.rb +70 -69
- data/lib/modsvaskr/tests_suites/exterior_cell.rb +120 -117
- data/lib/modsvaskr/tests_suites/interior_cell.rb +63 -63
- data/lib/modsvaskr/tests_suites/npc.rb +67 -64
- data/lib/modsvaskr/tests_suites/npc_head.rb +2 -1
- data/lib/modsvaskr/ui.rb +205 -204
- data/lib/modsvaskr/version.rb +5 -5
- data/lib/modsvaskr/xedit.rb +65 -65
- metadata +42 -13
@@ -4,6 +4,7 @@ module Modsvaskr
|
|
4
4
|
|
5
5
|
module TestsSuites
|
6
6
|
|
7
|
+
# Test NPCs by taking head screenshots
|
7
8
|
class NpcHead < TestsSuites::Npc
|
8
9
|
|
9
10
|
# Return the in-game tests suite to which we forward the tests to be run
|
@@ -21,7 +22,7 @@ module Modsvaskr
|
|
21
22
|
# * Hash< String, Hash<Symbol,Object> >: Ordered hash of test information, per test name
|
22
23
|
def discover_tests
|
23
24
|
tests = super
|
24
|
-
tests.
|
25
|
+
tests.each_value do |test_info|
|
25
26
|
test_info[:name].gsub!('Take screenshot', 'Take head screenshot')
|
26
27
|
end
|
27
28
|
tests
|
data/lib/modsvaskr/ui.rb
CHANGED
@@ -1,204 +1,205 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require 'modsvaskr/
|
4
|
-
require 'modsvaskr/
|
5
|
-
require 'modsvaskr/
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
'
|
74
|
-
|
75
|
-
'
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
end
|
125
|
-
|
126
|
-
end
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
)
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
end
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
end
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
end
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
logs_menu.item
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
1
|
+
require 'English'
|
2
|
+
require 'curses_menu'
|
3
|
+
require 'modsvaskr/logger'
|
4
|
+
require 'modsvaskr/tests_runner'
|
5
|
+
require 'modsvaskr/run_cmd'
|
6
|
+
require 'modsvaskr/version'
|
7
|
+
|
8
|
+
module Modsvaskr
|
9
|
+
|
10
|
+
# Main UI, using ncurses
|
11
|
+
class Ui
|
12
|
+
|
13
|
+
include RunCmd
|
14
|
+
include Logger
|
15
|
+
|
16
|
+
# Constructor
|
17
|
+
#
|
18
|
+
# Parameters::
|
19
|
+
# * *config* (Config): Configuration object
|
20
|
+
def initialize(config:)
|
21
|
+
log "Launch Modsvaskr UI v#{Modsvaskr::VERSION} - Logs in #{Logger.log_file}"
|
22
|
+
@config = config
|
23
|
+
end
|
24
|
+
|
25
|
+
# Run the UI
|
26
|
+
def run
|
27
|
+
last_modsvaskr_version = nil
|
28
|
+
gem_list_stdout = `gem list modsvaskr --remote`
|
29
|
+
gem_list_stdout.split("\n").each do |line|
|
30
|
+
if line =~ /^modsvaskr \((.+?)\)/
|
31
|
+
last_modsvaskr_version = Regexp.last_match(1)
|
32
|
+
break
|
33
|
+
end
|
34
|
+
end
|
35
|
+
log "!!! Could not get latest Modsvaskr version. Output of gem list modsvaskr --remote:\n#{gem_list_stdout}" if last_modsvaskr_version.nil?
|
36
|
+
key_presses = @config.auto_keys.map do |key_str|
|
37
|
+
case key_str
|
38
|
+
when 'KEY_ENTER', 'KEY_ESCAPE'
|
39
|
+
CursesMenu.const_get(key_str.to_sym)
|
40
|
+
when /^KEY_\w+$/
|
41
|
+
Curses.const_get(key_str.to_sym)
|
42
|
+
else
|
43
|
+
key_str
|
44
|
+
end
|
45
|
+
end
|
46
|
+
CursesMenu.new(
|
47
|
+
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods#{!last_modsvaskr_version.nil? && last_modsvaskr_version != Modsvaskr::VERSION ? " - !!! New version available: #{last_modsvaskr_version}" : ''}",
|
48
|
+
key_presses:
|
49
|
+
) do |main_menu|
|
50
|
+
@config.games.each do |game|
|
51
|
+
main_menu.item "#{game.name} (#{game.path})" do
|
52
|
+
CursesMenu.new(
|
53
|
+
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods > #{game.name}",
|
54
|
+
key_presses:
|
55
|
+
) do |game_menu|
|
56
|
+
game_menu.item 'Testing' do
|
57
|
+
# Read tests info
|
58
|
+
tests_runner = TestsRunner.new(@config, game)
|
59
|
+
# Selected test names, per test type
|
60
|
+
# Hash< Symbol, Hash< String, nil > >
|
61
|
+
selected_tests_suites = {}
|
62
|
+
CursesMenu.new(
|
63
|
+
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods > #{game.name} > Testing",
|
64
|
+
key_presses:
|
65
|
+
) do |test_menu|
|
66
|
+
tests_runner.tests_suites.each do |tests_suite|
|
67
|
+
statuses_for_suite = tests_runner.statuses_for(tests_suite)
|
68
|
+
all_tests_selected = selected_tests_suites.key?(tests_suite) &&
|
69
|
+
selected_tests_suites[tests_suite].keys.sort == statuses_for_suite.map { |(test_name, _test_status)| test_name }.sort
|
70
|
+
test_menu.item(
|
71
|
+
"[#{
|
72
|
+
if all_tests_selected
|
73
|
+
'*'
|
74
|
+
elsif selected_tests_suites.key?(tests_suite)
|
75
|
+
'+'
|
76
|
+
else
|
77
|
+
' '
|
78
|
+
end
|
79
|
+
}] #{tests_suite} - #{statuses_for_suite.select { |(_name, status)| status == 'ok' }.size} / #{statuses_for_suite.size}",
|
80
|
+
actions: {
|
81
|
+
'd' => {
|
82
|
+
name: 'Details',
|
83
|
+
execute: proc do
|
84
|
+
CursesMenu.new(
|
85
|
+
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods > #{game.name} > Testing > Tests #{tests_suite}",
|
86
|
+
key_presses:
|
87
|
+
) do |tests_suite_menu|
|
88
|
+
statuses_for_suite.each do |(test_name, test_status)|
|
89
|
+
test_selected = selected_tests_suites.key?(tests_suite) && selected_tests_suites[tests_suite].key?(test_name)
|
90
|
+
tests_suite_menu.item "[#{test_selected ? '*' : ' '}] #{test_name} - #{test_status} - #{tests_runner.test_info(tests_suite, test_name)[:name]}" do
|
91
|
+
if test_selected
|
92
|
+
selected_tests_suites[tests_suite].delete(test_name)
|
93
|
+
selected_tests_suites.delete(tests_suite) if selected_tests_suites[tests_suite].empty?
|
94
|
+
else
|
95
|
+
selected_tests_suites[tests_suite] = {} unless selected_tests_suites.key?(tests_suite)
|
96
|
+
selected_tests_suites[tests_suite][test_name] = nil
|
97
|
+
end
|
98
|
+
:menu_refresh
|
99
|
+
end
|
100
|
+
end
|
101
|
+
tests_suite_menu.item 'Back' do
|
102
|
+
:menu_exit
|
103
|
+
end
|
104
|
+
end
|
105
|
+
:menu_refresh
|
106
|
+
end
|
107
|
+
}
|
108
|
+
}
|
109
|
+
) do
|
110
|
+
if all_tests_selected
|
111
|
+
selected_tests_suites.delete(tests_suite)
|
112
|
+
else
|
113
|
+
selected_tests_suites[tests_suite] = statuses_for_suite.to_h { |(test_name, _test_status)| [test_name, nil] }
|
114
|
+
end
|
115
|
+
:menu_refresh
|
116
|
+
end
|
117
|
+
end
|
118
|
+
test_menu.item 'Select tests that are not ok' do
|
119
|
+
selected_tests_suites = {}
|
120
|
+
tests_runner.tests_suites.map do |tests_suite|
|
121
|
+
tests_not_ok = {}
|
122
|
+
tests_runner.statuses_for(tests_suite).each do |(test_name, test_status)|
|
123
|
+
tests_not_ok[test_name] = nil unless test_status == 'ok'
|
124
|
+
end
|
125
|
+
selected_tests_suites[tests_suite] = tests_not_ok unless tests_not_ok.empty?
|
126
|
+
end
|
127
|
+
:menu_refresh
|
128
|
+
end
|
129
|
+
test_menu.item 'Register tests from selected test suites' do
|
130
|
+
selected_tests_suites.each_key do |tests_suite|
|
131
|
+
tests_runner.set_statuses_for(
|
132
|
+
tests_suite,
|
133
|
+
(
|
134
|
+
tests_runner.discover_tests_for(tests_suite) -
|
135
|
+
tests_runner.statuses_for(tests_suite).map { |(test_name, _test_status)| test_name }
|
136
|
+
).map { |test_name| [test_name, ''] }
|
137
|
+
)
|
138
|
+
end
|
139
|
+
:menu_refresh
|
140
|
+
end
|
141
|
+
test_menu.item 'Unregister tests from selected test suites' do
|
142
|
+
selected_tests_suites.each_key do |tests_suite|
|
143
|
+
tests_runner.clear_tests_for(tests_suite)
|
144
|
+
end
|
145
|
+
:menu_refresh
|
146
|
+
end
|
147
|
+
test_menu.item 'Clear selected test statuses' do
|
148
|
+
selected_tests_suites.each do |tests_suite, test_names_set|
|
149
|
+
tests_runner.set_statuses_for(tests_suite, test_names_set.keys.map { |test_name| [test_name, ''] })
|
150
|
+
end
|
151
|
+
:menu_refresh
|
152
|
+
end
|
153
|
+
test_menu.item 'Run remaining selected tests' do
|
154
|
+
tests_runner.run(
|
155
|
+
selected_tests_suites.map do |selected_tests_suite, selected_test_names_set|
|
156
|
+
[
|
157
|
+
selected_tests_suite,
|
158
|
+
# Make sure tests to be run are ordered from the registered list
|
159
|
+
tests_runner.
|
160
|
+
statuses_for(selected_tests_suite).map { |(test_name, _test_status)| test_name }.
|
161
|
+
select { |test_name| selected_test_names_set.key?(test_name) }
|
162
|
+
]
|
163
|
+
end
|
164
|
+
)
|
165
|
+
:menu_refresh
|
166
|
+
end
|
167
|
+
test_menu.item 'Back' do
|
168
|
+
:menu_exit
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
game.complete_game_menu(game_menu) if game.respond_to?(:complete_game_menu)
|
173
|
+
game_menu.item 'Back' do
|
174
|
+
:menu_exit
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
main_menu.item 'See logs' do
|
180
|
+
CursesMenu.new(
|
181
|
+
'Modsvaskr - Stronghold of Mods > Logs',
|
182
|
+
key_presses:
|
183
|
+
) do |logs_menu|
|
184
|
+
File.read(Logger.log_file).split("\n").each do |line|
|
185
|
+
logs_menu.item line
|
186
|
+
end
|
187
|
+
logs_menu.item 'Back' do
|
188
|
+
:menu_exit
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
main_menu.item 'Quit' do
|
193
|
+
:menu_exit
|
194
|
+
end
|
195
|
+
end
|
196
|
+
rescue
|
197
|
+
log "Unhandled exception: #{$ERROR_INFO}\n#{$ERROR_INFO.backtrace.join("\n")}"
|
198
|
+
raise
|
199
|
+
ensure
|
200
|
+
log 'Close Modsvaskr UI'
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
data/lib/modsvaskr/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
module Modsvaskr
|
2
|
-
|
3
|
-
VERSION = '0.
|
4
|
-
|
5
|
-
end
|
1
|
+
module Modsvaskr
|
2
|
+
|
3
|
+
VERSION = '0.2.0'
|
4
|
+
|
5
|
+
end
|
data/lib/modsvaskr/xedit.rb
CHANGED
@@ -1,65 +1,65 @@
|
|
1
|
-
require 'csv'
|
2
|
-
require 'modsvaskr/encoding'
|
3
|
-
require 'modsvaskr/run_cmd'
|
4
|
-
|
5
|
-
module Modsvaskr
|
6
|
-
|
7
|
-
# Helper to use an instance of xEdit
|
8
|
-
class Xedit
|
9
|
-
|
10
|
-
include RunCmd
|
11
|
-
|
12
|
-
# String: Installation path
|
13
|
-
attr_reader :install_path
|
14
|
-
|
15
|
-
# Constructor
|
16
|
-
#
|
17
|
-
# Parameters::
|
18
|
-
# * *install_path* (String): Installation path of xEdit
|
19
|
-
# * *game_path* (String): Installation path of the game to use xEdit on
|
20
|
-
def initialize(install_path, game_path)
|
21
|
-
@install_path = install_path
|
22
|
-
@game_path = game_path
|
23
|
-
# Set of scripts that have been run
|
24
|
-
@runs = {}
|
25
|
-
end
|
26
|
-
|
27
|
-
# Run an xEdit script
|
28
|
-
#
|
29
|
-
# Parameters::
|
30
|
-
# * *script* (String): Script name, as defined in xedit_scripts (without the Modsvaskr_ prefix and .pas suffix)
|
31
|
-
# * *only_once* (Boolean): If true, then make sure this script is run only once by instance [default: false]
|
32
|
-
def run_script(script, only_once: false)
|
33
|
-
if
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
# Parse a CSV that has been dumped by a previous run of xEdit
|
53
|
-
#
|
54
|
-
# Parameters::
|
55
|
-
# * *csv* (String): Name of the CSV file (from Edit Scripts), without .csv
|
56
|
-
# *
|
57
|
-
# Parameters::
|
58
|
-
# * *row* (Array<String>): CSV row
|
59
|
-
def parse_csv(csv, &
|
60
|
-
CSV.parse(Encoding.
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
1
|
+
require 'csv'
|
2
|
+
require 'modsvaskr/encoding'
|
3
|
+
require 'modsvaskr/run_cmd'
|
4
|
+
|
5
|
+
module Modsvaskr
|
6
|
+
|
7
|
+
# Helper to use an instance of xEdit
|
8
|
+
class Xedit
|
9
|
+
|
10
|
+
include RunCmd
|
11
|
+
|
12
|
+
# String: Installation path
|
13
|
+
attr_reader :install_path
|
14
|
+
|
15
|
+
# Constructor
|
16
|
+
#
|
17
|
+
# Parameters::
|
18
|
+
# * *install_path* (String): Installation path of xEdit
|
19
|
+
# * *game_path* (String): Installation path of the game to use xEdit on
|
20
|
+
def initialize(install_path, game_path)
|
21
|
+
@install_path = install_path
|
22
|
+
@game_path = game_path
|
23
|
+
# Set of scripts that have been run
|
24
|
+
@runs = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Run an xEdit script
|
28
|
+
#
|
29
|
+
# Parameters::
|
30
|
+
# * *script* (String): Script name, as defined in xedit_scripts (without the Modsvaskr_ prefix and .pas suffix)
|
31
|
+
# * *only_once* (Boolean): If true, then make sure this script is run only once by instance [default: false]
|
32
|
+
def run_script(script, only_once: false)
|
33
|
+
return if only_once && @runs.key?(script)
|
34
|
+
|
35
|
+
FileUtils.cp "#{__dir__}/../../xedit_scripts/Modsvaskr_#{script}.pas", "#{@install_path}/Edit Scripts/Modsvaskr_#{script}.pas"
|
36
|
+
run_cmd(
|
37
|
+
{
|
38
|
+
dir: @install_path,
|
39
|
+
exe: 'SSEEdit.exe'
|
40
|
+
},
|
41
|
+
args: %W[
|
42
|
+
-IKnowWhatImDoing
|
43
|
+
-AllowMasterFilesEdit
|
44
|
+
-SSE
|
45
|
+
-autoload
|
46
|
+
-script:"Modsvaskr_#{script}.pas"
|
47
|
+
]
|
48
|
+
)
|
49
|
+
@runs[script] = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
# Parse a CSV that has been dumped by a previous run of xEdit
|
53
|
+
#
|
54
|
+
# Parameters::
|
55
|
+
# * *csv* (String): Name of the CSV file (from Edit Scripts), without .csv
|
56
|
+
# * Proc: Code called for each CSV row
|
57
|
+
# Parameters::
|
58
|
+
# * *row* (Array<String>): CSV row
|
59
|
+
def parse_csv(csv, &)
|
60
|
+
CSV.parse(Encoding.to_utf_8(File.read("#{install_path}/Edit Scripts/#{csv}.csv", mode: 'rb'))).each(&)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|