Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bin/rubyripper_cli
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
60 changes: 60 additions & 0 deletions spec/cli/cliTracklist_spec.rb
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>

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
64 changes: 64 additions & 0 deletions spec/cli/commandLineInterface_spec.rb
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>

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