pdd 0.20.4 → 0.20.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/pdd.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2018 Yegor Bugayenko
1
+ # Copyright (c) 2014-2021 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -30,7 +30,7 @@ require_relative 'pdd/rule/roles'
30
30
 
31
31
  # PDD main module.
32
32
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
33
- # Copyright:: Copyright (c) 2014-2018 Yegor Bugayenko
33
+ # Copyright:: Copyright (c) 2014-2021 Yegor Bugayenko
34
34
  # License:: MIT
35
35
  module PDD
36
36
  # If it breaks.
@@ -52,21 +52,25 @@ module PDD
52
52
  # Get logger.
53
53
  def self.log
54
54
  unless defined?(@logger)
55
- @logger = Logger.new(STDOUT)
55
+ @logger = Logger.new($stdout)
56
56
  @logger.formatter = proc { |severity, _, _, msg|
57
- if severity == 'ERROR'
57
+ case severity
58
+ when 'ERROR'
58
59
  "#{Rainbow(severity).red}: #{msg}\n"
60
+ when 'WARN'
61
+ "#{Rainbow(severity).orange}: #{msg}\n"
59
62
  else
60
63
  "#{msg}\n"
61
64
  end
62
65
  }
63
- @logger.level = Logger::ERROR
66
+ @logger.level = Logger::WARN
64
67
  end
65
68
  @logger
66
69
  end
67
70
 
68
71
  class << self
69
72
  attr_writer :logger
73
+ attr_accessor :opts
70
74
  end
71
75
 
72
76
  # Code base abstraction
@@ -75,6 +79,7 @@ module PDD
75
79
  # +opts+:: Options
76
80
  def initialize(opts)
77
81
  @opts = opts
82
+ PDD.opts = opts
78
83
  PDD.log.level = Logger::INFO if @opts[:verbose]
79
84
  PDD.log.level = Logger::ERROR if @opts[:quiet]
80
85
  PDD.log.info "My version is #{PDD::VERSION}"
@@ -83,19 +88,15 @@ module PDD
83
88
 
84
89
  # Generate XML.
85
90
  def xml
86
- dir = @opts[:source] ? @opts[:source] : Dir.pwd
87
- PDD.log.info "Reading #{dir}"
91
+ dir = @opts[:source] || Dir.pwd
92
+ PDD.log.info "Reading from root dir #{dir}"
88
93
  require_relative 'pdd/sources'
