diff --git a/lib/twine/runner.rb b/lib/twine/runner.rb index 3b91d19..3b9ec49 100644 --- a/lib/twine/runner.rb +++ b/lib/twine/runner.rb @@ -184,40 +184,41 @@ module Twine all_keys = Set.new duplicate_keys = Set.new keys_without_tags = Set.new - errors = [] + invalid_keys = Set.new + valid_key_regex = /^[A-Za-z0-9_.]+$/ @strings.sections.each do |section| section.rows.each do |row| total_strings += 1 - if all_keys.include? row.key - duplicate_keys.add(row.key) - else - all_keys.add(row.key) - end + duplicate_keys.add(row.key) if all_keys.include? row.key + all_keys.add(row.key) - if row.tags == nil || row.tags.length == 0 - keys_without_tags.add(row.key) - end + keys_without_tags.add(row.key) if row.tags == nil or row.tags.length == 0 + + invalid_keys << row.key unless row.key =~ valid_key_regex end end - if duplicate_keys.length > 0 - error_body = duplicate_keys.to_a.join("\n ") - errors << "Found duplicate string key(s):\n #{error_body}" + errors = [] + join_keys = lambda { |set| set.map { |k| " " + k }.join("\n") } + + unless duplicate_keys.empty? + errors << "Found duplicate string key(s):\n#{join_keys.call(duplicate_keys)}" end if keys_without_tags.length == total_strings errors << "None of your strings have tags." elsif keys_without_tags.length > 0 - error_body = keys_without_tags.to_a.join("\n ") - errors << "Found strings(s) without tags:\n #{error_body}" + errors << "Found strings without tags:\n#{join_keys.call(keys_without_tags)}" end - if errors.length > 0 - raise Twine::Error.new errors.join("\n\n") + unless invalid_keys.empty? + errors << "Found key(s) with invalid characters:\n#{join_keys.call(invalid_keys)}" end + raise Twine::Error.new errors.join("\n\n") unless errors.empty? + Twine::stdout.puts "#{@options[:strings_file]} is valid." end diff --git a/test/test_validate_strings_file.rb b/test/test_validate_strings_file.rb new file mode 100644 index 0000000..fcb6a27 --- /dev/null +++ b/test/test_validate_strings_file.rb @@ -0,0 +1,55 @@ +# encoding: utf-8 + +require 'command_test_case' + +class TestValidateStringsFile < CommandTestCase + def setup + super + @options = { strings_file: 'input.txt' } + + @twine_file = build_twine_file 'en' do + add_section 'Section 1' do + add_row key1: 'value1', tags: ['tag1'] + add_row key2: 'value2', tags: ['tag1'] + end + + add_section 'Section 2' do + add_row key3: 'value3', tags: ['tag1', 'tag2'] + add_row key4: 'value4', tags: ['tag2'] + end + end + end + + def random_row + @twine_file.strings_map[@twine_file.strings_map.keys.sample] + end + + def test_recognizes_valid_file + Twine::Runner.new(@options, @twine_file).validate_strings_file + assert_equal "input.txt is valid.\n", Twine::stdout.string + end + + def test_reports_duplicate_keys + @twine_file.sections[0].rows << random_row + + assert_raises Twine::Error do + Twine::Runner.new(@options, @twine_file).validate_strings_file + end + end + + def test_reports_missing_tags + random_row.tags.clear + + assert_raises Twine::Error do + Twine::Runner.new(@options, @twine_file).validate_strings_file + end + end + + def test_reports_invalid_characters_in_keys + random_row.key[0] = "!?;:,^`ยด'\"\\|/(){}[]~-+*=#$%".chars.to_a.sample + + assert_raises Twine::Error do + Twine::Runner.new(@options, @twine_file).validate_strings_file + end + end +end