# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Issues::CreateFromVulnerabilityService, '#execute' do
  let_it_be(:group)   { create(:group) }
  let_it_be(:project) { create(:project, :public, :repository, namespace: group) }
  let_it_be(:user)    { create(:user) }
  let(:vulnerability) { create(:vulnerability, :with_finding, project: project) }
  let(:params) { { vulnerability: vulnerability, link_type: Vulnerabilities::IssueLink.link_types[:created] } }

  before do
    stub_licensed_features(security_dashboard: true)
    group.add_developer(user)
  end

  shared_examples 'a created issue' do
    let(:result) { described_class.new(container: project, current_user: user, params: params).execute }

    it 'creates the issue with the given params' do
      expect(result[:status]).to eq(:success)
      issue = result[:issue]
      expect(issue).to be_persisted
      expect(issue.project).to eq(project)
      expect(issue.author).to eq(user)
      expect(issue.title).to eq(expected_title)
      expect(issue.description).to eq(expected_description)
      expect(issue).to be_confidential
    end
  end

  context 'when a vulnerability exists' do
    let(:result) { described_class.new(container: project, current_user: user, params: params).execute }

    context 'is a vulnerability with remediations' do
      let(:vulnerability) { create(:vulnerability, :with_remediation, project: project) }

      context 'when raw_metadata has no remediations' do
        let(:vulnerability) { create(:vulnerability, :with_finding, project: project) }

        it 'does not display Remediations section' do
          expect(vulnerability.remediations).to eq(nil)
          expect(result[:issue].description).not_to match(/Remediations/)
        end
      end

      context 'when raw_metadata has empty remediations key' do
        before do
          finding = vulnerability.finding
          metadata = Gitlab::Json.parse(finding.raw_metadata)
          metadata["remediations"] = [nil]
          finding.raw_metadata = metadata.to_json
          finding.save!
        end

        it 'does not display Remediations section' do
          expect(vulnerability.remediations).to eq([nil])
          expect(result[:issue].description).not_to match(/Remediations/)
        end
      end

      context 'when raw_metadata has a remediation' do
        it 'displays Remediations section' do
          expect(vulnerability.remediations.length).to eq(1)
          expect(result[:issue].description).to match(/Remediations/)
        end

        it 'attaches the diff' do
          expect(result[:issue].description).to match(/This is a diff/)
        end
      end
    end

    context 'when user does not have permission to create issue' do
      before do
        allow_next_instance_of(described_class) do |instance|
          allow(instance).to receive(:can?).with(user, :create_issue, project).and_return(false)
        end
      end

      it 'returns expected error' do
        expect(result[:status]).to eq(:error)
        expect(result[:message]).to eq("Can't create issue")
      end
    end

    context 'when issues are disabled on project' do
      let(:project) { create(:project, :public, namespace: group, issues_access_level: ProjectFeature::DISABLED) }

      it 'returns expected error' do
        expect(result[:status]).to eq(:error)
        expect(result[:message]).to eq("Can't create issue")
      end
    end

    context 'when report type is SAST' do
      let(:expected_title) { "Investigate vulnerability: #{vulnerability.title}" }
      let(:expected_description) do
        <<~DESC.chomp
          Issue created from vulnerability <a href="http://localhost/#{group.name}/#{project.name}/-/security/vulnerabilities/#{vulnerability.id}">#{vulnerability.id}</a>

          ### Description:

          Description of #{vulnerability.title}

          * Severity: #{vulnerability.severity}
          * Confidence: #{vulnerability.confidence}
          * Location: [maven/src/main/java/com/gitlab/security_products/tests/App.java:29](http://localhost/#{project.full_path}/-/blob/master/maven/src/main/java/com/gitlab/security_products/tests/App.java#L29)

          ### Solution:

          #{vulnerability.solution}

          ### Identifiers:

          * [CVE-2018-1234](http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-1234)

          ### Links:

          * [Cipher does not check for integrity first?](https://crypto.stackexchange.com/questions/31428/pbewithmd5anddes-cipher-does-not-check-for-integrity-first)
        DESC
      end

      it_behaves_like 'a created issue'
    end
  end
end
