# frozen_string_literal: true

require 'spec_helper'

RSpec.describe VulnerabilityExports::Exporters::CsvService do
  let(:export_csv_service) { described_class.new(Vulnerability.all) }

  subject(:csv) { CSV.parse(export_csv_service.generate, headers: true) }

  context 'when block is not given' do
    it 'renders csv to string' do
      expect(export_csv_service.generate).to be_a String
    end
  end

  context 'when block is given' do
    it 'returns handle to Tempfile' do
      expect(export_csv_service.generate { |file| file }).to be_a Tempfile
    end
  end

  it 'includes the columns required for import' do
    expect(csv.headers).to contain_exactly('Group Name', 'Project Name', 'Scanner Type', 'Scanner Name', 'Status',
                                           'Vulnerability', 'Details', 'Additional Info', 'Severity', 'CVE', 'CWE', 'Other Identifiers')
  end

  describe 'CSV content' do
    context 'with valid findings' do
      before do
        vulnerability.finding.identifiers << create(:vulnerabilities_identifier, external_type: 'GSO', name: 'GSO-1234;1234')
        vulnerability.finding.identifiers << create(:vulnerabilities_identifier, external_type: 'TSO', name: 'TSO-1234')
      end

      context 'when a project belongs to a group' do
        let_it_be(:group) { create(:group) }
        let_it_be(:project) { create(:project, :public, group: group) }
        let_it_be(:vulnerability) { create(:vulnerability, :with_findings, project: project) }

        it 'includes proper values for each column type', :aggregate_failures do
          expect(csv[0]['Group Name']).to eq group.name
          expect(csv[0]['Project Name']).to eq project.name
          expect(csv[0]['Scanner Type']).to eq vulnerability.report_type
          expect(csv[0]['Scanner Name']).to eq vulnerability.finding_scanner_name
          expect(csv[0]['Status']).to eq vulnerability.state
          expect(csv[0]['Vulnerability']).to eq vulnerability.title
          expect(csv[0]['Details']).to eq vulnerability.finding_description
          expect(csv[0]['Additional Info']).to eq vulnerability.finding_message
          expect(csv[0]['Severity']).to eq vulnerability.severity
          expect(csv[0]['CVE']).to eq vulnerability.cve_value
          expect(csv[0]['CWE']).to eq vulnerability.cwe_value
          expect(csv[0]['Other Identifiers']).to eq '"GSO-1234;1234"; TSO-1234'
        end
      end

      context 'when a project belongs to a user' do
        let_it_be(:user) { create(:user) }
        let_it_be(:project) { create(:project, :public, namespace: user.namespace ) }
        let_it_be(:vulnerability) { create(:vulnerability, :with_findings, project: project) }

        it 'includes proper values for each column except group name' do
          expect(csv[0]['Group Name']).to be_nil
          expect(csv[0]['Project Name']).to eq project.name
          expect(csv[0]['Scanner Type']).to eq vulnerability.report_type
          expect(csv[0]['Scanner Name']).to eq vulnerability.finding_scanner_name
          expect(csv[0]['Status']).to eq vulnerability.state
          expect(csv[0]['Vulnerability']).to eq vulnerability.title
          expect(csv[0]['Details']).to eq vulnerability.finding_description
          expect(csv[0]['Additional Info']).to eq vulnerability.finding_message
          expect(csv[0]['Severity']).to eq vulnerability.severity
          expect(csv[0]['CVE']).to eq vulnerability.cve_value
          expect(csv[0]['CWE']).to eq vulnerability.cwe_value
          expect(csv[0]['Other Identifiers']).to eq '"GSO-1234;1234"; TSO-1234'
        end
      end
    end

    context 'when a vulnerability is missing a finding' do
      let_it_be(:group) { create(:group) }
      let_it_be(:project) { create(:project, :public, group: group) }
      let_it_be(:vulnerability) { create(:vulnerability, project: project) }

      it 'includes proper values for each column except Other Identifiers' do
        expect(csv[0]['Group Name']).to eq group.name
        expect(csv[0]['Project Name']).to eq project.name
        expect(csv[0]['Scanner Type']).to eq vulnerability.report_type
        expect(csv[0]['Scanner Name']).to eq vulnerability.finding_scanner_name
        expect(csv[0]['Status']).to eq vulnerability.state
        expect(csv[0]['Vulnerability']).to eq vulnerability.title
        expect(csv[0]['Details']).to eq vulnerability.finding_description
        expect(csv[0]['Additional Info']).to eq vulnerability.finding_message
        expect(csv[0]['Severity']).to eq vulnerability.severity
        expect(csv[0]['CVE']).to eq vulnerability.cve_value
        expect(csv[0]['CWE']).to eq vulnerability.cwe_value
        expect(csv[0]['Other Identifiers']).to be_nil
      end
    end
  end
end
