# frozen_string_literal: true

require 'spec_helper'

describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
  let!(:identifier) { build(:vulnerabilities_identifier) }
  let!(:base_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '123', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Occurrence::SEVERITY_LEVELS[:critical]) }
  let!(:head_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '123', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Occurrence::SEVERITY_LEVELS[:critical]) }

  before do
    allow(base_vulnerability).to receive(:location).and_return({})
    allow(head_vulnerability).to receive(:location).and_return({})
  end

  describe '#existing' do
    context 'with existing reports' do
      let(:vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:medium]) }
      let(:low_vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:low]) }
      let(:comparer) { described_class.new([base_vulnerability], [head_vulnerability]) }

      it 'points to source tree' do
        comparer = described_class.new([base_vulnerability], [head_vulnerability])

        expect(comparer.existing).to eq([head_vulnerability])
      end

      it 'does not change order' do
        comparer = described_class.new([base_vulnerability, vuln], [head_vulnerability, vuln, low_vuln])

        expect(comparer.existing).to eq([head_vulnerability, vuln])
      end
    end
  end

  describe '#added' do
    let(:vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Occurrence::SEVERITY_LEVELS[:critical]) }
    let(:low_vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Occurrence::SEVERITY_LEVELS[:low]) }

    context 'with new vulnerability' do
      let(:comparer) { described_class.new([base_vulnerability], [vuln, low, head_vulnerability]) }

      it 'points to source tree' do
        comparer = described_class.new([base_vulnerability], [head_vulnerability, vuln])

        expect(comparer.added).to eq([vuln])
      end

      it 'does not change order' do
        comparer = described_class.new([base_vulnerability], [head_vulnerability, vuln, low_vuln])

        expect(comparer.added).to eq([vuln, low_vuln])
      end
    end
  end

  describe '#fixed' do
    let(:vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888') }
    let(:medium_vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Occurrence::SEVERITY_LEVELS[:medium]) }

    context 'with fixed vulnerability' do
      it 'points to base tree' do
        comparer = described_class.new([base_vulnerability, vuln], [head_vulnerability])

        expect(comparer.fixed).to eq([vuln])
      end

      it 'does not change order' do
        comparer = described_class.new([vuln, medium_vuln, base_vulnerability], [head_vulnerability])

        expect(comparer.fixed).to eq([vuln, medium_vuln])
      end
    end
  end

  describe 'with empty vulnerabilities' do
    it 'returns empty array when reports are not present' do
      comparer = described_class.new(nil, nil)

      expect(comparer.existing).to eq([])
      expect(comparer.fixed).to eq([])
      expect(comparer.added).to eq([])
    end

    it 'returns added vulnerability when base is empty and head is not empty' do
      vuln = build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888')
      comparer = described_class.new(nil, [vuln])

      expect(comparer.existing).to eq([])
      expect(comparer.fixed).to eq([])
      expect(comparer.added).to eq([vuln])
    end

    it 'returns fixed vulnerability when head is empty and base is not empty' do
      vuln = build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888')
      comparer = described_class.new([vuln], nil)

      expect(comparer.existing).to eq([])
      expect(comparer.fixed).to eq([vuln])
      expect(comparer.added).to eq([])
    end
  end
end
