recog 3.1.1 → 3.1.2

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Gemfile +6 -0
  4. data/Rakefile +7 -5
  5. data/lib/recog/db.rb +67 -68
  6. data/lib/recog/db_manager.rb +22 -21
  7. data/lib/recog/fingerprint/regexp_factory.rb +10 -13
  8. data/lib/recog/fingerprint/test.rb +9 -8
  9. data/lib/recog/fingerprint.rb +252 -262
  10. data/lib/recog/fingerprint_parse_error.rb +3 -1
  11. data/lib/recog/formatter.rb +41 -39
  12. data/lib/recog/match_reporter.rb +82 -83
  13. data/lib/recog/matcher.rb +37 -40
  14. data/lib/recog/matcher_factory.rb +7 -6
  15. data/lib/recog/nizer.rb +218 -224
  16. data/lib/recog/verifier.rb +30 -28
  17. data/lib/recog/verify_reporter.rb +69 -73
  18. data/lib/recog/version.rb +3 -1
  19. data/lib/recog.rb +2 -0
  20. data/recog/bin/recog_match +21 -20
  21. data/recog/xml/apache_modules.xml +2 -0
  22. data/recog/xml/dhcp_vendor_class.xml +1 -1
  23. data/recog/xml/favicons.xml +133 -1
  24. data/recog/xml/ftp_banners.xml +1 -1
  25. data/recog/xml/html_title.xml +140 -1
  26. data/recog/xml/http_cookies.xml +20 -2
  27. data/recog/xml/http_servers.xml +38 -17
  28. data/recog/xml/http_wwwauth.xml +17 -4
  29. data/recog/xml/mdns_device-info_txt.xml +49 -15
  30. data/recog/xml/sip_banners.xml +0 -2
  31. data/recog/xml/sip_user_agents.xml +1 -1
  32. data/recog/xml/snmp_sysdescr.xml +1 -2
  33. data/recog/xml/ssh_banners.xml +8 -0
  34. data/recog/xml/telnet_banners.xml +3 -2
  35. data/recog/xml/tls_jarm.xml +1 -1
  36. data/recog/xml/x11_banners.xml +1 -0
  37. data/recog/xml/x509_issuers.xml +1 -1
  38. data/recog/xml/x509_subjects.xml +0 -1
  39. data/recog.gemspec +14 -13
  40. data/spec/lib/recog/db_spec.rb +37 -36
  41. data/spec/lib/recog/fingerprint/regexp_factory_spec.rb +19 -20
  42. data/spec/lib/recog/fingerprint_spec.rb +44 -42
  43. data/spec/lib/recog/formatter_spec.rb +20 -18
  44. data/spec/lib/recog/match_reporter_spec.rb +35 -30
  45. data/spec/lib/recog/nizer_spec.rb +85 -101
  46. data/spec/lib/recog/verify_reporter_spec.rb +45 -44
  47. data/spec/spec_helper.rb +2 -1
  48. data.tar.gz.sig +1 -3
  49. metadata +3 -3
  50. metadata.gz.sig +0 -0
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'recog/db'
2
4
 
3
5
  describe Recog::DB do
4
-
5
- describe "#fingerprints" do
6
- context "with inline example content" do
6
+ describe '#fingerprints' do
7
+ context 'with inline example content' do
7
8
  let(:xml_file) { File.expand_path File.join('spec', 'data', 'test_fingerprints.xml') }
8
9
  subject { Recog::DB.new(xml_file) }
9
10
 
@@ -11,50 +12,50 @@ describe Recog::DB do
11
12
 
12
13
  it { is_expected.to be_a(Enumerable) }
13
14
 
14
- context "with only a pattern" do
15
+ context 'with only a pattern' do
15
16
  subject(:entry) { described_class.new(xml_file).fingerprints[0] }
16
17
 
17
- it "has a blank name with no description" do
18
+ it 'has a blank name with no description' do
18
19
  expect(entry.name).to be_empty
19
20
  end
20
21
 
21
- it "has a pattern" do
22
- expect(entry.regex.source).to eq(".*\\(iSeries\\).*")
22
+ it 'has a pattern' do
23
+ expect(entry.regex.source).to eq('.*\\(iSeries\\).*')
23
24
  end
