diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 5a85d72..18bc6b7 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -29,12 +29,17 @@ jobs: bundler-cache: true # runs 'bundle install' and caches installed gems automatically - name: Run tests - run: bundle exec rake + run: bundle exec rake spec # enable code coverage reporting env: COVERAGE: 'true' COVERAGE_LCOV: 'true' + - name: Run RuboCop + # only for latest version, it is dropping Ruby support fster than us + if: ${{ matrix.ruby-version == '3.4' }} + run: bundle exec rake rubocop + - name: Coveralls Report # send it only for the latest version to avoid duplicate submits if: ${{ matrix.ruby-version == '3.4' }} diff --git a/.rubocop.yml b/.rubocop.yml index 29eaec1..556df67 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,9 @@ +inherit_from: .rubocop_todo.yml + AllCops: TargetRubyVersion: 2.4 + SuggestExtensions: false + NewCops: enable Exclude: # Do not check code borrowed from ActiveSupport - 'lib/dbus/core_ext/**/*.rb' @@ -73,6 +77,11 @@ Lint/RescueException: Naming/PredicateName: NamePrefix: # has_ and have_ are allowed + - does_ + - is_ + ForbiddenPrefixes: + # has_ and have_ are allowed + - does_ - is_ # Offense count: 1 diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 0000000..b2265ae --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,151 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2025-04-03 13:59:12 UTC using RuboCop version 1.68.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: Include. +# Include: **/*.gemspec +Gemspec/AddRuntimeDependency: + Exclude: + - 'ruby-dbus.gemspec' + +# Offense count: 8 +# Configuration parameters: EnforcedStyle, AllowedGems, Include. +# SupportedStyles: Gemfile, gems.rb, gemspec +# Include: **/*.gemspec, **/Gemfile, **/gems.rb +Gemspec/DevelopmentDependencies: + Exclude: + - 'ruby-dbus.gemspec' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: Severity, Include. +# Include: **/*.gemspec +Gemspec/RequireMFA: + Exclude: + - 'ruby-dbus.gemspec' + +# Offense count: 3 +# Configuration parameters: AllowComments, AllowEmptyLambdas. +Lint/EmptyBlock: + Exclude: + - 'examples/utils/notify.rb' + - 'spec/object_spec.rb' + - 'spec/signal_spec.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Lint/IncompatibleIoSelectWithFiberScheduler: + Exclude: + - 'lib/dbus/message_queue.rb' + +# Offense count: 3 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/EnvHome: + Exclude: + - 'examples/no-introspect/tracker-test.rb' + - 'lib/dbus/auth.rb' + - 'lib/dbus/bus.rb' + +# Offense count: 10 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowedVars. +Style/FetchEnvVar: + Exclude: + - 'examples/no-introspect/tracker-test.rb' + - 'lib/dbus/auth.rb' + - 'lib/dbus/bus.rb' + - 'lib/dbus/logger.rb' + - 'spec/connection_spec.rb' + - 'spec/coverage_helper.rb' + - 'spec/session_bus_spec.rb' + - 'spec/spec_helper.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: AllowSplatArgument. +Style/HashConversion: + Exclude: + - 'lib/dbus/data.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/MapIntoArray: + Exclude: + - 'lib/dbus/marshall.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/MinMaxComparison: + Exclude: + - 'lib/dbus/auth.rb' + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +Style/NegatedIfElseCondition: + Exclude: + - 'lib/dbus/connection.rb' + +# Offense count: 3 +Style/OpenStructUse: + Exclude: + - 'spec/packet_marshaller_spec.rb' + - 'spec/packet_unmarshaller_spec.rb' + - 'spec/property_spec.rb' + +# Offense count: 5 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: Methods. +Style/RedundantArgument: + Exclude: + - 'lib/dbus/auth.rb' + - 'lib/dbus/introspect.rb' + - 'lib/dbus/object.rb' + +# Offense count: 4 +# This cop supports safe autocorrection (--autocorrect). +Style/RedundantConstantBase: + Exclude: + - 'spec/data_spec.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/RedundantEach: + Exclude: + - 'spec/type_spec.rb' + +# Offense count: 3 +# This cop supports safe autocorrection (--autocorrect). +Style/RedundantRegexpArgument: + Exclude: + - 'examples/service/service_newapi.rb' + - 'lib/dbus/object.rb' + - 'spec/mock-service/spaghetti-monster.rb' + +# Offense count: 2 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/StringChars: + Exclude: + - 'examples/service/service_newapi.rb' + - 'spec/mock-service/spaghetti-monster.rb' + +# Offense count: 6 +# This cop supports safe autocorrection (--autocorrect). +Style/SuperArguments: + Exclude: + - 'examples/service/complex-property.rb' + - 'lib/dbus/data.rb' + - 'lib/dbus/introspect.rb' + - 'spec/mock-service/spaghetti-monster.rb' + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +Style/SuperWithArgsParentheses: + Exclude: + - 'lib/dbus/object.rb' + - 'spec/mock-service/spaghetti-monster.rb' diff --git a/Gemfile b/Gemfile index dbd048c..6e5bcb7 100644 --- a/Gemfile +++ b/Gemfile @@ -4,6 +4,10 @@ source "https://rubygems.org" gemspec +gem "rubocop", "~> 1.68.0" if RUBY_VERSION >= "2.7" +# newer versions have a noise deprecation warning +gem "rubocop-ast", "~> 1.36.0" if RUBY_VERSION >= "2.7" + group :test do # Optional dependency, we do want to test with it gem "nokogiri" diff --git a/NEWS.md b/NEWS.md index 9b588f9..0e35592 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,14 @@ ## Unreleased +## Ruby D-Bus 0.25.0 - 2025-04-03 + +Bug fixes: + * Mention qualified property name in Get or Set errors ([#147][]). + * Fix declaring logger and ostruct gems for Ruby 3.5 + +[#147]: https://github.com/mvidner/ruby-dbus/pull/147 + ## Ruby D-Bus 0.24.0 - 2025-01-02 Bug fixes: diff --git a/Rakefile b/Rakefile index 2700379..beea722 100755 --- a/Rakefile +++ b/Rakefile @@ -4,7 +4,7 @@ require "rake" require "fileutils" require "tmpdir" -require "rspec/core/rake_task" +require "shellwords" begin require "rubocop/rake_task" rescue LoadError @@ -34,13 +34,18 @@ desc "Default: run specs in the proper environment" task default: [:spec, :rubocop] task test: :spec -RSpec::Core::RakeTask.new("bare:spec") +desc "Run RSpec code examples" +task "bare:spec", [:options] do |_t, args| + args.with_defaults(options: "") + sh "rspec #{args[:options]}" +end ["spec"].each do |tname| desc "Run bare:#{tname} in the proper environment" - task tname do |_t| + task tname, [:options] do |_t, args| + args.with_defaults(options: "") cd "spec/tools" do - sh "./test_env rake bare:#{tname}" + sh "./test_env rake bare:#{tname}[#{args[:options].shellescape}]" end end end diff --git a/VERSION b/VERSION index 2094a10..d21d277 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.24.0 +0.25.0 diff --git a/lib/dbus/logger.rb b/lib/dbus/logger.rb index 69cddfa..1be2f2a 100644 --- a/lib/dbus/logger.rb +++ b/lib/dbus/logger.rb @@ -17,7 +17,7 @@ module DBus # The default one logs to STDERR, # with DEBUG if $DEBUG is set, otherwise INFO. def logger - if @logger.nil? + if !defined?(@logger) || @logger.nil? debug = $DEBUG || ENV["RUBY_DBUS_DEBUG"] @logger = Logger.new($stderr) @logger.level = debug ? Logger::DEBUG : Logger::INFO diff --git a/lib/dbus/marshall.rb b/lib/dbus/marshall.rb index d18d892..34914f1 100644 --- a/lib/dbus/marshall.rb +++ b/lib/dbus/marshall.rb @@ -180,7 +180,7 @@ def num_align(num, alignment) case alignment when 1, 2, 4, 8 bits = alignment - 1 - num + bits & ~bits + (num + bits) & ~bits else raise ArgumentError, "Unsupported alignment #{alignment}" end diff --git a/lib/dbus/message.rb b/lib/dbus/message.rb index 4d23f9a..e7a9b7e 100644 --- a/lib/dbus/message.rb +++ b/lib/dbus/message.rb @@ -103,9 +103,9 @@ def initialize(mtype = INVALID) def to_s "#{message_type} sender=#{sender} -> dest=#{destination} " \ - "serial=#{serial} reply_serial=#{reply_serial} " \ - "path=#{path}; interface=#{interface}; member=#{member} " \ - "error_name=#{error_name}" + "serial=#{serial} reply_serial=#{reply_serial} " \ + "path=#{path}; interface=#{interface}; member=#{member} " \ + "error_name=#{error_name}" end # @return [String] name of message type, as used in match rules: diff --git a/lib/dbus/object.rb b/lib/dbus/object.rb index 2bcb982..3f9ddf8 100644 --- a/lib/dbus/object.rb +++ b/lib/dbus/object.rb @@ -116,7 +116,7 @@ def self.dbus_interface(name) # Forgetting to declare the interface for a method/signal/property # is a ScriptError. - class UndefinedInterface < ScriptError # rubocop:disable Lint/InheritException + class UndefinedInterface < ScriptError def initialize(sym) super "No interface specified for #{sym}. Enclose it in dbus_interface." end @@ -253,7 +253,7 @@ def self.dbus_reader(ruby_name, type, dbus_name: nil, emits_changed_signal: nil) property = Property.new(dbus_name, type, :read, ruby_name: ruby_name) @@cur_intf.define(property) - ruby_name_eq = "#{ruby_name}=".to_sym + ruby_name_eq = :"#{ruby_name}=" return unless method_defined?(ruby_name_eq) dbus_watcher(ruby_name, dbus_name: dbus_name, emits_changed_signal: emits_changed_signal) @@ -294,7 +294,7 @@ def self.dbus_watcher(ruby_name, dbus_name: nil, emits_changed_signal: nil) interface_name = @@cur_intf.name ruby_name = ruby_name.to_s.sub(/=$/, "").to_sym - ruby_name_eq = "#{ruby_name}=".to_sym + ruby_name_eq = :"#{ruby_name}=" original_ruby_name_eq = "_original_#{ruby_name_eq}" dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name) @@ -455,11 +455,16 @@ def interfaces_and_properties property = dbus_lookup_property(interface_name, property_name) if property.readable? - ruby_name = property.ruby_name - value = public_send(ruby_name) - # may raise, DBus.error or https://ruby-doc.com/core-3.1.0/TypeError.html - typed_value = Data.make_typed(property.type, value) - [typed_value] + begin + ruby_name = property.ruby_name + value = public_send(ruby_name) + # may raise, DBus.error or https://ruby-doc.com/core-3.1.0/TypeError.html + typed_value = Data.make_typed(property.type, value) + [typed_value] + rescue StandardError => e + msg = "When getting '#{interface_name}.#{property_name}': " + e.message + raise e.exception(msg) + end else raise DBus.error("org.freedesktop.DBus.Error.PropertyWriteOnly"), "Property '#{interface_name}.#{property_name}' (on object '#{@path}') is not readable" @@ -470,11 +475,16 @@ def interfaces_and_properties property = dbus_lookup_property(interface_name, property_name) if property.writable? - ruby_name_eq = "#{property.ruby_name}=" - # TODO: declare dbus_method :Set to take :exact argument - # and type check it here before passing its :plain value - # to the implementation - public_send(ruby_name_eq, value) + begin + ruby_name_eq = "#{property.ruby_name}=" + # TODO: declare dbus_method :Set to take :exact argument + # and type check it here before passing its :plain value + # to the implementation + public_send(ruby_name_eq, value) + rescue StandardError => e + msg = "When setting '#{interface_name}.#{property_name}': " + e.message + raise e.exception(msg) + end else raise DBus.error("org.freedesktop.DBus.Error.PropertyReadOnly"), "Property '#{interface_name}.#{property_name}' (on object '#{@path}') is not writable" @@ -507,8 +517,8 @@ def interfaces_and_properties typed_value = Data.make_typed(property.type, value) p_hash[p_name.to_s] = typed_value rescue StandardError - DBus.logger.debug "Property '#{interface_name}.#{p_name}' (on object '#{@path}')" \ - " has raised during GetAll, omitting it" + DBus.logger.debug "Property '#{interface_name}.#{p_name}' (on object '#{@path}') " \ + "has raised during GetAll, omitting it" end end diff --git a/lib/dbus/proxy_object.rb b/lib/dbus/proxy_object.rb index 876970e..252f579 100644 --- a/lib/dbus/proxy_object.rb +++ b/lib/dbus/proxy_object.rb @@ -129,7 +129,7 @@ def has_iface?(name) # @return [void] def on_signal(name, &block) unless @default_iface && has_iface?(@default_iface) - raise NoMethodError, "undefined signal #{OPEN_QUOTE}#{name}' for DBus interface "\ + raise NoMethodError, "undefined signal #{OPEN_QUOTE}#{name}' for DBus interface " \ "#{OPEN_QUOTE}#{@default_iface}' on object #{OPEN_QUOTE}#{@path}'" end @@ -139,13 +139,6 @@ def on_signal(name, &block) #################################################### private - # rubocop:disable Lint/MissingSuper - # as this should forward everything - # - # https://github.com/rubocop-hq/ruby-style-guide#no-method-missing - # and http://blog.marc-andre.ca/2010/11/15/methodmissing-politely/ - # have a point to be investigated - # Handles all unkown methods, mostly to route method calls to the # default interface. def method_missing(name, *args, &reply_handler) @@ -154,7 +147,7 @@ def method_missing(name, *args, &reply_handler) # - di not specified # TODO # - di is specified but not found in introspection data - raise NoMethodError, "undefined method #{OPEN_QUOTE}#{name}' for DBus interface "\ + raise NoMethodError, "undefined method #{OPEN_QUOTE}#{name}' for DBus interface " \ "#{OPEN_QUOTE}#{@default_iface}' on object #{OPEN_QUOTE}#{@path}'" end @@ -166,16 +159,15 @@ def method_missing(name, *args, &reply_handler) raise unless e.to_s =~ /undefined method #{OPEN_QUOTE}#{name}'/ # BTW e.exception("...") would preserve the class. - raise NoMethodError, "undefined method #{OPEN_QUOTE}#{name}' for DBus interface "\ + raise NoMethodError, "undefined method #{OPEN_QUOTE}#{name}' for DBus interface " \ "#{OPEN_QUOTE}#{@default_iface}' on object #{OPEN_QUOTE}#{@path}'" end end - # rubocop:enable Lint/MissingSuper def respond_to_missing?(name, _include_private = false) - @default_iface && + (@default_iface && has_iface?(@default_iface) && - @interfaces[@default_iface].methods.key?(name) or super + @interfaces[@default_iface].methods.key?(name)) or super end end end diff --git a/lib/dbus/type.rb b/lib/dbus/type.rb index 823534f..4941605 100644 --- a/lib/dbus/type.rb +++ b/lib/dbus/type.rb @@ -163,7 +163,8 @@ def <<(item) if @sigtype == DICT_ENTRY case @members.size when 2 - raise SignatureException, "DICT_ENTRY must have 2 subtypes, found 3 or more in #{@signature}" + raise SignatureException, + "DICT_ENTRY must have 2 subtypes, found 3 or more: #{@members.inspect} << #{item.inspect}" when 0 if [STRUCT, ARRAY, DICT_ENTRY, VARIANT].member?(item.sigtype) raise SignatureException, "DICT_ENTRY key must be basic (non-container)" diff --git a/package/gem2rpm.yml b/package/gem2rpm.yml index 80a4581..fa365e7 100644 --- a/package/gem2rpm.yml +++ b/package/gem2rpm.yml @@ -73,7 +73,9 @@ Provides: ruby-dbus = %{version} Obsoletes: ruby-dbus < %{version} :preamble: |- + BuildRequires: %{rubygem logger} BuildRequires: %{rubygem nokogiri >= 1.12} + BuildRequires: %{rubygem ostruct} BuildRequires: %{rubygem packaging_rake_tasks} BuildRequires: %{rubygem rake} BuildRequires: %{rubygem rspec >= 3.9} diff --git a/package/rubygem-ruby-dbus.changes b/package/rubygem-ruby-dbus.changes index cc917e3..834243c 100644 --- a/package/rubygem-ruby-dbus.changes +++ b/package/rubygem-ruby-dbus.changes @@ -1,3 +1,12 @@ +------------------------------------------------------------------- +Thu Apr 3 12:35:53 UTC 2025 - Martin Vidner + +- 0.25.0 + Bug fixes: + * Mention qualified property name in Get or Set errors + (gh#mvidner/ruby-dbus#147). + * Fix declaring logger and ostruct gems for Ruby 3.5 + ------------------------------------------------------------------- Thu Jan 2 13:45:21 UTC 2025 - Martin Vidner diff --git a/package/rubygem-ruby-dbus.spec b/package/rubygem-ruby-dbus.spec index 9bd4a9b..396dc25 100644 --- a/package/rubygem-ruby-dbus.spec +++ b/package/rubygem-ruby-dbus.spec @@ -24,12 +24,14 @@ # Name: rubygem-ruby-dbus -Version: 0.24.0 +Version: 0.25.0 Release: 0 %define mod_name ruby-dbus %define mod_full_name %{mod_name}-%{version} # MANUAL +BuildRequires: %{rubygem logger} BuildRequires: %{rubygem nokogiri >= 1.12} +BuildRequires: %{rubygem ostruct} BuildRequires: %{rubygem packaging_rake_tasks} BuildRequires: %{rubygem rake} BuildRequires: %{rubygem rspec >= 3.9} diff --git a/ruby-dbus.gemspec b/ruby-dbus.gemspec index d77aedf..73387e8 100644 --- a/ruby-dbus.gemspec +++ b/ruby-dbus.gemspec @@ -1,7 +1,6 @@ # frozen_string_literal: true # -*- ruby -*- -require "rubygems" GEMSPEC = Gem::Specification.new do |s| s.name = "ruby-dbus" @@ -22,6 +21,7 @@ GEMSPEC = Gem::Specification.new do |s| s.required_ruby_version = ">= 2.4.0" + s.add_runtime_dependency "logger" # Either of rexml and nokogiri is required # but AFAIK gemspec cannot express that. # Nokogiri is recommended as rexml is dead slow. @@ -30,10 +30,10 @@ GEMSPEC = Gem::Specification.new do |s| # workaround: rubocop-1.0 needs base64 which is no longer in stdlib in newer rubies s.add_development_dependency "base64" + s.add_development_dependency "ostruct" s.add_development_dependency "packaging_rake_tasks" s.add_development_dependency "rake" s.add_development_dependency "rspec", "~> 3" - s.add_development_dependency "rubocop", "= 1.0" s.add_development_dependency "simplecov" s.add_development_dependency "simplecov-lcov" end diff --git a/spec/data_spec.rb b/spec/data_spec.rb index 044caa7..9eccab5 100755 --- a/spec/data_spec.rb +++ b/spec/data_spec.rb @@ -223,43 +223,43 @@ describe DBus::Data::Byte do include_examples "#== and #eql? work for basic types" - include_examples "constructor accepts numeric range", 0, 2**8 - 1 + include_examples "constructor accepts numeric range", 0, (2**8) - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::Int16 do include_examples "#== and #eql? work for basic types" - include_examples "constructor accepts numeric range", -2**15, 2**15 - 1 + include_examples "constructor accepts numeric range", -2**15, (2**15) - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::UInt16 do include_examples "#== and #eql? work for basic types" - include_examples "constructor accepts numeric range", 0, 2**16 - 1 + include_examples "constructor accepts numeric range", 0, (2**16) - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::Int32 do include_examples "#== and #eql? work for basic types" - include_examples "constructor accepts numeric range", -2**31, 2**31 - 1 + include_examples "constructor accepts numeric range", -2**31, (2**31) - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::UInt32 do include_examples "#== and #eql? work for basic types" - include_examples "constructor accepts numeric range", 0, 2**32 - 1 + include_examples "constructor accepts numeric range", 0, (2**32) - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::Int64 do include_examples "#== and #eql? work for basic types" - include_examples "constructor accepts numeric range", -2**63, 2**63 - 1 + include_examples "constructor accepts numeric range", -2**63, (2**63) - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::UInt64 do include_examples "#== and #eql? work for basic types" - include_examples "constructor accepts numeric range", 0, 2**64 - 1 + include_examples "constructor accepts numeric range", 0, (2**64) - 1 include_examples "constructor accepts plain or typed values", 42 end diff --git a/spec/mock-service/spaghetti-monster.rb b/spec/mock-service/spaghetti-monster.rb index 55f4326..f925374 100755 --- a/spec/mock-service/spaghetti-monster.rb +++ b/spec/mock-service/spaghetti-monster.rb @@ -122,6 +122,8 @@ def initialize(path) dbus_attr_reader :read_me, "s" def write_me=(value) + raise "We don't talk about Bruno" if value =~ /Bruno/ + @read_me = value end dbus_writer :write_me, "s" diff --git a/spec/node_spec.rb b/spec/node_spec.rb index 0b0fd8c..f322459 100755 --- a/spec/node_spec.rb +++ b/spec/node_spec.rb @@ -25,7 +25,7 @@ let(:manager_path) { "/org/example/FooManager" } let(:child_paths) do [ - # note that "/org/example/FooManager/good" + # NOTE: "/org/example/FooManager/good" # is a path under a managed object but there is no object there "/org/example/FooManager/good/1", "/org/example/FooManager/good/2", diff --git a/spec/property_spec.rb b/spec/property_spec.rb index deb9989..372dea4 100755 --- a/spec/property_spec.rb +++ b/spec/property_spec.rb @@ -31,17 +31,36 @@ expect(iface["ReadMe"]).to eq("READ ME") end - it "gets an error when reading a property whose implementation raises" do - expect { @iface["Explosive"] }.to raise_error(DBus::Error, /Something failed/) + context "when reading a property fails" do + it "gets an error, mentioning the qualified property name" do + expect { @iface["Explosive"] } + .to raise_error(DBus::Error, /getting.*SampleInterface.Explosive.*Something failed/) + end end it "tests property nonreading" do expect { @iface["WriteMe"] }.to raise_error(DBus::Error, /not readable/) end - it "tests property writing" do - @iface["ReadOrWriteMe"] = "VALUE" - expect(@iface["ReadOrWriteMe"]).to eq("VALUE") + context "writing properties" do + it "tests property writing" do + @iface["ReadOrWriteMe"] = "VALUE" + expect(@iface["ReadOrWriteMe"]).to eq("VALUE") + end + + context "when writing a read-only property" do + it "gets an error, mentioning the qualified property name" do + expect { @iface["ReadMe"] = "WROTE" } + .to raise_error(DBus::Error, /SampleInterface.ReadMe.*not writable/) + end + end + + context "when writing a property fails" do + it "gets an error, mentioning the qualified property name" do + expect { @iface["WriteMe"] = "Bruno is a city in Czechia" } + .to raise_error(DBus::Error, /setting.*SampleInterface.WriteMe/) + end + end end # https://github.com/mvidner/ruby-dbus/pull/19 @@ -54,10 +73,6 @@ expect(@iface["ReadOrWriteMe"]).to eq("VALUE") end - it "tests property nonwriting" do - expect { @iface["ReadMe"] = "WROTE" }.to raise_error(DBus::Error, /not writable/) - end - it "tests get all" do all = @iface.all_properties expect(all.keys.sort).to eq(["MyArray", "MyByte", "MyDict", "MyStruct", "MyVariant", "ReadMe", "ReadOrWriteMe"])