RSpec.shared_examples 'Database Schema' do
  context 'AAF shared implementation' do
    RSpec::Matchers.define :have_collation do |expected|
      match { |actual| actual[:Collation] == expected }

      failure_message do |actual|
        format('expected table `%<Name>s` to use collation `%<expected>s`, ' \
               'but was `%<Collation>s`', actual.merge(expected: expected))
      end
    end

    before { expect(connection).to be_a(Mysql2::Client) }

    it 'has the correct encoding set for the connection' do
      expect(connection.query_options).to include(encoding: 'utf8')
    end

    it 'has the correct collation set for the connection' do
      expect(connection.query_options).to include(collation: 'utf8_bin')
    end

    it 'has the correct collation' do
      result = connection.query('SHOW TABLE STATUS',
                                as: :hash, symbolize_keys: true)
      result.each do |table|
        next if table[:Name] == 'schema_migrations'
        expect(table).to have_collation('utf8_bin')
      end
    end
  end
end

RSpec.shared_examples 'Database Schema' do
  context 'AAF shared implementation' do
    RSpec::Matchers.define :have_collation do |expected|
      match { |actual| actual[:Collation] == expected }

      failure_message do |actual|
        if actual[:Field]
          format('expected field `%<Field>s` to use collation `%<expected>s`,' \
                 ' but was `%<Collation>s`', actual.merge(expected: expected))
        else
          format('expected table `%<Name>s` to use collation `%<expected>s`, ' \
                 'but was `%<Collation>s`', actual.merge(expected: expected))
        end
      end
    end

    before { expect(connection).to be_a(Mysql2::Client) }

    it 'has the correct encoding set for the connection' do
      expect(connection.query_options).to include(encoding: 'utf8')
    end

    it 'has the correct collation set for the connection' do
      expect(connection.query_options).to include(collation: 'utf8_bin')
    end

    it 'has the correct collation' do
      tables = connection.query('SHOW TABLE STATUS',
                                as: :hash, symbolize_keys: true)
      tables.each do |table|
        next if table[:Name] == 'schema_migrations'
        expect(table).to have_collation('utf8_bin')

        columns = connection.query("SHOW FULL COLUMNS FROM #{table[:Name]}",
                                   as: :hash, symbolize_keys: true)
        columns.each do |column|
          next unless column[:Collation]
          expect(column).to have_collation('utf8_bin')
        end
      end
    end
  end
end

Check the collation of each column too
Check the collation of each column too

When migrating to fix collation, it's possible to accidentally do so
without fixing the columns. Guard against this.