24
25
 
25
- it "has no params" do
26
+ it 'has no params' do
26
27
  expect(entry.params).to be_empty
27
28
  end
28
29
 
29
- it "has no tests" do
30
+ it 'has no tests' do
30
31
  expect(entry.tests).to be_empty
31
32
  end
32
33
  end
33
34
 
34
- context "with params" do
35
+ context 'with params' do
35
36
  subject(:entry) { described_class.new(xml_file).fingerprints[1] }
36
37
 
37
- it "has a name" do
38
+ it 'has a name' do
38
39
  expect(entry.name).to eq('PalmOS')
39
40
  end
40
41
 
41
- it "has a pattern" do
42
- expect(entry.regex.source).to eq(".*\\(PalmOS\\).*")
42
+ it 'has a pattern' do
43
+ expect(entry.regex.source).to eq('.*\\(PalmOS\\).*')
43
44
  end
44
45
 
45
- it "has params" do
46
- expect(entry.params).to eq({"os.vendor"=>[1, "Palm"], "os.device"=>[2, "General"]})
46
+ it 'has params' do
47
+ expect(entry.params).to eq({ 'os.vendor' => [1, 'Palm'], 'os.device' => [2, 'General'] })
47
48
  end
48
49
 
49
- it "has no tests" do
50
+ it 'has no tests' do
50
51
  expect(entry.tests).to be_empty
51
52
  end
52
53
  end
53
54
 
54
- context "with pattern flags" do
55
+ context 'with pattern flags' do
55
56
  subject(:entry) { described_class.new(xml_file).fingerprints[2] }
56
57
 
57
- it "has a name and only uses the first value" do
58
+ it 'has a name and only uses the first value' do
58
59
  expect(entry.name).to eq('HP Designjet printer')
59
60
  end
60
61
 
@@ -63,57 +64,57 @@ describe Recog::DB do
63
64
  expect(entry.regex.options).to eq(Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS | Regexp::IGNORECASE)
64
65
  end
65
66
 
66
- it "has a pattern" do
67
+ it 'has a pattern' do
67
68
  expect(entry.regex).to be_a(Regexp)
68
- expect(entry.regex.source).to eq("(designjet \\S+)")
69
+ expect(entry.regex.source).to eq('(designjet \\S+)')
69
70
  end
70
71
 
71
- it "has params" do
72
- expect(entry.params).to eq({"service.vendor"=>[0, "HP"]})
72
+ it 'has params' do
73
+ expect(entry.params).to eq({ 'service.vendor' => [0, 'HP'] })
73
74
  end
74
75
 
75
- it "has no tests" do
76
+ it 'has no tests' do
76
77
  expect(entry.tests).to be_empty
77
78
  end
78
79
  end
79
80
 
80
- context "with test" do
81
+ context 'with test' do
81
82
  subject(:entry) { described_class.new(xml_file).fingerprints[3] }
82
83
 
83
- it "has a name" do
84
+ it 'has a name' do
84
85
  expect(entry.name).to eq('HP JetDirect Printer')
85
86
  end
86
87
 
87
- it "has a pattern" do
88
- expect(entry.regex.source).to eq("laserjet (.*)(?: series)?")
88
+ it 'has a pattern' do
89
+ expect(entry.regex.source).to eq('laserjet (.*)(?: series)?')
89
90
  end
90
91
 
91
- it "has params" do
92
- expect(entry.params).to eq({"service.vendor"=>[0, "HP"]})
92
+ it 'has params' do
93
+ expect(entry.params).to eq({ 'service.vendor' => [0, 'HP'] })
93
94
  end
94
95
 
95
- it "has tests" do
96
- expect(entry.tests.map(&:content)).to match_array(["HP LaserJet 4100 Series", "HP LaserJet 2200"])
96
+ it 'has tests' do
97
+ expect(entry.tests.map(&:content)).to match_array(['HP LaserJet 4100 Series', 'HP LaserJet 2200'])
97
98
  end
98
99
  end
99
100
  end
