require 'spec_helper'

describe ActiveReporter::Dimension::Bin do
  def new_dimension(dimension_params = {}, report_params = {}, opts = {})
    report_params[:dimensions] = { foo: dimension_params }
    ActiveReporter::Dimension::Bin.new(:foo,
      OpenStruct.new(params: report_params),
      opts
    )
  end

  def expect_error(&block)
    expect { yield }.to raise_error(ActiveReporter::InvalidParamsError)
  end

  describe 'param validation' do
    it 'yells unless :bin_count is numeric' do
      expect_error { new_dimension(bin_count: 'hey') }
      expect_error { new_dimension(bin_count: nil) }
      new_dimension(bin_count: 5)
      new_dimension(bin_count: 1.24)
    end
  end

  describe '#min/max' do
    it 'finds the extremes in filter_values' do
      dimension = new_dimension(only: [{ min: 1, max: 3 }, { min: -3 }, { min: 17, max: 40 }])
      expect(dimension.min).to eq -3
      expect(dimension.max).to eq 40
    end

    it 'falls back to the smallest value in the data' do
      dimension = ActiveReporter::Dimension::Bin.new(:likes,
        OpenStruct.new(records: Post, params: {}),
        model: :post, attribute: :likes
      )
      expect(dimension.min).to be_nil
      expect(dimension.max).to be_nil
      create(:post, likes: 3)
      create(:post, likes: 10)
      create(:post, likes: 1)
      expect(dimension.min).to eq 1
      expect(dimension.max).to eq 10
    end
  end

  describe '#group_values' do
    it 'defaults to dividing the domain into bins of bin_width' do
      dimension = new_dimension(only: { min: 0, max: 3 })
      allow(dimension).to receive(:bin_width).and_return(1)
      allow(dimension).to receive(:data_contains_nil?).and_return(false)
      expect(dimension.group_values).to eq [
        { min: 0, max: 1 },
        { min: 1, max: 2 },
        { min: 2, max: 3 }
      ]
    end

    it 'is inclusive of max if data-driven' do
      dimension = new_dimension(only: { min: 0 })
      allow(dimension.report).to receive(:records).and_return(Post)
      allow(dimension).to receive(:expression).and_return('posts.likes')
      allow(dimension).to receive(:bin_width).and_return(1)
      create(:post, likes: 2)
      expect(dimension.group_values).to eq [
        { min: 0, max: 1 },
        { min: 1, max: 2 },
        { min: 2, max: 3 }
      ]
    end

    it 'can be customized' do
      dimension = new_dimension(bins: { min: 0, max: 1 })
      expect(dimension.group_values).to eq [{ min: 0, max: 1 }]
    end
  end
end