# frozen_string_literal: true

require 'spec_helper'

RSpec.describe GitlabSchema.types['Vulnerability'] do
  let_it_be(:project) { create(:project) }
  let_it_be(:user) { create(:user) }
  let_it_be(:vulnerability) { create(:vulnerability, project: project) }
  let_it_be(:fields) do
    %i[userPermissions
       id
       title
       description
       user_notes_count
       state
       severity
       report_type
       resolved_on_default_branch
       vulnerability_path
       location
       scanner
       primary_identifier
       identifiers
       project
       issueLinks
       detected_at
       confirmed_at
       resolved_at
       dismissed_at
       notes
       external_issue_links
       has_solutions
       merge_request
       discussions
       confirmed_by
       resolved_by
       dismissed_by
       details]
  end

  before do
    stub_licensed_features(security_dashboard: true)

    project.add_developer(user)
  end

  subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }

  it { expect(described_class).to have_graphql_fields(fields) }
  it { expect(described_class).to require_graphql_authorizations(:read_security_resource) }

  describe 'vulnerability_path' do
    let(:query) do
      %(
        query {
          project(fullPath: "#{project.full_path}") {
            name
            vulnerabilities {
              nodes {
                vulnerabilityPath
              }
            }
          }
        }
      )
    end

    it "is the path to the vulnerability's detail page" do
      vulnerabilities = subject.dig('data', 'project', 'vulnerabilities', 'nodes')

      expect(vulnerabilities.first['vulnerabilityPath']).to eq(
        ::Gitlab::Routing.url_helpers.project_security_vulnerability_path(project, vulnerability)
      )
    end
  end

  describe 'has_solutions' do
    let(:query) do
      %(
        query {
          project(fullPath: "#{project.full_path}") {
            name
            vulnerabilities {
              nodes {
                hasSolutions
              }
            }
          }
        }
      )
    end

    context 'N+1 queries' do
      it 'avoids N+1 database queries' do
        pending('See: https://gitlab.com/gitlab-org/gitlab/-/issues/292993')
        control_count = ActiveRecord::QueryRecorder.new { GitlabSchema.execute(query, context: { current_user: user }) }.count

        create(:vulnerability, :with_remediation, project: project)
        create(:vulnerability, :with_remediation, project: project)

        expect { GitlabSchema.execute(query, context: { current_user: user }) }.not_to exceed_query_limit(control_count)

        result = GitlabSchema.execute(query, context: { current_user: user }).to_h
        vulnerability = result.dig('data', 'project', 'vulnerabilities', 'nodes').first
        expect(vulnerability['hasSolution']).to be_truthy
      end
    end
  end

  describe '#description' do
    let_it_be(:vulnerability_with_finding) { create(:vulnerability, :with_findings, project: project) }

    let(:query) do
      %(
        query {
          project(fullPath: "#{project.full_path}") {
            name
            vulnerabilities {
              nodes {
                description
              }
            }
          }
        }
      )
    end

    context 'when the vulnerability description field is populated' do
      it 'returns the description for the vulnerability' do
        vulnerabilities = subject.dig('data', 'project', 'vulnerabilities', 'nodes')

        expect(vulnerabilities.first['description']).to eq(vulnerability_with_finding.description)
      end
    end

    context 'when the vulnerability description field is empty' do
      before do
        vulnerability_with_finding.description = nil
        vulnerability_with_finding.save!
      end

      it 'returns the description for the vulnerability finding' do
        vulnerabilities = subject.dig('data', 'project', 'vulnerabilities', 'nodes')

        expect(vulnerabilities.first['description']).to eq(vulnerability_with_finding.finding.description)
      end
    end
  end
end