89
- sources = Sources.new(dir)
90
- unless @opts[:exclude].nil?
91
- @opts[:exclude].each do |p|
92
- sources = sources.exclude(p)
93
- PDD.log.info "Excluding #{p}"
94
- end
95
- end
94
+ sources = Sources.new(File.expand_path(dir))
95
+ sources.exclude((@opts[:exclude] || []) + (@opts['skip-gitignore'] || []))
96
+ sources.include(@opts[:include])
96
97
  sanitize(
97
98
  rules(
98
- Nokogiri::XML::Builder.new do |xml|
99
+ Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
99
100
  xml << "<?xml-stylesheet type='text/xsl' href='#{xsl}'?>"
100
101
  xml.puzzles(attrs) do
101
102
  sources.fetch.each do |source|
@@ -147,16 +148,19 @@ module PDD
147
148
  unless list.select { |r| r.start_with?('max-duplicates:') }.empty?
148
149
  raise PDD::Error, 'You can\'t modify max-duplicates, it\'s always 1'
149
150
  end
151
+
150
152
  list.push('max-duplicates:1').map do |r|
151
153
  name, value = r.split(':')
152
154
  rule = RULES[name]
153
155
  raise "Rule '#{name}' doesn't exist" if rule.nil?
156
+
154
157
  rule.new(doc, value).errors.each do |e|
155
158
  PDD.log.error e
156
159
  total += 1
157
160
  end
158
161
  end
159
162
  raise PDD::Error, "#{total} errors, see log above" unless total.zero?
163
+
160
164
  xml
161
165
  end
162
166
 
@@ -168,6 +172,7 @@ module PDD
168
172
  errors.each { |e| PDD.log.error e }
169
173
  PDD.log.error(xml) unless errors.empty?
170
174
  raise SchemaError, errors.join('; ') unless errors.empty?
175
+
171
176
  xml
172
177
  end
173
178
  end
data/pdd.gemspec CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2018 Yegor Bugayenko
1
+ # Copyright (c) 2014-2021 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -20,17 +20,18 @@
20
20
 
21
21
  require 'English'
22
22
 
23
- lib = File.expand_path('../lib', __FILE__)
23
+ lib = File.expand_path('lib', __dir__)
24
24
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
25
25
  require_relative 'lib/pdd/version'
26
26
 
27
27
  Gem::Specification.new do |s|
28
28
  s.specification_version = 2 if s.respond_to? :specification_version=
29
29
  if s.respond_to? :required_rubygems_version=
30
- s.required_rubygems_version = Gem::Requirement.new('>= 0')
30
+ s.required_rubygems_version =
31
+ Gem::Requirement.new('>= 0')
31
32
  end
32
- s.rubygems_version = '2.2'
33
- s.required_ruby_version = '>= 2.2'
33
+ s.rubygems_version = '2.3'
34
+ s.required_ruby_version = '~> 2.3'
34
35
  s.name = 'pdd'
35
36
  s.version = PDD::VERSION
36
37
  s.license = 'MIT'
@@ -38,16 +39,17 @@ Gem::Specification.new do |s|
38
39
  s.description = 'Collects PDD puzzles from a source code base'
39
40
  s.authors = ['Yegor Bugayenko']
40
41
  s.email = 'yegor256@gmail.com'
41
- s.homepage = 'http://github.com/yegor256/pdd'
42
+ s.homepage = 'http://github.com/cqfn/pdd'
42
43
  s.files = `git ls-files`.split($RS)
43
44
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
44
45
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
45
46
  s.rdoc_options = ['--charset=UTF-8']
46
47
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
47
- s.add_runtime_dependency 'nokogiri', '1.8.2'
48
- s.add_runtime_dependency 'rainbow', '~>3.0'
49
- s.add_runtime_dependency 'slop', '4.6.1'
50
- s.add_development_dependency 'codecov', '0.1.10'
48
+ s.add_runtime_dependency 'nokogiri', '~> 1.10'
49
+ s.add_runtime_dependency 'rainbow', '~> 3.0'
50
+ s.add_runtime_dependency 'slop', '~> 4.6'
51
+ s.add_development_dependency 'aruba', '~> 0.14.1'
52
+ s.add_development_dependency 'codecov', '0.2.12'
51
53
  s.add_development_dependency 'cucumber', '3.1.0'
52
54
  s.add_development_dependency 'minitest', '5.5.0'
53
55
  s.add_development_dependency 'rake', '12.0.0'
@@ -55,5 +57,6 @@ Gem::Specification.new do |s|
55
57
  s.add_development_dependency 'rspec-rails', '3.1.0'
56
58
  s.add_development_dependency 'rubocop', '0.52.1'
57
59
  s.add_development_dependency 'rubocop-rspec', '1.15.1'
60
+ s.add_development_dependency 'slop', '4.9.1'
58
61
  s.add_development_dependency 'xcop', '0.5.8'
59
62
  end
data/test/test__helper.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2018 Yegor Bugayenko
1
+ # Copyright (c) 2014-2021 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -18,7 +18,7 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
19
  # SOFTWARE.
20
20
 
21
- STDOUT.sync = true
21
+ $stdout.sync = true
22
22
 
23
23
  require 'simplecov'
24
24
  SimpleCov.start
@@ -29,3 +29,16 @@ end
29
29
 
30
30
  require 'minitest/autorun'
31
31
  require_relative '../lib/pdd'
32
+
33
+ def stub_source_find_github_user(file, path = '')
34
+ source = PDD::Source.new(file, path)
35
+ verbose_source = PDD::VerboseSource.new(file, source)
36
+ fake = proc do |info = {}|
37
+ email, author = info.values_at(:email, :author)
38
+ { 'login' => 'yegor256' } if email == 'yegor256@gmail.com' ||
39
+ author == 'Yegor Bugayenko'
40
+ end
41
+ source.stub :find_github_user, fake do
42
+ yield verbose_source
43
+ end
44
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2018 Yegor Bugayenko
1
+ # Copyright (c) 2014-2021 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -24,7 +24,7 @@ require_relative '../lib/pdd/rule/duplicates'
24
24
 
25
25
  # PDD::Rule::MaxDuplicates class test.
26
26
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
27
- # Copyright:: Copyright (c) 2014-2018 Yegor Bugayenko
27
+ # Copyright:: Copyright (c) 2014-2021 Yegor Bugayenko
28
28
  # License:: MIT
29
29
  class TestMaxDuplicates < Minitest::Test
30
30
  def test_max_duplicates
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2018 Yegor Bugayenko
1
+ # Copyright (c) 2014-2021 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -24,7 +24,7 @@ require_relative '../lib/pdd/rule/estimates'
24
24
 
25
25
  # PDD::Rule::Estimate module tests.
26
26
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
27
- # Copyright:: Copyright (c) 2014-2018 Yegor Bugayenko
27
+ # Copyright:: Copyright (c) 2014-2021 Yegor Bugayenko
28
28
  # License:: MIT
29
29
  class TestEstimates < Minitest::Test
30
30
  def test_min
data/test/test_pdd.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2018 Yegor Bugayenko
1
+ # Copyright (c) 2014-2021 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -26,7 +26,7 @@ require_relative '../lib/pdd'
26
26
 
27
27
  # PDD main module test.
28
28
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
- # Copyright:: Copyright (c) 2014-2018 Yegor Bugayenko
29
+ # Copyright:: Copyright (c) 2014-2021 Yegor Bugayenko
30
30
  # License:: MIT
31
31
  class TestPDD < Minitest::Test
32
32
  def test_basic
@@ -75,6 +75,7 @@ class TestPDD < Minitest::Test
75
75
  git add -f .
76
76
  git commit --quiet -am 'first version'
77
77
  ")
78
+
78
79
  matches(
79
80
  Nokogiri::XML(PDD::Base.new(opts).xml),
80
81
  [
@@ -95,6 +96,7 @@ class TestPDD < Minitest::Test
95
96
  Slop.parse args do |o|
96
97
  o.bool '-v', '--verbose'
97
98
  o.bool '-q', '--quiet'
99
+ o.bool '--skip-errors'
98
100
  o.string '-s', '--source'
99
101
  o.array '-e', '--exclude'
100
102
  o.array '-r', '--rule'
@@ -0,0 +1,18 @@
1
+ require 'minitest/autorun'
2
+ require 'tmpdir'
3
+ require 'rake'
4
+ require_relative '../lib/pdd/rake_task'
5
+
6
+ # Test for RakeTask
7
+ class TestRakeTask < Minitest::Test
8
+ def test_basic
9
+ Dir.mktmpdir 'test' do |dir|
10
+ file = File.join(dir, 'a.txt')
11
+ File.write(file, "\x40todo #55 hello!")
12
+ PDD::RakeTask.new(:pdd1) do |task|
13
+ task.quiet = true
14
+ end
15
+ Rake::Task['pdd1'].invoke
16
+ end
17
+ end
18
+ end
data/test/test_roles.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2018 Yegor Bugayenko
1
+ # Copyright (c) 2014-2021 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -24,7 +24,7 @@ require_relative '../lib/pdd/rule/roles'
24
24
 
25
25
  # PDD::Rule::Role module tests.
26
26
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
27
- # Copyright:: Copyright (c) 2014-2018 Yegor Bugayenko
27
+ # Copyright:: Copyright (c) 2014-2021 Yegor Bugayenko
28
28
  # License:: MIT
29
29
  class TestRoles < Minitest::Test
30
30
  def test_incorrect_role
data/test/test_source.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2018 Yegor Bugayenko
1
+ # Copyright (c) 2014-2021 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -25,7 +25,7 @@ require_relative '../lib/pdd/sources'
25
25
 
26
26
  # Source test.
27
27
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
28
- # Copyright:: Copyright (c) 2014-2018 Yegor Bugayenko
28
+ # Copyright:: Copyright (c) 2014-2021 Yegor Bugayenko
29
29
  # License:: MIT
30
30
  class TestSource < Minitest::Test
31
31
  def test_parsing
@@ -42,15 +42,39 @@ class TestSource < Minitest::Test
42
42
  ~~ and it also has to work
43
43
  "
44
44
  )
45
- list = PDD::VerboseSource.new(file, PDD::Source.new(file, 'hey')).puzzles
46
- assert_equal 2, list.size
47
- puzzle = list.first
48
- assert_equal '2-3', puzzle.props[:lines]
49
- assert_equal 'привет, how are you doing?', puzzle.props[:body]
50
- assert_equal '44', puzzle.props[:ticket]
51
- assert puzzle.props[:author].nil?
52
- assert puzzle.props[:email].nil?
53
- assert puzzle.props[:time].nil?
45
+ stub_source_find_github_user(file, 'hey') do |source|
46
+ list = source.puzzles
47
+ assert_equal 2, list.size
48
+ puzzle = list.first
49
+ assert_equal '2-3', puzzle.props[:lines]
50
+ assert_equal 'привет, how are you doing?', puzzle.props[:body]
51
+ assert_equal '44', puzzle.props[:ticket]
52
+ assert puzzle.props[:author].nil?
53
+ assert puzzle.props[:email].nil?
54
+ assert puzzle.props[:time].nil?
55
+ end
56
+ end
57
+ end
58
+
59
+ def test_parsing_leading_spaces
60
+ Dir.mktmpdir 'test' do |dir|
61
+ file = File.join(dir, 'a.txt')
62
+ File.write(
63
+ file,
64
+ "
65
+ * \x40todo #56:30min this is a
66
+ * multi-line
67
+ * comment!
68
+ "
69
+ )
70
+ stub_source_find_github_user(file, 'hey') do |source|
71
+ list = source.puzzles
72
+ assert_equal 1, list.size
73
+ puzzle = list.first
74
+ assert_equal '2-4', puzzle.props[:lines]
75
+ assert_equal 'this is a multi-line comment!', puzzle.props[:body]
76
+ assert_equal '56', puzzle.props[:ticket]
77
+ end
54
78
  end
55
79
  end
56
80
 
@@ -65,12 +89,58 @@ class TestSource < Minitest::Test
65
89
  "
66
90
  )
67
91
  error = assert_raises PDD::Error do
68
- PDD::VerboseSource.new(file, PDD::Source.new(file, 'hey')).puzzles
92
+ stub_source_find_github_user(file, 'hey', &:puzzles)
69
93
  end
70
94
  assert !error.message.index('Space expected').nil?
71
95
  end
72
96
  end
73
97
 
98
+ def test_succeed_despite_bad_puzzles
99
+ Dir.mktmpdir 'test' do |dir|
100
+ file = File.join(dir, 'a.txt')
101
+ File.write(
102
+ file,
103
+ "
104
+ * \x40todo #44 this is an incorrectly formatted puzzle,
105
+ * with a second line without a leading space
106
+ Another badly formatted puzzle
107
+ * \x40todo this puzzle misses ticket name/number
108
+ Something else
109
+ * \x40todo #123 This puzzle is correctly formatted
110
+ "
111
+ )
112
+ PDD.opts = { 'skip-errors' => true }
113
+ stub_source_find_github_user(file, 'hey') do |source|
114
+ list = source.puzzles
115
+ PDD.opts = nil
116
+ assert_equal 1, list.size
117
+ puzzle = list.first
118
+ assert_equal '7-7', puzzle.props[:lines]
119
+ assert_equal 'This puzzle is correctly formatted', puzzle.props[:body]
120
+ assert_equal '123', puzzle.props[:ticket]
121
+ end
122
+ end
123
+ end
124
+
125
+ def test_succeed_utf8_encoded_body
126
+ Dir.mktmpdir 'test' do |dir|
127
+ file = File.join(dir, 'a.txt')
128
+ File.write(
129
+ file,
130
+ "
131
+ * \x40todo #44 Привет, мир, мне кофе
132
+ * вторая линия
133
+ "
134
+ )
135
+ list = PDD::VerboseSource.new(file, PDD::Source.new(file, 'hey')).puzzles
136
+ assert_equal 1, list.size
137
+ puzzle = list.first
138
+ assert_equal '2-3', puzzle.props[:lines]
139
+ assert_equal 'Привет, мир, мне кофе вторая линия', puzzle.props[:body]
140
+ assert_equal '44', puzzle.props[:ticket]
141
+ end
142
+ end
143
+
74
144
  def test_failing_on_incomplete_puzzle
75
145
  Dir.mktmpdir 't5' do |dir|
76
146
  file = File.join(dir, 'ff.txt')
@@ -81,7 +151,7 @@ class TestSource < Minitest::Test
81
151
  "
82
152
  )
83
153
  error = assert_raises PDD::Error do
84
- PDD::VerboseSource.new(file, PDD::Source.new(file, 'ff')).puzzles
154
+ stub_source_find_github_user(file, 'ff', &:puzzles)
85
155
  end
86
156
  assert !error.to_s.index("\x40todo is not followed by").nil?
87
157
  end
@@ -90,9 +160,9 @@ class TestSource < Minitest::Test
90
160
  def test_failing_on_broken_unicode
91
161
  Dir.mktmpdir 'test' do |dir|
92
162
  file = File.join(dir, 'xx.txt')
93
- File.write(file, ' * \x40todo #44 this is a broken unicode: ' + 0x92.chr)
163
+ File.write(file, " * \\x40todo #44 this is a broken unicode: #{0x92.chr}")
94
164
  assert_raises PDD::Error do
95
- PDD::VerboseSource.new(file, PDD::Source.new(file, 'xx')).puzzles
165
+ stub_source_find_github_user(file, 'xx', &:puzzles)
96
166
  end
97
167
  end
98
168
  end
@@ -107,7 +177,7 @@ class TestSource < Minitest::Test
107
177
  "
108
178
  )
