<commit_before>require 'rails_helper'
include ActionDispatch::TestProcess

RSpec.describe EffortEventChanger do
  let(:effort) { create(:effort, event: old_event) }
  let(:old_event) { create(:event, course: old_course, start_time: '2017-07-01 06:00:00') }
  let(:old_course) { create(:course_with_standard_splits, splits_count: 3) }

  describe '#initialization' do
    let(:effort) { build_stubbed(:effort) }
    let(:event) { build_stubbed(:event) }

    it 'initializes when provided with an effort and a new event_id' do
      expect { EffortEventChanger.new(effort: effort, event: event) }
          .not_to raise_error
    end

    it 'raises an error if no effort is provided' do
      expect { EffortEventChanger.new(effort: nil, event: event) }
          .to raise_error(/must include effort/)
    end

    it 'raises an error if no model is provided' do
      expect { EffortEventChanger.new(effort: effort, event: nil) }
          .to raise_error(/must include event/)
    end
  end

  describe '#assign_event' do
    context 'when the new event has the same splits as the old' do
      let(:new_event) { create(:event, course: old_course, start_time: '2017-07-01 08:00:00') }

      before do
        old_event.splits << old_course.splits
        new_event.splits << old_course.splits
        create_split_times_for_effort
      end

      it 'updates the effort event_id to the id of the provided event' do
        expect(effort.event_id).not_to eq(new_event.id)
        changer = EffortEventChanger.new(effort: effort, event: new_event)
        changer.assign_event
        expect(effort.event_id).to eq(new_event.id)
      end

      it 'does not change the split_id of any effort split_times' do
        split_times = effort.split_times
        expect(split_times.size).to eq(4)
        changer = EffortEventChanger.new(effort: effort, event: new_event)
        changer.assign_event
        expect(split_times.none?(&:changed?)).to be_truthy
      end

      it 'updates the effort start offset such that the absolute effort start_time does not change' do
        existing_start_time = effort.start_time
        puts existing_start_time
        changer = EffortEventChanger.new(effort: effort, event: new_event)
        changer.assign_event
        reloaded_effort = Effort.find(effort.id)
        expect(reloaded_effort.start_time).to eq(existing_start_time)
      end
    end

    context 'when the new event has different splits from the old' do
      let(:new_event) { create(:event, course: new_course) }
      let(:new_course) { create(:course_with_standard_splits, splits_count: 4) }

      before do
        FactoryGirl.reload
        normalize_distances(old_course.splits)
        normalize_distances(new_course.splits)
        old_event.splits << old_course.splits
        new_event.splits << new_course.splits
        create_split_times_for_effort
      end

      it 'updates the effort event_id to the id of the provided event' do
        expect(effort.event_id).not_to eq(new_event.id)
        changer = EffortEventChanger.new(effort: effort, event: new_event)
        changer.assign_event
        expect(effort.event_id).to eq(new_event.id)
      end

      it 'changes the split_ids of effort split_times to the corresponding split_ids of the new event' do
        time_points = new_event.required_time_points.first(effort.split_times.size)
        expect(effort.split_times.map(&:time_point)).not_to eq(time_points)
        changer = EffortEventChanger.new(effort: effort, event: new_event)
        changer.assign_event
        effort.reload
        expect(effort.split_times.map(&:time_point)).to eq(time_points)
      end

      it 'raises an error if distances do not coincide' do
        split = new_event.splits.find_by(distance_from_start: 10000)
        split.update(distance_from_start: 9999)
        expect { EffortEventChanger.new(effort: effort, event: new_event) }
            .to raise_error(/distances do not coincide/)
      end

      it 'raises an error if sub_splits do not coincide' do
        split = new_event.splits.find_by(distance_from_start: 10000)
        split.update(sub_split_bitmap: 1)
        expect { EffortEventChanger.new(effort: effort, event: new_event) }
            .to raise_error(/sub splits do not coincide/)
      end

      it 'raises an error if laps are out of range' do
        split_time = effort.split_times.last
        split_time.update(lap: 2)
        expect { EffortEventChanger.new(effort: effort, event: new_event) }
            .to raise_error(/laps exceed maximum required/)
      end
    end

    def normalize_distances(splits)
      splits.each_with_index { |split, i| split.update(distance_from_start: i * 10000) }
    end

    def create_split_times_for_effort
      time_points = old_event.required_time_points
      time_points.each_with_index do |time_point, i|
        create(:split_time, time_point: time_point, effort: effort, time_from_start: i * 1000)
      end<commit_msg>Fix intermittently failing test in EffortEventChanger.<commit_after>require 'rails_helper'
include ActionDispatch::TestProcess

