modsvaskr 0.1.8 → 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -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