109
179
  error = assert_raises PDD::Error do
110
- PDD::VerboseSource.new(file, PDD::Source.new(file, 'hey')).puzzles
180
+ stub_source_find_github_user(file, 'hey', &:puzzles)
111
181
  end
112
182
  assert !error.message.index('is not followed by a puzzle marker').nil?
113
183
  end
@@ -123,7 +193,7 @@ class TestSource < Minitest::Test
123
193
  "
124
194
  )
125
195
  error = assert_raises PDD::Error do
126
- PDD::VerboseSource.new(file, PDD::Source.new(file, 'x')).puzzles
196
+ stub_source_find_github_user(file, 'x', &:puzzles)
127
197
  end
128
198
  assert !error.message.index("\x40todo must have a leading space").nil?
129
199
  end
@@ -139,7 +209,7 @@ class TestSource < Minitest::Test
139
209
  "
140
210
  )
141
211
  error = assert_raises PDD::Error do
142
- PDD::VerboseSource.new(file, PDD::Source.new(file, 'x')).puzzles
212
+ stub_source_find_github_user(file, 'x', &:puzzles)
143
213
  end
144
214
  assert !error.message.index('an unexpected space').nil?
145
215
  end
@@ -153,20 +223,24 @@ class TestSource < Minitest::Test
153
223
  cd '#{dir}'
