# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Gitlab::Vulnerabilities::StandardVulnerability do
  let(:title) { 'Predictable pseudorandom number generator' }
  let(:name) { 'Predictable pseudorandom number generator (from name)' }
  let(:description) { 'Description of Predictable pseudorandom number generator' }
  let(:solution) { 'Please do something!' }
  let(:file) { 'subdir/src/main/java/com/gitlab/security_products/tests/App.java' }
  let(:line) { 15 }
  let(:blob_path) { "bar/foo/-/blob/sha/#{file}#L#{line}" }
  let(:location) do
    { file: file, start_line: line, blob_path: "/#{blob_path}" }
  end

  it 'inherits from Gitlab::Vulnerabilities::BaseVulnerability' do
    vulnerability = described_class.new(foo: 'bar')

    expect(vulnerability).to be_kind_of(Gitlab::Vulnerabilities::BaseVulnerability)
  end

  describe '#title' do
    context 'when title is present' do
      it 'returns title' do
        vulnerability = described_class.new(title: title)

        expect(vulnerability.title).to eq title
      end
    end

    context 'when title is not set' do
      it 'fallbacks to name' do
        vulnerability = described_class.new(name: name)

        expect(vulnerability.title).to eq name
      end
    end

    context 'when title and name are not set' do
      it 'returns nil' do
        vulnerability = described_class.new(foo: 'bar')

        expect(vulnerability.title).to be_nil
      end
    end
  end

  describe '#description' do
    context 'when description is present' do
      it 'returns description' do
        vulnerability = described_class.new(title: title, description: description)

        expect(vulnerability.description).to eq description
      end
    end

    context 'when description is not set' do
      it 'fallbacks to title' do
        vulnerability = described_class.new(title: title, name: name)

        expect(vulnerability.description).to eq title
      end
    end

    context 'when description and title are not set' do
      it 'fallbacks to name' do
        vulnerability = described_class.new(name: name)

        expect(vulnerability.description).to eq name
      end
    end

    context 'when title, name and description are not set' do
      it 'returns nil' do
        vulnerability = described_class.new(foo: 'bar')

        expect(vulnerability.description).to be_nil
      end
    end
  end

  describe '#file' do
    context 'when file is present' do
      it 'returns file' do
        vulnerability = described_class.new(file: file, location: location)

        expect(vulnerability.file).to eq file
      end
    end

    context 'when file is not set' do
      it 'fallbacks to location' do
        vulnerability = described_class.new(location: location)

        expect(vulnerability.file).to eq location[:file]
      end
    end

    context 'when file and location are not set' do
      it 'returns nil' do
        vulnerability = described_class.new(foo: 'bar')

        expect(vulnerability.file).to be_nil
      end
    end
  end

  describe '#line' do
    context 'when line is present' do
      it 'returns line' do
        vulnerability = described_class.new(line: line, location: location)

        expect(vulnerability.line).to eq line
      end
    end

    context 'when line is not set' do
      it 'fallbacks to location' do
        vulnerability = described_class.new(location: location)

        expect(vulnerability.line).to eq location[:start_line]
      end
    end

    context 'when line and location are not set' do
      it 'returns nil' do
        vulnerability = described_class.new(foo: 'bar')

        expect(vulnerability.line).to be_nil
      end
    end
  end

  describe '#location_text' do
    context 'when line is nil' do
      it 'returns a string with file' do
        vulnerability = described_class.new(file: file)

        expect(vulnerability.location_text).to eq file
      end
    end

    context 'when line is present' do
      it 'returns a string with file and line' do
        vulnerability = described_class.new(file: file, line: line)

        expect(vulnerability.location_text).to eq "#{file}:#{line}"
      end
    end
  end

  describe '#location_link' do
    context 'when blob_path is nil' do
      it 'returns file path' do
        vulnerability = described_class.new(file: "/foo/bar/-/blob/sha/#{file}")

        expect(vulnerability.location_link).to eq "/foo/bar/-/blob/sha/#{file}"
      end
    end

    context 'when line is present' do
      it 'returns a string with file and line' do
        vulnerability = described_class.new(blob_path: "/foo/bar/-/blob/sha/#{file}#L#{line}")

        expect(vulnerability.location_link).to eq "http://localhost/foo/bar/-/blob/sha/#{file}#L#{line}"
      end
    end
  end

  describe '#blob_path' do
    context 'when blob_path is in top level data' do
      let(:blob_path) { "foo/bar/-/blob/sha/#{file}#L#{line}" }

      it 'returns blob_path from top level' do
        vulnerability = described_class.new(blob_path: "/#{blob_path}", location: location)

        expect(vulnerability.blob_path).to eq blob_path
      end
    end

    context 'when blob_path is not in top level data but is in location data' do
      it 'returns blob_path from location data' do
        vulnerability = described_class.new(location: location)

        expect(vulnerability.blob_path).to eq blob_path
      end
    end

    context 'when blob_path is not present' do
      it 'returns nil' do
        vulnerability = described_class.new(blob_path: nil)

        expect(vulnerability.blob_path).to be_nil
      end
    end
  end
end
