asciidoctor-doctest 2.0.0.beta.4 → 2.0.0.beta.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.adoc +58 -0
  3. data/LICENSE +21 -0
  4. data/README.adoc +310 -0
  5. data/asciidoctor-doctest.gemspec +48 -0
  6. data/data/examples/asciidoc/embedded.adoc +15 -0
  7. data/data/examples/asciidoc/preamble.adoc +1 -2
  8. data/data/examples/asciidoc/section.adoc +9 -0
  9. data/data/examples/asciidoc/toc.adoc +21 -9
  10. data/lib/asciidoctor/doctest/html/converter.rb +1 -1
  11. data/lib/asciidoctor/doctest/io/asciidoc.rb +2 -3
  12. data/lib/asciidoctor/doctest/io/base.rb +1 -1
  13. data/lib/asciidoctor/doctest/io/xml.rb +1 -1
  14. data/lib/asciidoctor/doctest/test_reporter.rb +3 -3
  15. data/lib/asciidoctor/doctest/version.rb +1 -1
  16. metadata +20 -69
  17. data/doc/img/doctest-diag.odf +0 -0
  18. data/doc/img/doctest-diag.svg +0 -56
  19. data/doc/img/failing-test-term.gif +0 -0
  20. data/features/README +0 -1
  21. data/features/fixtures/html-slim/Rakefile +0 -9
  22. data/features/fixtures/html-slim/examples/asciidoc/document.adoc +0 -4
  23. data/features/fixtures/html-slim/examples/asciidoc/inline_quoted.adoc +0 -2
  24. data/features/fixtures/html-slim/examples/asciidoc/quote.adoc +0 -12
  25. data/features/fixtures/html-slim/examples/html/document.html +0 -7
  26. data/features/fixtures/html-slim/examples/html/quote.html +0 -26
  27. data/features/fixtures/html-slim/templates/document.html.slim +0 -13
  28. data/features/fixtures/html-slim/templates/embedded.html.slim +0 -3
  29. data/features/fixtures/html-slim/templates/inline_quoted.html.slim +0 -8
  30. data/features/fixtures/html-slim/templates/paragraph.html.slim +0 -1
  31. data/features/fixtures/html-slim/templates/quote.html.slim +0 -7
  32. data/features/generator_html.feature +0 -171
  33. data/features/step_definitions/doctest_steps.rb +0 -5
  34. data/features/support/env.rb +0 -24
  35. data/features/test_html.feature +0 -98
  36. data/spec/asciidoc_converter_spec.rb +0 -64
  37. data/spec/example_spec.rb +0 -180
  38. data/spec/factory_spec.rb +0 -46
  39. data/spec/html/converter_spec.rb +0 -137
  40. data/spec/html_normalizer_spec.rb +0 -70
  41. data/spec/io/asciidoc_spec.rb +0 -139
  42. data/spec/io/xml_spec.rb +0 -141
  43. data/spec/minitest_diffy_spec.rb +0 -59
  44. data/spec/no_fallback_template_converter_spec.rb +0 -38
  45. data/spec/shared_examples/base_examples.rb +0 -289
  46. data/spec/spec_helper.rb +0 -39
  47. data/spec/support/matchers.rb +0 -7
  48. data/spec/tester_spec.rb +0 -153
