modsvaskr 0.1.11 → 0.1.12

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