Skip to content

Commit 29b3f6f

Browse files
committed
Reject non-dictionary stringsdict entries with a clear error
`read` checked only that the plist root is a dictionary, so a file whose entry value wasn't a dictionary (e.g. a key mapped to a string) slipped through and crashed later in `plural_variables` with a cryptic `NoMethodError: private method 'select' called for String`. Validate each entry up front and raise the same clean `UI.user_error!` the root check uses, naming the offending key.
1 parent add6d13 commit 29b3f6f

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_stringsdict_helper.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,18 @@ class StringsdictHelper
5555
#
5656
# @param [String] path The path to the `.stringsdict` file.
5757
# @return [Hash] The parsed plist dictionary.
58-
# @raise [FastlaneCore::Interface::FastlaneError] If the file is missing or is not a plist dictionary.
58+
# @raise [FastlaneCore::Interface::FastlaneError] If the file is missing, is not a plist
59+
# dictionary, or contains an entry whose value is not a dictionary.
5960
def self.read(path:)
6061
UI.user_error!("Stringsdict file not found: #{path}") unless File.exist?(path)
6162

6263
data = Plist.parse_xml(path)
6364
UI.user_error!("Invalid stringsdict file (expected a plist dictionary at the root): #{path}") unless data.is_a?(Hash)
6465

66+
data.each do |key, value|
67+
UI.user_error!("Invalid stringsdict file (entry '#{key}' is not a dictionary): #{path}") unless value.is_a?(Hash)
68+
end
69+
6570
data
6671
end
6772

spec/ios_stringsdict_helper_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,19 @@ def convert_po_to_stringsdict(po_content, template:, locale:)
5353
expect { described_class.read(path: 'does-not-exist.stringsdict') }
5454
.to raise_error(FastlaneCore::Interface::FastlaneError, /Stringsdict file not found/)
5555
end
56+
57+
it 'raises a clear error when an entry is not a dictionary' do
58+
in_tmp_dir do |dir|
59+
bad = File.join(dir, 'bad.stringsdict')
60+
File.write(bad, <<~XML)
61+
<?xml version="1.0" encoding="UTF-8"?>
62+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
63+
<plist version="1.0"><dict><key>oops</key><string>not a dictionary</string></dict></plist>
64+
XML
65+
expect { described_class.read(path: bad) }
66+
.to raise_error(FastlaneCore::Interface::FastlaneError, /entry 'oops' is not a dictionary/)
67+
end
68+
end
5669
end
5770

5871
describe 'round-trip write/read' do

0 commit comments

Comments
 (0)