154
224
  git init --quiet .
155
225
  git config user.email test@teamed.io
156
- git config user.name test
226
+ git config user.name test_unknown
157
227
  echo '\x40todo #1 this is the puzzle' > a.txt
158
228
  git add a.txt
159
229
  git commit --quiet -am 'first version'
160
230
  ")
161
- list = PDD::Source.new(File.join(dir, 'a.txt'), '').puzzles
162
- assert_equal 1, list.size
163
- puzzle = list.first
164
- assert_equal '1-de87adc8', puzzle.props[:id]
165
- assert_equal '1-1', puzzle.props[:lines]
166
- assert_equal 'this is the puzzle', puzzle.props[:body]
167
- assert_equal 'test', puzzle.props[:author]
168
- assert_equal 'test@teamed.io', puzzle.props[:email]
169
- assert_match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/, puzzle.props[:time])
231
+
232
+ stub_source_find_github_user(File.join(dir, 'a.txt')) do |source|
233
+ list = source.puzzles
234
+ assert_equal 1, list.size
235
+ puzzle = list.first
236
+ assert_equal '1-de87adc8', puzzle.props[:id]
237
+ assert_equal '1-1', puzzle.props[:lines]
238
+ assert_equal 'this is the puzzle', puzzle.props[:body]
239
+ assert_equal 'test_unknown', puzzle.props[:author]
240
+ assert_equal 'test@teamed.io', puzzle.props[:email]
241
+ assert_match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/,
242
+ puzzle.props[:time])
243
+ end
170
244
  end
