spec/weather_spec.rb in barometer-0.8.0 vs spec/weather_spec.rb in barometer-0.9.0

- old
+ new

@@ -1,440 +1,260 @@ -require File.expand_path(File.dirname(__FILE__) + '/spec_helper') +require 'spec_helper' -describe Barometer::Weather do +module Barometer + describe Weather do + def fake_response(args) + success = args.delete(:success?) + weight = args.delete(:weight) || 1 - describe "when initialized" do - - before(:each) do - @weather = Barometer::Weather.new + double(:response, + success?: success.nil? ? true : success, + weight: weight, + current: double(:current, args) + ) end - it "responds to measurements (and sets default value)" do - @weather.measurements.should == [] - end + let(:weather) { Weather.new } - it "responds to current" do - @weather.respond_to?("current").should be_true + describe ".new" do + specify { expect( weather.responses ).to be_empty } end - it "responds to forecast" do - @weather.respond_to?("forecast").should be_true - end + describe "#source" do + let(:bar_response) { double(:response, source: :bar) } + let(:foo_response) { double(:response, source: :foo) } - it "responds to today" do - @weather.respond_to?("today").should be_true - end + before { weather.responses = [foo_response, bar_response] } - it "responds to tommorrow" do - @weather.respond_to?("tomorrow").should be_true - end - - it "responds to for" do - @weather.respond_to?("for").should be_true - end - - end - - describe "with measurements" do - - before(:each) do - @weather = Barometer::Weather.new - @wunderground = Barometer::Measurement.new(:wunderground) - @wunderground.stub!(:success).and_return(true) - @wunderground.stub!(:success?).and_return(true) - @yahoo = Barometer::Measurement.new(:yahoo) - @yahoo.stub!(:success).and_return(true) - @yahoo.stub!(:success?).and_return(true) - @google = Barometer::Measurement.new(:google) - @weather.measurements << @wunderground - @weather.measurements << @yahoo - @weather.measurements << @google - end - - it "retrieves a source measurement" do - lambda { @weather.source(1) }.should raise_error(ArgumentError) - lambda { @weather.source("valid") }.should_not raise_error(ArgumentError) - lambda { @weather.source(:valid) }.should_not raise_error(ArgumentError) - @weather.source(:does_not_exist).should be_nil - @weather.source(:wunderground).should == @wunderground - end - - it "lists the sources of measurements (that were successful)" do - sources = @weather.sources - sources.should_not be_nil - @wunderground.success?.should be_true - sources.include?(:wunderground).should be_true - @yahoo.success?.should be_true - sources.include?(:yahoo).should be_true - @google.success?.should be_false - sources.include?(:google).should be_false - end - - it "returns the default source" do - @weather.default.should == @wunderground - end - - end - - describe "when calculating averages" do - - before(:each) do - @weather = Barometer::Weather.new - @wunderground = Barometer::Measurement.new(:wunderground) - @wunderground.current = Barometer::Measurement::Result.new - @wunderground.stub!(:success).and_return(true) - @wunderground.stub!(:success?).and_return(true) - @yahoo = Barometer::Measurement.new(:yahoo) - @yahoo.current = Barometer::Measurement::Result.new - @yahoo.stub!(:success).and_return(true) - @yahoo.stub!(:success?).and_return(true) - @google = Barometer::Measurement.new(:google) - @weather.measurements << @wunderground - @weather.measurements << @yahoo - @weather.measurements << @google - end - - it "doesn't include nil values" do - @weather.source(:wunderground).current.temperature = Data::Temperature.new - @weather.source(:wunderground).current.temperature.c = 10 - - @weather.temperature.c.should == 10 - - @weather.source(:yahoo).current.temperature = Data::Temperature.new - @weather.source(:yahoo).current.temperature.c = nil - - @weather.temperature.c.should == 10 - end - - it "respects the measurement weight" do - @weather.source(:wunderground).current.temperature = Data::Temperature.new - @weather.source(:wunderground).current.temperature.c = 10 - @weather.source(:yahoo).current.temperature = Data::Temperature.new - @weather.source(:yahoo).current.temperature.c = 4 - - @weather.measurements.first.weight = 2 - - @weather.temperature.c.should == 8 - end - - describe "for temperature" do - - before(:each) do - @weather.source(:wunderground).current.temperature = Data::Temperature.new - @weather.source(:wunderground).current.temperature.c = 10 - @weather.source(:yahoo).current.temperature = Data::Temperature.new - @weather.source(:yahoo).current.temperature.c = 6 + it "returns the response for the specified source" do + expect( weather.source(:foo) ).to eq foo_response end - it "returns averages" do - @weather.temperature.c.should == 8 + it "returns nil when nothing is found" do + expect( weather.source(:baz) ).to be_nil end - - it "returns default when disabled" do - @weather.temperature(false).c.should == 10 - end - end - describe "for wind" do - - before(:each) do - @weather.source(:wunderground).current.wind = Data::Speed.new - @weather.source(:wunderground).current.wind.kph = 10 - @weather.source(:yahoo).current.wind = Data::Speed.new - @weather.source(:yahoo).current.wind.kph = 6 + describe "#success?" do + it "returns true when a response is successful" do + response_one = double(:response, success?: false) + response_two = double(:response, success?: true) + weather.responses = [response_one, response_two] + expect( weather ).to be_success end - it "returns averages" do - @weather.wind.kph.should == 8 + it "returns false when no responses are successful" do + response_one = double(:response, success?: false) + response_two = double(:response, success?: false) + weather.responses = [response_one, response_two] + expect( weather ).not_to be_success end - - it "returns default when disabled" do - @weather.wind(false).kph.should == 10 - end - end - describe "for humidity" do + describe "#current" do + it "returns the current response for the first successful response" do + current_two = double(:current) + response_one = double(:response, success?: false) + response_two = double(:response, success?: true, current: current_two) + weather.responses = [response_one, response_two] - before(:each) do - @weather.source(:wunderground).current.humidity = 10 - @weather.source(:yahoo).current.humidity = 6 + expect( weather.current ).to eq current_two end + end - it "returns averages" do - @weather.humidity.should == 8 - end + describe "#forecast" do + it "returns the forecast response for the first successful response" do + forecast_two = double(:forecast) + response_one = double(:response, success?: false) + response_two = double(:response, success?: true, forecast: forecast_two) + weather.responses = [response_one, response_two] - it "returns default when disabled" do - @weather.humidity(false).should == 10 + expect( weather.forecast ).to eq forecast_two end - end - describe "for pressure" do + describe "#today" do + it "returns the first forecast response for the first successful response" do + today = double(:forecast) + tommorrow = double(:forecast) + response_one = double(:response, success?: false) + response_two = double(:response, success?: true, forecast: [today, tommorrow]) + weather.responses = [response_one, response_two] - before(:each) do - @weather.source(:wunderground).current.pressure = Data::Pressure.new - @weather.source(:wunderground).current.pressure.mb = 10 - @weather.source(:yahoo).current.pressure = Data::Pressure.new - @weather.source(:yahoo).current.pressure.mb = 6 + expect( weather.today ).to eq today end + end - it "returns averages" do - @weather.pressure.mb.should == 8 - end + describe "#tomorrow" do + it "returns the second forecast response for the first successful response" do + today = double(:forecast) + tommorrow = double(:forecast) + response_one = double(:response, success?: false) + response_two = double(:response, success?: true, forecast: [today, tommorrow]) + weather.responses = [response_one, response_two] - it "returns default when disabled" do - @weather.pressure(false).mb.should == 10 + expect( weather.tomorrow ).to eq tommorrow end - end - describe "for dew_point" do + describe "#for" do + it "delegates to the first successful response" do + response_one = double(:response, success?: false, for: nil) + response_two = double(:response, success?: true, for: nil) + weather.responses = [response_one, response_two] - before(:each) do - @weather.source(:wunderground).current.dew_point = Data::Temperature.new - @weather.source(:wunderground).current.dew_point.c = 10 - @weather.source(:yahoo).current.dew_point = Data::Temperature.new - @weather.source(:yahoo).current.dew_point.c = 6 - end + query = build_query + weather.for(query) - it "returns averages" do - @weather.dew_point.c.should == 8 + expect( response_two ).to have_received(:for).with(query) end - - it "returns default when disabled" do - @weather.dew_point(false).c.should == 10 - end - end - describe "for heat_index" do + describe "#temperature" do + let(:response_one) { fake_response(temperature: Data::Temperature.new(:metric, 20)) } + let(:response_two) { fake_response(temperature: Data::Temperature.new(:metric, 30)) } - before(:each) do - @weather.source(:wunderground).current.heat_index = Data::Temperature.new - @weather.source(:wunderground).current.heat_index.c = 10 - @weather.source(:yahoo).current.heat_index = Data::Temperature.new - @weather.source(:yahoo).current.heat_index.c = 6 - end + before { weather.responses = [response_one, response_two] } - it "returns averages" do - @weather.heat_index.c.should == 8 + it "returns an average temeprature" do + expect( weather.temperature ).to eq Data::Temperature.new(:metric, 25.0) end - it "returns default when disabled" do - @weather.heat_index(false).c.should == 10 + it "returns nil when there is no valid data" do + response_one.stub(success?: false) + response_two.stub(success?: false) + expect( weather.temperature ).to be_nil end - end - - describe "for wind_chill" do - - before(:each) do - @weather.source(:wunderground).current.wind_chill = Data::Temperature.new - @weather.source(:wunderground).current.wind_chill.c = 10 - @weather.source(:yahoo).current.wind_chill = Data::Temperature.new - @weather.source(:yahoo).current.wind_chill.c = 6 + it "excludes unsuccessful responses" do + response_three = fake_response(success?: false, temperature: Data::Temperature.new(:metric, 10)) + weather.responses << response_three + expect( weather.temperature ).to eq Data::Temperature.new(:metric, 25.0) end - it "returns averages" do - @weather.wind_chill.c.should == 8 + it "excludes nil values" do + response_three = fake_response(temperature: nil) + weather.responses << response_three + expect( weather.temperature ).to eq Data::Temperature.new(:metric, 25.0) end - it "returns default when disabled" do - @weather.wind_chill(false).c.should == 10 + it "returns a weighted average temeprature" do + response_one.stub(weight: 3) + response_two.stub(weight: 1) + expect( weather.temperature ).to eq Data::Temperature.new(:metric, 22.5) end - end - - describe "for visibility" do - - before(:each) do - @weather.source(:wunderground).current.visibility = Data::Distance.new - @weather.source(:wunderground).current.visibility.km = 10 - @weather.source(:yahoo).current.visibility = Data::Distance.new - @weather.source(:yahoo).current.visibility.km = 6 + it "respects response units" do + response_two.current.stub(temperature: Data::Temperature.new(:imperial, 68.0)) + expect( weather.temperature.to_f ).to eq 20.0 end - it "returns averages" do - @weather.visibility.km.should == 8 - end + it "respects weather units" do + weather = Weather.new(:imperial) + weather.responses = [response_one, response_two] - it "returns default when disabled" do - @weather.visibility(false).km.should == 10 + expect( weather.temperature.to_f ).to eq 77.0 end - end - end + describe "#humidity" do + let(:response_one) { fake_response(humidity: 20.0) } + let(:response_two) { fake_response(humidity: 30.0) } - describe "when answering the simple questions," do + before { weather.responses = [response_one, response_two] } - before(:each) do - @weather = Barometer::Weather.new - @now = Data::LocalDateTime.parse("2:05 pm") - end - - describe "windy?" do - - # it "requires time as a Data::LocalTime object" do - # #lambda { @weather.windy?(1,"a") }.should raise_error(ArgumentError) - # lambda { @weather.windy?(1,@now) }.should_not raise_error(ArgumentError) - # end - - it "requires threshold as a number" do - lambda { @weather.windy?(@now,"a") }.should raise_error(ArgumentError) - lambda { @weather.windy?(@now,1) }.should_not raise_error(ArgumentError) - lambda { @weather.windy?(@now,1.1) }.should_not raise_error(ArgumentError) + it "returns an average humidity" do + expect( weather.humidity ).to eq 25.0 end - it "returns nil when no measurements" do - @weather.measurements.should be_empty - @weather.windy?.should be_nil + it "returns nil when there is no valid data" do + response_one.stub(success?: false) + response_two.stub(success?: false) + expect( weather.humidity ).to be_nil end - it "returns true if a measurement returns true" do - wunderground = Barometer::Measurement.new(:wunderground) - wunderground.stub!(:success).and_return(true) - wunderground.stub!(:success?).and_return(true) - @weather.measurements << wunderground - @weather.measurements.each { |m| m.stub!(:windy?).and_return(true) } - @weather.windy?.should be_true + it "excludes unsuccessful responses" do + response_three = fake_response(success?: false, humidity: 10.0) + weather.responses << response_three + expect( weather.humidity ).to eq 25.0 end - it "returns false if a measurement returns false" do - wunderground = Barometer::Measurement.new(:wunderground) - wunderground.stub!(:success).and_return(true) - wunderground.stub!(:success?).and_return(true) - @weather.measurements << wunderground - @weather.measurements.each { |m| m.stub!(:windy?).and_return(false) } - @weather.windy?.should be_false + it "excludes nil values" do + response_three = fake_response(humidity: nil) + weather.responses << response_three + expect( weather.humidity ).to eq 25.0 end + it "returns a weighted average humidity" do + response_one.stub(weight: 3) + response_two.stub(weight: 1) + expect( weather.humidity ).to eq 22.5 + end end - describe "wet?" do + describe "#dew_point" do + let(:response_one) { fake_response(dew_point: Data::Temperature.new(:metric, 20)) } + let(:response_two) { fake_response(dew_point: Data::Temperature.new(:metric, 30)) } - it "requires threshold as a number" do - lambda { @weather.wet?(@now,"a") }.should raise_error(ArgumentError) - lambda { @weather.wet?(@now,1) }.should_not raise_error(ArgumentError) - lambda { @weather.wet?(@now,1.1) }.should_not raise_error(ArgumentError) - end + before { weather.responses = [response_one, response_two] } - # it "requires time as a Data::LocalTime object" do - # #lambda { @weather.wet?(1,"a") }.should raise_error(ArgumentError) - # lambda { @weather.wet?(1,@now) }.should_not raise_error(ArgumentError) - # end - - it "returns nil when no measurements" do - @weather.measurements.should be_empty - @weather.wet?.should be_nil + it "returns an average dew_point" do + expect( weather.dew_point ).to eq Data::Temperature.new(:metric, 25.0) end + end - it "returns true if a measurement returns true" do - wunderground = Barometer::Measurement.new(:wunderground) - wunderground.stub!(:success).and_return(true) - wunderground.stub!(:success?).and_return(true) - @weather.measurements << wunderground - @weather.measurements.each { |m| m.stub!(:wet?).and_return(true) } - @weather.wet?.should be_true - end + describe "#heat_index" do + let(:response_one) { fake_response(heat_index: Data::Temperature.new(:metric, 20)) } + let(:response_two) { fake_response(heat_index: Data::Temperature.new(:metric, 30)) } - it "returns false if a measurement returns false" do - wunderground = Barometer::Measurement.new(:wunderground) - wunderground.stub!(:success).and_return(true) - wunderground.stub!(:success?).and_return(true) - @weather.measurements << wunderground - @weather.measurements.each { |m| m.stub!(:wet?).and_return(false) } - @weather.wet?.should be_false - end + before { weather.responses = [response_one, response_two] } + it "returns an average heat_index" do + expect( weather.heat_index ).to eq Data::Temperature.new(:metric, 25.0) + end end - describe "day? and night?" do + describe "#wind_chill" do + let(:response_one) { fake_response(wind_chill: Data::Temperature.new(:metric, 20)) } + let(:response_two) { fake_response(wind_chill: Data::Temperature.new(:metric, 30)) } - it "requires time as a Data::LocalTime object" do - #lambda { @weather.day?("a") }.should raise_error(ArgumentError) - lambda { @weather.day?(@now) }.should_not raise_error(ArgumentError) - end + before { weather.responses = [response_one, response_two] } - it "requires time as a Data::LocalTime object" do - #lambda { @weather.night?("a") }.should raise_error(ArgumentError) - lambda { @weather.night?(@now) }.should_not raise_error(ArgumentError) + it "returns an average wind_chill" do + expect( weather.wind_chill ).to eq Data::Temperature.new(:metric, 25.0) end + end - it "returns nil when no measurements" do - @weather.measurements.should be_empty - @weather.day?.should be_nil - @weather.night?.should be_nil - end + describe "#pressure" do + let(:response_one) { fake_response(pressure: Data::Pressure.new(:metric, 20)) } + let(:response_two) { fake_response(pressure: Data::Pressure.new(:metric, 30)) } - it "returns true if a measurement returns true (night is opposite)" do - wunderground = Barometer::Measurement.new(:wunderground) - wunderground.stub!(:success).and_return(true) - wunderground.stub!(:success?).and_return(true) - @weather.measurements << wunderground - @weather.measurements.each { |m| m.stub!(:day?).and_return(true) } - @weather.day?.should be_true - @weather.night?.should be_false - end + before { weather.responses = [response_one, response_two] } - it "returns false if a measurement returns false (night is opposite)" do - wunderground = Barometer::Measurement.new(:wunderground) - wunderground.stub!(:success).and_return(true) - wunderground.stub!(:success?).and_return(true) - @weather.measurements << wunderground - @weather.measurements.each { |m| m.stub!(:day?).and_return(false) } - @weather.day?.should be_false - @weather.night?.should be_true + it "returns an average pressure" do + expect( weather.pressure ).to eq Data::Pressure.new(:metric, 25.0) end - end - describe "sunny?" do + describe "#visibility" do + let(:response_one) { fake_response(visibility: Data::Distance.new(:metric, 20)) } + let(:response_two) { fake_response(visibility: Data::Distance.new(:metric, 30)) } - it "requires time as a Data::LocalTime object" do - #lambda { @weather.sunny?("a") }.should raise_error(ArgumentError) - lambda { @weather.sunny?(@now) }.should_not raise_error(ArgumentError) - end + before { weather.responses = [response_one, response_two] } - it "returns nil when no measurements" do - @weather.measurements.should be_empty - @weather.sunny?.should be_nil + it "returns an average visibility" do + expect( weather.visibility ).to eq Data::Distance.new(:metric, 25.0) end + end - it "returns true if a measurement returns true" do - wunderground = Barometer::Measurement.new(:wunderground) - wunderground.stub!(:success).and_return(true) - wunderground.stub!(:success?).and_return(true) - @weather.measurements << wunderground - @weather.measurements.each { |m| m.stub!(:day?).and_return(true) } - @weather.measurements.each { |m| m.stub!(:sunny?).and_return(true) } - @weather.sunny?.should be_true - end + describe "#wind" do + let(:response_one) { fake_response(wind: Data::Vector.new(:metric, 20)) } + let(:response_two) { fake_response(wind: Data::Vector.new(:metric, 30)) } - it "returns false if a measurement returns false" do - wunderground = Barometer::Measurement.new(:wunderground) - wunderground.stub!(:success).and_return(true) - wunderground.stub!(:success?).and_return(true) - @weather.measurements << wunderground - @weather.measurements.each { |m| m.stub!(:day?).and_return(true) } - @weather.measurements.each { |m| m.stub!(:sunny?).and_return(false) } - @weather.sunny?.should be_false - end + before { weather.responses = [response_one, response_two] } - it "returns false if night time" do - wunderground = Barometer::Measurement.new(:wunderground) - wunderground.stub!(:success).and_return(true) - wunderground.stub!(:success?).and_return(true) - @weather.measurements << wunderground - @weather.measurements.each { |m| m.stub!(:sunny?).and_return(true) } - @weather.measurements.each { |m| m.stub!(:day?).and_return(false) } - @weather.sunny?.should be_false + it "returns an average wind" do + expect( weather.wind ).to eq Data::Vector.new(:metric, 25.0) end - end - end - end