diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..404abb22 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +coverage/ diff --git a/Rakefile b/Rakefile new file mode 100644 index 00000000..7a6bcf2f --- /dev/null +++ b/Rakefile @@ -0,0 +1,11 @@ +# I have also just copied the contents of the Rakefile that was included in the in-class TDD demo. +# To run the rake tests, just be inside the FarMar directory in your terminal and type 'rake'. + +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.test_files = FileList['specs/*_spec.rb'] + #this is the set of files that will be tested. + end + +task default: :test diff --git a/far_mar.rb b/far_mar.rb new file mode 100644 index 00000000..8d4d9af2 --- /dev/null +++ b/far_mar.rb @@ -0,0 +1,11 @@ +# gems your project needs +require 'csv' + +# our namespace module +module FarMar; end + +# all of our data classes that live in the module +require_relative './lib/farmar_market' +require_relative './lib/farmar_product' +require_relative './lib/farmar_sale' +require_relative './lib/farmar_vendor' diff --git a/lib/farmar_market.rb b/lib/farmar_market.rb new file mode 100644 index 00000000..e10a4719 --- /dev/null +++ b/lib/farmar_market.rb @@ -0,0 +1,78 @@ +require 'csv' + +module FarMar + class Market + attr_reader :id, :name, :address + def initialize (id, name, address, city, county, state, zip) + # ID - (Fixnum) a unique identifier for that market + @id = id + # Name - (String) the name of the market (not guaranteed unique) + @name = name + # Address - (String) street address of the market + @address = address + # City - (String) city in which the market is located + # County - (String) county in which the market is located + # State - (String) state in which the market is located + # Zip - (String) zipcode in which the market is located) + end + + def self.all + # self.all: returns a collection of instances, representing all of the objects described in the CSV + markets = {} + + CSV.read("support/markets.csv").each do |line| + # Is there a way to do this with an enumerable instead of an each? + # id = line[0].to_i + # name = line[1] + # address = line[2] + # city = line[3] + # county = line[4] + # state = line[5] + # zip = line[6].to_i + + id, name, address, city, county, state, zip = line # parallel assignment! + id = id.to_i # need id to be a fixnum + zip = zip.to_i # want zip to be a fixnum also (I think) + + markets[id] = self.new(id, name, address, city, county, state, zip) + end + + return markets + end + + def self.find(id) + # self.find(id): returns an instance of the object where the value of the id field in the CSV matches the passed parameter. + all_markets = self.all + return all_markets[id] + end + + def vendors + Vendor.by_market(@id) + # Call Vendor.all (returns a hash of vendors) + # The Vaules of the Vendor.all hash is an array of Vendors, so want to group those on their market_id. + # Then, want only the vendors that correspond to the market instance's id. + end + + def prefered_vendor + #prefered_vendor: returns the vendor with the highest revenue + # I'm going to start with an array of all vendors for the MARKET. (market.vendors), then I want to calculate the revenue for each vendor, and store it with the corresponding vendor (hash, where revenue is the key, value is an array of vendors with that revenue, in case there are more than one). then, call .max on the keys of the hash, get the key, call the value. Or I can just use max_by. + vendors.max_by { |vendor| vendor.revenue } + + end + end +end + + +# This is what I wrote for the accounts self.all to read in the csv file. +# def self.all +# accounts = {} +# +# CSV.read("support/accounts.csv").each do |line| +# account_id = line[0].to_i +# balance = line[1].to_i +# open_date = line[2] +# accounts[account_id] = self.new(account_id, open_date, balance) +# end +# +# return accounts +# end diff --git a/lib/farmar_product.rb b/lib/farmar_product.rb new file mode 100644 index 00000000..94f8f54e --- /dev/null +++ b/lib/farmar_product.rb @@ -0,0 +1,63 @@ +require 'csv' + +module FarMar + class Product + attr_reader :product_id, :product_name, :vendor_id + def initialize(product_id, product_name, vendor_id) + # ID - (Fixnum) uniquely identifies the product + @product_id = product_id + # Name - (String) the name of the product (not guaranteed unique) + @product_name = product_name + # Vendor_id - (Fixnum) a reference to which vendor sells this product + @vendor_id = vendor_id + end + + def self.all + # self.all: returns a collection of instances, representing all of the objects described in the CSV + products = {} + + CSV.read("support/products.csv").each do |line| + product_id, product_name, vendor_id = line # parallel assignment! + product_id = product_id.to_i # need product_id to be a fixnum + vendor_id = vendor_id.to_i #want vendor_id to be a fixnum + + products[product_id] = self.new(product_id, product_name, vendor_id) + end + + return products + end + + def self.find(id) + # self.find(id): returns an instance of the object where the value of the id field in the CSV matches the passed parameter. + specific_product = Product.all + return specific_product[id] + end + + def vendor + #vendor: returns the FarMar::Vendor instance that is associated with this vendor using the FarMar::Product vendor_id field - this will work LIKE the vendor.market method. + Vendor.find(@vendor_id) + end + + def self.by_vendor(vendor_id) + # self.by_vendor(vendor_id): returns all of the products with the given vendor_id (will call this in the Vendor #products method. ) + all.values.select { |product| product.vendor_id == vendor_id } + #I don't like that these things are called the same thing -- I have an instance variable @vendor_id for a product instance, and the argument vendor_id that is getting passed in. Seems to be working though. + #TODO: rather than using group_by and getting all the product groups by vendor_id, and then throwing away all the groups except the one I care about, research using "filter". + end + + def sales + #sales: returns an array of FarMar::Sale instances that are associated using the FarMar::Sale product_id field. + Sale.all.values.select {|sale| sale.product_id == @product_id} + # Sale.all.values.group_by {|sale| sale.product_id}[@product_id] + #NOTE: It possible that a given product has NO sales. + end + + def number_of_sales + #number_of_sales: returns the number of times this product has been sold. + sales.length + end + end +end + + +#number_of_sales: returns the number of times this product has been sold. diff --git a/lib/farmar_sale.rb b/lib/farmar_sale.rb new file mode 100644 index 00000000..dadc6fbe --- /dev/null +++ b/lib/farmar_sale.rb @@ -0,0 +1,65 @@ +require 'csv' +# require 'date' + +module FarMar + class Sale + @@all_sales = nil + attr_reader :sale_id, :amount, :vendor_id, :product_id, :purchase_time + def initialize(sale_id, amount, purchase_time, vendor_id, product_id) + # sale_id, amount, purchase_time, vendor_id, product_id) + # ID - (Fixnum) uniquely identifies the sale + @sale_id = sale_id + # Amount - (Fixnum) the amount of the transaction, in cents (i.e., 150 would be $1.50) + @amount = amount + # Purchase_time - (Datetime) when the sale was completed + @purchase_time = DateTime.parse(purchase_time) # purchase_time in csv is the string representation of a datetime, not the comma delimited input that Datetime is expecting. https://ruby-doc.org/stdlib-2.3.1/libdoc/date/rdoc/DateTime.html#method-c-parse + # Vendor_id - (Fixnum) a reference to which vendor completed the sale + @vendor_id = vendor_id + # Product_id - (Fixnum) a reference to which product was sold + @product_id = product_id + end + + def self.all + # self.all: returns a collection of instances, representing all of the objects described in the CSV + if @@all_sales == nil + + @@all_sales = {} + + CSV.read("support/sales.csv").each do |line| + sale_id, amount, purchase_time, vendor_id, product_id = line # parallel assignment! + sale_id = sale_id.to_i # need sale_id to be a fixnum + amount = amount.to_i # want amount to be a fixnum also + vendor_id = vendor_id.to_i # want vendor_id to be a fixnum + product_id = product_id.to_i # want product_id also to be a fixnum + + @@all_sales[sale_id] = self.new(sale_id, amount, purchase_time, vendor_id, product_id) + end + end + + return @@all_sales + end + + def self.find(id) + # self.find(id): returns an instance of the object where the value of the id field in the CSV matches the passed parameter. + #this is going to call self.all, and then find the one with key of id + all[id] + end + + def vendor + #vendor: returns the FarMar::Vendor instance that is associated with this sale using the FarMar::Sale vendor_id field + Vendor.find(@vendor_id) + end + + def product + #product: returns the FarMar::Product instance that is associated with this sale using the FarMar::Sale product_id field + Product.find(@product_id) + end + + def self.between(beginning_time, end_time) + between_sales = Sale.all.select do |key, value| + value.purchase_time >= beginning_time && value.purchase_time <= end_time + end + between_sales + end + end +end diff --git a/lib/farmar_vendor.rb b/lib/farmar_vendor.rb new file mode 100644 index 00000000..0fc2be87 --- /dev/null +++ b/lib/farmar_vendor.rb @@ -0,0 +1,94 @@ +require 'csv' + +module FarMar + class Vendor + attr_reader :id, :name, :market_id, :num_employees + def initialize(id, name, num_employees, market_id) + # ID - (Fixnum) uniquely identifies the vendor + @id = id + # Name - (String) the name of the vendor (not guaranteed unique) + @name = name + # No. of Employees - (Fixnum) How many employees the vendor has at the market + @num_employees = num_employees + # Market_id - (Fixnum) a reference to which market the vendor attends + @market_id = market_id + end + + def self.all + # self.all: returns a collection of instances, representing all of the objects described in the CSV + vendors = {} + + CSV.read("support/vendors.csv").each do |line| + id, name, num_employees, market_id = line # parallel assignment! + id = id.to_i # need id to be a fixnum + num_employees = num_employees.to_i # want num_employees to be a fixnum also + market_id = market_id.to_i #want market_id to be a fixnum + + vendors[id] = self.new(id, name, num_employees, market_id) + end + + return vendors + end + + def self.find(id) + # self.find(id): returns an instance of the object where the value of the id field in the CSV matches the passed parameter. + all_vendors = self.all + all_vendors[id] + end + + def market + #market: returns the FarMar::Market instance that is associated with this vendor using the FarMar::Vendor market_id field + # Return the market object that corresponds to the instance's market_id. + Market.find(@market_id) + end + + def self.by_market(market_id) + # self.by_market(market_id): returns all of the vendors with the given market_id + Vendor.all.values.select { |vendor| vendor.market_id == market_id } + + #I don't like that these things are called the same thing -- I have an instance variable @market_id for a vendor instance, and the argument market_id that is getting passed in. Seems to be working though. + end + + def products + #products: returns an array of FarMar::Product instances that are associated by the FarMar::Product vendor_id field. Seems to be related to the Product.by_vendor(id), which returns all the products with a given vendor_id. + Product.by_vendor(@id) + end + + def sales + #sales: returns a collection of FarMar::Sale instances that are associated by the vendor_id field. + # for this vendor object, I should get the list of products associated with it, then call product.sales for each of those products, which should return a collection of sales (probably as a hash, keyed off of product_id). + sales_hash = {} + + products.each do |product| #for each product do the following. + # it is possible for there to be no sales for a given product + # unless product.sales == nil + unless product.sales == [] + #product.sales will return an empty array for products that have no sales. + sales_hash[product] = product.sales + end + end + + return sales_hash + end + + def revenue + #revenue: returns the the sum of all of the vendor's sales (in cents) + #probably uses the #sales method, grabs the amount associated with each sale, and then reduces (:+) them to a sum? + #sales returns a hash with key value pairs of product: [array of sales], so I'll want to iterate through each array of sales, grab the sale.amount, make a collection of those, and reduce them to the sum. Then for each product, I'll have a a total sale amount. (maybe use a map here), and I can then reduce again to get the total revenue. + revenue_by_product = sales.map do |k, v| + #v is an array of sales + #want to get an array of sale.amounts for it. + amounts = [] + v.each do |sale| + amounts << sale.amount + end + + # taking the array of sale.amounts, I'm going to reduce to get revenue for this product. The result should be an array of revenues per product. (number of amounts in this array should equal the same number of products for the vendor where there have been a sale.) + # at some point in the future, I might want to keep the product as the key, but for right now I don't think I care. + amounts.reduce(:+) + end + + revenue_by_product.reduce(:+) + end + end +end diff --git a/specs/market_spec.rb b/specs/market_spec.rb new file mode 100644 index 00000000..30b3c50b --- /dev/null +++ b/specs/market_spec.rb @@ -0,0 +1,76 @@ +require_relative 'spec_helper' #get all the stuff we need for testing. + +module FarMar + describe Market do + let(:market_test) {Market.new(1, "name", "address", "city", "county", "ST", 98017)} + let(:coop_market) {Market.new(1,"People's Co-op Farmers Market","30th and Burnside","Portland","Multnomah","Oregon",97202)} + describe "#initialize" do + it "should make a new instance of market" do + # this just tests the basic "I can make a new instance of this class." + market_test.must_be_instance_of(Market) + end + + # I will need to get some information back from each instance of market - namely the name and the ID, check that a newly instantiated market will have these things. + it "should respond to .id with a Fixnum" do + market_test.id.must_be_instance_of(Fixnum) + end + it "should respond to .name with a String" do + market_test.name.must_be_instance_of(String) + end + it "should respond to .address" do + market_test.address.must_be_instance_of(String) + end + end + describe "#self.all" do + it "should return a collection of the markets included in the csv" do + # self.all: returns a collection of instances, representing all of the objects described in the CSV + # I think this will be a hash - key of market_id, and value of market_name, etc. + Market.all.must_be_instance_of(Hash) + end + + it "should contain a specific market in the csv" do + # Check that the Hash contains a key of 2 + Market.all.keys.must_include(2) + end + end + describe "#self.find(id)" do + # self.find(id): returns an instance of the object where the value of the id field in the CSV matches the passed parameter. + it "should return an instance of Market when given an id" do + Market.find(2).must_be_instance_of(Market) + end + + it "should return the correct instance of Market when given an id" do + Market.find(12).name.must_equal("Coxsackie Farmers' Market") + end + end + describe "#vendors" do + it "should return an array" do + coop_market.vendors.must_be_instance_of(Array) + # I'm going to make it an array of Vendors. + end + it "should return an array of Vendor objects" do + # Check that the first item is a vendor. + coop_market.vendors[0].must_be_instance_of(Vendor) + end + it "the vendor returned, should have a market_id that matches the market" do + # Checking that the objects returned have the same id as the market instance I'm working with. + # NOTE: It's not ACTUALLY the same object (same data, different object id), since I have created coop_market here. I wonder if I should check for the same object. I'm not sure how. + # This will check using the market method in Vendor. + coop_market.vendors[0].market_id.must_be_same_as(coop_market.id) + end + end + describe "#prefered_vendor" do + + #prefered_vendor: returns the vendor with the highest revenue + # I'm going to start with an array of all vendors for the MARKET. (market.vendors), then I want to calculate the revenue for each vendor, and store it with the corresponding vendor (hash, where revenue is the key, value is an array of vendors with that revenue, in case there are more than one). then, call .max on the keys of the hash, get the key, call the value. + it "should return a Vendor" do + coop_market.prefered_vendor.must_be_instance_of(Vendor) + end + it "should return the vendor with highest revenue" do + #not sure how to check this + skip + + end + end + end +end diff --git a/specs/product_spec.rb b/specs/product_spec.rb new file mode 100644 index 00000000..78ad28c8 --- /dev/null +++ b/specs/product_spec.rb @@ -0,0 +1,84 @@ +require_relative 'spec_helper' #get all the stuff we need for testing. + +module FarMar + describe Product do + let(:pro_deal) {Product.new(1, "product", 123)} + let(:carrot) {Product.new(41,"Thundering Carrots",15)} + + describe "#initialize" do + it "should make a new instance of product" do + #write test to check that a new product instance was created. + pro_deal.must_be_instance_of(Product) + # ID - (Fixnum) uniquely identifies the product + # Name - (String) the name of the product (not guaranteed unique) + # Vendor_id - (Fixnum) a reference to which vendor sells this product + end + it "should respond to .product_name" do + pro_deal.product_name.must_equal("product") + end + end + describe "self.all" do + # self.all: returns a collection of instances, representing all of the objects described in the CSV + it "should return a collection of products" do + #return a collection of products + Product.all.must_be_instance_of(Hash) + end + + it "should be a hash of Products" do + Product.all[12].must_be_instance_of(Product) + end + end + describe "self.find(id)" do + # self.find(id): returns an instance of the object where the value of the id field in the CSV matches the passed parameter. + it "should return a Product object when given an id" do + Product.find(12).must_be_instance_of(Product) + end + + it "should return the correct Product object when given an id" do + Product.find(15).product_name.must_equal("Comfortable Pretzel") + # 15,Comfortable Pretzel,8 + end + end + describe "#vendor" do + #vendor: returns the FarMar::Vendor instance that is associated with this product using the FarMar::Product vendor_id field - this will work LIKE the vendor.market method. + # 41,Thundering Carrots,15 + it "should return the vendor that is associated with the vendor_id" do + carrot.vendor.id.must_equal(15) + end + it "should return a Vendor object" do + carrot.vendor.must_be_instance_of(Vendor) + end + end + describe "self.by_vendor(vendor_id)" do + # self.by_vendor(vendor_id): returns all of the products with the given vendor_id (will call this in the Vendor #products method. ) + # This is similar to self.by_market method in vendor. + it "should return an array" do + Product.by_vendor(1).must_be_instance_of(Array) + end + + it "should be an array of Products" do + Product.by_vendor(1)[0].must_be_instance_of(Product) + end + end + describe "#sales" do + #sales: returns a collection of FarMar::Sale instances that are associated using the FarMar::Sale product_id field. + it "should return an Array" do + # going to collect sales (using Sale.all), group by sale.product_id, grab only the array from this instance's product_id. + carrot.sales.must_be_instance_of(Array) + end + it "should return an array of Sales" do + carrot.sales[0].must_be_instance_of(Sale) + end + it "should return sales whose product_id is the same as this product_id" do + carrot.sales[0].product_id.must_equal(carrot.product_id) + end + end + describe "#number_of_sales" do + # number_of_sales: returns the number of times this product has been sold. + # will call #sales to get the list of sales for the product, and should look at the length. + it "must return the number of sales for the product" do + carrot.number_of_sales.must_equal(5) #replace with the number. + end + end + end +end diff --git a/specs/sale_spec.rb b/specs/sale_spec.rb new file mode 100644 index 00000000..0b6fe300 --- /dev/null +++ b/specs/sale_spec.rb @@ -0,0 +1,108 @@ +require_relative 'spec_helper' + +module FarMar + describe Sale do + let(:buy_a_thing) {Sale.new(1,100,"2013-11-07", 1, 1)} + let(:new_sale) {Sale.new(13,3450,"2013-11-12 12:00:35 -0800",3,4)} + describe "#initialize" do + it "should make a new instance of sale" do + buy_a_thing.must_be_instance_of(Sale) + # ID - (Fixnum) uniquely identifies the sale + # Amount - (Fixnum) the amount of the transaction, in cents (i.e., 150 would be $1.50) + # Purchase_time - (Datetime) when the sale was completed + # Vendor_id - (Fixnum) a reference to which vendor completed the sale + # Product_id - (Fixnum) a reference to which product was sold + end + + it "should have a sale amount" do + buy_a_thing.must_respond_to :amount + end + + it "should have a purchase_time" do + buy_a_thing.purchase_time.must_be_instance_of(DateTime) + end + end + + describe "self.all" do + # self.all: returns a collection of instances, representing all of the objects described in the CSV + it "should return a collection of Sale objects" do + # I'm going to start with hash with sale ID as the key. I think I'm going to need to get back out the vendor and product associated with it, but this seems good for now. + Sale.all.must_be_instance_of(Hash) + end + + end + + describe "self.find(id)" do + before(:all) do + @sale_21 = Sale.find(21) + end + # self.find(id): returns an instance of the object where the value of the id field in the CSV matches the passed parameter. + it "should return a sale, given an id" do + @sale_21.must_be_instance_of(Sale) + end + + it "should return the correct vendor id given the sale id" do + @sale_21.vendor_id.must_equal(4) + # 21,8963,2013-11-10 12:26:30 -0800,4,7 + end + it "should return the correct product id, given the sale id" do + @sale_21.product_id.must_equal(7) + end + end + + describe "#vendor" do + #vendor: returns the FarMar::Vendor instance that is associated with this sale using the FarMar::Sale vendor_id field + it "should return a vendor instance" do + # will this use the Vendor.find(id) method? + new_sale.vendor.must_be_instance_of(Vendor) + end + it "should be the correct vendor" do + # Same problem as other tests - it's a different instance of the object - same values, different object ID. + new_sale.vendor.name.must_equal("Breitenberg Inc") + end + end + + describe "#product" do + #product: returns the FarMar::Product instance that is associated with this sale using the FarMar::Sale product_id field + it "should return a product instance" do + # use the Product.find(id) method? + new_sale.product.must_be_instance_of(Product) + end + it "should be the correct product" do + #check that the name or the product_id is correct. + new_sale.product.product_id.must_equal(4) + end + end + + describe "self.between(begin,end)" do + let(:beginning_time) {DateTime.parse("2013-11-13 01:48:15 -0800")} + let(:end_time) {DateTime.parse("2013-11-13 01:49:37 -0800")} + let(:some_sales) {Sale.between(beginning_time, end_time)} + # self.between(beginning_time, end_time): returns a collection of FarMar::Sale objects where the purchase time is between the two times given as arguments + it "should return an Hash" do + #should return an array of sale objects + some_sales.must_be_instance_of(Hash) + end + + it "should return a Hash where the keys are Sale IDs" do + some_sales.keys[0].must_be_instance_of(Fixnum) + end + + it "should return the correct Sale ID as the key" do + some_sales[3].sale_id.must_equal(3) + end + + it "should return an array of Sale objects" do + some_sales.values[0].must_be_instance_of(Sale) + end + + it "should have Sales that are before end_time" do + some_sales.values[0].purchase_time.must_be :<=, end_time + end + + it "should have Sales that are after beginning_time" do + some_sales.values[0].purchase_time.must_be :>=, beginning_time + end + end + end +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 00000000..c5e9f160 --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,16 @@ +# This is from the simplecov documentation +require 'simplecov' +SimpleCov.start + +# I've just copied the spec_helper.rb file from the in-class TDD demo. +require 'minitest' +require 'minitest/spec' +require "minitest/autorun" +require "minitest/reporters" +require 'minitest/pride' + +# The far_mar file will reference all the farmer's market class files. + +require_relative '../far_mar' + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new diff --git a/specs/vendor_spec.rb b/specs/vendor_spec.rb new file mode 100644 index 00000000..f097aefe --- /dev/null +++ b/specs/vendor_spec.rb @@ -0,0 +1,125 @@ +require_relative 'spec_helper' + +module FarMar + describe Vendor do + let(:ven) {Vendor.new(1, "vendor name", 1, 1)} + let(:some_vendor) {Vendor.new(28,"Watsica and Sons",10,8)} + + describe "#initialize" do + it "should make a new instance of vendor" do + #write something here to test new instance of vendor + ven.must_be_instance_of(Vendor) + # ID - (Fixnum) uniquely identifies the vendor + # Name - (String) the name of the vendor (not guaranteed unique) + # No. of Employees - (Fixnum) How many employees the vendor has at the market + # Market_id - (Fixnum) a reference to which market the vendor attends + end + it "should respond to .name with a string" do + ven.name.must_be_instance_of(String) + end + + it "should respond to .name with the correct name" do + ven.name.must_equal("vendor name") + end + end + + describe "#self.all" do + # self.all: returns a collection of instances, representing all of the objects described in the CSV + it "should return a collection of Vendor objects" do + # I'm going to use the id as the key, rest of info as value. + Vendor.all.must_be_instance_of(Hash) + end + it "should contain a specific Vendor object, given the key" do + Vendor.all.must_include(2) + end + end + + describe "self.find(id)" do + # self.find(id): returns an instance of the object where the value of the id field in the CSV matches the passed parameter. + it "should return a vendor, given an id" do + Vendor.find(2).must_be_instance_of(Vendor) + end + + it "should return the correct name given the id" do + Vendor.find(74).name.must_equal("Haag-Padberg") + # 74,Haag-Padberg,3,17 + end + end + + describe "#market" do + #market: returns the FarMar::Market instance that is associated with this vendor using the FarMar::Vendor market_id field + let(:feil_f) {Vendor.new(1,"Feil-Farrell",8,1)} + it "should return the market object that is associated with the market_id" do + #this seems like it'll use Market.find ? + feil_f.market.name.must_equal("People's Co-op Farmers Market") + end + it "should return a market object" do + feil_f.market.must_be_instance_of(Market) + end + end + + describe "self.by_market" do + # self.by_market(market_id): returns all of the vendors with the given market_id + it "should return an array" do + Vendor.by_market(1).must_be_instance_of(Array) + end + + it "should be an array of Vendors" do + Vendor.by_market(1)[0].must_be_instance_of(Vendor) + end + end + + describe "#products" do + # Products: returns a collection of FarMar::Product instances that are associated by the FarMar::Product vendor_id field. + # This is going to call the Products.by_vendor(vendor_id) method! + it "should return an array" do + some_vendor.products.must_be_instance_of(Array) + # I'm going to make it an array of Products. + end + it "should return an array of Product objects" do + # Check that the first item is a vendor. + some_vendor.products[0].must_be_instance_of(Product) + end + it "the products returned should have a vendor_id that matches the vendor" do + # Checking that the objects returned have the same id as the vendor instance I'm working with. + # NOTE: It's not ACTUALLY the same object (same data, different object id), since I have created some_vendor here in the test. + # This will check using the Vendor method in Product. + some_vendor.products[0].vendor_id.must_be_same_as(some_vendor.id) + end + end + describe "#sales" do + #sales: returns a collection of FarMar::Sale instances that are associated by the vendor_id field. + # for this vendor object, I should get the list of products associated with it, then call product.sales for each of those products, which should return a collection of sales (as a hash, keyed off of product_id). + it "should return a Hash" do + some_vendor.sales.must_be_instance_of(Hash) + end + it "should return a Hash where the keys are Products" do + some_vendor.sales.keys[0].must_be_instance_of(Product) + end + it "should return a Hash where the values are an array of Sales" do + some_vendor.sales.values[0].must_be_instance_of(Array) + end + it "elements within the value Arrays should be Sale objects" do + #it is possible I'll have an empty array if there are no sales for a given product. + some_vendor.sales.values[0][0].must_be_instance_of(Sale) + end + it "should return Sales where the vendor_id is the same as it's vendor_id" do + some_vendor.sales.values[0][0].vendor_id.must_equal(some_vendor.id) + end + end + + describe "#revenue" do + #revenue: returns the the sum of all of the vendor's sales (in cents) + #probably uses the #sales method, grabs the amount associated with each sale, and then reduces (:+) them to a sum? + #sales returns a hash with key value pairs of product: [array of sales], so I'll want to iterate through each array of sales, grab the sale.amount, make a collection of those, and reduce them to the sum. Then for each product, I'll have a a total sale amount. (maybe use a map here), and I can then reduce again to get the total revenue. + it "should return a Fixnum" do + some_vendor.revenue.must_be_instance_of(Fixnum) + end + + it "should return the total revenue from all the products for the vendor" do + #in cents + some_vendor.revenue.must_equal(4589) + end + end + end +end