# frozen_string_literal: true

# All Theme Dynamic Finders returning a Version are tested here.
# When adding one to the spec/fixtures/db/dynamic_finder.yml, a few files have
# to be edited/created
#
# - spec/fixtures/dynamic_finder/expected.yml with the expected result/s
# - Then, depending on the finder class used: spec/fixtures/dynamic_finder/theme_version/
#
# Furthermore, the fixtures files _passive_all.html are also used by plugins/themes
# finders in spec/app/finders/plugins|themes to check the items existence from the homepage
#
# In case of a failure, it's recommended to use rspec -e "<Full Description>" while fixing.
# e.g: rspec -e "WPScan::Finders::ThemeVersion::Cardealerpress::HeaderPattern#passive"
# The -e option can also be used to test all HeaderPattern, for example: rspec -e "::HeaderPattern"

expected_all = df_expected_all['themes']

WPScan::DB::DynamicFinders::Theme.versions_finders_configs.each do |slug, configs|
  WPScan::DB::DynamicFinders::Theme.create_versions_finders(slug)

  configs.each do |finder_class, config|
    finder_super_class = config['class'] || finder_class

    # The QueryParameter specs are slow given the huge fixture file
    # If someone find a fix for that, please share!
    describe df_tested_class_constant('ThemeVersion', finder_class, slug), slow: true do
      subject(:finder) { described_class.new(theme) }
      let(:theme)      { WPScan::Model::Theme.new(slug, target) }
      let(:target)     { WPScan::Target.new('http://wp.lab/') }
      let(:fixtures)   { DYNAMIC_FINDERS_FIXTURES.join('theme_version') }

      let(:expected) do
        if expected_all[slug][finder_class].is_a?(Hash)
          [expected_all[slug][finder_class]]
        else
          expected_all[slug][finder_class]
        end
      end

      let(:stubbed_response) { { body: 'aa' } }

      before do
        allow(target).to receive(:content_dir).and_return('wp-content')

        # When creating a theme, the style.css is checked, let's stub that
        stub_request(:get, target.url("wp-content/themes/#{slug}/style.css"))
      end

      describe '#passive', slow: true do
        before { stub_request(:get, target.url).to_return(stubbed_response) }

        if config['path']
          context 'when PATH' do
            it 'returns nil' do
              expect(finder.passive).to eql nil
            end
          end
        else
          context 'when no PATH' do
            context 'when the version is detected' do
              let(:stubbed_response) do
                df_stubbed_response(
                  fixtures.join("#{finder_super_class.underscore}_passive_all.html"),
                  finder_super_class
                )
              end

              it 'returns the expected version/s from the homepage' do
                found = [*finder.passive]

                expect(found).to_not be_empty

                found.each_with_index do |version, index|
                  expected_version = expected.at(index)

                  expect(version).to be_a WPScan::Model::Version
                  expect(version.number).to eql expected_version['number'].to_s
                  expect(version.found_by).to eql expected_version['found_by']
                  expect(version.interesting_entries).to match_array expected_version['interesting_entries']

                  expect(version.confidence).to eql expected_version['confidence'] if expected_version['confidence']
                end
              end
            end

            context 'when the version is not detected' do
              it 'returns nil or an empty array' do
                expect(finder.passive).to eql finder_super_class == 'QueryParameter' ? [] : nil
              end
            end
          end
        end
      end

      describe '#aggressive' do
        let(:fixtures) { super().join(slug, finder_class.underscore) }

        before do
          stub_request(:get, theme.url(config['path'])).to_return(stubbed_response) if config['path']
        end

        if config['path']
          context 'when the version is detected' do
            let(:stubbed_response) do
              df_stubbed_response(fixtures.join(config['path']), finder_super_class)
            end

            it 'returns the expected version' do
              found = [*finder.aggressive]

              expect(found).to_not be_empty

              found.each_with_index do |version, index|
                expected_version = expected.at(index)

                expect(version).to be_a WPScan::Model::Version
                expect(version.number).to eql expected_version['number'].to_s
                expect(version.found_by).to eql expected_version['found_by']
                expect(version.interesting_entries).to match_array expected_version['interesting_entries']

                expect(version.confidence).to eql expected_version['confidence'] if expected_version['confidence']
              end
            end
          end

          context 'when the version is not detected' do
            it 'returns nil or an empty array' do
              expect(finder.aggressive).to eql finder_super_class == 'QueryParameter' ? [] : nil
            end
          end
        else
          it 'returns nil' do
            expect(finder.aggressive).to eql nil
          end
        end
      end
    end
  end
end
