require File.dirname(__FILE__) + '/../test_helper' class ProductTest < ActiveSupport::TestCase def setup @product_category = fast_create(ProductCategory, :name => 'Products') end should 'create product' do assert_difference Product, :count do p = Product.new(:name => 'test product1', :product_category => @product_category) assert p.save end end should 'destroy product' do p = fast_create(Product, :name => 'test product2', :product_category_id => @product_category.id) assert_difference Product, :count, -1 do p.destroy end end should 'display category name if name is nil' do p = fast_create(Product, :name => nil) p.expects(:category_name).returns('Software') assert_equal 'Software', p.name end should 'display category name if name is blank' do p = fast_create(Product, :name => '') p.expects(:category_name).returns('Software') assert_equal 'Software', p.name end should 'set nil to name if name is equal to category name' do p = fast_create(Product) p.expects(:category_name).returns('Software').at_least_once p.name = 'Software' p.save assert_equal 'Software', p.name assert_equal nil, p[:name] end should 'list recent products' do enterprise = fast_create(Enterprise, :name => "My enterprise", :identifier => 'my-enterprise') Product.delete_all p1 = enterprise.products.create!(:name => 'product 1', :product_category => @product_category) p2 = enterprise.products.create!(:name => 'product 2', :product_category => @product_category) p3 = enterprise.products.create!(:name => 'product 3', :product_category => @product_category) assert_equal [p3, p2, p1], Product.recent end should 'list recent products with limit' do enterprise = fast_create(Enterprise, :name => "My enterprise", :identifier => 'my-enterprise') Product.delete_all p1 = enterprise.products.create!(:name => 'product 1', :product_category => @product_category) p2 = enterprise.products.create!(:name => 'product 2', :product_category => @product_category) p3 = enterprise.products.create!(:name => 'product 3', :product_category => @product_category) assert_equal [p3, p2], Product.recent(2) end should 'save image on create product' do assert_difference Product, :count do p = Product.create!(:name => 'test product1', :product_category => @product_category, :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') }) assert_equal p.image(true).filename, 'rails.png' end end should 'calculate catagory full name' do cat = mock cat.expects(:full_name).returns('A/B/C') p = Product.new p.stubs(:product_category).returns(cat) assert_equal ['A','B','C'], p.category_full_name end should 'return a nil cateory full name when not categorized' do p = Product.new p.stubs(:product_category).returns(nil) assert_equal nil, p.category_full_name end should 'be indexed by category full name' do p = Product.new(:name => 'a test product', :product_category => @product_category) p.stubs(:category_full_name).returns('interesting category') p.save! assert_includes Product.find_by_contents('interesting'), p end should 'have same lat and lng of its enterprise' do ent = fast_create(Enterprise, :name => 'test enterprise', :identifier => 'test_enterprise', :lat => 30.0, :lng => 30.0) prod = ent.products.create!(:name => 'test product', :product_category => @product_category) prod = Product.find(prod.id) assert_equal ent.lat, prod.lat assert_equal ent.lng, prod.lng end should 'update lat and lng of product afer update enterprise' do ent = fast_create(Enterprise, :name => 'test enterprise', :identifier => 'test_enterprise', :lat => 30.0, :lng => 30.0) prod = ent.products.create!(:name => 'test product', :product_category => @product_category) ent.lat = 45.0; ent.lng = 45.0; ent.save! process_delayed_job_queue prod.reload assert_in_delta 45.0, prod.lat, 0.0001 assert_in_delta 45.0, prod.lng, 0.0001 end should 'be searched by radius and distance' do prod1 = fast_create(Product, :name => 'prod test 1', :lat => 30.0, :lng => 30.0, :product_category_id => @product_category.id) prod2 = fast_create(Product, :name => 'prod test 2', :lat => 45.0, :lng => 45.0, :product_category_id => @product_category.id) prods = Product.find(:all, :within => 10, :origin => [30.0, 30.0]) assert_includes prods, prod1 assert_not_includes prods, prod2 end should 'provide url' do product = Product.new enterprise = Enterprise.new enterprise.expects(:public_profile_url).returns({}) product.expects(:id).returns(999) product.expects(:enterprise).returns(enterprise) assert_equal({:controller => 'manage_products', :action => 'show', :id => 999}, product.url) end should 'categorize also with product categorization' do cat = fast_create(ProductCategory, :name => 'test cat', :environment_id => Environment.default.id) ent = fast_create(Enterprise, :name => 'test ent', :identifier => 'test_ent') p = ent.products.new(:name => 'test product') p.product_category = cat p.save! assert ProductCategorization.find(:first, :conditions => {:product_id => p, :category_id => cat}) end should 'categorize parent cateogries with product categorization' do parent_cat = fast_create(ProductCategory, :name => 'test cat', :environment_id => Environment.default.id) child_cat = fast_create(ProductCategory, :name => 'test cat', :environment_id => Environment.default.id, :parent_id => parent_cat.id) ent = fast_create(Enterprise, :name => 'test ent', :identifier => 'test_ent') p = ent.products.new(:name => 'test product') p.product_category = child_cat p.save! assert ProductCategorization.find(:first, :conditions => {:product_id => p, :category_id => parent_cat}) assert ProductCategorization.find(:first, :conditions => {:product_id => p, :category_id => child_cat}) end should 'change product categorization when product category changes' do cat1 = fast_create(ProductCategory, :name => 'test cat 1', :environment_id => Environment.default.id) cat2 = fast_create(ProductCategory, :name => 'test cat 2', :environment_id => Environment.default.id) ent = fast_create(Enterprise, :name => 'test ent', :identifier => 'test_ent') p = ent.products.create!(:name => 'test product', :product_category => cat1) p.product_category = cat2 p.save! assert ProductCategorization.find(:first, :conditions => {:product_id => p, :category_id => cat2}), 'must include the new category' assert !ProductCategorization.find(:first, :conditions => {:product_id => p, :category_id => cat1}), 'must exclude the old category' end should 'respond to public? as its enterprise public?' do e1 = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1') p1 = fast_create(Product, :name => 'test product 1', :enterprise_id => e1.id, :product_category_id => @product_category.id) assert p1.public? e1.public_profile = false e1.save!; p1.reload; assert !p1.public? end should 'accept prices in american\'s or brazilian\'s currency format' do [ [12.34, 12.34], ["12.34", 12.34], ["12,34", 12.34], ["12.345.678,90", 12345678.90], ["12,345,678.90", 12345678.90], ["12.345.678", 12345678.00], ["12,345,678", 12345678.00] ].each do |input, output| product = Product.new(:price => input) assert_equal output, product.price end end should 'accept discount in american\'s or brazilian\'s currency format' do [ [12.34, 12.34], ["12.34", 12.34], ["12,34", 12.34], ["12.345.678,90", 12345678.90], ["12,345,678.90", 12345678.90], ["12.345.678", 12345678.00], ["12,345,678", 12345678.00] ].each do |input, output| product = Product.new(:discount => input) assert_equal output, product.discount end end should 'strip name with malformed HTML when sanitize' do product = Product.new(:product_category => @product_category) product.name = "

