Class: Inferno::CLI::Session::SessionCompare::ComparedTestResult
- Inherits:
-
Object
- Object
- Inferno::CLI::Session::SessionCompare::ComparedTestResult
- Defined in:
- lib/inferno/apps/cli/session/session_compare.rb
Constant Summary collapse
- MESSAGE_TYPE_ORDER =
{ 'error' => 0, 'warning' => 1, 'info' => 2 }.freeze
- UNKNOWN_MESSAGE_TYPE_ORDER =
99
Instance Attribute Summary collapse
-
#actual_result ⇒ Object
readonly
Returns the value of attribute actual_result.
-
#expected_result ⇒ Object
readonly
Returns the value of attribute expected_result.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#short_id_map ⇒ Object
readonly
Returns the value of attribute short_id_map.
Instance Method Summary collapse
- #build_message_comparisons ⇒ Object
- #collapse_message_lines(lines) ⇒ Object
- #comparison_csv_row ⇒ Object
- #different_messages? ⇒ Boolean
- #different_result? ⇒ Boolean
- #different_result_message? ⇒ Boolean
- #format_messages_for_csv(results) ⇒ Object
-
#initialize(id, expected_result, actual_result, options, short_id_map = {}) ⇒ ComparedTestResult
constructor
A new instance of ComparedTestResult.
- #lcs_align(expected, actual) ⇒ Object
- #lcs_backtrack(matrix, expected, actual) ⇒ Object
-
#lcs_backtrack_step(matrix, expected, actual, expected_index, actual_index) ⇒ Object
Each step returns { entry:, next_expected_index:, next_actual_index: }.
- #lcs_matrix(expected, actual) ⇒ Object
- #message_comparisons ⇒ Object
- #message_line_for_csv(entry, is_expected) ⇒ Object
- #message_text_for_csv(message, matches) ⇒ Object
- #normalize_string(str) ⇒ Object
- #normalizing? ⇒ Boolean
- #optional_to_h_fields ⇒ Object
-
#parse_normalize_entry(entry) ⇒ Object
Parses a normalize entry into an array of [pattern, replacement] pairs.
- #parse_pattern_string(str) ⇒ Object
- #same_message?(expected_message, actual_message) ⇒ Boolean
- #same_messages? ⇒ Boolean
- #same_result? ⇒ Boolean
- #same_results? ⇒ Boolean
- #short_id ⇒ Object
- #sorted_messages(result) ⇒ Object
- #to_h ⇒ Object
- #type ⇒ Object
Constructor Details
#initialize(id, expected_result, actual_result, options, short_id_map = {}) ⇒ ComparedTestResult
Returns a new instance of ComparedTestResult.
195 196 197 198 199 200 201 202 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 195 def initialize(id, expected_result, actual_result, , short_id_map = {}) @id = id @expected_result = expected_result @actual_result = actual_result @options = @short_id_map = short_id_map @same = same_results? end |
Instance Attribute Details
#actual_result ⇒ Object (readonly)
Returns the value of attribute actual_result.
193 194 195 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 193 def actual_result @actual_result end |
#expected_result ⇒ Object (readonly)
Returns the value of attribute expected_result.
193 194 195 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 193 def expected_result @expected_result end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
193 194 195 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 193 def id @id end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
193 194 195 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 193 def @options end |
#short_id_map ⇒ Object (readonly)
Returns the value of attribute short_id_map.
193 194 195 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 193 def short_id_map @short_id_map end |
Instance Method Details
#build_message_comparisons ⇒ Object
279 280 281 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 279 def lcs_align((expected_result), (actual_result)) end |
#collapse_message_lines(lines) ⇒ Object
443 444 445 446 447 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 443 def (lines) lines.chunk_while { |a, b| a == b }.map do |group| group.size > 1 ? "(#{group.size}) #{group.first}" : group.first end end |
#comparison_csv_row ⇒ Object
401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 401 def comparison_csv_row row = [id, short_id, type, different_result?, expected_result&.dig('result'), actual_result&.dig('result')] if [:compare_result_message] row << row << normalize_string(expected_result&.dig('result_message')) row << normalize_string(actual_result&.dig('result_message')) end if [:compare_messages] row << row << (expected_result) row << (actual_result) end row end |
#different_messages? ⇒ Boolean
372 373 374 375 376 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 372 def return false unless type == 'Compared' ! end |
#different_result? ⇒ Boolean
362 363 364 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 362 def different_result? !same_result? end |
#different_result_message? ⇒ Boolean
366 367 368 369 370 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 366 def return false unless type == 'Compared' normalize_string(expected_result['result_message']) != normalize_string(actual_result['result_message']) end |
#format_messages_for_csv(results) ⇒ Object
426 427 428 429 430 431 432 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 426 def (results) return '' unless results&.dig('messages').present? is_expected = results == expected_result lines = .filter_map { |entry| (entry, is_expected) } (lines).join("\n") end |
#lcs_align(expected, actual) ⇒ Object
283 284 285 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 283 def lcs_align(expected, actual) lcs_backtrack(lcs_matrix(expected, actual), expected, actual) end |
#lcs_backtrack(matrix, expected, actual) ⇒ Object
303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 303 def lcs_backtrack(matrix, expected, actual) alignment = [] expected_index = expected.size actual_index = actual.size while expected_index.positive? || actual_index.positive? step = lcs_backtrack_step(matrix, expected, actual, expected_index, actual_index) alignment.unshift(step[:entry]) expected_index = step[:next_expected_index] actual_index = step[:next_actual_index] end alignment end |
#lcs_backtrack_step(matrix, expected, actual, expected_index, actual_index) ⇒ Object
Each step returns { entry:, next_expected_index:, next_actual_index: }. entry is { expected: msg_or_nil, actual: msg_or_nil, match: bool }.
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 319 def lcs_backtrack_step(matrix, expected, actual, expected_index, actual_index) if expected_index.positive? && actual_index.positive? && (expected[expected_index - 1], actual[actual_index - 1]) # Items match: consume both entry = { expected: expected[expected_index - 1], actual: actual[actual_index - 1], match: true } { entry:, next_expected_index: expected_index - 1, next_actual_index: actual_index - 1 } elsif actual_index.positive? && (expected_index.zero? || matrix[expected_index][actual_index - 1] >= matrix[expected_index - 1][actual_index]) # Item in actual is "Additional": consume only actual { entry: { expected: nil, actual: actual[actual_index - 1], match: false }, next_expected_index: expected_index, next_actual_index: actual_index - 1 } else # Item in expected is "Missing": consume only expected { entry: { expected: expected[expected_index - 1], actual: nil, match: false }, next_expected_index: expected_index - 1, next_actual_index: actual_index } end end |
#lcs_matrix(expected, actual) ⇒ Object
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 287 def lcs_matrix(expected, actual) matrix = Array.new(expected.size + 1) { Array.new(actual.size + 1, 0) } (1..expected.size).each do |expected_index| (1..actual.size).each do |actual_index| matrix[expected_index][actual_index] = if (expected[expected_index - 1], actual[actual_index - 1]) matrix[expected_index - 1][actual_index - 1] + 1 else [matrix[expected_index - 1][actual_index], matrix[expected_index][actual_index - 1]].max end end end matrix end |
#message_comparisons ⇒ Object
272 273 274 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 272 def @message_comparisons ||= end |
#message_line_for_csv(entry, is_expected) ⇒ Object
434 435 436 437 438 439 440 441 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 434 def (entry, is_expected) return if [:only_different_messages] && entry[:match] msg = is_expected ? entry[:expected] : entry[:actual] return if msg.nil? (msg, entry[:match]) end |
#message_text_for_csv(message, matches) ⇒ Object
449 450 451 452 453 454 455 456 457 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 449 def (, matches) prefix = matches ? '- ' : '! ' text = normalize_string(['message'].to_s) .gsub("\r\n", '\n') .gsub("\n", '\n') .gsub("\r", '\r') .gsub("\t", '\t') "#{prefix}(#{['type']}) \"#{text}\"" end |
#normalize_string(str) ⇒ Object
241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 241 def normalize_string(str) return str unless str.present? Array([:normalized_strings]).reduce(str) do |s, entry| parse_normalize_entry(entry).reduce(s) do |s2, (pattern, replacement)| if pattern.is_a?(Regexp) s2.gsub(pattern, replacement) else s2.gsub(pattern, replacement).gsub(CGI.escape(pattern), replacement) end end end end |
#normalizing? ⇒ Boolean
255 256 257 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 255 def normalizing? [:normalized_strings].present? end |
#optional_to_h_fields ⇒ Object
388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 388 def optional_to_h_fields fields = {} if [:compare_result_message] fields[:expected_result_message] = expected_result&.dig('result_message') fields[:actual_result_message] = actual_result&.dig('result_message') end if [:compare_messages] fields[:expected_messages] = expected_result&.dig('messages') fields[:actual_messages] = actual_result&.dig('messages') end fields end |
#parse_normalize_entry(entry) ⇒ Object
Parses a normalize entry into an array of [pattern, replacement] pairs. Entries may be:
- A plain string: literal match, replacement defaults to '<NORMALIZED>'
- A "/pattern/[flags]" string: compiled to Regexp, replacement defaults to '<NORMALIZED>'
- A hash with 'pattern' or 'patterns' and optional 'replacement' keys (from YAML):
pattern: '/code_challenge=[A-Za-z0-9+\/=_-]{20,}/'
replacement: '<CODE_CHALLENGE>'
Or multiple patterns sharing one replacement:
patterns:
- '/code_challenge=[A-Za-z0-9+\/=_-]{20,}/'
- '/code_verifier=[A-Za-z0-9+\/=_-]{20,}/'
replacement: '<PKCE_VALUE>'
220 221 222 223 224 225 226 227 228 229 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 220 def parse_normalize_entry(entry) if entry.is_a?(Hash) replacement = entry.fetch('replacement', '<NORMALIZED>') Array(entry['patterns'] || entry['pattern']).map do |pattern| [parse_pattern_string(pattern.to_s), replacement] end else [[parse_pattern_string(entry.to_s), '<NORMALIZED>']] end end |
#parse_pattern_string(str) ⇒ Object
231 232 233 234 235 236 237 238 239 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 231 def parse_pattern_string(str) return str unless (parsed_regex = str.match(%r{\A/(.+)/([imx]*)\z}m)) flags = 0 flags |= Regexp::IGNORECASE if parsed_regex[2].include?('i') flags |= Regexp::MULTILINE if parsed_regex[2].include?('m') flags |= Regexp::EXTENDED if parsed_regex[2].include?('x') Regexp.new(parsed_regex[1], flags) end |
#same_message?(expected_message, actual_message) ⇒ Boolean
353 354 355 356 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 353 def (, ) ['type'] == ['type'] && normalize_string(['message']) == normalize_string(['message']) end |
#same_messages? ⇒ Boolean
349 350 351 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 349 def .all? { |entry| entry[:match] } end |
#same_result? ⇒ Boolean
358 359 360 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 358 def same_result? @same end |
#same_results? ⇒ Boolean
259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 259 def same_results? return false unless type == 'Compared' return false unless expected_result['result'] == actual_result['result'] if [:compare_result_message] && normalize_string(expected_result['result_message']) != normalize_string(actual_result['result_message']) return false end return false if [:compare_messages] && ! true end |
#short_id ⇒ Object
204 205 206 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 204 def short_id short_id_map[id] end |
#sorted_messages(result) ⇒ Object
342 343 344 345 346 347 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 342 def (result) Array(result&.dig('messages')).sort_by do |m| [MESSAGE_TYPE_ORDER.fetch(m['type'].to_s, UNKNOWN_MESSAGE_TYPE_ORDER), normalize_string(m['message'].to_s)] end end |
#to_h ⇒ Object
378 379 380 381 382 383 384 385 386 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 378 def to_h { id: id, type: type, matched: same_result?, expected_result: expected_result&.dig('result'), actual_result: actual_result&.dig('result') }.merge(optional_to_h_fields) end |
#type ⇒ Object
416 417 418 419 420 421 422 423 424 |
# File 'lib/inferno/apps/cli/session/session_compare.rb', line 416 def type if expected_result.nil? 'Additional' elsif actual_result.nil? 'Missing' else 'Compared' end end |