Instruction:
Write RSpec test file for following ruby class
```ruby
class SetLocalizationService
  attr_reader :user, :http_accept_header

  include Redmine::I18n

  def initialize(user, http_accept_header = nil)
    @user = user
    @http_accept_header = http_accept_header
  end

  ##
  # Sets the locale.
  # The locale is determined with the following priority:
  #
  #   1. The language as configured by the user.
  #   2. The first language defined in the Accept-Language header sent by the browser.
  #   3. OpenProject's default language defined in the settings.

  def call
    lang = user_language || header_language || default_language

    set_language_if_valid(lang)
  end

  private

  def user_language
    find_language_or_prefix(user.language) if user.logged?
  end

  def header_language
    return unless http_accept_header

    accept_lang = parse_qvalues(http_accept_header).first
    find_language_or_prefix accept_lang
  end

  def default_language
    Setting.default_language
  end

  # qvalues http header parser
  # code taken from webrick
  def parse_qvalues(value)
    tmp = []
    if value
      parts = value.split(/,\s*/)
      parts.each do |part|
        match = /\A([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?\z/.match(part)
        if match
          val = match[1]
          q = (match[2] || 1).to_f
          tmp.push([val, q])
        end
      end
      tmp = tmp.sort_by { |_val, q| -q }
      tmp.map! { |val, _q| val }
    end

    tmp
  rescue StandardError
    nil
  end

  def find_language_or_prefix(language)
    return nil unless language

    language = language.to_s.downcase
    find_language(language) || find_language(language.split('-').first)
  end
end

```

Response:
require 'spec_helper'

RSpec.describe SetLocalizationService do
  let(:user) { build_stubbed(:user, language: user_language) }
  let(:http_accept_header) { "#{http_accept_language},en-US;q=0.8,en;q=0.6" }
  let(:instance) { described_class.new(user, http_accept_header) }
  let(:user_language) { :bogus_language }
  let(:http_accept_language) { :http_accept_language }
  let(:default_language) { :default_language }

  before do
    allow(I18n).to receive(:locale=).with(:en)
    allow(instance).to receive(:valid_languages).and_return [user_language,
                                                             http_accept_language,
                                                             default_language]
    allow(Setting).to receive(:default_language).and_return(default_language)
  end

  def expect_locale(locale)
    expect(I18n).to receive(:locale=).with(locale)
  end

  shared_examples_for 'falls back to the header' do
    it 'falls back to the header' do
      expect_locale(http_accept_language)

      instance.call
    end
  end

  shared_examples_for "falls back to the instane's default language" do
    it "falls back to the instance's default language" do
      expect_locale(default_language)

      instance.call
    end
  end

  context 'for a logged in user' do
    it "sets the language to the user's selected language" do
      expect_locale(user_language)

      instance.call
    end

    context 'with a language prefix being valid' do
      let(:prefix) { 'someprefix' }
      let(:user_language) { "#{prefix}-specific" }

      before do
        allow(instance).to receive(:valid_languages).and_return [prefix,
                                                                 http_accept_language,
                                                                 default_language]
      end

      it "sets the language to the valid prefix of the user's selected language" do
        expect_locale(prefix)

        instance.call
      end
    end

    context 'with the language not being valid' do
      before do
        allow(instance).to receive(:valid_languages).and_return [http_accept_language,
                                                                 default_language]
      end

      it_behaves_like 'falls back to the header'

      context 'with a language prefix being valid' do
        let(:prefix) { 'someprefix' }
        let(:http_accept_header) { "#{prefix}-specific" }

        before do
          allow(instance).to receive(:valid_languages).and_return [prefix,
                                                                   default_language]
        end

        it "sets the language to the valid prefix of the accept header" do
          expect_locale(prefix)

          instance.call
        end
      end
    end

    context 'with the user not having a language selected' do
      before do
        user.language = nil
      end

      it_behaves_like 'falls back to the header'

      context 'with the header not being valid' do
        before do
          allow(instance).to receive(:valid_languages).and_return [user_language,
                                                                   default_language]
        end

        it_behaves_like "falls back to the instane's default language"
      end

      context 'with no header set' do
        let(:http_accept_header) { nil }

        it_behaves_like "falls back to the instane's default language"
      end

      context 'with wildcard header set' do
        let(:http_accept_language) { '*' }

        it_behaves_like "falls back to the instane's default language"
      end
    end
  end

  context 'for an anonymous user' do
    let(:user) { build_stubbed(:anonymous) }

    it_behaves_like 'falls back to the header'

    context 'with no header set' do
      let(:http_accept_header) { nil }

      it_behaves_like "falls back to the instane's default language"
    end

    context 'with a wildcard header set' do
      let(:http_accept_language) { '*' }

      it_behaves_like "falls back to the instane's default language"
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class CreateTypeService < BaseTypeService
  def initialize(user)
    super Type.new, user
  end

  private

  def after_type_save(_params, options)
    # workflow copy
    if options[:copy_workflow_from].present? && (copy_from = ::Type.find_by(id: options[:copy_workflow_from]))
      type.workflows.copy_from_type(copy_from)
    end
  end
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'
require 'services/shared_type_service'

RSpec.describe CreateTypeService do
  let(:type) { instance.type }
  let(:user) { build_stubbed(:admin) }

  let(:instance) { described_class.new(user) }
  let(:service_call) { instance.call({ name: 'foo' }.merge(params), {}) }

  it_behaves_like 'type service'
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

##
# Create journal for the given user and note.
# Does not change the work package itself.

class AddWorkPackageNoteService
  include Contracted
  attr_accessor :user, :work_package

  def initialize(user:, work_package:)
    self.user = user
    self.work_package = work_package
    self.contract_class = WorkPackages::CreateNoteContract
  end

  def call(notes, send_notifications: nil)
    Journal::NotificationConfiguration.with send_notifications do
      work_package.add_journal(user:, notes:)

      success, errors = validate_and_yield(work_package, user) do
        work_package.save_journals
      end

      if success
        # In test environment, because of the difference in the way of handling transactions,
        # the journal needs to be actively loaded without SQL caching in place.
        journal = Journal.connection.uncached do
          work_package.journals.last
        end
      end

      ServiceResult.new(success:, result: journal, errors:)
    end
  end
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'

