How to catch the mocked infinite loop behavior and handle it with a rescue block using RSpec


#1

I have a Book Model which is a ruby script that assigns prices to
certain predefined Book titles mentioned in the program. I’m using Ruby
1.9.3-p327 and rspec 2.11.0

#class RspecLoopStop < Exception; end
class Book

  attr_accessor :books
  def initialize books
    puts "Welcome to setting book price program"
    @books = books
  end

  def get_prices
    puts "Please enter appropriate price for each book item:-"
    count = 0
    @books = @books.inject({}) { |hash, book|
      print "#{book.first}: "
      price = STDIN.gets.chomp
      while (price !~ /^[1-9]\d*$/ && price != "second hand")
        puts "Price cannot be 0 or a negative integer or in decimal

format or alphanumeric. \nPlease input appropriate duration in integer"
price = STDIN.gets.chomp #gets.chomp - throws error
end
price == “second hand” ? price = “100” : price #takes a
default price
hash[book.first] = price.to_i
hash
}
end

end

books = {"The Last Samurai" => nil,
         "Ruby Cookbook" =>  nil,
         "Rails Recipes" =>  nil,
         "Agile Development with Rails" =>  nil,
         "Harry Potter and the Deathly Hallows" =>  nil}


book_details = Book.new(books)
book_details.get_prices
#puts "\n*******Books:#{book_details.books}******\n"

If a user inputs any alphanumeric data or negative number or 0 or
anything having decimals, as per the program the user is asked to enter
only a positive integer for the price of each book. I’ve tried to mock
this behavior using RSpec.

My current challenge is how to catch the wrong user input, the message
that comes along with and handle it appropriately so that the spec
should pass. I’ve tried a couple of things but the below spec currently
runs into an infinite loop with input price given in the wrong format.
PFB my spec.

require 'spec_helper'

describe Book do

  before :each do
    books = {"The Last Samurai" => nil,
         "Ruby Cookbook" =>  nil,
         "Rails Recipes" =>  nil,
         "Agile Development with Rails" =>  nil,
         "Harry Potter and the Deathly Hallows" =>  nil}
    @book = Book.new(books)
  end

  describe "#getprice" do
    it "Should get the price in the correct format or else return

appropriate error" do
puts
“\n************************************************************************\n”
book_obj = @book
STDIN.stub(:gets) { “40” }
book_obj.get_prices.should_not be_nil
end

    it "Incorrect input format should return error message asking

user to re input" do
puts
“\n************************************************************************\n”
book_obj = @book
#STDIN.stub(:gets) { “40abc” }

      #book_obj.get_prices.should be_nil --> adding this line of

code goes into an infinite loop with the error message below
#Price cannot be 0 or a negative integer or in decimal format
or alphanumeric. \nPlease input appropriate duration in integer\n

      #STDOUT.should_receive(:puts).and_return("Price cannot be 0 or

a negative integer or in decimal format or alphanumeric. \nPlease input
appropriate duration in integer\n")

      #the below two tests fails with syntax error - don't seem that

easy to figure out what’s going wrong

      #STDOUT.should_receive("Price cannot be 0 or a negative

integer or in decimal format or alphanumeric. \nPlease input appropriate
duration in integer\n")
#\n towards the end is as in the third line of input the user
is asked to re enter input in correct format
#STDOUT.should == “Price cannot be 0 or a negative integer or
in decimal format or alphanumeric. \nPlease input appropriate duration
in integer\n”

      #begin    #didn't work for me
      #  STDIN.stub(:gets) { "40abc" }
      #  book_obj.get_prices.should_raise RspecLoopStop
      #rescue RspecLoopStop
      #  #exit
      #end

      begin
        STDIN.stub(:gets) { "40abc" } #incorrect input prompts user

to re enter price in correct format
book_obj.get_prices #how to catch the infinite loop as an
exception and exit out of it say using rescue block
rescue #I guess this won’t be called until the exception is
correctly caught
STDIN.stub(:gets) { “85” }
book_obj.get_prices.should_not be_nil
end

    end
  end

end

Can anyone please point me in the right direction on how can I handle
this correctly. I’m able to mock the user being asked to re enter data
for wrong input. My question is how can I stop that(as per the actual
program logic) upon correct input as part of the spec.

I did try one of the suggestions from a similar question, but it
doesn’t seem to be working for me. I could be missing something. The

code is also available to be cloned from Github. Thank you.