lib/tryouts/cli/formatters/test_run_state.rb
# lib/tryouts/cli/formatters/test_run_state.rb class Tryouts class CLI # Immutable state tracking for test runs using modern Ruby Data.define class TestRunState < Data.define( :total_tests, :passed, :failed, :errors, :files_completed, :total_files, :current_file, :current_test, :start_time, ) def self.empty new( total_tests: 0, passed: 0, failed: 0, errors: 0, files_completed: 0, total_files: 0, current_file: nil, current_test: nil, start_time: nil, ) end def self.initial(total_files: 0) empty.with( total_files: total_files, start_time: Time.now, ) end # Update state based on formatter events using pattern matching def update_from_event(event_type, *args, **_kwargs) case event_type in :phase_header _, file_count, level = args if level == 0 && file_count with(total_files: file_count, start_time: Time.now) else self end in :file_start file_path = args[0] pretty_path = Console.pretty_path(file_path) with(current_file: pretty_path) in :file_end with( files_completed: files_completed + 1, current_file: nil, ) in :test_start test_case = args[0] desc = test_case.description.to_s desc = "test #{args[1]}" if desc.empty? with(current_test: desc) in :test_end with(current_test: nil) in :test_result result_packet = args[0] updated_state = with(total_tests: total_tests + 1) case result_packet.status when :passed updated_state.with(passed: passed + 1) when :failed updated_state.with(failed: failed + 1) when :error updated_state.with(errors: errors + 1) else updated_state end else # Unknown event, return unchanged state self end end # Computed properties def elapsed_time start_time ? Time.now - start_time : 0 end def issues_count failed + errors end def passed_count total_tests - issues_count end def has_issues? issues_count > 0 end def tests_run? total_tests > 0 end def files_remaining total_files - files_completed end def completion_percentage return 0 if total_files == 0 (files_completed.to_f / total_files * 100).round(1) end end end end