RSpec.describe AddWorkPackageNoteService, type: :model do
  let(:user) { build_stubbed(:user) }
  let(:work_package) { build_stubbed(:work_package) }
  let(:instance) do
    described_class.new(user:,
                        work_package:)
  end

  describe '.contract' do
    it 'uses the CreateNoteContract contract' do
      expect(instance.contract_class).to eql WorkPackages::CreateNoteContract
    end
  end

  describe 'call' do
    let(:mock_contract) do
      double(WorkPackages::CreateNoteContract,
             new: mock_contract_instance)
    end
    let(:mock_contract_instance) do
      double(WorkPackages::CreateNoteContract,
             errors: contract_errors,
             validate: valid_contract)
    end
    let(:valid_contract) { true }
    let(:contract_errors) do
      double('contract errors')
    end

    let(:send_notifications) { false }

    before do
      expect(Journal::NotificationConfiguration)
        .to receive(:with)
        .with(send_notifications)
        .and_yield

      allow(instance).to receive(:contract_class).and_return(mock_contract)
      allow(work_package).to receive(:save_journals).and_return true
    end

    subject { instance.call('blubs', send_notifications:) }

    it 'is successful' do
      expect(subject).to be_success
    end

    it 'persists the value' do
      expect(work_package).to receive(:save_journals).and_return true

      subject
    end

    it 'has no errors' do
      expect(subject.errors).to be_empty
    end

    context 'when the contract does not validate' do
      let(:valid_contract) { false }

      it 'is unsuccessful' do
        expect(subject.success?).to be_falsey
      end

      it 'does not persist the changes' do
        expect(work_package).not_to receive(:save_journals)

        subject
      end

      it "exposes the contract's errors" do
        errors = double('errors')
        allow(mock_contract_instance).to receive(:errors).and_return(errors)

        subject

        expect(subject.errors).to eql errors
      end
    end

    context 'when the saving is unsuccessful' do
      before do
        expect(work_package).to receive(:save_journals).and_return false
      end

      it 'is unsuccessful' do
        expect(subject).not_to be_success
      end

      it 'leaves the value unchanged' do
        subject

        expect(work_package.journal_notes).to eql 'blubs'
        expect(work_package.journal_user).to eql user
      end

      it "exposes the work_packages's errors" do
        errors = double('errors')
        allow(work_package).to receive(:errors).and_return(errors)

        subject

        expect(subject.errors).to eql errors
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class UpdateTypeService < BaseTypeService
  def call(params)
    # forbid renaming if it is a standard type
    if params[:type] && type.is_standard?
      params[:type].delete :name
    end

    super(params, {})
  end
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'
require 'services/shared_type_service'

RSpec.describe UpdateTypeService do
  let(:type) { create(:type) }
  let(:user) { build_stubbed(:admin) }

  let(:instance) { described_class.new(type, user) }
  let(:service_call) { instance.call(params) }

  let(:valid_group) { { 'type' => 'attribute', 'name' => 'foo', 'attributes' => ['date'] } }

  it_behaves_like 'type service'

  describe "#validate_attribute_groups" do
    let(:params) { { name: 'blubs blubs' } }

    it 'raises an exception for invalid structure' do
      # Example for invalid structure:
      result = instance.call(attribute_groups: ['foo'])
      expect(result.success?).to be_falsey
      # Example for invalid structure:
      result = instance.call(attribute_groups: [[]])
      expect(result.success?).to be_falsey
      # Example for invalid group name:
      result = instance.call(attribute_groups: [['', ['date']]])
      expect(result.success?).to be_falsey
    end

    it 'fails for duplicate group names' do
      result = instance.call(attribute_groups: [valid_group, valid_group])
      expect(result.success?).to be_falsey
      expect(result.errors[:attribute_groups].first).to include 'used more than once.'
    end

    it 'passes validations for known attributes' do
      expect(type).to receive(:save).and_return(true)
      result = instance.call(attribute_groups: [valid_group])
      expect(result.success?).to be_truthy
    end

    it 'passes validation for defaults' do
      expect(type).to be_valid
    end

    it 'passes validation for reset' do
      # A reset is to save an empty Array
      expect(type).to receive(:save).and_return(true)
      result = instance.call(attribute_groups: [])
      expect(result.success?).to be_truthy
      expect(type).to be_valid
    end

    context 'with an invalid query' do
      let(:params) { { attribute_groups: [{ 'type' => 'query', name: 'some name', query: 'wat' }] } }

      it 'is invalid' do
        expect(service_call.success?).to be_falsey
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class ServiceResult
  SUCCESS = true
  FAILURE = false

  attr_accessor :success,
                :result,
                :errors,
                :dependent_results

  attr_writer :state

  # Creates a successful ServiceResult.
  def self.success(errors: nil,
                   message: nil,
                   message_type: nil,
                   state: nil,
                   dependent_results: [],
                   result: nil)
    new(success: SUCCESS,
        errors:,
        message:,
        message_type:,
        state:,
        dependent_results:,
        result:)
  end

  # Creates a failed ServiceResult.
  def self.failure(errors: nil,
                   message: nil,
                   message_type: nil,
                   state: nil,
                   dependent_results: [],
                   result: nil)
    new(success: FAILURE,
        errors:,
        message:,
        message_type:,
        state:,
        dependent_results:,
        result:)
  end

  def initialize(success: false,
                 errors: nil,
                 message: nil,
                 message_type: nil,
                 state: nil,
                 dependent_results: [],
                 result: nil)
    self.success = success
    self.result = result
    self.state = state

    initialize_errors(errors)
    @message = message
    @message_type = message_type

    self.dependent_results = dependent_results
  end

  alias success? :success

  def failure?
    !success?
  end

  ##
  # Merge another service result into this instance
  # allowing optionally to skip updating its service
  def merge!(other, without_success: false)
    merge_success!(other) unless without_success
    merge_errors!(other)
    merge_dependent!(other)
  end

  ##
  # Print messages to flash
  def apply_flash_message!(flash)
    if message
      flash[message_type] = message
    end
  end

  def all_results
    dependent_results.map(&:result).tap do |results|
      results.unshift result unless result.nil?
    end
  end

  def all_errors
    [errors] + dependent_results.map(&:errors)
  end

  ##
  # Test whether the returned errors respond
  # to the search key
  def includes_error?(attribute, error_key)
    all_errors.any? do |error|
      error.symbols_for(attribute).include?(error_key)
    end
  end

  ##
  # Collect all present errors for the given result
  # and dependent results.
  #
  # Returns a map of the service result to the error object
  def results_with_errors(include_self: true)
    results =
      if include_self
        [self] + dependent_results
      else
        dependent_results
      end

    results.reject { |call| call.errors.empty? }
  end

  def self_and_dependent
    [self] + dependent_results
  end

  def add_dependent!(dependent)
    merge_success!(dependent)

    inner_results = dependent.dependent_results
    dependent.dependent_results = []

    dependent_results << dependent
    self.dependent_results += inner_results
  end

  def on_success(&)
    tap(&) if success?
    self
  end

  def on_failure(&)
    tap(&) if failure?
    self
  end

  def each
    yield result if success?
    self
  end

  def map
    return self if failure?

    dup.tap do |new_result|
      new_result.result = yield result
    end
  end

  def to_a
    if success?
      [result]
    else
      []
    end
  end

  def message
    if @message
      @message
    elsif failure? && errors.is_a?(ActiveModel::Errors)
      errors.full_messages.join(" ")
    end
  end

  def state
    @state ||= ::Shared::ServiceState.build
  end

  private

  def initialize_errors(errors)
    self.errors = errors || new_errors_with_result
  end

  def new_errors_with_result
    ActiveModel::Errors.new(self).tap do |errors|
      errors.merge!(result) if result.try(:errors).present?
    end
  end

  def message_type
    if @message_type
      @message_type.to_sym
    elsif success?
      :notice
    else
      :error
    end
  end

  def merge_success!(other)
    self.success &&= other.success
  end

  def merge_errors!(other)
    errors.merge! other.errors
  end

  def merge_dependent!(other)
    self.dependent_results += other.dependent_results
  end
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'