@@ -1,59 +0,0 @@
1
- require 'asciidoctor/doctest/minitest_diffy'
2
- require 'corefines'
3
-
4
- using Corefines::String::color
5
-
6
- describe Diffy::Format do
7
-
8
- describe '#minitest' do
9
-
10
- subject(:output) { input.minitest }
11
- let(:input) { [] }
12
-
13
- # This looks odd, but Diffy is actually using Format exactly like that.
14
- # https://github.com/samg/diffy/blob/6e1f1312/lib/diffy/diff.rb#L132
15
- before { input.extend described_class }
16
-
17
- it { expect(described_class).to have_method :minitest }
18
-
19
- context 'line starting with ---, or +++' do
20
- let(:input) { ['--- a/file.rb', '+++ b/file.rb'] }
21
-
22
- it 'discards the line' do
23
- expect(output.chomp).to be_empty
24
- end
25
- end
26
-
27
- context 'line with ""' do
28
- let(:input) { [''] }
29
-
30
- it 'discards this line' do
31
- expect(output.chomp).to be_empty
32
- end
33
- end
34
-
35
- context 'line starting with +' do
36
- let(:input) { ['+ <div><p>chunky bacon</p></div>'] }
37
-
38
- it 'replaces "+" with "A", adds padding and colour' do
39
- is_expected.to eq "\n" + 'A <div><p>chunky bacon</p></div>'.color(:red)
40
- end
41
- end
42
-
43
- context 'line starting with -' do
44
- let(:input) { ['- <p>chunky bacon</p>'] }
45
-
46
- it 'replaces "-" with "E", adds padding and colour' do
47
- is_expected.to eq "\n" + 'E <p>chunky bacon</p>'.color(:green)
48
- end
49
- end
50
-
51
- context 'normal lines' do
52
- let(:input) { ['Lorem ipsum dolor', ' sit amet'] }
53
-
54
- it 'returns the lines with padding' do
55
- is_expected.to eq "\n Lorem ipsum dolor\n sit amet"
56
- end
57
- end
58
- end
59
- end
@@ -1,38 +0,0 @@
1
- describe DocTest::NoFallbackTemplateConverter do
2
-
3
- subject(:delegator) { described_class.new('html5', template_dirs: ['/tmp/html5']) }
4
-
5
- describe '#convert' do
6
-
7
- let(:converter) { delegator.__getobj__ }
8
- let(:node) { double('Node', node_name: 'block_foo') }
9
-
10
- before do
11
- expect(converter).to receive(:handles?).with('block_foo').and_return(handles)
12
- end
13
-
14
- context 'when template is not found' do
15
- let(:handles) { false }
16
-
17
- it 'returns a not found marker instead of converted node' do
18
- expect(converter).to_not receive(:convert)
19
- expect(delegator.convert node).to eq described_class::NOT_FOUND_MARKER
20
- end
21
-
22
- it 'prints a warning on stderr' do
23
- expect { delegator.convert node }.to output(/Could not find a custom template/i).to_stderr
24
- end
25
- end
26
-
27
- context 'when template is found' do
28
- let(:handles) { true }
29
-
30
- it 'delegates to the original #convert and returns result' do
31
- expect(converter).to receive(:convert)
32
- .with(node, 'block_foo', {}).and_return('allons-y!')
33
-
34
- expect(delegator.convert node).to eq 'allons-y!'
35
- end
36
- end
37
- end
38
- end
@@ -1,289 +0,0 @@
1
- require 'fileutils'
2
- require 'forwardable'
3
-
4
- using Corefines::Array::second
5
-
6
- shared_examples DocTest::IO::Base do
7
-
8
- subject(:suite) { described_class.new(file_ext: '.adoc', path: path) }
9
- let(:path) { ['/tmp/alpha', '/tmp/beta'] }
10
-
11
-
12
- describe '#initialize' do
13
-
14
- subject(:init) { described_class.new(args) }
15
- let(:args) { {} }
16
-
17
- {'nil' => nil, 'blank' => ' '}.each do |desc, file_ext|
18
- context "with file_ext #{desc}" do
19
- let(:args) { {file_ext: file_ext, path: path} }
20
- it { expect { init }.to raise_error ArgumentError }
21
- end
22
- end
23
-
24
- context 'with path string' do
25
- let(:args) { {file_ext: '.html', path: '/foo/bar'} }
26
-
27
- it 'wraps string to array' do
28
- is_expected.to have_attributes(path: ['/foo/bar'])
29
- end
30
- end
31
- end
32
-
33
-
34
- describe '#parse' do
35
- context 'empty file' do
36
- subject { suite.parse '', 'block_ulist' }
37
-
38
- it { is_expected.to be_empty }
39
- end
40
- end
41
-
42
-
43
- describe '#read_examples' do
44
- include FakeFS::SpecHelpers
45
-
46
- subject(:result) { suite.read_examples group_name }
47
-
48
- let(:group_name) { 'section' }
49
-
50
- before do
51
- path.each { |p| FileUtils.mkpath p }
52
- create_and_write_group path.first, 'noise', '.adoc', 'foo', 'bar'
53
-
54
- allow(suite).to receive(:parse) do |input, group_name|
55
- path, file_name, *example_names = input.split("\n")
56
- expect(group_name).to eq file_name.split('.').first
57
-
58
- example_names.map do |name|
59
- # this content is just filling to identify the example in test
60
- create_example [group_name, name], content: "#{path}/#{file_name}:#{name}"
61
- end
62
- end
63
- end
64
-
65
- context "when the group's file is not found" do
66
- it { is_expected.to be_empty }
67
- end
68
-
69
- context "when the group's file has a wrong file extension" do
70
- before do
71
- create_and_write_group path.first, group_name, '.html', 'level1', 'level2'
72
- end
73
-
74
- it { is_expected.to be_empty }
75
- end
76
-
77
- context 'when single group file is found' do
78
- let! :examples do
79
- create_and_write_group path.second, group_name, '.adoc', 'level1', 'level2'
80
- end
81
-
82
- it 'returns parsed examples' do
83
- is_expected.to eq examples
84
- end
85
- end
86
-
87
- context 'when multiple group files are found and contains example with same name' do
88
- let! :examples do
89
- first = create_and_write_group path.first, group_name, '.adoc', 'level1', 'level2'
90
- second = create_and_write_group path.second, group_name, '.adoc', 'level2', 'level3'
91
- [*first, second[1]]
92
- end
93
-
94
- it 'returns parsed examples without duplicates (first wins)' do
95
- is_expected.to eq examples
96
- end
97
- end
98
- end
99
-
100
-
101
- describe '#write_examples' do
102
- include FakeFS::SpecHelpers
103
-
104
- let :examples do
105
- (1..2).map { |i| create_example "section:level#{i}", content: 'yada' }
106
- end
107
-
108
- before { path.each { |p| FileUtils.mkpath p } }
109
-
110
- it 'writes serialized examples to file named after the group with file extension' do
111
- expect(suite).to receive :serialize do |exmpls|
112
- exmpls.map(&:name).join("\n")
113
- end
114
- suite.write_examples examples
115
-
116
- file = File.read "#{path.first}/section.adoc"
117
- expect(file).to eq examples.map(&:name).join("\n")
118
- end
119
- end
120
-
121
-
122
- describe '#file_names' do
123
- include FakeFS::SpecHelpers
124
-
125
- subject(:result) { suite.group_names }
126
-
127
- before { path.each { |p| FileUtils.mkpath p } }
128
-
129
- context 'when no file is found' do
130
- it { is_expected.to be_empty }
131
- end
132
-
133
- it 'returns names of files with matching file extension only' do
134
- %w[block_image.html block_ulist.adoc].each do |name|
135
- File.write "#{path.first}/#{name}", 'yada'
136
- end
137
- is_expected.to contain_exactly 'block_ulist'
138
- end
139
-
140
- it 'returns names sorted and deduplicated' do
141
- (names = %w[z j d c k d]).each_with_index do |name, i|
142
- File.write "#{path[i % 2]}/#{name}.adoc", 'yada'
143
- end
144
-
145
- is_expected.to eq names.uniq.sort
146
- end
147
-
148
- it 'ignores directories and files in subdirectories' do
149
- Dir.mkdir "#{path.first}/invalid.adoc"
150
- File.write "#{path.first}/invalid.adoc/wat.adoc", 'yada'
151
-
152
- is_expected.to be_empty
153
- end
154
- end
155
-
156
-
157
- describe '#update_examples' do
158
-
159
- let :current do
160
- %w[gr0:ex0 gr0:ex1 gr1:ex0 gr1:ex1].map do |name|
161
- create_example name, content: name.reverse
162
- end
163
- end
164
- let :updated do
165
- [ (create_example 'gr0:ex0', content: 'allons-y!'),
166
- (create_example 'gr1:ex1', content: 'allons-y!') ]
167
- end
168
-
169
- before do
170
- expect(suite).to receive(:read_examples).exactly(2).times do |group_name|
171
- current.select { |e| e.group_name == group_name }
172
- end
173
- end
174
-
175
- it 'merges current and updated examples and writes them' do
176
- is_expected.to receive(:write_examples).with [updated[0], current[1]]
177
- is_expected.to receive(:write_examples).with [current[2], updated[1]]
178
-
179
- suite.update_examples updated
180
- end
181
- end
182
-
183
-
184
- describe '#pair_with' do
185
-
186
- subject(:result) { ours_suite.pair_with(theirs_suite).to_a }
187
- let(:result_names) { result.map(&:first).map(&:name) }
188
-
189
- let(:ours_suite) { described_class.new(file_ext: '.xyz') }
190
- let(:theirs_suite) { DocTest::IO::Asciidoc.new(file_ext: '.adoc') }
191
-
192
- def ours_exmpl(suffix, group = 0)
193
- create_example "gr#{group}:ex#{suffix}", content: 'ours!'
194
- end
195
-
196
- def theirs_exmpl(suffix, group = 0)
197
- create_example "gr#{group}:ex#{suffix}", content: 'theirs!'
198
- end
199
-
200
- before do
201
- expect(ours_suite).to receive(:group_names)
202
- .and_return(['gr0', 'gr1'])
203
- expect(theirs_suite).to receive(:read_examples)
204
- .with(/gr[0-1]/).exactly(:twice).and_return(*theirs)
205
- expect(ours_suite).to receive(:read_examples)
206
- .with(/gr[0-1]/).exactly(:twice).and_return(*ours)
207
- end
208
-
209
- context do
210
- let :ours do
211
- [ [ ours_exmpl(0, 0), ours_exmpl(1, 0) ], [ ours_exmpl(0, 1), ours_exmpl(1, 1) ] ]
212
- end
213
- let :theirs do
214
- [ [ theirs_exmpl(1, 0), theirs_exmpl(0, 0) ], [ theirs_exmpl(0, 1), theirs_exmpl(1, 1) ] ]
215
- end
216
-
217
- it 'returns pairs of ours/theirs examples in ours order' do
218
- expect(result_names).to eq %w[gr0:ex0 gr0:ex1 gr1:ex0 gr1:ex1]
219
- expect(result).to eq ours.flatten(1).zip theirs.flatten(1).sort_by(&:name)
220
- end
221
- end
222
-
223
- context 'when some example is missing' do
224
- let(:ours) { [(0..2).map { |i| ours_exmpl i }, []] }
225
- let(:theirs) { [[1, 0, 2].map { |i| theirs_exmpl i }, []] }
226
-
227
- context 'in theirs suite' do
228
- let(:theirs) { [ [theirs_exmpl(2), theirs_exmpl(0)], [] ] }
229
-
230
- it 'returns pairs in ours order' do
231
- expect(result_names).to eq %w[gr0:ex0 gr0:ex1 gr0:ex2]
232
- end
233
-
234
- it 'replaces the missing example with empty one with the name' do
235
- expect(result.second.last).to eq create_example 'gr0:ex1'
236
- end
237
- end
238
-
239
- context 'in ours suite' do
240
- let(:ours) { [ [ours_exmpl(1), ours_exmpl(2)], [] ] }
241
-
242
- it 'returns pairs in ours order with the missing example at the end' do
243
- expect(result_names).to eq %w[gr0:ex1 gr0:ex2 gr0:ex0]
244
- end
245
-
246
- it 'replaces the missing example with empty one with the name' do
247
- expect(result.last.first).to eq create_example 'gr0:ex0'
248
- end
249
- end
250
- end
251
- end
252
-
253
-
254
- describe '#format_options' do
255
-
256
- shared_examples :format_options do |input, output|
257
- it "returns #{output} for #{input}" do
258
- expect(suite.send(:format_options, input)).to eq output
259
- end
260
- end
261
-
262
- context 'empty' do
263
- include_examples :format_options, {}, []
264
- end
265
-
266
- context 'options with one value' do
267
- include_examples :format_options, {opt1: 'val1', opt2: 'val2'}, [':opt1: val1', ':opt2: val2']
268
- end
269
-
270
- context 'options with multiple values' do
271
- include_examples :format_options, {opt1: %w[val11 val12], opt2: ['val2']},
272
- [':opt1: val11', ':opt1: val12', ':opt2: val2']
273
- end
274
-
275
- context 'boolean options' do
276
- include_examples :format_options, {opt1: true, opt2: false}, [':opt1:', ':opt2: false']
277
- end
278
- end
279
-
280
-
281
- def create_and_write_group(path, group_name, file_ext, *examples)
282
- content = [path, group_name + file_ext, *examples].join("\n")
283
- File.write File.join(path, group_name + file_ext), content
284
-
285
- examples.map do |name|
286
- create_example [group_name, name], content: "#{path}/#{group_name}#{file_ext}:#{name}"
287
- end
288
- end
289
- end
data/spec/spec_helper.rb DELETED
@@ -1,39 +0,0 @@
1
- require 'corefines'
2
- require 'rspec/collection_matchers'
3
- require 'simplecov'
4
- require 'asciidoctor/doctest'
5
- require 'fakefs/spec_helpers'
6
-
7
- Dir['./spec/{shared_examples,support}/**/*.rb'].each { |file| require file }
8
-
9
- RSpec.configure do |config|
10
-
11
- # rspec-expectations config
12
- config.expect_with :rspec do |expects|
13
-
14
- # This option disables deprecated 'should' syntax.
15
- expects.syntax = :expect
16
-
17
- # This option makes the +description+ and +failure_message+ of custom
18
- # matchers include text for helper methods defined using +chain+, e.g.:
19
- # be_bigger_than(2).and_smaller_than(4).description
20
- # # => "be bigger than 2 and smaller than 4"
21
- # ...rather than:
22
- # # => "be bigger than 2"
23
- expects.include_chain_clauses_in_custom_matcher_descriptions = true
24
- end
25
-
26
- # rspec-mocks config
27
- config.mock_with :rspec do |mocks|
28
-
29
- # Prevents you from mocking or stubbing a method that does not exist on
30
- # a real object.
31
- mocks.verify_partial_doubles = true
32
- end
33
-
34
- config.color = true
35
- end
36
-
37
- def create_example(*args)
38
- DocTest::Example.new(*args)
39
- end
@@ -1,7 +0,0 @@
1
- require 'rspec/expectations'
2
-
3
- RSpec::Matchers.define :have_method do |*names|
4
- match do |klass|
5
- names.all? { |name| klass.method_defined? name }
6
- end
7
- end
data/spec/tester_spec.rb DELETED
@@ -1,153 +0,0 @@
1
- describe DocTest::Tester do
2
-
3
- subject(:tester) { described_class.new(input_suite, output_suite, converter, reporter) }
4
-
5
- let(:converter) { double 'converter' }
6
- let(:input_suite) { double 'ExamplesSuite' }
7
- let(:output_suite) { double 'ExamplesSuite' }
8
- let(:reporter) { spy 'Reporter' }
9
- let(:examples) { fixtures }
10
-
11
-
12
- describe '#initialize' do
13
-
14
- context "with default reporter" do
15
- subject(:tester) { described_class.new(input_suite, output_suite, converter, nil) }
16
-
17
- it { expect(tester.reporter).to be_a DocTest::TestReporter }
18
- end
19
- end
20
-
21
-
22
- describe '#run_tests' do
23
-
24
- before do |ex|
25
- next if ex.metadata[:skip_before]
26
-
27
- expect(input_suite).to receive(:pair_with)
28
- .with(output_suite).and_return(examples.values)
29
- allow(tester).to receive(:test_example)
30
- end
31
-
32
- context "with default pattern" do
33
-
34
- it "pairs the examples and tests all valid pairs" do
35
- ['ex:alpha', 'ex:beta', 'ex:nooutput'].each do |name|
36
- expect(tester).to receive(:test_example).with(*examples[name])
37
- end
38
- tester.run_tests
39
- end
40
- end
41
-
42
- context "with specific pattern" do
43
-
44
- it "pairs the examples and tests those matching the pattern" do
45
- expect(tester).to receive(:test_example).with(*examples['ex:beta'])
46
- tester.run_tests(pattern: 'ex:b*')
47
- end
48
- end
49
-
50
- it "ignores pairs with empty input example" do
51
- expect(tester).to_not receive(:test_example).with(*examples['ex:noinput'])
52
- tester.run_tests
53
- end
54
-
55
- it "calls reporter's methods in the correct order", :skip_before do
56
- expect(reporter).to receive(:start).ordered
57
- expect(input_suite).to receive(:pair_with).and_return([]).ordered
58
- expect(reporter).to receive(:report).ordered
59
- expect(reporter).to receive(:passed?).ordered
60
-
61
- tester.run_tests
62
- end
63
- end
64
-
65
-
66
- describe '#test_example' do
67
-
68
- subject(:failures) { tester.test_example input_exmpl, output_exmpl }
69
-
70
- let(:examples_pair) { examples['ex:alpha'] }
71
- let(:input_exmpl) { examples_pair[0] }
72
- let(:output_exmpl) { examples_pair[1] }
73
- let(:actual) { output_exmpl.content }
74
- let(:expected) { output_exmpl.content }
75
-
76
- shared_examples :example do
77
- it "calls reporter" do
78
- expect(reporter).to receive(:record)
79
- tester.test_example input_exmpl, output_exmpl
80
- end
81
- end
82
-
83
- before do |ex|
84
- next if ex.metadata[:skip_before]
85
-
86
- expect(converter).to receive(:convert_examples)
87
- .with(input_exmpl, output_exmpl)
88
- .and_return([actual, expected])
89
- end
90
-
91
-
92
- context "when output example is empty", :skip_before do
93
-
94
- let(:examples_pair) { examples['ex:nooutput'] }
95
-
96
- it "skips the test" do
97
- is_expected.to contain_exactly Minitest::Skip
98
- end
99
-
100
- include_examples :example
101
- end
102
-
103
- context "when examples are equivalent" do
104
-
105
- it "returns no failure" do
106
- is_expected.to be_empty
107
- end
108
-
109
- include_examples :example
110
- end
111
-
112
- context "when examples are not equivalent" do
113
-
114
- let(:actual) { '<em>meh</em>' }
115
-
116
- it "returns failure" do
117
- is_expected.to include Minitest::Assertion
118
- end
119
-
120
- context "and input example has desc:" do
121
-
122
- it "returns failure with message that starts with the desc" do
123
- expect(failures.first.message).to match /^yada.*/
124
- end
125
- end
126
-
127
- context "and both input and output examples have desc:" do
128
-
129
- let(:examples_pair) { examples['ex:beta'] }
130
-
131
- it "returns failure with message that starts with the output's example desc" do
132
- expect(failures.first.message).to match /^Yoda.*/
133
- end
134
- end
135
-
136
- include_examples :example
137
- end
138
- end
139
-
140
-
141
- def fixtures
142
- data = {
143
- 'ex:alpha' => [ {content: '_alpha_', desc: 'yada'}, {content: '<i>alpha</i>'} ],
144
- 'ex:beta' => [ {content: '*beta*', desc: 'yada'}, {content: '<b>beta</b>', desc: 'Yoda'} ],
145
- 'ex:noinput' => [ {}, {content: '<del>noinput</del>'} ],
146
- 'ex:nooutput' => [ {content: 'nooutput'}, {} ]
147
- }
148
- data = data.map { |name, tuple|
149
- [ name, tuple.map { |opts| DocTest::Example.new(name, opts) } ]
150
- }
151
- Hash[data]
152
- end
153
- end