# encoding: utf-8 require "spec_helper" describe Money do describe "#new" do it "rounds the given cents to an integer" do Money.new(1.00, "USD").cents.should == 1 Money.new(1.01, "USD").cents.should == 1 Money.new(1.50, "USD").cents.should == 2 end it "is associated to the singleton instance of Bank::VariableExchange by default" do Money.new(0).bank.should be_equal(Money::Bank::VariableExchange.instance) end end describe "#cents" do it "returns the amount of cents passed to the constructor" do Money.new(200_00, "USD").cents.should == 200_00 end it "stores cents as an integer regardless of what is passed into the constructor" do [ Money.new(100), 1.to_money, 1.00.to_money, BigDecimal('1.00').to_money ].each do |m| m.cents.should == 100 m.cents.should be_an_instance_of(Fixnum) end end end describe "#dollars" do it "gets cents as dollars" do Money.new_with_dollars(1).should == Money.new(100) Money.new_with_dollars(1, "USD").should == Money.new(100, "USD") Money.new_with_dollars(1, "EUR").should == Money.new(100, "EUR") end it "should respect :subunit_to_unit currency property" do Money.new(1_00, "USD").dollars.should == 1 Money.new(1_000, "TND").dollars.should == 1 Money.new(1, "CLP").dollars.should == 1 end it "should not loose precision" do Money.new(100_37).dollars.should == 100.37 Money.new_with_dollars(100.37).dollars.should == 100.37 end end specify "#currency returns the currency passed to the constructor" do Money.new(200_00, "USD").currency.should == Money::Currency.new("USD") end specify "#currency_string returns the iso_code of the currency object" do Money.new(200_00, "USD").currency_as_string.should == Money::Currency.new("USD").to_s Money.new(200_00, "USD").currency_as_string.should == "USD" Money.new(200_00, "EUR").currency_as_string.should == "EUR" Money.new(200_00, "YEN").currency_as_string.should == "YEN" end specify "#currency_string= set the currency object using the provided string" do obj = Money.new(200_00, "USD") obj.currency_as_string = "EUR" obj.currency.should == Money::Currency.new("EUR") obj.currency_as_string = "YEN" obj.currency.should == Money::Currency.new("YEN") obj.currency_as_string = "USD" obj.currency.should == Money::Currency.new("USD") end specify "#exchange_to exchanges the amount via its exchange bank" do money = Money.new(100_00, "USD") money.bank.should_receive(:exchange_with).with(Money.new(100_00, Money::Currency.new("USD")), Money::Currency.new("EUR")).and_return(Money.new(200_00, Money::Currency.new('EUR'))) money.exchange_to("EUR") end specify "#exchange_to exchanges the amount properly" do money = Money.new(100_00, "USD") money.bank.should_receive(:exchange_with).with(Money.new(100_00, Money::Currency.new("USD")), Money::Currency.new("EUR")).and_return(Money.new(200_00, Money::Currency.new('EUR'))) money.exchange_to("EUR").should == Money.new(200_00, "EUR") end specify "#hash should return the same value for equal objects" do Money.new(1_00, :eur).hash.should == Money.new(1_00, :eur).hash Money.new(2_00, :usd).hash.should == Money.new(2_00, :usd).hash Money.new(1_00, :eur).hash.should_not == Money.new(2_00, :eur).hash Money.new(1_00, :eur).hash.should_not == Money.new(1_00, :usd).hash Money.new(1_00, :eur).hash.should_not == Money.new(2_00, :usd).hash end specify "#hash can be used to return the intersection of Money object arrays" do intersection = [Money.new(1_00, :eur), Money.new(1_00, :usd)] & [Money.new(1_00, :eur)] intersection.should == [Money.new(1_00, :eur)] end specify "Money.to_s works" do Money.new(10_00).to_s.should == "10.00" Money.new(400_08).to_s.should == "400.08" Money.new(-237_43).to_s.should == "-237.43" end specify "Money.to_s should respect :subunit_to_unit currency property" do Money.new(10_00, "BHD").to_s.should == "1.000" Money.new(10_00, "CNY").to_s.should == "10.00" end specify "Money.to_s shouldn't have decimal when :subunit_to_unit is 1" do Money.new(10_00, "CLP").to_s.should == "1000" end specify "Money.to_s should work with :subunit_to_unit == 5" do Money.new(10_00, "MGA").to_s.should == "200.0" end specify "Money.to_s should respect :decimal_mark" do Money.new(10_00, "BRL").to_s.should == "10,00" end specify "Money.to_f works" do Money.new(10_00).to_f.should == 10.0 end specify "Money.to_f should respect :subunit_to_unit currency property" do Money.new(10_00, "BHD").to_f.should == 1.0 end specify "#symbol works as documented" do currency = Money::Currency.new("EUR") currency.should_receive(:symbol).and_return("€") Money.empty(currency).symbol.should == "€" currency = Money::Currency.new("EUR") currency.should_receive(:symbol).and_return(nil) Money.empty(currency).symbol.should == "¤" end describe "Money.empty" do it "Money.empty creates a new Money object of 0 cents" do Money.empty.should == Money.new(0) end end describe "Money.ca_dollar" do it "creates a new Money object of the given value in CAD" do Money.ca_dollar(50).should == Money.new(50, "CAD") end end describe "Money.us_dollar" do it "creates a new Money object of the given value in USD" do Money.us_dollar(50).should == Money.new(50, "USD") end end describe "Money.euro" do it "creates a new Money object of the given value in EUR" do Money.euro(50).should == Money.new(50, "EUR") end end describe "Money.new_with_dollars" do it "converts given amount to cents" do Money.new_with_dollars(1).should == Money.new(100) Money.new_with_dollars(1, "USD").should == Money.new(100, "USD") Money.new_with_dollars(1, "EUR").should == Money.new(100, "EUR") end it "should respect :subunit_to_unit currency property" do Money.new_with_dollars(1, "USD").should == Money.new(1_00, "USD") Money.new_with_dollars(1, "TND").should == Money.new(1_000, "TND") Money.new_with_dollars(1, "CLP").should == Money.new(1, "CLP") end it "should not loose precision" do Money.new_with_dollars(1234).cents.should == 1234_00 Money.new_with_dollars(100.37).cents.should == 100_37 Money.new_with_dollars(BigDecimal.new('1234')).cents.should == 1234_00 end it "accepts a currency options" do m = Money.new_with_dollars(1) m.currency.should == Money.default_currency m = Money.new_with_dollars(1, Money::Currency.wrap("EUR")) m.currency.should == Money::Currency.wrap("EUR") m = Money.new_with_dollars(1, "EUR") m.currency.should == Money::Currency.wrap("EUR") end it "accepts a bank options" do m = Money.new_with_dollars(1) m.bank.should == Money.default_bank m = Money.new_with_dollars(1, "EUR", bank = Object.new) m.bank.should == bank end it "is associated to the singleton instance of Bank::VariableExchange by default" do Money.new_with_dollars(0).bank.should be_equal(Money::Bank::VariableExchange.instance) end end describe "split" do specify "#split needs at least one party" do lambda {Money.us_dollar(1).split(0)}.should raise_error(ArgumentError) lambda {Money.us_dollar(1).split(-1)}.should raise_error(ArgumentError) end specify "#gives 1 cent to both people if we start with 2" do Money.us_dollar(2).split(2).should == [Money.us_dollar(1), Money.us_dollar(1)] end specify "#split may distribute no money to some parties if there isnt enough to go around" do Money.us_dollar(2).split(3).should == [Money.us_dollar(1), Money.us_dollar(1), Money.us_dollar(0)] end specify "#split does not lose pennies" do Money.us_dollar(5).split(2).should == [Money.us_dollar(3), Money.us_dollar(2)] end specify "#split a dollar" do moneys = Money.us_dollar(100).split(3) moneys[0].cents.should == 34 moneys[1].cents.should == 33 moneys[2].cents.should == 33 end end describe "allocation" do specify "#allocate takes no action when one gets all" do Money.us_dollar(005).allocate([1.0]).should == [Money.us_dollar(5)] end specify "#allocate keeps currencies intact" do Money.ca_dollar(005).allocate([1]).should == [Money.ca_dollar(5)] end specify "#allocate does not loose pennies" do moneys = Money.us_dollar(5).allocate([0.3,0.7]) moneys[0].should == Money.us_dollar(2) moneys[1].should == Money.us_dollar(3) end specify "#allocate does not loose pennies" do moneys = Money.us_dollar(100).allocate([0.333,0.333, 0.333]) moneys[0].cents.should == 34 moneys[1].cents.should == 33 moneys[2].cents.should == 33 end specify "#allocate requires total to be less then 1" do lambda { Money.us_dollar(0.05).allocate([0.5,0.6]) }.should raise_error(ArgumentError) end end describe "Money.add_rate" do it "saves rate into current bank" do Money.add_rate("EUR", "USD", 10) Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD") end end end