RSpec.describe ServiceResult, type: :model do
  let(:instance) { described_class.new }

  describe 'success' do
    it 'is what the service is initialized with' do
      instance = described_class.new success: true

      expect(instance.success).to be_truthy
      expect(instance.success?).to be(true)

      instance = described_class.new success: false

      expect(instance.success).to be_falsey
      expect(instance.success?).to be(false)
    end

    it 'returns what is provided' do
      instance.success = true

      expect(instance.success).to be_truthy
      expect(instance.success?).to be(true)

      instance.success = false

      expect(instance.success).to be_falsey
      expect(instance.success?).to be(false)
    end

    it 'is false by default' do
      expect(instance.success).to be_falsey
      expect(instance.success?).to be(false)
    end
  end

  describe '.success' do
    it 'creates a ServiceResult with success: true' do
      instance = described_class.success
      expect(instance.success).to be_truthy
    end

    it 'accepts the same set of parameters as the initializer' do
      errors = ['errors']
      message = 'message'
      message_type = :message_type
      state = instance_double(Shared::ServiceState)
      dependent_results = ['dependent_results']
      result = instance_double(Object, 'result')

      instance = described_class.success(
        errors:,
        message:,
        message_type:,
        state:,
        dependent_results:,
        result:
      )

      expect(instance.errors).to be(errors)
      expect(instance.message).to be(message)
      expect(instance.state).to be(state)
      expect(instance.dependent_results).to be(dependent_results)
      expect(instance.result).to be(result)
    end
  end

  describe '.failure' do
    it 'creates a ServiceResult with success: false' do
      instance = described_class.failure
      expect(instance.success).to be_falsy
    end

    it 'accepts the same set of parameters as the initializer' do
      errors = ['errors']
      message = 'message'
      message_type = :message_type
      state = instance_double(Shared::ServiceState)
      dependent_results = ['dependent_results']
      result = instance_double(Object, 'result')

      instance = described_class.failure(
        errors:,
        message:,
        message_type:,
        state:,
        dependent_results:,
        result:
      )

      expect(instance.errors).to be(errors)
      expect(instance.message).to be(message)
      expect(instance.state).to be(state)
      expect(instance.dependent_results).to be(dependent_results)
      expect(instance.result).to be(result)
    end
  end

  describe 'errors' do
    let(:errors) { ['errors'] }

    it 'is what has been provided' do
      instance.errors = errors

      expect(instance.errors).to eql errors
    end

    it 'is what the object is initialized with' do
      instance = described_class.new(errors:)

      expect(instance.errors).to eql errors
    end

    it 'is an empty ActiveModel::Errors by default' do
      expect(instance.errors).to be_a ActiveModel::Errors
    end

    context 'when providing errors from user' do
      let(:result) { build(:work_package) }

      it 'creates a new errors instance' do
        instance = described_class.new(result:)
        expect(instance.errors).not_to eq result.errors
      end
    end
  end

  describe 'result' do
    let(:result) { instance_double(Object, 'result') }

    it 'is what the object is initialized with' do
      instance = described_class.new(result:)

      expect(instance.result).to eql result
    end

    it 'is what has been provided' do
      instance.result = result

      expect(instance.result).to eql result
    end

    it 'is nil by default' do
      instance = described_class.new

      expect(instance.result).to be_nil
    end
  end

  describe 'apply_flash_message!' do
    let(:message) { 'some message' }

    subject(:flash) do
      {}.tap { service_result.apply_flash_message!(_1) }
    end

    context 'when successful' do
      let(:service_result) { described_class.success(message:) }

      it { is_expected.to include(notice: message) }
    end

    context 'when failure' do
      let(:service_result) { described_class.failure(message:) }

      it { is_expected.to include(error: message) }
    end

    context 'when setting message_type to :info' do
      let(:service_result) { described_class.success(message:, message_type: :info) }

      it { is_expected.to include(info: message) }
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class ParseSchemaFilterParamsService
  extend ActiveModel::Naming
  extend ActiveModel::Translation

  attr_accessor :user

  def self.i18n_scope
    :activerecord
  end

  def initialize(user:)
    self.user = user
  end

  def call(filter)
    error_message = check_error_in_filter(filter)

    if error_message
      error(error_message)
    else
      pairs = valid_project_type_pairs(filter)

      success(pairs)
    end
  end

  private

  def check_error_in_filter(filter)
    if !filter.first['id']
      :id_filter_required
    elsif filter.first['id']['operator'] != '='
      :unsupported_operator
    elsif filter.first['id']['values'].any? { |id_string| !id_string.match(/\d+-\d+/) }
      :invalid_values
    end
  end

  def parse_ids(filter)
    ids_string = filter.first['id']['values']

    ids_string.map do |id_string|
      id_string.split('-')
    end
  end

  def error(message)
    errors = ActiveModel::Errors.new(self)
    errors.add(:base, message)
    ServiceResult.failure(errors:)
  end

  def success(result)
    ServiceResult.success(result:)
  end

  def valid_project_type_pairs(filter)
    ids = parse_ids(filter)

    projects_map = projects_by_id(ids.map(&:first))
    types_map = types_by_id(ids.map(&:last))

    valid_ids = only_valid_pairs(ids, projects_map, types_map)

    string_pairs_to_object_pairs(valid_ids, projects_map, types_map)
  end

  def projects_by_id(ids)
    Project.visible(user).where(id: ids).group_by(&:id)
  end

  def types_by_id(ids)
    Type.where(id: ids).group_by(&:id)
  end

  def only_valid_pairs(id_pairs, projects_map, types_map)
    id_pairs.reject do |project_id, type_id|
      projects_map[project_id.to_i].nil? || types_map[type_id.to_i].nil?
    end
  end

  def string_pairs_to_object_pairs(string_pairs, projects_map, types_map)
    string_pairs.map do |project_id, type_id|
      [projects_map[project_id.to_i].first, types_map[type_id.to_i].first]
    end
  end
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.

