Skip to content

Commit

Permalink
Sync from ruby/win32-registry
Browse files Browse the repository at this point in the history
  • Loading branch information
hsbt committed Oct 4, 2024
1 parent 4be5356 commit 08467d2
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 47 deletions.
20 changes: 13 additions & 7 deletions ext/win32/lib/win32/registry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,7 @@ module Win32
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

Expand Down Expand Up @@ -567,9 +563,16 @@ def close
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
Expand Down Expand Up @@ -600,13 +603,16 @@ def values
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
Expand Down
29 changes: 29 additions & 0 deletions ext/win32/win32-registry.gemspec
Original file line number Diff line number Diff line change
@@ -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 = ["[email protected]"]

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
210 changes: 170 additions & 40 deletions test/win32/test_registry.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM
begin
require 'win32/registry'
rescue LoadError
else
require 'test/unit'
end
end
# frozen_string_literal: true

require "test_helper"

if defined?(Win32::Registry)
class TestWin32Registry < Test::Unit::TestCase
class Win32::TestRegistry < Minitest::Test
COMPUTERNAME = 'SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName'
VOLATILE_ENVIRONMENT = 'Volatile Environment'

include RegistryHelper

def test_predefined
assert_predefined_key Win32::Registry::HKEY_CLASSES_ROOT
assert_predefined_key Win32::Registry::HKEY_CURRENT_USER
Expand All @@ -24,6 +21,38 @@ def test_predefined
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_raises(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_raises(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?
Expand All @@ -42,56 +71,157 @@ def test_read
Win32::Registry::HKEY_LOCAL_MACHINE.open(COMPUTERNAME) do |reg|
assert_equal computername, reg['ComputerName']
assert_equal [Win32::Registry::REG_SZ, computername], reg.read('ComputerName')
assert_raise(TypeError) {reg.read('ComputerName', Win32::Registry::REG_DWORD)}
assert_raises(TypeError) {reg.read('ComputerName', Win32::Registry::REG_DWORD)}
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_raises(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_raises(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

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

0 comments on commit 08467d2

Please sign in to comment.