# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Gitlab::Graphql::Aggregations::VulnerabilityStatistics::LazyAggregate do
  let(:query_ctx) do
    {}
  end

  let_it_be(:vulnerable) { create(:group) }
  let_it_be(:other_vulnerable) { create(:group) }
  let(:include_subgroups) { true }

  describe '#initialize' do
    it 'adds the vulnerable to the lazy state' do
      subject = described_class.new(query_ctx, vulnerable, include_subgroups: true)

      expect(subject.lazy_state[:pending_vulnerables]).to eq(true => Set.new([vulnerable]), false => Set.new)
      expect(subject.vulnerable).to match vulnerable
    end
  end

  describe '#execute' do
    let(:fake_data) do
      {
        vulnerable => [::Vulnerabilities::ProjectsGrade.new(vulnerable, 'a', [])],
        other_vulnerable => [::Vulnerabilities::ProjectsGrade.new(other_vulnerable, 'b', [])]
      }
    end

    subject { described_class.new(query_ctx, vulnerable, include_subgroups: include_subgroups) }

    before do
      subject.instance_variable_set(:@lazy_state, fake_state)
      allow(::Vulnerabilities::ProjectsGrade).to receive(:grades_for).and_return(fake_data)
    end

    context 'if the record has already been loaded' do
      let(:fake_state) do
        { pending_vulnerables: { true => Set.new, false => Set.new }, loaded_objects: { true => { vulnerable => [::Vulnerabilities::ProjectsGrade.new(vulnerable, 'a', [])] }, false => {} } }
      end

      it 'does not make the query again' do
        expect(::Vulnerabilities::ProjectsGrade).not_to receive(:grades_for)

        subject.execute
      end
    end

    context 'if the record has not been loaded' do
      let(:include_subgroups) { true }
      let(:fake_state) do
        { pending_vulnerables: { true => Set.new([vulnerable]), false => Set.new([other_vulnerable]) }, loaded_objects: { true => {}, false => {} } }
      end

      it 'makes the query' do
        expect(::Vulnerabilities::ProjectsGrade).to receive(:grades_for).with([vulnerable], include_subgroups: true)
        expect(::Vulnerabilities::ProjectsGrade).to receive(:grades_for).with([other_vulnerable], include_subgroups: false)

        subject.execute
      end

      it 'clears the pending IDs' do
        subject.execute

        expect(subject.lazy_state[:pending_vulnerables].values).to all(be_empty)
      end
    end
  end
end
