modsvaskr 0.1.11 → 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,64 +1,67 @@
1
- require 'modsvaskr/in_game_tests_suite'
2
-
3
- module Modsvaskr
4
-
5
- module TestsSuites
6
-
7
- class Npc < TestsSuite
8
-
9
- include InGameTestsSuite
10
-
11
- # Return the in-game tests suite to which we forward the tests to be run
12
- #
13
- # Result::
14
- # * Symbol: In-game tests suite
15
- def in_game_tests_suite
16
- :npcs
17
- end
18
-
19
- # Discover the list of tests information that could be run.
20
- # [API] - This method is mandatory
21
- #
22
- # Result::
23
- # * Hash< String, Hash<Symbol,Object> >: Ordered hash of test information, per test name
24
- def discover_tests
25
- tests = {}
26
- @game.xedit.run_script('DumpInfo', only_once: true)
27
- # Keep track of masters, per plugin
28
- # Hash<String, Array<String> >
29
- masters = {}
30
- # Keep track of NPCs
31
- # Array< [String, Integer, String] >
32
- # Array< [Plugin, FormID, NPC ] >
33
- npcs = []
34
- @game.xedit.parse_csv('Modsvaskr_ExportedDumpInfo') do |row|
35
- case row[1].downcase
36
- when 'npc_'
37
- npcs << [row[0].downcase, row[2].to_i(16), row[3]]
38
- when 'tes4'
39
- masters[row[0].downcase] = row[3..-1].map(&:downcase)
40
- end
41
- end
42
- npcs.each do |(esp, form_id, npc_name)|
43
- raise "Esp #{esp} declares NPC FormID #{form_id} (#{npc_name}) but its masters could not be parsed" unless masters.key?(esp)
44
- # Know from which mod this ID comes from
45
- mod_idx = form_id / 16_777_216
46
- raise "NPC FormID #{form_id} (#{npc_name}) from #{esp} references an unknown master (known masters: #{masters[esp].join(', ')})" if mod_idx > masters[esp].size
47
- test_name = "#{mod_idx == masters[esp].size ? esp : masters[esp][mod_idx]}/#{form_id % 16_777_216}"
48
- if tests.key?(test_name)
49
- # Add the name of the mod to the description, so that we know which mod modifies which NPC.
50
- tests[test_name][:name] << "/#{esp}"
51
- else
52
- tests[test_name] = {
53
- name: "Take screenshot of #{npc_name} - #{esp}"
54
- }
55
- end
56
- end
57
- tests
58
- end
59
-
60
- end
61
-
62
- end
63
-
64
- end
1
+ require 'modsvaskr/in_game_tests_suite'
2
+
3
+ module Modsvaskr
4
+
5
+ module TestsSuites
6
+
7
+ # Test NPCs by taking screenshots
8
+ class Npc < TestsSuite
9
+
10
+ include InGameTestsSuite
11
+
12
+ # Return the in-game tests suite to which we forward the tests to be run
13
+ #
14
+ # Result::
15
+ # * Symbol: In-game tests suite
16
+ def in_game_tests_suite
17
+ :npcs
18
+ end
19
+
20
+ # Discover the list of tests information that could be run.
21
+ # [API] - This method is mandatory
22
+ #
23
+ # Result::
24
+ # * Hash< String, Hash<Symbol,Object> >: Ordered hash of test information, per test name
25
+ def discover_tests
26
+ tests = {}
27
+ @game.xedit.run_script('DumpInfo', only_once: true)
28
+ # Keep track of masters, per plugin
29
+ # Hash<String, Array<String> >
30
+ masters = {}
31
+ # Keep track of NPCs
32
+ # Array< [String, Integer, String] >
33
+ # Array< [Plugin, FormID, NPC ] >
34
+ npcs = []
35
+ @game.xedit.parse_csv('Modsvaskr_ExportedDumpInfo') do |row|
36
+ case row[1].downcase
37
+ when 'npc_'
38
+ npcs << [row[0].downcase, row[2].to_i(16), row[3]]
39
+ when 'tes4'
40
+ masters[row[0].downcase] = row[3..].map(&:downcase)
41
+ end
42
+ end
43
+ npcs.each do |(esp, form_id, npc_name)|
44
+ raise "Esp #{esp} declares NPC FormID #{form_id} (#{npc_name}) but its masters could not be parsed" unless masters.key?(esp)
45
+
46
+ # Know from which mod this ID comes from
47
+ mod_idx = form_id / 16_777_216
48
+ raise "NPC FormID #{form_id} (#{npc_name}) from #{esp} references an unknown master (known masters: #{masters[esp].join(', ')})" if mod_idx > masters[esp].size
49
+
50
+ test_name = "#{mod_idx == masters[esp].size ? esp : masters[esp][mod_idx]}/#{form_id % 16_777_216}"
51
+ if tests.key?(test_name)
52
+ # Add the name of the mod to the description, so that we know which mod modifies which NPC.
53
+ tests[test_name][:name] << "/#{esp}"
54
+ else
55
+ tests[test_name] = {
56
+ name: "Take screenshot of #{npc_name} - #{esp}"
57
+ }
58
+ end
59
+ end
60
+ tests
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -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.values.each do |test_info|
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 'curses_menu'
2
- require 'modsvaskr/logger'
3
- require 'modsvaskr/tests_runner'
4
- require 'modsvaskr/run_cmd'
5
- require 'modsvaskr/version'
6
-
7
- module Modsvaskr
8
-
9
- class Ui
10
-
11
- include Logger, RunCmd
12
-
13
- # Constructor
14
- #
15
- # Parameters::
16
- # * *config* (Config): Configuration object
17
- def initialize(config:, skyrim: nil)
18
- log "Launch Modsvaskr UI v#{Modsvaskr::VERSION} - Logs in #{Logger.log_file}"
19
- @config = config
20
- end
21
-
22
- # Run the UI
23
- def run
24
- begin
25
- last_modsvaskr_version = nil
26
- gem_list_stdout = `gem list modsvaskr --remote`
27
- gem_list_stdout.split("\n").each do |line|
28
- if line =~ /^modsvaskr \((.+?)\)/
29
- last_modsvaskr_version = $1
30
- break
31
- end
32
- end
33
- log "!!! Could not get latest Modsvaskr version. Output of gem list modsvaskr --remote:\n#{gem_list_stdout}" if last_modsvaskr_version.nil?
34
- key_presses = @config.auto_keys.map do |key_str|
35
- case key_str
36
- when 'KEY_ENTER', 'KEY_ESCAPE'
37
- CursesMenu.const_get(key_str.to_sym)
38
- when /^KEY_\w+$/
39
- Curses.const_get(key_str.to_sym)
40
- else
41
- key_str
42
- end
43
- end
44
- CursesMenu.new(
45
- "Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods#{!last_modsvaskr_version.nil? && last_modsvaskr_version != Modsvaskr::VERSION ? " - !!! New version available: #{last_modsvaskr_version}" : ''}",
46
- key_presses: key_presses
47
- ) do |main_menu|
48
- @config.games.each do |game|
49
- main_menu.item "#{game.name} (#{game.path})" do
50
- CursesMenu.new(
51
- "Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods > #{game.name}",
52
- key_presses: key_presses
53
- ) do |game_menu|
54
- game_menu.item 'Testing' do
55
- # Read tests info
56
- tests_runner = TestsRunner.new(@config, game)
57
- # Selected test names, per test type
58
- # Hash< Symbol, Hash< String, nil > >
59
- selected_tests_suites = {}
60
- CursesMenu.new(
61
- "Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods > #{game.name} > Testing",
62
- key_presses: key_presses
63
- ) do |test_menu|
64
- tests_runner.tests_suites.each do |tests_suite|
65
- statuses_for_suite = tests_runner.statuses_for(tests_suite)
66
- all_tests_selected = selected_tests_suites.key?(tests_suite) &&
67
- selected_tests_suites[tests_suite].keys.sort == statuses_for_suite.map { |(test_name, _test_status)| test_name }.sort
68
- test_menu.item(
69
- "[#{
70
- if all_tests_selected
71
- '*'
72
- elsif selected_tests_suites.key?(tests_suite)
73
- '+'
74
- else
75
- ' '
76
- end
77
- }] #{tests_suite} - #{statuses_for_suite.select { |(_name, status)| status == 'ok' }.size} / #{statuses_for_suite.size}",
78
- actions: {
79
- 'd' => {
80
- name: 'Details',
81
- execute: proc do
82
- CursesMenu.new(
83
- "Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods > #{game.name} > Testing > Tests #{tests_suite}",
84
- key_presses: key_presses
85
- ) do |tests_suite_menu|
86
- statuses_for_suite.each do |(test_name, test_status)|
87
- test_selected = selected_tests_suites.key?(tests_suite) && selected_tests_suites[tests_suite].key?(test_name)
88
- tests_suite_menu.item "[#{test_selected ? '*' : ' '}] #{test_name} - #{test_status} - #{tests_runner.test_info(tests_suite, test_name)[:name]}" do
89
- if test_selected
90
- selected_tests_suites[tests_suite].delete(test_name)
91
- selected_tests_suites.delete(tests_suite) if selected_tests_suites[tests_suite].empty?
92
- else
93
- selected_tests_suites[tests_suite] = {} unless selected_tests_suites.key?(tests_suite)
94
- selected_tests_suites[tests_suite][test_name] = nil
95
- end
96
- :menu_refresh
97
- end
98
- end
99
- tests_suite_menu.item 'Back' do
100
- :menu_exit
101
- end
102
- end
103
- :menu_refresh
104
- end
105
- }
106
- }
107
- ) do
108
- if all_tests_selected
109
- selected_tests_suites.delete(tests_suite)
110
- else
111
- selected_tests_suites[tests_suite] = Hash[statuses_for_suite.map { |(test_name, _test_status)| [test_name, nil] }]
112
- end
113
- :menu_refresh
114
- end
115
- end
116
- test_menu.item 'Select tests that are not ok' do
117
- selected_tests_suites = {}
118
- tests_runner.tests_suites.map do |tests_suite|
119
- tests_not_ok = {}
120
- tests_runner.statuses_for(tests_suite).each do |(test_name, test_status)|
121
- tests_not_ok[test_name] = nil unless test_status == 'ok'
122
- end
123
- selected_tests_suites[tests_suite] = tests_not_ok unless tests_not_ok.empty?
124
- end
125
- :menu_refresh
126
- end
127
- test_menu.item 'Register tests from selected test suites' do
128
- selected_tests_suites.keys.each do |tests_suite|
129
- tests_runner.set_statuses_for(
130
- tests_suite,
131
- (
132
- tests_runner.discover_tests_for(tests_suite) -
133
- tests_runner.statuses_for(tests_suite).map { |(test_name, _test_status)| test_name }
134
- ).map { |test_name| [test_name, ''] }
135
- )
136
- end
137
- :menu_refresh
138
- end
139
- test_menu.item 'Unregister tests from selected test suites' do
140
- selected_tests_suites.keys.each do |tests_suite|
141
- tests_runner.clear_tests_for(tests_suite)
142
- end
143
- :menu_refresh
144
- end
145
- test_menu.item 'Clear selected test statuses' do
146
- selected_tests_suites.each do |tests_suite, test_names_set|
147
- tests_runner.set_statuses_for(tests_suite, test_names_set.keys.map { |test_name| [test_name, ''] })
148
- end
149
- :menu_refresh
150
- end
151
- test_menu.item 'Run remaining selected tests' do
152
- tests_runner.run(
153
- selected_tests_suites.map do |selected_tests_suite, selected_test_names_set|
154
- [
155
- selected_tests_suite,
156
- # Make sure tests to be run are ordered from the registered list
157
- tests_runner.
158
- statuses_for(selected_tests_suite).map { |(test_name, _test_status)| test_name }.
159
- select { |test_name| selected_test_names_set.key?(test_name) }
160
- ]
161
- end
162
- )
163
- :menu_refresh
164
- end
165
- test_menu.item 'Back' do
166
- :menu_exit
167
- end
168
- end
169
- end
170
- game.complete_game_menu(game_menu) if game.respond_to?(:complete_game_menu)
171
- game_menu.item 'Back' do
172
- :menu_exit
173
- end
174
- end
175
- end
176
- end
177
- main_menu.item 'See logs' do
178
- CursesMenu.new(
179
- 'Modsvaskr - Stronghold of Mods > Logs',
180
- key_presses: key_presses
181
- ) do |logs_menu|
182
- File.read(Logger.log_file).split("\n").each do |line|
183
- logs_menu.item line
184
- end
185
- logs_menu.item 'Back' do
186
- :menu_exit
187
- end
188
- end
189
- end
190
- main_menu.item 'Quit' do
191
- :menu_exit
192
- end
193
- end
194
- rescue
195
- log "Unhandled exception: #{$!}\n#{$!.backtrace.join("\n")}"
196
- raise
197
- ensure
198
- log 'Close Modsvaskr UI'
199
- end
200
- end
201
-
202
- end
203
-
204
- end
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: 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: 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: 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: 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.map { |(test_name, _test_status)| [test_name, nil] }.to_h
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: 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