require 'spec_helper'

RSpec.describe ParseSchemaFilterParamsService do
  let(:current_user) { build_stubbed(:user) }
  let(:instance) { described_class.new(user: current_user) }
  let(:project) { build_stubbed(:project) }
  let(:type) { build_stubbed(:type) }

  describe '#call' do
    let(:filter) do
      [{ 'id' => { 'values' => ["#{project.id}-#{type.id}"], 'operator' => '=' } }]
    end
    let(:result) { instance.call(filter) }

    let(:found_projects) { [project] }
    let(:found_types) { [type] }

    before do
      visible_projects = double('visible_projects')

      allow(Project)
        .to receive(:visible)
        .with(current_user)
        .and_return(visible_projects)

      allow(visible_projects)
        .to receive(:where)
        .with(id: [project.id.to_s])
        .and_return(found_projects)

      allow(Type)
        .to receive(:where)
        .with(id: [type.id.to_s])
        .and_return(found_types)
    end

    context 'valid' do
      it 'is a success' do
        expect(result).to be_success
      end

      it 'returns the [project, type] pair' do
        expect(result.result).to match_array [[project, type]]
      end
    end

    context 'for a non existing project' do
      let(:found_projects) { [] }

      it 'is a success' do
        expect(result).to be_success
      end

      it 'returns an empty array' do
        expect(result.result).to match_array []
      end
    end

    context 'for a non existing type' do
      let(:found_types) { [] }

      it 'is a success' do
        expect(result).to be_success
      end

      it 'returns an empty array' do
        expect(result.result).to match_array []
      end
    end

    context 'without the "=" operator' do
      let(:filter) do
        [{ 'id' => { 'values' => ["#{project.id}-#{type.id}"], 'operator' => '!' } }]
      end

      it 'is a failure' do
        expect(result).not_to be_success
      end

      it 'returns an empty array' do
        expect(result.result).to be_nil
      end

      it 'returns an error message' do
        expect(result.errors.messages[:base]).to match_array ['The operator is not supported.']
      end
    end

    context 'with an invalid value' do
      let(:filter) do
        [{ 'id' => { 'values' => ["bogus-1"], 'operator' => "=" } }]
      end

      it 'is a failure' do
        expect(result).not_to be_success
      end

      it 'returns an empty array' do
        expect(result.result).to be_nil
      end

      it 'returns an error message' do
        expect(result.errors.messages[:base]).to match_array ['A value is invalid.']
      end
    end

    context 'without an id filter' do
      let(:filter) do
        [{}]
      end

      it 'is a failure' do
        expect(result).not_to be_success
      end

      it 'returns an empty array' do
        expect(result.result).to be_nil
      end

      it 'returns an error message' do
        expect(result.errors.messages[:base]).to match_array ['An \'id\' filter is required.']
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

# -- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
# ++
#

class Settings::LanguageUpdateService < Settings::UpdateService
  def after_perform(call)
    force_users_to_use_only_available_languages

    call
  end

  private

  def force_users_to_use_only_available_languages
    User.where.not(language: Setting.available_languages)
        .update_all(language: Setting.default_language)
  end
end

```

Response:
# frozen_string_literal: true

# -- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
# ++
#

require 'spec_helper'

RSpec.describe Settings::LanguageUpdateService do
  let(:service) do
    described_class.new(user: build_stubbed(:admin))
  end
  let(:available_languages) { %w[de fr] }

  before do
    allow(service).to receive(:force_users_to_use_only_available_languages)
  end

  it 'sets language of users having a non-available language to the default language' do
    service.call(available_languages:)

    expect(service)
      .to have_received(:force_users_to_use_only_available_languages)
  end

  context 'when the contract is not successfully validated' do
    before do
      allow(service)
        .to receive(:validate_contract)
        .and_return(ServiceResult.failure(message: 'fake error'))
    end

    it 'does not change language of any users' do
      service.call(available_languages:)

      expect(service)
        .not_to have_received(:force_users_to_use_only_available_languages)
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2022 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTALITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class Settings::WorkingDaysUpdateService < Settings::UpdateService
  def call(params)
    params = params.to_h.deep_symbolize_keys
    self.non_working_days_params = params.delete(:non_working_days) || []
    self.previous_working_days = Setting[:working_days]
    self.previous_non_working_days = NonWorkingDay.pluck(:date)
    super
  end

  def validate_params(params)
    contract = Settings::WorkingDaysParamsContract.new(model, user, params:)
    ServiceResult.new success: contract.valid?,
                      errors: contract.errors,
                      result: model
  end

  def persist(call)
    results = call
    ActiveRecord::Base.transaction do
      # The order of merging the service is important to preserve
      # the errors model's base object, which is a NonWorkingDay
      results = persist_non_working_days
      results.merge!(super) if results.success?

      raise ActiveRecord::Rollback if results.failure?
    end

    results
  end

  def after_perform(call)
    super.tap do
      WorkPackages::ApplyWorkingDaysChangeJob.perform_later(
        user_id: User.current.id,
        previous_working_days:,
        previous_non_working_days:
      )
    end
  end

  private

  attr_accessor :non_working_days_params, :previous_working_days, :previous_non_working_days

  def persist_non_working_days
    # We don't support update for now
    to_create, to_delete = attributes_to_create_and_delete
    results = destroy_records(to_delete)
    create_results = create_records(to_create)
    results.merge!(create_results)
    results.result = Array(results.result) + Array(create_results.result)
    results
  end

  def attributes_to_create_and_delete
    non_working_days_params.reduce([[], []]) do |results, nwd|
      results.first << nwd if !nwd[:id]
      results.last << nwd[:id] if nwd[:_destroy] && nwd[:id]
      results
    end
  end

  def create_records(attributes)
    wrap_result(attributes.map { |attrs| NonWorkingDay.create(attrs) })
  end

  def destroy_records(ids)
    records = NonWorkingDay.where(id: ids)
    # In case the transaction fails we also mark the records for destruction,
    # this way we can display them correctly on the frontend.
    records.each(&:mark_for_destruction)
    wrap_result records.destroy_all
  end

  def wrap_result(result)
    model = NonWorkingDay.new
    errors = model.errors.tap do |err|
      result.each do |r|
        err.merge!(r.errors)
      end
    end
    success = model.errors.empty?

    ServiceResult.new(success:, errors:, result:)
  end
end

```