171
245
  end
172
246
 
@@ -183,15 +257,19 @@ class TestSource < Minitest::Test
183
257
  git add a.txt
184
258
  git commit --quiet -am 'first version'
185
259
  ")
186
- list = PDD::Source.new(File.join(dir, 'a.txt'), '').puzzles
187
- assert_equal 1, list.size
188
- puzzle = list.first
189
- assert_equal '1-de87adc8', puzzle.props[:id]
190
- assert_equal '1-1', puzzle.props[:lines]
191
- assert_equal 'this is the puzzle', puzzle.props[:body]
192
- assert_equal 'test', puzzle.props[:author]
193
- assert_nil puzzle.props[:email]
194
- assert_match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/, puzzle.props[:time])
260
+
261
+ stub_source_find_github_user(File.join(dir, 'a.txt')) do |source|
262
+ list = source.puzzles
263
+ assert_equal 1, list.size
264
+ puzzle = list.first
265
+ assert_equal '1-de87adc8', puzzle.props[:id]
266
+ assert_equal '1-1', puzzle.props[:lines]
267
+ assert_equal 'this is the puzzle', puzzle.props[:body]
268
+ assert_equal 'test', puzzle.props[:author]
269
+ assert_nil puzzle.props[:email]
270
+ assert_match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/,
271
+ puzzle.props[:time])
272
+ end
195
273
  end