100
101
 
101
- context "with external example content" do
102
+ context 'with external example content' do
102
103
  let(:xml_file) { File.expand_path File.join('spec', 'data', 'external_example_fingerprint.xml') }
103
104
  subject { Recog::DB.new(xml_file) }
104
105
 
105
106
  subject(:entry) { described_class.new(xml_file).fingerprints[0] }
106
107
 
107
- it "has tests" do
108
- expect(entry.tests.map(&:content)).to match_array(["HP LaserJet 4100 Series", "HP LaserJet 2200"])
108
+ it 'has tests' do
109
+ expect(entry.tests.map(&:content)).to match_array(['HP LaserJet 4100 Series', 'HP LaserJet 2200'])
109
110
  end
110
111
  end
111
112
 
112
- context "with external example content illegal path" do
113
+ context 'with external example content illegal path' do
113
114
  let(:xml_file) { File.expand_path File.join('spec', 'data', 'external_example_illegal_path_fingerprint.xml') }
114
115
  subject { Recog::DB.new(xml_file) }
115
116
 
116
- it "raises an illegal file path error" do
117
+ it 'raises an illegal file path error' do
117
118
  expect { subject }.to raise_error(/an example specifies an illegal file path '.+'/)
118
119
  end
119
120
  end
@@ -1,12 +1,12 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  require 'recog/fingerprint/regexp_factory'
3
4
 
4
5
  describe Recog::Fingerprint::RegexpFactory do
5
-
6
6
  describe 'FLAG_MAP' do
7
7
  subject { described_class::FLAG_MAP }
8
8
 
9
- it "should have the right number of flags" do
9
+ it 'should have the right number of flags' do
10
10
  expect(subject.size).to be 5
11
11
  end
12
12
  end
@@ -15,56 +15,55 @@ describe Recog::Fingerprint::RegexpFactory do
15
15
  subject { described_class.build(pattern, options) }
16
16
 
17
17
  let(:pattern) { 'Apache/(\d+)' }
18
- let(:options) { [ 'REG_ICASE' ] }
18
+ let(:options) { ['REG_ICASE'] }
19
19
 
20
20
  it { is_expected.to be_a(Regexp) }
21
21
  it { is_expected.to match('Apache/2') }
22
-
23
22
  end
24
23
 
25
24
  describe '.build_options' do
26
25
  subject { described_class.build_options(flags) }
27
26
 
28
- let(:flags) { [ ] }
27
+ let(:flags) { [] }
29
28
  it { is_expected.to be_a(Integer) }
30
29
 
31
30
  context 'without any explicit flags' do
32
- let(:flags) { [ ] }
33
- specify "sets default flags" do
31
+ let(:flags) { [] }
32
+ specify 'sets default flags' do
34
33
  expect(subject).to be Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS
35
34
  end
36
35
  end
37
36
 
38
37
  context 'with REG_ICASE' do
39
- let(:flags) { [ 'REG_ICASE' ] }
40
- specify "sets IGNORECASE" do
41
- expect(subject).to be (Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS | Regexp::IGNORECASE)
38
+ let(:flags) { ['REG_ICASE'] }
39
+ specify 'sets IGNORECASE' do
40
+ expect(subject).to be(Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS | Regexp::IGNORECASE)
42
41
  end
43
42
  end
44
43
 
45
44
  context 'with REG_DOT_NEWLINE' do
46
- let(:flags) { [ 'REG_DOT_NEWLINE' ] }
47
- specify "sets MULTILINE" do
48
- expect(subject).to be (Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS | Regexp::MULTILINE)
45
+ let(:flags) { ['REG_DOT_NEWLINE'] }
46
+ specify 'sets MULTILINE' do
47
+ expect(subject).to be(Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS | Regexp::MULTILINE)
49
48
  end
50
49
  end
51
50
 
52
51
  context 'with REG_LINE_ANY_CRLF' do
53
- let(:flags) { [ 'REG_LINE_ANY_CRLF' ] }
54
- specify "sets MULTILINE" do
55
- expect(subject).to be (Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS | Regexp::MULTILINE)
52
+ let(:flags) { ['REG_LINE_ANY_CRLF'] }
53
+ specify 'sets MULTILINE' do
54
+ expect(subject).to be(Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS | Regexp::MULTILINE)
56
55
  end
