diff --git a/bin/rubyripper_cli b/bin/rubyripper_cli index a6dd0af..454f4f1 100755 --- a/bin/rubyripper_cli +++ b/bin/rubyripper_cli @@ -130,7 +130,7 @@ private @out.puts _("Thanks for using RubyRipperRemix.") @out.puts _("Have a nice day!") when 1 then @cliPrefs.show() - when 2 then @cliDisc.show() + when 2 then @cliDisc.show() ; showError(@cliDisc.error) unless @cliDisc.error.nil? ; @cliTracklist = CliTracklist.new(@cliDisc, @out, @int) when 3 then @cliDisc.changeMetadata() when 4 then @cliTracklist.show() when 5 then startRip() diff --git a/spec/cli/cliTracklist_spec.rb b/spec/cli/cliTracklist_spec.rb new file mode 100644 index 0000000..0c7028f --- /dev/null +++ b/spec/cli/cliTracklist_spec.rb @@ -0,0 +1,60 @@ +#!/usr/bin/env ruby +# RubyRipperRemix - A secure ripper for Linux/BSD/OSX +# Copyright (C) 2026 Masterisk-F +# +# This file is part of RubyRipperRemix. RubyRipperRemix is free software: you can +# redistribute it and/or modify it under the terms of the GNU General +# Public License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +require 'rubyripper/cli/cliTracklist' + +describe CliTracklist do + let(:out) {StringIO.new} + let(:int) {double('CliGetInt').as_null_object} + let(:prefs) {double('Preferences::Main').as_null_object} + + context "When selection is requested without prior user interaction" do + it "should return all tracks from the disc" do + cli_disc = double('CliDisc').as_null_object + expect(cli_disc).to receive(:tracks).and_return({1 => 'Track 1', 2 => 'Track 2', 3 => 'Track 3'}) + tracklist = CliTracklist.new(cli_disc, out, int, prefs) + expect(tracklist.selection).to eq([1, 2, 3]) + end + + it "should lazily cache the selection after first access" do + cli_disc = double('CliDisc').as_null_object + expect(cli_disc).to receive(:tracks).once.and_return({1 => 'a', 2 => 'b'}) + tracklist = CliTracklist.new(cli_disc, out, int, prefs) + expect(tracklist.selection).to eq([1, 2]) + # second call should use cache, not call tracks again + expect(tracklist.selection).to eq([1, 2]) + end + end + + context "When the disc is rescanned" do + it "should get fresh track selection from the new disc when CliTracklist is recreated" do + cli_disc = double('CliDisc').as_null_object + + # First disc has 5 tracks + expect(cli_disc).to receive(:tracks).once.and_return({1 => 'Song A', 2 => 'Song B', 3 => 'Song C', 4 => 'Song D', 5 => 'Song E'}) + first_tracklist = CliTracklist.new(cli_disc, out, int, prefs) + expect(first_tracklist.selection).to eq([1, 2, 3, 4, 5]) + + # Simulate a rescan: CliDisc.tracks returns only 3 tracks now + expect(cli_disc).to receive(:tracks).once.and_return({1 => 'New A', 2 => 'New B', 3 => 'New C'}) + second_tracklist = CliTracklist.new(cli_disc, out, int, prefs) + + # The new instance should start fresh with all tracks from the new disc + expect(second_tracklist.selection).to eq([1, 2, 3]) + end + end +end diff --git a/spec/cli/commandLineInterface_spec.rb b/spec/cli/commandLineInterface_spec.rb new file mode 100644 index 0000000..9e4ceec --- /dev/null +++ b/spec/cli/commandLineInterface_spec.rb @@ -0,0 +1,64 @@ +#!/usr/bin/env ruby +# RubyRipperRemix - A secure ripper for Linux/BSD/OSX +# Copyright (C) 2026 Masterisk-F +# +# This file is part of RubyRipperRemix. RubyRipperRemix is free software: you can +# redistribute it and/or modify it under the terms of the GNU General +# Public License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +require 'rubyripper/base' +require 'rubyripper/errors' +require 'rubyripper/cli/cliArguments' +require 'rubyripper/cli/cliDisc' +require 'rubyripper/cli/cliTracklist' + +# CommandLineInterface is defined in bin/rubyripper_cli, +# which is not in the lib load path. Load it by explicit path. +# Load by absolute path: require/require_relative cannot resolve files without .rb extension. +load File.expand_path('../../bin/rubyripper_cli', File.dirname(__FILE__)) + +describe CommandLineInterface do + let(:out) {StringIO.new} + let(:int) {double('CliGetInt').as_null_object} + let(:cli_disc) {double('CliDisc').as_null_object} + let(:cli_prefs) {double('CliPreferences').as_null_object} + + before do + # CliTracklist.new (called during option 2 at line 133) resolves + # Preferences::Main.instance when prefs is not injected. + # In spec mode ($run_specs = true), Singleton is excluded, so define instance here. + prefs_instance = double('PreferencesMain').as_null_object + allow(prefs_instance).to receive(:image).and_return(false) + allow(Preferences::Main).to receive(:instance).and_return(prefs_instance) + end + + def setup_cli(cli_disc: nil, int: nil, prefs: nil) + CommandLineInterface.new(nil, out, prefs || cli_prefs, cli_disc || self.cli_disc, int || self.int) + end + + context "When option 2 (rescan) is selected with a scan error" do + it "should display the scan error" do + # Stub @int to return 2 (rescan) then 99 (exit main menu) + expect(int).to receive(:get).with("Please type the number of your choice", 99) + .and_return(2, 99) + + # CliDisc with non-nil error (simulating a failed scan) + allow(cli_disc).to receive(:error).and_return([:noDiscYet, '3']) + allow(cli_disc).to receive(:tracks).and_return({1 => 'Track 1'}) + allow(cli_disc).to receive(:cd).and_return(double('Disc').as_null_object) + + cli = setup_cli(cli_disc: cli_disc, int: int) + + expect { cli.send(:loopMainMenu) }.to output(/Error/).to_stdout + end + end +end