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.

Community
  • 1
  • 1
boddhisattva
  • 6,908
  • 11
  • 48
  • 72

0 Answers0