diff --git a/ext/win32/lib/win32/registry.rb b/ext/win32/lib/win32/registry.rb index c801b1327b..e84653d945 100644 --- a/ext/win32/lib/win32/registry.rb +++ b/ext/win32/lib/win32/registry.rb @@ -69,11 +69,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr WCHAR_NUL = "\0".encode(WCHAR).freeze WCHAR_CR = "\r".encode(WCHAR).freeze WCHAR_SIZE = WCHAR_NUL.bytesize - begin - LOCALE = Encoding.find(Encoding.locale_charmap) - rescue ArgumentError - LOCALE = Encoding::UTF_8 - end + LOCALE = Encoding::UTF_8 class Registry @@ -567,9 +563,16 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr end # - # Enumerate values. + # Enumerate all values in this registry path. + # + # For each value it yields key, type and data. + # + # key is a String which contains name of key. + # type is a type contant kind of Win32::Registry::REG_* + # data is the value of this key. # def each_value + return enum_for(:each_value) unless block_given? index = 0 while true begin @@ -600,13 +603,16 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr end # - # Enumerate subkeys. + # Enumerate all subkeys. + # + # For each subkey it yields subkey and wtime. # # subkey is String which contains name of subkey. # wtime is last write time as FILETIME (64-bit integer). # (see Registry.wtime2time) # def each_key + return enum_for(:each_key) unless block_given? index = 0 while true begin diff --git a/ext/win32/win32-registry.gemspec b/ext/win32/win32-registry.gemspec new file mode 100644 index 0000000000..b6df247574 --- /dev/null +++ b/ext/win32/win32-registry.gemspec @@ -0,0 +1,29 @@ +# frozen_string_literal: true +Gem::Specification.new do |spec| + spec.name = "win32-registry" + spec.version = "0.0.1" + spec.authors = ["U.Nakamura"] + spec.email = ["usa@garbagecollect.jp"] + + spec.summary = %q{Provides an interface to the Windows Registry in Ruby} + spec.description = spec.summary + spec.homepage = "https://github.com/ruby/win32-registry" + spec.required_ruby_version = ">= 2.6.0" + + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = spec.homepage + + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + spec.files = Dir.chdir(__dir__) do + `git ls-files -z`.split("\x0").reject do |f| + (File.expand_path(f) == __FILE__) || + f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile]) + end + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + spec.add_dependency "fiddle", "~> 1.0" +end diff --git a/test/win32/test_registry.rb b/test/win32/test_registry.rb index 02cafc09b0..8a98405a79 100644 --- a/test/win32/test_registry.rb +++ b/test/win32/test_registry.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM begin require 'win32/registry' @@ -10,7 +12,19 @@ end if defined?(Win32::Registry) class TestWin32Registry < Test::Unit::TestCase COMPUTERNAME = 'SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName' - VOLATILE_ENVIRONMENT = 'Volatile Environment' + + private def backslachs(path) + path.gsub("/", "\\") + end + + TEST_REGISTRY_KEY = "SOFTWARE/ruby-win32-registry-test/" + + def setup + Win32::Registry::HKEY_CURRENT_USER.open(backslachs(File.dirname(TEST_REGISTRY_KEY))) do |reg| + reg.delete_key File.basename(TEST_REGISTRY_KEY), true + end + rescue Win32::Registry::Error + end def test_predefined assert_predefined_key Win32::Registry::HKEY_CLASSES_ROOT @@ -24,6 +38,38 @@ if defined?(Win32::Registry) assert_predefined_key Win32::Registry::HKEY_DYN_DATA end + def test_open_no_block + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)).close + + reg = Win32::Registry::HKEY_CURRENT_USER.open(backslachs(TEST_REGISTRY_KEY), Win32::Registry::KEY_ALL_ACCESS) + assert_kind_of Win32::Registry, reg + assert_equal true, reg.open? + assert_equal false, reg.created? + reg["test"] = "abc" + reg.close + assert_raise(Win32::Registry::Error) do + reg["test"] = "abc" + end + end + + def test_open_with_block + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)).close + + regs = [] + Win32::Registry::HKEY_CURRENT_USER.open(backslachs(TEST_REGISTRY_KEY), Win32::Registry::KEY_ALL_ACCESS) do |reg| + regs << reg + assert_equal true, reg.open? + assert_equal false, reg.created? + reg["test"] = "abc" + end + + assert_equal 1, regs.size + assert_kind_of Win32::Registry, regs[0] + assert_raise(Win32::Registry::Error) do + regs[0]["test"] = "abc" + end + end + def test_class_open name1, keys1 = Win32::Registry.open(Win32::Registry::HKEY_LOCAL_MACHINE, "SYSTEM") do |reg| assert_predicate reg, :open? @@ -46,32 +92,145 @@ if defined?(Win32::Registry) end end - def test_create + def test_create_volatile desired = Win32::Registry::KEY_ALL_ACCESS option = Win32::Registry::REG_OPTION_VOLATILE - Win32::Registry::HKEY_CURRENT_USER.open(VOLATILE_ENVIRONMENT, desired) do |reg| - v = self.class.unused_value(reg) - begin - reg.create(v, desired, option) {} - ensure - reg.delete_key(v, true) - end + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY), desired) do |reg| + reg.create("volkey", desired, option) {} + reg.delete_key("volkey", true) + end + end + + def test_create_no_block + reg = Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)) + assert_kind_of Win32::Registry, reg + assert_equal true, reg.open? + assert_equal true, reg.created? + reg["test"] = "abc" + reg.close + assert_equal false, reg.open? + assert_raise(Win32::Registry::Error) do + reg["test"] = "abc" + end + end + + def test_create_with_block + regs = [] + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)) do |reg| + regs << reg + reg["test"] = "abc" + assert_equal true, reg.open? + assert_equal true, reg.created? + end + + assert_equal 1, regs.size + assert_kind_of Win32::Registry, regs[0] + assert_equal false, regs[0].open? + assert_raise(Win32::Registry::Error) do + regs[0]["test"] = "abc" end end def test_write desired = Win32::Registry::KEY_ALL_ACCESS - Win32::Registry::HKEY_CURRENT_USER.open(VOLATILE_ENVIRONMENT, desired) do |reg| - v = self.class.unused_value(reg) - begin - reg.write_s(v, "data") - assert_equal [Win32::Registry::REG_SZ, "data"], reg.read(v) - reg.write_i(v, 0x5fe79027) - assert_equal [Win32::Registry::REG_DWORD, 0x5fe79027], reg.read(v) - ensure - reg.delete(v) + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY), desired) do |reg| + reg.write_s("key1", "data") + assert_equal [Win32::Registry::REG_SZ, "data"], reg.read("key1") + reg.write_i("key2", 0x5fe79027) + assert_equal [Win32::Registry::REG_DWORD, 0x5fe79027], reg.read("key2") + end + end + + def test_accessors + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)) do |reg| + assert_kind_of Integer, reg.hkey + assert_kind_of Win32::Registry, reg.parent + assert_equal "HKEY_CURRENT_USER", reg.parent.name + assert_equal "SOFTWARE\\ruby-win32-registry-test\\", reg.keyname + assert_equal Win32::Registry::REG_CREATED_NEW_KEY, reg.disposition + end + end + + def test_name + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)) do |reg| + assert_equal "HKEY_CURRENT_USER\\SOFTWARE\\ruby-win32-registry-test\\", reg.name + end + end + + def test_keys + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)) do |reg| + reg.create("key1") + assert_equal ["key1"], reg.keys + end + end + + def test_each_key + keys = [] + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)) do |reg| + reg.create("key1") + reg.each_key { |*a| keys << a } + end + assert_equal [2], keys.map(&:size) + assert_equal ["key1"], keys.map(&:first) + assert_in_delta Win32::Registry.time2wtime(Time.now), keys[0][1], 10_000_000_000, "wtime should roughly match Time.now" + end + + def test_each_key_enum + keys = nil + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)) do |reg| + reg.create("key1") + reg.create("key2") + reg.create("key3") + reg["value1"] = "abcd" + keys = reg.each_key.to_a + end + assert_equal 3, keys.size + assert_equal [2, 2, 2], keys.map(&:size) + assert_equal ["key1", "key2", "key3"], keys.map(&:first) + end + + def test_values + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)) do |reg| + reg.create("key1") + reg["value1"] = "abcd" + assert_equal ["abcd"], reg.values + end + end + + def test_each_value + vals = [] + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)) do |reg| + reg.create("key1") + reg["value1"] = "abcd" + reg.each_value { |*a| vals << a } + end + assert_equal [["value1", Win32::Registry::REG_SZ, "abcd"]], vals + end + + def test_each_value_enum + vals = nil + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)) do |reg| + reg.create("key1") + reg["value1"] = "abcd" + reg["value2"] = 42 + vals = reg.each_value.to_a + end + assert_equal [["value1", Win32::Registry::REG_SZ, "abcd"], + ["value2", Win32::Registry::REG_DWORD, 42]], vals + end + + def test_utf8_encoding + keys = [] + Win32::Registry::HKEY_CURRENT_USER.create(backslachs(TEST_REGISTRY_KEY)) do |reg| + reg.create("abc EUR") + reg.create("abc €") + reg.each_key do |subkey| + keys << subkey end end + + assert_equal [Encoding::UTF_8] * 2, keys.map(&:encoding) + assert_equal ["abc EUR", "abc €"], keys end private @@ -79,19 +238,7 @@ if defined?(Win32::Registry) def assert_predefined_key(key) assert_kind_of Win32::Registry, key assert_predicate key, :open? - assert_not_predicate key, :created? - end - - class << self - def unused_value(reg, prefix = "Test_", limit = 100, fail: true) - limit.times do - v = + rand(0x100000).to_s(36) - reg.read(v) - rescue - return v - end - omit "Unused value not found in #{reg}" if fail - end + refute_predicate key, :created? end end end