57
56
  end
58
57
 
59
58
  context 'with multiple flags' do
60
- let(:flags) { [ 'REG_LINE_ANY_CRLF', 'REG_ICASE' ] }
61
- specify "sets correct flags" do
62
- expect(subject).to be (Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS | Regexp::MULTILINE | Regexp::IGNORECASE)
59
+ let(:flags) { %w[REG_LINE_ANY_CRLF REG_ICASE] }
60
+ specify 'sets correct flags' do
61
+ expect(subject).to be(Recog::Fingerprint::RegexpFactory::DEFAULT_FLAGS | Regexp::MULTILINE | Regexp::IGNORECASE)
63
62
  end
64
63
  end
65
64
 
66
65
  context 'with invalid flags' do
67
- let(:flags) { %w(SYN ACK FIN) } # oh, wrong flags!
66
+ let(:flags) { %w[SYN ACK FIN] } # oh, wrong flags!
68
67
  specify 'raises and lists supported/unsupported flags' do
69
68
  expect { subject }.to raise_error(/SYN,ACK,FIN. Must be one of: .+/)
70
69
  end
@@ -1,112 +1,114 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'nokogiri'
2
4
  require 'recog/fingerprint'
3
5
 
4
6
  describe Recog::Fingerprint do
5
- context "whitespace" do
7
+ context 'whitespace' do
6
8
  let(:xml) do
7
9
  path = File.expand_path(File.join('spec', 'data', 'whitespaced_fingerprint.xml'))
8
10
  doc = Nokogiri::XML(IO.read(path))
9
- doc.xpath("//fingerprint").first
11
+ doc.xpath('//fingerprint').first
10
12
  end
11
13
  subject { Recog::Fingerprint.new(xml) }
12
14
 
13
- describe "#name" do
14
- it "properly squashes whitespace" do
15
+ describe '#name' do
16
+ it 'properly squashes whitespace' do
15
17
  expect(subject.name).to eq('I love whitespace!')
16
18
  end
17
19
  end
18
20
  end
19
21
 
20
- describe "#verification" do
22
+ describe '#verification' do
21
23
  let(:xml_file) { File.expand_path(File.join('spec', 'data', 'verification_fingerprints.xml')) }
22
24
  let(:doc) { Nokogiri::XML(IO.read(xml_file)) }
23
25
 
24
- context "0 params" do
25
- let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[0]) }
26
+ context '0 params' do
27
+ let(:entry) { described_class.new(doc.xpath('//fingerprints/fingerprint')[0]) }
26
28
 
27
- it "does not yield if a fingerprint has 0 parameters" do
29
+ it 'does not yield if a fingerprint has 0 parameters' do
28
30
  expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.not_to yield_control
29
31
  end
30
32
  end
31
33
 
32
- context "0 capture groups" do
33
- let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[1]) }
34
+ context '0 capture groups' do
35
+ let(:entry) { described_class.new(doc.xpath('//fingerprints/fingerprint')[1]) }
34
36
 
35
- it "does not yield if a fingerprint has parameters, but 0 are defined by a capture group " do
37
+ it 'does not yield if a fingerprint has parameters, but 0 are defined by a capture group ' do
36
38
  expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.not_to yield_control
37
39
  end
38
40
  end
39
41
 
40
- context "0 examples" do
41
- let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[2]) }
42
+ context '0 examples' do
43
+ let(:entry) { described_class.new(doc.xpath('//fingerprints/fingerprint')[2]) }
42
44
 
43
- it "does not yield if a fingerprint has 0 examples" do
45
+ it 'does not yield if a fingerprint has 0 examples' do
44
46
  expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.not_to yield_control
45
47
  end
46
48
  end
47
49
 
48
- context "1 capture group, 1 example" do
49
-
50
- let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[3]) }
50
+ context '1 capture group, 1 example' do
51
+ let(:entry) { described_class.new(doc.xpath('//fingerprints/fingerprint')[3]) }
51
52
 