RSpec.describe EffortEventChanger do
  let(:effort) { create(:effort, event: old_event) }
  let(:old_event) { create(:event, course: old_course, start_time: '2017-07-01 06:00:00') }
  let(:old_course) { create(:course_with_standard_splits, splits_count: 3) }

  describe '#initialization' do
    let(:effort) { build_stubbed(:effort) }
    let(:event) { build_stubbed(:event) }

    it 'initializes when provided with an effort and a new event_id' do
      expect { EffortEventChanger.new(effort: effort, event: event) }
          .not_to raise_error
    end

    it 'raises an error if no effort is provided' do
      expect { EffortEventChanger.new(effort: nil, event: event) }
          .to raise_error(/must include effort/)
    end

    it 'raises an error if no model is provided' do
      expect { EffortEventChanger.new(effort: effort, event: nil) }
          .to raise_error(/must include event/)
    end
  end

  describe '#assign_event' do
    context 'when the new event has the same splits as the old' do
      let(:new_event) { create(:event, course: old_course, start_time: '2017-07-01 08:00:00') }

      before do
        old_event.splits << old_course.splits
        new_event.splits << old_course.splits
        create_split_times_for_effort
      end

      it 'updates the effort event_id to the id of the provided event' do
        expect(effort.event_id).not_to eq(new_event.id)
        changer = EffortEventChanger.new(effort: effort, event: new_event)
        changer.assign_event
        expect(effort.event_id).to eq(new_event.id)
      end

      it 'does not change the split_id of any effort split_times' do
        split_times = effort.split_times
        expect(split_times.size).to eq(4)
        changer = EffortEventChanger.new(effort: effort, event: new_event)
        changer.assign_event
        expect(split_times.none?(&:changed?)).to be_truthy
      end

      it 'updates the effort start offset such that the absolute effort start_time does not change' do
        existing_start_time = effort.start_time
        puts existing_start_time
        changer = EffortEventChanger.new(effort: effort, event: new_event)
        changer.assign_event
        reloaded_effort = Effort.find(effort.id)
        expect(reloaded_effort.start_time).to eq(existing_start_time)
      end
    end

    context 'when the new event has different splits from the old' do
      let(:new_event) { create(:event, course: new_course) }
      let(:new_course) { create(:course_with_standard_splits, splits_count: 4) }

      before do
        FactoryGirl.reload
        normalize_distances(old_course.splits)
        normalize_distances(new_course.splits)
        old_event.splits << old_course.splits
        new_event.splits << new_course.splits
        create_split_times_for_effort
      end

      it 'updates the effort event_id to the id of the provided event' do
        expect(effort.event_id).not_to eq(new_event.id)
        changer = EffortEventChanger.new(effort: effort, event: new_event)
        changer.assign_event
        expect(effort.event_id).to eq(new_event.id)
      end

      it 'changes the split_ids of effort split_times to the corresponding split_ids of the new event' do
        time_points = new_event.required_time_points.first(effort.split_times.size)
        expect(effort.split_times.map(&:time_point)).not_to eq(time_points)
        changer = EffortEventChanger.new(effort: effort, event: new_event)
        changer.assign_event
        effort.reload
        expect(effort.split_times.map(&:time_point)).to eq(time_points)
      end

      it 'raises an error if distances do not coincide' do
        split = new_event.splits.find_by(distance_from_start: 10000)
        split.update(distance_from_start: 9999)
        expect { EffortEventChanger.new(effort: effort, event: new_event) }
            .to raise_error(/distances do not coincide/)
      end

      it 'raises an error if sub_splits do not coincide' do
        split = new_event.splits.find_by(distance_from_start: 10000)
        split.update(sub_split_bitmap: 1)
        expect { EffortEventChanger.new(effort: effort, event: new_event) }
            .to raise_error(/sub splits do not coincide/)
      end

      it 'raises an error if laps are out of range' do
        split_time = effort.ordered_split_times.last
        split_time.update(lap: 2)
        expect { EffortEventChanger.new(effort: effort, event: new_event) }
            .to raise_error(/laps exceed maximum required/)
      end
    end

    def normalize_distances(splits)
      splits.each_with_index { |split, i| split.update(distance_from_start: i * 10000) }
    end

    def create_split_times_for_effort
      time_points = old_event.required_time_points
      time_points.each_with_index do |time_point, i|
        create(:split_time, time_point: time_point, effort: effort, time_from_start: i * 1000)
      end
{'fraction_non_alphanumeric': 0.08289171082891711, 'fraction_numerical': 0.011198880111988802, 'mean_word_length': 3.0774561761108847, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '812996', 'n_tokens_mistral': 3242, 'n_tokens_neox': 3098, 'n_words': 788}