From 4b9f36f44e35dd5357c09c55c6c75786052263af Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 24 Apr 2019 11:58:54 +0200 Subject: [PATCH 01/31] Corrects Badges Add Travis back in Add very important hound badge to our Readme file Fix Coverage pointing to branch ticket/TUNRIERE-155 instead of master --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2fa0341..d8f90bc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# turniere-backend [![pipeline status](https://gitlab.com/turniere/turniere-backend/badges/master/pipeline.svg)](https://gitlab.com/turniere/turniere-backend/commits/master) [![Coverage Status](https://coveralls.io/repos/gitlab/turniere/turniere-backend/badge.svg?branch=ticket%2FTURNIERE-155)](https://coveralls.io/gitlab/turniere/turniere-backend?branch=ticket%2FTURNIERE-155) +# turniere-backend [![Build Status](https://travis-ci.org/turniere/turniere-backend.svg?branch=master)](https://travis-ci.org/turniere/turniere-backend) [![pipeline status](https://gitlab.com/turniere/turniere-backend/badges/master/pipeline.svg)](https://gitlab.com/turniere/turniere-backend/commits/master) [![Coverage Status](https://coveralls.io/repos/gitlab/turniere/turniere-backend/badge.svg?branch=master)](https://coveralls.io/gitlab/turniere/turniere-backend?branch=master) [![](https://img.shields.io/badge/Protected_by-Hound-a873d1.svg)](https://houndci.com) Ruby on Rails application serving as backend for turnie.re # Installation From 26b8ff96c9bdc7ead894afc77f664724ce51a403 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 24 Apr 2019 12:00:17 +0200 Subject: [PATCH 02/31] Add teams method to group,match,stage It returns the unique teams that compete within the object --- app/models/group.rb | 4 ++++ app/models/match.rb | 4 ++++ app/models/stage.rb | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/app/models/group.rb b/app/models/group.rb index 39cba55..1b99378 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -4,4 +4,8 @@ class Group < ApplicationRecord belongs_to :stage has_many :matches, dependent: :destroy has_many :group_scores, dependent: :destroy + + def teams + matches.map(&:teams).flatten.uniq + end end diff --git a/app/models/match.rb b/app/models/match.rb index 0eb0c14..6c3eee8 100644 --- a/app/models/match.rb +++ b/app/models/match.rb @@ -11,6 +11,10 @@ class Match < ApplicationRecord validate :stage_xor_group + def teams + match_scores.map(&:team).flatten.uniq + end + private def stage_xor_group diff --git a/app/models/stage.rb b/app/models/stage.rb index b43d80c..64b788e 100644 --- a/app/models/stage.rb +++ b/app/models/stage.rb @@ -4,4 +4,8 @@ class Stage < ApplicationRecord belongs_to :tournament has_many :matches, dependent: :destroy has_many :groups, dependent: :destroy + + def teams + groups.map(&:teams).flatten.uniq + end end From 548d9241c433b4d79754533d892cf66d78257d49 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 24 Apr 2019 12:09:56 +0200 Subject: [PATCH 03/31] Add Interactor to add group stage to a tournament --- .../add_group_stage_to_tournament.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 app/interactors/add_group_stage_to_tournament.rb diff --git a/app/interactors/add_group_stage_to_tournament.rb b/app/interactors/add_group_stage_to_tournament.rb new file mode 100644 index 0000000..d8071f2 --- /dev/null +++ b/app/interactors/add_group_stage_to_tournament.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddGroupStageToTournament + include Interactor + + def call + tournament = context.tournament + groups = context.groups + context.fail! if tournament.stages.size > 1 + if (group_stage = GroupStageService.generate_group_stage(groups)) + tournament.stages = [group_stage] + context.tournament = tournament + else + context.fail! + end + end +end From 83cd4ed34008f3ab287a148394f3ccc1a14654e7 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sat, 27 Apr 2019 22:34:27 +0200 Subject: [PATCH 04/31] Let Context Fail if there are any stages already in the tournament --- app/interactors/add_group_stage_to_tournament.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/interactors/add_group_stage_to_tournament.rb b/app/interactors/add_group_stage_to_tournament.rb index d8071f2..77956f6 100644 --- a/app/interactors/add_group_stage_to_tournament.rb +++ b/app/interactors/add_group_stage_to_tournament.rb @@ -6,7 +6,7 @@ class AddGroupStageToTournament def call tournament = context.tournament groups = context.groups - context.fail! if tournament.stages.size > 1 + context.fail! unless tournament.stages.empty? if (group_stage = GroupStageService.generate_group_stage(groups)) tournament.stages = [group_stage] context.tournament = tournament From 04b047660356df6d749da3193f27c576b42471b1 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sat, 27 Apr 2019 22:34:50 +0200 Subject: [PATCH 05/31] Test Add Group Stage Interactor --- ...oup_stage_to_tournament_interactor_spec.rb | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 spec/interactors/add_group_stage_to_tournament_interactor_spec.rb diff --git a/spec/interactors/add_group_stage_to_tournament_interactor_spec.rb b/spec/interactors/add_group_stage_to_tournament_interactor_spec.rb new file mode 100644 index 0000000..ca126dc --- /dev/null +++ b/spec/interactors/add_group_stage_to_tournament_interactor_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +RSpec.describe AddGroupStageToTournament do + let(:empty_tournament_context) do + AddGroupStageToTournament.call(tournament: @empty_tournament, groups: @groups) + end + + let(:group_stage_tournament_context) do + AddGroupStageToTournament.call(tournament: @group_stage_tournament, groups: @groups) + end + + before do + @empty_tournament = create(:stage_tournament, stage_count: 0) + @group_stage_tournament = create(:group_stage_tournament) + @group_stage = create(:group_stage) + @groups = Hash[1 => create_list(:team, 4), 2 => create_list(:team, 4)].values + end + + context 'GroupStageService mocked' do + before do + expect(class_double('GroupStageService').as_stubbed_const(transfer_nested_constants: true)) + .to receive(:generate_group_stage).with(@groups) + .and_return(@group_stage) + end + + context 'Empty tournament' do + it 'context succeeds' do + expect(empty_tournament_context).to be_a_success + end + + it 'adds group stage to the tournament' do + test = empty_tournament_context.tournament.stages.first + expect(test).to eq(@group_stage) + end + end + end + + context 'playoff generation fails' do + before do + expect(class_double('GroupStageService').as_stubbed_const(transfer_nested_constants: true)) + .to receive(:generate_group_stage).with(@groups) + .and_return(false) + end + + it 'context fails' do + expect(empty_tournament_context).to be_a_failure + end + end + + context 'Tournament where group stage is already generated' do + it 'does not add group stage' do + expect(group_stage_tournament_context).to be_a_failure + end + end +end From f47ffebcd46808009dadb77f96d0d529be05aa5d Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 24 Apr 2019 12:25:30 +0200 Subject: [PATCH 06/31] Makes Groups have different incrementing numbers --- spec/factories/groups.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/factories/groups.rb b/spec/factories/groups.rb index 841f741..748cb69 100644 --- a/spec/factories/groups.rb +++ b/spec/factories/groups.rb @@ -2,7 +2,7 @@ FactoryBot.define do factory :group do - number { 0 } + sequence(:number) stage end end From f7919ec0c61a0f5a105f7bcfdc7b2475d2dcaaae Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 24 Apr 2019 12:28:19 +0200 Subject: [PATCH 07/31] Adds Organizer to Add a group stage to a tournament and save it --- ..._stage_to_tournament_and_save_tournament_to_database.rb | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 app/organizers/add_group_stage_to_tournament_and_save_tournament_to_database.rb diff --git a/app/organizers/add_group_stage_to_tournament_and_save_tournament_to_database.rb b/app/organizers/add_group_stage_to_tournament_and_save_tournament_to_database.rb new file mode 100644 index 0000000..83710b5 --- /dev/null +++ b/app/organizers/add_group_stage_to_tournament_and_save_tournament_to_database.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddGroupStageToTournamentAndSaveTournamentToDatabase + include Interactor::Organizer + + organize AddGroupStageToTournament, SaveTournamentToDatabase +end From a842e0db3c5869d5142d87ee650ef488b718c321 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 24 Apr 2019 12:29:46 +0200 Subject: [PATCH 08/31] Add group stage service This service is responsible for all actions concerning the group stage It returns false if no groups are given to generate_group_stage method This prevents dividing by zero in the next line --- app/services/group_stage_service.rb | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 app/services/group_stage_service.rb diff --git a/app/services/group_stage_service.rb b/app/services/group_stage_service.rb new file mode 100644 index 0000000..2e93f76 --- /dev/null +++ b/app/services/group_stage_service.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +class GroupStageService + def self.generate_group_stage(groups) + return false if groups.length.zero? + + average_group_size = (groups.flatten.length.to_f / groups.length.to_f) + if (average_group_size % 1).zero? + groups = groups.map { |group| get_group_object_from(group) } + group_stage = Stage.new level: -1, groups: groups + group_stage + else + false + end + end + + def self.get_group_object_from(team_array) + matches = generate_all_matches_between team_array + group = Group.new matches: matches + group + end + + def self.generate_all_matches_between(teams) + matches = [] + matchups = teams.combination(2).to_a + matchups.each_with_index do |matchup, i| + match = Match.new state: :not_started, + position: i, + match_scores: [ + MatchScore.create(team: matchup.first), + MatchScore.create(team: matchup.second) + ] + matches << match + end + matches + end +end From 6dba0ec73880e9f980f19cac4c33922385aab18c Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sat, 27 Apr 2019 23:52:27 +0200 Subject: [PATCH 09/31] Test GroupStageService --- spec/services/group_stage_service_spec.rb | 70 +++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 spec/services/group_stage_service_spec.rb diff --git a/spec/services/group_stage_service_spec.rb b/spec/services/group_stage_service_spec.rb new file mode 100644 index 0000000..1d18b63 --- /dev/null +++ b/spec/services/group_stage_service_spec.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +RSpec.describe GroupStageService do + before do + @stage = create(:stage) + @teams1 = create_list(:team, 4) + @teams2 = create_list(:team, 4) + @groups = Hash[1 => @teams1, 2 => @teams2].values + end + describe 'generate_group_stage method' do + it 'returns a stage object' do + group_stage = GroupStageService.generate_group_stage(@groups) + expect(group_stage).to be_a(Stage) + end + + it 'returns a stage object with level -1' do + group_stage_level = GroupStageService.generate_group_stage(@groups).level + expect(group_stage_level).to be(-1) + end + + it 'adds the provided groups to the stage' do + group_stage_teams = GroupStageService.generate_group_stage(@groups).teams + expect(group_stage_teams).to match_array(@groups.flatten) + end + + it 'returns false when given different sizes of groups' do + unequal_groups = @groups + unequal_groups.first.pop + group_stage = GroupStageService.generate_group_stage(@groups) + expect(group_stage).to eq(false) + end + end + + describe 'get_group_object_from' do + it 'returns a group' do + group = GroupStageService.get_group_object_from(@teams1) + expect(group).to be_a(Group) + end + end + + describe 'generate_all_matches_between' do + it 'generates a list of not started matches' do + matches = GroupStageService.generate_all_matches_between(@teams2) + matches.each do |match| + expect(match).to be_a(Match) + match_state = match.state + expect(match_state).to eq('not_started') + end + end + + it 'generates the right amount of matches' do + matches = GroupStageService.generate_all_matches_between(@teams2) + # (1..@teams2.size-1).sum -> 1. Team has to play against n-1 teams; second against n-2 .... + expect(matches.size).to be((1..@teams2.size - 1).sum) + end + + it 'gives matches exclusive positions' do + matches = GroupStageService.generate_all_matches_between(@teams2) + match_positions = matches.map(&:position) + expect(match_positions).to eq(match_positions.uniq) + end + + it 'doesn\'t match a team against itself' do + matches = GroupStageService.generate_all_matches_between(@teams1) + matches.each do |match| + expect(match.teams.first).to_not eq(match.teams.second) + end + end + end +end From f9b1b603f013d70c5f4071839535736fb472f22a Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 24 Apr 2019 12:31:26 +0200 Subject: [PATCH 10/31] Permits "group_stage" as valid parameter for a create request --- app/controllers/tournaments_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index e8ea5c0..1f1ddb6 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -83,7 +83,7 @@ class TournamentsController < ApplicationController end def tournament_params - params.slice(:name, :description, :public, :teams).permit! + params.slice(:name, :description, :public, :teams, :group_stage).permit! end def validate_create_params From 300f16b4c254a4e48618e1fbd8aa5442681ebd38 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 24 Apr 2019 12:33:17 +0200 Subject: [PATCH 11/31] Rename create_data to create_playoff_tournament_data This is done in preparation for the addition of group stage data within the next few commits --- .../tournaments_controller_spec.rb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/controllers/tournaments_controller_spec.rb b/spec/controllers/tournaments_controller_spec.rb index 7dc9d2e..84d60f6 100644 --- a/spec/controllers/tournaments_controller_spec.rb +++ b/spec/controllers/tournaments_controller_spec.rb @@ -103,7 +103,7 @@ RSpec.describe TournamentsController, type: :controller do end describe 'POST #create' do - let(:create_data) do + let(:create_playoff_tournament_data) do { name: Faker::Creature::Dog.name, description: Faker::Lorem.sentence, @@ -114,7 +114,7 @@ RSpec.describe TournamentsController, type: :controller do context 'without authentication headers' do it 'renders an unauthorized error response' do - put :create, params: create_data + put :create, params: create_playoff_tournament_data expect(response).to have_http_status(:unauthorized) end end @@ -127,32 +127,32 @@ RSpec.describe TournamentsController, type: :controller do context 'with existing teams' do it 'creates a new Tournament' do expect do - post :create, params: create_data + post :create, params: create_playoff_tournament_data end.to change(Tournament, :count).by(1) end it 'associates the new tournament with the authenticated user' do expect do - post :create, params: create_data + post :create, params: create_playoff_tournament_data end.to change(@user.tournaments, :count).by(1) end it 'associates the given teams with the created tournament' do - post :create, params: create_data + post :create, params: create_playoff_tournament_data body = deserialize_response response tournament = Tournament.find(body[:id]) expect(tournament.teams).to match_array(@teams) end it 'generates a playoff stage' do - post :create, params: create_data + post :create, params: create_playoff_tournament_data body = deserialize_response response tournament = Tournament.find(body[:id]) expect(tournament.stages.first).to be_a(Stage) end it 'generates a playoff stage with all given teams' do - post :create, params: create_data + post :create, params: create_playoff_tournament_data body = deserialize_response response tournament = Tournament.find(body[:id]) included_teams = tournament.stages.first.matches.map { |m| m.match_scores.map(&:team) }.flatten.uniq @@ -160,7 +160,7 @@ RSpec.describe TournamentsController, type: :controller do end it 'renders a JSON response with the new tournament' do - post :create, params: create_data + post :create, params: create_playoff_tournament_data expect(response).to have_http_status(:created) expect(response.content_type).to eq('application/json') expect(response.location).to eq(tournament_url(Tournament.last)) @@ -169,7 +169,7 @@ RSpec.describe TournamentsController, type: :controller do context 'with missing teams' do it 'returns an error response' do - data = create_data + data = create_playoff_tournament_data data[:teams] << { id: Team.last.id + 1 } post :create, params: data expect(response).to have_http_status(:not_found) @@ -178,7 +178,7 @@ RSpec.describe TournamentsController, type: :controller do context 'with team names' do it 'creates teams for given names' do - data = create_data + data = create_playoff_tournament_data data.delete :teams data[:teams] = (1..12).collect { { name: Faker::Creature::Dog.name } } expect do From acfc388da4f229c294520daf7036337585db9b4f Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 24 Apr 2019 12:33:43 +0200 Subject: [PATCH 12/31] Implements group stage tournament creation --- app/controllers/tournaments_controller.rb | 54 ++++++++++++++----- .../tournaments_controller_spec.rb | 40 ++++++++++++++ 2 files changed, 82 insertions(+), 12 deletions(-) diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index 1f1ddb6..e994448 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -31,25 +31,47 @@ class TournamentsController < ApplicationController def create params = tournament_params params.require(:teams) - # convert teams parameter into Team objects - teams = params.delete('teams').map do |team| - if team[:id] - Team.find team[:id] - elsif team[:name] - Team.create name: team[:name] - end - end + group_stage = params.delete(:group_stage) + teams = params.delete('teams') # create tournament tournament = current_user.tournaments.new params - # associate provided teams with tournament - tournament.teams = teams + if group_stage + groups = {} + teams.each do |team| + team_id = team[:id] + team_name = team[:name] + group = team[:group] + unless team_id.nil? + team = Team.find team_id + put_team_into_groups_hash(groups, team, group) + end + + unless team_name.nil? + team = Team.create name: team_name + put_team_into_groups_hash(groups, team, group) + end + end + # add groups to tournament + result = AddGroupStageToTournamentAndSaveTournamentToDatabase.call(tournament: tournament, groups: groups.values) + else + # convert teams parameter into Team objects + teams = teams.map do |team| + if team[:id] + Team.find team[:id] + elsif team[:name] + Team.create name: team[:name] + end + end + # associate provided teams with tournament + tournament.teams = teams + # add playoff stage to tournament + result = AddPlayoffsToTournamentAndSaveTournamentToDatabase.call(tournament: tournament) + end # validate tournament unless tournament.valid? render json: tournament.errors, status: :unprocessable_entity return end - # add playoff stage to tournament - result = AddPlayoffsToTournamentAndSaveTournamentToDatabase.call(tournament: tournament) # return appropriate result if result.success? render json: result.tournament, status: :created, location: result.tournament @@ -74,6 +96,14 @@ class TournamentsController < ApplicationController private + def put_team_into_groups_hash(groups, team, group) + if groups[group].is_a?(Array) + groups[group] << team + else + groups[group] = [team] + end + end + def set_tournament @tournament = Tournament.find(params[:id]) end diff --git a/spec/controllers/tournaments_controller_spec.rb b/spec/controllers/tournaments_controller_spec.rb index 84d60f6..02c8277 100644 --- a/spec/controllers/tournaments_controller_spec.rb +++ b/spec/controllers/tournaments_controller_spec.rb @@ -9,6 +9,8 @@ RSpec.describe TournamentsController, type: :controller do @another_user = create(:user) @private_tournament = create(:tournament, user: @another_user, public: false) @teams = create_list(:detached_team, 4) + @teams16 = create_list(:detached_team, 16) + @groups = create_list(:group, 4) end describe 'GET #index' do @@ -112,6 +114,17 @@ RSpec.describe TournamentsController, type: :controller do } end + let(:create_group_tournament_data) do + teams_with_groups = @teams16.each_with_index.map { |team, i| { id: team.id, group: (i / 4).floor } } + { + name: Faker::TvShows::FamilyGuy.character, + description: Faker::Movies::HarryPotter.quote, + public: false, + group_stage: true, + teams: teams_with_groups + } + end + context 'without authentication headers' do it 'renders an unauthorized error response' do put :create, params: create_playoff_tournament_data @@ -159,6 +172,24 @@ RSpec.describe TournamentsController, type: :controller do expect(included_teams).to match_array(@teams) end + context 'generates a group stage tournament' do + before(:each) do + post :create, params: create_group_tournament_data + body = deserialize_response response + @group_stage_tournament = Tournament.find(body[:id]) + end + + it 'with all given teams in their respective groups' do + included_teams = @group_stage_tournament.stages.find_by(level: -1).teams + expect(included_teams).to match_array(@teams16) + end + + it 'which is a stage' do + group_stage = @group_stage_tournament.stages.find_by(level: -1) + expect(group_stage).to be_a(Stage) + end + end + it 'renders a JSON response with the new tournament' do post :create, params: create_playoff_tournament_data expect(response).to have_http_status(:created) @@ -176,6 +207,15 @@ RSpec.describe TournamentsController, type: :controller do end end + context 'with unequal group sizes' do + it 'returns an error response' do + data = create_group_tournament_data + data[:teams].pop + post :create, params: data + expect(response).to have_http_status(:unprocessable_entity) + end + end + context 'with team names' do it 'creates teams for given names' do data = create_playoff_tournament_data From 6811c9e7eba166f6ab095cfbf7bb7eaacdde6a0e Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 24 Apr 2019 22:29:18 +0200 Subject: [PATCH 13/31] Corrects Test name --- spec/interactors/add_playoffs_to_tournament_interactor_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/interactors/add_playoffs_to_tournament_interactor_spec.rb b/spec/interactors/add_playoffs_to_tournament_interactor_spec.rb index 3bb385d..056dc2b 100644 --- a/spec/interactors/add_playoffs_to_tournament_interactor_spec.rb +++ b/spec/interactors/add_playoffs_to_tournament_interactor_spec.rb @@ -20,7 +20,7 @@ RSpec.describe AddPlayoffsToTournament do @stages = create_list(:stage, 5) end - context 'ez lyfe' do + context 'PlayoffStageService mocked' do before do expect(class_double('PlayoffStageService').as_stubbed_const(transfer_nested_constants: true)) .to receive(:generate_playoff_stages_from_tournament) From 3fc344249d2c7fbdb8148ea0c9a44e663fbb04be Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sat, 27 Apr 2019 22:27:38 +0200 Subject: [PATCH 14/31] Add multiple factories --- spec/factories/groups.rb | 8 ++++++++ spec/factories/stages.rb | 9 +++++++++ spec/factories/tournaments.rb | 7 +++++++ 3 files changed, 24 insertions(+) diff --git a/spec/factories/groups.rb b/spec/factories/groups.rb index 748cb69..839c230 100644 --- a/spec/factories/groups.rb +++ b/spec/factories/groups.rb @@ -2,7 +2,15 @@ FactoryBot.define do factory :group do + transient do + match_count { 4 } + end + sequence(:number) stage + + after(:create) do |group, evaluator| + create_list(:group_match, evaluator.match_count, group: group) + end end end diff --git a/spec/factories/stages.rb b/spec/factories/stages.rb index 4353af1..d033247 100644 --- a/spec/factories/stages.rb +++ b/spec/factories/stages.rb @@ -3,5 +3,14 @@ FactoryBot.define do factory :stage do tournament + factory :group_stage do + level { -1 } + transient do + group_count { 4 } + end + after(:create) do |stage, evaluator| + stage.groups = create_list(:group, evaluator.group_count) + end + end end end diff --git a/spec/factories/tournaments.rb b/spec/factories/tournaments.rb index 4b93176..6924332 100644 --- a/spec/factories/tournaments.rb +++ b/spec/factories/tournaments.rb @@ -11,6 +11,7 @@ FactoryBot.define do after(:create) do |tournament, evaluator| tournament.teams = create_list(:team, evaluator.teams_count, tournament: tournament) end + factory :stage_tournament do transient do stage_count { 1 } @@ -19,5 +20,11 @@ FactoryBot.define do tournament.stages = create_list(:stage, evaluator.stage_count) end end + + factory :group_stage_tournament do + after(:create) do |tournament, _evaluator| + tournament.stages = create_list(:group_stage, 1) + end + end end end From 22f0204f29e0bf7a70740053f69965eb26edd157 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sun, 28 Apr 2019 12:08:46 +0200 Subject: [PATCH 15/31] Add missing factory specs --- spec/models/match_spec.rb | 2 ++ spec/models/stage_spec.rb | 1 + spec/models/team_spec.rb | 1 + spec/models/tournament_spec.rb | 2 ++ 4 files changed, 6 insertions(+) diff --git a/spec/models/match_spec.rb b/spec/models/match_spec.rb index ad31ac6..63e436a 100644 --- a/spec/models/match_spec.rb +++ b/spec/models/match_spec.rb @@ -45,5 +45,7 @@ RSpec.describe Match, type: :model do it 'has a valid factory' do expect(build(:match)).to be_valid + expect(build(:running_playoff_match)).to be_valid + expect(build(:group_match)).to be_valid end end diff --git a/spec/models/stage_spec.rb b/spec/models/stage_spec.rb index 4af3c30..df3d79e 100644 --- a/spec/models/stage_spec.rb +++ b/spec/models/stage_spec.rb @@ -11,5 +11,6 @@ RSpec.describe Stage, type: :model do it 'has a valid factory' do expect(build(:stage)).to be_valid + expect(build(:group_stage)).to be_valid end end diff --git a/spec/models/team_spec.rb b/spec/models/team_spec.rb index ce229fa..d1e477b 100644 --- a/spec/models/team_spec.rb +++ b/spec/models/team_spec.rb @@ -15,5 +15,6 @@ RSpec.describe Team, type: :model do it 'has a valid factory' do expect(build(:team)).to be_valid + expect(build(:detached_team)).to be_valid end end diff --git a/spec/models/tournament_spec.rb b/spec/models/tournament_spec.rb index be6624a..c437df8 100644 --- a/spec/models/tournament_spec.rb +++ b/spec/models/tournament_spec.rb @@ -33,5 +33,7 @@ RSpec.describe Tournament, type: :model do it 'has valid factory' do expect(build(:tournament)).to be_valid + expect(build(:stage_tournament)).to be_valid + expect(build(:group_stage_tournament)).to be_valid end end From 74e9139b336e42c579ef7379b915893849804354 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sun, 28 Apr 2019 17:15:35 +0200 Subject: [PATCH 16/31] Removes unnecessary check --- app/controllers/tournaments_controller.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index e994448..d2fbc67 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -41,12 +41,10 @@ class TournamentsController < ApplicationController team_id = team[:id] team_name = team[:name] group = team[:group] - unless team_id.nil? + if team_id team = Team.find team_id put_team_into_groups_hash(groups, team, group) - end - - unless team_name.nil? + elsif team_name team = Team.create name: team_name put_team_into_groups_hash(groups, team, group) end From f9b96cbee201c5ab322e88849a0f8f49732f5009 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sun, 28 Apr 2019 17:18:02 +0200 Subject: [PATCH 17/31] Indicate the groups variable being changed within the method --- app/controllers/tournaments_controller.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index d2fbc67..ffaece6 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -43,10 +43,10 @@ class TournamentsController < ApplicationController group = team[:group] if team_id team = Team.find team_id - put_team_into_groups_hash(groups, team, group) + put_team_into_groups_hash!(groups, team, group) elsif team_name team = Team.create name: team_name - put_team_into_groups_hash(groups, team, group) + put_team_into_groups_hash!(groups, team, group) end end # add groups to tournament @@ -94,7 +94,7 @@ class TournamentsController < ApplicationController private - def put_team_into_groups_hash(groups, team, group) + def put_team_into_groups_hash!(groups, team, group) if groups[group].is_a?(Array) groups[group] << team else From 9053251706dfa08b6d50c808d12bd6a184ae6414 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sun, 28 Apr 2019 17:21:36 +0200 Subject: [PATCH 18/31] Document group_stage generation parameter preparation --- app/controllers/tournaments_controller.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index ffaece6..6e6c65e 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -36,11 +36,15 @@ class TournamentsController < ApplicationController # create tournament tournament = current_user.tournaments.new params if group_stage + # if parameter group_stage = true groups = {} + # each team gets put into a hash of groups depending on the value assigned in team[:group] + # groups is a key value hash; key being the group, value being the array of teams within that group teams.each do |team| team_id = team[:id] team_name = team[:name] group = team[:group] + # convert teams parameter into Team objects if team_id team = Team.find team_id put_team_into_groups_hash!(groups, team, group) From bbeda07028b9cf62c19bfaca01e7d48ddddd4f06 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sun, 28 Apr 2019 17:37:25 +0200 Subject: [PATCH 19/31] Change test / context / describe names --- spec/controllers/tournaments_controller_spec.rb | 6 +++--- .../add_group_stage_to_tournament_interactor_spec.rb | 8 ++++---- spec/services/group_stage_service_spec.rb | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/controllers/tournaments_controller_spec.rb b/spec/controllers/tournaments_controller_spec.rb index 02c8277..330ed5a 100644 --- a/spec/controllers/tournaments_controller_spec.rb +++ b/spec/controllers/tournaments_controller_spec.rb @@ -172,19 +172,19 @@ RSpec.describe TournamentsController, type: :controller do expect(included_teams).to match_array(@teams) end - context 'generates a group stage tournament' do + context 'with parameter group_stage=true' do before(:each) do post :create, params: create_group_tournament_data body = deserialize_response response @group_stage_tournament = Tournament.find(body[:id]) end - it 'with all given teams in their respective groups' do + it 'generates a group stage with all teams given in parameters' do included_teams = @group_stage_tournament.stages.find_by(level: -1).teams expect(included_teams).to match_array(@teams16) end - it 'which is a stage' do + it 'generates a group stage' do group_stage = @group_stage_tournament.stages.find_by(level: -1) expect(group_stage).to be_a(Stage) end diff --git a/spec/interactors/add_group_stage_to_tournament_interactor_spec.rb b/spec/interactors/add_group_stage_to_tournament_interactor_spec.rb index ca126dc..1c14d49 100644 --- a/spec/interactors/add_group_stage_to_tournament_interactor_spec.rb +++ b/spec/interactors/add_group_stage_to_tournament_interactor_spec.rb @@ -23,8 +23,8 @@ RSpec.describe AddGroupStageToTournament do .and_return(@group_stage) end - context 'Empty tournament' do - it 'context succeeds' do + context 'empty tournament' do + it 'succeeds' do expect(empty_tournament_context).to be_a_success end @@ -42,12 +42,12 @@ RSpec.describe AddGroupStageToTournament do .and_return(false) end - it 'context fails' do + it 'fails' do expect(empty_tournament_context).to be_a_failure end end - context 'Tournament where group stage is already generated' do + context 'tournament where group stage is already generated' do it 'does not add group stage' do expect(group_stage_tournament_context).to be_a_failure end diff --git a/spec/services/group_stage_service_spec.rb b/spec/services/group_stage_service_spec.rb index 1d18b63..a6b97c4 100644 --- a/spec/services/group_stage_service_spec.rb +++ b/spec/services/group_stage_service_spec.rb @@ -7,7 +7,7 @@ RSpec.describe GroupStageService do @teams2 = create_list(:team, 4) @groups = Hash[1 => @teams1, 2 => @teams2].values end - describe 'generate_group_stage method' do + describe '#generate_group_stage method' do it 'returns a stage object' do group_stage = GroupStageService.generate_group_stage(@groups) expect(group_stage).to be_a(Stage) @@ -31,14 +31,14 @@ RSpec.describe GroupStageService do end end - describe 'get_group_object_from' do + describe '#get_group_object_from' do it 'returns a group' do group = GroupStageService.get_group_object_from(@teams1) expect(group).to be_a(Group) end end - describe 'generate_all_matches_between' do + describe '#generate_all_matches_between' do it 'generates a list of not started matches' do matches = GroupStageService.generate_all_matches_between(@teams2) matches.each do |match| From fdac71a9f158e1c94b0e74a31766cf9d2e84d0ef Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sun, 28 Apr 2019 17:37:44 +0200 Subject: [PATCH 20/31] Unnecessary variable assignment --- app/services/group_stage_service.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/services/group_stage_service.rb b/app/services/group_stage_service.rb index 2e93f76..0af32b3 100644 --- a/app/services/group_stage_service.rb +++ b/app/services/group_stage_service.rb @@ -6,9 +6,8 @@ class GroupStageService average_group_size = (groups.flatten.length.to_f / groups.length.to_f) if (average_group_size % 1).zero? - groups = groups.map { |group| get_group_object_from(group) } - group_stage = Stage.new level: -1, groups: groups - group_stage + groups = groups.map(&method(:get_group_object_from)) + Stage.new level: -1, groups: groups else false end @@ -16,8 +15,7 @@ class GroupStageService def self.get_group_object_from(team_array) matches = generate_all_matches_between team_array - group = Group.new matches: matches - group + Group.new matches: matches end def self.generate_all_matches_between(teams) From 88d8367c472ab30be568783f91f34e0d117920a4 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sun, 28 Apr 2019 17:38:16 +0200 Subject: [PATCH 21/31] Check the length of the match positions instead of their exact content --- spec/services/group_stage_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/services/group_stage_service_spec.rb b/spec/services/group_stage_service_spec.rb index a6b97c4..6b82724 100644 --- a/spec/services/group_stage_service_spec.rb +++ b/spec/services/group_stage_service_spec.rb @@ -57,7 +57,7 @@ RSpec.describe GroupStageService do it 'gives matches exclusive positions' do matches = GroupStageService.generate_all_matches_between(@teams2) match_positions = matches.map(&:position) - expect(match_positions).to eq(match_positions.uniq) + expect(match_positions.length).to eq(match_positions.uniq.length) end it 'doesn\'t match a team against itself' do From bfadc7a6af41545bbe31b480641c3034f5d3a27d Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Mon, 29 Apr 2019 19:17:03 +0200 Subject: [PATCH 22/31] Dry out Tournaments Controller --- app/controllers/tournaments_controller.rb | 48 +++++++++-------------- 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index 6e6c65e..6a4a3e5 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -36,34 +36,12 @@ class TournamentsController < ApplicationController # create tournament tournament = current_user.tournaments.new params if group_stage - # if parameter group_stage = true - groups = {} - # each team gets put into a hash of groups depending on the value assigned in team[:group] - # groups is a key value hash; key being the group, value being the array of teams within that group - teams.each do |team| - team_id = team[:id] - team_name = team[:name] - group = team[:group] - # convert teams parameter into Team objects - if team_id - team = Team.find team_id - put_team_into_groups_hash!(groups, team, group) - elsif team_name - team = Team.create name: team_name - put_team_into_groups_hash!(groups, team, group) - end - end + groups = organize_teams_in_groups(teams) # add groups to tournament - result = AddGroupStageToTournamentAndSaveTournamentToDatabase.call(tournament: tournament, groups: groups.values) + result = AddGroupStageToTournamentAndSaveTournamentToDatabase.call(tournament: tournament, groups: groups) else # convert teams parameter into Team objects - teams = teams.map do |team| - if team[:id] - Team.find team[:id] - elsif team[:name] - Team.create name: team[:name] - end - end + teams = teams.map(&method(:find_or_create_team)) # associate provided teams with tournament tournament.teams = teams # add playoff stage to tournament @@ -98,11 +76,21 @@ class TournamentsController < ApplicationController private - def put_team_into_groups_hash!(groups, team, group) - if groups[group].is_a?(Array) - groups[group] << team - else - groups[group] = [team] + def organize_teams_in_groups(teams) + # each team gets put into a array of teams depending on the group specified in team[:group] + teams.group_by { |team| team['group'] }.values.map do |group| + group.map do |team| + find_or_create_team(team) + end + end + end + + def find_or_create_team(team) + # convert teams parameter into Team objects + if team[:id] + Team.find team[:id] + elsif team[:name] + Team.create name: team[:name] end end From 0f7279de97b9b415aad617aa64d6c47052545474 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Mon, 29 Apr 2019 22:11:21 +0200 Subject: [PATCH 23/31] Add running_group_match factory --- spec/factories/matches.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/factories/matches.rb b/spec/factories/matches.rb index 773151f..3f0a89c 100644 --- a/spec/factories/matches.rb +++ b/spec/factories/matches.rb @@ -16,5 +16,14 @@ FactoryBot.define do factory :group_match, class: Match do group + factory :running_group_match do + transient do + match_scores_count { 2 } + end + after(:create) do |match, evaluator| + match.match_scores = create_list(:match_score, evaluator.match_scores_count) + end + state { 3 } + end end end From db1518bdbd5ea77afadc46bcecd6ca3f5813a4ea Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Wed, 1 May 2019 16:10:55 +0200 Subject: [PATCH 24/31] Raise exceptions upon error in group_stage_service --- .../add_group_stage_to_tournament.rb | 5 +++-- app/services/group_stage_service.rb | 12 +++++------- ...roup_stage_to_tournament_interactor_spec.rb | 18 +++++++++++++++--- spec/services/group_stage_service_spec.rb | 11 ++++++++--- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/app/interactors/add_group_stage_to_tournament.rb b/app/interactors/add_group_stage_to_tournament.rb index 77956f6..14b798c 100644 --- a/app/interactors/add_group_stage_to_tournament.rb +++ b/app/interactors/add_group_stage_to_tournament.rb @@ -7,10 +7,11 @@ class AddGroupStageToTournament tournament = context.tournament groups = context.groups context.fail! unless tournament.stages.empty? - if (group_stage = GroupStageService.generate_group_stage(groups)) + begin + group_stage = GroupStageService.generate_group_stage(groups) tournament.stages = [group_stage] context.tournament = tournament - else + rescue StandardError context.fail! end end diff --git a/app/services/group_stage_service.rb b/app/services/group_stage_service.rb index 0af32b3..f31d14c 100644 --- a/app/services/group_stage_service.rb +++ b/app/services/group_stage_service.rb @@ -2,15 +2,13 @@ class GroupStageService def self.generate_group_stage(groups) - return false if groups.length.zero? + raise 'Cannot generate group stage without groups' if groups.length.zero? average_group_size = (groups.flatten.length.to_f / groups.length.to_f) - if (average_group_size % 1).zero? - groups = groups.map(&method(:get_group_object_from)) - Stage.new level: -1, groups: groups - else - false - end + raise 'Groups need to be equal size' unless (average_group_size % 1).zero? + + groups = groups.map(&method(:get_group_object_from)) + Stage.new level: -1, groups: groups end def self.get_group_object_from(team_array) diff --git a/spec/interactors/add_group_stage_to_tournament_interactor_spec.rb b/spec/interactors/add_group_stage_to_tournament_interactor_spec.rb index 1c14d49..b64c752 100644 --- a/spec/interactors/add_group_stage_to_tournament_interactor_spec.rb +++ b/spec/interactors/add_group_stage_to_tournament_interactor_spec.rb @@ -35,14 +35,26 @@ RSpec.describe AddGroupStageToTournament do end end - context 'playoff generation fails' do + context 'empty groups' do before do expect(class_double('GroupStageService').as_stubbed_const(transfer_nested_constants: true)) .to receive(:generate_group_stage).with(@groups) - .and_return(false) + .and_raise('Cannot generate group stage without groups') end - it 'fails' do + it 'playoff generation fails' do + expect(empty_tournament_context).to be_a_failure + end + end + + context 'unequal group sizes' do + before do + expect(class_double('GroupStageService').as_stubbed_const(transfer_nested_constants: true)) + .to receive(:generate_group_stage).with(@groups) + .and_raise('Groups need to be equal size') + end + + it 'playoff generation fails' do expect(empty_tournament_context).to be_a_failure end end diff --git a/spec/services/group_stage_service_spec.rb b/spec/services/group_stage_service_spec.rb index 6b82724..f88f598 100644 --- a/spec/services/group_stage_service_spec.rb +++ b/spec/services/group_stage_service_spec.rb @@ -23,11 +23,16 @@ RSpec.describe GroupStageService do expect(group_stage_teams).to match_array(@groups.flatten) end - it 'returns false when given different sizes of groups' do + it 'raises exception when given different sizes of groups' do unequal_groups = @groups unequal_groups.first.pop - group_stage = GroupStageService.generate_group_stage(@groups) - expect(group_stage).to eq(false) + expect { GroupStageService.generate_group_stage(unequal_groups) } + .to raise_exception 'Groups need to be equal size' + end + + it 'raises exception when given no groups' do + expect { GroupStageService.generate_group_stage([]) } + .to raise_exception 'Cannot generate group stage without groups' end end From babc233412c36c90d50d37104a4a2cd84767873b Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Thu, 2 May 2019 09:47:26 +0200 Subject: [PATCH 25/31] Adds :playoff_stage as factory --- spec/factories/stages.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spec/factories/stages.rb b/spec/factories/stages.rb index d033247..e8dce2d 100644 --- a/spec/factories/stages.rb +++ b/spec/factories/stages.rb @@ -12,5 +12,15 @@ FactoryBot.define do stage.groups = create_list(:group, evaluator.group_count) end end + + factory :playoff_stage do + level { rand(10) } + transient do + match_count { 4 } + end + after(:create) do |stage, evaluator| + stage.matches = create_list(:match, evaluator.match_count) + end + end end end From 6a2c71bad77ef4b9f60f5ac2921b8a4ff16b4d2d Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Thu, 2 May 2019 11:12:57 +0200 Subject: [PATCH 26/31] Fix stage.team method not returning teams for playoff stages --- app/models/stage.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/stage.rb b/app/models/stage.rb index 64b788e..48ad20d 100644 --- a/app/models/stage.rb +++ b/app/models/stage.rb @@ -6,6 +6,8 @@ class Stage < ApplicationRecord has_many :groups, dependent: :destroy def teams - groups.map(&:teams).flatten.uniq + return matches.map(&:teams).flatten.uniq unless matches.size.zero? + + groups.map(&:teams).flatten.uniq unless groups.size.zero? end end From f1490559659d5fce03c0bd1ac8d73cb313ea06c2 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Mon, 29 Apr 2019 22:11:42 +0200 Subject: [PATCH 27/31] Test teams methods of Matches, Groups and Stages --- spec/models/group_spec.rb | 15 +++++++++++++++ spec/models/match_spec.rb | 34 ++++++++++++++++++++++++++++++++++ spec/models/stage_spec.rb | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 0f5784a..e8c8be2 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -12,4 +12,19 @@ RSpec.describe Group, type: :model do it 'has a valid factory' do expect(build(:group)).to be_valid end + + describe '#teams' do + before do + @group = create(:group, match_count: 1) # this is getting stubbed anyways + @teams = create_list(:team, 4) + expect_any_instance_of(Match) + .to receive(:teams) + .and_return(@teams) + end + + it 'returns all teams from the matches within the matches below' do + teams = @group.teams + expect(teams).to match_array(@teams) + end + end end diff --git a/spec/models/match_spec.rb b/spec/models/match_spec.rb index 63e436a..01d34c5 100644 --- a/spec/models/match_spec.rb +++ b/spec/models/match_spec.rb @@ -43,6 +43,40 @@ RSpec.describe Match, type: :model do end end + context '#teams' do + before do + @playoff_match = create(:running_playoff_match) + @group_match = create(:running_group_match) + @teams = create_list(:team, 2) + @match_scores = create_list(:match_score, 2) + @match_scores.each_with_index { |match, i| match.team = @teams[i] } + @playoff_match.match_scores = @match_scores + @group_match.match_scores = @match_scores + end + + context 'called on group match' do + let(:call_teams_on_group_match) do + @group_match.teams + end + + it 'returns 2 team objects' do + teams = call_teams_on_group_match + expect(teams).to match_array(@teams) + end + end + + context 'called on playoff match' do + let(:call_teams_on_playoff_match) do + @playoff_match.teams + end + + it 'returns 2 team objects' do + teams = call_teams_on_playoff_match + expect(teams).to match_array(@teams) + end + end + end + it 'has a valid factory' do expect(build(:match)).to be_valid expect(build(:running_playoff_match)).to be_valid diff --git a/spec/models/stage_spec.rb b/spec/models/stage_spec.rb index df3d79e..a14fccd 100644 --- a/spec/models/stage_spec.rb +++ b/spec/models/stage_spec.rb @@ -13,4 +13,36 @@ RSpec.describe Stage, type: :model do expect(build(:stage)).to be_valid expect(build(:group_stage)).to be_valid end + + describe '#teams' do + context 'group stage' do + before do + @stage = create(:group_stage, group_count: 1) # this is getting stubbed anyways + @teams = create_list(:team, 4) + expect_any_instance_of(Group) + .to receive(:teams) + .and_return(@teams) + end + + it 'returns all teams from the matches within the groups below' do + teams = @stage.teams + expect(teams).to match_array(@teams) + end + end + + context 'playoff stage' do + before do + @stage = create(:playoff_stage, match_count: 1) # this is getting stubbed anyways + @teams = create_list(:team, 4) + expect_any_instance_of(Match) + .to receive(:teams) + .and_return(@teams) + end + + it 'returns all teams from the matches within the matches below' do + teams = @stage.teams + expect(teams).to match_array(@teams) + end + end + end end From ae29427e5d9d37c340b23cc23330c22b1cfc2502 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Thu, 2 May 2019 11:46:32 +0200 Subject: [PATCH 28/31] Don't run "before" before each test --- spec/controllers/tournaments_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/controllers/tournaments_controller_spec.rb b/spec/controllers/tournaments_controller_spec.rb index 330ed5a..3a64dde 100644 --- a/spec/controllers/tournaments_controller_spec.rb +++ b/spec/controllers/tournaments_controller_spec.rb @@ -173,7 +173,7 @@ RSpec.describe TournamentsController, type: :controller do end context 'with parameter group_stage=true' do - before(:each) do + before do post :create, params: create_group_tournament_data body = deserialize_response response @group_stage_tournament = Tournament.find(body[:id]) From f93c714e1a3f0b9c986cfd620d8f3b0bed9972e3 Mon Sep 17 00:00:00 2001 From: Thor77 Date: Thu, 2 May 2019 14:34:03 +0200 Subject: [PATCH 29/31] Add test for empty team hashes --- spec/controllers/tournaments_controller_spec.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/controllers/tournaments_controller_spec.rb b/spec/controllers/tournaments_controller_spec.rb index 3a64dde..da27ca7 100644 --- a/spec/controllers/tournaments_controller_spec.rb +++ b/spec/controllers/tournaments_controller_spec.rb @@ -233,6 +233,15 @@ RSpec.describe TournamentsController, type: :controller do expect(response).to have_http_status(:unprocessable_entity) end end + + context 'with empty team objects' do + it 'renders an unprocessable entity response' do + data = create_group_tournament_data + data[:teams] = [{ group: 1 }, { group: 1 }, { group: 2 }, { group: 2 }] + post :create, params: data + expect(response).to have_http_status(:unprocessable_entity) + end + end end end From 23249ee93b1c362fd6111efdf444765f084bd6e0 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Thu, 2 May 2019 15:17:32 +0200 Subject: [PATCH 30/31] Build Matches without saving directly to database --- app/services/group_stage_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/group_stage_service.rb b/app/services/group_stage_service.rb index f31d14c..0c2b7d7 100644 --- a/app/services/group_stage_service.rb +++ b/app/services/group_stage_service.rb @@ -23,8 +23,8 @@ class GroupStageService match = Match.new state: :not_started, position: i, match_scores: [ - MatchScore.create(team: matchup.first), - MatchScore.create(team: matchup.second) + MatchScore.new(team: matchup.first), + MatchScore.new(team: matchup.second) ] matches << match end From f7ed4b549d684da7071ffd5bc5af97eb916e0c08 Mon Sep 17 00:00:00 2001 From: Malaber <32635600+Malaber@users.noreply.github.com> Date: Sat, 4 May 2019 20:54:08 +0200 Subject: [PATCH 31/31] Destroying all Readability. Noone will ever be able to read this code again. --- app/services/group_stage_service.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/services/group_stage_service.rb b/app/services/group_stage_service.rb index 0c2b7d7..ea03168 100644 --- a/app/services/group_stage_service.rb +++ b/app/services/group_stage_service.rb @@ -4,22 +4,21 @@ class GroupStageService def self.generate_group_stage(groups) raise 'Cannot generate group stage without groups' if groups.length.zero? - average_group_size = (groups.flatten.length.to_f / groups.length.to_f) - raise 'Groups need to be equal size' unless (average_group_size % 1).zero? + # raise an error if the average group size is not a whole number + raise 'Groups need to be equal size' unless (groups.flatten.length.to_f / groups.length.to_f % 1).zero? groups = groups.map(&method(:get_group_object_from)) Stage.new level: -1, groups: groups end def self.get_group_object_from(team_array) - matches = generate_all_matches_between team_array - Group.new matches: matches + Group.new matches: generate_all_matches_between(team_array) end def self.generate_all_matches_between(teams) matches = [] - matchups = teams.combination(2).to_a - matchups.each_with_index do |matchup, i| + teams.combination(2).to_a # = matchups + .each_with_index do |matchup, i| match = Match.new state: :not_started, position: i, match_scores: [