52
- it "does not yield when one capture group parameter is tested for in one example" do
53
+ it 'does not yield when one capture group parameter is tested for in one example' do
53
54
  expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.not_to yield_control
54
55
  end
55
56
  end
56
57
 
57
- context "2 capture groups, 1 example" do
58
- let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[4]) }
58
+ context '2 capture groups, 1 example' do
59
+ let(:entry) { described_class.new(doc.xpath('//fingerprints/fingerprint')[4]) }
59
60
 
60
- it "does not yield when two capture group parameters are tested for in one example" do
61
+ it 'does not yield when two capture group parameters are tested for in one example' do
61
62
  expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.not_to yield_control
62
63
  end
63
64
  end
64
65
 
65
- context "2 capture groups, 2 examples, 1 in each" do
66
- let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[5]) }
66
+ context '2 capture groups, 2 examples, 1 in each' do
67
+ let(:entry) { described_class.new(doc.xpath('//fingerprints/fingerprint')[5]) }
67
68
 
68
- it "does not yield when two capture group parameters are tested for in two examples, one parameter in each" do
69
+ it 'does not yield when two capture group parameters are tested for in two examples, one parameter in each' do
69
70
  expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.not_to yield_control
70
71
  end
71
72
  end
72
73
 
73
- context "1 missing capture group, 1 example" do
74
-
75
- let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[6]) }
74
+ context '1 missing capture group, 1 example' do
75
+ let(:entry) { described_class.new(doc.xpath('//fingerprints/fingerprint')[6]) }
76
76
 
77
- it "identifies when a parameter defined by a capture group is not included in one example" do
77
+ it 'identifies when a parameter defined by a capture group is not included in one example' do
78
78
  expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:fail, String])
79
79
  end
80
80
  end
81
81
 
82
- context "2 missing capture groups, 1 example" do
83
- let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[7]) }
82
+ context '2 missing capture groups, 1 example' do
83
+ let(:entry) { described_class.new(doc.xpath('//fingerprints/fingerprint')[7]) }
84
84
 
85
- it "identifies when two parameters defined by a capture groups are not included in one example" do
86
- expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:fail, String], [:fail, String])
85
+ it 'identifies when two parameters defined by a capture groups are not included in one example' do
86
+ expect do |unused|
87
+ entry.verify_tests_have_capture_groups(&unused)
88
+ end.to yield_successive_args([:fail, String], [:fail, String])
87
89
  end
88
90
  end
89
91
 
90
- context "1 missing capture group, 2 examples" do
92
+ context '1 missing capture group, 2 examples' do
93
+ let(:entry) { described_class.new(doc.xpath('//fingerprints/fingerprint')[8]) }
91
94
 
92
- let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[8]) }
93
-
94
- it "identifies when a parameter defined by a capture group is not included in one example" do
95
+ it 'identifies when a parameter defined by a capture group is not included in one example' do
95
96
  expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:fail, String])
96
97
  end
97
98
  end
98
99
 
99
- context "2 missing capture groups, 2 examples" do
100
- let(:entry) { described_class.new(doc.xpath("//fingerprints/fingerprint")[9]) }
100
+ context '2 missing capture groups, 2 examples' do
101
+ let(:entry) { described_class.new(doc.xpath('//fingerprints/fingerprint')[9]) }
101
102
 
102
- it "identifies when two parameters defined by a capture groups are not included in one example" do
103
- expect { |unused| entry.verify_tests_have_capture_groups(&unused) }.to yield_successive_args([:fail, String], [:fail, String])
103
+ it 'identifies when two parameters defined by a capture groups are not included in one example' do
104
+ expect do |unused|
105
+ entry.verify_tests_have_capture_groups(&unused)
106
+ end.to yield_successive_args([:fail, String], [:fail, String])
104
107
  end
105
108
  end
106
-
107
109
  end
108
110
 
109
- skip "value interpolation" do
111
+ skip 'value interpolation' do
110
112
  # TODO
111
113
  end
112
114
  end
@@ -1,66 +1,68 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'recog/formatter'
2
4
 
