rdoc-spellcheck 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,655 @@
1
+ # coding: UTF-8
2
+
3
+ require 'rubygems'
4
+ require 'minitest/autorun'
5
+ require 'stringio'
6
+ require 'tempfile'
7
+
8
+ gem 'rdoc', '~> 3.12'
9
+
10
+ require 'rdoc' # automatically requires rdoc/generator/spell_check
11
+ require 'rdoc/test_case'
12
+
13
+ class TestRDocGeneratorSpellcheck < RDoc::TestCase
14
+
15
+ def setup
16
+ super
17
+
18
+ @SC = RDoc::Generator::Spellcheck
19
+ @options = RDoc::Options.new
20
+ @options.spell_language = 'en_US'
21
+ @options.spell_minimum_word_length = 3
22
+
23
+ @sc = @SC.new @options
24
+
25
+ @text = 'Hello, this class has real gud spelling!'
26
+
27
+ @tempfile = Tempfile.new __name__
28
+ @tempfile.puts "# #{@text}"
29
+ @tempfile.puts
30
+ @tempfile.puts "# funkify thingus"
31
+ @tempfile.flush
32
+
33
+ @escaped_path = Regexp.escape @tempfile.path
34
+
35
+ @top_level = RDoc::TopLevel.new @tempfile.path
36
+ @top_level.comment = comment 'funkify_thingus'
37
+
38
+ method = RDoc::AnyMethod.new nil, 'funkify_thingus'
39
+ @top_level.add_method method
40
+ end
41
+
42
+ def teardown
43
+ @tempfile.close
44
+
45
+ super
46
+ end
47
+
48
+ def test_add_name
49
+ @sc.add_name 'funkify_thingus'
50
+
51
+ assert @sc.spell.check('funkify'), 'funkify not added to wordlist'
52
+ assert @sc.spell.check('thingus'), 'thingus not added to wordlist'
53
+ end
54
+
55
+ def test_class_setup_options_default
56
+ orig_lang = ENV['LANG']
57
+ ENV['LANG'] = 'en_US.UTF-8'
58
+
59
+ options = RDoc::Options.new
60
+
61
+ options.parse %w[--format spellcheck]
62
+
63
+ refute options.spell_add_words
64
+ refute options.spell_aggregate_all
65
+ assert_equal 4, options.spell_minimum_word_length
66
+ assert_equal 'en_US', options.spell_language
67
+ assert_equal Dir.pwd, options.spell_source_dir
68
+
69
+ assert options.quiet
70
+ ensure
71
+ ENV['LANG'] = orig_lang
72
+ end
73
+
74
+ def test_class_setup_options_spell_aggregate_all
75
+ options = RDoc::Options.new
76
+
77
+ options.parse %w[
78
+ --format spellcheck
79
+ --no-ignore-invalid
80
+ --spell-aggregate-all
81
+ ]
82
+
83
+ assert options.spell_aggregate_all
84
+ end
85
+
86
+ def test_class_setup_options_spell_add_words
87
+ $stdin = StringIO.new "foo bar\nbaz"
88
+
89
+ options = RDoc::Options.new
90
+
91
+ options.parse %w[
92
+ --format spellcheck
93
+ --no-ignore-invalid
94
+ --spell-add-words
95
+ ]
96
+
97
+ assert_equal %w[foo bar baz], options.spell_add_words
98
+ ensure
99
+ $stdin = STDIN
100
+ end
101
+
102
+ def test_class_setup_options_spell_add_words_list
103
+ options = RDoc::Options.new
104
+
105
+ options.parse %w[
106
+ --format spellcheck
107
+ --no-ignore-invalid
108
+ --spell-add-words foo,bar
109
+ ]
110
+
111
+ assert_equal %w[foo bar], options.spell_add_words
112
+ end
113
+
114
+ def test_class_setup_options_spell_add_words_file
115
+ Tempfile.open 'words.txt' do |io|
116
+ io.write "foo bar\nbaz"
117
+ io.rewind
118
+
119
+ options = RDoc::Options.new
120
+
121
+ options.parse %W[
122
+ --format spellcheck
123
+ --no-ignore-invalid
124
+ --spell-add-words #{io.path}
125
+ ]
126
+
127
+ assert_equal %w[foo bar baz], options.spell_add_words
128
+ end
129
+ end
130
+
131
+ def test_class_setup_options_spell_language
132
+ options = RDoc::Options.new
133
+
134
+ options.parse %w[
135
+ --format spellcheck
136
+ --no-ignore-invalid
137
+ --spell-language en_GB
138
+ ]
139
+
140
+ assert_equal 'en_GB', options.spell_language
141
+ end
142
+
143
+ def test_class_setup_options_spell_minimum_word_length
144
+ options = RDoc::Options.new
145
+
146
+ options.parse %w[
147
+ --format spellcheck
148
+ --no-ignore-invalid
149
+ --spell-minimum-word-length 5
150
+ ]
151
+
152
+ assert_equal 5, options.spell_minimum_word_length
153
+ end
154
+
155
+ def test_initialize_add_words
156
+ private_wordlist do
157
+ @options.spell_add_words = %w[funkify thingus]
158
+
159
+ sc = @SC.new @options
160
+
161
+ spell = Aspell.new 'en_US'
162
+
163
+ assert spell.check('funkify'), 'funkify not added to personal wordlist'
164
+ assert spell.check('thingus'), 'thingus not added to personal wordlist'
165
+ end
166
+ end
167
+
168
+ def test_add_name
169
+ @sc.add_name '<=>'
170
+
171
+ assert true # just for counting
172
+ end
173
+
174
+ def test_add_name_utf_8
175
+ @sc.add_name 'Володя'
176
+
177
+ assert true # just for counting
178
+ end
179
+
180
+ def test_find_misspelled
181
+ private_wordlist do
182
+ c = comment @text
183
+
184
+ report = @sc.find_misspelled c
185
+
186
+ word, offset = report.shift
187
+
188
+ assert_equal 'gud', word
189
+ assert_equal 28, offset
190
+ end
191
+ end
192
+
193
+ def test_find_misspelled_length
194
+ private_wordlist do
195
+ c = comment @text
196
+
197
+ @sc.minimum_word_length = 4
198
+ report = @sc.find_misspelled c
199
+
200
+ assert_empty report
201
+ end
202
+ end
203
+
204
+ def test_find_misspelled_quote
205
+ c = comment "doesn't"
206
+
207
+ report = @sc.find_misspelled c
208
+
209
+ assert_empty report
210
+
211
+ c = comment "'quoted'"
212
+
213
+ report = @sc.find_misspelled c
214
+
215
+ assert_empty report
216
+
217
+ c = comment "other's"
218
+
219
+ report = @sc.find_misspelled c
220
+
221
+ assert_empty report
222
+ end
223
+
224
+ def test_find_misspelled_underscore
225
+ private_wordlist do
226
+ c = comment 'gud_method'
227
+
228
+ report = @sc.find_misspelled c
229
+
230
+ word, offset = report.shift
231
+
232
+ assert_equal 'gud', word
233
+ assert_equal 0, offset
234
+ end
235
+ end
236
+
237
+ def test_find_misspelled_utf_8
238
+ private_wordlist do
239
+ c = comment 'Marvin Gülker'
240
+
241
+ report = @sc.find_misspelled c
242
+
243
+ word, offset = report.shift
244
+
245
+ assert_equal 'Gülker', word
246
+ assert_equal 8, offset
247
+ end
248
+ end
249
+
250
+ def test_generate_attribute
251
+ klass = @top_level.add_class RDoc::NormalClass, 'Object'
252
+
253
+ attribute = RDoc::Attr.new nil, 'attr', 'RW', comment(@text)
254
+ attribute.record_location @top_level
255
+
256
+ klass.add_attribute attribute
257
+
258
+ out, err = capture_io do
259
+ @sc.generate [@top_level]
260
+ end
261
+
262
+ assert_empty err
263
+
264
+ assert_match %r%^Object\.attr_accessor :attr in #{@escaped_path}:%, out
265
+ assert_match %r%^"gud"%, out
266
+ end
267
+
268
+ def test_generate_class
269
+ klass = @top_level.add_class RDoc::NormalClass, 'Object'
270
+
271
+ c = comment @text
272
+ klass.add_comment c, @top_level
273
+
274
+ out, err = capture_io do
275
+ @sc.generate [@top_level]
276
+ end
277
+
278
+ assert_empty err
279
+
280
+ assert_match %r%^class Object in #{@escaped_path}:%, out
281
+ assert_match %r%^"gud"%, out
282
+ end
283
+
284
+ def test_generate_constant
285
+ klass = @top_level.add_class RDoc::NormalClass, 'Object'
286
+
287
+ const = RDoc::Constant.new 'CONSTANT', nil, comment(@text)
288
+ const.record_location @top_level
289
+
290
+ klass.add_constant const
291
+
292
+ out, err = capture_io do
293
+ @sc.generate [@top_level]
294
+ end
295
+
296
+ assert_empty err
297
+
298
+ assert_match %r%^Object::CONSTANT in #{@escaped_path}:%, out
299
+ assert_match %r%^"gud"%, out
300
+ end
301
+
302
+ def test_generate_correct
303
+ klass = @top_level.add_class RDoc::NormalClass, 'Object'
304
+
305
+ c = comment 'This class has perfect spelling!'
306
+ klass.add_comment c, @top_level
307
+
308
+ out, err = capture_io do
309
+ @sc.generate [@top_level]
310
+ end
311
+
312
+ assert_empty err
313
+ assert_equal "No misspellings found\n", out
314
+ end
315
+
316
+ def test_generate_file
317
+ @top_level.comment = comment @text
318
+ @top_level.parser = RDoc::Parser::Text
319
+
320
+ out, err = capture_io do
321
+ @sc.generate [@top_level]
322
+ end
323
+
324
+ assert_empty err
325
+
326
+ assert_match %r%^In #{@escaped_path}:%, out
327
+ assert_match %r%^"gud"%, out
328
+ end
329
+
330
+ def test_generate_include
331
+ klass = @top_level.add_class RDoc::NormalClass, 'Object'
332
+
333
+ incl = RDoc::Include.new 'INCLUDE', comment(@text)
334
+ incl.record_location @top_level
335
+
336
+ klass.add_include incl
337
+
338
+ out, err = capture_io do
339
+ @sc.generate [@top_level]
340
+ end
341
+
342
+ assert_empty err
343
+
344
+ assert_match %r%^Object\.include INCLUDE in #{@escaped_path}:%, out
345
+ assert_match %r%^"gud"%, out
346
+ end
347
+
348
+ def test_generate_method
349
+ klass = @top_level.add_class RDoc::NormalClass, 'Object'
350
+
351
+ meth = RDoc::AnyMethod.new nil, 'method'
352
+ meth.record_location @top_level
353
+ meth.comment = comment @text, meth
354
+
355
+ klass.add_method meth
356
+
357
+ out, err = capture_io do
358
+ @sc.generate [@top_level]
359
+ end
360
+
361
+ assert_empty err
362
+
363
+ assert_match %r%^Object#method in #{@escaped_path}:%, out
364
+ assert_match %r%^"gud"%, out
365
+ end
366
+
367
+ def test_generate_multiple
368
+ klass = @top_level.add_class RDoc::NormalClass, 'Object'
369
+ c = comment @text
370
+ klass.add_comment c, @top_level
371
+
372
+ meth = RDoc::AnyMethod.new nil, 'method'
373
+ meth.record_location @top_level
374
+ meth.comment = comment @text, meth
375
+
376
+ klass.add_method meth
377
+
378
+ out, err = capture_io do
379
+ @sc.generate [@top_level]
380
+ end
381
+
382
+ assert_empty err
383
+
384
+ assert_match %r%^Object#method in #{@escaped_path}:%, out
385
+ assert_match %r%^"gud"%, out
386
+ assert_match %r%^2 gud%, out
387
+ end
388
+
389
+ def test_location_of
390
+ Tempfile.open 'location_of' do |io|
391
+ io.puts "##"
392
+ io.puts "# Here is some text with proper spelling"
393
+ io.puts "#"
394
+ io.puts "# #{@text}"
395
+ io.flush
396
+
397
+ tl = RDoc::TopLevel.new io.path
398
+ text = "Here is some text with proper spelling\n\n#{@text}"
399
+ offset = text.index "gud"
400
+
401
+ line, column = @sc.location_of text, offset, tl
402
+
403
+ assert_equal 3, line
404
+ assert_equal 30, column
405
+ end
406
+ end
407
+
408
+ def test_location_of_first_line
409
+ Tempfile.open 'location_of' do |io|
410
+ io.puts "# #{@text}"
411
+ io.flush
412
+
413
+ tl = RDoc::TopLevel.new io.path
414
+ offset = @text.index "gud"
415
+
416
+ line, column = @sc.location_of @text, offset, tl
417
+
418
+ assert_equal 0, line
419
+ assert_equal 30, column
420
+ end
421
+ end
422
+
423
+ def test_location_of_include
424
+ Tempfile.open 'location_of' do |io|
425
+ io.puts "##"
426
+ io.puts "# Here is some text with proper spelling"
427
+ io.puts "#"
428
+ io.puts "# :include: other.rdoc"
429
+ io.flush
430
+
431
+ tl = RDoc::TopLevel.new io.path
432
+ text = "Here is some text with proper spelling\n\n#{@text}"
433
+ offset = text.index "gud"
434
+
435
+ assert_nil @sc.location_of text, offset, tl
436
+ end
437
+ end
438
+
439
+ def test_misspellings_for
440
+ out = @sc.misspellings_for 'class Object', comment(@text), @top_level
441
+
442
+ out = out.join "\n"
443
+
444
+ location = Regexp.escape @top_level.absolute_name
445
+ assert_match %r%^class Object in #{location}%, out
446
+ assert_match %r%^#{location}:0:32%, out
447
+ assert_match %r%^"gud"%, out
448
+ end
449
+
450
+ def test_misspellings_for_empty
451
+ out = @sc.misspellings_for 'class Object', comment(''), @top_level
452
+
453
+ assert_empty out
454
+ end
455
+
456
+ def test_misspellings_for_include
457
+ Tempfile.open 'other' do |io|
458
+ io.write "# :include: original.txt"
459
+ io.flush
460
+
461
+ tl = RDoc::TopLevel.new io.path
462
+
463
+ out = @sc.misspellings_for 'class Object', comment(@text), tl
464
+
465
+ out = out.join "\n"
466
+
467
+ include_location = Regexp.escape tl.absolute_name
468
+ source_location = Regexp.escape @top_level.absolute_name
469
+
470
+ assert_match %r%^class Object in #{include_location}%, out
471
+ assert_match %r%^\(via include\)%, out
472
+ assert_match %r%^"gud"%, out
473
+ end
474
+ end
475
+
476
+ def test_setup_dictionary_attribute
477
+ klass = @top_level.add_class RDoc::NormalClass, 'Object'
478
+
479
+ attribute = RDoc::Attr.new nil, 'funkify_thingus', 'RW', comment(@text)
480
+ attribute.record_location @top_level
481
+
482
+ klass.add_attribute attribute
483
+
484
+ @sc.setup_dictionary
485
+
486
+ assert @sc.spell.check('FUNKIFY'), 'FUNKIFY not added to wordlist'
487
+ assert @sc.spell.check('THINGUS'), 'THINGUS not added to wordlist'
488
+ end
489
+
490
+ def test_setup_dictionary_class
491
+ klass = @top_level.add_class RDoc::NormalClass, 'FunkifyThingus'
492
+
493
+ c = comment @text
494
+ klass.add_comment c, @top_level
495
+
496
+ @sc.setup_dictionary
497
+
498
+ assert @sc.spell.check('FunkifyThingus'),
499
+ 'FunkifyThingus not added to wordlist'
500
+ end
501
+
502
+ def test_setup_dictionary_constant
503
+ klass = @top_level.add_class RDoc::NormalClass, 'Object'
504
+
505
+ const = RDoc::Constant.new 'FUNKIFY_THINGUS', nil, comment(@text)
506
+ const.record_location @top_level
507
+
508
+ klass.add_constant const
509
+
510
+ @sc.setup_dictionary
511
+
512
+ assert @sc.spell.check('FUNKIFY'), 'FUNKIFY not added to wordlist'
513
+ assert @sc.spell.check('THINGUS'), 'THINGUS not added to wordlist'
514
+ end
515
+
516
+ def test_setup_dictionary_defaults
517
+ @sc.setup_dictionary
518
+
519
+ word = RDoc::Generator::Spellcheck::DEFAULT_WORDS.first
520
+
521
+ assert @sc.spell.check(word), "#{word} not added to wordlist"
522
+ end
523
+
524
+ def test_setup_dictionary_file
525
+ RDoc::TopLevel.new 'funkify_thingus.rb'
526
+
527
+ @sc.setup_dictionary
528
+
529
+ assert @sc.spell.check('funkify'), 'funkify not added to wordlist'
530
+ assert @sc.spell.check('thingus'), 'thingus not added to wordlist'
531
+ end
532
+
533
+ def test_setup_dictionary_include
534
+ klass = @top_level.add_class RDoc::NormalClass, 'Object'
535
+
536
+ incl = RDoc::Include.new 'FUNKIFY_THINGUS', comment(@text)
537
+ incl.record_location @top_level
538
+
539
+ klass.add_include incl
540
+
541
+ @sc.setup_dictionary
542
+
543
+ assert @sc.spell.check('FUNKIFY'), 'FUNKIFY not added to wordlist'
544
+ assert @sc.spell.check('THINGUS'), 'THINGUS not added to wordlist'
545
+ end
546
+
547
+ def test_setup_dictionary_method
548
+ klass = @top_level.add_class RDoc::NormalClass, 'Object'
549
+
550
+ meth = RDoc::AnyMethod.new nil, 'bagas_methd'
551
+ meth.block_params = 'foo, bar'
552
+ meth.params = 'baz, hoge'
553
+ meth.record_location @top_level
554
+ meth.comment = comment @text, meth
555
+
556
+ klass.add_method meth
557
+
558
+ @sc.setup_dictionary
559
+
560
+ assert @sc.spell.check('bagas'), 'bagas not added to wordlist'
561
+ assert @sc.spell.check('methd'), 'methd not added to wordlist'
562
+
563
+ assert @sc.spell.check('foo'), 'foo not added to wordlist'
564
+ assert @sc.spell.check('bar'), 'bar not added to wordlist'
565
+ assert @sc.spell.check('baz'), 'baz not added to wordlist'
566
+ assert @sc.spell.check('hoge'), 'hoge not added to wordlist'
567
+ end
568
+
569
+ def test_suggestion_text
570
+ out = @sc.suggestion_text @text, 'gud', 28
571
+
572
+ suggestions = suggest('gud').join ', '
573
+
574
+ expected = <<-EXPECTED
575
+ "...has real \e[1;31mgud\e[m spelling!..."
576
+
577
+ "gud" suggestions:
578
+ \t#{suggestions}
579
+
580
+ EXPECTED
581
+
582
+ assert_equal expected, out
583
+ end
584
+
585
+ def test_suggestion_text_end
586
+ out = @sc.suggestion_text 'you did real gud', 'gud', 14
587
+
588
+ suggestions = suggest('gud').join ', '
589
+
590
+ expected = <<-EXPECTED
591
+ "...did real \e[1;31mgud\e[m"
592
+
593
+ "gud" suggestions:
594
+ \t#{suggestions}
595
+
596
+ EXPECTED
597
+
598
+ assert_equal expected, out
599
+ end
600
+
601
+ def test_suggestion_text_newline
602
+ text = "This text has a typo\non the secnd line"
603
+ out = @sc.suggestion_text text, 'secnd', 29
604
+
605
+ suggestions = suggest('secnd').join ', '
606
+
607
+ expected = <<-EXPECTED
608
+ "...o\non the \e[1;31msecnd\e[m line"
609
+
610
+ "secnd" suggestions:
611
+ \t#{suggestions}
612
+
613
+ EXPECTED
614
+
615
+ assert_equal expected, out
616
+ end
617
+
618
+ def test_suggestion_text_start
619
+ out = @sc.suggestion_text 'gud night world, see you tomorrow', 'gud', 0
620
+
621
+ suggestions = suggest('gud').join ', '
622
+
623
+ expected = <<-EXPECTED
624
+ "\e[1;31mgud\e[m night wor..."
625
+
626
+ "gud" suggestions:
627
+ \t#{suggestions}
628
+
629
+ EXPECTED
630
+
631
+ assert_equal expected, out
632
+ end
633
+
634
+ def private_wordlist
635
+ orig_aspell_conf = ENV['ASPELL_CONF']
636
+
637
+ Tempfile.open 'personal_wordlist' do |wordlist|
638
+ Tempfile.open 'personal_repl' do |repl|
639
+ ENV['ASPELL_CONF'] = "personal #{wordlist.path};repl #{repl.path}"
640
+
641
+ @sc = @SC.new @options
642
+
643
+ yield
644
+ end
645
+ end
646
+ ensure
647
+ ENV['ASPELL_CONF'] = orig_aspell_conf
648
+ end
649
+
650
+ def suggest word
651
+ Aspell.new('en_US').suggest(word).first 5
652
+ end
653
+
654
+ end
655
+