Response:
#  OpenProject is an open source project management software.
#  Copyright (C) 2010-2022 the OpenProject GmbH
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License version 3.
#
#  OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
#  Copyright (C) 2006-2013 Jean-Philippe Lang
#  Copyright (C) 2010-2013 the ChiliProject Team
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
#  See COPYRIGHT and LICENSE files for more details.

require 'spec_helper'
require_relative 'shared/shared_call_examples'

RSpec.describe Settings::WorkingDaysUpdateService do
  let(:instance) do
    described_class.new(user:)
  end
  let(:user) { build_stubbed(:user) }
  let(:contract) do
    instance_double(Settings::UpdateContract,
                    validate: contract_success,
                    errors: instance_double(ActiveModel::Error))
  end
  let(:contract_success) { true }
  let(:params_contract) do
    instance_double(Settings::WorkingDaysParamsContract,
                    valid?: params_contract_success,
                    errors: instance_double(ActiveModel::Error))
  end
  let(:params_contract_success) { true }
  let(:setting_name) { :a_setting_name }
  let(:new_setting_value) { 'a_new_setting_value' }
  let(:previous_setting_value) { 'the_previous_setting_value' }
  let(:setting_params) { { setting_name => new_setting_value } }
  let(:non_working_days_params) { {} }
  let(:params) { setting_params.merge(non_working_days: non_working_days_params) }

  before do
    # stub a setting definition
    allow(Setting)
      .to receive(:[])
          .and_call_original
    allow(Setting)
      .to receive(:[]).with(setting_name)
          .and_return(previous_setting_value)
    allow(Setting)
      .to receive(:[]=)

    # stub contract
    allow(Settings::UpdateContract)
      .to receive(:new)
          .and_return(contract)
    allow(Settings::WorkingDaysParamsContract)
      .to receive(:new)
          .and_return(params_contract)
  end

  describe '#call' do
    subject { instance.call(params) }

    shared_examples 'successful working days settings call' do
      include_examples 'successful call'

      it 'calls the WorkPackages::ApplyWorkingDaysChangeJob' do
        previous_working_days = Setting[:working_days]
        previous_non_working_days = NonWorkingDay.pluck(:date)

        allow(WorkPackages::ApplyWorkingDaysChangeJob).to receive(:perform_later)

        subject

        expect(WorkPackages::ApplyWorkingDaysChangeJob)
          .to have_received(:perform_later)
          .with(user_id: user.id, previous_working_days:, previous_non_working_days:)
      end
    end

    shared_examples 'unsuccessful working days settings call' do
      include_examples 'unsuccessful call'

      it 'does not persists the non working days' do
        expect { subject }.not_to change(NonWorkingDay, :count)
      end

      it 'does not calls the WorkPackages::ApplyWorkingDaysChangeJob' do
        allow(WorkPackages::ApplyWorkingDaysChangeJob).to receive(:perform_later)
        subject

        expect(WorkPackages::ApplyWorkingDaysChangeJob).not_to have_received(:perform_later)
      end
    end

    include_examples 'successful working days settings call'

    context 'when non working days are present' do
      let!(:existing_nwd) { create(:non_working_day, name: 'Existing NWD') }
      let!(:nwd_to_delete) { create(:non_working_day, name: 'NWD to delete') }
      let(:non_working_days_params) do
        [
          { 'name' => 'Christmas Eve', 'date' => '2022-12-24' },
          { 'name' => 'NYE', 'date' => '2022-12-31' },
          { 'id' => existing_nwd.id },
          { 'id' => nwd_to_delete.id, '_destroy' => true }
        ]
      end

      include_examples 'successful working days settings call'

      it 'persists (create/delete) the non working days' do
        expect { subject }.to change(NonWorkingDay, :count).by(1)

        expect { nwd_to_delete.reload }.to raise_error(ActiveRecord::RecordNotFound)

        expect(NonWorkingDay.all).to contain_exactly(
          have_attributes(name: 'Christmas Eve', date: Date.parse('2022-12-24')),
          have_attributes(name: 'NYE', date: Date.parse('2022-12-31')),
          have_attributes(existing_nwd.slice(:id, :name, :date))
        )
      end

      context 'when there are duplicates' do
        context 'with both within the params' do
          let(:non_working_days_params) do
            [
              { 'name' => 'Christmas Eve', 'date' => '2022-12-24' },
              { 'name' => 'Christmas Eve', 'date' => '2022-12-24' }
            ]
          end

          include_examples 'unsuccessful working days settings call'
        end

        context 'with one saved in the database' do
          let(:non_working_days_params) do
            [existing_nwd.slice(:name, :date)]
          end

          include_examples 'unsuccessful working days settings call'

          context 'when deleting and re-creating the duplicate non-working day' do
            let(:non_working_days_params) do
              [
                nwd_to_delete.slice(:id, :name, :date).merge('_destroy' => true),
                nwd_to_delete.slice(:name, :date)
              ]
            end

            include_examples 'successful working days settings call'

            it 'persists (create/delete) the non working days' do
              expect { subject }.not_to change(NonWorkingDay, :count)
              expect { nwd_to_delete.reload }.to raise_error(ActiveRecord::RecordNotFound)

              # The nwd_to_delete is being re-created after the deletion.
              expect(NonWorkingDay.all).to contain_exactly(
                have_attributes(existing_nwd.slice(:name, :date)),
                have_attributes(nwd_to_delete.slice(:name, :date))
              )
            end
          end

          context 'with duplicate params when deleting and re-creating non-working days' do
            let(:non_working_days_params) do
              [
                existing_nwd.slice(:id, :name, :date).merge('_destroy' => true),
                existing_nwd.slice(:name, :date),
                existing_nwd.slice(:name, :date)
              ]
            end

            include_examples 'unsuccessful working days settings call'

            it 'returns the unchanged results including the ones marked for destruction' do
              result = subject.result

              expect(result).to contain_exactly(
                have_attributes(existing_nwd.slice(:id, :name, :date)),
                have_attributes(existing_nwd.slice(:name, :date).merge(id: nil)),
                have_attributes(existing_nwd.slice(:name, :date).merge(id: nil))
              )

              expect(result.find { |r| r.id == existing_nwd.id }).to be_marked_for_destruction
            end
          end
        end
      end
    end

    context 'when the params contract is not successfully validated' do
      let(:params_contract_success) { false }

      include_examples 'unsuccessful working days settings call'
    end

    context 'when the contract is not successfully validated' do
      let(:contract_success) { false }

      include_examples 'unsuccessful working days settings call'

      context 'when non working days are present' do
        let(:non_working_days_params) do
          [
            { 'name' => 'Christmas Eve', 'date' => '2022-12-24' },
            { 'name' => 'NYE', 'date' => '2022-12-31' }
          ]
        end

        include_examples 'unsuccessful working days settings call'
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class Settings::UpdateService < BaseServices::BaseContracted
  def initialize(user:)
    super user:,
          contract_class: Settings::UpdateContract
  end

  def persist(call)
    params.each do |name, value|
      set_setting_value(name, value)
    end
    call
  end

  private

  def set_setting_value(name, value)
    Setting[name] = derive_value(value)
  end

  def derive_value(value)
    case value
    when Array, Hash
      # remove blank values in array, hash settings
      value.compact_blank!
    else
      value.strip
    end
  end