3
5
  describe Recog::Formatter do
4
6
  let(:output) { StringIO.new }
5
7
 
6
- context "with no color" do
8
+ context 'with no color' do
7
9
  subject { Recog::Formatter.new(double(color: false), output) }
8
10
 
9
- describe "#message" do
10
- it "outputs the text" do
11
+ describe '#message' do
12
+ it 'outputs the text' do
11
13
  subject.status_message 'some text'
12
14
  expect(output.string).to eq("some text\n")
13
15
  end
14
16
  end
15
17
 
16
- describe "#success_message" do
17
- it "outputs the text" do
18
+ describe '#success_message' do
19
+ it 'outputs the text' do
18
20
  subject.success_message 'a success'
19
21
  expect(output.string).to eq("a success\n")
20
22
  end
21
23
  end
22
24
 
23
- describe "#warning_message" do
24
- it "outputs the text" do
25
+ describe '#warning_message' do
26
+ it 'outputs the text' do
25
27
  subject.warning_message 'a warning'
26
28
  expect(output.string).to eq("a warning\n")
27
29
  end
28
30
  end
29
31
 
30
- describe "#failure_message" do
31
- it "outputs the text" do
32
+ describe '#failure_message' do
33
+ it 'outputs the text' do
32
34
  subject.failure_message 'a failure'
33
35
  expect(output.string).to eq("a failure\n")
34
36
  end
35
37
  end
36
38
  end
37
39
 
38
- context "with color" do
40
+ context 'with color' do
39
41
  subject { Recog::Formatter.new(double(color: true), output) }
40
42
 
41
- describe "#message" do
42
- it "outputs the text in white" do
43
+ describe '#message' do
44
+ it 'outputs the text in white' do
43
45
  subject.status_message 'some text'
44
46
  expect(output.string).to eq("\e[15msome text\e[0m\n")
45
47
  end
46
48
  end
47
49
 
48
- describe "#success_message" do
49
- it "outputs the text in green" do
50
+ describe '#success_message' do
51
+ it 'outputs the text in green' do
50
52
  subject.success_message 'a success'
51
53
  expect(output.string).to eq("\e[32ma success\e[0m\n")
52
54
  end
53
55
  end
54
56
 
55
- describe "#warning_message" do
56
- it "outputs the text in yellow" do
57
+ describe '#warning_message' do
58
+ it 'outputs the text in yellow' do
57
59
  subject.warning_message 'a warning'
58
60
  expect(output.string).to eq("\e[33ma warning\e[0m\n")
59
61
  end
60
62
  end
61
63
 
62
- describe "#failure_message" do
63
- it "outputs the text in red" do
64
+ describe '#failure_message' do
65
+ it 'outputs the text in red' do
64
66
  subject.failure_message 'a failure'
65
67
  expect(output.string).to eq("\e[31ma failure\e[0m\n")
66
68
  end
@@ -1,103 +1,108 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'recog/match_reporter'
2
4
 
3
5
  describe Recog::MatchReporter do
4
- let(:options) { double(detail: false, json_format: false, quiet: false, multi_match: false) }
6
+ let(:options) { double(detail: false, json_format: false, quiet: false, multi_match: false) }
5
7
  let(:formatter) { double('formatter').as_null_object }
6
8
  subject { Recog::MatchReporter.new(options, formatter) }
7
9
 
8
10
  def run_report
9
11
  subject.report do
10
- subject.increment_line_count
11
- subject.match [{'data' => 'a match'}]
12
- subject.failure 'a failure'
12
+ subject.increment_line_count
13
+ subject.match [{ 'data' => 'a match' }]
14
+ subject.failure 'a failure'
13
15
  end
14
16
  end
15
17
 
16
- describe "#report" do
17
- it "prints matches" do
18
+ describe '#report' do
19
+ it 'prints matches' do
18
20
  expect(formatter).to receive(:success_message).with('MATCH: {"data"=>"a match"}')
19
21
  run_report
20
22
  end
21
23
 
22
- it "prints failures" do
24
+ it 'prints failures' do
23
25
  expect(formatter).to receive(:failure_message).with('FAIL: a failure')
