# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ReleaseTools::ParallelMethods do
  include described_class

  let(:numbers) { (1..10).to_a }

  shared_examples 'parameter in_threads' do |parallel_method, iterator|
    it 'creates twice amount of threads as processors' do
      allow(Parallel).to receive(iterator)

      public_send(parallel_method, numbers, &:itself)

      expect(Parallel).to have_received(iterator)
        .with(numbers, in_threads: described_class::DEFAULT_THREAD_COUNT)
    end

    it 'uses passed in_threads parameter' do
      allow(Parallel).to receive(iterator)

      public_send(parallel_method, numbers, in_threads: 3, &:itself)

      expect(Parallel).to have_received(iterator)
        .with(numbers, in_threads: 3)
    end

    it 'uses PARALLEL_PROCESSOR_COUNT envvar if set' do
      stub_const('ENV', { 'PARALLEL_PROCESSOR_COUNT' => '3' })
      allow(Parallel).to receive(iterator)

      public_send(parallel_method, numbers, &:itself)

      expect(Parallel).to have_received(iterator)
        .with(numbers, in_threads: 3)
    end

    it 'fails if PARALLEL_PROCESSOR_COUNT is not numeric' do
      stub_const('ENV', { 'PARALLEL_PROCESSOR_COUNT' => 'STRING' })

      expect { public_send(parallel_method, numbers, &:itself) }
        .to raise_error(ArgumentError, /invalid value for Integer\(\): "STRING"/)
    end
  end

  describe '#parallel_each' do
    it 'iterates in parallel' do
      actual = []

      parallel_each(numbers) do |element|
        actual << element
      end

      expect(actual.sort).to eq(numbers)
    end

    it_behaves_like 'parameter in_threads', :parallel_each, :each
  end

  describe '#parallel_map' do
    it 'maps in parallel' do
      actual = parallel_map(numbers, &:itself)

      expect(actual).to eq(numbers)
    end

    it_behaves_like 'parameter in_threads', :parallel_map, :map
  end
end
