diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..2aacaa234 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/coverage/ +/specs/coverage/ diff --git a/Rakefile b/Rakefile index c556a763c..f5b131443 100644 --- a/Rakefile +++ b/Rakefile @@ -1 +1,10 @@ # Fill me in! +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.libs = ["lib"] + t.warning = true + t.test_files = FileList['specs/*_spec.rb'] +end + +task default: :test diff --git a/lib/InvalidIDError.rb b/lib/InvalidIDError.rb new file mode 100644 index 000000000..cbb960b9a --- /dev/null +++ b/lib/InvalidIDError.rb @@ -0,0 +1,2 @@ +class InvalidIDError < StandardError +end diff --git a/lib/InvalidRatingError.rb b/lib/InvalidRatingError.rb new file mode 100644 index 000000000..7094ff07d --- /dev/null +++ b/lib/InvalidRatingError.rb @@ -0,0 +1,2 @@ +class InvalidRatingError < StandardError +end diff --git a/lib/InvalidVinError.rb b/lib/InvalidVinError.rb new file mode 100644 index 000000000..36de16ee6 --- /dev/null +++ b/lib/InvalidVinError.rb @@ -0,0 +1,2 @@ +class InvalidVinError < StandardError +end diff --git a/lib/driver.rb b/lib/driver.rb new file mode 100644 index 000000000..3732750d7 --- /dev/null +++ b/lib/driver.rb @@ -0,0 +1,48 @@ +require 'csv' +require_relative 'trip' +require_relative 'InvalidVinError' +require_relative 'InvalidIDError' + +class Driver + attr_reader :id, :name, :vin + + @@all_drivers = nil + + def initialize(id, name, vin) + @id = id + @name = name + + if vin.length == 17 + @vin = vin + else + raise InvalidVinError.new("vin must be 17 characters long") + end + end + + def self.all + return @@all_drivers if @@all_drivers + drivers = CSV.read("support/drivers.csv", { :headers => true }) + + @@all_drivers = drivers.map { |line| Driver.new(line[0].to_i, line[1], line[2]) } + end + + def self.find(driver_id) + unless (driver_id.is_a? Integer) && driver_id >= 0 + raise InvalidIDError.new("driver ID:#{driver_id} is not valid") + end + + Driver.all.find { |driver| driver.id == driver_id } + end + + def list_trips + Trip.find_trips_driver(@id) + end + + def avg_rating + ratings = list_trips.map { |trip| trip.rating.to_f } + return 0 if ratings == [] + rating = (ratings.reduce(:+)) / ratings.length + rating.round(2) + end + +end diff --git a/lib/rider.rb b/lib/rider.rb new file mode 100644 index 000000000..df167931f --- /dev/null +++ b/lib/rider.rb @@ -0,0 +1,42 @@ +require 'csv' +require_relative 'trip' +require_relative 'driver' +require_relative 'InvalidIDError' + +class Rider + attr_reader :id, :name, :phone_num + + @@all_riders = nil + + def initialize(id, name, phone_num) + @id = id + @name = name + @phone_num = phone_num + end + + def self.all + return @@all_riders if @@all_riders + riders = CSV.read("support/riders.csv", { :headers => true }) + + @@all_riders = riders.map { |line| Rider.new(line[0].to_i, line[1], line[2]) } + end + + def self.find(rider_id) + unless (rider_id.is_a? Integer) && rider_id >= 0 + raise InvalidIDError.new("rider ID:#{rider_id} is not valid") + end + + Rider.all.find { |rider| rider.id == rider_id } + end + + def list_trips + Trip.find_trips_rider(@id) + end + + def list_drivers + drivers = list_trips.map { |trip| Driver.find(trip.driver_id) } + + drivers.uniq { |driver| driver.id } + end + +end diff --git a/lib/trip.rb b/lib/trip.rb new file mode 100644 index 000000000..8aad1ed92 --- /dev/null +++ b/lib/trip.rb @@ -0,0 +1,47 @@ +require 'csv' +require_relative 'InvalidRatingError' + +class Trip + attr_reader :id, :driver_id, :rider_id, :date, :rating + + @@all_trips = nil + + def initialize(id, driver_id, rider_id, date, rating) + @id = id + @driver_id = driver_id + @rider_id = rider_id + @date = date + + unless (rating.is_a? Integer) && (1..5).include?(rating) + raise InvalidRatingError.new("rating must be an integer within range 1-5") + else + @rating = rating + end + end + + def self.all + return @@all_trips if @@all_trips + trips = CSV.read("support/trips.csv", { :headers => true }) + + @@all_trips = trips.map do |line| + Trip.new(line[0].to_i, line[1].to_i, line[2].to_i, line[3], line[4].to_i) + end + end + + def self.find_trips_driver(driver_id) + Trip.all.select { |trip| trip.driver_id == driver_id } + end + + def self.find_trips_rider(rider_id) + Trip.all.select { |trip| trip.rider_id == rider_id } + end + + def driver + Driver.find(@driver_id) + end + + def rider + Rider.find(@rider_id) + end + +end diff --git a/specs/driver_spec.rb b/specs/driver_spec.rb new file mode 100644 index 000000000..2b49d835d --- /dev/null +++ b/specs/driver_spec.rb @@ -0,0 +1,137 @@ +require_relative 'spec_helper' + +describe "Driver" do + + describe "#initialize" do + it "Takes an ID, name, and vin" do + name = "Bob Belcher" + id = 12345 + vin = "9e87e65r98302e984" + driver = Driver.new(id, name, vin) + + driver.must_respond_to :id + driver.id.must_equal id + + driver.must_respond_to :name + driver.name.must_equal name + + driver.must_respond_to :vin + driver.vin.must_equal vin + end + + it "Is a kind of Driver" do + name = "Bob Belcher" + id = 12345 + vin = "9e87e65r98302e984" + driver = Driver.new(id, name, vin) + + driver.must_be_kind_of Driver + end + + it "Doesn't create a driver if vin is not 17 characters long" do + proc { + Driver.new(123, "Tina Belcher", "w3475rs78t") + }.must_raise InvalidVinError + end + end + + describe "Driver.all" do + + before do + @drivers = Driver.all + end + + it "Returns an array of all drivers" do + @drivers.class.must_equal Array + @drivers.each { |driver| driver.must_be_instance_of Driver } + @drivers.length.must_equal 100 + + @drivers.first.id.must_equal 1 + @drivers[0].name.must_equal "Bernardo Prosacco" + @drivers.first.vin.must_equal "WBWSS52P9NEYLVDE9" + + @drivers.last.id.must_equal 100 + @drivers[-1].name.must_equal "Minnie Dach" + @drivers.last.vin.must_equal "XF9Z0ST7X18WD41HT" + + # index = 0 + # CSV.read("support/drivers.csv", { :headers => true }).each do |line| + # + # @drivers[index].id.must_equal line[0].to_i + # @drivers[index].name.must_equal line[1].to_s + # @drivers[index].vin.must_equal line[2] + # index += 1 + # end + end + + end + + describe "Driver.find" do + + before do + @drivers = Driver.all + end + + it "Returns a driver that exists" do + driver = Driver.find(54) + driver.must_be_instance_of Driver + end + + it "Can find the first driver from the CSV" do + driver = Driver.find(1) + driver.name.must_equal @drivers.first.name + end + + it "Can find the last driver from the CSV" do + driver = Driver.find(100) + driver.name.must_equal @drivers.last.name + end + + it "Returns nil for a driver that doesn't exist" do + driver = Driver.find(101) + driver.must_be_nil + end + + it "Raises an error for an invalid driver ID" do + proc { + Driver.find("a") + }.must_raise InvalidIDError + end + end + + describe "Driver#list_trips" do + it "Returns a list of trips for a specific driver" do + driver = Driver.new(36, "Mr. Marcelina Jenkins", "WD3VLLK2X04HF50PL") + driver.list_trips.must_be_kind_of Array + driver.list_trips.each { |trip| trip.must_be_kind_of Trip } + end + + it "Returns a correct number of trips for a specific driver" do + driver = Driver.new(1, "Bernardo Prosacco", "WBWSS52P9NEYLVDE9") + driver.list_trips.length.must_equal 9 + end + + it "Returns an empty array if there are no trips for that driver" do + driver = Driver.new(100, "Minnie Dach", "XF9Z0ST7X18WD41HT") + driver.list_trips.must_equal [] + end + end + + describe "Driver#avg_rating" do + it "Returns a number" do + driver = Driver.new(60, "Oma Swift DDS", "TAMCBRPM7EN5GD88L") + driver.avg_rating.must_be_kind_of Float + end + + it "Returns correct average for a specific driver" do + driver = Driver.new(1, "Bernardo Prosacco", "WBWSS52P9NEYLVDE9") + driver.avg_rating.must_equal 2.33 + end + + it "Returns 0 if there are no trips for this driver" do + driver = Driver.new(100, "Minnie Dach", "XF9Z0ST7X18WD41HT") + driver.avg_rating.must_equal 0 + end + end + +end diff --git a/specs/rider_spec.rb b/specs/rider_spec.rb new file mode 100644 index 000000000..90a81206b --- /dev/null +++ b/specs/rider_spec.rb @@ -0,0 +1,135 @@ +require 'pry' +require_relative 'spec_helper' + +describe "Rider" do + + describe "#initialize" do + it "Takes an ID, name, and phone number" do + name = "Louise Belcher" + id = 12345 + phone_num = "(206) 222 222" + rider = Rider.new(id, name, phone_num) + + rider.must_respond_to :id + rider.id.must_equal id + + rider.must_respond_to :name + rider.name.must_equal name + + rider.must_respond_to :phone_num + rider.phone_num.must_equal phone_num + end + + it "Is a kind of Rider" do + name = "Louise Belcher" + id = 12345 + phone_num = "(206) 222 222" + rider = Rider.new(id, name, phone_num) + + rider.must_be_kind_of Rider + end + end + + describe "Rider.all" do + + before do + @riders = Rider.all + end + + it "Returns an array of all riders" do + @riders.class.must_equal Array + @riders.each { |rider| rider.must_be_instance_of Rider } + @riders.length.must_equal 300 + + @riders.first.id.must_equal 1 + @riders[0].name.must_equal "Nina Hintz Sr." + @riders.first.phone_num.must_equal "560.815.3059" + + @riders.last.id.must_equal 300 + @riders[-1].name.must_equal "Miss Isom Gleason" + @riders.last.phone_num.must_equal "791-114-8423 x70188" + + # index = 0 + # CSV.read("support/riders.csv", { :headers => true }).each do |line| + # + # @riders[index].id.must_equal line[0].to_i + # @riders[index].name.must_equal line[1] + # @riders[index].phone_num.must_equal line[2] + # index += 1 + # end + end + end + + describe "Rider.find" do + + before do + @riders = Rider.all + end + + it "Returns a rider that exists" do + rider = Rider.find(150) + rider.must_be_instance_of Rider + end + + it "Can find the first rider from the CSV" do + rider = Rider.find(1) + rider.name.must_equal @riders.first.name + end + + it "Can find the last rider from the CSV" do + rider = Rider.find(300) + rider.name.must_equal @riders.last.name + end + + it "Returns nil for a rider that doesn't exist" do + rider = Rider.find(301) + rider.must_be_nil + end + + it "Raises an error for an invalid rider ID" do + proc { + Rider.find("a") + }.must_raise InvalidIDError + end + end + + describe "Rider#list_trips" do + it "Returns a list of trips for a specific rider" do + rider = Rider.new(210, "Rhea Zieme", "940-838-2968 x4910") + rider.list_trips.must_be_kind_of Array + rider.list_trips.each { |trip| trip.must_be_kind_of Trip } + end + + it "Returns a correct number of trips for a specific rider" do + rider = Rider.new(1, "Nina Hintz Sr.", "560.815.3059") + rider.list_trips.length.must_equal 2 + end + + it "Returns an empty array if there are no trips for that rider" do + rider = Rider.new(100, "Hipolito Rogahn", "944.179.4883") + rider.list_trips.must_equal [] + end + end + + describe "Rider#list_drivers" do + it "Returns a list of drivers for a specific rider" do + rider = Rider.new(93, "Mrs. Rickey Dickens", "5FS0Y47Z59YGGSXS0") + rider_drivers = rider.list_drivers + rider_drivers.must_be_kind_of Array + rider_drivers.each { |driver| driver.must_be_kind_of Driver } + end + + it "Returns a correct number of drivers for a specific rider" do + rider = Rider.new(41, "Ms. Westley Pouros", "133.000.1809 x9028") + rider.list_drivers.length.must_equal 2 + rider.list_drivers.length.wont_equal rider.list_trips.length + end + + # Hipolito exists as a Rider, but didn't take any trips yet + it "Returns an empty array if there are no drivers for that rider" do + rider = Rider.new(100, "Hipolito Rogahn", "944.179.4883") + rider.list_drivers.must_equal [] + end + end + +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb index 4d1e3fdc8..2c29b1f64 100644 --- a/specs/spec_helper.rb +++ b/specs/spec_helper.rb @@ -1,8 +1,13 @@ +require 'simplecov' +SimpleCov.start + require 'minitest' require 'minitest/autorun' require 'minitest/reporters' -# Add simplecov Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new -# Require_relative your lib files here! +require 'csv' +require_relative '../lib/driver' +require_relative '../lib/rider' +require_relative '../lib/trip' diff --git a/specs/trip_spec.rb b/specs/trip_spec.rb new file mode 100644 index 000000000..8fb96dcc3 --- /dev/null +++ b/specs/trip_spec.rb @@ -0,0 +1,188 @@ +require_relative 'spec_helper' + + +describe "Trip" do + + describe "#initialize" do + it "Takes an ID, driver ID, raider ID, date, and rating" do + id = 12345 + driver_id = 45678 + rider_id = 9876 + date = "2016-04-05" + rating = 4 + trip = Trip.new(id, driver_id, rider_id, date, rating) + + trip.must_respond_to :id + trip.id.must_equal id + + trip.must_respond_to :driver_id + trip.driver_id.must_equal driver_id + + trip.must_respond_to :rider_id + trip.rider_id.must_equal rider_id + + trip.must_respond_to :date + trip.date.must_equal date + + trip.must_respond_to :rating + trip.rating.must_equal rating + end + + it "Is a kind of Trip" do + id = 12345 + driver_id = 45678 + rider_id = 9876 + date = "2016-04-05" + rating = 4 + trip = Trip.new(id, driver_id, rider_id, date, rating) + + trip.must_be_kind_of Trip + end + + it "Accepts rating" do + trip = Trip.new(12, 21, 382, "2016-01-04", 1) + trip.rating.must_equal 1 + end + + it "Accepts rating only as integers" do + proc { + Trip.new(12, 21, 382, "2016-01-04", 1.3) + }.must_raise InvalidRatingError + end + + it "Allows rating only within acceptable range (1 - 5)" do + proc { + Trip.new(12, 21, 382, "2016-01-04", 0) + }.must_raise InvalidRatingError + end + + it "Raises an error if invalid rating is given" do + proc { + Trip.new(12, 21, 382, "2016-01-04", "a") + }.must_raise InvalidRatingError + end + + end + + describe "Trip.all" do + + before do + @trips = Trip.all + end + + it "Returns an array of all trips" do + @trips.class.must_equal Array + @trips.each { |trip| trip.must_be_instance_of Trip } + @trips.length.must_equal 600 + + @trips.first.id.must_equal 1 + @trips[0].driver_id.must_equal 1 + @trips.first.rider_id.must_equal 54 + @trips.first.date.must_equal "2016-04-05" + @trips.first.rating.must_equal 3 + + @trips.last.id.must_equal 600 + @trips[-1].driver_id.must_equal 61 + @trips.last.rider_id.must_equal 168 + @trips.last.date.must_equal "2016-04-25" + @trips.last.rating.must_equal 3 + + # index = 0 + # CSV.read("support/trips.csv", { :headers => true }) do |line| + # @trips[index].id.must_equal line[0].to_i + # puts @trips + # @trips[index].driver_id.must_equal line[1].to_i + # @trips[index].rider_id.must_equal line[2].to_i + # @trips[index].date.must_equal line[3] + # @trips[index].rating.must_equal line[4].to_i + # index += 1 + # end + end + end + + describe "Trip.find_trips_driver" do + + before do + @driver_trips = Trip.find_trips_driver(1) + end + + it "Returns a list of trips" do + @driver_trips.must_be_kind_of Array + @driver_trips.each { |trip| trip.must_be_instance_of Trip } + + # trips = 0 + # CSV.read("support/trips.csv", { :headers => true }).each do |line| + # trips += 1 if line[1].to_i == 1 + # end + + @driver_trips.length.must_equal 9 + end + + it "Returns an empty array for a driver ID that doesn't exist" do + Trip.find_trips_driver(101).must_equal [] + end + + it "Returns an empty array if there are no trips for this driver ID" do + Trip.find_trips_driver(100).must_equal [] + end + end + + describe "Trip.find_trips_rider" do + + before do + @rider_trips = Trip.find_trips_rider(1) + end + + it "Returns a list of trips" do + @rider_trips.must_be_kind_of Array + @rider_trips.each { |trip| trip.must_be_instance_of Trip } + + @rider_trips.length.must_equal 2 + end + + it "Returns an empty array if there are no trips for this rider ID" do + Trip.find_trips_rider(100).must_equal [] + end + + it "Returns an empty array for a rider ID that doesn't exist" do + Trip.find_trips_rider(301).must_equal [] + end + end + + describe "trip#driver" do + it "Returns a driver that exists" do + trip = Trip.new(100, 29, 138, "2016-09-04", 2) + trip.driver.must_be_kind_of Driver + end + + it "Returns the correct driver for a specific trip" do + trip = Trip.new(100, 29, 138, "2016-09-04", 2) + name = "Miss Gustave Erdman" + trip.driver.name.must_equal name + end + + it "Returns nil if driver doesn't exist" do + trip = Trip.new(83, 0, 103, "2015-12-25", 2) + trip.driver.must_be_nil + end + end + + describe "trip#rider" do + it "Returns a rider that exists" do + trip = Trip.new(100, 29, 138, "2016-09-04", 2) + trip.rider.must_be_kind_of Rider + end + + it "Returns the correct rider for a specific trip" do + trip = Trip.new(100, 29, 138, "2016-09-04", 2) + name = "Miss Frida Abshire" + trip.rider.name.must_equal name + end + + it "Returns nil if rider doesn't exist" do + trip = Trip.new(267, 14, 0, "2015-04-23", 4) + trip.rider.must_be_nil + end + end + +end