end

```

Response:
#  OpenProject is an open source project management software.
#  Copyright (C) 2010-2022 the OpenProject GmbH
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License version 3.
#
#  OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
#  Copyright (C) 2006-2013 Jean-Philippe Lang
#  Copyright (C) 2010-2013 the ChiliProject Team
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
#  See COPYRIGHT and LICENSE files for more details.

require 'spec_helper'
require_relative 'shared/shared_call_examples'
require_relative 'shared/shared_setup_context'

RSpec.describe Settings::UpdateService do
  include_context 'with update service setup'

  describe '#call' do
    subject { instance.call(params) }

    include_examples 'successful call'

    context 'when the contract is not successfully validated' do
      let(:contract_success) { false }

      include_examples 'unsuccessful call'
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module PlaceholderUsers
  class SetAttributesService < ::BaseServices::SetAttributes
  end
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'

RSpec.describe PlaceholderUsers::SetAttributesService, type: :model do
  let(:current_user) { build_stubbed(:user) }

  let(:contract_instance) do
    contract = double('contract_instance')
    allow(contract)
      .to receive(:validate)
      .and_return(contract_valid)
    allow(contract)
      .to receive(:errors)
      .and_return(contract_errors)
    contract
  end

  let(:contract_errors) { double('contract_errors') }
  let(:contract_valid) { true }
  let(:model_valid) { true }

  let(:instance) do
    described_class.new(user: current_user,
                        model: model_instance,
                        contract_class:,
                        contract_options: {})
  end
  let(:model_instance) { PlaceholderUser.new }
  let(:contract_class) do
    allow(PlaceholderUsers::CreateContract)
      .to receive(:new)
      .and_return(contract_instance)

    PlaceholderUsers::CreateContract
  end

  let(:params) { {} }

  before do
    allow(model_instance)
      .to receive(:valid?)
      .and_return(model_valid)
  end

  subject { instance.call(params) }

  it 'returns the instance as the result' do
    expect(subject.result)
      .to eql model_instance
  end

  it 'is a success' do
    expect(subject)
      .to be_success
  end

  context 'with params' do
    let(:params) do
      {
        name: 'Foobar'
      }
    end

    it 'assigns the params' do
      subject

      expect(model_instance.name).to eq 'Foobar'
      expect(model_instance.lastname).to eq 'Foobar'
    end
  end

  context 'with an invalid contract' do
    let(:contract_valid) { false }
    let(:expect_time_instance_save) do
      expect(model_instance)
        .not_to receive(:save)
    end

    it 'returns failure' do
      expect(subject)
        .not_to be_success
    end

    it "returns the contract's errors" do
      expect(subject.errors)
        .to eql(contract_errors)
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class PlaceholderUsers::UpdateService < BaseServices::Update
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'
require 'services/base_services/behaves_like_update_service'

RSpec.describe PlaceholderUsers::UpdateService, type: :model do
  it_behaves_like 'BaseServices update service'
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class PlaceholderUsers::CreateService < BaseServices::Create
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'
require 'services/base_services/behaves_like_create_service'

RSpec.describe PlaceholderUsers::CreateService, type: :model do
  it_behaves_like 'BaseServices create service'
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class PlaceholderUsers::DeleteService < BaseServices::Delete
  def destroy(placeholder)
    placeholder.locked!
    ::Principals::DeleteJob.perform_later(placeholder)

    true
  end
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'

RSpec.describe PlaceholderUsers::DeleteService, type: :model do
  let(:placeholder_user) { build_stubbed(:placeholder_user) }
  let(:project) { build_stubbed(:project) }

  let(:instance) { described_class.new(model: placeholder_user, user: actor) }

  subject { instance.call }

  shared_examples 'deletes the user' do
    it do
      expect(placeholder_user).to receive(:locked!)
      expect(Principals::DeleteJob).to receive(:perform_later).with(placeholder_user)
      expect(subject).to be_success
    end
  end

  shared_examples 'does not delete the user' do
    it do
      expect(placeholder_user).not_to receive(:locked!)
      expect(Principals::DeleteJob).not_to receive(:perform_later)
      expect(subject).not_to be_success
    end
  end

  context 'with admin user' do
    let(:actor) { build_stubbed(:admin) }

    it_behaves_like 'deletes the user'
  end

  context 'with global user' do
    let(:actor) { build_stubbed(:user) }

    before do
      mock_permissions_for(actor) do |mock|
        mock.allow_globally :manage_placeholder_user
      end
    end

    it_behaves_like 'deletes the user'
  end

  context 'with unprivileged system user' do
    let(:actor) { User.system }

    before do
      allow(actor).to receive(:admin?).and_return false
    end

    it_behaves_like 'does not delete the user'
  end

  context 'with privileged system user' do
    let(:actor) { User.system }

    it_behaves_like 'deletes the user' do
      around do |example|
        actor.run_given { example.run }
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

# TODO: This is but a stub
module Messages
  class SetAttributesService < ::BaseServices::SetAttributes
    include Attachments::SetReplacements

    private

    def set_default_attributes(*)
      set_default_author
    end

    def set_default_author
      model.change_by_system do
        model.author = user
      end
    end
  end
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'

RSpec.describe Messages::SetAttributesService, type: :model do
  let(:user) { build_stubbed(:user) }
  let(:forum) { build_stubbed(:forum) }
  let(:contract_instance) do
    contract = double('contract_instance')
    allow(contract)
      .to receive(:validate)
      .and_return(contract_valid)
    allow(contract)
      .to receive(:errors)
      .and_return(contract_errors)
    contract
  end

  let(:contract_errors) { double('contract_errors') }
  let(:contract_valid) { true }
  let(:time_entry_valid) { true }

  let(:instance) do
    described_class.new(user:,
                        model: message_instance,
                        contract_class:,
                        contract_options: {})
  end
  let(:message_instance) { Message.new }
  let(:contract_class) do
    allow(Messages::CreateContract)
      .to receive(:new)
      .with(message_instance, user, options: {})
      .and_return(contract_instance)

    Messages::CreateContract
  end

  let(:params) { {} }

  before do
    allow(message_instance)
      .to receive(:valid?)
      .and_return(time_entry_valid)
  end

  subject { instance.call(params) }

  it 'returns the message instance as the result' do
    expect(subject.result)
      .to eql message_instance
  end

  it 'is a success' do
    expect(subject)
      .to be_success
  end

  it "has the service's user assigned as author" do
    subject

    expect(message_instance.author)
      .to eql user
  end

  it 'notes the author to be system changed' do
    subject

    expect(message_instance.changed_by_system['author_id'])
      .to eql [nil, user.id]
  end

  context 'with params' do
    let(:params) do
      {
        forum:
      }
    end

    let(:expected) do
      {
        author_id: user.id,
        forum_id: forum.id
      }.with_indifferent_access
    end

    it 'assigns the params' do
      subject

      attributes_of_interest = message_instance
                                 .attributes
                                 .slice(*expected.keys)

      expect(attributes_of_interest)
        .to eql(expected)
    end
  end

  context 'with an invalid contract' do
    let(:contract_valid) { false }
    let(:expect_time_instance_save) do
      expect(message_instance)
        .not_to receive(:save)
    end

    it 'returns failure' do
      expect(subject)
        .not_to be_success
    end

    it "returns the contract's errors" do
      expect(subject.errors)
        .to eql(contract_errors)
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class Messages::UpdateService < BaseServices::Update
  include Attachments::ReplaceAttachments
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'
require 'services/base_services/behaves_like_update_service'

RSpec.describe Messages::UpdateService, type: :model do
  it_behaves_like 'BaseServices update service'
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class Messages::CreateService < BaseServices::Create
  include Attachments::ReplaceAttachments
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'
require 'services/base_services/behaves_like_create_service'

RSpec.describe Messages::CreateService, type: :model do
  it_behaves_like 'BaseServices create service'
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class Relations::UpdateService < Relations::BaseService
  attr_accessor :model

  def initialize(user:, model:)
    super(user:)
    self.model = model
    self.contract_class = Relations::UpdateContract
  end

  def perform(attributes)
    in_user_context(send_notifications: attributes[:send_notifications]) do
      update_relation model, attributes
    end
  end
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'

RSpec.describe Relations::UpdateService do
  let(:work_package1_start_date) { nil }
  let(:work_package1_due_date) { Date.today }
  let(:work_package2_start_date) { nil }
  let(:work_package2_due_date) { nil }

  let(:follows_relation) { false }
  let(:delay) { 3 }

  let(:work_package1) do
    build_stubbed(:work_package,
                  due_date: work_package1_due_date,
                  start_date: work_package1_start_date)
  end
  let(:work_package2) do
    build_stubbed(:work_package,
                  due_date: work_package2_due_date,
                  start_date: work_package2_start_date)
  end
  let(:instance) do
    described_class.new(user:, model: relation)
  end
  let(:relation) do
    relation = build_stubbed(:relation)

    allow(relation)
      .to receive(:follows?)
      .and_return(follows_relation)

    relation
  end
  let(:attributes) do
    {
      to: work_package1,
      from: work_package2,
      delay:
    }
  end

  let(:user) { build_stubbed(:user) }
  let(:model_valid) { true }
  let(:contract_valid) { true }
  let(:contract) { double('contract') }
  let(:symbols_for_base) { [] }

  subject do
    instance.call(attributes:)
  end

  before do
    allow(relation)
      .to receive(:save)
      .and_return(model_valid)

    allow(Relations::UpdateContract)
      .to receive(:new)
      .with(relation, user, options: {})
      .and_return(contract)
    allow(contract)
      .to receive(:validate)
      .and_return(contract_valid)
  end

  context 'when all valid and it is a follows relation' do
    let(:set_schedule_service) { double('set schedule service') }
    let(:set_schedule_work_package2_result) do
      ServiceResult.success result: work_package2, errors: work_package2.errors
    end
    let(:set_schedule_result) do
      sr = ServiceResult.success result: work_package2, errors: work_package2.errors
      sr.dependent_results << set_schedule_work_package2_result
      sr
    end

    let(:follows_relation) { true }

    before do
      expect(WorkPackages::SetScheduleService)
        .to receive(:new)
        .with(user:, work_package: work_package1)
        .and_return(set_schedule_service)

      expect(set_schedule_service)
        .to receive(:call)
        .and_return(set_schedule_result)

      allow(work_package2)
        .to receive(:changed?)
        .and_return(true)

      expect(work_package2)
        .to receive(:save)
        .and_return(true)

      allow(set_schedule_result)
        .to receive(:success=)
    end

    it 'is successful' do
      expect(subject)
        .to be_success
    end

    it 'returns the relation' do
      expect(subject.result)
        .to eql relation
    end

    it 'has a dependent result for the from-work package' do
      expect(subject.dependent_results)
        .to match_array [set_schedule_work_package2_result]
    end
  end

  context 'when all is valid and it is not a follows relation' do
    it 'is successful' do
      expect(subject)
        .to be_success
    end

    it 'returns the relation' do
      expect(subject.result)
        .to eql relation
    end
  end

  context 'when the contract is invalid' do
    let(:contract_valid) { false }
    let(:contract_errors) { double('contract_errors') }

    before do
      allow(contract)
        .to receive(:errors)
        .and_return(contract_errors)
      allow(contract_errors)
        .to receive(:symbols_for)
        .with(:base)
        .and_return(symbols_for_base)
    end

    it 'is unsuccessful' do
      expect(subject)
        .to be_failure
    end

    it "returns the contract's errors" do
      expect(subject.errors)
        .to eql contract_errors
    end
  end

  context 'when the model is invalid' do
    let(:model_valid) { false }
    let(:model_errors) { double('model_errors') }

    before do
      allow(relation)
        .to receive(:errors)
        .and_return(model_errors)
      allow(model_errors)
        .to receive(:symbols_for)
        .with(:base)
        .and_return(symbols_for_base)
    end

    it 'is unsuccessful' do
      expect(subject)
        .to be_failure
    end

    it "returns the model's errors" do
      expect(subject.errors)
        .to eql model_errors
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

class Relations::CreateService < Relations::BaseService
  def initialize(user:)
    super
    self.contract_class = Relations::CreateContract
  end

  def perform(send_notifications: nil, **attributes)
    in_user_context(send_notifications:) do
      update_relation ::Relation.new, attributes
    end
  end
end

```

