# frozen_string_literal: true

require 'spec_helper'

describe Gitlab::Ci::Parsers::Security::Formatters::DeprecatedFormattedContainerScanningVulnerability do
  let(:raw_report) do
    JSON.parse!(
      File.read(
        Rails.root.join('ee/spec/fixtures/security_reports/deprecated/gl-container-scanning-report.json')
      )
    )
  end

  let(:vulnerability) { raw_report['vulnerabilities'].first }

  let(:data_with_all_keys) do
    raw_report['vulnerabilities'].first.merge(
      'description' => 'Better hurry and fix that.',
      'featurename' => 'hexes',
      'featureversion' => '6.6.6',
      'fixedby' => '6.6.7',
      'link' => 'https://theintercept.com',
      'namespace' => 'malevolences',
      'vulnerability' => 'Level 9000 Soul Breach'
    )
  end

  subject { described_class.new(data_with_all_keys) }

  describe '#message' do
    it 'creates a message from the vulnerability and featurename' do
      expect(subject.message).to eq('Level 9000 Soul Breach in hexes')
    end

    context 'when there is no featurename' do
      it 'uses vulnerability for the message' do
        data_without_featurename = data_with_all_keys.deep_dup.merge('featurename' => '')

        formatted_vulnerability = described_class.new(data_without_featurename)

        expect(formatted_vulnerability.message).to eq('Level 9000 Soul Breach')
      end
    end
  end

  describe '#description' do
    it 'uses the given description' do
      expect(subject.description).to eq('Better hurry and fix that.')
    end

    context 'when there is no description' do
      let(:data_without_description) { data_with_all_keys.deep_dup.merge('description' => '') }

      it 'creates a description from the featurename and featureversion' do
        formatted_vulnerability = described_class.new(data_without_description)

        expect(formatted_vulnerability.description).to eq('hexes:6.6.6 is affected by Level 9000 Soul Breach')
      end

      context 'when there is no featureversion' do
        it 'creates a description from the featurename' do
          data_without_featureversion = data_without_description.deep_dup.merge('featureversion' => '')

          formatted_vulnerability = described_class.new(data_without_featureversion)

          expect(formatted_vulnerability.description).to eq('hexes is affected by Level 9000 Soul Breach')
        end
      end

      context 'when there is no featurename and no featureversion' do
        it 'creates a description from the namespace' do
          data_only_namespace = data_without_description.deep_dup.merge(
            'featurename' => '',
            'featureversion' => ''
          )

          formatted_vulnerability = described_class.new(data_only_namespace)

          expect(formatted_vulnerability.description).to eq('malevolences is affected by Level 9000 Soul Breach')
        end
      end
    end
  end

  describe '#severity' do
    using RSpec::Parameterized::TableSyntax

    where(:report_severity_category, :gitlab_severity_category) do
      'Unknown'    | 'unknown'
      'Negligible' | 'low'
      'Low'        | 'low'
      'Medium'     | 'medium'
      'High'       | 'high'
      'Critical'   | 'critical'
      'Defcon1'    | 'critical'
    end

    with_them do
      it 'translates the severity into our categorization' do
        data_with_severity = data_with_all_keys.deep_dup.merge('severity' => report_severity_category)

        formatted_vulnerability = described_class.new(data_with_severity)

        expect(formatted_vulnerability.severity).to eq(gitlab_severity_category)
      end
    end

    context 'when the given severity is not valid' do
      it 'throws a parser error' do
        data_with_invalid_severity = vulnerability.deep_dup.merge(
          'severity' => 'cats, curses, and <coffee>'
        )

        formatted_vulnerability = described_class.new(data_with_invalid_severity)

        expect { formatted_vulnerability.severity }.to raise_error(
          ::Gitlab::Ci::Parsers::Security::Common::SecurityReportParserError,
          'Unknown severity in container scanning report: cats, curses, and &lt;coffee&gt;'
        )
      end
    end
  end

  describe '#solution' do
    it 'creates a solution from the featurename, featureversion, and fixedby' do
      expect(subject.solution).to eq('Upgrade hexes from 6.6.6 to 6.6.7')
    end

    context 'when there is no featurename' do
      it 'formats the solution using fixedby' do
        data_without_featurename = data_with_all_keys.deep_dup.merge('featurename' => '')

        formatted_vulnerability = described_class.new(data_without_featurename)

        expect(formatted_vulnerability.solution).to eq('Upgrade to 6.6.7')
      end
    end

    context 'when there is no featureversion' do
      it 'formats a solution using featurename' do
        data_without_featureversion = data_with_all_keys.deep_dup.merge('featureversion' => '')

        formatted_vulnerability = described_class.new(data_without_featureversion)

        expect(formatted_vulnerability.solution).to eq('Upgrade hexes to 6.6.7')
      end
    end

    context 'when there is no fixedby' do
      it 'does not include a solution' do
        data_without_fixedby = vulnerability.deep_dup.merge('fixedby' => '')

        formatted_vulnerability = described_class.new(data_without_fixedby)

        expect(formatted_vulnerability.solution).to be_nil
      end
    end
  end

  describe '#cve' do
    it 'reads the CVE from the vulnerability' do
      expect(subject.cve).to eq('Level 9000 Soul Breach')
    end
  end

  describe '#operating_system' do
    it 'reads the operating system from the namespace' do
      expect(subject.operating_system).to eq('malevolences')
    end
  end

  describe '#package_name' do
    it 'reads the package name from the featurename' do
      expect(subject.package_name).to eq('hexes')
    end
  end

  describe '#version' do
    it 'reads the version from featureversion' do
      expect(subject.version).to eq('6.6.6')
    end
  end

  describe '#url' do
    it 'reads the url from the link in the report' do
      expect(subject.url).to eq('https://theintercept.com')
    end
  end
end