196
274
  end
197
275
 
@@ -207,10 +285,37 @@ class TestSource < Minitest::Test
207
285
  git add a.txt
208
286
  git commit --quiet -am 'first version'
209
287
  ")
210
- list = PDD::Source.new(File.join(dir, 'a.txt'), '').puzzles
211
- assert_equal 1, list.size
212
- puzzle = list.first
213
- assert_equal '@yegor256', puzzle.props[:author]
288
+
289
+ stub_source_find_github_user(File.join(dir, 'a.txt')) do |source|
290
+ list = source.puzzles
291
+ assert_equal 1, list.size
292
+ puzzle = list.first
293
+ assert_equal '@yegor256', puzzle.props[:author]
294
+ end
295
+ end
296
+ end
297
+
298
+ def test_skips_uncommitted_changes
299
+ skip if Gem.win_platform?
300
+ Dir.mktmpdir 'test' do |dir|
301
+ raise unless system("
302
+ cd '#{dir}'
303
+ git init --quiet .
304
+ git config user.email yegor256@gmail.com
305
+ git config user.name test
306
+ echo 'hi' > a.txt
307
+ git add a.txt
308
+ git commit --quiet -am 'first version'
309
+ echo '\x40todo #1 this is a puzzle uncommitted' > a.txt
310
+ ")
311
+
312
+ stub_source_find_github_user(File.join(dir, 'a.txt')) do |source|
313
+ list = source.puzzles
314
+ assert_equal 1, list.size
315
+ puzzle = list.first
316
+ assert_nil puzzle.props[:email]
317
+ assert_equal 'Not Committed Yet', puzzle.props[:author]
318
+ end
214
319
  end
215
320
  end
216
321
 
@@ -221,12 +326,14 @@ class TestSource < Minitest::Test
221
326
  file,
222
327
  '<!--/* @todo #123 puzzle info */-->'
223
328
  )
