Guy
Guy

Reputation: 79

Timer RSpec Test Ruby

I am trying to solve the timer problem from TestFirst Ruby.

I got the first two criteria correctly but the third one when tested for time = 12 seconds does not work. It does not look like Ruby is reading the time = 12 secs.

The codes are pretty lazy and not optimized, apparently. Also I did tried out the padded method but the test never worked. I had my padded method defined as

def padded(num)
 if num<=9
   return "0"<<num.to_s
 else 
   return num.to_s
 end
end

It would be great if someone can show me how to set that up correctly since that might have been the problems.

Here are my complete codes:

class Timer
#initialization of seconds
def seconds
    return 0
end

#seconds= method
def seconds=(time)
    @seconds = time_string(time)
end

#time_string method

def time_string(time=0)
    #format of hour:minute:second
    #minute must be less than 59 (or 59*60 seconds), otherwise it will convert to hour
    minute = time/60    #note that this is integer math, so it will take the minute and not the remainder
    hour = minute/60
    remainder_seconds = time%60
    if time<=9
        return "00:00:0" << time.to_s
    elsif time>9 && time<=60
        return "00:00:" << time.to_s
    elsif time>60 && time<=9*60 #9 minutes and greater than 1 min
        #ensuring double XX seconds or 0X seconds (this would be easier to use the padded method)
        if remainder_seconds >9
            remainder_seconds_sd = remainder_seconds.to_s
        else
            remainder_seconds_sd = "0" << remainder_seconds.to_s
        end

        return "00:0" << minute.to_s << ":" << remainder_seconds_sd
    end
end

end

RSpec below:

require '09_timer'

describe "Timer" do
  before(:each) do
    @timer = Timer.new
  end

  it "should initialize to 0 seconds" do
    @timer.seconds.should == 0
  end

  describe 'time_string' do
    it "should display 0 seconds as 00:00:00" do
      @timer.seconds = 0
      @timer.time_string.should == "00:00:00"
    end

    it "should display 12 seconds as 00:00:12" do
      @timer.seconds = 12
      @timer.time_string.should == "00:00:12"
    end

    it "should display 66 seconds as 00:01:06" do
      @timer.seconds = 66
      @timer.time_string.should == "00:01:06"
    end

    it "should display 4000 seconds as 01:06:40" do
      @timer.seconds = 4000
      @timer.time_string.should == "01:06:40"
    end
      end


  # One way to implement the Timer is with a helper method.
  # Uncomment these specs if you want to test-drive that
  # method, then call that method from inside of time_string.
  #

=begin
   describe 'padded' do
     it 'pads zero' do
       @timer.padded(0).should == '00'
     end
     it 'pads one' do
       @timer.padded(1).should == '01'
     end
     it "doesn't pad a two-digit number" do
       @timer.padded(12).should == '12'
     end
   end
=end
end

Upvotes: 0

Views: 1081

Answers (2)

Brian Aiken
Brian Aiken

Reputation: 11

A cleaner version:

class Timer
  attr_accessor :seconds

  def initialize
    @seconds = 0
  end

  def time_string
    seconds = @seconds % 60
    minutes = (@seconds / 60) % 60
    hours = @seconds / (60**2)
    "#{padded(hours)}:#{padded(minutes)}:#{padded(seconds)}"
  end

  def padded(num)
    return '0' + num.to_s if num < 10
    return num.to_s if num >= 10
  end
end

Upvotes: 1

Paweł Dawczak
Paweł Dawczak

Reputation: 9639

The problem with your tests and Timer is that, in your tests you are setting the value of @timer.seconds, but the Timer#time_string does not rely on the @seconds variable set. Your time_string method is implemented the way it accepts the amount of seconds as an argument, not an attribute of Timer.

Try changing your tests as follows:

describe "Timer" do
  # rest of your code

  describe 'time_string' do
    it "should display 0 seconds as 00:00:00" do
      @timer.time_string(0).should == "00:00:00"
    end

    it "should display 12 seconds as 00:00:12" do
      @timer.time_string(12).should == "00:00:12"
    end

    it "should display 66 seconds as 00:01:06" do
      @timer.time_string(66).should == "00:01:06"
    end

    it "should display 4000 seconds as 01:06:40" do
      @timer.time_string(4000).should == "01:06:40"
    end
  end
end

You might be wondering okay, but why the first test - 00:00:00 - did work in first place?. Well, this is, because your time_string method argument defaults to 0:

def time_string(time=0)
  # Rest of the code
end

and because you were not passing any other value, the 0 has been used.

If you have any questions - I'm happy to help!

Good luck!

Edit

If you want to make it the other way around - make the class to work for your tests, change your Timer class:

class Timer
  def initialize
    @seconds = 0
  end

  def seconds
    @seconds
  end

  def seconds=(time)
    @seconds = time
  end

  def time_string
    #format of hour:minute:second
    #minute must be less than 59 (or 59*60 seconds), otherwise it will convert to hour
    minute = @seconds/60    #note that this is integer math, so it will take the minute and not the remainder
    hour = minute/60
    remainder_seconds = @seconds%60
    if @seconds<=9
      return "00:00:0" << @seconds.to_s
    elsif @seconds>9 && @seconds<=60
      return "00:00:" << @seconds.to_s
    elsif @seconds>60 && @seconds<=9*60 #9 minutes and greater than 1 min
      #ensuring double XX seconds or 0X seconds (this would be easier to use the padded method)
      if remainder_seconds >9
        remainder_seconds_sd = remainder_seconds.to_s
      else
        remainder_seconds_sd = "0" << remainder_seconds.to_s
      end

      return "00:0" << minute.to_s << ":" << remainder_seconds_sd
    end
  end
end

We have added initialize method, we have changed def seconds=(time) method, and we have changed all occurrences of time in your time_string method.

If that works for you, consider posting the code to https://codereview.stackexchange.com/. There is a lot in the code to improve, and codereview is a great place to ask for help!

Upvotes: 1

Related Questions