24
26
  run_report
25
27
  end
26
28
 
27
- context "with detail" do
28
- subject { Recog::MatchReporter.new(double(detail: true, json_format: false, quiet: false, multi_match: false), formatter) }
29
+ context 'with detail' do
30
+ subject do
31
+ Recog::MatchReporter.new(double(detail: true, json_format: false, quiet: false, multi_match: false), formatter)
32
+ end
29
33
 
30
- it "prints the lines processed" do
34
+ it 'prints the lines processed' do
31
35
  expect(formatter).to receive(:status_message).with("\nProcessed 1 lines")
32
36
  run_report
33
37
  end
34
38
 
35
- it "prints summary" do
36
- expect(formatter).to receive(:failure_message).with("SUMMARY: 1 matches and 1 failures")
39
+ it 'prints summary' do
40
+ expect(formatter).to receive(:failure_message).with('SUMMARY: 1 matches and 1 failures')
37
41
  run_report
38
42
  end
39
43
  end
40
44
 
41
- context "with JSON" do
42
- subject { Recog::MatchReporter.new(double(detail: false, json_format: true, quiet: false, multi_match: false), formatter) }
45
+ context 'with JSON' do
46
+ subject do
47
+ Recog::MatchReporter.new(double(detail: false, json_format: true, quiet: false, multi_match: false), formatter)
48
+ end
43
49
 
44
- it "prints matches" do
50
+ it 'prints matches' do
45
51
  expect(formatter).to receive(:success_message).with('{"data":"a match","match":{}}')
46
52
  run_report
47
53
  end
48
54
 
49
- it "prints failures" do
55
+ it 'prints failures' do
50
56
  expect(formatter).to receive(:failure_message).with('{"data":"a failure","match_failure":true,"match":null}')
51
57
  run_report
52
58
  end
53
59
  end
54
60
  end
55
61
 
56
- describe "#print_summary" do
57
- context "with all matches" do
62
+ describe '#print_summary' do
63
+ context 'with all matches' do
58
64
  before { subject.match ['match'] }
59
65
 
60
- it "prints a successful summary" do
61
- msg = "SUMMARY: 1 matches and 0 failures"
66
+ it 'prints a successful summary' do
67
+ msg = 'SUMMARY: 1 matches and 0 failures'
62
68
  expect(formatter).to receive(:success_message).with(msg)
63
69
  subject.print_summary
64
70
  end
65
71
  end
66
72
 
67
- context "with failures" do
73
+ context 'with failures' do
68
74
  before { subject.failure 'fail' }
69
75
 
70
- it "prints a failure summary" do
71
- msg = "SUMMARY: 0 matches and 1 failures"
76
+ it 'prints a failure summary' do
77
+ msg = 'SUMMARY: 0 matches and 1 failures'
72
78
  expect(formatter).to receive(:failure_message).with(msg)
73
79
  subject.print_summary
74
80
  end
75
81
  end
76
82
  end
77
83
 
78
- describe "#stop?" do
79
- context "with a failure limit" do
80
-
84
+ describe '#stop?' do
85
+ context 'with a failure limit' do
81
86
  let(:options) { double(fail_fast: true, stop_after: 3, detail: false, json_format: false, multi_match: false) }
82
87
  before do
83
88
  subject.failure 'first'
84
89
  subject.failure 'second'
85
90
  end
86
91
 
87
- it "returns true when the limit is reached " do
92
+ it 'returns true when the limit is reached ' do
88
93
  subject.failure 'third'
89
94
  expect(subject.stop?).to be true
90
95
  end
91
96
 
92
- it "returns false when under the limit" do
97
+ it 'returns false when under the limit' do
93
98
  expect(subject.stop?).to be false
94
99
  end
95
100
  end
96
101
 
97
- context "with no failure limit" do
102
+ context 'with no failure limit' do
98
103
  let(:options) { double(fail_fast: false, detail: false, json_format: false, multi_match: false) }
99
104
 
100
- it "return false" do
105
+ it 'return false' do
101
106
  expect(subject.stop?).to be false
102
107
  end
103
108
  end