" product.valid? assert_equal @product_category.name, product.name end should 'escape malformed html tags' do product = Product.new(:product_category => @product_category) product.name = "

> html >< tag" product.description = "

><<> >> html >< tag" product.valid? assert_no_match /[<>]/, product.name assert_no_match /[<>]/, product.description end should 'use name of category when has no name yet' do product = Product.new(:product_category => @product_category) assert product.valid? assert_equal product.name, @product_category.name end should 'not save without category' do product = Product.new(:name => 'A product without category') product.valid? assert product.errors.invalid?(:product_category_id) end should 'not save with a invalid category' do category = Category.new(:name => 'Region', :environment => Environment.default) assert_raise ActiveRecord::AssociationTypeMismatch do Product.new(:name => 'Invalid category product', :product_category => category) end end should 'format values to float with 2 decimals' do ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1') product = fast_create(Product, :enterprise_id => ent.id, :price => 12.994, :discount => 1.994) assert_equal "12.99", product.formatted_value(:price) assert_equal "1.99", product.formatted_value(:discount) end should 'calculate price with discount' do ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1') product = fast_create(Product, :enterprise_id => ent.id, :price => 12.994, :discount => 1.994) assert_equal 11.00, product.price_with_discount end should 'have default image' do product = Product.new assert_equal '/images/icons-app/product-default-pic-thumb.png', product.default_image end should 'have inputs' do product = Product.new assert_respond_to product, :inputs end should 'return empty array if has no input' do product = Product.new assert product.inputs.empty? end should 'return product inputs' do ent = fast_create(Enterprise) product = fast_create(Product, :enterprise_id => ent.id) input = fast_create(Input, :product_id => product.id, :product_category_id => @product_category.id) assert_equal [input], product.inputs end should 'destroy inputs when product is removed' do ent = fast_create(Enterprise) product = fast_create(Product, :enterprise_id => ent.id) input = fast_create(Input, :product_id => product.id, :product_category_id => @product_category.id) services_category = fast_create(ProductCategory, :name => 'Services') input2 = fast_create(Input, :product_id => product.id, :product_category_id => services_category.id) assert_difference Input, :count, -2 do product.destroy end end should 'test if name is blank' do product = Product.new assert product.name_is_blank? end should 'has basic info if filled unit, price or discount' do product = Product.new assert !product.has_basic_info? product = Product.new(:unit => Unit.new) assert product.has_basic_info? product = Product.new(:price => 1) assert product.has_basic_info? product = Product.new(:discount => 1) assert product.has_basic_info? end should 'destroy all qualifiers when save qualifiers list' do product = fast_create(Product) product.product_qualifiers.create(:qualifier => fast_create(Qualifier), :certifier => fast_create(Certifier)) product.product_qualifiers.create(:qualifier => fast_create(Qualifier), :certifier => fast_create(Certifier)) product.product_qualifiers.create(:qualifier => fast_create(Qualifier), :certifier => fast_create(Certifier)) assert_equal 3, product.qualifiers.count product.qualifiers_list = [[fast_create(Qualifier).id, fast_create(Certifier).id]] assert_equal 1, product.qualifiers.count end should 'save order of inputs' do product = fast_create(Product) first = Input.create!(:product => product, :product_category => fast_create(ProductCategory)) second = Input.create!(:product => product, :product_category => fast_create(ProductCategory)) third = Input.create!(:product => product, :product_category => fast_create(ProductCategory)) assert_equal [first, second, third], product.inputs product.order_inputs!([second.id, first.id, third.id]) assert_equal [second, first, third], product.inputs(true) end should 'format name with unit' do product = Product.new(:name => "My product") assert_equal "My product", product.name_with_unit product.unit = Unit.new(:name => 'litre') assert_equal "My product - litre", product.name_with_unit end should 'have relation with unit' do product = Product.new assert_kind_of Unit, product.build_unit end should 'index by schema name when database is postgresql' do uses_postgresql 'schema_one' p1 = Product.create!(:name => 'some thing', :product_category => @product_category) assert_equal Product.find_by_contents('thing'), [p1] uses_postgresql 'schema_two' p2 = Product.create!(:name => 'another thing', :product_category => @product_category) assert_not_includes Product.find_by_contents('thing'), p1 assert_includes Product.find_by_contents('thing'), p2 uses_postgresql 'schema_one' assert_includes Product.find_by_contents('thing'), p1 assert_not_includes Product.find_by_contents('thing'), p2 uses_sqlite end should 'not index by schema name when database is not postgresql' do uses_sqlite p1 = Product.create!(:name => 'some thing', :product_category => @product_category) assert_equal Product.find_by_contents('thing'), [p1] p2 = Product.create!(:name => 'another thing', :product_category => @product_category) assert_includes Product.find_by_contents('thing'), p1 assert_includes Product.find_by_contents('thing'), p2 end should 'respond to price details' do product = Product.new assert_respond_to product, :price_details end should 'return total value of inputs' do product = fast_create(Product) first = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) second = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1) assert_equal 50.0, product.inputs_cost end should 'return 0 on total value of inputs if has no input' do product = fast_create(Product) assert product.inputs_cost.zero? end should 'know if price is described' do product = fast_create(Product, :price => 30.0) first = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 1) assert !Product.find(product.id).price_described? second = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1) assert Product.find(product.id).price_described? end should 'return false on price_described if price of product is not defined' do product = fast_create(Product) assert_equal false, product.price_described? end should 'create price details' do product = fast_create(Product) cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') assert product.price_details.empty? product.update_price_details([{:production_cost_id => cost.id, :price => 10}]) assert_equal 1, Product.find(product.id).price_details.size end should 'update price of a cost on price details' do product = fast_create(Product) cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') cost2 = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') price_detail = product.price_details.create(:production_cost_id => cost.id, :price => 10) assert !product.price_details.empty? product.update_price_details([{:production_cost_id => cost.id, :price => 20}, {:production_cost_id => cost2.id, :price => 30}]) assert_equal 20, product.price_details.find_by_production_cost_id(cost.id).price assert_equal 2, Product.find(product.id).price_details.size end should 'destroy price details if product is removed' do product = fast_create(Product) cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') price_detail = product.price_details.create(:production_cost_id => cost.id, :price => 10) assert_difference PriceDetail, :count, -1 do product.destroy end end should 'have production costs' do product = fast_create(Product) cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') product.price_details.create(:production_cost_id => cost.id, :price => 10) assert_equal [cost], Product.find(product.id).production_costs end should 'return production costs from enterprise and environment' do ent = fast_create(Enterprise) product = fast_create(Product, :enterprise_id => ent.id) ent_production_cost = fast_create(ProductionCost, :owner_id => ent.id, :owner_type => 'Profile') env_production_cost = fast_create(ProductionCost, :owner_id => ent.environment.id, :owner_type => 'Environment') assert_equal [env_production_cost, ent_production_cost], product.available_production_costs end should 'return all production costs' do ent = fast_create(Enterprise) product = fast_create(Product, :enterprise_id => ent.id) env_production_cost = fast_create(ProductionCost, :owner_id => ent.environment.id, :owner_type => 'Environment') ent_production_cost = fast_create(ProductionCost, :owner_id => ent.id, :owner_type => 'Profile') product.price_details.create(:production_cost => env_production_cost, :product => product) assert_equal [env_production_cost, ent_production_cost], product.available_production_costs end should 'return total value of production costs' do ent = fast_create(Enterprise) product = fast_create(Product, :enterprise_id => ent.id) env_production_cost = fast_create(ProductionCost, :owner_id => ent.environment.id, :owner_type => 'Environment') price_detail = product.price_details.create(:production_cost => env_production_cost, :price => 10) input = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) assert_equal price_detail.price + input.cost, product.total_production_cost end should 'return inputs cost as total value of production costs if has no price details' do ent = fast_create(Enterprise) product = fast_create(Product, :enterprise_id => ent.id) input = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) assert_equal input.cost, product.total_production_cost end should 'return 0 on total production cost if has no input and price details' do product = fast_create(Product) assert product.total_production_cost.zero? end should 'format inputs cost values to float with 2 decimals' do ent = fast_create(Enterprise) product = fast_create(Product, :enterprise_id => ent.id) first = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) second = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1) assert_equal "50.00", product.formatted_value(:inputs_cost) end should 'return 0 on price_description_percentage by default' do assert_equal 0, Product.new.price_description_percentage end should 'return 0 on price_description_percentage if price is 0' do product = fast_create(Product, :price => 0) assert_equal 0, product.price_description_percentage end should 'return 0 on price_description_percentage if price is not defined' do product = fast_create(Product) assert_equal 0, product.price_description_percentage end should 'return 0 on price_description_percentage if total_production_cost is 0' do product = fast_create(Product, :price => 50) assert_equal 0, product.price_description_percentage end end