Response:
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

require 'spec_helper'

RSpec.describe Relations::CreateService do
  let(:work_package1_start_date) { nil }
  let(:work_package1_due_date) { Date.today }
  let(:work_package2_start_date) { nil }
  let(:work_package2_due_date) { nil }

  let(:follows_relation) { false }
  let(:delay) { 3 }

  let(:work_package1) do
    build_stubbed(:work_package,
                  due_date: work_package1_due_date,
                  start_date: work_package1_start_date)
  end
  let(:work_package2) do
    build_stubbed(:work_package,
                  due_date: work_package2_due_date,
                  start_date: work_package2_start_date)
  end
  let(:instance) do
    described_class.new(user:)
  end
  let(:relation) do
    relation = Relation.new attributes

    allow(relation)
      .to receive(:follows?)
      .and_return(follows_relation)

    relation
  end
  let(:attributes) do
    {
      to: work_package1,
      from: work_package2,
      delay:
    }
  end

  let(:user) { build_stubbed(:user) }
  let(:model_valid) { true }
  let(:contract_valid) { true }
  let(:contract) { double('contract') }
  let(:symbols_for_base) { [] }

  subject do
    instance.call(attributes)
  end

  before do
    allow(Relation)
      .to receive(:new)
            .and_return(relation)

    allow(relation)
      .to receive(:save)
      .and_return(model_valid)

    allow(Relations::CreateContract)
      .to receive(:new)
      .with(relation, user, options: {})
      .and_return(contract)
    allow(contract)
      .to receive(:validate)
      .and_return(contract_valid)
  end

  context 'if all valid and it is a follows relation' do
    let(:set_schedule_service) { double('set schedule service') }
    let(:set_schedule_work_package2_result) do
      ServiceResult.success result: work_package2, errors: work_package2.errors
    end
    let(:set_schedule_result) do
      sr = ServiceResult.success result: work_package2, errors: work_package2.errors
      sr.dependent_results << set_schedule_work_package2_result
      sr
    end

    let(:follows_relation) { true }

    before do
      expect(WorkPackages::SetScheduleService)
        .to receive(:new)
        .with(user:, work_package: work_package1)
        .and_return(set_schedule_service)

      expect(set_schedule_service)
        .to receive(:call)
        .and_return(set_schedule_result)

      allow(work_package2)
        .to receive(:changed?)
        .and_return(true)

      expect(work_package2)
        .to receive(:save)
        .and_return(true)

      allow(set_schedule_result)
        .to receive(:success=)
    end

    it 'is successful' do
      expect(subject)
        .to be_success
    end

    it 'returns the relation' do
      expect(subject.result)
        .to eql relation
    end

    it 'has a dependent result for the from-work package' do
      expect(subject.dependent_results)
        .to contain_exactly(set_schedule_work_package2_result)
    end
  end

  context 'if all is valid and it is not a follows relation' do
    it 'is successful' do
      expect(subject)
        .to be_success
    end

    it 'returns the relation' do
      expect(subject.result)
        .to eql relation
    end
  end

  context 'if the contract is invalid' do
    let(:contract_valid) { false }
    let(:contract_errors) { double('contract_errors') }

    before do
      allow(contract)
        .to receive(:errors)
        .and_return(contract_errors)
      allow(contract_errors)
        .to receive(:symbols_for)
        .with(:base)
        .and_return(symbols_for_base)
    end

    it 'is unsuccessful' do
      expect(subject)
        .to be_failure
    end

    it "returns the contract's errors" do
      expect(subject.errors)
        .to eql contract_errors
    end
  end

  context 'if the model is invalid' do
    let(:model_valid) { false }
    let(:model_errors) { double('model_errors') }

    before do
      allow(relation)
        .to receive(:errors)
        .and_return(model_errors)
      allow(model_errors)
        .to receive(:symbols_for)
        .with(:base)
        .and_return(symbols_for_base)
    end

    it 'is unsuccessful' do
      expect(subject)
        .to be_failure
    end

    it "returns the model's errors" do
      expect(subject.errors)
        .to eql model_errors
    end
  end
end