224
- list = PDD::VerboseSource.new(file, PDD::Source.new(file, 'hey')).puzzles
225
- assert_equal 1, list.size
226
- puzzle = list.first
227
- assert_equal '1-1', puzzle.props[:lines]
228
- assert_equal 'puzzle info', puzzle.props[:body]
229
- assert_equal '123', puzzle.props[:ticket]
329
+ stub_source_find_github_user(file, 'hey') do |source|
330
+ list = source.puzzles
331
+ assert_equal 1, list.size
332
+ puzzle = list.first
333
+ assert_equal '1-1', puzzle.props[:lines]
334
+ assert_equal 'puzzle info', puzzle.props[:body]
335
+ assert_equal '123', puzzle.props[:ticket]
336
+ end
230
337
  end
231
338
  end
232
339
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2018 Yegor Bugayenko
1
+ # Copyright (c) 2014-2021 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -24,16 +24,18 @@ require_relative '../lib/pdd'
24
24
  require_relative '../lib/pdd/sources'
25
25
 
26
26
  class TestSourceTodo < Minitest::Test
27
- def check_valid_puzzle(text, lines, body, ticket)
27
+ def check_valid_puzzle(text, lines, body, ticket, count = 1)
28
28
  Dir.mktmpdir 'test' do |dir|
29
29
  file = File.join(dir, 'a.txt')
30
30
  File.write(file, text)
31
- list = PDD::VerboseSource.new(file, PDD::Source.new(file, 'hey')).puzzles
32
- assert_equal 1, list.size
33
- puzzle = list.first
34
- assert_equal lines, puzzle.props[:lines]
35
- assert_equal body, puzzle.props[:body]
36
- assert_equal ticket, puzzle.props[:ticket]
31
+ stub_source_find_github_user(file, 'hey') do |source|
32
+ list = source.puzzles
33
+ assert_equal count, list.size
34
+ puzzle = list.first
35
+ assert_equal lines, puzzle.props[:lines]
36
+ assert_equal body, puzzle.props[:body]
37
+ assert_equal ticket, puzzle.props[:ticket]
38
+ end
37
39
  end
38
40
  end
39
41
 
@@ -42,7 +44,7 @@ class TestSourceTodo < Minitest::Test
42
44
  file = File.join(dir, 'a.txt')
43
45
  File.write(file, text)
44
46
  error = assert_raises PDD::Error do
45
- PDD::VerboseSource.new(file, PDD::Source.new(file, 'hey')).puzzles
47
+ stub_source_find_github_user(file, 'hey', &:puzzles)
46
48
  end
47
49
  assert !error.message.index(error_msg).nil?
48
50
  end
@@ -71,6 +73,18 @@ class TestSourceTodo < Minitest::Test
71
73
  )
72
74
  end
73
75
 
76
+ def test_todo_utf8_encoded_body
77
+ check_valid_puzzle(
78
+ "
79
+ // TODO #45 Привет, мир, мне кофе
80
+ // вторая линия
81
+ ",
82
+ '2-3',
83
+ 'Привет, мир, мне кофе вторая линия',
84
+ '45'
85
+ )
86
+ end
87
+
74
88
  def test_todo_colon_parsing
75
89
  check_valid_puzzle(
76
90
  "
@@ -82,6 +96,19 @@ class TestSourceTodo < Minitest::Test
82
96
  )
83
97
  end
84
98
 
99
+ def test_multiple_todo_colon
100
+ check_valid_puzzle(
101
+ "
102
+ // TODO: #45 task description
103
+ // TODO: #46 another task description
104
+ ",
105
+ '2-2',
106
+ 'task description',
107
+ '45',
108
+ 2
109
+ )
110
+ end
111
+
85
112
  def test_todo_colon_parsing_multi_line
86
113
  check_valid_puzzle(
87
114
  "