scottwillson/racing_on_rails

View on GitHub
test/models/categories/best_match_in_test.rb

Summary

Maintainability
B
5 hrs
Test Coverage
# frozen_string_literal: true

require "test_helper"

module Competitions
  # :stopdoc:
  class BestMatchInTest < ActiveSupport::TestCase
    setup do
      @senior_men = Category.find_or_create_by_normalized_name("Senior Men")
      @cat_1 = Category.find_or_create_by_normalized_name("Category 1")
      @cat_1_2 = Category.find_or_create_by_normalized_name("Category 1/2")
      @cat_1_2_3 = Category.find_or_create_by_normalized_name("Category 1/2/3")
      @pro_1_2 = Category.find_or_create_by_normalized_name("Pro 1/2")
      @cat_2 = Category.find_or_create_by_normalized_name("Category 2")
      @cat_3 = Category.find_or_create_by_normalized_name("Category 3")
      @cat_3_4 = Category.find_or_create_by_normalized_name("Category 3/4")
      @cat_4 = Category.find_or_create_by_normalized_name("Category 4")
      @cat_4_women = Category.find_or_create_by_normalized_name("Category 4 Women")
      @cat_4_5_women = Category.find_or_create_by_normalized_name("Category 4/5 Women")
      @elite_men = Category.find_or_create_by_normalized_name("Elite Men")
      @pro_elite_men = Category.find_or_create_by_normalized_name("Pro Elite Men")
      @pro_cat_1 = Category.find_or_create_by_normalized_name("Pro/Category 1")
      @masters_men = Category.find_or_create_by_normalized_name("Masters Men")
      @masters_novice = Category.find_or_create_by_normalized_name("Masters Novice")
      @masters_men_4_5 = Category.find_or_create_by_normalized_name("Masters Men 4/5")
      @senior_women = Category.find_or_create_by_normalized_name("Senior Women")
      @junior_men = Category.find_or_create_by_normalized_name("Junior Men")
      @junior_women = Category.find_or_create_by_normalized_name("Junior Women")
      @junior_men_10_14 = Category.find_or_create_by_normalized_name("Junior Men 10-14")
      @junior_men_15_plus = Category.find_or_create_by_normalized_name("Junior 15+")
      @junior_men_3_4_5 = Category.find_or_create_by_normalized_name("Junior Men 3/4/5")
      @singlespeed = Category.find_or_create_by_normalized_name("Singlespeed/Fixed")
      @singlespeed_men = Category.find_or_create_by_normalized_name("Singlespeed Men")
      @singlespeed_women = Category.find_or_create_by_normalized_name("Singlespeed Women")
    end

    test "Cross Crusade juniors" do
      event = FactoryBot.create(:event)
      event.races.create!(category: @junior_men_3_4_5)
      junior_men_9_12 = Category.find_or_create_by_normalized_name("Junior Men 9-12")
      event.races.create!(category: junior_men_9_12)
      junior_men_13_14 = Category.find_or_create_by_normalized_name("Junior Men 13-14")
      event.races.create!(category: junior_men_13_14)
      elite_junior_men = Category.find_or_create_by_normalized_name("Elite Junior Men")
      event.races.create!(category: elite_junior_men)
      u10_junior = Category.find_or_create_by_normalized_name("Junior U10")

      assert_best_match_in [u10_junior, junior_men_9_12], junior_men_9_12, event, 10
    end

    test "OJCS 2021" do
      event = FactoryBot.create(:event)
      junior_open_123 = Category.find_or_create_by_normalized_name("Junior Open 1/2/3")
      event.races.create!(category: junior_open_123)
      junior_open_345_9_12 = Category.find_or_create_by_normalized_name("Junior Open 3/4/5 9-12")
      event.races.create!(category: junior_open_345_9_12)

      junior_open_345_11_12 = Category.find_or_create_by_normalized_name("Junior Open 3/4/5 11-12")

      assert_best_match_in [junior_open_345_9_12, junior_open_345_11_12], junior_open_345_9_12, event
      assert_best_match_in [junior_open_345_9_12, junior_open_345_11_12], junior_open_345_9_12, event, 11
    end

    test "ability only" do
      event = FactoryBot.create(:event)
      event.races.create!(category: @cat_1)
      event.races.create!(category: @cat_2)
      event.races.create!(category: @cat_3)
      event.races.create!(category: @cat_4)

      assert_best_match_in [@cat_1, @cat_1_2, @cat_1_2_3], @cat_1, event
      assert_best_match_in [@cat_2], @cat_2, event
      assert_best_match_in [@cat_3, @cat_3_4], @cat_3, event
      assert_best_match_in [@cat_4, @cat_4_women, @cat_4_5_women], @cat_4, event
      assert_best_match_in [@cat_1, @cat_1_2, @cat_1_2_3, @junior_women], @cat_1, event, 15
    end

    test "cyclocross categories" do
      event = FactoryBot.create(:event)
      cat_2_3 = Category.find_or_create_by_normalized_name("Category 2/3")
      cat_5 = Category.find_or_create_by_normalized_name("Category 5")

      event.races.create!(category: @cat_1_2)
      event.races.create!(category: cat_2_3)
      event.races.create!(category: @cat_3_4)
      event.races.create!(category: cat_5)

      assert_best_match_in [@cat_1, @cat_1_2, @cat_1_2_3, @cat_2], @cat_1_2, event
      assert_best_match_in [cat_2_3, @cat_3], cat_2_3, event
      assert_best_match_in [@cat_3_4, @cat_4, @cat_4_women, @cat_4_5_women], @cat_3_4, event
      assert_best_match_in [cat_5], cat_5, event
    end

    test "beginners and Cat 4s" do
      event = FactoryBot.create(:event)
      cat_2_3 = Category.find_or_create_by_normalized_name("Category 2/3 Open")
      cat_4 = Category.find_or_create_by_normalized_name("Category 4 Open")
      beginner_open = Category.find_or_create_by_normalized_name("Beginner Open")

      event.races.create!(category: @cat_1_2)
      event.races.create!(category: cat_2_3)
      event.races.create!(category: cat_4)
      event.races.create!(category: beginner_open)

      assert_best_match_in [@cat_1_2], @cat_1_2, event
      assert_best_match_in [cat_2_3,], cat_2_3, event
      assert_best_match_in [cat_4], cat_4, event
      assert_best_match_in [beginner_open], beginner_open, event
    end

    test "ability + gender" do
      event = FactoryBot.create(:event)
      event.races.create!(category: @cat_1)
      event.races.create!(category: @cat_2)
      event.races.create!(category: @cat_3)
      event.races.create!(category: @cat_4)
      event.races.create!(category: @cat_4_5_women)

      assert_best_match_in [@cat_1, @cat_1_2, @cat_1_2_3], @cat_1, event
      assert_best_match_in [@cat_2], @cat_2, event
      assert_best_match_in [@cat_4], @cat_4, event
      assert_best_match_in [@cat_4_women, @cat_4_5_women], @cat_4_5_women, event
    end

    test "ages" do
      event = FactoryBot.create(:event)
      event.races.create!(category: @senior_men)
      event.races.create!(category: @senior_women)
      event.races.create!(category: @cat_3)
      event.races.create!(category: @cat_4)
      event.races.create!(category: @cat_4_women)
      event.races.create!(category: @masters_men)
      event.races.create!(category: @masters_men_4_5)
      event.races.create!(category: @junior_men)
      event.races.create!(category: @junior_women)

      assert_best_match_in [@senior_men, @cat_1, @cat_1_2, @cat_1_2_3, @pro_1_2, @cat_2, @pro_cat_1, @elite_men, @pro_elite_men], @senior_men, event
      assert_best_match_in [@senior_women], @senior_women, event
      assert_best_match_in [@cat_3, @cat_3_4], @cat_3, event
      assert_best_match_in [@cat_4], @cat_4, event
      assert_best_match_in [@cat_4_women, @cat_4_5_women], @cat_4_women, event
      assert_best_match_in [@masters_men], @masters_men, event
      assert_best_match_in [@masters_men_4_5, @masters_novice], @masters_men_4_5, event
      assert_best_match_in [@junior_men, @junior_men_10_14, @junior_men_15_plus, @junior_men_3_4_5], @junior_men, event
      assert_best_match_in [@junior_women], @junior_women, event
    end

    test "masters women" do
      event = FactoryBot.create(:event)
      masters_women = Category.find_or_create_by_normalized_name("Masters Women")
      masters_women_4 = Category.find_or_create_by_normalized_name("Masters Women 4")
      masters_women_50_plus = Category.find_or_create_by_normalized_name("Masters Women 50+")
      masters_women_50_59 = Category.find_or_create_by_normalized_name("Masters Women 50-59")
      event.races.create!(category: masters_women)
      event.races.create!(category: masters_women_4)

      assert_best_match_in [masters_women, masters_women_50_plus, masters_women_50_59], masters_women, event
      assert_best_match_in [masters_women_4], masters_women_4, event
    end

    test "multiple 'and older' categories" do
      event = FactoryBot.create(:event)
      masters_men_50_plus = Category.find_or_create_by_normalized_name("Masters Men 50+")
      masters_men_60_plus = Category.find_or_create_by_normalized_name("Masters Men 60+")
      masters_men_70_plus = Category.find_or_create_by_normalized_name("Masters Men 70+")
      event.races.create!(category: masters_men_50_plus)
      event.races.create!(category: masters_men_60_plus)

      assert_best_match_in [masters_men_60_plus, masters_men_70_plus], masters_men_60_plus, event
    end

    test "multiple 'and older' categories for non-age" do
      event = FactoryBot.create(:event)
      masters_men_50_plus = Category.find_or_create_by_normalized_name("Masters Men 50+")
      masters_men_60_plus = Category.find_or_create_by_normalized_name("Masters Men 60+")
      men_5 = Category.find_or_create_by_normalized_name("Men 5")
      event.races.create!(category: masters_men_50_plus)
      event.races.create!(category: masters_men_60_plus)

      assert_best_match_in [masters_men_50_plus], masters_men_50_plus, event, 51
      assert_best_match_in [], men_5, event, 51
    end

    test "age range with 'and over'" do
      event = FactoryBot.create(:event)
      masters_men_50_plus = Category.find_or_create_by_normalized_name("Masters Men 50+")
      masters_men_60_plus = Category.find_or_create_by_normalized_name("Masters Men 60+")
      masters_men_60_69 = Category.find_or_create_by_normalized_name("Masters Men 60-69")
      event.races.create!(category: masters_men_50_plus)
      event.races.create!(category: masters_men_60_plus)

      assert_best_match_in [masters_men_60_plus, masters_men_60_69], masters_men_60_plus, event
    end

    test "ability and overlapping age" do
      event = FactoryBot.create(:event)
      masters_men_30_39 = Category.find_or_create_by_normalized_name("Masters Men 30-39")
      masters_men_35_39 = Category.find_or_create_by_normalized_name("Masters Men 35-39")
      masters_men_3_4_35 = Category.find_or_create_by_normalized_name("Masters 3/4 35+")
      event.races.create!(category: masters_men_30_39)
      event.races.create!(category: masters_men_35_39)

      assert_best_match_in [masters_men_3_4_35, masters_men_35_39], masters_men_35_39, event
    end

    test "equipment" do
      event = FactoryBot.create(:event)
      event.races.create!(category: @singlespeed)
      fixed_gear = Category.find_or_create_by_normalized_name("Fixed Gear")
      fixed_gear_men = Category.find_or_create_by_normalized_name("Fix Gear Men")
      fixed_gear_women = Category.find_or_create_by_normalized_name("Fix Gear Women")
      assert_best_match_in [@singlespeed, @singlespeed_men, @singlespeed_women], @singlespeed, event
      assert_best_match_in [@singlespeed, @singlespeed_men, @singlespeed_women, fixed_gear, fixed_gear_men, fixed_gear_women], @singlespeed, event
    end

    test "equipment + gender" do
      event = FactoryBot.create(:event)
      event.races.create!(category: @singlespeed_men)
      event.races.create!(category: @singlespeed_women)
      singlespeed_40_plus = Category.find_or_create_by_normalized_name("Singlespeed Men 40+")
      singlespeed_women_40_plus = Category.find_or_create_by_normalized_name("Singlespeed Women 40+")

      assert_best_match_in [@singlespeed_men, @singlespeed, singlespeed_40_plus], @singlespeed_men, event
      assert_best_match_in [@singlespeed_women, singlespeed_women_40_plus], @singlespeed_women, event
    end

    test "consider equipment before ability" do
      event = FactoryBot.create(:event)

      fixed_gear = Category.find_or_create_by_normalized_name("Men Fixed Gear Open")
      event.races.create!(category: fixed_gear)

      men_1_2_3 = Category.find_or_create_by_normalized_name("Men 1/2/3")
      event.races.create!(category: men_1_2_3)

      assert_best_match_in [@senior_men, men_1_2_3], men_1_2_3, event
      assert_best_match_in [fixed_gear], fixed_gear, event
    end

    test "athena" do
      athena = ::Category.find_or_create_by_normalized_name("Athena")
      men_9_18 = ::Category.find_or_create_by_normalized_name("Men 9-18")
      women_35_49 = ::Category.find_or_create_by_normalized_name("Women 35-49")

      event = FactoryBot.create(:event)
      event.races.create!(category: men_9_18)
      event.races.create!(category: women_35_49)

      # best_match_by_age_in would match Athena and Women 35-49
      assert_best_match_in [women_35_49], women_35_49, event, 35
      assert_best_match_in [], athena, event, 35
    end

    test "athena 160+" do
      athena = ::Category.find_or_create_by_normalized_name("Athena")
      athena_160 = ::Category.find_or_create_by_normalized_name("Athena 160+")
      men_9_18 = ::Category.find_or_create_by_normalized_name("Men 9-18")

      event = FactoryBot.create(:event)
      event.races.create!(category: men_9_18)
      event.races.create!(category: athena)

      assert_best_match_in [athena, athena_160], athena, event
      assert_best_match_in [athena, athena_160], athena, event, 35
    end

    test "gender over ability" do
      women_1_2_3 = Category.find_or_create_by_normalized_name("Women 1/2/3")

      event = FactoryBot.create(:event)
      event.races.create!(category: @pro_1_2)
      event.races.create!(category: Category.find_or_create_by_normalized_name("Pro/1/2 40+"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Pro/1/2 50+"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 3 Men"))
      event.races.create!(category: women_1_2_3)
      event.races.create!(category: Category.find_or_create_by_normalized_name("Women 4/5"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Masters Men 40-49 (Category 3/4/5)"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Masters Women 40+ (Category 3/4/5)"))
      event.races.create!(category: @junior_men)
      event.races.create!(category: @junior_women)

      women_1_2 = Category.find_or_create_by_normalized_name("Women 1/2")
      assert_best_match_in [women_1_2, women_1_2_3], women_1_2_3, event
    end

    test "mtb bar categories" do
      event = FactoryBot.create(:event)
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 1 Men"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 1 Women"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 2 Men"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 2 Women"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 3 Men"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 3 Women"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 4 Men"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 4 Women"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 5 Men"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 5 Women"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Clydesdale"))
      elite_men = Category.find_or_create_by_normalized_name("Elite Men")
      event.races.create!(category: elite_men)
      event.races.create!(category: Category.find_or_create_by_normalized_name("Elite Women"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Junior Men"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Junior Women"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Masters Men"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Masters Women"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Singlespeed/Fixed"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Tandem"))
      men_19_29 = Category.find_or_create_by_normalized_name("19-29 Men")

      assert_best_match_in [elite_men, men_19_29], elite_men, event
    end

    test "bar categories" do
      junior_women_10_12 = Category.find_or_create_by_normalized_name("Junior Women 10-12")
      men_15_24 = Category.find_or_create_by_normalized_name("Men 15-24")
      men_19_29 = Category.find_or_create_by_normalized_name("19-29 Men")
      men_19_39 = Category.find_or_create_by_normalized_name("Amateur 19-39 Men")
      pro_1_2_men = Category.find_or_create_by_normalized_name("Pro/1/2 Men")
      pro_1_2_women = Category.find_or_create_by_normalized_name("Pro/1/2 Women")
      eddy_men = Category.find_or_create_by_normalized_name("Eddy Men")
      eddy_senior_men = Category.find_or_create_by_normalized_name("Eddy Senior Men")
      eddy_women = Category.find_or_create_by_normalized_name("Eddy Women")
      eddy_senior_women = Category.find_or_create_by_normalized_name("Eddy Senior Women")
      singlespeed_40_plus = Category.find_or_create_by_normalized_name("Singlespeed Men 40+")
      singlespeed_women_40_plus = Category.find_or_create_by_normalized_name("Singlespeed Women 40+")

      event = FactoryBot.create(:event)
      event.races.create!(category: Category.find_or_create_by_normalized_name("Athena"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Clydesdale"))
      event.races.create!(category: @cat_3)
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 3 Women"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 4 Men"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 4 Women"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 5 Men"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Category 5 Women"))
      event.races.create!(category: @junior_men)
      event.races.create!(category: @junior_women)
      event.races.create!(category: Category.find_or_create_by_normalized_name("Masters Men"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Masters Men 4/5"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Masters Women"))
      event.races.create!(category: Category.find_or_create_by_normalized_name("Masters Women 4"))
      event.races.create!(category: pro_1_2_men)
      event.races.create!(category: pro_1_2_women)
      event.races.create!(category: @singlespeed)
      event.races.create!(category: Category.find_or_create_by_normalized_name("Tandem"))

      assert_best_match_in [pro_1_2_men, men_15_24, men_19_29], pro_1_2_men, event
      assert_best_match_in [@cat_3, men_19_39], @cat_3, event
      assert_best_match_in [@junior_women, junior_women_10_12], @junior_women, event
      assert_best_match_in [eddy_men, eddy_senior_men, pro_1_2_men], pro_1_2_men, event
      assert_best_match_in [eddy_women, eddy_senior_women, pro_1_2_women], pro_1_2_women, event
      assert_best_match_in [@singlespeed, singlespeed_40_plus, singlespeed_women_40_plus], @singlespeed, event
    end

    def assert_best_match_in(categories, race_category, event, result_age = nil)
      categories.each do |category|
        best_match = category.best_match_in(event.categories, result_age)
        assert race_category == best_match,
               "#{race_category&.name} should be best_match_in for #{category.name} in event with " \
               "categories #{event.races.map(&:name).join(', ')} but was #{best_match&.name}"
      end

      event.categories
           .reject { |category| category.in?(categories) }
           .each do |category|
             best_match = category.best_match_in(event.categories)
             assert race_category != best_match,
                    "Did not expect #{race_category&.name} to match #{category.name} in event with " \
                    "categories #{event.races.map(&:name).join(', ')}, but was #{best_match.name}"
           end
    end
  end
end