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